Skip to content

Architecture Overview

System architecture and design documentation for the Odoo 15 ERP platform.

System Overview

flowchart TB
    subgraph Internet
        Users[Users/Browsers]
        Mobile[Mobile Devices]
    end

    subgraph "Nginx Reverse Proxy :80/:443"
        SSL[SSL Termination<br/>TLS 1.2/1.3]
    end

    subgraph "Docker Services"
        Odoo[Odoo 15 ERP<br/>:8069 internal<br/>:8016 external]
        Landing[Landing Page<br/>Flask :8001]
        PWA[Field PWA<br/>Flask :8000]
        Docs[Documentation<br/>MkDocs :8002]
    end

    subgraph "Data Layer"
        DB[(PostgreSQL<br/>:5432<br/>Local/AWS RDS)]
        FileStore[(Filestore<br/>./odoo-data)]
        S3[(AWS S3<br/>Signatures/Photos)]
    end

    subgraph "External Services"
        JustCall[JustCall API<br/>SMS/MMS]
        Xero[Xero API<br/>Accounting]
        reCAPTCHA[Google reCAPTCHA]
        GChat[Google Chat<br/>Notifications]
    end

    Users --> SSL
    Mobile --> SSL
    SSL -->|erp.domain| Odoo
    SSL -->|www.domain| Landing
    SSL -->|field.domain| PWA
    SSL -->|docs.domain| Docs

    Odoo --> DB
    Odoo --> FileStore
    Odoo --> S3
    Odoo <--> JustCall
    Odoo <--> Xero
    Odoo --> GChat
    Landing --> Odoo
    Landing --> reCAPTCHA
    PWA --> Odoo
    PWA --> S3

Port Mapping

Service Internal Port External Port (Test) Production
Odoo 8069 8016 Via nginx only
Landing Page 8001 8001 Via nginx only
Field PWA 8000 8000 Via nginx only
Documentation 8002 8002 Via nginx only
Nginx 80, 443 80, 443 80, 443
PostgreSQL 5432 5432 (test only) AWS RDS

Technology Stack

Backend

Component Technology Version Purpose
ERP Odoo 15.0 CE Core business logic
Database PostgreSQL 15 Data persistence (Local or AWS RDS)
Web Server Werkzeug Built-in Odoo HTTP server
PWA Backend Flask + Gunicorn 3.0+ Field PWA application
Landing Backend Flask + Gunicorn 3.0+ Public website

Frontend

Component Technology Version Purpose
ERP UI Odoo Web Client 15.0 Desktop interface
PWA Bootstrap 5 + JS ES6+ Mobile field app
Landing Page Tailwind CSS 3.x Public website styling
JS Framework Alpine.js 3.x Landing page reactivity

Infrastructure

Component Technology Purpose
Containerization Docker 20.10+
Orchestration Docker Compose 2.x
Reverse Proxy Nginx SSL termination, routing
Documentation MkDocs Material 9.x
SSL Certificates Let's Encrypt Auto-renewed HTTPS

External Services

Service Provider Purpose
SMS/MMS JustCall Two-way customer communication
Storage AWS S3 Signatures, photos, backups
Accounting Xero Invoice/payment sync
Spam Protection Google reCAPTCHA v3 Landing page form protection
Notifications Google Chat Team alerts (FSM, Sales, etc.)

Container Architecture

Docker Compose Services

services:
  odoo:       # Odoo ERP application
  db:         # PostgreSQL database (test only, prod uses RDS)
  pwa:        # Field service PWA
  landing:    # Public landing page
  nginx:      # Reverse proxy with SSL
  docs:       # Documentation portal

Container Details

Service Base Image Internal Port Test External Production
odoo odoo:15 (custom) 8069 8016 nginx only
db postgres:15 5432 5432 AWS RDS
pwa python:3.11-slim 8000 8000 nginx only
landing python:3.11-slim 8001 8001 nginx only
nginx nginx:alpine 80, 443 80, 443 80, 443
docs python:3.11-slim 8002 8002 nginx only

Environment Overlays

