Architecture
CRIE is a small, well-bounded set of services connected over a single REST/JSON API. The boundary between PHI and non-PHI is enforced at every layer.
Services
- Web (
apps/web) — Next.js 14 App Router, React 18, Tailwind, R3F for the 3D background. Server-rendered shell with React Query on the client. Talks only to the API. - API (
services/api) — Rust + Axum. Owns sessions, RBAC, validation, audit, the LLM bridge, and all domain logic. - Database (
db/) — PostgreSQL 17 withpgcryptoandpgvectorextensions. Schema is managed by sqlx migrations. - Models — Local Ollama by default, cloud providers (Anthropic, OpenAI) opt-in via env.
Request lifecycle (analyse a note)
- Browser POSTs
/v1/analyseswith note ID + auth cookie. - Axum middleware validates PASETO, double-submit CSRF, RBAC role.
- Handler reads note via parameterised SQL; pgcrypto decrypts in DB.
- PHI is scrubbed/de-identified before the LLM prompt is built.
- LLM is called (Ollama local or cloud); response is JSON-validated.
- Result is written back, audit log row appended (hash-chained).
- Signed JSON response returned; web caches with React Query.
Data classification
- Class A — direct PHI:
patients.*_enc,clinical_notes.body_enc. Encrypted, RLS-restricted, audited on every touch. - Class B — derived PHI: analysis output, alerts, predictive scores. Linked to a patient ID, RLS-restricted.
- Class C — operational: users, audit log, migration history. No patient identifiers; safe to log opaque IDs.
Deployment
The repo ships with Coolify-ready Dockerfiles and a docker-compose file for local development. Migrations run as a post-deploy step; the API refuses to start unless the schema is at the required version. See infra/coolify/ for the full topology.
