595 lines
21 KiB
Markdown
595 lines
21 KiB
Markdown
# 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.
|