Pivot: fold drizzlebox as utils, HonkerEventTarget, OperationSpecs as repo surface
- Update architecture docs to reflect pivot from @libsql/client to Honker - Fold @alkdev/drizzlebox Phase 0 into src/sqlite/utils/ (ADR-046) - Add HonkerEventTarget adapter for pubsub TypedEventTarget (ADR-047) - Replace hand-written CRUD with OperationSpec generation (ADR-048) - Resolved OQ-26: Honker replaces Redis for single-node pub/sub (POC validated) - Updated OQ-17, OQ-18, OQ-19 for OperationSpec repository surface - Added OQ-30 (composite event target), OQ-31 (consumer naming), OQ-32 (Drizzle Kit) - POC results: adapter buildable, same-process pub/sub works, transactional outbox semantics confirmed, concurrent listeners/streams work - Research doc at docs/research/pivot-honker-sqlite-adapter.md
This commit is contained in:
@@ -0,0 +1,74 @@
|
||||
---
|
||||
status: accepted
|
||||
date: 2026-06-01
|
||||
supersedes: ADR-033 (partially — OQ-17, OQ-18, OQ-19 updated)
|
||||
---
|
||||
|
||||
# ADR-048: OperationSpecs as Repository Surface
|
||||
|
||||
## Context
|
||||
|
||||
ADR-033 established JSON path queries with hand-written CRUD for v1. The
|
||||
question was whether the repository layer would be hand-written query
|
||||
functions, auto-generated from table definitions, or something else.
|
||||
|
||||
The `@alkdev/operations` package provides `OperationSpec` — a serializable
|
||||
descriptor for a query, mutation, or subscription operation. Hubs and spokes
|
||||
register specs in an `OperationRegistry` along with handlers. The operations
|
||||
runtime handles execution, call protocol routing, subscriptions, access
|
||||
control, and validation.
|
||||
|
||||
This presents a natural alternative to hand-written CRUD: storage outputs
|
||||
`OperationSpec[]` describing CRUD operations per table, and the consumer
|
||||
wires them into the operations registry.
|
||||
|
||||
## Decision
|
||||
|
||||
Storage does not ship a "repository layer" of hand-written query functions.
|
||||
Instead, it outputs `OperationSpec[]` per table — flat arrays describing
|
||||
CRUD operations. The consumer (hub/spoke) imports these specs, registers
|
||||
handlers, and the operations runtime handles execution.
|
||||
|
||||
```ts
|
||||
// Storage defines table + operation contracts
|
||||
export const graphTypes = sqliteTable("graph_types", { ... });
|
||||
export const graphTypeSpecs: OperationSpec[] = [
|
||||
{ name: "create", namespace: "graph_types", type: "mutation", ... },
|
||||
{ name: "find", namespace: "graph_types", type: "query", ... },
|
||||
{ name: "list", namespace: "graph_types", type: "query", ... },
|
||||
{ name: "update", namespace: "graph_types", type: "mutation", ... },
|
||||
{ name: "delete", namespace: "graph_types", type: "mutation", ... },
|
||||
];
|
||||
|
||||
// Hub registers specs + handlers
|
||||
for (const spec of graphTypeSpecs) {
|
||||
registry.registerSpec(spec);
|
||||
registry.registerHandler(`${spec.namespace}.${spec.name}`, handler);
|
||||
}
|
||||
```
|
||||
|
||||
The handler is consumer-provided. Storage defines the contract (input/output
|
||||
schemas, operation type); the hub provides the execution (Drizzle queries,
|
||||
Honker transactions, notifications).
|
||||
|
||||
`@alkdev/operations` is a type-only peer dependency of storage. No circular
|
||||
dependency.
|
||||
|
||||
## Consequences
|
||||
|
||||
- **No hand-written repository functions** — storage avoids the maintenance
|
||||
burden of typed CRUD code. The contract is the OperationSpec.
|
||||
- **Consumer owns execution** — the hub decides how to handle each operation
|
||||
(raw Drizzle query, with Honker notification, with access control, etc.).
|
||||
Storage doesn't execute queries.
|
||||
- **Subscriptions for free** — OperationSpec supports `type: "subscription"`.
|
||||
Table-level change streams become operation subscriptions rather than
|
||||
custom event handling.
|
||||
- **Clean dependency graph** — storage depends on operations only for the
|
||||
`OperationSpec` type (peer dep). No runtime dependency.
|
||||
- **Attribute queries remain JSON path** — for metagraph tables where
|
||||
attributes are dynamic JSON, `json_extract()` is still the query mechanism.
|
||||
Domain-specific tables with native columns produce simpler specs.
|
||||
- **Supersedes ADR-033 partially** — the "hand-written CRUD" part is replaced.
|
||||
The "JSON path queries for attributes" part still applies to metagraph
|
||||
tables.
|
||||
Reference in New Issue
Block a user