Pillar 8 · Events: bus, outbox and webhooks
Parent: key-designs
Status: released in v0.1.76 (2026-09-27) — design and as-built record in docs/design/event-bus-outbox-webhooks.md in the StandMeet repo.
Every "after X, also do Y" in StandMeet used to be hand-wired at its call site: coupled to it, not durable (a restart lost it), and invisible when it failed. This pillar gives all of them one path: an event committed in the same transaction as the change it describes (the outbox), fanned out by a relay into durable jobs on the Postgres we already run, consumed by in-process subscribers and, outside the instance, by signed webhooks. The embed update hook that lets standmeet.com follow the corpus is one consumer of it.
Children
The model
- event-model — an event is a string type plus JSON, declared once as data;
Exposuredefaults to internal; 39 types are declared. - two-sources-of-events — row facts captured by database triggers; semantic facts recorded explicitly.
- relay-claims-rows-not-cursor — a relay loop in every process claims unfanned rows with
SKIP LOCKED; a sequence cursor loses events; coalescing is opt-in per subscription. - queue-behind-ports —
Recorder, andJobs/Inspector/Runtime; River today, swappable without upper layers noticing. - code-structure — packages, the transaction passed to the use case as an explicit parameter (never in
ctx), zero-glue subscribers. - why-not-a-broker — why not Kafka, RabbitMQ or Redis/Bull.
Outward
- webhooks — thin, signed (Standard Webhooks), scoped by the single ACL predicate, one delivery in flight per endpoint.
- embed-update-hook — the corpus tells its embeds; how standmeet.com follows it without a deploy.
Behaviour under async
- async-response-contract — a response promises only what is committed; receipts for the rest.
- completion-hooks — a finished job sends a notification; the four callers that wait for results.
- message-loss-guarantees — a guarantee per hop; nothing is lost silently.
- retry-has-one-owner — the job layer retries; handlers only classify failures.
- concurrency-control — bounded, time-limited, stoppable workers; no network call inside a transaction.
- storage-bounds — every way storage can run away has a hard limit and is visible.
- saturation-degrades-gracefully — under saturation: slow down, queue, alert.
- tasks-panel — the queue, periodic jobs, event stream and deliveries, visible in admin.
Keeping it that way, and getting there
- no-bypass-by-structure — the request path holds no side-effect capability; seven gates keep it so.
- consolidation-inventory — all 101 items found in the sweep and where each landed.
- events-test-plan — the UT suites and the 11 new e2e specs that exist, regression, and the final all-green acceptance.
- events-roadmap — phases P0–P5 and their status, and the decisions of 2026-09-26.
Related pillars: structure (the layering and guardrails this extends), monitor (whose in-memory job list the Tasks panel replaced), embed-credential-never-carries-the-code (the embed the update hook attaches to).