update worker

This commit is contained in:
meninjar
2026-07-29 06:38:42 +00:00
parent cc62620719
commit 7137774c32
15 changed files with 1060 additions and 108 deletions

No files matched your search

+218
View File
@@ -0,0 +1,218 @@
# 🛡️ Quality Management Document (QMD)
**Project:** GoPrint Service General (`worker-satusehat`)
**Versi:** 1.0
**Tanggal:** 2026-05-13
Dokumen ini merangkum **standar mutu, pola tata-kelola kode, dan kontrol resiko** yang berlaku pada codebase. Setiap item disertai titik verifikasi (file/fungsi) supaya bisa diaudit ulang.
---
## 1. Standar Arsitektur
### 1.1 Clean Architecture + CQRS
Setiap modul bisnis (`auth`, `master/role/*`, `master/kfa`, `worker/satusehat/*`) **WAJIB** terdiri minimal dari:
- `entity.go` — definisi domain (GORM struct).
- `dto.go` — request/response & filter.
- `repository.go` — terpisah `CommandRepository` (GORM, primary) dan `QueryRepository` (sqlx, read replica).
- `service.go` — orkestrasi, validasi, integrasi cache.
- `mapper.go` — DTO ↔ Entity (anti-leak GORM tag).
> Generator boilerplate tersedia: lihat [scripts/](scripts/) dan `tools/generate.go`. Wajib digunakan untuk modul baru supaya struktur konsisten.
### 1.2 Pembagian Tanggung Jawab Worker
Setiap worker SatuSehat di `internal/worker/satusehat/<resource>/` menggunakan kontrak yang seragam:
- `Config{ DBManager, InternalBaseURL, OrganizationID }`
- `TokenManager` interface (`GetAccessToken`, `ForceRefreshAndGetToken`) — di-implement oleh `worker.Manager`.
- `Run(ctx context.Context)` — long-running loop dengan select-context untuk *graceful shutdown*.
- Tracker per modul (`last_*_id.txt` / `last_*_time.txt`) — *to be migrated to DB*.
---
## 2. Observability & Logging
### 2.1 Logger (`pkg/logger`)
- Wrapper **Logrus** dengan format JSON otomatis di mode `production`, text-formatted di `development`.
- **`localTimeHook`** memaksa timestamp = `Asia/Jakarta` (WIB). Tidak boleh ada log dengan timezone lain.
- Rotasi harian: `logs/YYYY/MM/YYYY-MM-DD.log` (writer ditutup & dibuka ulang per hari).
- Helper field: `logger.String/Int/Int64/Bool/Any/ErrorField` untuk konsistensi key.
- `caller` & `function_name` aktif otomatis ketika `Environment != "production"`.
### 2.2 Metrics
- `prometheus/client_golang` ter-import. Belum ada handler `/metrics` yang terpasang di routes — **TODO** sebelum production multi-instance.
### 2.3 Tracing
- Field `request_id` (UUID) wajib di-inject melalui middleware HTTP. Untuk worker, gunakan ID dokumen yang sedang diproses (`idxpesanobat`, `kfa_code`) sebagai correlation ID.
---
## 3. Database Resilience
### 3.1 Connection Pool
Setiap entry `databases.<name>` di `config.yaml` wajib mendefinisikan:
```yaml
max_open_conns: 25
max_idle_conns: 25
conn_max_lifetime: 5m
```
Jika `max_open_conns` tidak diatur, infrastructure menerapkan formula default `(CPU_Cores * 2) + 1`.
### 3.2 Multi-DB & Read Replica
- Database Manager mendukung **PostgreSQL, MySQL, SQL Server, SQLite, MongoDB** dalam satu service.
- `CommandRepository` selalu menulis ke primary; `QueryRepository` membaca dari replica (round-robin) jika dikonfigurasi.
- **SLOW QUERY THRESHOLD: 200 ms** (GORM logger adapter); query di atas ambang ini dilog warn level dengan SQL + duration.
### 3.3 Query Builder (`pkg/utils/query`)
- Whitelist kolom + dialect-aware (Postgres, MySQL, MSSQL).
- Pencegahan SQL injection wajib via parameter binding — *no string concat di repository*.
- Tests: [sql_builder_test.go](pkg/utils/query/sql_builder_test.go), [dialects_test.go](pkg/utils/query/dialects_test.go).
---
## 4. Keamanan
### 4.1 Secret Management
- Semua kredensial dilarang hardcoded. Akses via env var atau Viper dari `.env` / `.env.prod`.
- **Anomali yang diketahui** ([patient/migrator.go:23-26](internal/worker/patient/migrator.go#L23-L26)): `defaultUsername "adm_pendaftaran"` & `defaultPassword "1234"`. **WAJIB dihapus** atau dijadikan env-only sebelum file ini diaktifkan.
### 4.2 Auth
- Provider pluggable: `jwt`, `keycloak`, `static`, `hybrid` (config `auth.type` + `auth.fallback_to`).
- JWT signing key di env; Keycloak JWKS URL di env.
- Rate limit per IP dikelola Redis (`security.rate_limit.requests_per_minute`, default 60).
### 4.3 Crypto BPJS
- HMAC-SHA256 untuk signature (`X-cons-id` + `&` + `X-timestamp`).
- Dekripsi AES-256-CBC (`bpjs/crypto.go`):
- key = `SHA256(ConsID + SecretKey + Timestamp)`
- IV = 16 byte pertama dari key
- Padding PKCS7
- Auto-decompression `LZString → Gzip → plaintext` ([decompression.go](internal/interfaces/bpjs/decompression.go)).
### 4.4 SatuSehat OAuth2
- Client-Credentials flow; token cached in-memory dengan **safety margin 60 detik** sebelum exp.
- Pada 401, request retry otomatis setelah `ForceRefreshAndGetToken` ([satusehat/client.go](internal/interfaces/satusehat/client.go)).
- Mutex `tokenMutex` di [worker.Manager](internal/worker/worker.go#L25-L27) mencegah race antar worker.
### 4.5 RBAC Caching
- Kunci cache permission menggunakan SHA-256 dari (role_id, page_id, parameter query) — bukan plaintext.
- *Invalidate by prefix* otomatis pada `Create/Update/Delete`.
---
## 5. Resiliensi Worker
### 5.1 Initial Login Retry
- 6× percobaan dengan jeda 5 detik. Jika semua gagal → `Fatal` (service mati). Lihat [worker.go:42-55](internal/worker/worker.go#L42-L55).
### 5.2 Rate Limit Handling (per worker)
| Worker | Strategi |
| :--- | :--- |
| KFA Master Puller | 30s list API, 60s detail API, 500ms antar item, idle 6h saat halaman kosong |
| Medication / MedicationRequest / MedicationDispense | `rateLimitSleep = 60s` + retry dokumen yang sama (tidak skip ID) |
| ImagingStudy / ServiceRequest | Pola serupa, time-based tracker |
> Deteksi rate-limit fleksibel: cek status code 429 *atau* substring respons (`"too many requests"`, `"rate limit"`, `"limit exceeded"`, `"limit pengiriman"`, `"quota exceeded"`).
### 5.3 Token Recovery
- Tiap worker yang memanggil API internal `service-satusehat` *wajib*:
1. Sertakan `Authorization: Bearer <token>` dari `TokenManager.GetAccessToken()`.
2. Jika respons 401 → `ForceRefreshAndGetToken` lalu retry sekali.
3. Jika refresh gagal → fallback re-login ([auth.go:139-149](internal/worker/auth.go#L139-L149)).
### 5.4 Graceful Shutdown
- Root `context` dengan `errgroup` (`golang.org/x/sync/errgroup`).
- Sinyal `SIGINT`/`SIGTERM``cancel()` → semua goroutine select-context exit → `g.Wait()`.
- Tidak boleh ada `for { ... }` tanpa `select { case <-ctx.Done(): return; default: ... }` di kode worker.
### 5.5 Staggered Startup
- `baseDelay = 10s` antar tiap worker untuk mencegah *thundering herd* terhadap API gov't ([worker.go:268-303](internal/worker/worker.go#L268-L303)).
---
## 6. State Management Worker
### 6.1 Tracker File (Praktik Saat Ini)
- Lokasi: `internal/worker/satusehat/<resource>/last_*.txt` & `internal/master/kfa/kfa_tracker.txt`.
- Format: integer ID (medication, KFA, imagingstudy) atau ISO timestamp (servicerequest radiology).
- Mapping FHIR ID disimpan harian: `mapperdata/YYYY-MM/YYYY-MM-DD.txt` berformat `idxpesanobat|fhir_id`.
> **Batasan kritikal:** tidak aman untuk multi-replica. **Wajib** dipindah ke DB / Redis untuk deployment Kubernetes (lihat Devplan Phase 2).
### 6.2 Sync Log
- Setiap pengiriman → record `SyncLog` (request payload, response, status `SUCCESS`/`FAILED`/`RATE_LIMITED`, error message) tersimpan di tabel SIMRS untuk audit.
---
## 7. Standar Penulisan Kode
### 7.1 Linting & Format
- `go fmt` mandatory (CI hook disarankan).
- Komentar fungsi publik dalam Bahasa Indonesia diperbolehkan (codebase saat ini multilingual); konsistensi per file diutamakan.
### 7.2 Error Handling
- Gunakan `pkg/errors.AppError` untuk error berkode (HTTP/gRPC mapping otomatis).
- *Wrapping*: `fmt.Errorf("konteks: %w", err)` — selalu `%w` jika ingin di-unwrap.
- Worker **tidak boleh panic**; pakai `logger.Error` + retry/skip.
### 7.3 Testing
- File `*_test.go` wajib di package `pkg/utils/query`. Coverage modul bisnis saat ini rendah — **TODO** unit test layer service.
### 7.4 Generator Boilerplate
- Modul baru dibuat via `scripts/context.sh -s <file.sql>` atau `-j <file.json>`.
- Generator menghasilkan: entity, DTO, repository (Command + Query), service, mapper, gRPC proto draft.
---
## 8. Dependensi & Lisensi
- Go runtime: **1.25** (go.mod baris 3).
- Web: Gin 1.10, gRPC 1.78, Swagger via `swaggo/swag` 1.16.
- Persistence: GORM 1.30 (postgres/mysql/sqlserver/sqlite driver), sqlx 1.4, MongoDB driver 1.17.
- Cache & infra: redis/go-redis v9.17, MinIO Go v7.0.98, Prometheus client 1.23.
- Crypto: golang.org/x/crypto v0.49, JWT golang-jwt v5.2.
- Util: logrus 1.9, viper-style config via `karincake/apem`.
- License: Apache 2.0 (lihat header swagger).
---
## 9. Checklist Audit Periodik
- [ ] Semua tracker `.txt` masih dibutuhkan & sinkron dengan DB.
- [ ] Tidak ada secret di repository (`grep -r "password.*=.*\"" .` clean).
- [ ] `logger.Default()` digunakan; tidak ada `fmt.Println` di production path.
- [ ] Setiap worker punya rate-limit handler + token retry.
- [ ] Cache TTL & invalidation pattern terdokumentasi per modul.
- [ ] Migration script idempotent.
- [ ] Prometheus `/metrics` endpoint live & terkonsumsi monitoring stack.
---
*Disusun ulang: Tim Engineering GoPrint, 2026-05-13.*