8.3 KiB
8.3 KiB
Sprint Change Proposal — ERP → Create Transaction → Payment Link Flow
Summary
- Trigger: Checkout tidak lagi dimulai dari tombol “Buy Now” di frontend. Sistem eksternal (ERP/billing script) mengirim data transaksi ke server dan menerima tautan pembayaran terenkripsi untuk dibagikan ke pengguna.
- Outcome: Backend menjadi titik inisiasi transaksi. Pengguna membuka Payment Page via link (
/pay/:token), memilih metode (VA/GoPay/Cstore/Kartu), lalu UI mengeksekusi charge seperti biasa. Webhook Midtrans dan ERP callback tetap berjalan.
Objectives (Sprint)
- Menyediakan endpoint backend
POST /createtransaksiyang mengeluarkan payment link bertanda-tangan (HMAC‑SHA256) dengan TTL dan anti‑replay. - Menambahkan rute frontend
"/pay/:token"(Payment Page) untuk memvalidasi token, menampilkan metode, dan melakukan charge menggunakanorder_iddari token. - Menjaga kompatibilitas endpoint yang ada:
POST /api/payments/charge,GET /api/payments/:orderId/status,POST /api/payments/webhook. - Menyelaraskan PRD, Arsitektur UI, dan Story E2E dengan alur baru.
Scope & Impact
- PRD (
docs/prd.md): Tambah FR “External Create Transaction & Payment Link”, ubah sumberorder_id(berasal dariitem_id), tambahkan ketentuan TTL, signature, dan anti‑replay. - Arsitektur UI (
docs/ui-architecture.md): Tambah rute"/pay/:token", alur token‑driven.CheckoutPagetetap sebagai demo/QA. - Story E2E (
docs/stories/midtrans-e2e-checkout-to-webhook.md): Mulai dari Payment Page via token, bukan dari CheckoutPage langsung. - Backend (
server/index.cjs): Tambah endpointPOST /createtransaksidan resolver token (API untuk FE). Env baru:EXTERNAL_API_KEY,PAYMENT_LINK_SECRET,PAYMENT_LINK_TTL_MINUTES. - Frontend: Tambah halaman
PayPage(/pay/:token), service untuk resolve token.postCharge/getPaymentStatustetap.
Proposed Design
1) Backend — Create Transaction API
- Endpoint:
POST /createtransaksi - Auth: Header
X-API-KEY: <EXTERNAL_API_KEY>(validasi exact match; opsi IP whitelist & rate limit di reverse proxy). - Body (contoh minimal):
{ "merchant_id": "TKG-250520029803", "deskripsi": "Pembelian item", "nominal": 200000, "nama": "Dwiki Kurnia Sandi", "no_telepon": "081234567890", "email": "demo@example.com", "item": [ { "item_id": "ITEM-12345", "qty": 1, "price": 200000, "name": "Produk A" } ] } - Mapping
order_id: gunakanitem[0].item_idsebagaiorder_iduntuk Midtrans (validasi format/unik per transaksi aktif). - Idempotensi: jika
order_id+nominalsama dan status transaksi masihpending, kembalikan payment link sebelumnya; jikanominalberbeda, kembalikan422 AMOUNT_MISMATCH. - Response (sukses):
{ "status_code": "200", "status_message": "OK", "url": "https://cifopayment.id/pay/<token>?sig=<signature>", "exp": 1730000000 }token: opaque base64url berisi klaim minimal (mis.order_id,nominal,exp) yang disimpan server.signature:hex(HMAC_SHA256(token, PAYMENT_LINK_SECRET)).exp: UNIX epoch seconds (TTL default 30 menit; dapat dikonfigurasi).
2) Backend — Payment Link Resolve API
- Endpoint:
GET /api/payment-links/:token(digunakan frontend untuk bootstrap Payment Page). - Query: otomatis memverifikasi signature (
sigdi query atau header), TTL/anti‑replay, dan mengembalikan payload:{ "order_id": "ITEM-12345", "nominal": 200000, "customer": { "name": "Dwiki", "phone": "081234567890", "email": "demo@example.com" }, "expire_at": 1730000000, "allowed_methods": ["bank_transfer", "gopay", "cstore", "credit_card"] } - Error:
401 INVALID_SIGNATURE,410 LINK_EXPIRED,409 LINK_USED(opsional jika anti‑replay menandai sekali pakai).
3) Frontend — Payment Page (/pay/:token)
- Flow:
- Ambil
tokendari URL → panggilGET /api/payment-links/:token. - Set lokal
orderId,amount,expireAt, dan info pelanggan. - Render komponen metode (VA/GoPay/Cstore/Kartu) seperti di Checkout, tetapi
orderIdberasal dari token. - Setelah charge, navigasi ke
"/payments/:orderId/status"(polling status tetap).
- Ambil
- Catatan:
CheckoutPagetetap ada untuk demo/QA; jalur produksi menggunakan Payment Page via link.
4) Webhook & ERP Callback
- Tetap:
POST /api/payments/webhookmemverifikasi signature Midtrans dan memperbarui status. - ERP Callback: kirim
POSTkehttps://apibackend.erpskrip.id/paymentnotification/pada status sukses, signaturesha512(mercant_id + status_code + nominal + client_id)seperti implementasi saat ini.
5) Security & Config
- Secrets:
EXTERNAL_API_KEY: memvalidasiX-API-KEYdari ERP.PAYMENT_LINK_SECRET: kunci HMAC untuk signature token.PAYMENT_LINK_TTL_MINUTES: default 30.
- Praktik:
- Rate‑limit
POST /createtransaksidan audit log. - Anti‑replay: tandai token sebagai “used” setelah berhasil charge (opsional; atau izinkan reuse sampai status final).
- Rotasi secret terjadwal; invalidasi token lama secara bertahap bila diperlukan.
- Rate‑limit
Acceptance Criteria (Sprint)
- Backend mengeluarkan payment link dengan
token+signature, valid hingga TTL. - Resolve API mengembalikan
order_iddannominalyang konsisten; invalid jika signature/TTL gagal. - Frontend Payment Page (
/pay/:token) dapat:- Memvalidasi token dan menampilkan metode pembayaran.
- Melakukan charge via endpoint yang ada menggunakan
order_iddari token. - Menavigasi ke halaman status dan menampilkan detail (VA/QR/payment code/kartu) sesuai metode.
- Webhook menerima notifikasi Midtrans dan ERP callback tetap terkirim saat sukses.
- Dokumentasi PRD, Arsitektur UI, dan Story E2E diperbarui mencerminkan alur baru.
Non‑Functional Requirements
- Observability: logging request ID, event penting (
link.create,link.resolve,charge.start/success,webhook.receive). - Idempotensi: kembalikan link lama untuk transaksi
pendingdenganorder_id+nominalyang sama. - Keamanan: tidak mengekspos server key; signature Midtrans diverifikasi; token link ditandatangani HMAC‑SHA256.
- Kinerja: endpoint create/resolver respon <200ms p95 (lokal dev).
Risks & Mitigations
- Replay/penyalahgunaan link: enforce TTL, anti‑replay flag, rate‑limit.
- Konflik
order_id: validasi unik; strategy untuk recurring (suffix waktu/sequence bila diperlukan). - Ketidaksesuaian nominal:
422 AMOUNT_MISMATCHuntukorder_idsama namun nominal beda. - Gangguan ERP: retry callback dengan backoff, feature flag
ERP_ENABLE_NOTIFuntuk mematikan sementara.
Rollback Plan
- Nonaktifkan konsumsi resolver token (feature flag) dan kembalikan ke alur Checkout demo.
- Pertahankan endpoint status & webhook agar UI tetap dapat polling status.
Deliverables (Sprint)
- Backend:
POST /createtransaksi,GET /api/payment-links/:token(validator signature/TTL), konfigurasi env baru. - Frontend: halaman
PayPage(/pay/:token) dengan integrasi panel metode yang ada. - Docs: update PRD, Arsitektur UI, dan Story E2E sesuai token‑driven flow.
Timeline & Tasking (5 hari)
- Day 1: Skeleton endpoint
createtransaksi+ HMAC signing + env wiring. - Day 2: Resolver API + idempotensi + anti‑replay dasar.
- Day 3: FE
PayPage+ servicegetPaymentLinkPayload(token)+ navigasi. - Day 4: QA manual (sandbox) + webhook/ERP callback sanity.
- Day 5: Dokumentasi & polish (error codes, logging, runbook).
Decisions Confirmed
- TTL payment link: 30 menit (konfigurabel; default 30) — disetujui.
- Token: HMAC‑SHA256 signature (tanpa enkripsi payload; confidentiality tidak diwajibkan saat ini).
- Recurring transaksi: tidak didukung. Kebijakan:
- Satu transaksi aktif per
item_idpada satu waktu. - Jika status sukses (
settlementataucapture + fraud_status=accept), permintaan baru untukitem_idyang sama ditolak (409 ORDER_COMPLETED). - Re-attempt diperbolehkan hanya jika transaksi sebelumnya tidak sukses dan sudah berakhir (
expire/cancel/deny), menggunakan kebijakan unikorder_idsesuai kebutuhan implementasi Midtrans.
- Satu transaksi aktif per
Appendix — Example
- Request
POST /createtransaksi(ringkas): lihat contoh pada bagian Backend di atas. - Response sukses:
{ "status_code": "200", "status_message": "OK", "url": "https://cifopayment.id/pay/eyJvcmRlcl9pZCI6IklURU0tMTIzNDUiLCJub21pbmFsIjoyMDAwMDAsImV4cCI6MTczMDAwMDAwMH0?sig=4c7f...", "exp": 1730000000 }