Multi-Tenant Architecture¶
Each client (hotel, hospital) is an isolated organisation with its own users, DIDs, trunks, queues, and Asterisk dialplan contexts.
Tenant isolation¶
┌─ Organisation: GrandEstancia ──────────────────┐
│ context_prefix: org_mna9x47k_ │
│ DIDs: +918065978001, +918065978003 │
│ Users: ext 1001 (Hari), ext 0986 (Manivel) │
│ Queues: Reception (5001) │
│ Asterisk contexts: │
│ [org_mna9x47k__internal] ← extensions │
│ [org_mna9x47k__incoming] ← DID routing │
│ [org_mna9x47k__outbound] ← external calls │
│ [org_mna9x47k__queue] ← call queues │
│ Firestore: astrapbx/{org_id}/tickets/... │
│ Recordings: GCS bucket/org_id/... │
└─────────────────────────────────────────────────┘
┌─ Organisation: TechStart ──────────────────────┐
│ context_prefix: org_mnd5khym_ │
│ (completely isolated from GrandEstancia) │
│ Same extension numbers (1001) don't collide │
└─────────────────────────────────────────────────┘
Organisation data model¶
| Table | Scope | Purpose |
|---|---|---|
organizations | Global | Org name, API key, settings, limits |
users | Per-org | SIP extensions + credentials |
did_numbers | Per-org | Phone numbers + routing rules |
sip_trunks | Per-org | SIP provider connections |
queues | Per-org | Call queues + members |
org_users | Per-org | Platform login accounts (RBAC) |
org_compliance | Per-org | Retention policy, consent mode |
asterisk_cdr | Global | Call detail records (filtered by accountcode) |
audit_log | Per-org | Who did what, when |
Config generation¶
Each org's Asterisk config is generated by the AstraPBX API:
POST /api/v1/config/deploy
→ dialplanGenerator.js generates:
/etc/asterisk/pjsip_<orgname>.conf (endpoints, auth, AORs)
/etc/asterisk/ext_<orgname>.conf (dialplan contexts)
/etc/asterisk/queues_<orgname>.conf (queue definitions)
→ AMI: core reload (no call drops)
Resource limits¶
Each org has configurable limits enforced at API level:
max_users— SIP extensionsmax_dids— phone numbersmax_trunks— SIP connectionsmax_queues— call queuesconcurrent_calls— enforced in Asterisk dialplan viaGROUP_COUNT()