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.
3.8 KiB
ADR-039: Honker as SQLite Extension and Transport
Status
Accepted
Context
The hub architecture was designed around three separate infrastructure components:
- PostgreSQL — persistence (tables, queries, transactions)
- Redis — pub/sub transport for event-driven communication
- Application-level task queues — background job processing
This creates operational complexity (three services to deploy, monitor, and secure) and a dual-write problem: writing data to PostgreSQL and publishing events to Redis cannot happen in a single transaction. If the process crashes between the DB commit and the Redis publish, data and events become inconsistent.
Honker (@russellthehippo/honker-node) is a SQLite extension that adds Postgres-style NOTIFY/LISTEN semantics, durable event streams with per-consumer offsets, at-least-once work queues with retries and dead-letter handling, cron scheduling, advisory locks, and rate limiting — all within the same SQLite .db file.
Decision
@alkdev/storage uses Honker as its SQLite extension and transport layer. Honker provides:
- Database operations — SQLite with WAL mode, a bounded reader pool, and a single writer slot
- Ephemeral pub/sub —
notify()/listen()for fire-and-forget notifications within the DB transaction - Durable event streams —
stream()with per-consumer offset tracking for replay-safe delivery - Task queues —
queue()with at-least-once claims, retries, priority, delayed jobs, and dead-letter - Advisory locks —
tryLock()for leader election and exclusive access - Cron scheduling —
scheduler()for time-triggered operations
Drizzle ORM integrates with Honker via a thin session adapter (~100 lines) that wraps Honker's query()/execute() API inside Drizzle's SQLiteSession<'sync'> contract. No Drizzle fork required. The adapter exposes the Honker Database as $client on the Drizzle instance for direct access to pubsub/queue features.
Consequences
Positive:
- Transactional consistency:
INSERT INTO nodesandqueue.enqueue()commit atomically. No dual-write problem. - No Redis dependency: Honker's
stream()replaces Redis as the durable pub/sub transport - No PostgreSQL dependency: SQLite with Honker covers persistence + events + queues
- Operational simplicity: One
.dbfile contains everything — data, events, queues, schedules - Drizzle integration: Full Drizzle type safety for queries + Honker for pubsub/queue on the same connection
- Ecosystem fit: The @alkdev platform is event-driven. Honker's durable streams with per-consumer offsets map directly to
@alkdev/operations' call protocol events and@alkdev/flowgraph's event-sourced model
Negative:
- Single-machine: Honker is a single-process SQLite extension. No cross-server events. For multi-node deployment, a separate transport (Redis, NATS) would still be needed for internode communication.
lastInsertRowidoverhead: Honker'sexecute()returns only affected row count. GettinglastInsertRowidrequires an extraSELECT last_insert_rowid()call via napi, or a small Rust addition to honker-node's Transaction class.- No prepared statement handles at JS level: Every Drizzle query goes through
query(sql, params). Mitigated by honker-core'sprepare_cachedon the Rust side. - Honker is alpha software: Not yet beta-quality. API may change. Risk mitigated by the thin adapter — if Honker's query API changes, only the adapter needs updating.
References
- Honker source:
/workspace/honker/ - Honker Node binding:
/workspace/honker/packages/honker-node/ - ADR-038: SQLite-first, Postgres removed
- ADR-004: Injectable clients, no side effects (Honker client is injectable)
@alkdev/operationscall protocol architecture@alkdev/pubsub— Honker may replace or supplement the Redis transport