# continuum-schemas Single source of truth for the Continuum data model. Everything here is JSON Schema, compiled into two consumer packages: - `packages/ts-types` - hand-written [TypeBox](https://github.com/sinclairzx81/typebox) schemas under `src/schemas/` used for runtime validation in `continuum-backend`'s ElysiaJS routes. - `packages/rust-types` - a Rust crate (`continuum-rust-types`) with hand-written, `serde`-derived structs for `continuum-proxy` and `continuum-ai-worker`. ## Layout ``` schemas/continuum/v1/ Continuum's own model ai/ continuum-backend <-> continuum-ai-worker: the stream:camera_frames work queue and the channel:print_alerts notification channel edge/ continuum-backend <-> continuum-proxy: the /ws/edge/v1 gateway uplink protocol material/ printer/ domain objects vendor.schema.json schemas/bambulab/ Bambu Lab MQTT wire schemas (v1/v2, report + request) packages/ts-types/ TypeBox schemas (hand-written, mirrors schemas/) packages/rust-types/ serde structs (hand-written, mirrors schemas/) ``` The two inter-service protocols - `edge/` and `ai/` - are here for a specific reason: each has two independent implementations, one per repo, and when there was nothing written down between them they drifted completely while every test passed. `/ws/edge/v1` had an `auth` handshake the gateway never sent; `stream:camera_frames` had a producer writing `printerId` and a consumer reading `printer_id`, so every frame was attributed to a printer called "unknown". Neither failure was visible from either side alone, which is what a canonical schema plus a contract test on each end is for. `schemas/continuum/v1/*.schema.json` is the canonical shape for each domain object; `packages/ts-types/src/schemas/` and `packages/rust-types/src/lib.rs` both mirror it by hand. A mirror is added per schema only once something actually consumes it, so not every file here has one, and the two inter-service protocols keep their Rust mirror in the single repo that consumes it rather than in `packages/rust-types`: `edge/` in `continuum-proxy/src/uplink/protocol.rs`, `ai/` in `continuum-ai-worker/src/task.rs`. The set is small and changes slowly, which is why keeping hand-synced copies in sync is less overhead than a codegen pipeline (`protoc`/`ts-proto`/`prost-build`) nothing actually consumed - see git history for the protobuf version this replaced, and why it was dropped: every service in this system talks JSON (JSON Schema for the wire, TypeBox/serde for runtime validation), so protobuf's actual value - a single schema compiled into a compact **binary** wire format for both languages - never applied. Whenever a domain schema changes, update all three by hand: the JSON Schema file, the TypeBox schema, and the Rust struct. ## Build / verify Requires `npm install` at the repo root, and a Rust toolchain, first. ``` npm install npm run build:rust # cargo build, confirms the Rust structs compile npm run typecheck # tsc -b, confirms the TypeBox schemas compile ``` There's no `build:ts` step - the TS side is hand-written, not generated.