Skip to main content
Version: main 🚧

Phase 1 Data Model: data_source → knowledge_base inheritance

The "data model" here is the OpenFGA authorization model (object types, relations, derived permissions, and the tuples that wire them). No application database schema changes.

Object types & relations

knowledge_base (parent — unchanged)

RelationTypeMeaning
ownerdirect: user, service_accountCreator/owner of the KB.
readerdirect: user, user:*, service_account, team#member, team#admin, external_group#member, slack_channel, webex_spaceCan read/search. user:* = public.
ingestordirect: user, service_account, team#member, team#admin, external_group#memberCan ingest/update content.
managerdirect: user, service_account, team#admin, organization#adminCan administer/delete.
auditordirect: user, service_account, team#adminRead audit.
can_readreader or can_ingest or can_manage or ownerDerived.
can_ingestingestor or can_manage or ownerDerived.
can_managemanager or ownerDerived.

Grants are written here. This is the single source of truth for who-can-do-what on a datasource.

data_source (component — CHANGED)

RelationTypeMeaning
parent_kb (new)direct: knowledge_baseWires this datasource to its KB for inheritance. Exactly one per datasource (1:1 today).
ownerdirect: user, service_accountDirect component owner (rare).
readerdirect: user, user:*, service_account, team#member, team#admin, external_group#memberDirect component read (rare; usually inherited).
ingestordirect: user, service_account, team#member, team#admin, external_group#memberComponent-only ingest (the reason the type exists — Story 3).
managerdirect: user, service_account, team#admin, organization#adminDirect component manage (rare).
auditordirect: user, service_account, team#adminRead audit.
can_readreader or can_manage or owner or **can_read from parent_kb**Derived; inherits KB read.
can_ingestingestor or can_manage or owner or **can_ingest from parent_kb**Derived; inherits KB ingest.
can_deletecan_manageDerived (unchanged).
can_managemanager or owner or **can_manage from parent_kb**Derived; inherits KB manage.
can_discover, can_use, can_write, can_auditunchanged derivations

Only the three can_* derivations gain a ... from parent_kb branch and the new parent_kb relation is added. Direct relations are retained verbatim so component-only grants and any non-KB-backed datasource still work.

Relationships

user / team#member / team#admin / external_group#member / user:*
│ (reader | ingestor | manager | owner) ← grants written HERE

knowledge_base:<id>

│ parent_kb ← one structural tuple per datasource
data_source:<id>
│ can_read / can_ingest / can_manage = direct ∪ (inherited from parent_kb)

enforced by: BFF data_source#read filter + RAG server inject_kb_filter

Tuples

Structural (new, one per datasource):

data_source:<id>  parent_kb  knowledge_base:<id>

Access (written on the KB — unchanged shapes):

team:<slug>#member  reader     knowledge_base:<id>
team:<slug>#member ingestor knowledge_base:<id>
team:<slug>#admin manager knowledge_base:<id>
user:<sub> owner knowledge_base:<id>
user:* reader knowledge_base:<id> # public (inherited by the datasource)

Component-only (optional, direct on data_source — Story 3):

team:<slug>#member  ingestor   data_source:<id>          # ingest without KB read

Validation / invariants

  • INV-1: Each data_source:<id> has exactly one parent_kb edge (1:1 with its KB) after backfill. Datasources with no KB (none today) simply have no edge and rely on direct tuples.
  • INV-2: data_source:<id>#can_readknowledge_base:<id>#can_read (inheritance never narrows KB access).
  • INV-3: A direct ingestor on data_source:<id> with no KB read grant yields can_ingest = true, can_read = false (component-only ingest is expressible — Story 3).
  • INV-4: Removing a KB-level grant removes the inherited datasource permission with no separate data_source delete (FR-008).
  • INV-5: Backfill is additive + idempotent; running it twice changes nothing (US2).

State transitions

EventTuple effect
Datasource createdWrite data_source:<id> parent_kb knowledge_base:<id> (replaces the old access dual-write).
Team granted KB read/ingest/adminWrite KB grant only; datasource access follows by inheritance.
Team grant revokedDelete KB grant only; inherited datasource access disappears.
Datasource made publicWrite user:* reader knowledge_base:<id> (inherited).
Datasource un-publishedDelete user:* reader knowledge_base:<id>.
Datasource deletedDelete parent_kb edge + any direct data_source tuples (FR-010).