# irohbet API Contract v1

Backend ve Frontend'in UYMAK ZORUNDA olduğu tek sözleşme. Değişiklik yapmadan önce bu
dosyayı güncelle.

## Genel kurallar
- Base URL (dev): `http://localhost:3000/api`
- Tüm yanıtlar JSON. Başarı: `{ ok: true, data: ... }`. Hata: `{ ok: false, error: "msg" }` (HTTP 4xx/5xx).
- Para her yerde **cents** (integer) cinsinden. Frontend ₺ görüntülerken /100 yapar.
- Auth: `Authorization: Bearer <token>`. `GET /api/auth/me` ile token doğrulanır.
- Zorunlu auth isteklerinde geçersiz token → 401 `{ ok:false, error:"unauthorized" }`.

## Kimlik
- `POST /api/auth/register` {email, username, password} → data: {token, user}
  - email & username benzersiz olmalı (çakışma → 409)
  - şifre min 8 karakter
- `POST /api/auth/login` {email, password} → data: {token, user}
- `GET /api/auth/me` (auth) → data: user (aşağıdaki PublicUser şekli)
- `PUT /api/auth/me` (auth) {username?} → data: user
- `POST /api/auth/change-password` (auth) {currentPassword, newPassword} → {ok:true}
- `POST /api/auth/logout` (auth) → {ok:true}

### PublicUser (her yerde aynı şekil)
```
{
  id, email, username,
  nation: "WATER"|"EARTH"|"FIRE"|"AIR"|null,
  isAvatar, avatarAt, points, status,
  createdAt, lastLoginAt, loginStreak,
  wallet: { balanceCents, lockedCents, totalDepositCents, totalWithdrawCents } | null,
  badgeCount, // int
  avatarProgress // 0..100 tüm rozetlerin yüzdesi
}
```

## Ulus (nations)
- `POST /api/nations/select` (auth) {nation} → data: user (nation set edilir; null ise hata)
  - Ulus DEĞİŞTİRİLEMEZ bir kez seçildikten sonra → seçili ise 409
- `GET /api/nations` → data: { nations: [NationInfo...], badges: [Badge...], my: {nation, earned: [badgeCode...], avatarProgress, isAvatar} | null }
  - auth opsiyonel: token yoksa my:null
- NationInfo: { id:"WATER", name:"Su Ulusu", subtitle, color, icon, description }
- Badge: { id, code, nation, tier, title, description, icon, metric, target, hidden }

## Cüzdan
- `GET /api/wallet` (auth) → data: { balanceCents, lockedCents, totalDepositCents, totalWithdrawCents }
- `POST /api/wallet/deposit` (auth) {amountCents} → data: { balanceCents, tx }
  - DEMO: gerçek para modelinde ödeme sağlayıcı çağrısı burada olacak. Şimdilik bakiye arttırılır.
  - amountCents >= 100 olmalı
- `POST /api/wallet/withdraw` (auth) {amountCents, method, account} → data: { request, balanceCents }
  - PENDING çekim oluşturur, tutar lockedCents'e eklenir.
- `GET /api/wallet/transactions` (auth) ?limit&offset → data: { items: [Tx...] }
  - Tx: { id, type, amountCents, balanceAfterCents, status, createdAt, meta }
- `GET /api/wallet/withdrawals` (auth) → data: { items: [WithdrawalRequest...] }

## Oyunlar
- `GET /api/games` → data: { games: [GameInfo...] } (katalog, login gerektirmez)
  - GameInfo: { slug, title, subtitle, icon, category, minBet, maxBet, popular, color, tagline }
  - slug'lar: SLOTS, BLACKJACK, ROULETTE, BACCARAT, CRASH
