How the Orbis tables fit together · 2026-04-24
Every paying customer is a tenant. Each tenant gets their own database, their own worker, their own WhatsApp number. A shared orbis-admin control plane keeps track of all of them but never holds a tenant's conversation data.
Every tenant DB has the same core schema plus one vertical overlay. Zero cross-tenant data. Zero shared tables between customers.
Three stacked layers. The bottom is universal, the middle is industry-specific, the top is bespoke. A tenant can opt out of the upper two — a plain Orbis with zero verticals works fine.
orbis_state.events (with kind), tracks in-flight state → workflow_state, stores flags/caches/dedup → orbis_kv. No new bespoke tables. Enforced by review + lint hook. See docs/orbis-schema-discipline.md.
One table — contacts — is the canonical person record. Everywhere else in the schema where a person appears, the table holds a contact_id pointing back at contacts.id. No parallel users table. No WhatsApp LID stored as identity anywhere.
users table. Phone is the canonical identifier for routing. WhatsApp LIDs are never stored.
If you ever touch a person anywhere in the system — sending them a message, adding them to a deal, logging a meeting, booking a trip for them — it lands in contacts first. Everything else references.
A closer look at what sits in each box, with the columns that matter for understanding the FK relationships.
Every group chat is a walled garden. Knowledge shared inside a container stays in the container unless an explicit container_share audit trail is written. Orbis never silently crosses a boundary.
These tables only exist in tenants running the agency vertical. They sit on top of the core and reference contacts for every person.
nova-leon to orbis-dreamlink, schema upgraded in-flightusers rows auto-linked via phone / Slack / unambiguous name matchingcontact_id pointing to a real personcontact_id = NULL and sender_name; not deleted, not fake-attributedlid_jid column no longer exists anywhere in the new schema
Phase 2B — migrate knowledge, deals, PM, meetings, trust-layer data into orbis-dreamlink.
Phase 3 — flip the nine workers that currently read nova-leon to read orbis-dreamlink instead, one at a time, with dual-write windows.
Phase 4 — extract dreamlink-ops (agency PM/staff for Dashboard) and nova-db (travel product) out of orbis-dreamlink.
Phase 5 — drop nova-leon and provision the first external tenant (Gaku) against the proven architecture.