# 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
