# Task Breakdown: EnakGame **Sumber:** [RFC EnakGame](rfc-enakgame.md), [PRD EnakGame](enakgame-prd.md) **Tanggal:** 2026-10-07 Setiap task menyebut bagian RFC yang dikerjakan, lapisan kode yang disentuh, task yang harus selesai lebih dulu, dan kriteria selesai. Ukuran: **S** ≤ 1 hari, **M** 2–3 hari, **L** 4–5 hari. Konvensi kode mengikuti yang sudah ada: `migrations/` (lanjut dari `000101`), `entities` → `repository` → `processor` → `service` → `handler` / `validator` → `router`, dan wiring di `internal/app/app.go`. Repository **selalu** memakai `DBFromContext`. Semua mutasi saldo **hanya** lewat `WalletProcessor`. --- ## Ringkasan | Fase | Task | Terblokir oleh | |---|---|---| | 0. Matikan bayar dengan EnakPoint | EG-001 – EG-002 | – | | 1. Fondasi | EG-101 – EG-106 | – | | 2. Admin game & session | EG-201 – EG-206 | – | | 3. Reward Engine & complete | EG-301 – EG-303 | Pembulatan (RFC §19.2 #1) sebelum **rilis** | | 4. Economy Guard | EG-401 – EG-402 | – | | 5. Voucher & redemption | EG-501 – EG-507 | – | | 6. Budget metrics | EG-601 – EG-602 | Exhaustion policy & threshold (#3, #4) sebelum **rilis** | | 7. Event / campaign | EG-701 – EG-704 | Event stacking (#2) sebelum **rilis** | | 8. Voucher eksternal | EG-801 – EG-803 | Provider pertama yang konkret sebelum **dikerjakan** | | 9. Budget Controller & analytics | EG-901 – EG-903 | Threshold (#4) sebelum **dikerjakan** | | 10. Spin & bersih-bersih | EG-1001 – EG-1003 | – | Fase 0 independen dan bisa jalan paralel dengan semua fase lain, tetapi **harus selesai sebelum EnakGame rilis** (PRD §3.2). Fase 1–3 membuat game bisa dimainkan end-to-end dengan Coin. Fase 5 membuat Point bisa ditukar. Fase 6 membuat Finance bisa melihat biaya. ``` Fase 0 EG-001 ── EG-002 Fondasi EG-101 ── EG-102 ── EG-105 EG-103, EG-104, EG-106, EG-301 (independen) Game EG-104 + EG-105 ─────────────────── EG-201, EG-203 EG-104 + EG-105 + EG-301 ────────── EG-202 EG-103 + EG-201 + EG-202 + EG-203 ─ EG-204 ── EG-205 EG-204 + EG-205 + EG-301 + EG-302 ─ EG-303 EG-106 ── EG-401 EG-303 + EG-401 ─────────────────── EG-402 Voucher EG-501 ── EG-502 EG-103 + EG-502 + EG-503 ────────── EG-504 EG-303 + EG-504 ─────────────────── EG-505 ── EG-601 ─┬─ EG-602 └─ EG-901 ── EG-902 EG-504 ── EG-801 EG-505 + EG-801 ─────────────────── EG-802 ── EG-803 Event EG-102 ── EG-701 EG-203 + EG-701 ─────────────────── EG-702 EG-402 + EG-702 ─────────────────── EG-703 Akhir EG-402 ── EG-1001 ── EG-1002 ── EG-1003 ``` Task kecil yang tidak digambar: EG-206, EG-302 (setelah EG-105), EG-506 (EG-504), EG-507 (EG-501), EG-704 (EG-206 + EG-702), EG-903 (EG-303 + EG-505). --- ## Fase 0 — Matikan Bayar dengan EnakPoint PRD §3.2: Point hanya bisa ditukar ke voucher. Belum ada order yang dibayar dengan Point, jadi tidak ada data yang dimigrasi. ### EG-001 · Tutup semua jalur pembayaran EnakPoint · M - **RFC:** §14 - **Kerjakan:** - Sudah dikonfirmasi belum ada pembayaran dengan EnakPoint di production (2026-10-07). - Migrasi: drop trigger yang membuat payment method `point` untuk organisasi baru (`000094`), lalu nonaktifkan / hapus baris `payment_methods` tipe `point`. - Tolak pembayaran bertipe `point` di jalur POS (`order_handler`, `order_processor`, `payment_method_processor`) dan customer app (`customer_order_payment_service`). - Hapus route `GET /orders/:id/point-payment/preview` dan `POST /customer/wallet/payment-code`. - Hapus `PAYMENT` dan `PAYMENT_REFUND` dari `walletTypeRules`, supaya engine menolak keduanya. CHECK database dibiarkan. - Hapus setting `loyalty.point.accept_payment` dari descriptor `LoyaltySettingsProcessor` dan dari response outlet customer. - **Selesai jika:** pembayaran order dengan method `point` ditolak di POS dan customer app, outlet baru tidak lagi mendapat payment method EnakPoint, dan test yang ada diperbarui. - **Bergantung pada:** – ### EG-002 · Hapus kode point payment · S - **Kerjakan:** hapus `PointPaymentProcessor`, `point_payment_refund.go`, `PointPaymentRepository`, `PointPaymentService`, `PointPaymentHandler`, wiring di `app.go` / `router.go`, dan test-nya (`point_payment_db_test.go`, `point_payment_method_db_test.go`). Pindahkan dulu helper yang ternyata dipakai di tempat lain (mis. pola pembuatan lot refund, yang dipakai ulang di EG-205). - **Selesai jika:** `go build ./...` dan seluruh test lulus, dan `grep -rn "PointPayment" internal/` kosong. - **Bergantung pada:** EG-001 --- ## Fase 1 — Fondasi ### EG-101 · Migrasi extend `games` + arsipkan game lama · S - **RFC:** §5.1, §14 - **Kerjakan:** migrasi up & down persis seperti §5.1. Semua baris lama menjadi `ARCHIVED`. **Tidak ada `DELETE`** (FK `game_plays` CASCADE). - **Selesai jika:** - Up/down bersih di database kosong dan di salinan staging. - Jumlah baris `game_plays` sebelum = sesudah. - Ditolak database: game `ACTIVE` tanpa `organization_id` atau `slug`; `entry_cost = 0`; dua game dengan slug sama di satu org. - **Bergantung pada:** – ### EG-102 · Migrasi budget, reward config, session · M - **RFC:** §5.2, §5.3, §5.4, §5.6 - **Kerjakan:** `game_budgets`, `game_reward_configs`, `game_sessions`, `game_session_rewards`, dalam urutan foreign key. - **Selesai jika:** up/down bersih. Ditolak database: dua config `ACTIVE` untuk satu game; session `REFUNDED` tanpa `refund_transaction_id`; dua budget `GLOBAL` dengan `period_start` sama di satu org; `game_session_rewards` dengan `wallet_transaction_id` yang sama dua kali. - **Bergantung pada:** EG-101 ### EG-103 · Tipe ledger baru · M - **RFC:** §6 - **Kerjakan:** - Konstanta `GAME_SPEND_REFUND`, `GAME_REWARD`, `REWARD_REDEEM_REFUND`, ref `GAME_SESSION` di `constants/wallet.go`. - `walletTypeRules`: tambah tiga tipe, dan izinkan ref `GAME_SESSION` pada `GAME_SPEND`. - Migrasi: drop + create ulang tiga CHECK di `wallet_transactions` (§6.2). - Periksa invariant di `wallet_reconciliation_repository.go` terhadap tipe baru. - **Selesai jika:** test validasi di `wallet_processor_test.go` per tipe baru (currency salah, ref salah, reversal tanpa `reverses_transaction_id` → ditolak), dan test DB yang benar-benar insert ke `wallet_transactions` untuk setiap tipe (lolos engine **dan** CHECK). - **Bergantung pada:** – ### EG-104 · `audit_logs` + helper · S - **RFC:** §5.9, §13 - **Kerjakan:** migrasi, entity, dan `AuditLogger.Record(ctx, entry)` yang menulis lewat `DBFromContext`, sehingga audit ikut commit/rollback bersama perubahannya. - **Selesai jika:** perubahan yang di-rollback tidak meninggalkan baris audit. - **Bergantung pada:** – ### EG-105 · Entities & repository EnakGame · M - **RFC:** §5.1–§5.6 - **Kerjakan:** entities dan repository untuk kolom baru `games`, `game_reward_configs`, `game_sessions`, `game_session_rewards`, `game_budgets`. Transisi status session sebagai `UPDATE ... WHERE status = 'STARTED'` yang mengembalikan jumlah baris ter-update (D4). Semua query game/budget memfilter `organization_id`. - **Selesai jika:** test repository: dua transisi bersamaan pada session yang sama, hanya satu yang mendapat 1 baris. - **Bergantung pada:** EG-101, EG-102 ### EG-106 · Setting limit EnakGame · S - **RFC:** §5.10 - **Kerjakan:** key `enakgame.limit.user_daily` dan `enakgame.limit.global_daily` sebagai field descriptor di `LoyaltySettingsProcessor` (default 0 = tanpa batas, min 0). - **Selesai jika:** setting terbaca dengan default, bisa diubah lewat endpoint loyalty settings yang ada, dan perubahan tercatat di `loyalty_setting_changes`. - **Bergantung pada:** – --- ## Fase 2 — Admin Game & Session ### EG-201 · Admin game CRUD · M - **RFC:** §11 (admin) - **Kerjakan:** `/marketing/enakgame/games` CRUD + `PUT /:id/status`, org dari user admin. Validasi `slug`, `entry_cost ≥ 1`, `result_rules`. Game `ARCHIVED` tidak bisa diubah. Perubahan status masuk `audit_logs`. - **Selesai jika:** admin org A tidak bisa melihat atau mengubah game org B; game lama (arsip) tidak muncul. - **Bergantung pada:** EG-104, EG-105 ### EG-202 · Admin reward config versioning · M - **RFC:** §5.2, D7 - **Kerjakan:** `POST /games/:id/reward-configs` (versi baru, `rules` divalidasi `RewardCalculator.Validate`), `POST /reward-configs/:id/activate` (dalam satu transaksi: config lama → `RETIRED`, yang baru → `ACTIVE`), `GET` daftar versi. Tidak ada endpoint update atau delete. Wajib `RequireLoyaltyManager`. Semua aksi masuk `audit_logs`. - **Selesai jika:** config yang sudah dipakai session tidak bisa diubah lewat jalur apa pun; aktivasi bersamaan dua versi berakhir dengan tepat satu `ACTIVE`. - **Bergantung pada:** EG-104, EG-105, EG-301 ### EG-203 · Admin budget + `GameBudgetPeriodJob` · M - **RFC:** §5.6, §12 - **Kerjakan:** CRUD `/marketing/enakgame/budgets` (scope `GLOBAL` / `EVENT`), wajib `RequireLoyaltyManager`, audit. Job harian yang membuat budget global bulan berikutnya dari bulan berjalan bila belum ada. - **Selesai jika:** job aman dijalankan berulang (unique index mencegah duplikat), dan perubahan `amount` tercatat sebelum/sesudah di audit. - **Bergantung pada:** EG-104, EG-105 ### EG-204 · Start Game · M - **RFC:** §7.1 - **Kerjakan:** `POST /customer/enakgame/sessions` dengan `Idempotency-Key` wajib (≤ 50 karakter, pola `customer_wallet_handler.go`). Langkah persis §7.1. - **Selesai jika:** test untuk: - Key yang sama dua kali → satu debit, session yang sama dikembalikan. - Coin kurang → ditolak, tidak ada ledger maupun session. - Game org lain, game tidak `ACTIVE`, tanpa config aktif, tanpa budget global → ditolak. - `entry_cost` dan `reward_config_id` tersimpan sebagai snapshot: mengubah game setelah start tidak mengubah session. - **Bergantung pada:** EG-103, EG-105, EG-201, EG-202, EG-203 ### EG-205 · Refund otomatis + `GameSessionJob` · M - **RFC:** §7.3, §6.3 - **Kerjakan:** - `RefundSession(ctx, sessionID, reason)`: lock wallet → transisi bersyarat ke `REFUNDED` → `Credit` `GAME_SPEND_REFUND` dengan lot per alokasi asal (`RefundExpiry`, `origin_lot_id`) → audit `SYSTEM`. - Job tiap 1 menit, per batch, satu transaksi per session, sesuai tabel §7.3. - Wiring start/stop di `app.go` seperti `WalletExpiryJob`. - **Selesai jika:** test untuk: - Game dinonaktifkan → session `STARTED` di-refund tanpa menunggu kedaluwarsa. - Expired dengan `completion_failed_at` → refund. Expired tanpa → `EXPIRED`, saldo tetap. - Lot refund punya `origin_lot_id` ke lot asal dan `expires_at` minimal 7 hari. - Complete dan refund bersamaan pada session yang sama → tepat satu yang berhasil. - Job dijalankan dua kali → tidak ada refund ganda. - **Bergantung pada:** EG-204 ### EG-206 · Customer: daftar game & riwayat session · S - **RFC:** §11 (customer) - **Kerjakan:** `GET /customer/enakgame/games`, `GET /sessions`, `GET /sessions/:id`. Hanya game `ACTIVE` milik org customer. Rincian internal (`reward_breakdown` lengkap, angka RNG) tidak ditampilkan. - **Bergantung pada:** EG-105 --- ## Fase 3 — Reward Engine & Complete ### EG-301 · `RewardCalculator` + empat tipe · M - **RFC:** §8 - **Kerjakan:** interface `Validate` / `Calculate`, implementasi `FIXED`, `SCORE_BASED`, `OUTCOME_BASED`, `PROBABILITY`. RNG lewat interface yang diisi `crypto/rand` di production dan RNG tetap di test. Pembulatan ke bawah. - **Selesai jika:** unit test: contoh tabel PRD §12 untuk setiap tipe; band skor tumpang tindih / berlubang ditolak `Validate`; bobot `PROBABILITY` nol atau negatif ditolak; distribusi `PROBABILITY` pada 100.000 undian berada dalam toleransi bobotnya. - **Bergantung pada:** – ### EG-302 · Result Validator · S - **RFC:** §7.2 langkah 5 - **Kerjakan:** validasi `result` terhadap `games.result_rules`: durasi minimal, skor maksimum, skor per detik, outcome yang dikenal. Mengembalikan alasan, bukan error. - **Selesai jika:** unit test per aturan, termasuk game tanpa `result_rules` (semua lolos). - **Bergantung pada:** EG-105 ### EG-303 · Complete Game · L - **RFC:** §7.2, §7.3 (bagian `completion_failed_at`) - **Kerjakan:** - `POST /customer/enakgame/sessions/:id/complete`, langkah §7.2 dengan base reward dari budget global saja. Event menyusul di EG-703, guard di EG-402. - Satu baris `GAME_REWARD` + `game_session_rewards` per budget, key `game-reward:{session}:{budget}`. Lot dengan `ComputeExpiry(CoinExpiry)`. - Game tidak `ACTIVE` saat complete → `RefundSession(GAME_DEACTIVATED)`. - Error non-bisnis → tulis `completion_failed_at` di transaksi terpisah (`DetachTransaction`), lalu kembalikan 5xx. - **Selesai jika:** test untuk: - Complete dua kali → satu reward, response kedua sama dengan yang pertama. - Hasil tidak valid → reward 0, `flagged`, session `COMPLETED`, tanpa refund. - Session milik customer lain → 404. Session expired → ditolak. - Error yang disuntikkan setelah kredit → rollback total, `completion_failed_at` terisi. - Request yang membawa field `reward` diabaikan (P1). - **Bergantung pada:** EG-204, EG-205, EG-301, EG-302 --- ## Fase 4 — Economy Guard ### EG-401 · Counter reward + increment bersyarat · M - **RFC:** §5.8, §9 - **Kerjakan:** migrasi `game_reward_counters`; repository `Consume(scope, id, day, x, limit)` yang mengembalikan jumlah yang **benar-benar** diterima (dipotong ke sisa limit, 0 bila habis). Hari dihitung di Asia/Jakarta. - **Selesai jika:** test DB: 20 goroutine menambah counter yang sama dengan limit 100 → total tepat 100, tidak pernah lewat. - **Bergantung pada:** EG-106 ### EG-402 · Guard di complete · S - **RFC:** §9 - **Kerjakan:** panggil `Consume` untuk `USER` dan `GLOBAL` harian (dari setting) dan `GAME` harian (dari `result_rules`) sebelum kredit. Batas yang memotong dicatat di `reward_breakdown` dan dikembalikan di response. - **Selesai jika:** reward 30 dengan sisa limit user 10 → kredit 10, breakdown menyebut limit user. Sisa 0 → session `COMPLETED` dengan reward 0. - **Bergantung pada:** EG-303, EG-401 --- ## Fase 5 — Voucher & Redemption ### EG-501 · Migrasi voucher · M - **RFC:** §5.7 - **Kerjakan:** `vouchers`, `voucher_codes`, `voucher_redemptions`, `voucher_redemption_costs`. - **Selesai jika:** up/down bersih. Ditolak database: voucher `STATIC` tanpa `stock`; `EXTERNAL` tanpa `provider`; kode `REDEEMED` tanpa `redemption_id`; dua redemption dengan `(customer_id, idempotency_key)` yang sama. - **Bergantung pada:** – ### EG-502 · Admin voucher + impor kode · M - **RFC:** §11 (admin) - **Kerjakan:** CRUD `/marketing/enakgame/vouchers`, `POST /:id/codes` (CSV, kode duplikat dilewati dan dilaporkan), `GET /:id/codes` dengan jumlah per status. `RequireLoyaltyManager` dan audit. - **Selesai jika:** impor CSV yang sama dua kali tidak menggandakan kode. - **Bergantung pada:** EG-104, EG-501 ### EG-503 · Aksi PIN `REDEEM` · S - **RFC:** §7.4 langkah 2 - **Kerjakan:** `PinActionRedeem` di `customer_pin_processor.go`, ikut aturan kunci yang ada (5 salah, 30 menit). - **Bergantung pada:** – ### EG-504 · Redemption internal · L - **RFC:** §7.4 - **Kerjakan:** `POST /customer/enakgame/vouchers/:id/redeem` untuk `STATIC` dan `CODE_POOL`, satu transaksi, langkah persis §7.4. Debit `REWARD_REDEEM` dengan key `redeem:{redemption}`. - **Selesai jika:** test untuk: - Stok tersisa 1, dua customer menukar bersamaan → tepat satu berhasil. - `CODE_POOL`: dua redemption bersamaan mendapat kode berbeda (`SKIP LOCKED`). - Key yang sama dua kali → satu debit, satu kode. - Point kurang, PIN salah, `max_per_customer` tercapai, voucher di luar masa berlaku → ditolak tanpa apa pun tercatat. - **Bergantung pada:** EG-103, EG-501, EG-502, EG-503 ### EG-505 · Atribusi realized cost · M - **RFC:** §7.6, D5 - **Kerjakan:** query rekursif §7.6 di dalam transaksi redemption, pembagian `face_value` proporsional dengan sisa pembulatan ke bagian terbesar, insert `voucher_redemption_costs`. - **Selesai jika:** test DB untuk rantai: `GAME_REWARD` → exchange → redeem; `GAME_REWARD` → transfer → exchange → redeem; campuran `GAME_REWARD` + `EARN` (contoh §7.6: Rp7.500 ke budget, Rp2.500 tanpa budget); `Σ cost = face_value` untuk kombinasi angka yang tidak habis dibagi. - **Bergantung pada:** EG-303, EG-504 ### EG-506 · Customer: katalog & voucher saya · S - **RFC:** §11 (customer) - **Kerjakan:** `GET /customer/enakgame/vouchers` (stok tersedia, tanpa membocorkan jumlah kode per status) dan `GET /redemptions` (dengan kode voucher). - **Bergantung pada:** EG-504 ### EG-507 · `VoucherCodeExpiryJob` · S - **RFC:** §12 - **Kerjakan:** `AVAILABLE → EXPIRED` untuk kode lewat `expires_at`, per batch. - **Bergantung pada:** EG-501 --- ## Fase 6 — Budget Metrics ### EG-601 · Perhitungan metrik & status budget · M - **RFC:** §10 - **Kerjakan:** realized cost, Coin issued, remaining, utilization, forecast, exposure, dan status per budget. Global dibatasi periode; event tanpa batas waktu. Threshold dari `game_budgets.thresholds`. - **Selesai jika:** test dengan data tetap menghasilkan angka contoh PRD §30 (budget Rp100M, realized Rp60M, sisa 10 hari); Point dari `EARN` tidak ikut dihitung. - **Bergantung pada:** EG-505 ### EG-602 · Endpoint metrik budget · S - **Kerjakan:** `GET /marketing/enakgame/budgets/:id/metrics`. - **Bergantung pada:** EG-601 --- ## Fase 7 — Event / Campaign ### EG-701 · Migrasi event · S - **RFC:** §5.5 - **Kerjakan:** `game_events`, `game_event_games`. - **Selesai jika:** up/down bersih; event tanpa `budget_id` atau dengan `end_at ≤ start_at` ditolak. - **Bergantung pada:** EG-102 ### EG-702 · Admin event · M - **RFC:** §5.5, §11 - **Kerjakan:** CRUD + status. Budget yang dipasang harus milik org yang sama dan ber-scope `EVENT`. Audit. - **Bergantung pada:** EG-203, EG-701 ### EG-703 · Modifier event di complete · M - **RFC:** §7.2 langkah 7, §8 (modifier), D6 - **Kerjakan:** cari event aktif untuk game, hitung tambahan dari multiplier dan bonus, pisahkan menjadi komponen per budget, terapkan `reward_limit` dan `user_daily_limit` event lewat counter `EVENT`, cap `max_reward`. Aturan tumpuk mengikuti default PRD §16. - **Selesai jika:** contoh PRD §7 (10 Coin + Ramadan 2x) menghasilkan dua baris `GAME_REWARD`: 10 ke budget global, 10 ke budget event; event di luar jam aktif tidak berpengaruh. - **Bergantung pada:** EG-402, EG-702 ### EG-704 · Event di daftar game customer · S - **Kerjakan:** `GET /customer/enakgame/games` menyertakan event aktif per game (nama, banner, multiplier/bonus, berakhir kapan). - **Bergantung pada:** EG-206, EG-702 --- ## Fase 8 — Voucher Eksternal Terblokir sampai provider pertama ditentukan: API-nya menentukan bentuk adapter dan apakah provider menerima idempotency key (RFC §18). ### EG-801 · Interface provider + adapter pertama · M - **Kerjakan:** `VoucherProvider` (`Issue(ctx, redemptionID, voucher)`, `Lookup(ctx, redemptionID)`), adapter provider pertama, dan klasifikasi hasil: sukses, gagal pasti, tidak jelas. - **Bergantung pada:** EG-504 ### EG-802 · Redemption dua tahap · M - **RFC:** §7.5 - **Kerjakan:** jalur `EXTERNAL` di endpoint redeem: transaksi 1 (`PENDING` + debit), panggil provider di luar transaksi, transaksi 2 (`COMPLETED` + atribusi, atau `FAILED` + `REWARD_REDEEM_REFUND`). - **Selesai jika:** test dengan provider palsu untuk ketiga hasil; timeout meninggalkan `PENDING` dengan Point terpotong dan response "sedang diproses". - **Bergantung pada:** EG-505, EG-801 ### EG-803 · `VoucherRedemptionRecoveryJob` · M - **RFC:** §7.5 langkah 4, §12 - **Kerjakan:** ambil `PENDING` lewat N menit, `Lookup` ke provider, selesaikan transaksi 2. Setelah batas percobaan → refund + `FAILED`. - **Selesai jika:** tidak ada redemption yang tertinggal `PENDING` melewati batas percobaan; job berjalan dua kali tidak merefund dua kali. - **Bergantung pada:** EG-802 --- ## Fase 9 — Budget Controller & Analytics ### EG-901 · Rekomendasi multiplier · M - **RFC:** §10 (rekomendasi), PRD §30–§31 - **Kerjakan:** hitung multiplier yang membuat forecast = budget, dibatasi step maksimum dan min/max multiplier. `GET /budgets/:id/recommendation`. - **Bergantung pada:** EG-601 ### EG-902 · Terima rekomendasi · S - **Kerjakan:** admin menerima rekomendasi → reward config versi baru dibuat dari config aktif dengan angka yang disesuaikan, tercatat di audit dengan `source = budget_controller`. - **Bergantung pada:** EG-202, EG-901 ### EG-903 · Analytics · M - **RFC:** PRD §36 - **Kerjakan:** endpoint dashboard game (plays, completed, rata-rata skor & reward, Coin issued, entry cost dibayar, Coin di-refund) dan economy (Coin generated / spent / expired / outstanding, Point redeemed), per org dan rentang tanggal. - **Bergantung pada:** EG-303, EG-505 --- ## Fase 10 — Spin & Bersih-bersih ### EG-1001 · Spin sebagai game EnakGame · S - **RFC:** §14 - **Kerjakan:** seeder / langkah admin untuk game spin baru dengan config `PROBABILITY` dan reward Coin. Client Phaser di luar repo ini. - **Selesai jika:** spin bisa dimainkan lewat `/customer/enakgame/sessions` end-to-end. - **Bergantung pada:** EG-402 ### EG-1002 · Hapus alur game lama · M - **RFC:** §14, §15 - **Kerjakan:** hapus route `POST /customer/spin`, `GET /customer/games`, `GET /customer/ferris-wheel`, admin `/marketing/games`, `/marketing/game-prizes`, dan `/marketing/rewards`, beserta handler, service, processor, dan test-nya (`GamePlayProcessor`, `SpinGameService`, dan seterusnya). **Tabel `games`, `game_prizes`, `game_plays` tetap ada** untuk riwayat ledger. - **Selesai jika:** build dan test lulus; aplikasi customer sudah tidak memanggil endpoint lama (konfirmasi tim aplikasi). - **Bergantung pada:** EG-1001. Tabel `rewards` tidak punya data produksi (dikonfirmasi 2026-10-07), jadi tidak ada yang dipindah ke `vouchers`. - **Catatan:** endpoint customer lama boleh dimatikan **lebih awal**, kapan pun, untuk menutup temuan RFC §15 nomor 1 dan 2. ### EG-1003 · Bersihkan kolom lama `games` · S - **Kerjakan:** drop `games.is_active` dan berhenti membaca `metadata.coin_cost`. - **Bergantung pada:** EG-1002 --- ## Yang Bisa Dimulai Sekarang Bisa dikerjakan paralel tanpa menunggu apa pun: - **EG-001** (matikan bayar dengan EnakPoint) → **EG-002** - **EG-101** → **EG-102** → **EG-105** (skema & repository) - **EG-103** (tipe ledger) - **EG-104** (audit), **EG-106** (setting limit) - **EG-301** (Reward Engine, kode murni tanpa database) - **EG-501**, **EG-503** (fondasi voucher) Jalur kritis: **EG-105 → EG-204 → EG-303 → EG-402**. Hampir semua fase setelahnya menunggu complete game selesai.