# Spin sebagai Game EnakGame **Sumber:** [RFC EnakGame](rfc-enakgame.md) §14, task EG-1001 **Pembaca:** admin organisasi dan tim backoffice / aplikasi customer Spin lama (`POST /customer/spin`) diganti dengan game EnakGame biasa: tipe `SPIN`, reward `PROBABILITY`, hadiah berupa EnakCoin. Spin dimainkan lewat endpoint session yang sama dengan game lain, sehingga ikut mendapat idempotency, refund otomatis, budget, event, dan Economy Guard. Tidak ada seeder: setiap organisasi membuat spin-nya sendiri lewat API admin di bawah. Semua langkah memakai token admin organisasi; langkah 2–4 butuh loyalty manager. ## Langkah Admin ### 1. Buat game `POST /api/v1/marketing/enakgame/games` ```json { "name": "Spin Harian", "slug": "spin", "type": "SPIN", "entry_cost": 5, "status": "ACTIVE", "thumbnail_url": "https://…/spin.png", "game_url": "https://…/spin/index.html" } ``` `entry_cost` adalah EnakCoin yang dipotong setiap kali spin (minimal 1). ### 2. Buat reward config `PROBABILITY` `POST /api/v1/marketing/enakgame/games/:id/reward-configs` ```json { "reward_type": "PROBABILITY", "max_reward": 50, "rules": { "table": [ { "weight": 50, "amount": 0, "label": "Zonk" }, { "weight": 30, "amount": 3, "label": "3 Coin" }, { "weight": 15, "amount": 10, "label": "10 Coin" }, { "weight": 5, "amount": 50, "label": "Jackpot" } ] }, "reason": "Spin pertama" } ``` - Satu baris `table` = satu segmen roda, urut searah gambar roda. - `weight` bilangan bulat ≥ 1. Peluang segmen = `weight` ÷ total weight (di atas: 50%, 30%, 15%, 5%). Weight tidak pernah dikirim ke customer. - `amount` EnakCoin yang didapat (boleh 0). `label` opsional, maksimal 100 karakter, ditampilkan di roda. - `max_reward` minimal sebesar `amount` terbesar, kalau tidak hadiah besar terpotong. ### 3. Aktifkan config `POST /api/v1/marketing/enakgame/reward-configs/:id/activate` Mengganti hadiah nanti berarti membuat versi config baru lalu mengaktifkannya; session yang sedang berjalan tetap memakai versi saat dimulai. ### 4. Pastikan ada budget global bulan berjalan `POST /api/v1/marketing/enakgame/budgets` dengan `scope: "GLOBAL"`, bila belum ada. Tanpa budget global, customer tidak bisa memulai game apa pun. ## Alur di Aplikasi Customer 1. `GET /api/v1/customer/enakgame/games`: game spin punya `prizes`, yaitu segmen roda (`entry`, `label`, `amount`) dalam urutan config. Gambar roda dari sini. 2. `POST /api/v1/customer/enakgame/sessions` dengan `{"game_id": "…"}` dan header `Idempotency-Key`. Entry cost dipotong di sini. 3. `POST /api/v1/customer/enakgame/sessions/:id/complete` dengan body `{}`. Server yang mengundi. Response berisi `prize` (`entry`, `label`, `amount`): putar roda sampai berhenti di segmen `entry` itu. `reward_total` adalah Coin yang benar-benar masuk, bisa lebih besar dari `prize.amount` karena event, atau lebih kecil karena limit harian (`limited_by`). Aplikasi tidak boleh mengundi sendiri atau mengirim hadiah: apa pun yang dikirim selain data hasil diabaikan.