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.
1.9 KiB
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_memberswork (cascade delete when org or account is removed) - Fast indexed lookups for membership lists — no graph traversal needed
- ACL evaluator can still traverse
BelongsToEdgefor 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)