Sentra Healthcare — Ops (Security + Deployment + Testing)¶
Security — Healthcare Delta¶
Baseline security patterns:
_shared/security-patterns.md
Overrides¶
- MFA Requirement: Seluruh role klinis (Dokter, Perawat, Apoteker) wajib menggunakan MFA untuk login — tidak cukup hanya password. Ini adalah override dari baseline yang hanya merekomendasikan MFA untuk admin. Di healthcare, MFA adalah mandatory tanpa pengecualian sesuai Permenkes 24/2022.
Tambahan Sistem-Spesifik¶
RME Immutability & BSrE Signature Chain:
- Rekam medis yang telah ditandatangani oleh dokter dengan BSrE (Balai Sertifikasi Elektronik) tidak dapat dimodifikasi secara langsung.
- Hash BSrE (SHA-256) disimpan di kolom soap_notes.digital_signature_hash. Setiap request UPDATE ke record yang sudah memiliki signed_at ditolak di level aplikasi (middleware layer) sebelum menyentuh database.
- Modifikasi setelah sign-off hanya diperbolehkan melalui endpoint Addendum (POST /soap/:id/addendum) yang: (a) memerlukan BSrE re-signing dengan justifikasi tertulis, (b) menyimpan versi lama ke soap_notes_history, (c) mencatat JSON diff penuh ke audit_logs.
- Tanda tangan BSrE memberikan legal validity kepada RME — setara dengan tanda tangan basah dalam hukum Indonesia (UU ITE + Permenkes 24/2022).
Patient Data Privacy (UU PDP No. 27/2022 Compliant):
- Data sensitif klinis (diagnosa, anamnesa SOAP, alergi, riwayat penyakit) dienkripsi di level kolom PostgreSQL menggunakan AES-256-GCM sebelum disimpan. Aplikasi mendekripsi saat membaca.
- Kunci enkripsi dikelola oleh HashiCorp Vault — tidak pernah disimpan di database yang sama dengan data medis.
- Data rekam medis di-anonymized (nama disingkat, alamat hanya setingkat kecamatan) di server analitik pelaporan kesehatan.
- Retensi Data: Sesuai Permenkes, rekam medis dewasa disimpan minimal 5 tahun setelah kunjungan terakhir; rekam medis anak disimpan hingga 25 tahun atau minimal 5 tahun setelah pasien dewasa. Data tidak boleh dihapus sebelum masa retensi berakhir.
- Permintaan akses data pasien dari pihak ketiga (termasuk penyidik hukum) wajib melalui proses persetujuan Owner/Direktur Klinik dan dicatat ke audit_logs dengan kategori EXTERNAL_DATA_REQUEST.
Doctor Authentication for Sign-Off (2FA Dual-Layer): - Sign & Lock SOAP memerlukan 2 faktor autentikasi: 1. Session Login: JWT aktif dari Keycloak (username + password + OTP). 2. PIN BSrE Khusus: PIN terpisah yang terdaftar ke BSrE dan terikat pada identitas dokter (NIK + SIP dokter). PIN ini tidak sama dengan password login dan tidak bisa direset oleh admin klinik. - Percobaan PIN BSrE yang salah > 3 kali membekukan kemampuan sign-off dokter tersebut dan memicu alert ke Clinic Manager.
Audit Logs Append-Only Enforcement:
- Di level PostgreSQL, hak UPDATE dan DELETE pada tabel audit_logs direvoke dari semua application roles:
SELECT dan INSERT yang diizinkan — mencegah manipulasi jejak audit oleh insider.
- Faktur billing yang sudah terbit dikunci secara absolut. Void/diskon wajib PIN Supervisor dan dicatat ke audit log.
Anti-Allergy Prescription Guard:
- Setiap item resep divalidasi terhadap profil alergi pasien (kolom patients.allergies) sebelum disimpan.
- Jika terdapat konflik alergi, sistem menampilkan modal peringatan warna merah yang memaksa dokter memilih antara batalkan atau bypass dengan justifikasi tertulis yang dilog ke audit_logs dengan level HIGH_SEVERITY_ALLERGY_OVERRIDE.
Deployment — Healthcare Delta¶
Baseline deployment:
_shared/deployment-baseline.md
Overrides¶
- Database: Amazon Aurora PostgreSQL (Active-Passive Multi-AZ) — bukan RDS standar — untuk memastikan failover otomatis < 30 detik tanpa kehilangan data transaksi klinis.
Tambahan Sistem-Spesifik¶
SatuSehat Bridging Service (Dedicated Microservice): - Karena SatuSehat IHS API bersifat rate-limited dan frekuensi timeout-nya lebih tinggi dari API eksternal lain, adapter SatuSehat dijalankan sebagai dedicated ECS/EKS pod terpisah dari core monolith. - Pod SatuSehat bisa di-scale independen saat volume kunjungan klinik meningkat (misal: musim flu). - RabbitMQ FHIR Queue berfungsi sebagai buffer decoupling antara core backend dan SatuSehat pod.
BPJS Gateway Dedicated Network: - Akses ke BPJS PCare dan VClaim API mengharuskan IP Whitelist yang didaftarkan ke BPJS Kesehatan secara manual. - Klinik yang terdaftar di jaringan SentraClinic mendapatkan IP Elastic (static) yang didaftarkan satu kali ke BPJS. - Untuk VClaim (FKRTL), jaringan komunikasi menggunakan VPN dedicated atau leased line khusus BPJS FKRTL — tidak bisa menggunakan koneksi internet publik biasa. - BPJSAdapter berjalan di subnet terpisah dengan Security Group yang hanya mengizinkan outbound ke IP BPJS Kesehatan.
Edge Node (Offline-First Clinic Server): - Setiap cabang klinik memiliki mini PC lokal (Intel NUC / Raspberry Pi Server) yang menjalankan Go Sync Daemon + SQLCipher database. - SQLCipher passphrase disimpan di HashiCorp Vault Agent yang berjalan di edge node — bukan di environment variable atau file plain text. - Edge node dikonfigurasi dengan Docker Compose (lihat konfigurasi di bawah). - Sync daemon memonitor status internet setiap 5 detik; begitu internet pulih, outbox queue diproses secara batch.
# docker-compose.yml — Edge Clinic Node
version: '3.8'
services:
edge-gateway:
image: sentraclinic/edge-sync-daemon:latest
container_name: local_sync_gateway
restart: always
environment:
- CLINIC_BRANCH_ID=99ea7b42-1200-4b32-8411-d00db60ab292
- CLOUD_API_URL=https://api.sentraclinic.co.id/v1
- LOCAL_SQLITE_PATH=/data/sentraclinic_local.db
- SQLCIPHER_PASSPHRASE_FILE=/vault/secrets/cipher_key.txt
- RECONCILIATION_INTERVAL_SECS=30
volumes:
- edge-db-volume:/data
- /etc/vault/secrets:/vault/secrets:ro
ports:
- "8080:8080"
networks:
- clinic-lan
edge-queue-display:
image: sentraclinic/queue-display-web:latest
restart: always
ports:
- "80:80"
environment:
- EDGE_API_HOST=http://edge-gateway:8080
networks:
- clinic-lan
volumes:
edge-db-volume:
driver: local
networks:
clinic-lan:
driver: bridge
Backup & Georedundancy (Medical Records Compliance): - Rekam medis wajib disimpan dengan georedundant backup (minimal 2 region AWS) sesuai standar keamanan data kesehatan. - Backup PostgreSQL dilakukan setiap 6 jam dengan retenti snapshot 30 hari. - Immutable Backup: Backup RME menggunakan AWS Backup dengan Vault Lock (WORM — Write Once Read Many) untuk mencegah penghapusan backup sebelum periode retensi berakhir (sesuai kebutuhan retensi Permenkes 25+ tahun). - Recovery Point Objective (RPO): < 6 jam. Recovery Time Objective (RTO): < 2 jam.
Testing Checklist¶
| Kategori | Skenario Test | Target / Expected Result | Tipe |
|---|---|---|---|
| SatuSehat Integration | Simulasi HTTP Timeout pada SatuSehat API saat pengiriman SOAP | Sistem menyimpan payload FHIR ke antrian fallback SQLite dan tidak memblokir antrean dokter. Begitu koneksi pulih, background task memproses sinkronisasi secara tertib | Integration / Mock API |
| RME Lock Enforcement | Attempt PUT /soap setelah sign-off BSrE | API mengembalikan HTTP 423 Locked. Data SOAP tidak berubah |
Unit / Security |
| BSrE Invalid Signature | Submit SOAP dengan signature hash BSrE yang tidak valid | API mengembalikan HTTP 422 Unprocessable. SOAP tidak tersimpan. Audit log mencatat percobaan gagal |
Unit / Security |
| Konkurensi Antrean | 20 frontdesk menekan tombol "Ambil Antrean" secara bersamaan | Database mengeluarkan nomor antrean unik berurutan tanpa duplikasi (Zero Duplicate) | Performance / Concurrency |
| FEFO Resep | E-Prescribing paralel untuk obat dengan stok tipis | Stok batch terpotong tanpa race condition; batch ke-21 error Out of Stock jika stok habis, tidak ada stok minus |
Unit / Stress Test |
| PPh 21 Kalkulasi | Kalkulasi PPh 21 jasa medis untuk dokter berstatus pegawai vs freelance | Validasi kesesuaian formula slip gaji dokter dengan tabel PPh 21 progresif DJP RI | Functional / QA Audit |
| Skenario Offline | Cabut internet saat proses SOAP dokter berjalan | Aplikasi desktop mendeteksi offline, merutekan query ke SQLite lokal, memperbolehkan input SOAP dasar, menahan antrian lokal dengan andal | Operational / Chaos Test |
| BPJS API Downtime | BPJS PCare API tidak merespons selama 30 menit | Data kunjungan masuk antrian retry lokal; kasir tetap bisa memproses pembayaran cash; alert terkirim ke admin setelah 3 retry gagal | Integration / Resilience |
| Allergy Guard | Dokter menulis resep Amoxicillin untuk pasien dengan alergi Amoxicillin | Modal peringatan warna merah muncul; resep tidak tersimpan sampai dokter konfirmasi bypass dengan justifikasi | Unit / Safety |
| Audit Log Immutability | Attempt UPDATE/DELETE langsung ke tabel audit_logs via psql | PostgreSQL mengembalikan permission denied untuk app_role |
Security / DB |