Schema ERD
Synced from
docs/generated/erd/— do not hand-edit.
Regenerate withbun run docs:erd(needs staging reader), then this script runs automatically.
Labels:docs/db/erd-table-labels.yml· Runbook:docs/runbooks/erd-schema-docs.md
GENERATED — DO NOT HAND-EDIT. Regenerated from the live staging schema by tbls. Hand edits will be overwritten on the next run. Exception for humans: edit labels in
docs/db/erd-table-labels.yml, then regenerate.How the system works (durable runbook):
docs/runbooks/erd-schema-docs.md
Coverage (full schema — not a sample)
Section titled “Coverage (full schema — not a sample)”tbls always introspects the full public schema on live staging. What is committed to git is a git-friendly subset (GitHub rejects PR diffs over ~300 files):
| In git | Contents |
|---|---|
| Domain viewpoints | 8 × viewpoint-*.md with Mermaid ERs |
| Labeled table pages | Tables in erd-table-labels.yml (full column/FK docs + Description) |
| SCHEMA_INDEX.md | Complete list of every public table from the last run |
| This README | Naming traps + how to regen |
Full local tree (all public.*.md pages): ERD_KEEP_ALL_TABLES=1 bun run docs:erd
- Customer help (
help/) and PLATFORM.md are separate systems — not generated here.
How to regenerate
Section titled “How to regenerate”bun scripts/generate-erd.ts# orbun run docs:erdRequires:
tblson PATH (brew install tbls)- Staging reader credentials (SELECT-only + BYPASSRLS):
- macOS Keychain item
memberos-db-reader-staging, or - env
MEMBEROS_DB_READER_URL_STAGING
- macOS Keychain item
- See
docs/runbooks/db-reader-role.mdfor provisioning
Faithfulness / trust
Section titled “Faithfulness / trust”| Attribute | Value |
|---|---|
| Tier | Tier-1 deterministic — HIGH trust |
| Source | Live staging Postgres via direct reader connection |
| Tool | tbls (schema introspection → Markdown + Mermaid) |
| Environment | Staging only — never production |
| Link mode | Link-free — never supabase link; uses resolveReaderUrl("staging") |
| Role | memberos_reader — SELECT-only + BYPASSRLS |
| Labels | Curated in docs/db/erd-table-labels.yml (survives regen) |
This is machine truth of the current staging schema, not aspirational design docs.
If generated docs disagree with prose in docs/analysis/ or issue comments, the live schema wins for “what exists today.”
Labels do not change the schema — they only disambiguate names for human readers.
Naming traps (durable labels)
Section titled “Naming traps (durable labels)”Curated disambiguation for tables whose names look alike. Source of wording:
docs/db/erd-table-labels.yml — edit that file, then re-run
bun run docs:erd. Labels are injected into each table page as tbls comments and listed here.
public. is a schema name, not “world-readable”
Section titled “public. is a schema name, not “world-readable””The public. prefix on every table is the Postgres schema name (Supabase
default for app data) — not “world-readable.” Isolation is RLS + role
grants (anon has no SELECT on business tables). Almost every MemberOS
business table is public.<name>.
Table labels
Section titled “Table labels”| Table | Label | Not to be confused with | See |
|---|---|---|---|
commerce_products |
Sellable SKU catalog (platform / association / org-owned products) | Chamber member benefit definitions; external product keys | docs/decisions/2581-modules-vs-entitlements-vs-rls.md |
commerce_entitlements |
Plan / agreement commercial limits (seats, quota, access windows) | Chamber member benefit allocations (see member_entitlements) | docs/decisions/2581-modules-vs-entitlements-vs-rls.md |
member_entitlements |
Chamber member benefit allocations (quantity + usage per benefit) | Commerce plan limits (see commerce_entitlements); anchors benefit_definitions | — |
member_product_entitlements |
External product provisioning (e.g. Bullseye access by product_key) | Commerce SKUs; chamber benefit ledger | — |
entitlements |
Legacy / sponsorship-fulfilment entitlement rows (not the platform commerce ledger) | commerce_entitlements (ADR 2581 explicitly distinguishes these) | docs/decisions/2581-modules-vs-entitlements-vs-rls.md |
benefit_definitions |
Catalog of chamber benefits that member_entitlements allocate | commerce_products (sellable SKUs) | — |
members |
Member identity hub row (org-scoped); satellites hold profile/billing/metrics | Full member payload — write profiles/billing/metrics to their tables | docs/PLATFORM.md |
member_profiles |
Member profile satellite (name, contact fields, etc.) | members identity hub; no org_id on satellite — RLS scopes via member | — |
member_billing |
Member billing satellite | commerce_entitlements / plan limits ledger | — |
member_metrics |
Member metrics / engagement satellite | Billing or entitlements | — |
contacts |
Person identity (auth-linked via contact_auth); used across CRM and membership | A member by itself — membership is members + org seat | — |
“Entitlement” — three different concepts
Section titled ““Entitlement” — three different concepts”| Table | Means |
|---|---|
commerce_entitlements |
Plan / agreement commercial limits (seats, quota, access) |
member_entitlements |
Chamber member benefit allocations (via benefit_definitions) |
member_product_entitlements |
External product provisioning (e.g. Bullseye by product_key) |
entitlements (bare) |
Separate legacy/sponsorship-style ledger — not the commerce one (ADR #2581) |
Domain viewpoints
Section titled “Domain viewpoints”Human-oriented slices aligned to docs/analysis/SYSTEMS-CATALOG.md.
Each viewpoint has its own Mermaid ER and table list (see files named viewpoint-*.md).
| Viewpoint | Focus |
|---|---|
| Identity, Tenancy & RBAC | orgs, contacts, contact_auth, organization_users, rbac_* |
| Membership & Billing | members split-payload, tiers, commerce, billing_*, entitlement naming traps |
| CRM & Tasks | companies, prospects, tasks, feedback, committees |
| Events & Registration | chamber_events, registrations, tickets, signature_events |
| Communications & Journeys | email_*, campaigns, journeys, playbooks |
| Website, Funnels & Public | website_, funnels, exchange_, hot_deals |
| Sponsorships | sponsorships, offerings, sponsor placements |
| Platform Catalog & Modules | permission_catalog_*, modules, autonomy lanes |
First review target (Nathan / Craig)
Section titled “First review target (Nathan / Craig)”Start with the members / member_profiles / member_billing / member_metrics / contacts cluster:
- Viewpoint: Membership & Billing → group “Member core (split payload)”
- Individual tables: members, member_profiles, member_billing, member_metrics, contacts
Then the entitlement naming trap groups on the same viewpoint: commerce plan limits vs member benefits vs external product provisioning.
Constraints (do not violate)
Section titled “Constraints (do not violate)”- Never run
supabase linkin the repo cwd for this pipeline. - Never point this at production credentials.
- Never commit connection strings, passwords, or resolved DSNs.
- Output stays under
docs/generated/erd/only. - Table lists in
.tbls.ymlviewpoints must match real public tables (verified againsttypes.ts/ staging). - Edit labels in
docs/db/erd-table-labels.yml, not underdocs/generated/.
Doc-vs-reality questions
Section titled “Doc-vs-reality questions”If something here looks wrong, incomplete, or surprises you:
→ Ask Carson (maintainer lane). Do not “fix” the schema from these docs; open a DB Request or staging investigation instead.
Config source
Section titled “Config source”- tbls config:
.tbls.ymlat repo root - Labels:
docs/db/erd-table-labels.yml - Generator:
scripts/generate-erd.ts - Full table list: SCHEMA_INDEX.md
- Generated at:
2026-07-27T16:06:01.944Z - Environment: staging
- Epic: #3626 · Issue: #3627 (DOC-1)

