Skip to content

Schema ERD

Synced from docs/generated/erd/ — do not hand-edit.
Regenerate with bun 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

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.
Terminal window
bun scripts/generate-erd.ts
# or
bun run docs:erd

Requires:

  • tbls on PATH (brew install tbls)
  • Staging reader credentials (SELECT-only + BYPASSRLS):
    • macOS Keychain item memberos-db-reader-staging, or
    • env MEMBEROS_DB_READER_URL_STAGING
  • See docs/runbooks/db-reader-role.md for provisioning
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.

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 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)

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

Start with the members / member_profiles / member_billing / member_metrics / contacts cluster:

Then the entitlement naming trap groups on the same viewpoint: commerce plan limits vs member benefits vs external product provisioning.

  1. Never run supabase link in the repo cwd for this pipeline.
  2. Never point this at production credentials.
  3. Never commit connection strings, passwords, or resolved DSNs.
  4. Output stays under docs/generated/erd/ only.
  5. Table lists in .tbls.yml viewpoints must match real public tables (verified against types.ts / staging).
  6. Edit labels in docs/db/erd-table-labels.yml, not under docs/generated/.

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.

  • Generated at: 2026-07-27T16:06:01.944Z
  • Environment: staging
  • Epic: #3626 · Issue: #3627 (DOC-1)