207 lines
7.0 KiB
Markdown
207 lines
7.0 KiB
Markdown
# Fase 1 — Step 1: Core Foundation (Spesifikasi Implementasi)
|
|
|
|
Dokumen ini memecah Step 1 menjadi paket kerja per service, API, schema, dan acceptance detail agar bisa langsung jadi ticket development.
|
|
|
|
## 1) Service yang Dibangun Dulu (Urutan Implementasi)
|
|
|
|
1. `shared` — tracing, idempotency key store, error envelope, request context
|
|
2. `identity` — admin auth + device auth + RBAC baseline
|
|
3. `merchant` — merchant onboarding dasar
|
|
4. `location` — outlet dan terminal
|
|
5. `device-tms` — registrasi device dan binding
|
|
6. `core-db` — migrasi schema MVP + seed data
|
|
7. `ingress` — endpoint admin yang membutuhkan service di atas
|
|
|
|
## 2) Kontrak Data dan ID Standard
|
|
|
|
### 2.1 ID
|
|
- `merchant_id`, `outlet_id`, `terminal_id`, `device_id`, `binding_id`, `transaction_id`, `notification_id`
|
|
- format rekomendasi: ULID/UUID v4
|
|
|
|
### 2.2 Standard Trace/Event
|
|
- Setiap request HTTP dan MQTT message harus membawa:
|
|
- `request_id` (wajib di inbound entry API / webhook / mqtt)
|
|
- `trace_id` (inherit antar service)
|
|
- `event_id` (untuk emission / audit event)
|
|
|
|
### 2.3 Idempotency
|
|
- Table `idempotency_keys` baru:
|
|
- `id`
|
|
- `scope` (`merchant_create`, `outlet_create`, `terminal_create`, dll)
|
|
- `key` (unique)
|
|
- `response_hash`
|
|
- `created_at`, `expires_at`
|
|
- Rule: hit yang sama + key sama => response deterministic dari cache/replay.
|
|
|
|
## 3) Skema DB (MVP Step 1) — Detail Migrasi
|
|
|
|
### 3.1 Tabel Inti yang Harus Ada
|
|
- `merchants`
|
|
- `outlets`
|
|
- `terminals`
|
|
- `devices`
|
|
- `device_bindings`
|
|
- `device_heartbeats`
|
|
- `transactions`
|
|
- `transaction_events`
|
|
- `notifications`
|
|
- `audit_logs`
|
|
- `users`
|
|
- `roles`
|
|
- `idempotency_keys` (tambah)
|
|
|
|
### 3.2 Field Wajib Step 1 per Tabel
|
|
|
|
#### `merchants`
|
|
- id, merchant_code, legal_name, brand_name
|
|
- status, onboarding_status
|
|
- settlement_account_reference, settlement_account_type, fee_profile_id
|
|
- created_at, updated_at
|
|
|
|
#### `outlets`
|
|
- id, merchant_id(FK), outlet_code, name, address, status
|
|
- created_at, updated_at
|
|
|
|
#### `terminals`
|
|
- id, outlet_id(FK), terminal_code, qr_mode, partner_reference, status
|
|
- created_at, updated_at
|
|
|
|
#### `devices`
|
|
- id, device_code, serial_number, vendor, model
|
|
- communication_mode, capability_profile_json, auth_method, status
|
|
- last_seen_at, firmware_version
|
|
- created_at, updated_at
|
|
|
|
#### `device_bindings`
|
|
- id, device_id(FK), merchant_id(FK), outlet_id(FK), terminal_id(FK)
|
|
- active_flag, bound_at, unbound_at
|
|
- unique index: (`device_id`, `active_flag` where active_flag=true)
|
|
|
|
#### `device_heartbeats`
|
|
- id, device_id(FK), received_at
|
|
- network_strength, battery_level, firmware_version, state, payload_json
|
|
|
|
#### `transactions`
|
|
- id, transaction_code, merchant_id(FK), outlet_id(FK), terminal_id(FK), device_id(FK)
|
|
- qr_mode, initiation_mode, partner_reference, amount, currency, status, created_at, paid_at, expired_at, updated_at
|
|
|
|
#### `transaction_events`
|
|
- id, transaction_id(FK), event_type, source, payload_json, created_at
|
|
|
|
#### `notifications`
|
|
- id, transaction_id(FK), device_id(FK), delivery_channel, payload_type
|
|
- delivery_status, retry_count, ack_status, sent_at, ack_at
|
|
|
|
#### `audit_logs`
|
|
- id, actor_type, actor_id, action, entity_type, entity_id
|
|
- before_json, after_json, source_ip, created_at
|
|
|
|
#### `users` / `roles` (minimal)
|
|
- users: id, name, email, password_hash, role_id, status, created_at
|
|
- roles: id, name, permissions_json, created_at
|
|
|
|
### 3.3 Index Prioritas Step 1
|
|
- `device_bindings(device_id, active_flag)`
|
|
- `transactions(partner_reference)`
|
|
- `transactions(merchant_id, created_at)`
|
|
- `transactions(status, created_at)`
|
|
- `notifications(device_id, delivery_status)`
|
|
- `device_heartbeats(device_id, received_at)`
|
|
- `audit_logs(entity_type, entity_id, created_at)`
|
|
|
|
## 4) Modul API Step 1 (Spesifikasi Ringkas)
|
|
|
|
### 4.1 Admin/Auth
|
|
- `POST /auth/login` (bila auth service belum ada, temporary token stub boleh pakai untuk sprint 1)
|
|
- `POST /auth/token/refresh` (opsional)
|
|
- Validasi RBAC untuk endpoint admin:
|
|
- `admin` minimal bisa akses semua CRUD Fase 1
|
|
- Error standar:
|
|
- `UNAUTHORIZED`, `FORBIDDEN`, `VALIDATION_ERROR`
|
|
|
|
### 4.2 Merchant
|
|
- `POST /admin/merchants`
|
|
- body:
|
|
- `legal_name`, `brand_name`, `settlement_account_reference`, `settlement_account_type`, `fee_profile_id`
|
|
- `settlement_account_type` contoh: `merchant_virtual_account`, `merchant_bank_account`, `partner_payout_reference`
|
|
- `payout_mode` (opsional): `merchant_direct` (default), `manual`
|
|
- `merchant_direct` = payout diarahkan via reference payout merchant
|
|
- `manual` = pencairan dibantu operasional, belum otomatis
|
|
- validasi: `legal_name` required
|
|
- idempotency: `Idempotency-Key` optional untuk create
|
|
- `GET /admin/merchants`
|
|
- `GET /admin/merchants/{merchantId}`
|
|
- `PATCH /admin/merchants/{merchantId}`
|
|
- `DELETE /admin/merchants/{merchantId}` (opsional; bisa soft delete via status=inactive)
|
|
|
|
### 4.3 Outlet
|
|
- `POST /admin/merchants/{merchantId}/outlets`
|
|
- `GET /admin/outlets`
|
|
- `GET /admin/outlets/{outletId}`
|
|
- `PATCH /admin/outlets/{outletId}`
|
|
|
|
### 4.4 Terminal
|
|
- `POST /admin/outlets/{outletId}/terminals`
|
|
- `GET /admin/terminals`
|
|
- `GET /admin/terminals/{terminalId}`
|
|
- `PATCH /admin/terminals/{terminalId}`
|
|
|
|
### 4.5 Device & Binding
|
|
- `POST /admin/devices`
|
|
- `GET /admin/devices`
|
|
- `GET /admin/devices/{deviceId}`
|
|
- `PATCH /admin/devices/{deviceId}`
|
|
- `POST /admin/devices/{deviceId}/bind`
|
|
- body: `{ merchant_id, outlet_id, terminal_id }`
|
|
- rule: endpoint ini membuat record `device_bindings` baru dan menonaktifkan binding aktif lama
|
|
- `POST /admin/devices/{deviceId}/unbind`
|
|
- body: `{ reason }`
|
|
|
|
## 5) Acceptance Criteria per Paket
|
|
|
|
### 5.1 Merchant/Location
|
|
- merchant, outlet, terminal bisa dibuat, diubah, list, detail
|
|
- semua response memuat `request_id`
|
|
- duplikasi create request dengan idempotency key yang sama menghasilkan resource yang sama
|
|
|
|
### 5.2 Device Binding
|
|
- bind mengikat hanya satu binding aktif/device pada saat yang sama
|
|
- unbind membuat binding aktif jadi nonaktif dan merekam `unbound_at`
|
|
- binding referensi invalid menyebabkan endpoint device/transaction terkait ditolak di tahap berikutnya
|
|
|
|
### 5.3 Observability/Platform
|
|
- semua response error mengikuti envelope:
|
|
- `code`, `message`, `details`, `request_id`
|
|
- log audit tersimpan saat create/update pada merchant, device, bind/unbind
|
|
|
|
### 5.4 Operasional
|
|
- `last_seen_at` device berubah saat heartbeat valid (step 2 nantinya lebih lengkap)
|
|
- pipeline dasar bisa menjalankan 10 request bersamaan tanpa crash (smoke test)
|
|
|
|
## 6) Definisi File/Artefak
|
|
|
|
### 6.1 Yang Harus Dibuat di Step 1
|
|
- `12-fase1-step1-core-foundation-spec.md` (dokumen ini)
|
|
- `DECISIONS_LOG.md` (dibuat bersama)
|
|
- migration file untuk tabel Step 1
|
|
- endpoint handlers sesuai list di atas
|
|
- seed file:
|
|
- 2 merchant
|
|
- 2 outlet + 2 terminal
|
|
- 3 devices (static, dynamic-mqtt, dynamic-api)
|
|
|
|
### 6.2 Testing Wajib (manual smoke, tanpa alat tambahan)
|
|
- login/admin auth
|
|
- CRUD merchant
|
|
- CRUD outlet/terminal
|
|
- bind/unbind device
|
|
- seed device bisa dilihat di GET list
|
|
|
|
## 7) Handover ke Step 2
|
|
|
|
Step 2 tidak dimulai sampai:
|
|
- endpoint binding dan auth stabil
|
|
- transaksi memiliki struktur minimal `transactions + transaction_events`
|
|
- event/error format terstandardisasi
|
|
- idempotency baseline aktif
|