#What it is
Fabriq is a data fabric for Go: one transactional write path that fans out to relational, time-series, vector, graph and search engines. It exists because an application that outgrows a single database usually grows a second write in the same handler, and that second write is where silent divergence starts.
#Three invariants
Everything else in the design follows from these, and each is enforced structurally rather than by convention.
- Every write emits exactly one versioned event. A command runs in a Postgres transaction that applies state, appends the event and inserts an outbox row. A leader-elected relay, woken by LISTEN/NOTIFY, publishes it to Redis Streams in order.
- Every access is tenant-scoped. Tenant rides on context.Context and is stamped into each engine the way that engine can enforce: Postgres SET LOCAL plus row-level security, a FalkorDB graph per tenant, Elasticsearch index routing, Redis key prefixes. A pre-query hook is a loud backstop, not the mechanism.
- Projections are rebuildable from Postgres. The knowledge graph and the search index are derived. Nothing writes to them except an applier reading the log, so both can be dropped and replayed.
#What is implemented
All of the following has integration coverage:
- Command plane and outbox: registry-driven commands, optimistic concurrency, atomic batches.
- Postgres as source of truth: RLS verified as a non-superuser, Timescale hypertables for bulk telemetry, pgvector with HNSW for similarity, and PostGIS for geometry with GiST-accelerated Within queries (SRID 4326 resolves to true metres).
- Dynamic entities: entities defined at runtime from a schema descriptor rather than a Go struct, with fabriq-managed DDL, map-native reads and writes over real typed columns, and the full projection pipeline. It is a fenced, opt-in lane so the migrations-as-authority discipline stays intact for everything else.
- Redis Streams fan-out: consumer groups with XAUTOCLAIM recovery, plus a subscription hub with delta conflation, SSE and Last-Event-ID resume.
- Live queries: a filter/sort/limit subscription returns a snapshot then exact enter, leave, move and update deltas. The in-engine window stays an exact prefix of the Postgres-ordered result through a cushion and keyset boundary refill, so top-N is exact at all times.
- Graph projection: an openCypher dialect behind a conformance suite that acts as the engine-swap gate, a batched traverse-and-hydrate, and blue-green rebuilds verified to produce an identical graph.
- Search projection: version-gated bulk writes, lazy per-tenant index and alias provisioning, and atomic alias-swap rebuilds.
- Reconciler: per-aggregate drift detection between Postgres and the projections, classified as missing, stale or zombie.
#Operating it
cmd/fabriq is the whole fabric in one binary. serve runs the worker (outbox relay, projection consumers, reconciler and document plane), and migrate, rebuild, reconcile and inspect are the operator commands.
The property worth the complexity is not exactly-once delivery. It is that dropping a projection entirely is a routine operation rather than an incident.