first (part 2: other directories)
Deploy Iddaai Backend / build-and-deploy (push) Failing after 18s

This commit is contained in:
2026-04-16 15:11:25 +03:00
parent 7814e0bc6b
commit 2f0b85a0c7
203 changed files with 59989 additions and 0 deletions
+594
View File
@@ -0,0 +1,594 @@
# Suggest-Bet-BE — Veritabanı Şemas ve Proje Tam Referansı
> **Tarih:** 2026-03-13
> Google Gemini 3.1 Pro Deep Think ile çözüm üretimi için hazırlanmış kapsamlı referans dokümanıdır.
---
## 1. Proje Özeti
**Suggest-Bet-BE**, yapay zeka destekli bir spor bahis tahmin ve analiz platformu backend servisidir.
| Katman | Teknoloji | Port |
|--------|-----------|------|
| **Backend API** | NestJS 11 (TypeScript) | `3005` |
| **AI Engine** | Python FastAPI, XGBoost, LightGBM Ensemble | `8000` |
| **Veritabanı** | PostgreSQL 16 + Prisma ORM | `5432` |
| **Kuyruk/Cache** | BullMQ + Redis (opsiyonel) | `6379` |
| **Auth** | JWT + Passport (Access 15dk + Refresh 7gün) | — |
| **Scraping** | Axios + Cheerio (Mackolik.com) | — |
| **AI** | Google Gemini API (yorum üretimi) | — |
**Temel Akış:**
1. Mackolik API'den canlı maç verisi çekilir (15dk cron)
2. Kullanıcı maç seçer → AI Engine'e gönderilir
3. V20+ model çoklu market tahmin paketi üretir (MS, OU, BTTS, DC, HT/FT)
4. İsteğe bağlı akıllı kupon önerilir (5 strateji: SAFE, BALANCED, AGGRESSIVE, VALUE, MIRACLE)
---
## 2. Veritabanı Şeması (PostgreSQL — 27 Tablo, 6 Enum)
### 2.1 Enum Tanımları
```sql
-- Spor türleri
enum Sport { football, basketball }
-- Kullanıcı rolleri
enum UserRole { user, superadmin }
-- Abonelik durumu
enum SubscriptionStatus { free, active, expired }
-- Oyuncu pozisyonları (futbol)
enum PlayerPosition { goalkeeper, defender, midfielder, striker }
-- Maç olayı türleri
enum EventType { goal, card, substitute }
-- Maç pozisyonu (ev sahibi/deplasman)
enum MatchPosition { home, away }
```
### 2.2 Tablo Detayları
---
#### `countries` — Ülkeler (160 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `String` PK | Mackolik ülke ID |
| `name` | `String` UNIQUE | Ülke adı |
| `flag_url` | `String?` | Bayrak görseli URL |
| `created_at` | `DateTime` | — |
**İlişkiler:**`leagues[]`
---
#### `leagues` — Ligler (1,505 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `String` PK | Mackolik lig ID |
| `name` | `String` | Lig adı |
| `country_id` | `String?` FK → countries | Ülke |
| `sport` | `Sport` | football / basketball |
| `competition_slug` | `String?` | URL slug |
| `code` | `String?` | Kısa kod |
| `logo_url` | `String?` | Logo URL |
| `created_at` | `DateTime` | — |
**Unique:** `(name, country_id, sport)`
**İndeksler:** `sport`, `country_id`
**İlişkiler:**`matches[]`, `live_matches[]`
---
#### `teams` — Takımlar (19,595 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `String` PK | Mackolik takım ID |
| `name` | `String` | Takım adı |
| `slug` | `String?` | URL slug |
| `sport` | `Sport` | football / basketball |
| `logo_url` | `String?` | Logo URL. CDN: `https://file.mackolikfeeds.com/teams/{id}` |
| `created_at` | `DateTime` | — |
**İndeksler:** `sport`, `name`
**İlişkiler:** → home/away matches, participations, events, stats
---
#### `players` — Oyuncular (217,040 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `String` PK | Mackolik oyuncu ID |
| `name` | `String` | Oyuncu adı |
| `slug` | `String?` UNIQUE | URL slug |
| `created_at` | `DateTime` | — |
**İndeksler:** `name`
**İlişkiler:** → participations, events (scorer, assist, out), stats
---
#### `matches` — Kalıcı Maç Kayıtları (236,859 kayıt, 100 MB)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `String` PK | Mackolik maç ID |
| `league_id` | `String?` FK → leagues | Lig |
| `home_team_id` | `String?` FK → teams | Ev sahibi |
| `away_team_id` | `String?` FK → teams | Deplasman |
| `sport` | `Sport` | football / basketball |
| `match_name` | `String?` | "Galatasaray vs Fenerbahçe" |
| `match_slug` | `String?` | URL slug |
| `mst_utc` | `BigInt` | Maç zamanı (Unix ms) |
| `status` | `String?` | Durum |
| `state` | `String?` | postGame, preGame, live, etc. |
| `score_home` | `Int?` | Ev sahibi skor |
| `score_away` | `Int?` | Deplasman skor |
| `ht_score_home` | `Int?` | İlk yarı ev sahibi skor |
| `ht_score_away` | `Int?` | İlk yarı deplasman skor |
| `winner` | `String?` | Kazanan |
| `iddaa_code` | `String?` | İddaa maç kodu |
| `created_at` | `DateTime` | — |
| `updated_at` | `DateTime` | — |
**İndeksler:** `mst_utc DESC`, `sport`, `state`, `league_id`, `home_team_id`, `away_team_id`, `iddaa_code`
**İlişkiler:** → oddCategories, teamStats, playerParticipations, playerEvents, playerStats, officials, prediction, aiFeatures, couponItems
---
#### `live_matches` — Canlı/Yaklaşan Maçlar (82 kayıt, döngüsel)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `String` PK | Mackolik maç ID |
| `league_id` | `String?` FK → leagues | Lig |
| `home_team_id` | `String?` FK → teams | Ev sahibi |
| `away_team_id` | `String?` FK → teams | Deplasman |
| `sport` | `String?` | football / basketball |
| `match_name` | `String?` | Maç adı |
| `match_slug` | `String?` | URL slug |
| `mst_utc` | `BigInt?` | Maç zamanı (Unix ms) |
| `status` | `String?` | Durum |
| `state` | `String?` | pre, live, post |
| `substate` | `String?` | Alt durum |
| `score_home` | `Int?` | Ev sahibi skor |
| `score_away` | `Int?` | Deplasman skor |
| `updated_at` | `DateTime` | Son güncelleme |
| **`odds`** | **`Json?`** | **Tüm bahis oranları (JSON blob)** |
| `odds_updated_at` | `DateTime?` | Oran güncelleme zamanı |
| `referee_name` | `String?` | Hakem adı |
| **`lineups`** | **`Json?`** | **Kadro (JSON blob, home/away dizileri)** |
| **`sidelined`** | **`Json?`** | **Sakatlar/Cezalılar (JSON blob)** |
**İndeksler:** `mst_utc`, `state`
**Not:** Maç bitince `live_matches``matches` tablosuna migrate edilir (30dk cron).
---
#### `odd_categories` — Bahis Kategorileri (3,161,172 kayıt, 689 MB)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `db_id` | `Int` PK autoincrement | — |
| `match_id` | `String` FK → matches | Maç |
| `category_json_id` | `Int?` | Mackolik kategori ID |
| `name` | `String?` | "Maç Sonucu", "2,5 Alt/Üst", "Karşılıklı Gol" vb. |
| `created_at` | `DateTime` | — |
**Unique:** `(match_id, name)`
**İndeksler:** `match_id`
---
#### `odd_selections` — Bahis Seçimleri ve Oranları (8,511,132 kayıt, 1 GB)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `db_id` | `Int` PK autoincrement | — |
| `odd_category_db_id` | `Int` FK → odd_categories | Kategori |
| `name` | `String?` | "1", "X", "2", "Alt", "Üst", "1-X", vb. |
| `odd_value` | `String?` | Oran değeri ("1.85", "3.04") |
| `position` | `String?` | Sıralama pozisyonu |
| `sov` | `Float?` | — |
| `state` | `String?` | — |
| `created_at` | `DateTime` | — |
| `updated_at` | `DateTime` | — |
**Unique:** `(odd_category_db_id, name)`
**İndeksler:** `odd_category_db_id`
---
#### `odds_history` — Oran Değişim Geçmişi (0 kayıt, henüz aktif değil)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `BigInt` PK autoincrement | — |
| `selection_id` | `Int` FK → odd_selections | Seçim |
| `match_id` | `String` | Maç ID |
| `previous_value` | `Float` | Önceki oran |
| `new_value` | `Float` | Yeni oran |
| `bookmaker` | `String?` default "MACKOLIK" | — |
| `change_time` | `DateTime` | Değişim zamanı |
**İndeksler:** `(match_id, change_time)`, `selection_id`
---
#### `match_team_stats` — Takım İstatistikleri (310,991 kayıt, 91 MB)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `Int` PK autoincrement | — |
| `match_id` | `String` FK → matches | Maç |
| `team_id` | `String` FK → teams | Takım |
| **Futbol Alanları:** | | |
| `possession_percentage` | `Float?` | Topla oynama % |
| `shots_on_target` | `Int?` | İsabetli şut |
| `shots_off_target` | `Int?` | İsabetsiz şut |
| `total_shots` | `Int?` | Toplam şut |
| `total_passes` | `Int?` | Toplam pas |
| `corners` | `Int?` | Korner |
| `fouls` | `Int?` | Faul |
| `offsides` | `Int?` | Ofsayt |
| **Basketbol Alanları:** | | |
| `points` | `Int?` | Toplam sayı |
| `rebounds` | `Int?` | Ribaund |
| `assists` | `Int?` | Asist |
| `fg_made` / `fg_attempted` | `Int?` | Field goal |
| `three_pt_made` / `three_pt_attempted` | `Int?` | 3 sayı |
| `ft_made` / `ft_attempted` | `Int?` | Serbest atış |
| `steals` | `Int?` | Top çalma |
| `blocks` | `Int?` | Blok |
| `turnovers` | `Int?` | Top kaybı |
| `q1_score` ... `q4_score`, `ot_score` | `Int?` | Periyot skorları |
**Unique:** `(match_id, team_id)`
---
#### `match_player_participation` — Oyuncu Kadro Katılımları (3,342,839 kayıt, 1 GB)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `Int` PK autoincrement | — |
| `match_id` | `String` FK → matches | Maç |
| `player_id` | `String` FK → players | Oyuncu |
| `team_id` | `String` FK → teams | Takım |
| `position` | `PlayerPosition?` | goalkeeper, defender, midfielder, striker |
| `shirt_number` | `Int?` | Forma numarası |
| `is_starting` | `Boolean` default true | İlk 11'de mi? |
| `created_at` | `DateTime` | — |
**Unique:** `(match_id, player_id, team_id)`
---
#### `match_player_events` — Maç Olayları (1,453,227 kayıt, 356 MB)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `Int` PK autoincrement | — |
| `match_id` | `String` FK → matches | Maç |
| `player_id` | `String` FK → players | Olay yapan oyuncu |
| `team_id` | `String` FK → teams | Takım |
| `event_type` | `EventType` | goal, card, substitute |
| `event_subtype` | `String?` | "yellow", "red", "penalty", vb. |
| `time_minute` | `String` | Dakika ("45+2") |
| `time_seconds` | `Int?` | Saniye |
| `period_id` | `Int?` | Periyot |
| `assist_player_id` | `String?` FK → players | Asist yapan oyuncu |
| `score_after` | `String?` | Olay sonrası skor ("1-0") |
| `player_out_id` | `String?` FK → players | Çıkan oyuncu (değişiklik için) |
| `position` | `MatchPosition?` | home / away |
**İndeksler:** `match_id`, `player_id`, `team_id`, `event_type`, `assist_player_id`
**Dağılım:** substitute: 787K, card: 409K, goal: 257K
---
#### `match_player_stats` — Oyuncu İstatistikleri (344,688 kayıt, basketbol odaklı)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `Int` PK autoincrement | — |
| `match_id` | `String` FK → matches | Maç |
| `player_id` | `String` FK → players | Oyuncu |
| `team_id` | `String` FK → teams | Takım |
| `minutes` | `String?` | Oynanan süre |
| `points`, `rebounds`, `assists` | `Int?` | Temel istatistikler |
| `steals`, `blocks`, `turnovers`, `fouls` | `Int?` | Detay istatistikler |
| `fg_made/attempted`, `three_pt_made/attempted`, `ft_made/attempted` | `Int?` | Şut istatistikleri |
**Unique:** `(match_id, player_id, team_id)`
---
#### `match_officials` — Hakem Bilgileri (340,824 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `Int` PK autoincrement | — |
| `match_id` | `String` FK → matches | Maç |
| `name` | `String` | Hakem adı |
| `role_id` | `Int` FK → official_roles | Hakem rolü |
**Unique:** `(match_id, name, role_id)`
---
#### `official_roles` — Hakem Rolleri (5 kayıt)
| id | Rol |
|----|-----|
| 1 | Orta Hakem |
| 2 | Yardımcı Hakem |
| 3 | 4. Hakem |
| 4 | VAR |
| 5 | AVAR |
---
#### `match_ai_features` — AI Feature Cache (279 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `match_id` | `String` PK FK → matches | Maç |
| `home_elo` | `Float` default 1500 | Ev sahibi ELO |
| `away_elo` | `Float` default 1500 | Deplasman ELO |
| `home_form_score` | `Float` default 50 | Ev sahibi form skoru |
| `away_form_score` | `Float` default 50 | Deplasman form skoru |
| `missing_players_impact` | `Float` default 0 | Eksik oyuncu etkisi |
| `calculator_ver` | `String` default "v1.0" | Hesaplama versiyonu |
| `updated_at` | `DateTime` | — |
---
#### `predictions` — AI Tahmin Cache (3 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `match_id` | `String` PK FK → matches | Maç |
| `prediction_json` | `Json` | Tam tahmin paketi (SingleMatchPredictionPackage) |
| `created_at` | `DateTime` | — |
| `updated_at` | `DateTime` | TTL: 6 saat |
---
#### `ai_predictions_log` — AI Tahmin Loglama (0 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `Int` PK autoincrement | — |
| `match_id` | `String` | Maç ID |
| `model_version` | `String` | "v20plus.X" |
| `recommended_bets` | `Json?` | Önerilen bahisler |
| `confidence_score` | `Float?` | Güven skoru |
| `is_resolved` | `Boolean` default false | Sonuçlandı mı? |
| `actual_result` | `String?` | Gerçek sonuç |
| `is_correct` | `Boolean?` | Doğru mu? |
| `accuracy_score` | `Float?` | Doğruluk puanı |
---
#### `users` — Kullanıcılar (1 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `UUID` PK | — |
| `email` | `String` UNIQUE | — |
| `password_hash` | `String` | bcrypt (12 rounds) |
| `first_name` | `String?` | — |
| `last_name` | `String?` | — |
| `role` | `UserRole` default user | user / superadmin |
| `subscription_status` | `SubscriptionStatus` default free | free / active / expired |
| `subscription_expires_at` | `DateTime?` | — |
| `encrypted_api_key` | `String?` | — |
| `is_active` | `Boolean` default true | — |
| `deleted_at` | `DateTime?` | Soft delete |
**Limitler:** Free: 10 analiz + 3 kupon/gün, Active: 50 analiz + 10 kupon/gün
---
#### `user_coupons` — Kullanıcı Kuponları (0 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `UUID` PK | — |
| `user_id` | `String` FK → users | Kullanıcı |
| `strategy` | `String` | SAFE, BALANCED, AGGRESSIVE, VALUE, MIRACLE |
| `total_odds` | `Float` | Toplam oran |
| `status` | `String` default "PENDING" | PENDING, WON, LOST |
| `is_public` | `Boolean` default false | Herkes görebilir mi? |
---
#### `user_coupon_items` — Kupon Bahisleri (0 kayıt)
| Kolon | Tip | Açıklama |
|-------|-----|----------|
| `id` | `Int` PK autoincrement | — |
| `coupon_id` | `String` FK → user_coupons | Kupon |
| `match_id` | `String` FK → matches | Maç |
| `selection` | `String` | "MS 1", "2.5 Üst", "KG Var" vb. |
| `odd_at_time` | `Float` | Kayıt anındaki oran |
| `is_correct` | `Boolean?` | Sonuç |
---
#### `usage_limits`, `analyses`, `refresh_tokens`, `app_settings`, `translations`
Bu tablolar standart destek tablolarıdır (kullanım limiti, analiz geçmişi, JWT refresh token, key-value ayarlar, çeviri verileri).
---
## 3. İlişki Diyagramı (ER)
```
Country 1──N League 1──N Match N──1 Team (home/away)
├──N OddCategory 1──N OddSelection 1──N OddsHistory
├──N MatchTeamStats N──1 Team
├──N MatchPlayerParticipation N──1 Player, N──1 Team
├──N MatchPlayerEvents N──1 Player (scorer, assist, out), N──1 Team
├──N MatchPlayerStats N──1 Player, N──1 Team
├──N MatchOfficial N──1 OfficialRole
├──1 MatchAiFeature
└──1 Prediction
User 1──N Analysis
User 1──N UserCoupon 1──N UserCouponItem N──1 Match
User 1──1 UsageLimit
User 1──N RefreshToken
League 1──N LiveMatch N──1 Team (home/away)
```
---
## 4. Canlı Veritabanı İstatistikleri (2026-03-12)
| Tablo | Kayıt | Boyut |
|-------|-------|-------|
| `odd_selections` | 8,511,132 | 1,070 MB |
| `match_player_participation` | 3,342,839 | 1,077 MB |
| `odd_categories` | 3,161,172 | 689 MB |
| `match_player_events` | 1,453,227 | 356 MB |
| `match_player_stats` | 344,688 | 120 MB |
| `match_officials` | 340,824 | 75 MB |
| `match_team_stats` | 310,991 | 91 MB |
| `matches` | 236,859 | 100 MB |
| `players` | 217,040 | 64 MB |
| `teams` | 19,595 | 5.2 MB |
| `leagues` | 1,505 | 760 KB |
| **Toplam DB** | — | **3,658 MB** |
### Spor Dağılımı
| Spor | Maç | Lig | Ort. Ev Skor | Ort. Dep. Skor |
|------|-----|-----|-------------|---------------|
| Futbol | 189,291 | 1,094 | 1.55 | 1.27 |
| Basketbol | 47,568 | 304 | 84.36 | 81.57 |
---
## 5. AI Engine V20+ Tahmin Çıktısı (SingleMatchPredictionPackage)
```json
{
"model_version": "v20plus.X",
"match_info": { "match_id", "match_name", "home_team", "away_team", "league", "match_date_ms" },
"data_quality": { "label": "HIGH|MEDIUM|LOW", "score": 0-1, "flags": [], "home_lineup_count", "away_lineup_count" },
"risk": { "level": "LOW|MEDIUM|HIGH|EXTREME", "score", "is_surprise_risk", "surprise_type", "warnings" },
"engine_breakdown": { "team", "player", "odds", "referee" },
"main_pick": { "market", "pick", "probability", "confidence", "odds", "raw_confidence", "calibrated_confidence", "min_required_confidence", "edge", "play_score", "playable", "bet_grade": "A|B|C|PASS", "stake_units", "decision_reasons" },
"value_pick": { same as main_pick, odds >= 1.60 },
"bet_advice": { "playable", "suggested_stake_units", "reason" },
"bet_summary": [{ "market", "pick", "raw_confidence", "calibrated_confidence", "bet_grade", "playable", "stake_units", "play_score", "reasons" }],
"supporting_picks": [pick objects],
"aggressive_pick": { "market", "pick", "probability", "confidence", "odds" },
"scenario_top5": [{ "score", "prob" }],
"score_prediction": { "ft", "ht", "xg_home", "xg_away", "xg_total" },
"market_board": { "MS": {pick, confidence, probs}, "DC", "OU15", "OU25", "OU35", "BTTS", "HT", "HTFT": {probs: {"1/1": n, ...}} },
"reasoning_factors": ["..."]
}
```
---
## 6. API Endpointleri (50 Toplam)
### Auth (4) — Public
- `POST /api/auth/register` — Kayıt ol
- `POST /api/auth/login` — Giriş yap
- `POST /api/auth/refresh` — Token yenile
- `POST /api/auth/logout` — Çıkış yap
### Matches (4) — Public
- `GET /api/matches` — Maç listesi (paginated, matches tablosundan)
- `POST /api/matches/query` — Gelişmiş maç sorgusu (sport, league, status, date, team filtresi, live_matches tablosundan)
- `GET /api/matches/leagues/active` — Aktif ligler (cached 1dk)
- `GET /api/matches/:id` — Maç detayı (kadro, stat, oran, olaylar)
### Leagues (8) — Public
- `GET /api/leagues` — Tüm ligler
- `GET /api/leagues/:id` — Lig detay
- `GET /api/leagues/countries` — Ülke listesi
- `GET /api/leagues/countries/:id` — Ülke detay + ligleri
- `GET /api/leagues/teams/search` — Takım arama
- `GET /api/leagues/teams/:id` — Takım detay
- `GET /api/leagues/teams/:id/matches` — Takım son maçları
- `GET /api/leagues/teams/h2h` — Head-to-head
### Coupon (6) — Mixed
- `POST /api/coupon/analyze-match` — Tekil maç analizi (Public)
- `POST /api/coupon/daily-banko` — Günün bankosu (Public)
- `POST /api/coupon/suggest` — Akıllı kupon öner (Public)
- `POST /api/coupon/create` — Kupon kaydet (Auth)
- `GET /api/coupon/my-stats` — Kullanıcı istatistikleri (Auth)
- `GET /api/coupon/history` — Kupon geçmişi (Auth)
### Predictions (7) — Requires Redis
- `GET /api/predictions/health` — AI Engine health
- `GET /api/predictions/upcoming` — Yaklaşan tahminler
- `GET /api/predictions/value-bets` — EV+ fırsatları
- `GET /api/predictions/history` — Tahmin geçmişi
- `GET /api/predictions/:matchId` — Tekil tahmin (cached 6 saat)
- `POST /api/predictions/generate` — Tahmin üret
- `POST /api/predictions/smart-coupon` — Smart Coupon
### Admin (11) — Superadmin
- Kullanıcı CRUD, rol/abonelik güncelleme, ayarlar, analytics
### Analysis (2) — Auth
- `POST /api/analysis/analyze-matches` — Çoklu maç analizi
- `GET /api/analysis/history` — Analiz geçmişi
### Users (5) — Auth
- CRUD + restore
### Health (3) — Public
- `GET /api/health` — Readiness
- `GET /api/health/live` — Liveness
- `GET /api/health/detail` — Detaylı sağlık
---
## 7. Cron/Zamanlanmış Görevler
| Görev | Cron | Açıklama |
|-------|------|----------|
| `fetchLiveMatches()` | `*/15 * * * *` | Mackolik API'den futbol maçlarını çek → live_matches |
| `fetchOddsForPreMatches()` | `*/15 * * * *` | Başlamamış maçların oranlarını çek |
| `fetchBasketballMatches()` | Manuel | Basketbol maçlarını çek |
| `updateLiveScores()` | `*/15 * * * *` | Canlı maç skorlarını güncelle |
| `finalizeFinishedMatches()` | `*/30 * * * *` | Bitmiş maçları live_matches → matches'e migrate et |
| `resetUsageLimits()` | `0 3 * * *` | Günlük kullanım limitlerini sıfırla |
| `cleanupOldData()` | `0 4 * * *` | 30 günlük AI logları sil |
| `checkSubscriptions()` | `0 0 * * *` | Süresi dolmuş abonelikleri expired yap |
---
## 8. Standart API Response Formatı
```json
{
"success": true,
"status": 200,
"message": "Success",
"data": { ... },
"errors": []
}
```
**Not:** Global Exception Filter tüm hataları HTTP 200 olarak döner, gerçek status body içindedir.