Modules¶
Canopy is a modular monolith: one FastAPI application mounts independent sub-applications, each owning a single concern. Modules talk to each other through in-process gateways, so the whole platform runs as one API process (plus a background worker).
Mounted modules¶
| Mount | Module | What it does |
|---|---|---|
/hare |
Hare | Live-PV broker: WebSocket streaming, REST reads and writes |
/mole |
Mole | Archiver Appliance proxy for historical PV data |
/raccoon |
Raccoon | PV name-lookup proxy over the lab directory service |
/vole |
Vole | In-memory per-PV buffers merging Hare live data with Mole history |
/fox |
Fox | Formula engine — expressions over live and historical PV data |
/squirrel |
Squirrel | Machine-state snapshots: save, restore, and compare (Postgres-backed) |
/jobs |
Jobs | Background-job status over the Arq/Redis queue |
/converter |
Converter | Legacy screen converter — EDM .edl / Qt .ui to Canopy Screen IR |
Modules without a guide here yet are documented by their interactive API docs (below).
The top-level Swagger UI at /docs provides a dropdown to switch between
Canopy's core API and each mounted module. Each module's standalone Swagger UI
and OpenAPI schema remain available at /<module>/docs and
/<module>/openapi.json.
Conventions every module follows¶
URLs. APIs are versioned per module: /<module>/v1/.... Each module also
serves its own Swagger UI at /<module>/docs — with the API running, that is
the authoritative, always-current endpoint reference.
Authentication. Send an API key in the X-API-Key header. Read endpoints
need a key with the read scope, mutating endpoints need write. WebSocket
endpoints also accept ?api_key=<token> in the URL for clients that cannot
set handshake headers. See Getting started
for key registration.
Errors. Every error response uses one envelope:
{
"code": "pv_read_timeout",
"detail": "TEST:SINE: no response within 5.0 s"
}
code is a stable machine-readable slug; match on it rather than on detail
text or HTTP status alone.
JSON casing. Wire payloads use camelCase field names (tsNs,
valueKind, pvNames).
Health. Each module exposes two endpoints under /<module>/v1/health:
GET /<module>/v1/health/watchdog— liveness heartbeat (module, version, uptime). No auth, touches nothing external.GET /<module>/v1/health/summary— module status rollup (backend state, counters). Requires read access.
The root GET /health is a plain process-liveness check used by container
health probes.
Internal packages (not mounted)¶
These live in the same codebase but expose no HTTP API of their own:
- core — configuration, API-key auth, database sessions, the error envelope, time parsing.
- epics — the CA/PVA connector Hare speaks through. Ships two backends:
simulation(default; synthetic data, no network) andepics(real Channel Access / PV Access). Selected withCANOPY_EPICS__BACKEND. - contracts — shared DTOs used across modules (PV values, samples).
- worker — the Arq entrypoint (
canopy.worker.WorkerSettings) that runs background jobs for Squirrel and Converter.
Planned modules¶
- Owl — plot-configuration persistence + legacy importer.
- Wren — rules engine, hosted inside Hare.