Skip to content

Multi-tenancy

One deployment serves many clients. The tenant is resolved by hostname; everything client-specific hangs off that.

flowchart LR
  H[request host] --> R[_tenant.js resolveTenant]
  R --> J[tenants/&lt;slug&gt;.json<br/>branding · gateCodes · odooEnv]
  J --> BR[brand.js themes the page]
  J --> CAT[api/catalog serves that catalogue<br/>+ live Odoo prices]
  J --> SEC[getTenantSecrets → ODOO_URL_&lt;ENV&gt; …]
  SEC --> LEAD[api/lead → _odoo push to THAT tenant's Odoo]
Aspect Where Secret?
Branding (logo, colour, title, tagline) tenants/<slug>.jsonbrand no — in Git
Hosts that map to the tenant tenants/<slug>.jsonhosts no
Access codes tenants/<slug>.jsongateCodes no
Product catalogue tenants/<slug>/catalog.js no
Logo image tenants/<slug>/logo.png no
Odoo / CRM credentials Vercel env, keyed by odooEnv yes — never in Git
{
"slug": "duratray",
"name": "Duratray",
"hosts": ["duratraydemo.goask.com.au", "duratray3dconfig.vercel.app"],
"brand": {
"title": "Duratray 3D Configurator",
"logo": "/tenants/duratray/logo.png",
"accent": "#E54441",
"accentDark": "#c23a37",
"tagline": "Complete Traybody Solutions",
"legal": "Duratray"
},
"gateCodes": ["demo"],
"odooEnv": "DURATRAY"
}

Per-tenant Odoo credentials live only in Vercel env vars, keyed by the tenant’s odooEnv:

ODOO_URL_<ENV> ODOO_DB_<ENV> ODOO_USER_<ENV> ODOO_PW_<ENV>

getTenantSecrets() reads these, falling back to the unsuffixed ODOO_URL etc. for local single-tenant dev.

Tenant Domain Odoo
Oz Chivalry ozchivalrydemo.goask.com.au ozchivalry-odoo.up.railway.app
Duratray duratraydemo.goask.com.au ❌ not yet (branding + catalogue only)

To add a new one, see Add a tenant — it is data + config only, no code change.