253 lines
12 KiB
Markdown
253 lines
12 KiB
Markdown
# Product Requirements Document (PRD)
|
||
## Service: `service-satusehat`
|
||
|
||
| Field | Value |
|
||
|---|---|
|
||
| Document Version | 1.0 |
|
||
| Status | Draft |
|
||
| Owner | Backend Engineering — Meninjar |
|
||
| Last Updated | 2026-05-13 |
|
||
| Repository | `goprint/service-satusehat` |
|
||
| Primary Language | Go 1.25 |
|
||
| Target Audience | Backend engineers, integration partners, ops, hospital IT (RS) |
|
||
|
||
---
|
||
|
||
## 1. Overview
|
||
|
||
### 1.1 Product Summary
|
||
|
||
`service-satusehat` is a backend microservice that acts as the **integration gateway** between an Indonesian hospital information system (SIMRS / HIS) and Indonesia's national health platforms — primarily **SATUSEHAT** (HL7 FHIR R4) operated by the Ministry of Health, with secondary integration paths for **BPJS Kesehatan** (VClaim, Antrol, Apotek, Aplicare, IHS) and supporting infrastructure (Keycloak SSO, MinIO object storage, Redis cache, Prometheus observability).
|
||
|
||
The service exposes a **dual transport surface** (REST via Gin and gRPC) and is built on **Clean Architecture + Domain-Driven Design + CQRS**. It centralizes all outbound calls to SATUSEHAT, normalizes FHIR resource construction, manages OAuth2 tokens, and protects upstream callers from FHIR/JSON-Patch complexity.
|
||
|
||
### 1.2 Problem Statement
|
||
|
||
Hospitals in Indonesia are mandated by the Ministry of Health to send clinical encounter data to SATUSEHAT (HL7 FHIR). Direct integration is hard because:
|
||
|
||
1. **Heterogeneous internal data sources** — most hospitals have data spread across multiple databases (PostgreSQL / MySQL / SQL Server) and legacy systems.
|
||
2. **Strict FHIR R4 contract** — resource structure, references, codings, and identifier systems must follow SATUSEHAT IG.
|
||
3. **OAuth2 token lifecycle** — SATUSEHAT requires short-lived tokens with automatic refresh and concurrency-safe caching.
|
||
4. **Auxiliary services** — KFA (drug master), KYC, Consent, DICOM, BPJS all have different auth, signing, and payload conventions.
|
||
5. **Observability & auditability** — every regulated submission must be logged, traceable, and retryable.
|
||
|
||
A single integration service that solves the above once, and is reusable across hospital products, is significantly cheaper than re-implementing the contract in every product team.
|
||
|
||
### 1.3 Goals
|
||
|
||
| # | Goal | Success indicator |
|
||
|---|---|---|
|
||
| G1 | Provide one canonical Go service that submits every required FHIR resource to SATUSEHAT | All 19 FHIR resources implemented with Create/Update/Patch/Get/Search |
|
||
| G2 | Abstract OAuth2 + auxiliary auth (KFA, KYC, Consent, DICOM) from callers | Single client handles token caching and header injection |
|
||
| G3 | Be deployable in a hospital data center with minimal ops effort | Single Docker image, distroless, Compose stack with dev/prod profiles |
|
||
| G4 | Stay observable in production | Prometheus metrics, structured logs, health endpoints, request tracing fields |
|
||
| G5 | Stay vendor-agnostic at the storage layer | Multi-DB support (Postgres, MySQL, SQL Server, MongoDB, SQLite) with read replicas |
|
||
| G6 | Be safe to refactor and extend | Clean Architecture boundaries, generated code, CQRS separation |
|
||
|
||
### 1.4 Non-Goals
|
||
|
||
- ❌ **Front-end UI** — this is a backend service only.
|
||
- ❌ **Long-term clinical data storage** — the hospital's primary database remains the source of truth.
|
||
- ❌ **Generic FHIR server** — only SATUSEHAT-required resources and profiles are supported, not the full HL7 FHIR spec.
|
||
- ❌ **BPJS claim submission UI/UX** — only the integration layer is in scope.
|
||
- ❌ **HL7 v2 messaging** — out of scope.
|
||
|
||
---
|
||
|
||
## 2. Target Users & Personas
|
||
|
||
### 2.1 Primary Users (callers)
|
||
|
||
| Persona | Description | What they need |
|
||
|---|---|---|
|
||
| **SIMRS Backend** | Internal hospital ERP/HIS server that emits clinical events | A stable REST/gRPC contract that hides SATUSEHAT details |
|
||
| **Mobile / Web App teams** | Patient portal, clinician app | A simple "submit encounter" API; no FHIR construction |
|
||
| **Data engineering** | Builds dashboards / reports on submitted resources | Read-back, search, and audit logs |
|
||
|
||
### 2.2 Secondary Users
|
||
|
||
| Persona | Description |
|
||
|---|---|
|
||
| **Ops / SRE** | Runs the container in the hospital data center. Cares about logs, metrics, health, restart safety |
|
||
| **Integration developers** | Add new SATUSEHAT resources, debug failures |
|
||
| **Compliance / regulators** | Need audit trail of submissions for inspection |
|
||
|
||
---
|
||
|
||
## 3. Functional Requirements
|
||
|
||
### 3.1 SATUSEHAT FHIR Submission (P0 — core value)
|
||
|
||
The service MUST expose endpoints for the following 19 FHIR resources, each with **Create / Update (full) / Patch (JSON Patch RFC 6902) / Get-by-ID / Search**:
|
||
|
||
| # | Resource | Use case |
|
||
|---|---|---|
|
||
| 1 | AllergyIntolerance | Patient allergy registry |
|
||
| 2 | CarePlan | Treatment plan |
|
||
| 3 | ClinicalImpression | Clinician assessment |
|
||
| 4 | Composition | Document grouping |
|
||
| 5 | Condition | Diagnosis (ICD-10) |
|
||
| 6 | DiagnosticReport | Lab / radiology report |
|
||
| 7 | Encounter | Patient visit (rawat jalan/inap/IGD) |
|
||
| 8 | EpisodeOfCare | Continuous treatment episode |
|
||
| 9 | ImagingStudy | Radiology study link |
|
||
| 10 | Immunization | Vaccination record |
|
||
| 11 | Medication | Drug definition |
|
||
| 12 | MedicationDispense | Pharmacy dispense event |
|
||
| 13 | MedicationRequest | Prescription |
|
||
| 14 | MedicationStatement | Patient-reported medication |
|
||
| 15 | Observation | Vital signs, lab results |
|
||
| 16 | Procedure | Performed procedure (ICD-9-CM) |
|
||
| 17 | QuestionnaireResponse | Form / triage answers |
|
||
| 18 | ServiceRequest | Lab / radiology order |
|
||
| 19 | Specimen | Lab specimen |
|
||
|
||
Plus minimal **Studies (DICOM)** for imaging linkage.
|
||
|
||
### 3.2 SATUSEHAT Reference Lookups (P0)
|
||
|
||
The service MUST proxy reads to the following SATUSEHAT registries:
|
||
|
||
- **Patient** — search by NIK, name, DOB
|
||
- **Practitioner** — by NIK or NPP
|
||
- **Organization** — facility registry
|
||
- **Location** — room/bed
|
||
- **KFA** — Katalog Farmasi Alkes (drug & device master)
|
||
- **KYC** — verifikasi identitas
|
||
- **Auth** — token refresh / validate
|
||
|
||
### 3.3 Authentication & Authorization (P0)
|
||
|
||
- **Inbound**: JWT-based auth (with Keycloak, static-token, and hybrid modes). RBAC via Role / Page / Permission / Access master tables.
|
||
- **Outbound**: OAuth2 client-credentials flow to SATUSEHAT with concurrency-safe in-memory token caching (≥1 minute buffer before expiry).
|
||
- **BPJS**: HMAC-SHA256 signature header per BPJS spec (cons-id + secret).
|
||
|
||
### 3.4 Storage & Master Data (P1)
|
||
|
||
- Multi-database support (Postgres preferred) for:
|
||
- Auth (users, sessions, tokens)
|
||
- Role / Page / Permission / Access (RBAC master)
|
||
- Audit log of SATUSEHAT submissions (TBD — see §7 Gaps)
|
||
- Read replicas with round-robin load balancing.
|
||
- GORM as primary ORM; raw SQL via sqlx / squirrel where ORM is too slow.
|
||
|
||
### 3.5 Cross-Cutting (P1)
|
||
|
||
- Structured logging (logrus) to console + daily file `logs/YYYY/MM/YYYY-MM-DD.log`.
|
||
- Prometheus metrics: HTTP request counts/latency, DB pool stats, cache hit ratio, error counters by code.
|
||
- Health endpoints: overall + per-database + external (SATUSEHAT, KFA, KYC).
|
||
- i18n-ready error system (English + Indonesian).
|
||
- Soft-delete + audit trail at the master-data layer.
|
||
|
||
### 3.6 Object Storage (P2)
|
||
|
||
- MinIO integration for storing supporting artifacts (e.g., DICOM tarballs, KYC scans, consent PDFs). Buckets configurable per environment.
|
||
|
||
---
|
||
|
||
## 4. Non-Functional Requirements
|
||
|
||
| Category | Requirement |
|
||
|---|---|
|
||
| **Performance** | P95 latency for outbound SATUSEHAT create ≤ 2 s when SATUSEHAT responds within SLA; service overhead ≤ 50 ms |
|
||
| **Throughput** | ≥ 100 sustained writes/sec per service instance (single-node, 4 vCPU) |
|
||
| **Availability** | 99.5 % (hospital data-center, single instance acceptable; horizontal scale-out supported) |
|
||
| **Recovery** | Graceful shutdown ≤ 5 s; in-flight requests drained on SIGTERM |
|
||
| **Security** | No plaintext secrets in logs; parameterised queries; CORS configurable; rate-limit configurable |
|
||
| **Compliance** | Comply with Permenkes 24/2022 (rekam medis elektronik) and SATUSEHAT IG R4 |
|
||
| **Observability** | Every outbound SATUSEHAT call MUST be traceable by `request_id` (TBD) |
|
||
| **Portability** | Single static binary, distroless image, runs on amd64 Linux |
|
||
| **Time zone** | All timestamps in `Asia/Jakarta` (WIB); FHIR payloads use ISO-8601 with offset |
|
||
|
||
---
|
||
|
||
## 5. Out-of-Scope Items (deliberately excluded)
|
||
|
||
- Web frontend / admin UI.
|
||
- Long-term clinical archival.
|
||
- HL7 v2 messaging.
|
||
- Direct BPJS claim file generation (RBAC adjustments only).
|
||
- Patient-facing mobile API.
|
||
|
||
---
|
||
|
||
## 6. Dependencies
|
||
|
||
### 6.1 External (third-party)
|
||
|
||
| Dependency | Purpose | Notes |
|
||
|---|---|---|
|
||
| SATUSEHAT FHIR R4 | Primary integration target | Staging + production base URLs configured |
|
||
| SATUSEHAT KFA | Drug & device master | Separate endpoint and headers |
|
||
| SATUSEHAT KYC | Identity verification | Public/private key pair (config) |
|
||
| SATUSEHAT Consent | Patient consent | Webhook secret configured |
|
||
| SATUSEHAT DICOM | Imaging study upload | Separate endpoint |
|
||
| BPJS VClaim / Antrol / Apotek / Aplicare / IHS | Insurance integration | HMAC-SHA256 auth |
|
||
| Keycloak | SSO / OAuth2 issuer (optional) | JWKS validation |
|
||
|
||
### 6.2 Internal
|
||
|
||
- PostgreSQL 12+ (recommended)
|
||
- Redis 6+ (cache, rate limit) — optional but recommended
|
||
- MinIO (S3-compatible) — optional
|
||
- Prometheus (scrape `/metrics`)
|
||
|
||
---
|
||
|
||
## 7. Known Gaps & Risks (carried into DEVPLAN)
|
||
|
||
| # | Gap | Severity | Owner |
|
||
|---|---|---|---|
|
||
| R1 | gRPC defined in config but **no `.proto` files committed** and registry empty | High | Backend |
|
||
| R2 | Test coverage ≈ **2 files total** — query builder only | High | Backend |
|
||
| R3 | Rate-limit config exists, no middleware implementation | Medium | Backend |
|
||
| R4 | Auth logout does **not** revoke refresh tokens in DB (TODO at `internal/auth/service.go:233`) | Medium | Backend |
|
||
| R5 | KYC service does **not** persist verification to local DB | Medium | Backend |
|
||
| R6 | Role / Page / Permission services have TODO cache invalidation | Medium | Backend |
|
||
| R7 | 60+ `fmt.Printf` debug calls in `pkg/utils/query` — leaks to stdout in production | Low | Backend |
|
||
| R8 | NoOp cache fallback is not thread-safe (map without mutex) | Medium | Backend |
|
||
| R9 | Folder name typo `internal/master/role/accses/` (should be `access`) | Low | Backend |
|
||
| R10 | Audit-log table for SATUSEHAT submissions not yet defined | High | Backend |
|
||
| R11 | No CI pipeline committed | High | Ops |
|
||
|
||
---
|
||
|
||
## 8. Success Metrics
|
||
|
||
| Metric | Target |
|
||
|---|---|
|
||
| SATUSEHAT submission success rate | ≥ 99 % (per resource, per hour) |
|
||
| Coverage on `internal/satusehat/usecase/**` | ≥ 60 % unit tests, ≥ 1 contract test per resource |
|
||
| Mean time to add a new FHIR resource | ≤ 1 day (via code-gen template) |
|
||
| Production crash-loop incidents | 0 per month |
|
||
| Time to detect a SATUSEHAT outage | ≤ 1 minute via health probe |
|
||
|
||
---
|
||
|
||
## 9. Release Plan (high-level — detail in DEVPLAN)
|
||
|
||
| Milestone | Description |
|
||
|---|---|
|
||
| **M1 — Hardening** | Fix R1–R3, R7, R8; add CI; unit-test FHIR mappers |
|
||
| **M2 — Auditability** | Implement audit-log table + middleware emitting one row per outbound SATUSEHAT call (R10) |
|
||
| **M3 — gRPC** | Author proto files; generate; register services for at least Encounter, EpisodeOfCare, Condition, Observation |
|
||
| **M4 — Resilience** | Retry with exponential backoff for SATUSEHAT 5xx + circuit breaker |
|
||
| **M5 — Production rollout** | Single-instance deployment in hospital DC, then dual-instance behind nginx |
|
||
|
||
---
|
||
|
||
## 10. Glossary
|
||
|
||
| Term | Meaning |
|
||
|---|---|
|
||
| **SATUSEHAT** | Indonesia national health-data platform (Kemenkes) |
|
||
| **FHIR** | Fast Healthcare Interoperability Resources (HL7 R4) |
|
||
| **BPJS** | Badan Penyelenggara Jaminan Sosial — Indonesian social insurance |
|
||
| **VClaim** | BPJS claim API |
|
||
| **KFA** | Katalog Farmasi Alkes (drug/device catalogue) |
|
||
| **KYC** | Know Your Customer — identity verification |
|
||
| **SIMRS** | Sistem Informasi Manajemen Rumah Sakit (hospital management system) |
|
||
| **IHS** | Indonesia Health Services (BPJS) |
|
||
| **CQRS** | Command Query Responsibility Segregation |
|
||
| **DDD** | Domain-Driven Design |
|