- `GET /api/games/:slug` → data: { game }
- **Oyun oynama akışı (tüm oyunlar):**
  - `POST /api/games/blackjack/start` (auth) {betCents} → data: { roundId, hand:{...} } — bahis cüzdandan DÜŞER (GAME_BET tx), BLACKJACK'te server kartları üretir.
  - `POST /api/games/blackjack/hit` (auth) {roundId} → data: { hand } — 21'i geçerse auto-stand sonucu döner
  - `POST /api/games/blackjack/stand` (auth) {roundId} → data: { result } — dealer oynar, ödül verilir
  - `POST /api/games/blackjack/double` (auth) {roundId} → data: { result }
  - `POST /api/games/roulette/spin` (auth) {betCents, betType, betValue} → data: { result:{ number, color, payoutMultiplier, resultCents }, winCents, balanceCents }
    - betType: "straight"|"red"|"black"|"odd"|"even"|"high"|"low" (betValue straight için sayı)
  - `POST /api/games/slots/spin` (auth) {betCents} → data: { result:{ reels:[...3x3], lines:[...], winCents, multiplier }, balanceCents }
  - `POST /api/games/baccarat/play` (auth) {betCents, betOn:"player"|"banker"|"tie"} → data: { result:{ playerCards, bankerCards, playerScore, bankerScore, winner, payoutMultiplier, resultCents }, balanceCents }
  - `POST /api/games/crash/start` (auth) {betCents} → data: { roundId, hash } — bahis düşer, multiplier yükselir
  - `POST /api/games/crash/cashout` (auth) {roundId, multiplier} → data: { resultCents, balanceCents } — Payout hesaplanır (multiplier < crashPoint ise kazanır)
  - `POST /api/games/crash/end` (auth) {roundId, crashPoint} → data: { resultCents, balanceCents } — crash noktasına ulaşınca client çağırır (kayıp)
  - Tüm oyun sonuçları: cüzdan güncellenir, GAME_WIN tx (kazanç varsa), GameRound kaydı, UserProgress metric güncellemesi, socket `balance` event'i.
- `GET /api/games/history` (auth) ?limit → data: { items: [GameRound...] }
- Bahis kuralı: betCents < minBet veya balance üzeri → 400. locked varsa kullanılamaz.
- Yanıtlarda daima `balanceCents` dön (client header'da güncel bakiye göstersin).

### GameRound (history şekli)
```
{ id, game, betCents, resultCents, status, createdAt, state }
```

## Liderlik
- `GET /api/leaderboard` ?period=week|month|all → data: { items: [{ rank, username, nation, points, isAvatar, isMe }] }
  - week: son 7 gün, month: son 30 gün, all: tüm zamanlar (points'e göre)
  - isMe: o anki kullanıcı (token varsa)

## Admin (auth + admin rolü)
Admin token nasıl doğrulanır: admin girişi ayrı: `POST /api/auth/admin-login` {username, password} → data: { token }
- Admin ile ilgili tüm rotalar `Authorization: Bearer <adminToken>` ister ve `requireAdmin` middleware'den geçer.
- `GET /api/admin/stats` → data: { users, activeUsers, totalBalanceCents, totalDepositsCents, totalWithdrawalsCents, rounds, pendingWithdrawals }
- `GET /api/admin/users` ?search&page → data: { items: [...], total }
- `PATCH /api/admin/users/:id` {status?|nation?|points?} → data: user
- `GET /api/admin/transactions` ?page → data: { items, total }
- `GET /api/admin/withdrawals` → data: { items }
- `PATCH /api/admin/withdrawals/:id` {status:"APPROVED"|"REJECTED"} → data: item
  - APPROVED: lockedCents'ten düş, totalWithdrawCents'e ekle, PENDING tx COMPLETED.
  - REJECTED: lockedCents'i geri balance'a ekle.
- `GET /api/admin/badges` → data: { items }
- `POST /api/admin/badges` {code,nation,tier,title,description,icon,metric,target} → data: badge
- `PATCH /api/admin/badges/:id` {…} → data: badge
- `DELETE /api/admin/badges/:id` → {ok:true}
- `GET /api/admin/settings` → data: { items: [{key,value}] }
- `PUT /api/admin/settings/:key` {value} → data: item

## Socket.io
- Namespace `/` default. Event'ler:
  - client → server: `auth` {token}
  - server → client: `balance` { balanceCents, lockedCents }
  - server → client: `badge` { badge, userBadge } (yeni rozet kazanılınca)
  - server → client: `avatar` { user } (Avatar statüsüne ulaşınca)
  - client → server: `joinRoom` { room }, `leaveRoom` { room }
  - server → client: `roomUpdate` { room, data } (liderlik canlı güncellemesi vb.)

## Rozet metriği (UserProgress) kullanılan key'ler
- `games_played` : oynanan toplam oyun (her round +1)
- `games_won` : kazanılan round (resultCents > betCents)
- `total_bet_cents` : toplam bahis
- `total_win_cents` : toplam kazanç
- `login_days` : toplam giriş yapılan gün sayısı
- `deposits_count` : yatırma işlemi sayısı
- `profit_cents` : net kazanç (win - bet)
- `max_single_win_cents` : tek oyunda en büyük kazanç
- `rounds_slots`,`rounds_blackjack`,`rounds_roulette`,`rounds_baccarat`,`rounds_crash` : oyun bazlı oynama sayısı

Badge tanımları seed'de. `metric` + `target` üzerinden ilerleme hesaplanır
(UserProgress.value >= target → rozet kazanılır).