File Purpose Database Exposed Ports
docker-compose.yml Base services - -
docker-compose.test.yml Test overlay Local PostgreSQL All services
docker-compose.prod.yml Production overlay AWS RDS Only nginx 80/443
# Test environment (default in .env)
COMPOSE_FILE=docker-compose.yml:docker-compose.test.yml

# Production environment
COMPOSE_FILE=docker-compose.yml:docker-compose.prod.yml

Network Architecture

flowchart TB
    subgraph "Docker Bridge Network"
        subgraph "Services"
            odoo[Odoo :8069]
            db[PostgreSQL :5432]
            pwa[PWA :8000]
            landing[Landing :8001]
            docs[Docs :8002]
            nginx[Nginx :80/:443]
        end

        odoo <--> db
        nginx --> odoo
        nginx --> pwa
        nginx --> landing
        nginx --> docs
        pwa --> odoo
        landing --> odoo
    end

    Internet((Internet)) --> nginx

Network isolation: - All services on internal bridge network - Only nginx exposes ports to host - In production, only ports 80/443 accessible externally

Volume Mounts

Volume Type Container Path Purpose
./odoo-data Bind mount odoo /var/lib/odoo Filestore, sessions, addons
postgres-data Docker volume db /var/lib/postgresql/data Database (test only)
./extra-addons/odoo Bind mount odoo /mnt/extra-addons/odoo Custom modules
./extra-addons/helpdesk Bind mount odoo /mnt/extra-addons/helpdesk Helpdesk modules
./configs/odoo.conf Bind mount odoo /etc/odoo/odoo.conf Odoo configuration
./nginx/conf.d Bind mount nginx /etc/nginx/conf.d Nginx server configs
./nginx/ssl Bind mount nginx /etc/nginx/ssl SSL certificates
./nginx/certbot Bind mount nginx /var/www/certbot ACME challenge files

Odoo Data Storage

The odoo-data directory is a bind mount for easier backup and direct host access:

odoo-data/
├── addons/        # Downloaded Odoo Apps store modules
├── filestore/     # Attachments, images, documents
│   └── <db_name>/ # Database-specific files
└── sessions/      # User session data

PostgreSQL Data

PostgreSQL uses a Docker named volume (postgres-data) for data integrity and proper file permissions.


Module Architecture

Module Categories

extra-addons/
├── odoo/                    # Custom Odoo modules
│   ├── jdx_*               # JDX company modules
│   ├── justcall_*          # JustCall integrations
│   ├── xero_*              # Xero integrations
│   └── fieldservice/       # FSM base module
├── helpdesk/               # Helpdesk modules
│   ├── helpdesk/           # Core helpdesk
│   └── jdx_helpdesk_fsm/   # FSM integration
└── (other categories)

Module Dependencies

                    ┌─────────┐
                    │  base   │
                    └────┬────┘
         ┌───────────────┼───────────────┐
         │               │               │
         ▼               ▼               ▼
    ┌─────────┐    ┌──────────┐    ┌──────────┐
    │  sale   │    │ contacts │    │  stock   │
    └────┬────┘    └────┬─────┘    └────┬─────┘
         │              │               │
         │         ┌────┴────┐          │
         │         ▼         ▼          │
         │   ┌──────────┐ ┌─────────┐   │
         │   │ helpdesk │ │   crm   │   │
         │   └────┬─────┘ └────┬────┘   │
         │        │            │        │
         ▼        ▼            ▼        ▼
    ┌─────────────────────────────────────────┐
    │           fieldservice                   │
    └─────────────────┬───────────────────────┘
    ┌─────────────────┼─────────────────┐
    │                 │                 │
    ▼                 ▼                 ▼
┌────────────┐  ┌───────────┐  ┌──────────────┐
│jdx_fsm_    │  │jdx_service│  │jdx_field_    │
│calendar    │  │_signature │  │service_auto  │
└────────────┘  └───────────┘  └──────────────┘

Custom Module Overview

Module Purpose Dependencies
justcall_sms SMS/MMS messaging contacts
jdx_service_signature Digital signatures fieldservice
xero_integration Accounting sync account
jdx_field_service_automation FSM extensions fieldservice
jdx_fsm_calendar Calendar sync fieldservice, calendar
restapi REST API endpoints base

Data Flow

