Initial commit
This commit is contained in:
157
17-fase1-implementation-task-pack.md
Normal file
157
17-fase1-implementation-task-pack.md
Normal file
@ -0,0 +1,157 @@
|
||||
# Fase 1 — Task Pack (Urutan Implementasi Langsung)
|
||||
|
||||
Dokumen ini adalah daftar kerja yang bisa langsung dipakai sebagai urutan PR/ticket.
|
||||
|
||||
## Paket A — Foundation Core (Step 1)
|
||||
|
||||
## A.1 PR: Shared Foundation + Middleware
|
||||
- scope: `shared`, tracing, request/error wrapper, idempotency table baseline, audit helper
|
||||
- target file:
|
||||
- shared error formatter
|
||||
- request_id/trace_id generator
|
||||
- idempotency service CRUD/read
|
||||
- acceptance:
|
||||
- semua response punya `request_id` di body meta
|
||||
- idempotency write/read bisa ditest di local endpoint sample
|
||||
|
||||
## A.2 PR: Auth Baseline
|
||||
- scope: login/admin token minimal, auth middleware, role dasar
|
||||
- acceptance:
|
||||
- endpoint admin menolak tanpa token (`401`)
|
||||
- token valid memberi akses CRUD Step 1
|
||||
|
||||
## A.3 PR: Merchant CRUD
|
||||
- scope: `POST /admin/merchants`, `GET /admin/merchants`, `GET /admin/merchants/{id}`, `PATCH /admin/merchants/{id}`
|
||||
- acceptance:
|
||||
- create/read/update berhasil
|
||||
- duplikasi create dengan idempotency key tidak membuat duplicate
|
||||
|
||||
## A.4 PR: Outlet + Terminal
|
||||
- scope:
|
||||
- `POST /admin/merchants/{merchantId}/outlets`
|
||||
- `GET /admin/outlets`, `GET /admin/outlets/{id}`, `PATCH /admin/outlets/{id}`
|
||||
- `POST /admin/outlets/{outletId}/terminals`
|
||||
- `GET /admin/terminals`, `GET /admin/terminals/{id}`, `PATCH /admin/terminals/{id}`
|
||||
- acceptance:
|
||||
- outlet/terminal berkait dengan merchant/outlet parent
|
||||
- error jika parent tidak valid
|
||||
|
||||
## A.5 PR: Device Registry + Binding
|
||||
- scope:
|
||||
- `POST /admin/devices`, `GET /admin/devices`, `GET /admin/devices/{id}`, `PATCH /admin/devices/{id}`
|
||||
- `POST /admin/devices/{id}/bind`
|
||||
- `POST /admin/devices/{id}/unbind`
|
||||
- acceptance:
|
||||
- bind menghasilkan `device_bindings` aktif tunggal
|
||||
- unbind menonaktifkan binding aktif
|
||||
|
||||
## A.6 PR: Migration + Seed Phase 1
|
||||
- scope:
|
||||
- tables dari Step 1 MVP
|
||||
- seed: 2 merchant, 2 outlet, 2 terminal, 3 device
|
||||
- user/admin seed baseline
|
||||
- acceptance:
|
||||
- sistem startup clean dengan data seed
|
||||
- query dasar berjalan
|
||||
|
||||
## Paket B — Transaction + Webhook (Step 2)
|
||||
|
||||
## B.1 PR: Transaction Core & State Machine
|
||||
- scope:
|
||||
- tabel `transactions`, `transaction_events`
|
||||
- states: initiated, awaiting_payment, paid, failed, expired
|
||||
- acceptance:
|
||||
- create transaksi dasar
|
||||
- timeline event tercatat saat state berubah
|
||||
|
||||
## B.2 PR: Callback Receiver
|
||||
- scope: `POST /integrations/qris/callback`
|
||||
- rules:
|
||||
- signature validation
|
||||
- idempotency callback
|
||||
- duplicate replay handling
|
||||
- acceptance:
|
||||
- valid callback -> state paid
|
||||
- duplicate callback tidak mengubah state
|
||||
- signature salah -> 401
|
||||
|
||||
## B.3 PR: Event Emission (`transaction.paid`)
|
||||
- scope:
|
||||
- emit internal event saat status bayar sukses
|
||||
- acceptance:
|
||||
- setiap successful callback menghasilkan event sekali (idempotent)
|
||||
|
||||
## Paket C — Notification (Step 3)
|
||||
|
||||
## C.1 PR: Notification Orchestrator
|
||||
- scope:
|
||||
- listen `transaction.paid`
|
||||
- buat `notifications` record
|
||||
- acceptance:
|
||||
- transaksi paid menghasilkan record notification
|
||||
|
||||
## C.2 PR: MQTT Publisher
|
||||
- scope:
|
||||
- publish ke `devices/{deviceId}/downlink/payment/success`
|
||||
- payload sesuai kontrak
|
||||
- acceptance:
|
||||
- publish sukses update `delivery_status=sent`
|
||||
- fallback jika publish gagal -> `retrying/failed`
|
||||
|
||||
## C.3 PR: Retry + Admin Retry API
|
||||
- scope:
|
||||
- retry loop (15/30/60)
|
||||
- `POST /admin/transactions/{transactionId}/retry-notification`
|
||||
- acceptance:
|
||||
- status update berjalan dari retrying ke sent/gagal
|
||||
|
||||
## Paket D — Device & Ops Monitoring (Step 4)
|
||||
|
||||
## D.1 PR: Heartbeat Ingestion
|
||||
- scope:
|
||||
- `POST /device/heartbeat`
|
||||
- update `devices.last_seen_at`
|
||||
- simpan `device_heartbeats`
|
||||
- acceptance:
|
||||
- status heartbeat dan latest heartbeat terlihat per device
|
||||
|
||||
## D.2 PR: Device Listing + Detail
|
||||
- scope:
|
||||
- `GET /admin/devices`
|
||||
- `GET /admin/devices/{id}`
|
||||
- derived status online/stale/offline/degraded
|
||||
- acceptance:
|
||||
- list/detail bisa difilter dan menampilkan status
|
||||
|
||||
## D.3 PR: Transaction List/Detail + Heartbeat History
|
||||
- scope:
|
||||
- `GET /admin/transactions`, `GET /admin/transactions/{id}`
|
||||
- `GET /admin/devices/{id}/heartbeats`
|
||||
- acceptance:
|
||||
- timeline event dan heartbeat history tampil
|
||||
|
||||
## D.4 PR: Dashboard KPI + Failed Notification View
|
||||
- scope:
|
||||
- `GET /admin/dashboard/summary`
|
||||
- `GET /admin/notifications/failed`
|
||||
- acceptance:
|
||||
- 5 metrik minimum tampil
|
||||
- daftar notifikasi failed bisa difilter
|
||||
|
||||
## Urutan Eksekusi Terbuka
|
||||
1. A.1 → A.2 → A.6 (mendukung semua service berikutnya)
|
||||
2. A.3 → A.4 → A.5
|
||||
3. B.1 → B.2 → B.3
|
||||
4. C.1 → C.2 → C.3
|
||||
5. D.1 → D.2 → D.3 → D.4
|
||||
|
||||
## Aturan Dependensi
|
||||
- B paket tidak boleh dimulai jika A.5 belum selesai (binding + transaksi dasar belum valid)
|
||||
- C paket tidak boleh dimulai jika B.3 belum siap
|
||||
- D paket bisa jalan paralel dengan C jika A dan B core sudah jalan
|
||||
|
||||
## Exit Criteria Fase 1 (siap Step 2)
|
||||
- [ ] static paid flow jalan end-to-end
|
||||
- [ ] tidak ada duplicate state via callback
|
||||
- [ ] notification ada untuk paid tx
|
||||
- [ ] device heartbeat dan status ops visible
|
||||
Reference in New Issue
Block a user