Files
storage/docs/architecture/decisions/045-org-members-authoritative-belongsto-derived.md
glm-5.1 6aa2fcc6ff Architect storage around SQLite+Honker: remove PG, add multi-tenant identity, scoping
Reorient @alkdev/storage around a single SQLite database host with Honker
for pub/sub, event streams, and task queues. PostgreSQL is removed as a
target (ADR-038), eliminating dual schema maintenance and infrastructure
complexity. Honker provides DB + pubsub + queues in one .db file (ADR-039).

Add system/tenant DB model (ADR-040): identity tables in system.db, all
graph data in tenant-{orgId}.db files. Identity tables move from the hub
into storage (ADR-041). Scoping columns (ownerId, projectId) added to
graphs table (ADR-042). Graph types get scope (system/tenant/user) to
protect infrastructure schemas (ADR-043).

Define Drizzle-Honker session adapter (ADR-044): ~100-line adapter enabling
Drizzle typed queries and Honker pubsub/queue on a single connection with
transactional consistency.

Resolve OQ-03, OQ-04, OQ-19, OQ-21, OQ-22, OQ-23, OQ-24. Add new
open questions OQ-26 through OQ-29 for Honker integration specifics.

New docs: honker-integration.md (adapter, event patterns, migration).
Scrub all PG/jsonb/libsql references from existing spec docs.
2026-05-31 15:41:41 +00:00

42 lines
1.9 KiB
Markdown

# ADR-045: Organization Members as Authoritative SQL Table, BelongsToEdge as Derived
## Status
Accepted
## Context
OQ-23 asked whether `BelongsToEdge` in the ACL graph should be derived (materialized from `organization_members`) or primary (ACL graph is the source of truth).
The ACL graph needs `BelongsToEdge` for traversal-based permission evaluation (ADR-034). The hub needs `organization_members` for fast SQL lookups ("list all members of org X", FK constraints on cascading behavior).
Two sources of truth for the same data creates a consistency risk.
## Decision
`organization_members` is the authoritative SQL table. `BelongsToEdge` in the ACL graph is derived.
When org membership changes, the consumer (hub) writes to `organization_members` first, then creates or removes the corresponding `BelongsToEdge` in the ACL graph instance. The ACL edge mirrors the SQL table; it does not define it.
If the two fall out of sync, the SQL table is the source of truth. An audit/reconciliation process can re-derive ACL edges from the SQL table.
## Consequences
**Positive:**
- Clear authority — one write path for membership, one derived read path for ACL traversal
- FK constraints on `organization_members` work (cascade delete when org or account is removed)
- Fast indexed lookups for membership lists — no graph traversal needed
- ACL evaluator can still traverse `BelongsToEdge` for permission resolution
- Reconciliation is straightforward — scan `organization_members`, compare against ACL edges, fix discrepancies
**Negative:**
- Dual-write contract — the consumer must write both places. If the ACL edge write fails after the SQL write, they're out of sync.
- The ACL graph is not self-contained for org membership — it depends on an external table
## References
- ADR-034: ACL as metagraph
- ADR-041: Identity tables in storage package
- OQ-23: BelongsToEdge derivation (now resolved)