1. 📌 Overview & Purpose
Goal: Foundation guardrails yang melindungi pesakit + klinisin + ALESA. Tiada modul lain boleh deploy ke production sebelum M9 LIVE. Build sprint 1.1 (week 1-2) supaya semua sprint selepas dibungkus dlm guardrail layer.
Cross-cutting: M9 ada code yang dipanggil oleh M1, M4, M5, M7 (semua agent). Bukan microservice berasingan, tapi library/middleware yang ditarik ke semua app.
Compliance scope: PDPA 2010 · MOH CPG alignment · MMC scope of practice · 7-yr audit retention · breach notification <72h · DSAR (Data Subject Access Request) 30-day SLA · right to erasure cascade.
2. 🛡️ 5 Guardrail Layers
Block list untuk tindakan high-risk yang AI propose tanpa explicit consultant approval. Default OFF — owner enable per-modul per-ward.
Semua input ke LLM lalu PII stripper. IC, nama penuh, alamat, no telefon, email, MRN ditukar dgn token. Output detok at UI layer hanya.
Setiap dx · dose · CPG cadangan WAJIB cite source. Tiada source = tiada paparan. UI tunjuk citation card setiap kali (bukan cuma footnote).
Agent propose, doktor/farmasis approve. Tiada auto-execute pada clinical actions. Timeout default reject · 1-tap UI approve/reject/modify.
Setiap tool call · LLM call · HITL approve · feature flag toggle — log lengkap, queryable. MOH-ready audit trail. 7-yr retention. Anomali alert real-time.
3. ✅ Functional Requirements
@requires_approval · stores proposed action · suspend agent · UI prompt · resume on approve/timeout4. ⚙️ Non-Functional Requirements
| Aspect | Target | Notes |
|---|---|---|
| PII strip latency | <50ms p99 | Critical path · pre-LLM |
| Audit log write | async <200ms | Non-blocking · queue (Redis stream → PostgreSQL) |
| Audit log retention | 7 tahun | MOH requirement · partitioned monthly |
| Audit log query | <2s for 30-day window | Indexed by ts + user + tenant |
| HITL approval round-trip | <1s UI render | Doctor sees prompt fast |
| Feature flag check | <5ms | Cached in Redis · invalidate on toggle |
| Citation retrieval | <500ms | pgvector HNSW · top-3 match |
| Breach alert latency | <30s | Real-time anomaly detect |
| DSAR export | ≤30 days SLA | PDPA requirement · async batch OK |
| RBAC overhead | <10ms per request | Cached · revalidate on role change |
| Audit log immutability | WORM | No update/delete · only insert · cryptographic chain optional |
| Coverage for clinical actions | 100% | Every prescribe · order · sign-off audited |
5. 🗄️ Data Model
5a. Audit Log (PostgreSQL · partitioned monthly)
CREATE TABLE audit_log ( id BIGSERIAL, ts TIMESTAMPTZ DEFAULT now(), request_id UUID, -- correlates across spans tenant_id UUID NOT NULL, user_id UUID, -- staff (null for patient/system) patient_id UUID, -- subject (null for non-patient ops) agent_id VARCHAR(20), -- M1, M4, M5, M7, M9, system action VARCHAR(80) NOT NULL, -- e.g. "rx.create", "soap.sign_off" resource_type VARCHAR(40), -- e.g. "prescription", "encounter" resource_id VARCHAR(80), before_state JSONB, -- mutation diff after_state JSONB, metadata JSONB, -- agent metadata, citations, confidence ip_address INET, user_agent TEXT, geo_country CHAR(2), outcome VARCHAR(20), -- success, blocked, failed PRIMARY KEY (id, ts) ) PARTITION BY RANGE (ts); -- monthly partitions auto-create CREATE INDEX idx_audit_ts ON audit_log (ts DESC); CREATE INDEX idx_audit_user_ts ON audit_log (user_id, ts DESC); CREATE INDEX idx_audit_patient_ts ON audit_log (patient_id, ts DESC); CREATE INDEX idx_audit_action ON audit_log (action, ts DESC); CREATE INDEX idx_audit_tenant_ts ON audit_log (tenant_id, ts DESC);
5b. Other Tables
| Table | Key fields | Purpose |
|---|---|---|
feature_flags | flag_key, tenant_id, enabled, set_by, set_at, reason, scope (modul/ward), default_value | Per-tenant toggles |
consent_log | patient_id, action_type, consented_at, scope_json, expires_at, withdrawn_at, withdrawn_reason | Per-action consent |
hitl_pending | id, agent_id, proposed_action_json, requires_role, requested_at, expires_at, status (pending|approved|rejected|timeout), responder_id, response_at, response_reason | HITL queue |
pii_token_map | tenant_id, token, original_value (encrypted), pii_type, created_at | Reversible mapping |
incident_log | id, severity, type (jailbreak|breach|safety_block), agent_id, user_id?, details_json, detected_at, resolved_at, post_mortem_url | Security incidents |
dsar_requests | id, patient_id, request_type (access|export|delete), status, requested_at, completed_at, export_url | FR-9.12/13 |
citation_library | id, source_type (cpg|npra|who|sop), title, version, content_text, embedding (vector), published_at | Hallucination guard source |
block_list | id, action_pattern, severity, requires_role_to_override, reason, added_at, added_by | Clinical safety gate |
6. 🔌 API + Middleware
6a. Audit Query API
GET /api/v1/audit/logs
Query: from, to, user_id, patient_id, action, agent_id, tenant_id, limit, cursor
Returns: paginated audit entries · super_admin/clinic_admin only
GET /api/v1/audit/logs/{id}
Detail single entry
GET /api/v1/audit/timeline/patient/{patient_id}
Patient lifecycle view (intake → encounter → RX → adverse → discharge)
GET /api/v1/audit/timeline/staff/{user_id}
Staff activity audit (today/week/month)
GET /api/v1/audit/incidents
Security/safety incidents only · severity filter
6b. HITL API
POST /api/v1/hitl/request
Body: { agent_id, proposed_action, context, requires_role, expires_in_sec }
Returns: { hitl_id, expires_at }
GET /api/v1/hitl/pending # for current user role
POST /api/v1/hitl/{id}/respond
Body: { decision: "approved|rejected|modified", reason, modified_action? }
GET /api/v1/hitl/{id}/wait
Long-poll for agent · returns when responded or timeout
6c. Feature Flag API
GET /api/v1/flags # all flags for current tenant
GET /api/v1/flags/{flag_key} # specific
PUT /api/v1/flags/{flag_key} # toggle (admin only)
Body: { enabled, reason }
→ triggers audit log + Redis cache invalidate
6d. PDPA / DSAR API
POST /api/v1/pdpa/dsar # patient initiates request
Body: { request_type: "access|export|delete", justification }
GET /api/v1/pdpa/dsar/{id} # status check
GET /api/v1/pdpa/dsar/{id}/export # download FHIR Bundle ZIP
DELETE /api/v1/pdpa/data/{patient_id} # cascade soft-delete (admin only)
POST /api/v1/pdpa/breach # internal breach declaration
→ triggers MOH/PDP notification workflow
6e. Middleware (Laravel + Python)
Laravel: app/Http/Middleware/PIIStrip.php (request body sanitise) app/Http/Middleware/AuditWriter.php (response wrap · log async) app/Http/Middleware/RBACEnforcer.php (route gate · per-tenant) app/Http/Middleware/FeatureFlagGate.php (route enable check) app/Http/Middleware/RateLimiter.php (per-user · per-endpoint) Python (agents/medieco/guardrails/): pii_filter.py (regex + NER · 50ms target) citation_enforcer.py (LLM response validator · retry logic) hitl_gate.py (decorator @requires_approval) block_list.py (clinical safety gate) audit_emitter.py (structured event → Redis stream)
7. 🎚️ Feature Flags Catalog
Default OFF untuk semua clinical AI features. Owner enable bila ready.
| Flag Key | Module | Default | Purpose |
|---|---|---|---|
m1.selfcare_advice | M1 | OFF | Enable AI self-care advice (otherwise just escalate) |
m1.whatsapp_channel | M1 | OFF | WAHA WhatsApp intake channel |
m1.voice_input | M1 | OFF | WebRTC voice symptom intake |
m1.photo_symptom | M1 | OFF | Photo upload (rash · luka) |
m4.ambient_scribe | M4 | OFF | WebRTC audio capture · auto SOAP |
m4.cdss_active | M4 | OFF | AI DDx suggestion panel |
m4.auto_icd10 | M4 | OFF | Auto ICD-10 coding suggest |
m4.history_search | M4 | OFF | Semantic patient history Q |
m5.ddi_blocking | M5 | OFF (warn-only) | Block dispense on MAJOR DDI vs warn-only |
m5.halal_filter | M5 | OFF | Halal pharma filtering |
m6.cross_clinic_share | M6 | OFF | Adverse reaction share across network |
m7.einvoice_lhdn | M7 | OFF | Auto e-Invoice submission |
m7.noshow_predict | M7 | OFF | AI no-show prediction + intervention |
m8.cross_clinic_continuity | M8 | OFF | Patient data follow patient |
m9.cloud_burst_llm | M9 | OFF | Allow cloud LLM (gpt-4o-mini) for peak overflow |
m9.audit_log_immutable | M9 | ON | WORM audit log enforcement |
m9.breach_auto_lock | M9 | ON | Auto-lock account on breach signal |
global.maintenance_mode | — | OFF | Reject all writes (read-only) |
8. 📜 Audit Event Schema
Standard Event Format
{
"ts": "2026-05-26T10:45:23.412Z",
"request_id": "req_abc123def456",
"tenant_id": "klinik_pilot_001",
"user_id": "doctor_007",
"patient_id": "patient_2026-001245",
"agent_id": "M4",
"action": "rx.create",
"resource_type": "prescription",
"resource_id": "rx_xyz789",
"before_state": null,
"after_state": {
"items": [{ "drug_code": "AMX500", "dose": "500mg PO TDS x 5/7" }],
"ai_suggested": true,
"doctor_modified": false
},
"metadata": {
"model_used": "llama-3.1-70b-q5",
"tokens_total": 845,
"latency_ms": 312,
"citations": ["MOH CPG URTI 2019"],
"confidence": 0.84,
"hitl_id": "hitl_pqr",
"approved_at": "2026-05-26T10:45:18.123Z",
"approver_id": "doctor_007"
},
"ip_address": "10.0.1.45",
"user_agent": "Mozilla/5.0...",
"geo_country": "MY",
"outcome": "success"
}
Common Action Types
auth.login consent.granted rx.create auth.logout consent.withdrawn rx.sign auth.failed patient.create rx.dispense auth.locked patient.update rx.cancel encounter.create patient.access order.create encounter.brief_received patient.delete order.send encounter.scribe_start patient.export (DSAR) ddi.block encounter.scribe_stop allergy.alert encounter.soap_draft audit.query feature_flag.toggle encounter.soap_edit hitl.request hitl.approve encounter.sign_off hitl.reject hitl.timeout referral.create pii.strip citation.miss (refused) billing.claim_submit pii.detok incident.detected billing.einvoice_submit breach.declared safety_block.refused
9. 🎨 UI / Dashboards
/admin/audit dgn:
- Audit Timeline (per-patient + per-staff)
- HITL Queue (pending approvals · respond inline)
- Feature Flags page (toggle dgn audit reason)
- Incident Log (security/safety events)
- Breach Dashboard (anomaly trend · alerts)
- DSAR Inbox (patient requests · status workflow)
- MOH Report Generator (quarterly compliance summary export)
10. ✔️ Acceptance Criteria
- AC-9.1: 100% clinical actions audited (test: 50 sample actions traced end-to-end)
- AC-9.2: PII strip detect 95%+ of 12 PII types in 100 sample messages (regex + NER)
- AC-9.3: Citation enforcer rejects LLM responses without citation in 100% test cases
- AC-9.4: HITL gate blocks 30 jailbreak attempts (auto-RX · auto-order) → 0 success
- AC-9.5: Audit log query 30-day window returns <2s for typical patient
- AC-9.6: Feature flag toggle reflects in <5s across all instances (cache invalidate)
- AC-9.7: DSAR export generates valid FHIR Bundle for sample patient · machine-parseable
- AC-9.8: Right-to-erasure soft-deletes patient data · audit retain · cross-table cascade tested
- AC-9.9: Breach simulation (cross-tenant access attempt) → alert <30s · account auto-lock
- AC-9.10: Audit log immutability — attempt UPDATE/DELETE returns DB-level error
- AC-9.11: Q5 PDPA self-audit pass · DPO sign-off documented
- AC-9.12: All other modules (M1, M4, M5, M7) pass through M9 middleware in test suite
11. 🧪 Test Plan
| Tier | Cases | Coverage Target |
|---|---|---|
| Unit | PII regex (12 types) · token round-trip · citation validator · HITL state machine · feature flag cache | ≥90% |
| Integration | Middleware chain (PIIStrip → AuditWriter → RBACEnforcer) · audit log write/query · HITL request/respond cycle | 100% middleware paths |
| E2E | End-to-end patient journey (M1 intake → M4 encounter → M5 RX → M7 billing) — verify every action logged | 1:1 audit trail |
| Security | 30 jailbreak attempts · 20 cross-tenant access · 10 token reuse attacks · OWASP Top 10 scan | 0 high/critical |
| PDPA simulation | 3 DSAR scenarios · 2 erasure scenarios · 1 breach scenario · MOH report generation | All pass |
| Load | 1000 audit writes/sec · 50 HITL requests concurrent · feature flag check 10K/sec | No drop |
| Chaos | Audit DB outage (must fail-safe to local queue) · vault outage (PII fallback) · LLM down (fall back to deterministic rules) | Graceful degrade |
| Compliance audit | External pen-test simulation · MOH-style audit walkthrough | Pass |
12. 🔗 Dependencies & Integration
- Hard: NONE — M9 first to build (Sprint 1.1)
- External: Vault (Hashicorp) atau equivalent for PII token store · PostgreSQL 16 · Redis 7 · Loki/Grafana stack
- Library reuse: Laravel Sanctum · Spatie Permissions · Laravel Audit package as base · custom extensions
- Downstream consumers: M1, M4, M5, M7 — semua import M9 middleware/decorators
- Compliance reference: PDPA 2010 · MOH CPG library · MMC scope of practice docs
13. 🏃 Sprint Allocation
- Day 1-2: Repo init · CI/CD scaffold · base auth (Sanctum) · RBAC seed
- Day 3-4: Patient 11-section model + migrations (canonical · shared dgn M1/M4)
- Day 5-6: PII filter (regex + NER) + token map · vault integration
- Day 7-8: Audit log (PostgreSQL partition + Redis stream) + middleware
- Day 9-10: HITL gate library (Python + PHP) · UI prompt component
- Day 11: Feature flag service · admin UI
- Day 12: Citation enforcer + library · clinical safety block list
- Day 13: Integration test · 100% audit coverage check
- Day 14: Sprint demo · ALESA Preflight Q1 prep · merge ke develop
14. ⚠️ Module-Specific Risks
| Risk | Likelihood | Impact | Mitigation |
|---|---|---|---|
| Audit log write fail (DB outage) → action lost | Low-Med | 🔴 Compliance gap | Redis stream buffer · local disk fallback queue · daily reconciliation · DR drill |
| PII strip miss (NER false negative) | Med | 🔴 PDPA breach | Regex + NER hybrid · 95% target · monitoring · quarterly improvement loop |
| HITL gate bypass (UI-only enforcement) | Low | 🔴 Inappropriate action | Server-side enforcement · decorator wraps tool call · 30-prompt jailbreak suite |
| Citation library outdated | Med | 🟠 Wrong advice | Quarterly CPG refresh · version metadata · alert on stale source |
| Audit log volume cost | Med | 🟢 Budget | Compression · archive to S3 cold storage after 1-yr hot · partition pruning |
| Feature flag cascade (toggle wrong order) | Med | 🟠 Feature instability | Dependency graph · disable cascade · staged rollout · rollback procedure |
| RBAC complexity (6 roles × per-tenant × per-modul) | Med | 🟠 Permission bug | Spatie Permissions baseline · matrix test (role × resource × action) · per-PR security review |
| DSAR export performance (large patient history) | Low | 🟢 SLA miss | Async background job · email notify on ready · 30-day SLA generous |