Platform Architecture
OEC.sh is a multi-tenant Odoo hosting platform. This page explains how its core entities relate to each other.
Platform Overview
The top-level entity is the Organisation. Everything else belongs to one.
| Entity | Belongs to | Purpose |
|---|---|---|
| Server / VM | Organisation | The machine Odoo runs on (BYOS or platform-provisioned) |
| Project | Organisation | An Odoo application (version, primary repo, addon selection) |
| Environment | Project + Server | A running Odoo instance (dev / staging / production) |
| Team | Organisation | Group of members assigned to projects with a role |
| Cloud Account | Organisation | Credentials for AWS, Azure, GCP, DO, Vultr, Hetzner |
| Git Connection | Platform or Org | Authentication for private Git repos |
| DNS Provider | Organisation | Cloudflare, Route53, Azure DNS, etc. |
| Backup Storage | Organisation | S3, R2, B2, MinIO, FTP, SFTP |
Repository Hierarchy
Addon repositories follow a four-level cascade — from platform-wide down to per-environment overrides:
Levels Explained
🌐 Platform Addon Repos
Managed by portal admins. Available to every organisation on the platform. Each repo has a version mapping — a separate Git branch per Odoo version (16.0, 17.0, 18.0 …). Stored at /opt/oecsh/platform/{slug}/.
🏢 Organisation Addon Repos
Managed by Org Owners and Admins. Visible only to projects within the organisation. Authenticated via an Org Git Connection. Stored at /opt/oecsh/org_{uuid}/{slug}/.
📁 Project — Module Repositories Attached to one project. Each repo has a branch mapping — a different branch per environment type:
dev → develop
staging → staging
production → mainThe deployer resolves the correct branch automatically for each environment.
📁 Project — Additional Repos Also attached to one project. Unlike module repositories, additional repos use a single branch and are always included in every environment. Used for utility libraries, shared components, or extra OCA modules not in the org repo.
⚙️ Environment — Repo Overrides Environments can override any inherited repo:
- Branch override — use a different branch than the project default for this env only
- Exclusion — skip a repo entirely for this env (e.g. exclude heavy dev tools from production)
The override system follows the zero-config principle: no override row = inherit everything from the project. Only set overrides when an environment genuinely needs to diverge.
Environment Internals
Each environment is an isolated stack running on a server:
Environment
├── Odoo container docker run -e KEY=VALUE ...
├── PostgreSQL {env_id}_db container
│ ├── PgBouncer connection pooling (Pro+)
│ └── Read Replica streaming replication (Odoo 18+, Pro+)
├── Traefik routing auto-provisioned TLS via Cloudflare
└── Netdata real-time metrics (proxied at /_oecsh/netdata/)Resources (CPU, RAM, disk) are allocated per environment and count against the organisation's quota.
Access Control
Two systems control who can do what:
Organisation-level roles — set on OrganizationMember:
| Role | Can do |
|---|---|
| Owner | Everything, including billing and deleting the org |
| Admin | All resources except billing management |
| Developer | Environments assigned to their managed projects |
| Viewer | Read-only across the org |
Team-based access — Teams are groups of members assigned to specific projects with a project role (Admin / Developer / Viewer). A user's effective permission on a project is the highest role from any team membership plus their org-level role.
Full permission matrix: Permissions
Key Field Mappings
Some fields have different names between the database and API — notable ones:
| Database column | API / frontend field | Notes |
|---|---|---|
project.git_branch | default_branch | Primary repo branch |
module_repository.default_branch | default_branch | Module repo default |
project_environments.create_date | created_at | Environments table uses create_date, not created_at |
project_environments.environment_type | env_type | Enum: development / staging / production |