- 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)
28 lines
1.7 KiB
Markdown
28 lines
1.7 KiB
Markdown
# 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. |