Files
apskel-pos-backend/docs/enakgame-spin.md
T
efrilmandClaude Opus 5.5 18e87398bb feat(enakgame): spin as an EnakGame game; remove the old game flow
EnakGame phase 10 of docs/tasks-enakgame.md (EG-1001 to EG-1003).

Spin (EG-1001)
- PROBABILITY entries take an optional label (a wheel segment). The customer game
  list shows a PROBABILITY game's prizes (entry, label, amount, never weights), and
  completing returns the drawn prize, so the client can draw the wheel and stop it
  on the server's draw.
- docs/enakgame-spin.md: the admin steps to set up spin per organization (no
  seeder) and the customer app flow. An HTTP test plays it end to end.

Old game flow removed (EG-1002)
- Routes POST /customer/spin, GET /customer/games, GET /customer/ferris-wheel, and
  admin /marketing/games, /marketing/game-prizes, /marketing/rewards, with their
  handlers, services, processors, repositories, validators, models, contracts,
  mappers and tests (GamePlayProcessor, SpinGameService, rewards, ...). This also
  closes RFC §15 findings 1 and 2 (double charge, spinning another org's game).
- Tables games, game_prizes, game_plays and rewards stay for ledger history.
  entities.StringSlice moves to its own file; the omset tracker (unrouted) keeps
  game_id but no longer embeds the old game response.

games.is_active dropped (EG-1003)
- Migration 000115; nothing reads metadata.coin_cost any more.

The EnakPoint integration docs now point at /customer/enakgame. The Postgres tests
were not run: no test database here. Migration 000115 has not been run anywhere.
The customer app must stop calling the removed endpoints before this is deployed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:31:56 +07:00

3.0 KiB
Raw Blame History

Spin sebagai Game EnakGame

Sumber: RFC EnakGame §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

{
  "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

{
  "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.