Order to Field Service Flow

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  Sale    │     │   FSM    │     │   PWA    │     │ Customer │
│  Order   │────▶│  Order   │────▶│  App     │────▶│ Signature│
└──────────┘     └──────────┘     └──────────┘     └──────────┘
     │                │                │                │
     │                │                │                │
     ▼                ▼                ▼                ▼
┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│ Invoice  │     │ Schedule │     │ Complete │     │   S3     │
│ Created  │     │ Calendar │     │   Job    │     │ Storage  │
└──────────┘     └──────────┘     └──────────┘     └──────────┘

SMS Notification Flow

┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│   Odoo      │     │  JustCall   │     │  Customer   │
│  Trigger    │────▶│    API      │────▶│   Phone     │
└─────────────┘     └─────────────┘     └─────────────┘
      │                    │                   │
      │                    │                   │
      ▼                    ▼                   ▼
┌─────────────┐     ┌─────────────┐     ┌─────────────┐
│  Log SMS    │     │  Delivery   │     │  Response   │
│  Record     │◀────│   Status    │◀────│  (if any)   │
└─────────────┘     └─────────────┘     └─────────────┘

API Authentication Flow

┌──────────┐     ┌──────────┐     ┌──────────┐     ┌──────────┐
│  Client  │     │  Nginx   │     │  Odoo    │     │ Database │
│  Request │────▶│  Proxy   │────▶│  API     │────▶│  Verify  │
└──────────┘     └──────────┘     └──────────┘     └──────────┘
     │                                  │
     │                                  │
     │           ┌──────────┐           │
     │◀──────────│  JSON    │◀──────────┘
                 │ Response │
                 └──────────┘

Security Architecture

Network Security

Internet ──▶ Firewall ──▶ Nginx (SSL) ──▶ Internal Network
                    ┌─────────────────┐
                    │  Rate Limiting  │
                    │  IP Filtering   │
                    │  SSL/TLS 1.3    │
                    └─────────────────┘

Authentication Layers

Layer Method Purpose
Nginx Basic Auth (optional) Admin protection
Odoo Session/Cookie User authentication
API API Key / Token Service authentication
Database Password Direct access (restricted)

Data Protection

Data Type Protection Storage
Passwords Hashed (PBKDF2) PostgreSQL
API Keys Encrypted PostgreSQL
Sessions Signed cookies Memory/DB
Files Access controlled Filestore/S3

Scalability Considerations

Current Architecture (Single Server)

┌─────────────────────────────────────┐
│           Single Server             │
│  ┌─────┐ ┌────┐ ┌─────┐ ┌─────┐   │
│  │Odoo │ │ DB │ │ PWA │ │Nginx│   │
│  └─────┘ └────┘ └─────┘ └─────┘   │
└─────────────────────────────────────┘

Scaled Architecture (Future)

                    ┌─────────────┐
                    │Load Balancer│
                    └──────┬──────┘
          ┌────────────────┼────────────────┐
          │                │                │
          ▼                ▼                ▼
    ┌──────────┐    ┌──────────┐    ┌──────────┐
    │  Odoo 1  │    │  Odoo 2  │    │  Odoo 3  │
    └────┬─────┘    └────┬─────┘    └────┬─────┘
         │               │               │
         └───────────────┼───────────────┘
              ┌─────────────────────┐
              │   PostgreSQL RDS    │
              │   (Primary/Replica) │
              └─────────────────────┘

Scaling Strategy

Component Horizontal Vertical Notes
Odoo Yes (workers) Yes Add workers, then instances
PostgreSQL Read replicas Yes RDS handles scaling
Nginx Yes Limited Multiple load balancers
PWA Yes Yes Stateless, easy to scale

Disaster Recovery

Backup Strategy

Component Frequency Retention Location
Database Daily 30 days S3
Filestore Daily 30 days S3
Config On change Version controlled Git
Secrets On change Encrypted Secure vault

Recovery Procedures

Scenario RTO RPO Procedure
Container crash 5 min 0 Auto-restart
Server failure 30 min 24 hr Restore from backup
Data corruption 1 hr 24 hr Point-in-time recovery
Region failure 4 hr 24 hr Cross-region restore

Monitoring Points

Health Checks

