English | Русский
Evidence-first clinician-in-the-loop workflow control plane for structured case intake, bounded document and FHIR ingestion, physician-packet drafting, explicit review and finalization, and append-only auditability.
This repository is intentionally not an AI doctor, clinical decision engine, or general-purpose FHIR server. Its public scope is workflow support for clinician review, with claims kept narrower than the code, tests, and evidence currently support.
Anamnesis is designed as a narrow standalone slice for healthcare-adjacent workflow software. The project favors verifiable scope, explicit interoperability boundaries, and auditable state transitions over speculative medical or AI claims. In practice, that means the repository optimizes for truthful workflow assistance rather than diagnosis, treatment, triage, prescription logic, or inflated clinical positioning.
- structured case intake and case lifecycle APIs;
- workflow-family-aware case creation for general intake, MRI second-opinion, and mRNA board-review paths;
- owner-scoped visibility for JWT-created cases, with API-key operator access retained as the shared-secret admin path;
- revocable case sharing so a JWT case owner or API-key operator can grant or revoke another JWT principal's case access, while destructive case-admin actions remain owner-or-operator only;
- source artifact registration and removal with packet staleness tracking;
- derived artifact metadata carry-through plus a read-only evidence-lineage graph route for lineage-aware evidence bundles;
- molecular sample registration for case-scoped review workflows;
- imaging study-context attachment and QC-summary recording for second-opinion workflows;
- bounded text document ingestion for
text/plainandtext/markdown; - bounded FHIR-compatible import for inline
BinaryandDocumentReferenceresources carryingtext/plainortext/markdownpayloads; - bounded FHIR Bundle import for
documentandcollectionbundles, withdocumentbundles requiring aCompositionfirst entry plusidentifier.system,identifier.value, andtimestamp; - explicit, request-gated
attachment.urldereference overhttpswith public-target validation, redirect rejection, text-only response filtering, byte limits, and optional host allowlisting; - physician packet drafting from current case state;
- explicit clinician review ledger (
approved,changes_requested,rejected); - packet finalization only for clinician-approved, non-stale drafts;
- append-only audit trail, operations summary, and remote-JWKS operational observability;
- Bearer-token authentication via API key, HS256 shared secret, RS256 PEM public key, local kid-aware JWKS, or issuer-bound remote JWKS with cache-aware refresh; rate limiting, security headers, and graceful shutdown;
- durable SQLite persistence with AES-256-GCM encryption at rest.
- medical diagnosis;
- triage urgency scoring;
- treatment or prescription recommendations;
- clinical validation or regulatory clearance;
- general-purpose FHIR REST server behavior;
- SMART on FHIR authorization flows;
- imaging pixel-data ingestion, genomics file-transport pipelines, wearable ingestion, or OCR pipelines;
- EHR replacement.
Anamnesis adopts a reduced architectural kernel extracted from the broader MicroPhoenix platform, but only where the pattern improves clarity without inflating runtime complexity.
| Layer | Responsibility in this slice |
|---|---|
| Core | IDs, correlation, audit-event envelope, normalization-profile primitives |
| Domain | Case workflow, artifact model, bounded import parsing, physician packet and review rules |
| Application | HTTP routes, request validation, auth, rate limiting, metrics, error mapping |
| Infrastructure | SQLite stores, AES-256-GCM encryption, audit persistence, bounded external attachment fetch |
| Runtime chain | src/index.ts -> src/bootstrap.ts -> src/application/create-app.ts |
Key transfer principles from MicroPhoenix:
- one explicit composition root and one runtime chain;
- code, tests, docs, and evidence move together before a capability is promoted as real;
- adapters and bounded seams come before heavier platform machinery;
- public claims remain downstream of verified evidence, not upstream of ambition.
FHIR support exists only as a bounded import seam into workflow artifacts. The repository does not expose generic FHIR CRUD, search, transactions, history, subscriptions, messaging, or /metadata capability discovery.
Supported now:
- inline
Binarywithtext/plainortext/markdownpayloads; - inline
DocumentReference.content.attachment.datawithtext/plainortext/markdownpayloads; Bundle.type=documentandBundle.type=collectionwhen entries remain inside the supported slice;documentbundles only when the bundle carries the standard document envelope used in this repository;- remote
attachment.urldereference only through an explicit, opt-in, bounded,https-only path.
The current security baseline is intentionally modest but explicit:
- secure-by-default bearer authentication on application routes;
- explicit development-only unauthenticated override, blocked in production;
- per-IP sliding-window rate limiting;
- Helmet-based header hardening;
- encrypted durable case storage when
STORE_PATHandENCRYPTION_KEYare configured; - append-only audit history for write flows;
- SSRF-aware remote attachment controls for the highest-risk interoperability path.
Current non-claims remain important:
- no full tenant RBAC model or fine-grained per-field access policy;
- no autonomous diagnosis, treatment recommendation, or always-on model-generated packet workflow; a configured local LLM sidecar may append bounded draft-assistance sections, but packet drafting still remains clinician-review-first and fail-closed when no sidecar is available;
- no cryptographically sealed audit log;
- no automated encrypted-store key rotation, restore-drill orchestration, or disaster-recovery automation;
- TLS is expected to be handled by deployment infrastructure, not by the Node process itself.
This repository is organized so that public language can be checked against implementation and tests rather than inferred from aspiration.
Primary authority surfaces:
- design.md
- docs/design-refresh-2026-04-03.md
- docs/architecture/overview.md
- docs/api-scope.md
- docs/claim-boundary.md
- docs/interop/README.md
- docs/traceability-matrix.md
- docs/security/posture-and-gaps.md
- docs/security/backup-restore-and-key-rotation.md
- docs/academic/evidence-register.md
- openapi.yaml
The shortest claim-to-code-to-test route is docs/traceability-matrix.md.
Adjacent open-source projects in this space tend to cluster around two patterns:
- local-first intake assistants centered on patient-side data capture and printable summaries;
- AI summarization MVPs centered on conservative note generation while disclaiming diagnosis and treatment.
Anamnesis is positioned differently. It is a server-side, evidence-governed workflow control plane: narrower than a digital front door, less speculative than a generic medical AI demo, and more explicit about interoperability, auditability, and claim boundaries than many adjacent prototypes.
| Technology | Version | Role |
|---|---|---|
| Node.js | >=24 |
Runtime |
| TypeScript | ^6.0.2 |
Type system and compiler |
| Express | ^5.2.1 |
HTTP framework |
| Helmet | ^8.1.0 |
Security headers |
| Zod | ^4.3.6 |
Request validation and runtime schemas |
| better-sqlite3 | ^12.8.0 |
Durable persistence |
| node:test | built-in | Test runner |
Use .env.example as the baseline runtime contract.
npm install
npm run validate:public-export
npm run devSet one of API_KEY, JWT_SECRET, JWT_PUBLIC_KEY, JWT_JWKS, or JWT_JWKS_URL before starting the server unless ALLOW_INSECURE_DEV_AUTH=true is explicitly enabled for local development.
Default runtime port: 4020
Publication-grade local verification:
npm run validate:public-exportFocused local sidecar evaluation gate:
npm run test:llm-evaluationThis expands to:
npm run lint
npm run test:coverage
npm run build
npm run audit:prodOperational probes:
GET /healthzGET /readyzGET /metrics
/metricsremains unauthenticated like/healthzand/readyz, so monitoring access should sit behind separate network controls when exposure beyond the local trust boundary is possible. WhenJWT_JWKS_URLis enabled, the metrics surface also includes remote verifier freshness, cache-hit, refresh, and failure counters. When an OpenAI-compatibleLlmSidecaris configured, the same surface also exposes draft-assistance request, success, failure, and last-attempt timestamps.- If you enable
RATE_LIMIT_RPMbehind a reverse proxy or load balancer, configure Express proxy trust for the deployment topology before relying onrequest.ipfor enforcement. - Optional draft-only packet enrichment can be enabled by pointing
LLM_SIDECAR_BASE_URLandLLM_SIDECAR_MODELat an operator-managed OpenAI-compatible sidecar. The write path remains fail-closed: invalid, empty, or clinically unsafe sidecar responses do not block packet drafting and do not widen the product claim boundary. - The current sidecar baseline includes a fixture-backed evaluation pack in
tests/llm-sidecar-evaluation.test.ts; runnpm run test:llm-evaluationto verify that review-oriented summaries are accepted and diagnosis, treatment, or prescription language is rejected before packet enrichment is accepted.
A multi-stage Dockerfile is included. Build and run:
docker build -t anamnesis .
docker run -p 4020:4020 \
-e API_KEY=your-secret-key \
-e STORE_PATH=/data/anamnesis.db \
-e ENCRYPTION_KEY=$(openssl rand -hex 32) \
-v anamnesis-data:/data \
anamnesisThe image uses Node 24 Alpine, runs as a non-root user, and includes a built-in health check against /healthz.
| Variable | Required | Default | Description |
|---|---|---|---|
PORT |
No | 4020 |
HTTP listen port |
API_KEY |
One auth mechanism is required unless explicit local-dev override is enabled | — | Opaque bearer token for application endpoints |
JWT_SECRET |
No | — | HS256 verifier secret for JWT bearer authentication; mutually exclusive with JWT_PUBLIC_KEY, JWT_JWKS, and JWT_JWKS_URL |
JWT_PUBLIC_KEY |
No | — | PEM-encoded RSA public key for RS256 JWT verification with one active verifier key; mutually exclusive with JWT_SECRET, JWT_JWKS, and JWT_JWKS_URL |
JWT_JWKS |
No | — | JSON JWK Set for RS256 JWT verification with local, kid-aware key selection and staged overlap during restart-time key rotation; mutually exclusive with JWT_SECRET, JWT_PUBLIC_KEY, and JWT_JWKS_URL |
JWT_JWKS_URL |
No | — | HTTPS URL for issuer-bound remote RS256 JWKS retrieval with Cache-Control or Expires freshness, ETag/Last-Modified revalidation, and forced refresh when an otherwise-valid token references an unseen kid; mutually exclusive with JWT_SECRET, JWT_PUBLIC_KEY, and JWT_JWKS |
JWT_ISSUER |
No | — | Optional JWT issuer constraint for local modes; required and must be an absolute https issuer URL on the same origin as JWT_JWKS_URL in remote JWKS mode |
JWT_AUDIENCE |
No | — | Optional JWT audience constraint |
JWT_TYP |
No | — | Optional JOSE typ value that JWTs must match |
ALLOW_INSECURE_DEV_AUTH |
No | false |
Explicit local-development override that allows startup without API_KEY, JWT_SECRET, JWT_PUBLIC_KEY, JWT_JWKS, or JWT_JWKS_URL; rejected when NODE_ENV=production |
RATE_LIMIT_RPM |
No | 0 |
Maximum requests per minute per IP; health and readiness probes are exempt |
EXTERNAL_ATTACHMENT_HOST_ALLOWLIST |
No | — | Optional comma-separated hostname allowlist for external FHIR bundle attachment fetches |
LLM_SIDECAR_BASE_URL |
No | — | Base URL for an operator-managed OpenAI-compatible draft-assistance sidecar; must be paired with LLM_SIDECAR_MODEL |
LLM_SIDECAR_MODEL |
No | — | Model name passed to the OpenAI-compatible draft-assistance sidecar; must be paired with LLM_SIDECAR_BASE_URL |
LLM_SIDECAR_API_KEY |
No | — | Optional Bearer token sent to the configured draft-assistance sidecar |
LLM_SIDECAR_TIMEOUT_MS |
No | 5000 |
Positive integer timeout in milliseconds for one draft-assistance sidecar request |
STORE_PATH |
No | — | Path to SQLite database file; when unset, data is stored in memory only |
ENCRYPTION_KEY |
When STORE_PATH is set |
— | 64-character hex string used for AES-256-GCM encryption at rest |
Current operational guidance for backup, restore, and key handling lives in docs/security/backup-restore-and-key-rotation.md.
POST /api/casesGET /api/casesGET /api/cases/:caseIdDELETE /api/cases/:caseIdPOST /api/cases/:caseId/access-grantsDELETE /api/cases/:caseId/access-grants/:principalIdPOST /api/cases/:caseId/artifactsDELETE /api/cases/:caseId/artifacts/:artifactIdGET /api/cases/:caseId/evidence-lineagePOST /api/cases/:caseId/samplesPOST /api/cases/:caseId/study-contextPOST /api/cases/:caseId/qc-summaryPOST /api/cases/:caseId/document-ingestionsPOST /api/cases/:caseId/fhir-importsPOST /api/cases/:caseId/fhir-bundle-importsPOST /api/cases/:caseId/physician-packetsGET /api/cases/:caseId/physician-packetsPOST /api/cases/:caseId/physician-packets/:packetId/reviewsGET /api/cases/:caseId/physician-packets/:packetId/reviewsPOST /api/cases/:caseId/physician-packets/:packetId/finalizeGET /api/cases/:caseId/audit-eventsGET /api/operations/summaryGET /healthzGET /readyzGET /metrics
Machine-readable contract: openapi.yaml
- README.md
- openapi.yaml
- docs/claim-boundary.md
- docs/traceability-matrix.md
- docs/security/posture-and-gaps.md
- CONTRIBUTING.md
- SECURITY.md
- SUPPORT.md
- GOVERNANCE.md
- CITATION.cff
- CHANGELOG.md
- GOVERNANCE.md defines maintainer rules, evidence requirements, and change-control boundaries.
- SUPPORT.md explains support routing and security-reporting boundaries.
- PUBLISHING.md is the public GitHub release checklist and repository-metadata guide.
- CONTRIBUTING.md covers contribution flow.
- SECURITY.md covers security reporting.
- CITATION.cff provides machine-readable citation metadata.
.github/workflows/ci.ymland.github/workflows/dependency-review.ymldefine the current GitHub validation baseline.
MIT. See LICENSE.