- 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)
1.7 KiB
1.7 KiB
ADR-0005: Protocol Buffers for event schemas, OpenAPI for HTTP
Status
Accepted — 2026-04-13
Context
Two contract surfaces exist:
- HTTP — synchronous, client ↔ server, human-readable debugging matters. OpenAPI is the default and generates decent TS clients.
- 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;
reservedfor removed fields; newschema_versionfor 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.