24API routesUpload to signing
18Use-casesApplication layer
7AI endpointsOne agentic, six assistive
9Chain stepsScanner to signed report
A / Architecture
Four layers.
One protected workflow.
01Presentation
Next.js shells, React, viewerRoute files are razor-thin shells; real UI lives in presentation components, hooks and the Cornerstone lib layer. The Zustand store mirrors transient viewport state only: no business logic, no DICOM data.
presentation/components · hooks · lib/cornerstone 02Application
Use cases and orchestration18 use-cases orchestrate upload, retrieval, reporting and identity. Route handlers act as composition roots, wiring concrete implementations through factories.
application/usecases · factories as composition roots 03Domain
Rules, entities, portsStudy assembly grouped by series and instance UIDs, modality window presets, agent tool names, and the repository and AI ports all live framework-free. The AI is typed in the domain before any provider exists.
domain/services · repositories (interfaces) 04Infrastructure
Providers and persistenceThe DICOMweb repository, four Postgres stores (identity, reports, worklist, audit), a scrypt password hasher, Anthropic and Google adapters, and the Python edge gateway implement the ports.
infrastructure/repositories · services · identity B / Reliability
Built for clinics,
not demos.
R1The edge survives outages
Store-and-forward with stable-study detection: the gateway pushes only fully received studies, retries forever through connectivity loss, deduplicates by SOP Instance UID, and deletes its local copy only after the cloud archive confirms.
STOW-RS · retry forever R2The archive is never exposed
The browser reaches the archive only through a read-only proxy that injects server-held credentials, validates every path segment against an allowlist regex, checks tenancy per request, and caches privately.
Credential-injecting proxy R3Tenancy, audit, immutability
Center users see only their center's studies, deny-by-default for anything unindexed. Every sensitive action lands in an append-only audit log. Signing is restricted to radiologists and admins, and a signed report can never be edited again.
audit_log · signed reports R4A control plane that deploys itself
Raw Postgres with no ORM. The schema self-migrates on first use under a Postgres advisory lock, so a fresh deploy needs no migration step and concurrent instances cannot race. Passwords use memory-hard scrypt; session tokens are stored only as hashes.
Advisory-lock migrate · scrypt R5Rendering that survives real phones
A one-time WebGL2 probe reads each device's true texture ceiling and measures the largest float32 3D texture it can actually sample, fixing black volume renders on older iPhones. Pixel ratio is capped on 3x phones, a decode worker is reserved so scrolling never starves, and slices decimate to a GPU memory budget.
Device profile · WebGL2 R6An agent under guardrails
A 16-step ceiling with wrap-up forced at step 13, image history pruned to the last two tool steps, over-call traps written into the protocol prompt, a mandatory verification pass, and a required first impression line: AI-proposed draft, radiologist verification required.
Bounded loop · protocol prompt C / Decision record
Explicit choices.
Visible tradeoffs.
D-01Speak DICOMweb only, never vendor APIs
- Context
- Orthanc's proprietary REST API is convenient and everywhere in tutorials.
- Decision
- The application talks to the archive exclusively through STOW-RS, QIDO-RS and WADO-RS, with original transfer syntax preserved.
- Tradeoff
- No vendor shortcuts, in exchange for an archive that swaps for AWS, Google or Azure health imaging as a configuration change.
D-02Two systems of record, split by data nature
- Context
- A PACS holds two very different things: large immutable pixel data and small mutable operational truth.
- Decision
- Pixels live in the DICOM archive keyed by SOP Instance UID; identity, tenancy, reports, the worklist index and audit live in Postgres.
- Tradeoff
- Two stores to operate, each doing exactly what it is built for.
D-03The browser executes the agent's tools
- Context
- The pixel data and the GPU renderer live client-side; shipping pixels to the server would duplicate the entire viewer.
- Decision
- The server plans one stateless model turn at a time; the viewer executes view_slices and measure_hu on an off-screen viewport and returns labeled montages.
- Tradeoff
- A chattier loop, but the model sees exactly what a radiologist sees, and the patient's name never leaves the app.
D-04A deliberately dumb edge
- Context
- The gateway runs inside clinics on hardware nobody maintains.
- Decision
- A standard-library-only Python sidecar on a bare Alpine container: watch, forward, confirm, delete. No queue framework, no dependencies.
- Tradeoff
- No cleverness at the edge, and therefore nothing to operate or break inside a clinic.
D / Evidence boundary
Credibility includes
what is not claimed.
Repository demonstrates
- A real end-to-end imaging chain in one codebase: edge gateway, cloud archive, worklist, viewer, reporting
- Standards discipline: DICOMweb-only to the archive, classic DIMSE at the edge, swappable by configuration
- An agentic AI reader whose tools execute in the browser, scored against an offline ground-truth harness
- Device-adaptive GPU rendering built from debugging real failures on real phones
Not claimed without product data
- Clinical accuracy or regulatory clearance: this is not a certified medical device
- Hospital deployments, imaging throughput or uptime
- Automated test coverage: the repository currently ships none
- DICOM de-identification: PHI is governed by tenancy and an append-only audit trail, and the AI path strips the patient name