Audit Service — Service Overview
Status: populated Owner: TBD Last updated: 2026-04-18 Companion: Service Template · 03 platform-services · 02 DDD
1. Purpose
The Audit Service is the centralised, tamper-evident audit log for the entire Ghasi eHealth platform. It is a purely reactive service: it consumes domain events emitted by every other service, stores immutable AuditEntry records in a write-once PostgreSQL store, and exposes a read API for compliance officers, Tenant Admins, and Super Admins. No other service may write to or modify the audit store directly.
2. Bounded Context
| Field | Value |
|---|---|
| Context name | audit |
| DDD type | Supporting domain |
| Slice | S0 — platform infrastructure |
| Epic prefix | AUDIT-EPIC |
| Story prefix | AUDIT-US |
| FR prefix | FR-AUDIT-* |
| Source module | _sources/audit/ (PLAT-AUDIT v2.0) |
| FHIR resources | AuditEvent, Provenance (read-only projections via interop-service) |
3. Responsibilities
| In scope | Out of scope |
|---|---|
Consume ALL platform/clinical NATS events and persist AuditEntry rows | Application-level structured logging (OpenTelemetry / Loki) |
| Immutable, tamper-evident storage (INSERT-only Postgres role) | Consent enforcement (owned by access-policy-service) |
| SHA-256 chain-hash tamper detection + verification job | PHI masking / redaction at source |
| Query API scoped by tenant and role | Business-logic analytics on audit data |
Accounting-of-disclosures (GET /api/v1/audit/disclosures) | Alerting and on-call pages (Grafana Alertmanager) |
| Async NDJSON / CSV export with signed download URL | Secrets management or key rotation |
| Background chain-integrity verification job | Storage of application traces (Jaeger/Tempo) |
| Self-auditing of bulk-export requests | Real-time access control enforcement |
4. Architecture Diagram
5. Upstream / Downstream Dependencies
Upstream consumers
| Service | NATS wildcard | Event categories created |
|---|---|---|
| identity-service | com.ghasi-ehr.iam.user.* | User lifecycle |
| identity-service | com.ghasi-ehr.iam.provider.* | Provider profile |
| identity-service | com.ghasi-ehr.iam.service_account.* | Service accounts |
| tenant-service | com.ghasi-ehr.tenant.* | Tenant lifecycle, subscription |
| facility/hierarchy-service | com.ghasi-ehr.hierarchy.* | Node, edge, membership |
| platform-admin-service | com.ghasi-ehr.platform.* | Config, feature flags |
| config-service | ghasi.config-resolver.* | Role, feature, override mutations |
| Clinical services (MVP1+) | com.ghasi-ehr.clinical.* | Patient data access events |
Downstream consumers
| Consumer | What they consume |
|---|---|
| Compliance officer UI | GET /api/v1/audit/entries |
| Patient portal | GET /api/v1/audit/disclosures (accounting-of-disclosures) |
| Regulators / MoPH | Async exports via POST /api/v1/audit/exports |
| platform-admin-service | audit.dlq.alert events — marks audit health as degraded |
6. Key Architectural Decisions
| Decision | Rationale |
|---|---|
PostgreSQL role audit_app has INSERT-only on audit_entries | Enforces immutability at the DB engine; no application code path can bypass it |
| SHA-256 chain hash per entry | Tamper detection: each entry hashes prev_id:event_id:tenant_id:occurred_at:resource_id |
Monthly range-partition on recorded_at | Manages table growth; partition pruning for time-ranged queries |
| No Redis cache | Write-heavy service; read queries are rare and correctness-critical; caching adds complexity |
| Append-only event store, no UPDATE/DELETE | Meets HIPAA analogue, GDPR audit, MoPH data-retention obligations |
| 7-year retention floor | Platform policy per BR-AUD-003; tenants may extend via policy |
| Live query limited to 90-day windows | Prevents full-table scans; wider ranges use async export |
| Self-auditing of bulk exports | Meta-audit requirement: export events are themselves AuditEntry rows |
Dedup on source_event_id (UNIQUE index) | Idempotent ingestion; NATS at-least-once delivery is safe |
7. Source Reconciliation
Single source: _sources/audit/ (PLAT-AUDIT v2.0). No module merge required.
Legacy NATS subjects use com.ghasi-ehr.* prefix; canonical naming follows NAMING.md {service}.{aggregate}.{event}.v{N}. Both forms are listed in EVENT_SCHEMAS.md.