10 KiB
📑 Product Requirements Document (PRD)
Nama Produk: GoPrint Service General — SatuSehat Bridging & SIMRS Master Gateway
Repository: worker-satusehat
Versi Dokumen: 1.0
Tanggal: 2026-05-13
Status: DRAFT (sinkron dengan kondisi kode terkini)
1. Latar Belakang
Fasilitas kesehatan (faskes) di Indonesia wajib melaporkan transaksi pelayanan medis ke platform nasional SatuSehat (Kemenkes RI) dalam format FHIR R4, dan tetap terhubung dengan layanan BPJS Kesehatan (VClaim / Antrol / Apotek / IHS) untuk klaim & antrean. Saat ini Sistem Informasi Manajemen Rumah Sakit (SIMRS) lokal tidak dirancang untuk menangani latensi, autentikasi (OAuth2 + HMAC + AES), dan rate limit dari API pemerintah secara langsung.
Visi: GoPrint Service General menjadi bridging gateway tunggal yang:
- Memisahkan beban integrasi eksternal dari SIMRS inti.
- Menjamin pengiriman data ke SatuSehat tahan terhadap rate limit dan kegagalan token.
- Menyediakan abstraksi REST/gRPC sederhana bagi tim aplikasi internal.
- Menampung modul administrasi (RBAC hierarkis, master data) yang dipakai bersama oleh seluruh aplikasi rumah sakit.
2. Pengguna & Persona
| Persona | Interaksi | Kebutuhan Utama |
|---|---|---|
| SIMRS Backend / Aplikasi Klinis | Konsumsi REST /api/v1/... & gRPC :9090 |
Latensi rendah, abstraksi FHIR, tidak menangani token SatuSehat sendiri |
| Worker (Sub-system internal) | Polling DB SIMRS → POST ke API internal service-satusehat |
Pengiriman asinkron, recovery 401/429, tracker per resource |
| Admin Faskes (IT) | Web UI (eksternal) memanggil REST RBAC | CRUD role/pages/permission hirarkis, cache invalidasi otomatis |
| DevOps / Operator | Dashboard log + metrik | Log JSON terstruktur (WIB), Prometheus, graceful shutdown |
| Auditor Kemenkes | Tidak langsung — via histori sync | Jejak audit per dokumen (request, response, FHIR ID) |
3. Ruang Lingkup Fitur (Scope)
3.1. Modul Integrasi Eksternal
A. SatuSehat (Kemenkes)
- Klien resmi
satusehat.SatuSehatClient(client.go):- OAuth2 client-credentials dengan caching token + safety margin 60 detik.
- Auto-retry pada HTTP 401 (refresh token, request ulang).
- Tiga endpoint terpisah:
DoRequest(FHIR R4),DoKFA(master farmasi),DoConsent.
- FHIRPayload Builder (
types.go): fluent interface (Set/Append/ToJSON) untuk membangun payload resource FHIR tanpa risiko nil pointer. - Resource yang DIDUKUNG (struktur worker tersedia di internal/worker/satusehat/):
- Implementasi lengkap (ready-to-activate):
Encounter,ImagingStudy,ServiceRequest(default + radiology),Medication,MedicationRequest,MedicationDispense. - Kerangka stub (perlu pengisian logika sinkron):
AllergyIntolerance,CarePlan,ClinicalImpression,Composition,Condition,DiagnosticReport,EpisodeOfCare,Immunization,MedicationStatement,Observation,Procedure,QuestionnaireResponse,Specimen.
- Implementasi lengkap (ready-to-activate):
B. BPJS Kesehatan
- Klien resmi
bpjs.Client(client.go):- Header otomatis
X-cons-id,X-timestamp,X-signature(HMAC-SHA256). - Dekripsi respons V2 (AES-256-CBC, key = SHA256(ConsID+SecretKey+Timestamp), IV = 16 byte awal key, padding PKCS7).
- Auto-decompression berurutan: LZString → Gzip → plaintext JSON.
- Header otomatis
- Service yang siap: VClaim, AntreanRS, AntreanFKTP, Aplicare, Apotek, PCare, ICare, ERekamMedis. Belum terhubung sebagai worker aktif — disediakan sebagai SDK on-demand.
C. Master KFA (Kamus Farmasi & Alkes)
- Worker
KFA Master Puller(puller.go):- Polling halaman
/satusehat/reference/kfa/products?product_type=farmasivia API internalservice-satusehat. - Fetch detail per
kfa_code, UPSERT bundle 3 tabel:kfa_product,kfa_product_active_ingredient,kfa_product_packaging. - Pencegahan rate-limit: 500ms antar item, 30s pada 429 list API, 60s pada 429 detail API, reset ke halaman 1 + idle 6 jam jika halaman kosong.
- Status: SATU-SATUNYA WORKER YANG AKTIF di runtime saat ini.
- Polling halaman
3.2. Modul Internal (System Management)
A. Multi-Database & CQRS
- Database Manager mendukung PostgreSQL, MySQL, SQL Server, SQLite, MongoDB melalui GORM +
sqlx+ driver native. - Setiap modul bisnis (auth, role/pages, role/permission, role/master, kfa) mengikuti pola:
CommandRepository(GORM, write → primary DB)QueryRepository(sqlx raw SQL, read → replica jika dikonfigurasi)Service(orkestrasi, validasi, cache-aside)
- Multi-koneksi sekaligus (config:
databases.postgres,databases.satudata,databases.simrs).
B. RBAC Hierarkis
- Empat sub-modul (internal/master/role/):
master— definisi role induk.pages— daftar halaman/menu dengan parent-child + level.permission— CRUD permission per role per page (Create/Read/Update/Delete/Disable).accses— endpoint agregasiGetRoleAccess(userID)untuk konsumsi UI.
- Caching tree menu via Redis dengan kunci hash SHA-256 dari parameter query; invalidate by prefix pada mutasi.
C. Transport
- REST API (Gin) — port 8080 default, registry-based service wiring di http/servers, Swagger UI (/docs/swagger).
- gRPC (port 9090 default) — kerangka tersedia, registrasi handler belum diaktifkan (main.go:200-204 —
permissionHandlermasih dikomentari). - Middleware: Auth (JWT/Keycloak/Static/Hybrid), CORS, Request-ID, rate-limit Redis-backed.
D. Auth Pluggable
- Provider yang didukung di config:
jwt(default),keycloak,static,hybriddengan fallback. JWT signing key, Keycloak issuer/JWKS URL semuanya via env.
3.3. Object Storage
- MinIO/S3 terkoneksi via interfaces/minio untuk penyimpanan dokumen klinis (PDF, hasil radiologi) — diinisialisasi di startup.
3.4. Observability
- Logger Logrus kustom (JSON, WIB timezone, rotasi harian
logs/YYYY/MM/YYYY-MM-DD.log). - Prometheus client (
prometheus/client_golang) ter-import; metric endpoint perlu dipasang di routes. - Field log standar:
service,environment,request_id,caller,function_name.
4. Persyaratan Non-Fungsional
| Kategori | Target |
|---|---|
| Latensi REST internal | p95 ≤ 200 ms (cache hit), ≤ 800 ms (cache miss + DB query) |
| Throughput Worker KFA | ≥ 100 produk / menit (dibatasi rate limit Kemenkes) |
| Ketahanan API gov't | Retry otomatis pada 401 (refresh), 429 (sleep 30-60s), 5xx (retry dengan backoff) |
| Availability | 99.5% (single-instance), 99.9% (multi-instance — butuh migrasi tracker DB) |
| Resource startup | Token initial login, retry 6×, fail-fast Fatal jika tidak berhasil |
| Graceful shutdown | SIGTERM → errgroup cancel → wait-group worker → close DB & cache |
| Keamanan | TLS pada API gov't, parameter binding SQL, payload BPJS dekripsi sebelum log, password DB & secret via env |
| Konfigurasi | Viper YAML + overlay env var (DATABASES_POSTGRES_HOST dsb) |
5. Asumsi & Ketergantungan
- API internal
service-satusehat(port 8096 default,internal_fhir_server_url) sudah running dan menyediakan endpoint:/auth/login,/auth/refresh— token JWT untuk worker./satusehat/reference/kfa/products&/products/{kfa_code}./satusehat/medication,/satusehat/imaging-study,/satusehat/service-request, dst. — proxy ke Kemenkes.
- Database SIMRS read-only (atau read-write via koneksi
simrs/satudata) berisi tabel sumber:m_pasien, transaksi pesan obat, dispensing, imaging study order. - Redis tersedia untuk cache + rate-limit; tanpa Redis sistem fallback ke NoOp cache (bukan failure).
- Akses outbound ke
https://api-satusehat.kemkes.go.iddanhttps://apijkn.bpjs-kesehatan.go.id.
6. Kriteria Sukses (Acceptance Criteria)
v1 (Saat Ini — Production untuk KFA saja)
- Service start dengan REST + gRPC + KFA Worker tanpa error.
- Master KFA tertarik secara periodik & ter-UPSERT lengkap ke 3 tabel.
- RBAC CRUD via REST berfungsi, cache hit > 80% setelah warm-up.
- Login worker SatuSehat berhasil retry 6× sebelum fatal.
v1.x (Aktivasi Worker Klinis — Target Q3 2026)
- Worker
Medication,MedicationRequest,MedicationDispenseaktif → sync log tersimpan, mapping file harian terbentuk, FHIR ID kembali dan tersimpan. - Worker
ServiceRequest (Radiology)&ImagingStudyaktif end-to-end. - Worker
Encounteraktif sebagai prasyarat referensi resource lain. - Bug
satusehatClient = nildi main.go:235 diselesaikan.
v2 (Stateless & Event-Driven — Target Q4 2026 / Q1 2027)
- State tracker (
*.txt) dipindah ke tabelsync_trackeratau Redis hash → mendukung multi-replica. - Kafka producer aktif (saat ini dikomentari di main.go:111-113).
- PostgreSQL
LISTEN/NOTIFYmenggantikan sebagian polling worker. - Endpoint manual retry per
sync_log.iduntuk koreksi data.
7. Di Luar Cakupan (Out of Scope)
- UI dashboard (akan dibangun di repository terpisah, frontend).
- Sinkron pasien (
internal/worker/patient/migrator.go) — kode tersedia tapi tidak dipanggil darimain.go/worker.go; dianggap deprecated atau tugas migrasi one-shot manual. - 13 resource FHIR yang masih stub (lihat §3.1.A) — diaktifkan setelah 6 resource utama stabil.
- Integrasi BPJS aktif sebagai worker — disediakan sebagai SDK, use case belum dikonfirmasi.
8. Risiko & Mitigasi
| Risiko | Dampak | Mitigasi |
|---|---|---|
Tracker .txt korup / race antara replica |
Duplikasi atau data lost saat pengiriman | Pindah ke DB row-locked atau Redis INCR (Devplan Phase 2). |
| Token SatuSehat expired di tengah burst | Worker stuck 401 | Sudah ditangani: refresh dengan mutex + fallback re-login (auth.go). |
| Rate limit Kemenkes berubah | Throughput turun | Setiap worker punya konstanta rateLimitSleep per resource — bisa di-tune via config (rekomendasi). |
| Password hardcoded di patient/migrator.go:23-26 | Keamanan jika diaktifkan | Hapus default atau wajibkan env var sebelum digunakan. |
Bug nil SatuSehat client di main |
Panic jika worker yang membutuhkan diaktifkan | Inisialisasi via satusehat.NewClient(cfg) sebelum worker.NewManager. |
Disusun ulang: Tim Engineering GoPrint, 2026-05-13.