Files
oO/docs/adr/0005-event-schemas-protobuf.md
alvis 7f173f88d3 refactor: architecture revision — modular monolith, auth-commit, event protobuf, privacy-from-day-0
- ADR-0003: modular monolith for Phase 0 with documented extraction triggers
- ADR-0004: Auth.js + OIDC-shaped boundary; dedicated provider when mobile ships
- ADR-0005: protobuf for events, OpenAPI for HTTP, schema-registry CI gate
- New architecture docs: data-model, metrics (magic proxies), privacy (Phase-0 feature)
- Prime directives updated: privacy-as-feature, modular-by-package-deployable-by-stage
- Roadmap revised: Apple OAuth deferred to M1; web push in M1; k3s intermediate; tip-kind-aware UI
- PLAN updated: Phase-0 deletion endpoint, metrics baseline, compose profiles, import-boundary lint
- License decision in README (ARR with OSS plan in Phase 5)
2026-04-13 14:36:11 +00:00

1.7 KiB

ADR-0005: Protocol Buffers for event schemas, OpenAPI for HTTP

Status

Accepted — 2026-04-13

Context

Two contract surfaces exist:

  1. HTTP — synchronous, client ↔ server, human-readable debugging matters. OpenAPI is the default and generates decent TS clients.
  2. Events — durable, fan-out to ML consumers, schema evolution critical. Feature pipelines trained on old schemas will silently misbehave when producers change a field.

Using OpenAPI for both means:

  • Python pydantic generation is awkward and hand-maintained in practice.
  • No wire-format discipline (JSON is loose).
  • No central schema registry, so schema drift is undetected until a model regresses.

Decision

  • HTTP contracts: OpenAPI 3.1 in packages/shared-types/http/. Generate TS clients; hand-write Python pydantic models for ML consumers (few, and they're shallow).
  • Event contracts: Protocol Buffers in packages/shared-types/events/. Generate TS and Python. All events carry an envelope: {event_id, occurred_at, schema_version, producer, payload}.
  • Schema registry: lightweight self-hosted (buf.build Schema Registry OSS or a tiny registry in events/). CI check blocks breaking changes without a version bump.
  • Evolution rules: additive only within a major version; reserved for removed fields; new schema_version for breaking changes; consumers advertise the versions they accept.

Consequences

  • One extra build step in shared-types (buf or protoc).
  • Breaking event changes cost something — good; they should.
  • ML pipelines can replay old events against new code with confidence.

Non-consequences

  • No gRPC. HTTP stays HTTP/JSON. Protobuf is only the wire format on the event bus.