Service Endpoint Expected
Odoo /web/health 200 OK
PWA /health 200 OK
Nginx /nginx-health 200 OK
PostgreSQL pg_isready 0 exit

Key Metrics

Metric Warning Critical
CPU Usage > 70% > 90%
Memory Usage > 80% > 95%
Disk Usage > 70% > 90%
Response Time > 2s > 5s
Error Rate > 1% > 5%

Integration Points

External APIs

Integration Direction Protocol Authentication
JustCall Outbound REST/HTTPS API Key
Xero Bidirectional OAuth 2.0 Token
AWS S3 Outbound HTTPS IAM Keys
Google Calendar Bidirectional REST OAuth 2.0

Internal APIs

Endpoint Purpose Auth
/api/v1/* REST API API Key
/jsonrpc JSON-RPC Session
/xmlrpc XML-RPC Basic Auth

File Structure

odoo15-production/
├── docker-compose.yml           # Base Docker Compose
├── docker-compose.test.yml      # Test environment overlay
├── docker-compose.prod.yml      # Production environment overlay
├── production_deploy.sh         # Centralized deployment script
├── .env                         # Active configuration (not in git)
├── .env.example                 # Environment template
├── .env.test                    # Test environment template
├── odoo/                        # Custom Odoo Docker image
│   ├── Dockerfile               # Extends odoo:15 with Python deps
│   └── requirements.txt         # Additional Python packages
├── odoo-data/                   # Odoo data (bind mount)
│   ├── addons/                  # Downloaded Odoo Apps store modules
│   ├── filestore/               # Attachments, images, documents
│   │   └── <db_name>/           # Database-specific files
│   └── sessions/                # User session data
├── configs/
│   └── odoo.conf                # Odoo configuration
├── extra-addons/                # Custom modules
│   ├── odoo/                    # Main custom modules
│   │   ├── jdx_core_data/       # Base configuration
│   │   ├── justcall_sms/        # SMS integration
│   │   ├── jdx_service_signature/ # Digital signatures
│   │   ├── xero_integration/    # Accounting sync
│   │   ├── restapi/             # REST API
│   │   └── ...
│   └── helpdesk/                # Helpdesk module stack
├── pwa/                         # Field service PWA
│   ├── app/                     # Flask application
│   ├── templates/               # Jinja2 templates
│   ├── static/                  # CSS, JS, images
│   ├── Dockerfile
│   └── requirements.txt
├── landing-page/                # Public landing page
│   ├── app/                     # Flask application
│   ├── templates/               # Jinja2 templates
│   ├── static/                  # CSS, JS, images
│   ├── tailwind.config.js       # Tailwind CSS config
│   ├── Dockerfile
│   └── requirements.txt
├── nginx/                       # Nginx configuration
│   ├── conf.d/
│   │   ├── default.conf         # Test HTTP config
│   │   └── production.conf.template  # Production HTTPS template
│   ├── ssl/                     # SSL certificates
│   │   └── live/<domain>/       # Let's Encrypt certs
│   └── certbot/                 # ACME challenge files
├── scripts/                     # Utility scripts
│   ├── backup.sh                # Backup script
│   ├── restore.sh               # Restore script
│   ├── health-check.sh          # Health check
│   ├── ssl-init.sh              # SSL certificate management
│   └── ssl-renew-cron.sh        # SSL auto-renewal (cron)
├── docs/                        # Documentation (MkDocs)
│   ├── mkdocs.yml               # MkDocs configuration
│   ├── content/                 # Markdown files
│   ├── Dockerfile
│   └── requirements.txt
└── LESSONS_LEARNED.md           # Project notes

Configuration Flow

┌─────────────────────────────────────────────────────────────┐
│                   .env (Source of Truth)                    │
├─────────────────────────────────────────────────────────────┤
│  ENVIRONMENT        → test / production                     │
│  COMPOSE_FILE       → Which compose files to load           │
│  DB_*               → Database connection                   │
│  DOMAIN_*           → Domain names for nginx                │
│  LETSENCRYPT_EMAIL  → SSL certificate notifications        │
└─────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│  production_deploy.sh  │  ssl-init.sh  │  docker-compose    │
└─────────────────────────────────────────────────────────────┘