08 — Event System
Deep dive on the eventing backbone as a product surface. The internal bus already exists (ADR-0006 outbox + NATS); this exposes it as change feeds, webhooks, and the trigger source for Functions — the nervous system of the programmable platform.
1. The event backbone, productized
flowchart TB
classDef s fill:#fde68a,stroke:#b45309,color:#111827;
classDef b fill:#fbcfe8,stroke:#be185d,color:#111827;
classDef o fill:#bbf7d0,stroke:#15803d,color:#111827;
src["domain mutations → transactional outbox (ADR-0006)"]:::s --> bus{{"NATS JetStream"}}:::b
bus --> feed["Change-feed / stream API (cursor-based)"]:::o
bus --> hook["Signed webhooks (retried, DLQ)"]:::o
bus --> fn["Functions triggers (01 §2)"]:::o
bus --> audit["Audit lake + SIEM export"]:::o
bus --> notif["in-app / email notifications"]:::o
All five consumers ride one outbox-sourced, at-least-once, idempotent bus (ADR-0006) — no new core infra, just exposed surfaces.
2. Sub-features
EV-1 — Change-feed / event-stream API
- Subscribe to a tenant’s namespace events (created/updated/moved/deleted/shared) as a cursor-based stream — the same cursor mechanics as sync (sync/07), so it’s resumable and ordered. BitVault’s analog of S3 Event Notifications / EventBridge.
| Why | Complexity | Dependencies | Resume |
|---|---|---|---|
| lets external systems react to file activity; integration backbone | M | bus (ADR-0006), cursor design (ADR-0024) | Medium-high |
EV-2 — Signed webhooks
- Per-tenant HTTP endpoints receive HMAC-signed, retried (backoff + jitter), DLQ‘d, replayable event deliveries; idempotency keys for safe redelivery.
| Why | Complexity | Dependencies | Resume |
|---|---|---|---|
| the universal integration primitive; expected of any platform | S–M | bus, delivery worker | Medium (signing + reliable delivery details) |
EV-3 — Event catalog & schema (Published Language)
- A versioned, typed event catalog (the Published Language from 04 bounded-contexts) generated from protobuf (ADR-0003) — stable contracts consumers can rely on, with evolution rules (ADR-0015).
| Why | Complexity | Dependencies | Resume |
|---|---|---|---|
| makes the event surface trustworthy + non-breaking | S | proto/codegen (ADR-0003) | Low-medium |
EV-4 — Audit lake & SIEM export
- Stream all events to a customer’s SIEM (Splunk/Datadog/Elastic) and into the tamper-evident audit log (02 E2) — security teams get real-time, verifiable visibility.
| Why | Complexity | Dependencies | Resume |
|---|---|---|---|
| enterprise security/compliance integration | M | bus, transparency log (02) | Medium |
3. Design notes
- Lossy vs reliable, separated (same lesson as sync, ADR-0024): realtime notifications may be lossy; the change-feed pull is authoritative — so a dropped webhook never means lost state, just re-pull.
- At-least-once everywhere → all consumers idempotent (event id dedup); per-aggregate ordering preserved (ADR-0006).
- Tenant isolation on every stream/webhook (scoped subjects, ADR-0007).
Scaling: the notifier/webhook tier is stateless and NATS-sharded by tenant; webhook delivery is a bounded, retrying worker pool (sync/10); the change feed reuses the journal + cursor, so it scales with the (sharded) metadata store (storage/08).
Priorities within events
EV-2 (webhooks) + EV-1 (change feed) first — cheap on the existing bus, unlock all integration + Functions. EV-4 is the enterprise security tie-in; EV-3 is the contract hygiene that makes the rest safe.