Skip to main content

Document Service — Security Model

Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · 13 security-compliance-tenancy · 14 compliance-security-extended


1. RBAC / ABAC Matrix

OperationMinimum RoleLicense RequiredAdditional Conditions
List / search documentsCLINICIANehr.documentsPatient must be accessible to caller's facility
Download / view documentCLINICIANehr.documentsABAC check per document sensitivity
Generate documentCLINICIANehr.documentsContext resource must be accessible
Upload scanned documentCLINICIANehr.documentsVirus scan mandatory
Create / edit template draftDOCUMENT_AUTHORehr.documents.designerTenant-scoped
Publish template versionDOCUMENT_AUTHORehr.documents.designer
Fork platform templateDOCUMENT_AUTHORehr.documents.designer
Retire templateTENANT_ADMINehr.documents
Enqueue async bulk generationTENANT_ADMINehr.documents.bulk
Edit platform reference templateNobodyReturns 403 PLATFORM_TEMPLATE_IMMUTABLE
Access another tenant's documentsNobodyRLS + CROSS_TENANT deny

2. Tenant Isolation

ControlImplementation
Row-Level SecurityPostgreSQL RLS on all tables; tenant_id = current_setting('app.current_tenant_id')
Object storage isolationAll objects stored under /{tenantId}/ prefix; presigned URL generator validates tenantId claim
JWT claim enforcementtenantId extracted from JWT; never from request body alone
FHIR resourcesDocumentReference created with tenant-scoped patient; cross-patient access checked by FHIR gateway

3. Encryption

Data classEncryptionNotes
PDF artifacts (object storage)AES-256 SSE-S3 or SSE-KMSEncryption at rest; per-tenant KMS key where configured
Quarantined filesAES-256 SSE-S3Retained per policy; access restricted
document_template_versions.definition (JSONB)At rest: PostgreSQL TDENo PHI in template definitions
Render job context JSONBAt rest: PostgreSQL TDEContains resource IDs only, not PHI content
Transit (all)TLS 1.2+All HTTP and NATS connections
Presigned URLsShort-lived (default 15 min TTL)No credentials embedded; time-bounded HMAC signature

4. Virus Scanning

StageAction
Upload initiationFile staged to quarantine prefix
FinalizationClamAV scan before any storage or FHIR registration
Virus detectedFile moved to quarantine-infected/; document.upload.quarantined.v1 event emitted; caller receives 422
CleanFile moved to /{tenantId}/documents/; DocumentReference created
Scan timeoutUpload rejected; caller retries; quarantine object cleaned up after TTL

5. Audit Events

All document access events are emitted to NATS and persisted by audit-service with 7-year retention.

TriggerAction logged
Document downloadedaction=download, actorId, tenantId, documentReferenceId, patientId
Document viewed in UIaction=view
Document printed / exportedaction=print / action=export
Document generatedaction=generate, templateVersionId, inputSnapshotHash
Document uploadedaction=upload, uploadId
Template publishedaction=template_publish
Platform template forkaction=template_fork
Virus quarantineaction=quarantine, uploadId, reason

6. GDPR Participation

AspectNotes
Personal dataPDFs contain PHI; stored in tenant-scoped object storage
Data subject rightsPatient document list available via GET /v1/documents?patientId=...; deletion follows legal hold policy
RetentionMinimum 7 years for clinical documents; legal hold overrides deletion
Data residencyObject storage and PostgreSQL in tenant's designated region
Accounting of disclosuresAudit record on every download/export; reportable for HIPAA accounting
Purpose limitationDocuments used only for clinical care and audit; not shared with analytics or AI training without explicit consent

7. Security Hardening

ControlDetail
Virus scan mandatoryNo upload bypasses scan; quarantine on detection
Presigned URL TTLDefault 15 min; configurable per tenant with minimum 5 min
No raw storage paths exposedClients receive presigned URLs; internal S3 paths never returned in API
Input validationZod on all DTOs; max file size configurable per tenant
Server-side rendering onlyNo PHI in client-side or third-party rendering pipelines
Rate limitingKong rate limits on generate and upload endpoints to prevent abuse