Architecture¶
System Overview¶
┌─────────────────────────────────────────────────────────────┐
│ Nginx │
│ (Reverse Proxy) │
└─────────────────────────────────────────────────────────────┘
│ │ │ │
▼ ▼ ▼ ▼
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
│ Landing │ │ Odoo │ │ PWA │ │ Docs │
│ :8001 │ │ :8069 │ │ :8000 │ │ :8080 │
└─────────┘ └─────────┘ └─────────┘ └─────────┘
│ │
│ ▼
│ ┌──────────┐
└───────►│ REST API │
│/restapi/ │
└──────────┘
│
▼
┌────────────────┐
│ PostgreSQL │
│ (Odoo DB) │
└────────────────┘
Request Flow¶
Estimate Form Submission¶
1. User fills estimate form
2. Alpine.js validates client-side
3. reCAPTCHA v3 generates token
4. POST /api/estimate with form data + token
5. Flask verifies reCAPTCHA with Google
6. Flask calls Odoo REST API to create crm.lead
7. Success/error response returned to user
Helpdesk Form Submission¶
1. User fills helpdesk form
2. Alpine.js validates client-side
3. reCAPTCHA v3 generates token
4. POST /api/helpdesk with form data + token
5. Flask verifies reCAPTCHA with Google
6. Flask calls Odoo REST API to create helpdesk.ticket
7. Success/error response returned to user
Component Architecture¶
Flask Application¶
# App Factory Pattern
app/
├── __init__.py # create_app() factory
├── config.py # Config from environment
├── routes/ # Blueprints
│ ├── main.py # MainBlueprint: /, /services, /about
│ ├── estimate.py # EstimateBlueprint: /free-estimate, /api/estimate
│ └── helpdesk.py # HelpdeskBlueprint: /helpdesk, /api/helpdesk
└── services/ # Business logic
├── recaptcha.py # verify_recaptcha(token)
└── odoo_api.py # OdooAPI.create(), OdooAPI.search()
Template Inheritance¶
base.html
├── index.html
├── services.html
├── about.html
├── estimate.html
└── helpdesk.html
components/
├── header.html # Navigation
├── footer.html # Footer with contact info
├── hero.html # Hero section
└── forms.html # Form macros (input, textarea, etc.)
CSS Architecture¶
static/css/
├── style.css # Compiled Tailwind output
└── themes/
├── blue.css # --color-primary: #1e40af
├── slate.css # --color-primary: #334155
└── earth.css # --color-primary: #78350f
Theme is selected via THEME environment variable and loaded in base.html.
Docker Integration¶
The landing page runs as a Docker container in the main stack:
# docker-compose.yml
landing:
build:
context: ./landing-page
dockerfile: Dockerfile
environment:
- THEME=${LANDING_THEME:-slate}
- ODOO_BASE_URL=http://odoo:8069
- RECAPTCHA_SITE_KEY=${RECAPTCHA_SITE_KEY}
# ... other env vars
depends_on:
- odoo
healthcheck:
test: ["CMD", "python", "-c", "...urlopen('http://localhost:8001/health')"]
Security¶
- reCAPTCHA v3: Invisible bot protection on all forms
- HTTPS: SSL termination at Nginx
- No Direct DB Access: All data goes through Odoo REST API
- API Key Auth: Odoo API key for authenticated requests
- Input Validation: Client-side (Alpine.js) + Server-side (Flask)