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 withpgcrypto and pgvector extensions. Schema is managed by sqlx migrations.
  • Models — Local Ollama by default, cloud providers (Anthropic, OpenAI) opt-in via env.

Request lifecycle (analyse a note)

  1. Browser POSTs /v1/analyses with note ID + auth cookie.
  2. Axum middleware validates PASETO, double-submit CSRF, RBAC role.
  3. Handler reads note via parameterised SQL; pgcrypto decrypts in DB.
  4. PHI is scrubbed/de-identified before the LLM prompt is built.
  5. LLM is called (Ollama local or cloud); response is JSON-validated.
  6. Result is written back, audit log row appended (hash-chained).
  7. 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.