EnakGame: pay EnakCoin to play, earn EnakCoin from the result, exchange into EnakPoint, and redeem EnakPoint for vouchers only. - enakgame-prd.md: economy and business rules, including entry cost and automatic refund, monthly global budget with a separate budget per event (event = campaign), and EnakPoint being voucher-only. - rfc-enakgame.md: built on the existing wallet, ledger and lots. Game sessions with a state machine, versioned reward configs, Economy Guard counters, vouchers with internal codes and external providers, and realized cost attributed to budgets by tracing the lots spent. - tasks-enakgame.md: EG-001 to EG-1003 in eleven phases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1623 lines
39 KiB
Markdown
1623 lines
39 KiB
Markdown
# EnakGame — Economy & Business Rules v1
|
||
|
||
| Item | Value |
|
||
| --------------------------- | ----------------------------------------------------------------------------------- |
|
||
| **Status** | Draft v1 |
|
||
| **Purpose** | Source of truth untuk perencanaan dan implementasi EnakGame menggunakan Claude Code |
|
||
| **Backend** | Go |
|
||
| **Database** | PostgreSQL |
|
||
| **Game Client** | Phaser |
|
||
| **Frontend/Backoffice** | Next.js |
|
||
| **Cache/Temporary Session** | Redis (opsional, sesuai kebutuhan implementasi) |
|
||
|
||
---
|
||
|
||
## 1. Product Overview
|
||
|
||
EnakGame adalah game portal dalam ekosistem Enaklo/F&B.
|
||
|
||
- User membayar **Coin** untuk memainkan mini-game (entry cost), dan dapat memperoleh **Coin** sebagai virtual reward dari hasil permainan.
|
||
- Coin dapat dikonversi/digunakan sebagai **Point**, kemudian Point **hanya** dapat ditukar ke voucher yang disediakan Enaklo.
|
||
- Point **tidak** dapat digunakan sebagai alat pembayaran dan **tidak** dapat diuangkan.
|
||
- EnakGame **bukan** platform gambling dan **tidak** menggunakan uang tunai sebagai hadiah dari game.
|
||
|
||
### Core Flow
|
||
|
||
```text
|
||
User
|
||
↓
|
||
Game Lobby
|
||
↓
|
||
Start Game
|
||
↓
|
||
Pay Entry Cost (Coin) + Create Game Session
|
||
↓
|
||
Play Game
|
||
↓
|
||
Submit Result
|
||
↓
|
||
Result Validation
|
||
↓
|
||
Reward Engine
|
||
↓
|
||
Economy Guard
|
||
↓
|
||
Coin Wallet + Ledger
|
||
↓
|
||
Coin → Point
|
||
↓
|
||
Voucher Redemption
|
||
↓
|
||
Realized Voucher Cost
|
||
↓
|
||
Budget Controller
|
||
```
|
||
|
||
---
|
||
|
||
## 2. Core Business Principles
|
||
|
||
### 2.1 Server Is Authoritative
|
||
|
||
Client/game (Phaser) **tidak boleh** menentukan reward final.
|
||
|
||
Client hanya mengirim hasil permainan yang diperlukan, misalnya:
|
||
|
||
- `session_id`
|
||
- `score`
|
||
- `outcome`
|
||
- game-specific result data
|
||
|
||
Backend menghitung reward berdasarkan configuration yang aktif.
|
||
|
||
#### ❌ Tidak boleh
|
||
|
||
```text
|
||
Phaser:
|
||
score = 800
|
||
reward = 1000 Coin
|
||
→ backend menerima 1000 Coin
|
||
```
|
||
|
||
#### ✅ Yang benar
|
||
|
||
```text
|
||
Phaser:
|
||
score = 800
|
||
|
||
Backend:
|
||
score 800
|
||
→ load active reward configuration
|
||
→ calculate reward
|
||
→ validate limits
|
||
→ issue approved Coin
|
||
```
|
||
|
||
---
|
||
|
||
## 3. Currency Model
|
||
|
||
EnakGame memiliki dua konsep utama: **Coin** dan **Point**.
|
||
|
||
### 3.1 Coin
|
||
|
||
Coin adalah **virtual game/reward currency**.
|
||
|
||
Sumber utama:
|
||
|
||
- Game reward
|
||
- Event reward
|
||
- Mission reward
|
||
- Bonus/promo yang diizinkan
|
||
|
||
Penggunaan:
|
||
|
||
- Membayar entry cost untuk memainkan game (lihat [Section 10.1](#101-game-entry-cost))
|
||
- Dikonversi ke Point
|
||
|
||
Coin dapat memiliki expiration (lihat [Section 4](#4-coin-expiration)).
|
||
|
||
### 3.2 Point
|
||
|
||
Point adalah **redemption currency**.
|
||
|
||
Current business rule:
|
||
|
||
```text
|
||
1 Coin = 1 Point = Rp1
|
||
```
|
||
|
||
Penggunaan Point dibatasi:
|
||
|
||
- Point **hanya** dapat ditukar ke voucher (lihat [Section 26](#26-redemption-flow)).
|
||
- Point **tidak** dapat digunakan sebagai alat pembayaran (misalnya membayar order).
|
||
- Point **tidak** dapat diuangkan (cash out).
|
||
|
||
Nilai `Rp1` di atas adalah nilai acuan untuk perhitungan voucher dan budget, **bukan** nilai tukar ke uang tunai.
|
||
|
||
Konversi dan expiration mengikuti sistem existing ([prd-point-coin.md](prd-point-coin.md)), tidak didesain ulang:
|
||
|
||
- **Coin → Point** menggunakan fitur exchange existing (K3, F4): dilakukan manual oleh customer, satu arah, kurs di-configure di level organisasi (default 1 : 1).
|
||
- **Point expiration** menggunakan sistem expiration existing per lot (F12).
|
||
|
||
> **Catatan perubahan dari sistem existing:** Berdasarkan keputusan sebelumnya ([prd-point-coin.md](prd-point-coin.md)), backend saat ini masih mengizinkan EnakPoint dipakai untuk **membayar order** (point payment, ledger `PAYMENT` / `PAYMENT_REFUND`). Aturan EnakGame di atas menggantikan keputusan tersebut, sehingga fitur point payment perlu di-update/dinonaktifkan sebelum EnakGame berjalan. Belum ada order yang dibayar dengan Point, jadi tidak ada data lama yang perlu dimigrasi. Saldo Point user tetap sebagai Point; yang berubah hanya penggunaannya (redeem voucher saja).
|
||
|
||
Namun Coin dan Point tetap diperlakukan sebagai **konsep/domain yang berbeda** agar sistem tidak terlalu tightly coupled.
|
||
|
||
Tujuannya agar business rule di masa depan dapat berubah tanpa membongkar Game/Reward Engine.
|
||
|
||
---
|
||
|
||
## 4. Coin Expiration
|
||
|
||
Sistem Coin sudah memiliki konsep expiration. Expiration harus tetap menjadi bagian dari economy.
|
||
|
||
Coin yang expired:
|
||
|
||
```text
|
||
Wallet usable balance
|
||
↓
|
||
berkurang
|
||
|
||
Ledger
|
||
↓
|
||
mencatat expiration transaction
|
||
```
|
||
|
||
> **Penting:** Expiration **tidak boleh** dianggap sebagai voucher redemption.
|
||
|
||
Kategori transaksi harus dapat dibedakan:
|
||
|
||
```text
|
||
Wallet usable balance
|
||
↓
|
||
berkurang
|
||
|
||
Ledger
|
||
↓
|
||
mencatat expiration transaction
|
||
```
|
||
|
||
Implementasi detail expiration mengikuti sistem existing dan tidak perlu didesain ulang kecuali diperlukan.
|
||
|
||
---
|
||
|
||
## 5. Budget Model
|
||
|
||
### 5.1 Budget Is Shared
|
||
|
||
Semua game menggunakan **budget pool yang sama**. Tidak ada kewajiban setiap game memiliki budget terpisah.
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
EnakGame Global Budget
|
||
Rp100.000.000
|
||
│
|
||
├── Runner
|
||
├── Spin
|
||
├── Memory
|
||
└── Puzzle
|
||
```
|
||
|
||
Semua reward normal game berasal dari economy/budget pool yang sama.
|
||
|
||
Pengecualian: **Event/Campaign** memiliki budget sendiri (lihat [Section 7](#7-budget-hierarchy)).
|
||
|
||
### 5.2 Budget Period
|
||
|
||
- Global budget menggunakan periode **bulanan** secara default.
|
||
- Periode budget dapat di-**configure**.
|
||
- Setiap Event/Campaign memiliki budget sendiri, terpisah dari global budget bulanan.
|
||
|
||
---
|
||
|
||
## 6. Budget vs Realized Cost
|
||
|
||
### 6.1 Budget Is Based on Actual Voucher Redemption
|
||
|
||
Budget Controller menggunakan **voucher yang benar-benar diredeem** sebagai dasar actual cost.
|
||
|
||
Coin yang baru diterbitkan **bukan** otomatis dianggap sebagai biaya voucher.
|
||
|
||
Contoh:
|
||
|
||
| Metric | Jumlah |
|
||
| ------------------- | ---------- |
|
||
| Coin Generated | 20.000.000 |
|
||
| Coin Outstanding | 12.000.000 |
|
||
| Coin Expired | 3.000.000 |
|
||
| Coin Used/Converted | 5.000.000 |
|
||
|
||
```text
|
||
Actual Voucher Cost = Rp5.000.000
|
||
```
|
||
|
||
Karena `1 Point = Rp1` dan Point digunakan untuk redemption.
|
||
|
||
### 6.1.1 Hanya Point dari EnakGame yang Dihitung ke Budget
|
||
|
||
Satu voucher dapat dibayar dengan Point dari berbagai asal: reward game, belanja (earning order), transfer, atau adjustment.
|
||
|
||
Realized cost yang dihitung ke budget EnakGame (global maupun event) **hanya** bagian voucher yang dibayar dengan Point yang berasal dari **reward EnakGame**. Bagian yang dibayar dengan Point dari belanja tetap dicatat untuk reporting Finance, tetapi **tidak** mengurangi budget mana pun.
|
||
|
||
```text
|
||
Voucher face value = Rp10.000, point cost = 8.000
|
||
Point dipakai = 6.000 (dari reward game) + 2.000 (dari belanja)
|
||
|
||
Dihitung ke budget = Rp7.500
|
||
Tidak ke budget = Rp2.500
|
||
```
|
||
|
||
### 6.2 Important Distinction
|
||
|
||
Sistem harus membedakan:
|
||
|
||
| Konsep | Definisi |
|
||
| ----------------- | ------------------------------------------------------------ |
|
||
| **Issuance** | Berapa Coin yang dikeluarkan oleh Reward Engine |
|
||
| **Outstanding** | Berapa Coin masih berada di user/economy |
|
||
| **Redemption** | Berapa Point benar-benar digunakan untuk mendapatkan voucher |
|
||
| **Realized Cost** | Nilai voucher yang benar-benar menjadi cost bisnis |
|
||
|
||
Budget Controller terutama menggunakan **realized redemption/cost**, bukan sekadar total Coin issuance.
|
||
|
||
---
|
||
|
||
## 7. Budget Hierarchy
|
||
|
||
Secara konsep:
|
||
|
||
```text
|
||
GLOBAL BUDGET (bulanan, configurable)
|
||
│
|
||
└── Regular Game Activity (reward normal semua game)
|
||
|
||
EVENT/CAMPAIGN BUDGET (per event, terpisah)
|
||
│
|
||
└── Tambahan reward dari event (multiplier + bonus)
|
||
```
|
||
|
||
**Event dan Campaign adalah hal yang sama.** Setiap event memiliki **budget sendiri**, terpisah dari global budget.
|
||
|
||
Pembagian biaya saat event berjalan:
|
||
|
||
| Komponen reward | Dibiayai oleh |
|
||
| ------------------------------------ | --------------- |
|
||
| Reward normal game (base reward) | Global budget |
|
||
| Tambahan dari event (multiplier/bonus) | Budget event |
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
Normal Reward 10 Coin → Global budget
|
||
Ramadan 2x +10 Coin → Budget event Ramadan
|
||
──────────────────────────
|
||
Final Reward 20 Coin
|
||
```
|
||
|
||
Realized cost dari Point yang berasal dari tambahan event dihitung ke budget event tersebut, **kapan pun** Point itu ditukar ke voucher, termasuk setelah event berakhir.
|
||
|
||
---
|
||
|
||
## 8. Budget Metrics
|
||
|
||
Minimum metric yang harus tersedia:
|
||
|
||
- Total Budget
|
||
- Allocated Budget
|
||
- Realized Cost
|
||
- Remaining Budget
|
||
- Budget Utilization
|
||
- Forecasted Cost
|
||
- Forecasted Remaining Budget
|
||
- Budget Status
|
||
|
||
Contoh status:
|
||
|
||
- `HEALTHY`
|
||
- `WARNING`
|
||
- `CRITICAL`
|
||
- `EXHAUSTED`
|
||
|
||
Threshold harus **configurable**.
|
||
|
||
---
|
||
|
||
## 9. Game Management
|
||
|
||
Game Management mengelola semua game yang tersedia di EnakGame.
|
||
|
||
Minimum information:
|
||
|
||
- `id`
|
||
- `name`
|
||
- `slug`
|
||
- `description`
|
||
- `thumbnail`
|
||
- game URL/path
|
||
- `version`
|
||
- `status`
|
||
- `configuration`
|
||
- `created_at`
|
||
- `updated_at`
|
||
|
||
Game status minimal:
|
||
|
||
- `DRAFT`
|
||
- `ACTIVE`
|
||
- `INACTIVE`
|
||
- `ARCHIVED`
|
||
|
||
Game harus dapat memiliki reward configuration.
|
||
|
||
---
|
||
|
||
## 10. Game Session
|
||
|
||
Setiap permainan yang dapat menghasilkan reward **harus** memiliki session.
|
||
|
||
Flow:
|
||
|
||
```text
|
||
User
|
||
↓
|
||
Start Game
|
||
↓
|
||
Debit Entry Cost (Coin) + Create Game Session
|
||
↓
|
||
Phaser Game
|
||
↓
|
||
Submit Result
|
||
↓
|
||
Validate Session
|
||
↓
|
||
Calculate Reward
|
||
↓
|
||
Issue Reward
|
||
```
|
||
|
||
Session harus dapat mencegah:
|
||
|
||
- duplicate completion
|
||
- duplicate reward
|
||
- expired session
|
||
- invalid session
|
||
- user mismatch
|
||
- game mismatch
|
||
|
||
Recommended concept: `game_session_id` menjadi **idempotency key** untuk reward completion.
|
||
|
||
> **Penting:** Satu session tidak boleh menghasilkan reward berkali-kali.
|
||
|
||
### 10.1 Game Entry Cost
|
||
|
||
Semua game **wajib berbayar** menggunakan **Coin**. Tidak ada game gratis.
|
||
|
||
- Entry cost di-configure per game sebagai bagian dari game configuration, dengan nilai minimal **1 Coin**.
|
||
- Entry cost dibayar dengan **Coin**, bukan Point.
|
||
- Coin dipotong saat **Start Game**, yaitu saat session dibuat — bukan saat submit result.
|
||
- Debit Coin dan pembuatan session terjadi dalam **satu database transaction**. Jika salah satu gagal, tidak ada Coin yang terpotong dan tidak ada session yang terbuat.
|
||
- Jika usable balance Coin tidak cukup, session **tidak** dibuat dan user tidak dapat bermain.
|
||
- Entry cost yang berlaku dicatat di session (snapshot), sehingga perubahan configuration tidak mengubah session yang sudah berjalan.
|
||
- Debit dicatat di ledger sebagai `SPENT` dengan reference `game_session_id` dan `game_id`.
|
||
- Satu session hanya boleh didebit **satu kali** (`game_session_id` menjadi idempotency key untuk debit).
|
||
|
||
```text
|
||
Start Game
|
||
→ load game configuration (entry cost)
|
||
→ check Coin usable balance
|
||
→ [1 transaction] debit Coin (SPENT) + create session
|
||
→ return session_id ke Phaser
|
||
```
|
||
|
||
#### Entry Cost & Budget
|
||
|
||
Entry cost **tidak** mengurangi atau meng-offset perhitungan budget.
|
||
|
||
Budget Controller dan Budget Metrics hanya memperhitungkan **reward** (Coin yang diterbitkan) dan realized voucher cost. Coin yang dibayar untuk bermain tidak dianggap sebagai pemasukan yang menambah budget.
|
||
|
||
```text
|
||
Reward issued = 1.000.000 Coin
|
||
Entry cost paid = 400.000 Coin
|
||
|
||
Budget memakai → 1.000.000 Coin (reward), bukan 600.000 (net)
|
||
```
|
||
|
||
### 10.2 Entry Cost Refund
|
||
|
||
Entry cost dapat dikembalikan (refund) ke user untuk session yang tidak dapat diselesaikan.
|
||
|
||
- Refund mengembalikan **jumlah Coin yang sama** dengan entry cost yang tercatat di session.
|
||
- Refund dicatat di ledger sebagai `REFUND` dengan reference `game_session_id` dan reference ke transaksi `SPENT` asalnya.
|
||
- Refund **wajib idempotent**: satu session maksimal satu kali refund.
|
||
- Session yang sudah di-refund **tidak** boleh menghasilkan reward, dan session yang sudah rewarded **tidak** boleh di-refund.
|
||
- Refund bukan reward: tidak melewati Reward Engine, tidak dihitung sebagai Coin issued, dan tidak dihitung di budget.
|
||
- Refund harus auditable (siapa/sistem apa yang memicu dan alasannya).
|
||
|
||
Kondisi refund:
|
||
|
||
| Kondisi | Refund |
|
||
| -------------------------------------------------------- | -------------------------- |
|
||
| System error (session gagal diselesaikan karena sistem) | **Ya, otomatis** oleh sistem |
|
||
| Game di-nonaktifkan saat session sedang berjalan | **Ya, otomatis** oleh sistem |
|
||
| Session expired/abandoned oleh user | **Tidak** |
|
||
|
||
- Refund dijalankan **otomatis** oleh sistem, tanpa perlu request user atau approval admin.
|
||
- Session yang ditinggalkan user tidak di-refund, agar user tidak dapat memulai game lalu meninggalkannya saat hasilnya tidak menguntungkan.
|
||
|
||
---
|
||
|
||
## 11. Reward Engine
|
||
|
||
Reward Engine adalah komponen yang menentukan berapa reward yang **secara teoritis** berhak diterima user berdasarkan result dan configuration.
|
||
|
||
Reward Engine **tidak** bertanggung jawab sendirian untuk memutuskan apakah reward boleh diterbitkan.
|
||
|
||
Flow:
|
||
|
||
```text
|
||
Game Result
|
||
↓
|
||
Reward Engine
|
||
↓
|
||
Base Reward
|
||
↓
|
||
Event Modifier / Bonus
|
||
↓
|
||
Final Calculated Reward
|
||
↓
|
||
Economy Guard
|
||
```
|
||
|
||
---
|
||
|
||
## 12. Supported Reward Types
|
||
|
||
Reward Engine dirancang agar **extensible**.
|
||
|
||
Jenis reward minimum yang dapat didukung:
|
||
|
||
### `FIXED`
|
||
|
||
```text
|
||
Play completed → 5 Coin
|
||
```
|
||
|
||
### `SCORE_BASED`
|
||
|
||
| Score | Reward |
|
||
| -------- | ------- |
|
||
| 0–100 | 1 Coin |
|
||
| 101–500 | 5 Coin |
|
||
| 501–1000 | 10 Coin |
|
||
| 1001+ | 20 Coin |
|
||
|
||
### `OUTCOME_BASED`
|
||
|
||
| Outcome | Reward |
|
||
| --------- | ------- |
|
||
| `PERFECT` | 20 Coin |
|
||
| `GOOD` | 10 Coin |
|
||
| `NORMAL` | 5 Coin |
|
||
| `FAIL` | 0 Coin |
|
||
|
||
### `PROBABILITY`
|
||
|
||
Reward berdasarkan probability yang **dihitung server**.
|
||
|
||
Contoh:
|
||
|
||
| Probability | Reward |
|
||
| ----------- | --------- |
|
||
| 0.1% | 1000 Coin |
|
||
| 1% | 100 Coin |
|
||
| 10% | 10 Coin |
|
||
| 88.9% | 0 Coin |
|
||
|
||
Probability harus tervalidasi.
|
||
|
||
### `MULTIPLIER`
|
||
|
||
Base reward dikalikan modifier.
|
||
|
||
```text
|
||
Base = 10 Coin
|
||
Multiplier = 2x
|
||
|
||
Final = 20 Coin
|
||
```
|
||
|
||
### `TIERED`
|
||
|
||
Reward berdasarkan tier/user/game progression.
|
||
|
||
---
|
||
|
||
Jenis reward dapat ditambah di masa depan tanpa mengubah seluruh engine.
|
||
|
||
---
|
||
|
||
## 13. Reward Configuration
|
||
|
||
Reward configuration harus memiliki **lifecycle/version**.
|
||
|
||
Contoh:
|
||
|
||
| Config | Reward |
|
||
| ----------------------- | ------- |
|
||
| Runner Reward Config v1 | 10 Coin |
|
||
| Runner Reward Config v2 | 8 Coin |
|
||
|
||
> **Penting:** Jangan overwrite configuration lama jika configuration tersebut sudah pernah digunakan dalam transaksi.
|
||
|
||
Tujuan:
|
||
|
||
- audit
|
||
- debugging
|
||
- historical accuracy
|
||
- mengetahui rule yang berlaku saat user bermain
|
||
|
||
Setiap reward transaction idealnya dapat dilacak ke configuration/version yang digunakan.
|
||
|
||
---
|
||
|
||
## 14. Normal Reward + Event Reward
|
||
|
||
Normal reward dan event modifier **boleh aktif bersamaan**.
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
Normal Reward 10 Coin
|
||
Ramadan Event 2x multiplier
|
||
Mission Bonus +5 Coin
|
||
─────────────────────────
|
||
Final Reward 25 Coin
|
||
```
|
||
|
||
Event **tidak boleh** mengubah permanent/base configuration game. Event bekerja sebagai **layer/override/modifier**.
|
||
|
||
Setelah event selesai:
|
||
|
||
```text
|
||
Normal Reward 10 Coin
|
||
```
|
||
|
||
---
|
||
|
||
## 15. Event Management
|
||
|
||
Event digunakan untuk seasonal/campaign activity.
|
||
|
||
Contoh:
|
||
|
||
- Ramadan
|
||
- Christmas
|
||
- Independence Day
|
||
- Anniversary
|
||
- F&B campaign
|
||
|
||
Minimum event data:
|
||
|
||
- `id`
|
||
- `name`
|
||
- `slug`
|
||
- `description`
|
||
- `banner`
|
||
- `start_at`
|
||
- `end_at`
|
||
- `timezone`
|
||
- `status`
|
||
- `priority`
|
||
- reward configuration/modifier
|
||
- budget sendiri (lihat [Section 7](#7-budget-hierarchy))
|
||
- rules
|
||
|
||
Event dapat menentukan:
|
||
|
||
- participating games
|
||
- reward multiplier
|
||
- bonus reward
|
||
- mission
|
||
- daily limit
|
||
- user limit
|
||
- leaderboard
|
||
- event-specific campaign rules
|
||
|
||
---
|
||
|
||
## 16. Multiple Event Handling
|
||
|
||
Karena event dapat overlap, sistem harus memiliki **priority/stacking rule**.
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
Normal Reward
|
||
+ Event A
|
||
+ Event B
|
||
```
|
||
|
||
Sistem harus memiliki aturan jelas apakah:
|
||
|
||
- hanya event priority tertinggi yang berlaku
|
||
- modifier dapat ditumpuk
|
||
- bonus dapat ditumpuk
|
||
- ada maximum multiplier
|
||
|
||
Default recommendation:
|
||
|
||
| Komponen | Rule |
|
||
| ------------------ | --------------------- |
|
||
| Reward Modifier | Controlled stacking |
|
||
| Bonus | Independently tracked |
|
||
| Maximum Reward Cap | Always enforced |
|
||
|
||
> **Penting:** Final stacking rules harus ditentukan sebelum production.
|
||
|
||
---
|
||
|
||
## 17. Economy Guard
|
||
|
||
Economy Guard menentukan apakah calculated reward **benar-benar boleh diterbitkan**.
|
||
|
||
Minimum checks:
|
||
|
||
- session valid
|
||
- session belum rewarded
|
||
- user valid
|
||
- game valid
|
||
- reward configuration active
|
||
- user daily limit
|
||
- game daily limit
|
||
- event limit
|
||
- global limit
|
||
- maximum reward
|
||
- budget/economy status
|
||
- fraud/risk checks
|
||
- idempotency
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
Reward Engine
|
||
→ 20 Coin
|
||
|
||
Economy Guard
|
||
→ daily limit OK
|
||
→ event limit OK
|
||
→ duplicate NO
|
||
→ budget status OK
|
||
|
||
Approved
|
||
→ issue 20 Coin
|
||
```
|
||
|
||
---
|
||
|
||
## 18. Coin Wallet
|
||
|
||
Wallet menyimpan **current usable balance**.
|
||
|
||
Namun wallet **bukan** satu-satunya source of truth. Source of truth untuk audit adalah **ledger**.
|
||
|
||
| Komponen | Digunakan untuk |
|
||
| ---------- | ---------------------------------------------------------------- |
|
||
| **Wallet** | fast balance lookup, current balance |
|
||
| **Ledger** | transaction history, audit, reconciliation, debugging, reporting |
|
||
|
||
---
|
||
|
||
## 19. Coin Ledger
|
||
|
||
Setiap perubahan balance **harus** menghasilkan ledger transaction.
|
||
|
||
Minimum transaction concepts:
|
||
|
||
- `EARNED`
|
||
- `BONUS`
|
||
- `SPENT`
|
||
- `EXPIRED`
|
||
- `ADJUSTMENT`
|
||
- `REVERSAL`
|
||
- `CONVERSION`
|
||
- `REFUND`
|
||
|
||
`SPENT` mencakup pembayaran entry cost game. `REFUND` adalah pengembalian entry cost (lihat [Section 10.2](#102-entry-cost-refund)).
|
||
|
||
Transaction harus dapat memiliki reference:
|
||
|
||
- `game_session_id`
|
||
- `game_id`
|
||
- `event_id`
|
||
- `voucher_redemption_id`
|
||
- `mission_id`
|
||
- admin adjustment reference
|
||
|
||
Idealnya setiap transaction memiliki:
|
||
|
||
- `balance_before`
|
||
- `amount`
|
||
- `balance_after`
|
||
|
||
---
|
||
|
||
## 20. Idempotency
|
||
|
||
Reward transaction **wajib idempotent**.
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
POST /game-session/complete
|
||
session_id = ABC
|
||
```
|
||
|
||
Request pertama:
|
||
|
||
```text
|
||
Reward = 10 Coin
|
||
Status = SUCCESS
|
||
```
|
||
|
||
Request kedua dengan session yang sama:
|
||
|
||
```text
|
||
Tidak membuat reward baru.
|
||
Return existing reward/result.
|
||
```
|
||
|
||
Database harus memiliki **unique constraint/strategy** yang menjamin satu session tidak bisa menghasilkan duplicate reward.
|
||
|
||
Hal yang sama berlaku untuk entry cost: satu session maksimal satu debit `SPENT` dan satu `REFUND`.
|
||
|
||
---
|
||
|
||
## 21. Voucher Management
|
||
|
||
Voucher Management adalah **core module tersendiri**.
|
||
|
||
Voucher adalah benefit yang dapat ditukar menggunakan Point.
|
||
|
||
Minimum voucher data:
|
||
|
||
- `id`
|
||
- `name`
|
||
- `description`
|
||
- `image`
|
||
- provider/merchant
|
||
- voucher value
|
||
- point cost
|
||
- stock
|
||
- validity
|
||
- terms
|
||
- status
|
||
- redemption rules
|
||
|
||
Sumber voucher mendukung **keduanya**:
|
||
|
||
- **Internal voucher codes** — kode dikelola sendiri (lihat [Section 25](#25-voucher-stock)).
|
||
- **External API** — kode/voucher diterbitkan oleh provider eksternal saat redemption.
|
||
|
||
---
|
||
|
||
## 22. Voucher Value vs Point Cost
|
||
|
||
Jangan menganggap `Voucher Value = Point Cost` selamanya.
|
||
|
||
Current conversion:
|
||
|
||
```text
|
||
1 Coin = 1 Point = Rp1
|
||
```
|
||
|
||
Tetapi sebuah voucher dapat memiliki:
|
||
|
||
| Voucher Value | Point Cost |
|
||
| ------------- | ---------- |
|
||
| Rp10.000 | 8.000 |
|
||
| Rp10.000 | 12.000 |
|
||
|
||
Hal ini memungkinkan Product/Finance mengatur **subsidy, promotion, atau margin**.
|
||
|
||
---
|
||
|
||
## 23. Voucher Types
|
||
|
||
Voucher Management harus **extensible**.
|
||
|
||
Contoh:
|
||
|
||
| Type | Contoh |
|
||
| ----------------------- | ---------------------------------------------------------- |
|
||
| **Fixed Value** | Rp5.000, Rp10.000, Rp20.000 |
|
||
| **Percentage Discount** | 10%, 20%, 50% |
|
||
| **Free Item** | Free Coffee, Free Food |
|
||
| **Merchant Benefit** | Benefit yang hanya berlaku pada merchant/location tertentu |
|
||
|
||
Jenis voucher dapat ditambah sesuai kebutuhan.
|
||
|
||
---
|
||
|
||
## 24. Voucher Inventory
|
||
|
||
Jika voucher menggunakan unique code, sistem harus memiliki inventory.
|
||
|
||
Status minimal:
|
||
|
||
- `AVAILABLE`
|
||
- `RESERVED`
|
||
- `REDEEMED`
|
||
- `EXPIRED`
|
||
- `CANCELLED`
|
||
|
||
Flow normal:
|
||
|
||
```text
|
||
AVAILABLE → RESERVED → REDEEMED
|
||
```
|
||
|
||
Jika redemption gagal/timeout:
|
||
|
||
```text
|
||
RESERVED → AVAILABLE
|
||
```
|
||
|
||
Jika voucher expired:
|
||
|
||
```text
|
||
AVAILABLE → EXPIRED
|
||
```
|
||
|
||
---
|
||
|
||
## 25. Voucher Stock
|
||
|
||
Voucher dapat menggunakan salah satu dari:
|
||
|
||
### Static Stock
|
||
|
||
Admin memasukkan jumlah stock.
|
||
|
||
```text
|
||
Stock = 1.000
|
||
```
|
||
|
||
### Code Pool
|
||
|
||
Admin/provider memasukkan unique voucher codes.
|
||
|
||
```text
|
||
CODE-001
|
||
CODE-002
|
||
CODE-003
|
||
...
|
||
```
|
||
|
||
System harus mengetahui stock available secara **reliable**.
|
||
|
||
---
|
||
|
||
## 26. Redemption Flow
|
||
|
||
Recommended flow:
|
||
|
||
```text
|
||
User
|
||
↓
|
||
Select Voucher
|
||
↓
|
||
Check Point Balance
|
||
↓
|
||
Check Voucher Availability
|
||
↓
|
||
Reserve Voucher
|
||
↓
|
||
Deduct Point
|
||
↓
|
||
Issue Voucher
|
||
↓
|
||
Mark Voucher Redeemed
|
||
↓
|
||
Create Redemption Record
|
||
↓
|
||
Record Realized Cost
|
||
```
|
||
|
||
Transaction harus **atomic**.
|
||
|
||
> **Penting:** Jangan sampai Point sudah dikurangi **+** voucher gagal diberikan tanpa recovery/rollback.
|
||
|
||
---
|
||
|
||
## 27. Redemption Idempotency
|
||
|
||
Redemption juga **harus idempotent**.
|
||
|
||
Satu redemption request tidak boleh menghasilkan:
|
||
|
||
- dua voucher
|
||
- dua Point deduction
|
||
- dua cost records
|
||
|
||
Gunakan idempotency/reference key.
|
||
|
||
---
|
||
|
||
## 28. Realized Cost
|
||
|
||
Setiap successful voucher redemption menghasilkan **realized cost**.
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
Voucher Value = Rp10.000
|
||
Point Used = 10.000
|
||
|
||
Realized Cost = Rp10.000
|
||
```
|
||
|
||
Realized cost menggunakan **voucher face value**.
|
||
|
||
Sistem tetap menyimpan field berikut secara terpisah:
|
||
|
||
- `voucher_value` — face value, menjadi dasar realized cost dan budget
|
||
- `point_cost` — Point yang dibayar user
|
||
- `business_cost` — opsional, untuk reporting Finance jika berbeda dari face value; **tidak** dipakai untuk budget
|
||
|
||
---
|
||
|
||
## 29. Budget Controller
|
||
|
||
Budget Controller bertugas mengontrol reward economy berdasarkan **actual redemption dan forecast**.
|
||
|
||
### Input
|
||
|
||
Minimum input:
|
||
|
||
- global budget
|
||
- realized voucher cost
|
||
- remaining budget
|
||
- remaining days
|
||
- historical redemption
|
||
- coin issuance
|
||
- active users
|
||
- plays
|
||
- average reward
|
||
- event status
|
||
- redemption rate
|
||
- target utilization
|
||
|
||
### Output
|
||
|
||
Budget Controller dapat menghasilkan:
|
||
|
||
- budget status
|
||
- forecast cost
|
||
- recommended reward multiplier
|
||
- recommended reward rate
|
||
- warning
|
||
- automatic adjustment
|
||
- stop reward recommendation
|
||
|
||
---
|
||
|
||
## 30. Redemption-Based Forecast
|
||
|
||
Contoh kondisi:
|
||
|
||
| Metric | Nilai |
|
||
| -------------- | ------ |
|
||
| Global Budget | Rp100M |
|
||
| Realized Cost | Rp60M |
|
||
| Remaining | Rp40M |
|
||
| Remaining Days | 10 |
|
||
|
||
Jika current burn rate terlalu tinggi:
|
||
|
||
```text
|
||
Forecast = Rp115M
|
||
```
|
||
|
||
System dapat menghitung adjustment.
|
||
|
||
Contoh:
|
||
|
||
| Item | Nilai |
|
||
| ---------------------- | -------- |
|
||
| Current Reward | 10 Coin |
|
||
| Recommended Multiplier | 0.85x |
|
||
| New Effective Reward | 8.5 Coin |
|
||
|
||
> **Penting:** Rounding rule harus ditentukan agar reward final tidak menghasilkan pecahan Coin jika Coin integer.
|
||
|
||
---
|
||
|
||
## 31. Dynamic Rate Safety
|
||
|
||
Reward rate **tidak boleh** berubah secara liar setiap request.
|
||
|
||
Gunakan:
|
||
|
||
- configuration version
|
||
- `effective_at`
|
||
- cooldown
|
||
- min/max multiplier
|
||
- adjustment step
|
||
- forecast window
|
||
- audit log
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
Current = 10 Coin
|
||
Allowed adjustment step = 10%
|
||
|
||
Next possible: 9 Coin atau 11 Coin
|
||
```
|
||
|
||
❌ Jangan:
|
||
|
||
```text
|
||
10 → 7 → 12 → 5 → 14 (dalam waktu singkat)
|
||
```
|
||
|
||
Tujuannya menjaga **predictability** dan **user trust**.
|
||
|
||
---
|
||
|
||
## 32. Budget Status
|
||
|
||
Recommended:
|
||
|
||
| Status | Arti |
|
||
| ----------- | ------------------------------------- |
|
||
| `HEALTHY` | Budget aman |
|
||
| `WARNING` | Burn rate mulai tinggi |
|
||
| `CRITICAL` | Forecast berpotensi melewati budget |
|
||
| `EXHAUSTED` | Budget sudah mencapai limit |
|
||
|
||
Behavior setiap status harus **configurable**.
|
||
|
||
---
|
||
|
||
## 33. Automatic vs Approval
|
||
|
||
Sistem sebaiknya mendukung dua mode:
|
||
|
||
### `RECOMMENDATION MODE`
|
||
|
||
```text
|
||
System calculates recommendation
|
||
↓
|
||
Admin/Product/Finance approves
|
||
↓
|
||
Publish
|
||
```
|
||
|
||
### `AUTOMATIC MODE`
|
||
|
||
```text
|
||
System calculates
|
||
↓
|
||
Guardrails
|
||
↓
|
||
Auto publish
|
||
```
|
||
|
||
Automatic mode hanya boleh berjalan dengan:
|
||
|
||
- min reward
|
||
- max reward
|
||
- min multiplier
|
||
- max multiplier
|
||
- maximum daily adjustment
|
||
- budget safety threshold
|
||
- audit log
|
||
- rollback capability
|
||
|
||
> **Default recommendation untuk production awal:** `RECOMMENDATION MODE`
|
||
>
|
||
> Setelah economy memiliki data historis yang cukup, automatic mode dapat diaktifkan untuk rule tertentu.
|
||
|
||
---
|
||
|
||
## 34. Budget Exhaustion
|
||
|
||
Jika budget exhausted, system harus memiliki policy.
|
||
|
||
Possible policy:
|
||
|
||
1. Stop rewards
|
||
2. Reduce rewards to minimum
|
||
3. Allow non-budget rewards only
|
||
4. Disable affected event
|
||
5. Continue game but no reward
|
||
|
||
Policy harus **configurable**.
|
||
|
||
Game tetap dapat dimainkan meskipun reward sementara tidak tersedia, kecuali Product menentukan game harus ikut disabled.
|
||
|
||
---
|
||
|
||
## 35. Limits
|
||
|
||
Minimum limit concepts:
|
||
|
||
| Limit | Definisi |
|
||
| -------------------- | ----------------------------------------------------- |
|
||
| **User Daily Limit** | Jumlah Coin maksimal yang dapat diperoleh user per hari |
|
||
| **Game Daily Limit** | Total reward game per hari |
|
||
| **Event Limit** | Reward maksimal dari event |
|
||
| **Global Limit** | Global economy protection |
|
||
| **Session Limit** | Satu session hanya dapat rewarded sekali |
|
||
|
||
Semua limit harus dapat di-**configure**.
|
||
|
||
Jika reward melewati limit, reward **dipotong ke sisa limit** (bukan dibatalkan seluruhnya). Jika sisa limit 0, reward menjadi 0.
|
||
|
||
---
|
||
|
||
## 36. Reporting & Analytics
|
||
|
||
Dashboard minimal:
|
||
|
||
### Game
|
||
|
||
- DAU
|
||
- total plays
|
||
- completed games
|
||
- average score
|
||
- total Coin issued
|
||
- average reward
|
||
- reward per play
|
||
- total Coin spent for entry cost
|
||
- total Coin refunded
|
||
|
||
### Economy
|
||
|
||
- Coin generated
|
||
- Coin spent
|
||
- Coin expired
|
||
- Coin outstanding
|
||
- Point balance
|
||
- Point redeemed
|
||
|
||
### Voucher
|
||
|
||
- redemption count
|
||
- voucher value
|
||
- point spent
|
||
- realized cost
|
||
- stock
|
||
- redemption rate
|
||
|
||
### Budget
|
||
|
||
- total budget
|
||
- realized cost
|
||
- remaining budget
|
||
- utilization
|
||
- forecast
|
||
- burn rate
|
||
|
||
### Event
|
||
|
||
- participants
|
||
- plays
|
||
- Coin issued
|
||
- redemption
|
||
- event cost
|
||
- event performance
|
||
|
||
---
|
||
|
||
## 37. Audit Log
|
||
|
||
Admin changes harus dapat **diaudit**.
|
||
|
||
Minimal audit:
|
||
|
||
- who
|
||
- what
|
||
- before
|
||
- after
|
||
- timestamp
|
||
- reason
|
||
- source
|
||
|
||
Contoh:
|
||
|
||
```text
|
||
Who : Admin A
|
||
Change : Reward 10 Coin → 8 Coin
|
||
Reason : Budget optimization
|
||
Timestamp : 2027-03-10 10:00
|
||
```
|
||
|
||
Audit terutama **wajib** untuk:
|
||
|
||
- reward configuration
|
||
- event configuration
|
||
- budget
|
||
- voucher
|
||
- Point/Coin adjustment
|
||
- automatic controller changes
|
||
|
||
---
|
||
|
||
## 38. Security & Anti-Abuse
|
||
|
||
Minimum protection:
|
||
|
||
- server-side reward calculation
|
||
- session validation
|
||
- idempotency
|
||
- rate limiting
|
||
- duplicate detection
|
||
- suspicious score detection
|
||
- impossible score detection
|
||
- concurrent request protection
|
||
- atomic wallet update
|
||
- atomic redemption
|
||
- audit trail
|
||
|
||
> **Penting:** Jangan mempercayai reward amount dari client.
|
||
|
||
---
|
||
|
||
## 39. Recommended System Architecture
|
||
|
||
```text
|
||
┌──────────────────┐
|
||
│ Next.js Web │
|
||
│ Game Portal │
|
||
└────────┬─────────┘
|
||
│
|
||
▼
|
||
┌──────────────────┐
|
||
│ Go API │
|
||
└────────┬─────────┘
|
||
│
|
||
┌────────────────────┼────────────────────┐
|
||
│ │ │
|
||
▼ ▼ ▼
|
||
Game Management Game Session User/Economy
|
||
│ │ │
|
||
└────────────────────┼────────────────────┘
|
||
▼
|
||
Result Validator
|
||
│
|
||
▼
|
||
Reward Engine
|
||
│
|
||
▼
|
||
Economy Guard
|
||
│
|
||
┌──────┴──────┐
|
||
▼ ▼
|
||
Budget Controller Event
|
||
│ │
|
||
└──────┬──────┘
|
||
▼
|
||
Coin Wallet
|
||
│
|
||
▼
|
||
Coin Ledger
|
||
│
|
||
▼
|
||
Point Layer
|
||
│
|
||
▼
|
||
Voucher Management
|
||
│
|
||
▼
|
||
Redemption Engine
|
||
│
|
||
▼
|
||
Realized Cost
|
||
│
|
||
▼
|
||
Budget Controller
|
||
```
|
||
|
||
---
|
||
|
||
## 40. Recommended Development Order
|
||
|
||
Jangan langsung membuat semua modul sekaligus.
|
||
|
||
### Phase 1 — Business Rules
|
||
|
||
Lock:
|
||
|
||
- Coin
|
||
- Point
|
||
- Voucher
|
||
- Budget
|
||
- Redemption
|
||
- Reward
|
||
- Event
|
||
- Limits
|
||
- Expiration
|
||
|
||
### Phase 2 — Domain & Database
|
||
|
||
Design:
|
||
|
||
- `games`
|
||
- `game_sessions`
|
||
- `reward_configs`
|
||
- `events`
|
||
- `event_reward_configs`
|
||
- `wallets`
|
||
- `coin_transactions`
|
||
- `budgets`
|
||
- `budget_transactions`
|
||
- `vouchers`
|
||
- `voucher_inventory`
|
||
- `redemptions`
|
||
- `audit_logs`
|
||
|
||
Exact schema harus ditentukan setelah business rules final.
|
||
|
||
### Phase 3 — Game Management
|
||
|
||
Build:
|
||
|
||
- Game CRUD
|
||
- Game status
|
||
- Game configuration
|
||
- Game version
|
||
|
||
### Phase 4 — Game Session
|
||
|
||
Build:
|
||
|
||
- create session
|
||
- entry cost debit (Coin) saat create session
|
||
- entry cost refund
|
||
- validate session
|
||
- complete session
|
||
- idempotency
|
||
|
||
### Phase 5 — Reward Engine
|
||
|
||
Build:
|
||
|
||
- fixed reward
|
||
- score based
|
||
- outcome based
|
||
- probability
|
||
- multiplier
|
||
- tiered
|
||
- reward configuration versioning
|
||
|
||
### Phase 6 — Coin Economy
|
||
|
||
Build:
|
||
|
||
- wallet
|
||
- ledger
|
||
- earning
|
||
- expiration integration
|
||
- adjustment
|
||
- transaction history
|
||
|
||
### Phase 7 — Voucher Management
|
||
|
||
Build:
|
||
|
||
- voucher CRUD
|
||
- voucher type
|
||
- voucher value
|
||
- point cost
|
||
- stock
|
||
- code pool
|
||
- expiration
|
||
- status
|
||
|
||
### Phase 8 — Redemption
|
||
|
||
Build:
|
||
|
||
- voucher reservation
|
||
- Point deduction
|
||
- voucher issue
|
||
- rollback
|
||
- idempotency
|
||
- realized cost
|
||
|
||
### Phase 9 — Event Management
|
||
|
||
Build:
|
||
|
||
- event CRUD
|
||
- participating games
|
||
- reward modifiers
|
||
- missions
|
||
- event limits
|
||
- event leaderboard
|
||
|
||
### Phase 10 — Budget Controller
|
||
|
||
Build:
|
||
|
||
- budget pool
|
||
- realized cost tracking
|
||
- burn rate
|
||
- forecast
|
||
- recommendation
|
||
- automatic mode
|
||
- guardrails
|
||
|
||
### Phase 11 — Analytics
|
||
|
||
Build:
|
||
|
||
- game analytics
|
||
- economy analytics
|
||
- voucher analytics
|
||
- budget dashboard
|
||
- event analytics
|
||
|
||
### Phase 12 — Phaser Integration
|
||
|
||
Integrate real games with:
|
||
|
||
- game session
|
||
- result submission
|
||
- reward result
|
||
- leaderboard
|
||
- missions
|
||
|
||
---
|
||
|
||
## 41. Important Implementation Rules for Claude Code
|
||
|
||
Claude Code **must** follow these principles:
|
||
|
||
1. Do not invent business rules that are not defined.
|
||
2. Do not let Phaser/client determine reward amount.
|
||
3. Do not mutate historical reward configuration that has already been used in transactions.
|
||
4. Every reward completion must be idempotent.
|
||
5. Every wallet mutation must have a ledger record.
|
||
6. Voucher redemption must be atomic/recoverable.
|
||
7. Budget actual cost is based on successful voucher redemption, according to the current business rule.
|
||
8. All games use the same global/shared budget pool.
|
||
9. Normal reward and event reward can be active simultaneously.
|
||
10. Event configuration must not permanently mutate normal game reward configuration.
|
||
11. Automatic reward adjustment must have guardrails.
|
||
12. All important admin/economy changes must be auditable.
|
||
13. Use database transactions for wallet, redemption, and other financial/economic mutations.
|
||
14. Avoid premature microservices. Start with a modular Go backend unless scale requires otherwise.
|
||
15. Prefer clear domain boundaries inside the existing backend.
|
||
16. Entry cost is debited in Coin when the session is created, in the same transaction as the session.
|
||
17. Entry cost and its refund never offset the budget; budget only counts reward and realized voucher cost.
|
||
18. Point can only be redeemed for vouchers. It must never be usable as payment or cashed out.
|
||
|
||
---
|
||
|
||
## 42. Current Decisions
|
||
|
||
These decisions are **confirmed for v1**:
|
||
|
||
| Decision | Rule |
|
||
| ----------------------- | -------------------------------- |
|
||
| Backend | Go |
|
||
| Database | PostgreSQL |
|
||
| Game engine | Phaser |
|
||
| Temporary session | Redis optional |
|
||
| Coin | Virtual game currency |
|
||
| Point | Redemption currency |
|
||
| Coin : Point | 1 : 1 |
|
||
| Coin : Rupiah | 1 Coin = Rp1 (nilai acuan, bukan cash out) |
|
||
| Point usage | Voucher redemption only |
|
||
| Point as payment | Not allowed |
|
||
| Point cash out | Not allowed |
|
||
| Game entry cost | Paid in Coin |
|
||
| Entry cost debit | At session creation (Start Game) |
|
||
| Entry cost refund | Automatic, idempotent; only for system error / game deactivated mid-session |
|
||
| Abandoned/expired session | No refund |
|
||
| Entry cost vs budget | Not counted; budget = reward only |
|
||
| Coin expiration | Existing system |
|
||
| Point expiration | Existing system |
|
||
| Coin → Point | Existing exchange (manual, configurable rate) |
|
||
| Budget model | Shared/global pool |
|
||
| Budget period | Monthly (default), configurable |
|
||
| Event = Campaign | Same concept |
|
||
| Budget counts | Only Point originating from EnakGame rewards |
|
||
| Budget actual cost | Successful voucher redemption |
|
||
| Realized cost basis | Voucher face value |
|
||
| Voucher source | Internal codes + external API |
|
||
| Free game | Not allowed (entry cost ≥ 1 Coin) |
|
||
| Event budget | Own budget per event, separate from global; funds the event's extra reward |
|
||
| Over limit | Reward capped to remaining limit |
|
||
| Game reward Coin transfer | Allowed |
|
||
| Voucher redemption PIN | Required |
|
||
| Legacy games (spin, ferris wheel) | Removed; spin rebuilt as EnakGame game |
|
||
| Game budget | Shared pool, not isolated per game |
|
||
| Normal + Event reward | Can run together |
|
||
| Reward authority | Backend |
|
||
| Reward idempotency | Required |
|
||
| Wallet | Required |
|
||
| Ledger | Required |
|
||
| Voucher Management | Core module |
|
||
| Redemption | Atomic/idempotent |
|
||
| Budget Controller | Required |
|
||
| Dynamic reward | Supported |
|
||
| Auto adjustment | Supported with guardrails |
|
||
| Default adjustment mode | Recommendation/approval |
|
||
| Event | Layer over normal game reward |
|
||
| Historical configs | Must be versioned |
|
||
| Audit | Required |
|
||
|
||
---
|
||
|
||
## 43. Open Decisions Before Database Design
|
||
|
||
The following should remain **explicitly unresolved** until Product/Finance decides them:
|
||
|
||
1. **Reward rounding**
|
||
- integer Coin only
|
||
- allow fractional internal calculation but round final reward
|
||
2. **Event stacking**
|
||
- priority only
|
||
- controlled stacking
|
||
- maximum multiplier
|
||
3. **Budget exhaustion policy** (global dan event)
|
||
4. **Automatic Budget Controller thresholds**
|
||
5. **Voucher reservation timeout**
|
||
|
||
Sudah diputuskan (lihat [Section 42](#42-current-decisions)): budget period, event/campaign budget, budget attribution, redemption cost model, Coin → Point conversion, Point expiration, voucher provider, free game, entry cost refund conditions.
|
||
|
||
These decisions should be finalized before production schema/API is considered final.
|
||
|
||
---
|
||
|
||
## 44. Definition of Done for Economy v1
|
||
|
||
Economy v1 is considered technically ready when:
|
||
|
||
- [ ] Game session cannot be rewarded twice.
|
||
- [ ] Entry cost is debited exactly once per session, atomically with session creation.
|
||
- [ ] Session cannot start when Coin balance is insufficient.
|
||
- [ ] Entry cost refund is idempotent, and a session cannot be both refunded and rewarded.
|
||
- [ ] Sessions failed by system error or game deactivation are refunded automatically; abandoned/expired sessions are not.
|
||
- [ ] Entry cost does not affect budget calculation.
|
||
- [ ] Point cannot be used as payment or cashed out.
|
||
- [ ] Client cannot directly choose reward amount.
|
||
- [ ] Reward configuration is versioned.
|
||
- [ ] Reward Engine calculates reward correctly.
|
||
- [ ] Economy Guard enforces limits.
|
||
- [ ] Wallet balance is consistent with ledger.
|
||
- [ ] Coin expiration is correctly represented.
|
||
- [ ] Voucher stock cannot go negative.
|
||
- [ ] Redemption is atomic.
|
||
- [ ] Redemption is idempotent.
|
||
- [ ] Successful redemption records realized cost.
|
||
- [ ] Budget Controller can calculate current utilization.
|
||
- [ ] Budget Controller can forecast future cost.
|
||
- [ ] Reward adjustment has guardrails.
|
||
- [ ] Event reward does not corrupt normal reward configuration.
|
||
- [ ] Admin changes are auditable.
|
||
- [ ] Finance can reconcile voucher cost against redemption records.
|
||
|
||
---
|
||
|
||
## 45. Guiding Principle
|
||
|
||
| Component | Responsibility |
|
||
| ---------------------- | ------------------------------------ |
|
||
| **Product/Finance** | Defines the budget |
|
||
| **Game Management** | Defines the game |
|
||
| **Reward Engine** | Calculates the reward |
|
||
| **Economy Guard** | Protects the economy |
|
||
| **Budget Controller** | Protects the budget |
|
||
| **Voucher Management** | Defines what users can redeem |
|
||
| **Redemption** | Records the actual business cost |
|
||
| **Ledger** | Provides the audit trail |
|
||
|
||
The goal is not simply to build a collection of games.
|