Hospital Private Clinical Documents
U3 document foundation, private storage, quarantine, access rules, retries, and deployment gates.
Delivery Boundary
U3 provides a private document foundation for later PDF-first Lab and local insurance workflows. It does not connect the Lab or TPA screens, approve a report, clear readiness, or select a scanner provider. Uploads are disabled by default. D2 approval and verified private storage/scanning block staging and production deployment of this candidate. The default-off flag supports isolated foundation tests; it is not deployment approval. Use the forward delivery plan and manual QA.
Ownership And Patterns
Clinical owns canonical Clinical::Document metadata.
Clinical::Hospital::CaseDocument owns the protected case link, opaque object key, immutable content hash, upload state, scan state, and revision chain.
Composite foreign keys bind tenant, facility, patient registration, patient, and document identity.
An additional database trigger protects linked canonical file names, sizes, types, and paths from edits.
Tenant FORCE RLS, Hospital facility checks, and effective permission policies all apply.
The existing attachment ID repair is not repeated.
Current patterns are Hospital readiness commands for scoped writes/audit, Connect's service-key approach for private storage, and hospitalStockApi for a separate typed Hospital HTTP consumer.
Do not copy Connect's local-disk fallback or thread policy.
The typed hospitalDocumentsApi remains separate from the unconnected Lab/TPA workbench methods; those pages stay unavailable in live mode until U4/U5.
General record detail routes keep the patient selector separate from the resource selector.
The timeline uses the same canonical public-document scope for rows and counts.
HTTP Surface
All routes below are relative to /clinical/facilities/:facility_id/surgical_cases/:case_id/documents.
The shared client supplies /api, the session bearer, and profile context.
| Method | Suffix | Contract |
|---|---|---|
| GET | Empty | Paginated revision metadata. Require purpose=lab or purpose=tpa; optional page and exact operation_key lookup. |
| POST | Empty | Multipart document[file], document[purpose], document[operation_key], optional document[supersedes_id]. |
| GET | /:id | Authorized metadata for one case-linked revision. |
| GET | /:id/download | Authenticated, audited attachment delivery only for stored, clean bytes. No storage redirect or public URL. |
| POST | /:id/retry_scan | Requeue a stored pending/failed scan under current write authority and available configuration. Final scan outcomes remain unchanged. |
Metadata includes IDs, purpose, predecessor, uploader, file name/size/type, upload/scan states, scan time, creation time, superseded flag, and download availability.
The upload response also includes replayed.
It never includes an object key, signed blob ID, public file path, or storage URL.
Old clean revisions remain available to authorized history readers; that does not make them current evidence.
The resource policy requires view_hospital, view_surgical_cases, active facility access, and the relevant enabled modules.
Lab documents additionally require manage_lab_readiness; insurance documents require verify_insurance.
General case view alone grants neither category.
General clinician and patient-facing document lists, details, timelines, and counts exclude Hospital evidence.
The filter preserves ordinary documents with no document type.
Even a clean scan does not publish a report to the general patient record.
Writes also require an active practice and a non-terminal case.
These existing permissions are the foundation contract, not approval of the final pilot actor policy.
Role management stays in Shell; flags stay in Admin.
Upload And Scan Lifecycle
- Validate current authority, deployment availability, operation key, actual PDF signature/type/end marker, file size, and safe file name.
- Commit canonical metadata, the immutable case/revision link, opaque key, and required activity audit before sending bytes to storage.
- Write the bytes outside the case transaction. Verify/finalize the stored state and append the case event and required audit.
- Queue scanning. A false return or enqueue exception preserves the stored object and records a failed scan for recovery.
- Read and scan immutable bytes without holding the scan finalization lock. Verify size and SHA-256, then finalize the scan with required audit under tenant context.
Upload states are pending, stored, and failed.
Scan states are pending_scan, clean, rejected, and scan_failed.
Unavailable, malformed, or failed scanning never produces a clean result.
Signature/type checks are not malware scanning or proof of clinical validity.
No scan outcome writes a readiness review or marks a case ready.
A storage timeout leaves a durable quarantine record, not an unreferenced object. Retry the same operation key with the same purpose, predecessor, file name, and bytes to recover it. A different payload under that key conflicts. Only one successor is permitted for each revision; separate Lab reports can have separate revision chains. History/content identity cannot be rewritten or deleted through ordinary database writes.
DocumentScanJob uses short explicit tenant-context blocks and restores prior context on success and failure.
Automatic retries are bounded; pending/failed scans remain visible and have an authorized retry endpoint.
Downloads recheck current authority on every request, verify the stored bytes, and use private/no-store cache headers and nosniff.
The client downloads a Blob through the shared authenticated transport, not a browser navigation to S3.
Deployment Gate
| Configuration | Requirement |
|---|---|
CLINICAL_DOCUMENT_UPLOADS_ENABLED | Defaults off; only an explicitly approved deployment may set it to true. |
CLINICAL_DOCUMENT_POLICY_REFERENCE | Required approval reference covering file limits, retention/deletion, and upload/review actors. A string alone is not approval evidence. |
CLINICAL_DOCUMENT_MAX_BYTES | Explicit positive limit approved under D2. No production limit is invented by this implementation. |
CLINICAL_DOCUMENT_BUCKET | Dedicated durable private bucket, with credential fallback matching storage.yml. Required outside local environments. |
CLINICAL_DOCUMENT_KMS_KEY_ID | Deployment encryption configuration for the dedicated S3 service; verify the actual bucket/IAM/KMS posture. |
| Scanner | A reviewed provider assigned to the server configuration's clinical_document_scanner, accepting an IO and returning :clean or :infected. None is installed by U3. Missing provider disables uploads. |
Development/test storage is explicit local/test storage. Staging and production never fall back to disk. An empty Rails custom-options object is not a configured scanner, even though it reports dynamic methods. The dedicated S3 service is registered in the existing credential patcher. Boot success or a configured bucket does not prove private storage, encryption, scanner health, or deployment readiness. Do not enable uploads until Security/operations verify these and the document owner accepts the policy.
Automatic retention deletion is not implemented because its policy is unapproved. History deletion is blocked; an approved retention/legal-hold deletion path needs a reviewed forward change before pilot activation. Do not remove evidence to roll back deployment; disable uploads and preserve existing records.
Verification And Remaining Work
Tests cover durable retries, audit/storage/enqueue failures, quarantine/scan outcomes, authorization, private downloads, raw-SQL scope integrity, revision protection, and tenant job context. Migration checks must verify both migration execution and SQL loading in disposable databases. The foundation has four forward migrations. Parent scope indexes are built concurrently; table, constraints, history/metadata triggers, and RLS creation are transactional. Check for an invalid concurrent index after an interrupted migration before retrying it. Evidence/history migrations refuse destructive rollback. The scan recovery path reloads a rolled-back record before taking its lock. Verify this with a standalone job as well as transactional test fixtures.
The remaining U3 release work is selected-provider integration, approved retention/deletion behavior, D2 deployment verification, and manual acceptance. U4 still owns the Lab queue, report review/replacement semantics, freshness, and readiness projection. U5 still owns local insurance capture/review. The backlog records these separately from foundation implementation.