secretkey update
This commit is contained in:
No files matched your search
@@ -0,0 +1,505 @@
|
||||
# 📋 Dokumentasi Modul — `internal/aplicare`
|
||||
|
||||
Modul ini adalah **inti dari fitur Aplicare** — bertanggung jawab penuh atas proses sinkronisasi data ketersediaan tempat tidur antara **SIMRS** dan **BPJS Kesehatan** melalui API Aplicares.
|
||||
|
||||
---
|
||||
|
||||
## Daftar Isi
|
||||
|
||||
1. [Apa itu Modul Aplicare?](#apa-itu-modul-aplicare)
|
||||
2. [Struktur File](#struktur-file)
|
||||
3. [Penjelasan Per File](#penjelasan-per-file)
|
||||
4. [Alur Sinkronisasi (End-to-End)](#alur-sinkronisasi-end-to-end)
|
||||
5. [Struktur Data Penting](#struktur-data-penting)
|
||||
6. [Environment Variable yang Dipakai](#environment-variable-yang-dipakai)
|
||||
7. [Endpoint HTTP](#endpoint-http)
|
||||
8. [Cara Mengembangkan Lebih Lanjut](#cara-mengembangkan-lebih-lanjut)
|
||||
|
||||
---
|
||||
|
||||
## Apa itu Modul Aplicare?
|
||||
|
||||
Modul ini menyelesaikan satu masalah spesifik:
|
||||
|
||||
> *"Berapa tempat tidur yang tersedia di setiap ruangan SIMRS saat ini? Kalau ada yang berubah dari sebelumnya, kirimkan perubahannya ke BPJS."*
|
||||
|
||||
Prosesnya berjalan **otomatis di background** menggunakan scheduler, dan bisa juga dipicu manual melalui HTTP endpoint. Hanya data yang **benar-benar berubah** yang dikirim ke BPJS — efisien, tidak flood API.
|
||||
|
||||
---
|
||||
|
||||
## Struktur File
|
||||
|
||||
```
|
||||
internal/aplicare/
|
||||
├── aplicare.go ← Entry point modul: AplicaresHandler + HTTP handlers + Scheduler
|
||||
├── bpjs.go ← Client HTTP ke API BPJS Aplicares (BacaKamar, PostKamar, dsb.)
|
||||
├── database.go ← Query ke database SIMRS + transform data menjadi BedData
|
||||
├── state.go ← Baca/tulis state.json + hitung diff (apa yang berubah)
|
||||
└── synclog.go ← Tulis log sinkronisasi ke file JSON Lines harian
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Penjelasan Per File
|
||||
|
||||
---
|
||||
|
||||
### `aplicare.go` — Handler Utama & Scheduler
|
||||
|
||||
File ini adalah **pintu masuk** modul. Di sini semua komponen dirakit dan di-expose ke HTTP.
|
||||
|
||||
#### Struct
|
||||
|
||||
```go
|
||||
type AplicaresHandler struct {
|
||||
syncer *Syncer // orkestrasi proses sync
|
||||
simrs *SimrsDB // pembaca database SIMRS
|
||||
validator *validator.Validate
|
||||
logger logger.Logger
|
||||
cfg *config.Config
|
||||
once sync.Once // pastikan scheduler hanya jalan sekali
|
||||
interval time.Duration // interval sync dari env APLICARES_SYNC_INTERVAL
|
||||
}
|
||||
```
|
||||
|
||||
#### `NewAplicaresHandler(cfg)`
|
||||
|
||||
Fungsi konstruktor. Yang dilakukan saat dipanggil:
|
||||
1. Baca `APLICARES_STATE_PATH` dari env (default: `./data/state.json`)
|
||||
2. Baca `APLICARES_SYNC_INTERVAL` dari env (default: `5m`)
|
||||
3. Baca `APLICARES_DRY_RUN` dari env (default: `false`)
|
||||
4. Inisialisasi `SimrsDB`, `Syncer`
|
||||
5. Pastikan direktori `./data` ada (`os.MkdirAll`)
|
||||
|
||||
#### Scheduler
|
||||
|
||||
```
|
||||
StartScheduler(ctx)
|
||||
└── sync.Once → goroutine runScheduler(ctx)
|
||||
├── runOnce() segera saat startup
|
||||
└── ticker setiap `interval`:
|
||||
└── runOnce() → Syncer.Sync(ctx)
|
||||
```
|
||||
|
||||
Scheduler **berhenti otomatis** ketika `ctx.Done()` — yaitu saat aplikasi menerima sinyal `SIGTERM`/`SIGINT` (graceful shutdown). Tidak perlu cleanup manual.
|
||||
|
||||
#### HTTP Handlers
|
||||
|
||||
| Handler | Method | Path | Timeout |
|
||||
|---|---|---|---|
|
||||
| `GetBeds` | GET | `/api/v1/aplicares/beds` | 30s |
|
||||
| `GetState` | GET | `/api/v1/aplicares/state` | — |
|
||||
| `TriggerSync` | POST | `/api/v1/aplicares/sync` | 120s |
|
||||
| `CheckBPJS` | GET | `/api/v1/aplicares/check-bpjs` | 30s |
|
||||
| `GetRefKelas` | GET | `/api/v1/aplicares/ref/kelas` | 30s |
|
||||
| `GetSyncLogs` | GET | `/api/v1/aplicares/logs` | — |
|
||||
|
||||
> **`GetSyncLogs`** membaca file `./logs/sync.log`, mengembalikan 100 entry terakhir, diurutkan terbaru di atas.
|
||||
|
||||
> **Kapan dimodifikasi:** Tambah handler baru di sini jika ada endpoint baru untuk modul Aplicare.
|
||||
|
||||
---
|
||||
|
||||
### `bpjs.go` — Client HTTP ke API BPJS Aplicares
|
||||
|
||||
Semua komunikasi ke BPJS dilakukan di file ini. File lain tidak boleh langsung hit ke API BPJS.
|
||||
|
||||
#### Struct
|
||||
|
||||
```go
|
||||
type BpjsClient struct {
|
||||
baseURL string
|
||||
consID string
|
||||
consSecret string
|
||||
kodePPK string // kode provider (faskes)
|
||||
httpClient *http.Client
|
||||
}
|
||||
```
|
||||
|
||||
#### Autentikasi (HMAC-SHA256)
|
||||
|
||||
Setiap request dikirim dengan 3 header khusus:
|
||||
```
|
||||
X-cons-id : {consID}
|
||||
X-timestamp : {unix timestamp saat ini}
|
||||
X-signature : base64(HMAC-SHA256("{consID}&{timestamp}", consSecret))
|
||||
```
|
||||
|
||||
> ⚠️ Autentikasi Aplicares **berbeda** dengan VClaim. VClaim pakai tambahan `user_key`, Aplicares tidak.
|
||||
|
||||
#### Method yang Tersedia
|
||||
|
||||
| Method | Request ke BPJS | Keterangan |
|
||||
|---|---|---|
|
||||
| `BacaKamar(ctx, start, limit)` | `GET bed/read/{kodePPK}/{start}/{limit}` | Baca daftar kamar di BPJS |
|
||||
| `PostKamar(ctx, bed)` | `POST bed/update` → fallback `POST bed/create` | Kirim data kamar (upsert) |
|
||||
| `HapusKamar(ctx, kodekelas, koderuang)` | `POST bed/delete/{kodePPK}` | Hapus satu kamar dari BPJS |
|
||||
| `Flush(ctx, currentBeds)` | Kombinasi BacaKamar + HapusKamar | Hapus kamar di BPJS yang sudah tidak ada di SIMRS |
|
||||
| `GetRefKelas(ctx)` | `GET ref/kelas` | Ambil referensi kelas perawatan dari BPJS |
|
||||
|
||||
#### Logika `PostKamar` (Upsert)
|
||||
|
||||
```
|
||||
PostKamar(bed)
|
||||
├── POST bed/update/{kodePPK}
|
||||
│ ├── [sukses: code=1] → return nil ✓
|
||||
│ └── [gagal]
|
||||
│ └── POST bed/create/{kodePPK}
|
||||
│ ├── [sukses: code=1] → return nil ✓
|
||||
│ ├── [response "sudah ada"] → POST bed/update lagi → return
|
||||
│ └── [gagal] → return error ✗
|
||||
```
|
||||
|
||||
#### Konfigurasi Kredensial
|
||||
|
||||
Prioritas env var (dari tertinggi ke terendah):
|
||||
1. `APLICARES_BPJS_BASEURL`, `APLICARES_BPJS_CONSID`, `APLICARES_BPJS_SECRETKEY` (khusus Aplicares)
|
||||
2. `BPJS_BASEURL`, `BPJS_CONSID`, `BPJS_SECRETKEY` (fallback ke config umum BPJS)
|
||||
|
||||
> **Kapan dimodifikasi:** Jika ada endpoint baru dari API BPJS Aplicares, tambahkan method baru di sini.
|
||||
|
||||
---
|
||||
|
||||
### `database.go` — Pembaca SIMRS & Transform Data
|
||||
|
||||
File ini bertugas membaca data dari database SIMRS dan mengubahnya menjadi format yang bisa dikirim ke BPJS.
|
||||
|
||||
#### Struct: `SimrsDB`
|
||||
|
||||
```go
|
||||
type SimrsDB struct {
|
||||
db database.Service
|
||||
}
|
||||
```
|
||||
|
||||
#### Tabel yang Dibaca dari SIMRS
|
||||
|
||||
**1. `m_ruang` — master ruangan**
|
||||
```sql
|
||||
SELECT no, jumlah_tt, kode_aplicare, nama_ruang, kode_kelas
|
||||
FROM m_ruang
|
||||
WHERE st_aktif = 1 AND kode_aplicare IS NOT NULL
|
||||
ORDER BY no
|
||||
```
|
||||
- `kode_aplicare` — kode ruangan yang sudah di-mapping ke format BPJS (diisi via Admin Panel)
|
||||
- `kode_kelas` — kelas perawatan (KL1, KL2, KL3, ICU, dsb.)
|
||||
- Hanya ruangan dengan `kode_aplicare` yang sudah diisi yang ikut sync
|
||||
|
||||
**2. `m_detail_tempat_tidur` — detail bed yang terisi**
|
||||
```sql
|
||||
SELECT idxruang
|
||||
FROM m_detail_tempat_tidur
|
||||
WHERE status IN (1, 5)
|
||||
```
|
||||
- Setiap row = 1 bed yang sedang **tidak tersedia** (terisi/dipakai)
|
||||
- `status 1` dan `5` = kondisi bed tidak tersedia (sesuai konvensi SIMRS setempat)
|
||||
|
||||
#### Kalkulasi `tersedia`
|
||||
|
||||
```
|
||||
tersedia = jumlah_tt - COUNT(row di m_detail per ruangan)
|
||||
```
|
||||
|
||||
- `jumlah_tt` = total kapasitas dari `m_ruang`
|
||||
- `COUNT(...)` = jumlah bed terisi dari `m_detail_tempat_tidur`
|
||||
|
||||
Hasil ini disimpan dalam `BedData.Tersedia`.
|
||||
|
||||
#### `NamaKelasMap` — Mapping Kode → Nama Kelas
|
||||
|
||||
```go
|
||||
var NamaKelasMap = map[string]string{
|
||||
"NON": "-",
|
||||
"VVP": "VVIP",
|
||||
"VIP": "VIP",
|
||||
"UTM": "UTAMA",
|
||||
"KL1": "KELAS I",
|
||||
"KL2": "KELAS II",
|
||||
"KL3": "KELAS III",
|
||||
"ICU": "ICU",
|
||||
"ICC": "ICCU",
|
||||
"NIC": "NICU",
|
||||
"PIC": "PICU",
|
||||
"IGD": "IGD",
|
||||
"UGD": "UGD",
|
||||
"SAL": "RUANG BERSALIN",
|
||||
"HCU": "HCU",
|
||||
"ISO": "RUANG ISOLASI",
|
||||
}
|
||||
```
|
||||
|
||||
Jika kode tidak ada di map, nama kelas akan diisi langsung dengan nilai kode dari database.
|
||||
|
||||
> **Kapan dimodifikasi:**
|
||||
> - Tambah kelas baru → tambahkan ke `NamaKelasMap`
|
||||
> - Ganti query → modifikasi `GetRuangan()` atau `GetBedDetails()`
|
||||
> - Ganti kondisi status bed → ubah `WHERE status IN (1, 5)`
|
||||
|
||||
---
|
||||
|
||||
### `state.go` — Manajemen State & Deteksi Perubahan
|
||||
|
||||
File ini menjawab pertanyaan: *"Apakah data tempat tidur ruangan X sudah berubah sejak sync terakhir?"*
|
||||
|
||||
State disimpan di file `data/state.json` agar persisten meski server restart.
|
||||
|
||||
#### Struct
|
||||
|
||||
```go
|
||||
// Nilai sesaat dari satu ruangan
|
||||
type RoomSnapshot struct {
|
||||
Kapasitas int
|
||||
Tersedia int
|
||||
TersediaPria int
|
||||
TersediaWanita int
|
||||
TersediaPriaWanita int
|
||||
}
|
||||
|
||||
// State per ruangan (old vs new)
|
||||
type RoomState struct {
|
||||
KodeRuang string
|
||||
KodeKelas string
|
||||
NamaRuang string
|
||||
OldValue RoomSnapshot // nilai saat sync sebelumnya
|
||||
NewValue RoomSnapshot // nilai saat ini
|
||||
Changed bool // true jika OldValue != NewValue
|
||||
LastSynced string // timestamp terakhir berhasil dikirim ke BPJS
|
||||
}
|
||||
|
||||
// Root state.json
|
||||
type State struct {
|
||||
LastUpdated string
|
||||
Rooms map[string]RoomState // key: kode_ruang
|
||||
}
|
||||
```
|
||||
|
||||
#### Fungsi
|
||||
|
||||
| Fungsi | Tujuan |
|
||||
|---|---|
|
||||
| `LoadState(path)` | Baca `state.json` dari disk. Jika file belum ada, return empty state (bukan error) |
|
||||
| `SaveState(path, state)` | Tulis state ke disk. Otomatis set `last_updated` ke waktu sekarang |
|
||||
| `ComputeDiff(old, current)` | Bandingkan data SIMRS terbaru vs state lama. Set `Changed=true` hanya yang berbeda |
|
||||
| `GetChangedBeds(state, allBeds)` | Filter dan return hanya `BedData` yang `Changed=true` |
|
||||
|
||||
#### Cara Kerja `ComputeDiff`
|
||||
|
||||
```
|
||||
untuk setiap ruangan di data SIMRS terbaru:
|
||||
ambil RoomSnapshot lama dari state.json (jika ada)
|
||||
buat RoomSnapshot baru dari data terbaru
|
||||
bandingkan (snapshotEqual):
|
||||
jika berbeda → Changed = true, LastSynced = now
|
||||
jika sama → Changed = false, pertahankan LastSynced lama
|
||||
simpan ke newState
|
||||
```
|
||||
|
||||
> **Kapan dimodifikasi:**
|
||||
> - Tambah field baru yang perlu dibandingkan → tambahkan ke `RoomSnapshot` dan `snapshotEqual()`
|
||||
> - Ganti lokasi state file → ubah default path di `NewAplicaresHandler` atau env `APLICARES_STATE_PATH`
|
||||
|
||||
---
|
||||
|
||||
### `synclog.go` — Logging Sinkronisasi
|
||||
|
||||
Menulis log setiap aktivitas sync ke file JSON Lines, dipisah per hari secara otomatis.
|
||||
|
||||
#### Struct
|
||||
|
||||
```go
|
||||
type SyncLog struct {
|
||||
Timestamp string // waktu event
|
||||
KodeRuang string // kode ruangan yang di-sync
|
||||
NamaRuang string
|
||||
KodeKelas string
|
||||
Kapasitas int
|
||||
Tersedia int
|
||||
Action string // "post", "batch_sync"
|
||||
Status string // "sukses", "gagal", "partial"
|
||||
Error string // isi jika status gagal
|
||||
ResponseMs int64 // latensi response BPJS dalam ms
|
||||
}
|
||||
```
|
||||
|
||||
#### Nama File Log
|
||||
|
||||
```
|
||||
logs/sync-{YYYY-MM-DD}.log
|
||||
```
|
||||
|
||||
Contoh: `logs/sync-2026-07-10.log`
|
||||
|
||||
Tidak ada rotasi manual — pemisahan otomatis per hari karena nama file sudah mengandung tanggal.
|
||||
|
||||
#### Fungsi
|
||||
|
||||
| Fungsi | Kapan Dipanggil | Isi Log |
|
||||
|---|---|---|
|
||||
| `WriteLog(entry)` | Setelah setiap `PostKamar` (per kamar) | kode ruangan, status, latensi, error |
|
||||
| `WriteBatchLog(result)` | Di akhir setiap satu run sync | total rooms, changed, posted, status batch |
|
||||
|
||||
#### Menentukan Status Batch
|
||||
|
||||
```
|
||||
jika len(errors) > 0 → status = "partial"
|
||||
jika posted == 0 && changed > 0 → status = "gagal"
|
||||
selainnya → status = "sukses"
|
||||
```
|
||||
|
||||
> **Kapan dimodifikasi:**
|
||||
> - Tambah field baru ke log → tambahkan ke struct `SyncLog`
|
||||
> - Ubah format/lokasi log → modifikasi `getLogPath()` dan `writeToFile()`
|
||||
|
||||
---
|
||||
|
||||
## Alur Sinkronisasi (End-to-End)
|
||||
|
||||
```
|
||||
[Scheduler ticker / POST /sync]
|
||||
│
|
||||
▼
|
||||
Syncer.Sync(ctx)
|
||||
│
|
||||
├─ 1. simrs.GetRuangan()
|
||||
│ └─ Query m_ruang WHERE st_aktif=1 AND kode_aplicare IS NOT NULL
|
||||
│
|
||||
├─ 2. simrs.GetBedDetails()
|
||||
│ └─ Query m_detail_tempat_tidur WHERE status IN (1,5)
|
||||
│
|
||||
├─ 3. buildBedData(ruangans, detailMap)
|
||||
│ └─ tersedia = jumlah_tt - COUNT(bed terisi per ruangan)
|
||||
│
|
||||
├─ 4. LoadState("./data/state.json")
|
||||
│
|
||||
├─ 5. ComputeDiff(oldState, beds)
|
||||
│ └─ bandingkan RoomSnapshot lama vs baru
|
||||
│
|
||||
├─ 6. GetChangedBeds(newState, beds)
|
||||
│ └─ filter hanya yang Changed = true
|
||||
│
|
||||
├─ [DRY_RUN = true]
|
||||
│ ├─ Tampilkan perubahan di stdout saja
|
||||
│ ├─ SaveState()
|
||||
│ └─ WriteBatchLog() → SELESAI
|
||||
│
|
||||
└─ [LIVE MODE]
|
||||
│
|
||||
├─ 7. untuk setiap bed yang berubah:
|
||||
│ ├─ BpjsClient.PostKamar(bed)
|
||||
│ │ ├─ [sukses] WriteLog(status="sukses"), result.Posted++
|
||||
│ │ └─ [gagal] WriteLog(status="gagal"), append ke result.Errors
|
||||
│ └─ Update newState: OldValue = NewValue, Changed = false
|
||||
│
|
||||
├─ 8. SaveState("./data/state.json", newState)
|
||||
│
|
||||
└─ 9. WriteBatchLog(result)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Struktur Data Penting
|
||||
|
||||
### `BedData` — Data Siap Kirim ke BPJS
|
||||
|
||||
```go
|
||||
type BedData struct {
|
||||
No int // nomor urut ruangan di SIMRS
|
||||
KodeKelas string // kode kelas (KL1, KL2, ICU, dsb.)
|
||||
NamaKelas string // nama kelas panjang (KELAS I, ICU, dsb.)
|
||||
KodeRuang string // kode BPJS ruangan (dari kolom kode_aplicare)
|
||||
NamaRuang string // nama ruangan
|
||||
Kapasitas int // total tempat tidur
|
||||
Tersedia int // tempat tidur kosong saat ini
|
||||
TersediaPria int // selalu 0 (belum dibedakan)
|
||||
TersediaWanita int // selalu 0 (belum dibedakan)
|
||||
TersediaPriaWanita int // = Tersedia (sementara semua masuk sini)
|
||||
}
|
||||
```
|
||||
|
||||
> **Catatan pengembangan:** Field `TersediaPria` dan `TersediaWanita` saat ini selalu 0. Jika SIMRS sudah mencatat jenis kelamin pasien per bed, logika di `buildBedData()` bisa diperbarui.
|
||||
|
||||
### `SyncResult` — Ringkasan Satu Run Sync
|
||||
|
||||
```go
|
||||
type SyncResult struct {
|
||||
RunAt string // timestamp mulai sync
|
||||
TotalRooms int // jumlah ruangan yang dibaca dari SIMRS
|
||||
Changed int // jumlah ruangan yang terdeteksi berubah
|
||||
Posted int // jumlah ruangan yang berhasil dikirim ke BPJS
|
||||
Errors []string // daftar error yang terjadi
|
||||
DryRun bool // apakah ini dry run atau live
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Environment Variable yang Dipakai
|
||||
|
||||
| Variable | Default | Keterangan |
|
||||
|---|---|---|
|
||||
| `APLICARES_SYNC_INTERVAL` | `5m` | Interval scheduler otomatis. Format Go duration: `1m`, `10m`, `1h` |
|
||||
| `APLICARES_STATE_PATH` | `./data/state.json` | Lokasi file state persistence |
|
||||
| `APLICARES_DRY_RUN` | `false` | Jika `true`, tidak ada yang dikirim ke BPJS. Hanya tampilkan diff di stdout |
|
||||
| `APLICARES_KODE_PPK` | `1323R001` | Kode Provider (faskes) untuk URL endpoint BPJS |
|
||||
| `APLICARES_BPJS_BASEURL` | *(fallback ke `BPJS_BASEURL`)* | Base URL API BPJS Aplicares |
|
||||
| `APLICARES_BPJS_CONSID` | *(fallback ke `BPJS_CONSID`)* | Consumer ID untuk autentikasi |
|
||||
| `APLICARES_BPJS_SECRETKEY` | *(fallback ke `BPJS_SECRETKEY`)* | Secret key untuk HMAC-SHA256 |
|
||||
|
||||
---
|
||||
|
||||
## Endpoint HTTP
|
||||
|
||||
Semua endpoint di bawah ini terdaftar di `internal/routes/v1/routes.go` dan dilayani oleh `AplicaresHandler`.
|
||||
|
||||
| Method | Path | Handler | Keterangan |
|
||||
|---|---|---|---|
|
||||
| `GET` | `/api/v1/aplicares/beds` | `GetBeds` | Data tempat tidur real-time dari SIMRS saat ini |
|
||||
| `GET` | `/api/v1/aplicares/state` | `GetState` | Isi `data/state.json` — snapshot sinkronisasi terakhir |
|
||||
| `POST` | `/api/v1/aplicares/sync` | `TriggerSync` | Jalankan sync manual, return `SyncResult` |
|
||||
| `GET` | `/api/v1/aplicares/check-bpjs` | `CheckBPJS` | Cek koneksi ke API BPJS, tampilkan sample data kamar |
|
||||
| `GET` | `/api/v1/aplicares/ref/kelas` | `GetRefKelas` | Ambil daftar referensi kelas dari BPJS |
|
||||
| `GET` | `/api/v1/aplicares/logs` | `GetSyncLogs` | 100 log sync terakhir dari file log harian |
|
||||
|
||||
---
|
||||
|
||||
## Cara Mengembangkan Lebih Lanjut
|
||||
|
||||
### Menambah Field yang Disinkronkan
|
||||
|
||||
Misalnya ingin menambah jumlah tersedia berdasarkan jenis kelamin:
|
||||
|
||||
1. **`database.go`** — perbarui query `GetBedDetails()` agar ikut mengambil info jenis kelamin pasien
|
||||
2. **`database.go`** — perbarui `buildBedData()` untuk menghitung `TersediaPria` dan `TersediaWanita` secara terpisah
|
||||
3. **`state.go`** — tambah field baru ke `RoomSnapshot` dan perbarui `snapshotEqual()` agar field baru juga ikut dibandingkan
|
||||
|
||||
### Menambah Endpoint BPJS Baru
|
||||
|
||||
1. Tambahkan method baru di **`bpjs.go`** menggunakan helper `get()` atau `post()` yang sudah ada
|
||||
2. Tambahkan handler di **`aplicare.go`**
|
||||
3. Daftarkan route di `internal/routes/v1/routes.go`
|
||||
|
||||
### Mengubah Kondisi "Bed Terisi"
|
||||
|
||||
Status bed yang dianggap "terisi" ditentukan di `database.go`:
|
||||
```go
|
||||
WHERE status IN (1, 5)
|
||||
```
|
||||
Sesuaikan nilai status dengan konvensi tabel `m_detail_tempat_tidur` di SIMRS.
|
||||
|
||||
### Menambah Field ke Log
|
||||
|
||||
1. Tambahkan field baru ke struct `SyncLog` di **`synclog.go`**
|
||||
2. Isi field tersebut di tempat `WriteLog()` dipanggil dalam **`syncer.go`**
|
||||
|
||||
### Menguji Tanpa Kirim ke BPJS
|
||||
|
||||
Set di `.env`:
|
||||
```env
|
||||
APLICARES_DRY_RUN=true
|
||||
```
|
||||
Restart server. Setiap sync akan menampilkan perubahan di stdout tanpa menyentuh API BPJS.
|
||||
|
||||
---
|
||||
|
||||
> 📝 Dokumen ini khusus membahas `internal/aplicare/`. Untuk dokumentasi seluruh project, lihat `DOCUMENTATION.md`.
|
||||
> 📝 Dibuat: 2026-07-10
|
||||
Reference in New Issue
Block a user