generator client { provider = "prisma-client-js" binaryTargets = ["native", "linux-musl-arm64-openssl-3.0.x", "linux-musl-openssl-3.0.x"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ───────────────────────────────────────────────────────────── // Domain Models — Sports Data // ───────────────────────────────────────────────────────────── model Country { id String @id name String @unique flagUrl String? @map("flag_url") createdAt DateTime @default(now()) @map("created_at") leagues League[] @@map("countries") } model League { id String @id name String countryId String? @map("country_id") sport Sport competitionSlug String? @map("competition_slug") code String? logoUrl String? @map("logo_url") createdAt DateTime @default(now()) @map("created_at") country Country? @relation(fields: [countryId], references: [id]) liveMatches LiveMatch[] matches Match[] @@unique([name, countryId, sport]) @@index([sport]) @@index([countryId]) @@map("leagues") } model Team { id String @id name String slug String? sport Sport logoUrl String? @map("logo_url") createdAt DateTime @default(now()) @map("created_at") awayMatchesLive LiveMatch[] @relation("AwayTeamLive") homeMatchesLive LiveMatch[] @relation("HomeTeamLive") playerEvents MatchPlayerEvents[] playerParticipations MatchPlayerParticipation[] basketballPlayerStats BasketballPlayerStats[] footballTeamStats FootballTeamStats[] basketballTeamStats BasketballTeamStats[] awayMatches Match[] @relation("AwayTeam") homeMatches Match[] @relation("HomeTeam") eloRating TeamEloRating? @@index([name]) @@index([sport]) @@map("teams") } model Player { id String @id name String slug String? @unique createdAt DateTime @default(now()) @map("created_at") assistEvents MatchPlayerEvents[] @relation("AssistPlayer") playerEvents MatchPlayerEvents[] @relation("EventPlayer") substitutedOutEvents MatchPlayerEvents[] @relation("SubstitutedOut") participations MatchPlayerParticipation[] playerStats BasketballPlayerStats[] @@index([name]) @@map("players") } model Match { id String @id leagueId String? @map("league_id") homeTeamId String? @map("home_team_id") awayTeamId String? @map("away_team_id") sport Sport matchName String? @map("match_name") matchSlug String? @map("match_slug") mstUtc BigInt @map("mst_utc") status String? state String? scoreHome Int? @map("score_home") scoreAway Int? @map("score_away") htScoreHome Int? @map("ht_score_home") htScoreAway Int? @map("ht_score_away") winner String? iddaaCode String? @map("iddaa_code") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") footballAiFeatures FootballAiFeature? basketballAiFeatures BasketballAiFeature? officials MatchOfficial[] playerEvents MatchPlayerEvents[] playerParticipations MatchPlayerParticipation[] basketballPlayerStats BasketballPlayerStats[] footballTeamStats FootballTeamStats[] basketballTeamStats BasketballTeamStats[] awayTeam Team? @relation("AwayTeam", fields: [awayTeamId], references: [id]) homeTeam Team? @relation("HomeTeam", fields: [homeTeamId], references: [id]) league League? @relation(fields: [leagueId], references: [id]) oddCategories OddCategory[] prediction Prediction? predictionOutcomes PredictionOutcome[] couponItems UserCouponItem[] @@index([awayTeamId]) @@index([homeTeamId]) @@index([iddaaCode]) @@index([leagueId]) @@index([mstUtc(sort: Desc)]) @@index([sport]) @@index([state]) @@index([status, mstUtc(sort: Desc)]) @@map("matches") } model LiveMatch { id String @id leagueId String? @map("league_id") homeTeamId String? @map("home_team_id") awayTeamId String? @map("away_team_id") sport String? matchName String? @map("match_name") matchSlug String? @map("match_slug") mstUtc BigInt? @map("mst_utc") status String? state String? substate String? scoreHome Int? @map("score_home") scoreAway Int? @map("score_away") htScoreHome Int? @map("ht_score_home") htScoreAway Int? @map("ht_score_away") updatedAt DateTime @default(now()) @updatedAt @map("updated_at") odds Json? oddsUpdatedAt DateTime? @map("odds_updated_at") refereeName String? @map("referee_name") lineups Json? sidelined Json? awayTeam Team? @relation("AwayTeamLive", fields: [awayTeamId], references: [id]) homeTeam Team? @relation("HomeTeamLive", fields: [homeTeamId], references: [id]) league League? @relation(fields: [leagueId], references: [id]) @@index([mstUtc]) @@index([state]) @@map("live_matches") } // ───────────────────────────────────────────────────────────── // Match Details — Stats, Events, Participation, Officials // ───────────────────────────────────────────────────────────── model FootballAiFeature { matchId String @id @map("match_id") homeElo Float @default(1500.0) @map("home_elo") awayElo Float @default(1500.0) @map("away_elo") homeHomeElo Float @default(1500.0) @map("home_home_elo") awayAwayElo Float @default(1500.0) @map("away_away_elo") homeFormElo Float @default(1500.0) @map("home_form_elo") awayFormElo Float @default(1500.0) @map("away_form_elo") eloDiff Float @default(0.0) @map("elo_diff") homeFormScore Float @default(50.0) @map("home_form_score") awayFormScore Float @default(50.0) @map("away_form_score") homeGoalsAvg5 Float @default(0.0) @map("home_goals_avg_5") awayGoalsAvg5 Float @default(0.0) @map("away_goals_avg_5") homeConcededAvg5 Float @default(0.0) @map("home_conceded_avg_5") awayConcededAvg5 Float @default(0.0) @map("away_conceded_avg_5") homeCleanSheetRate Float @default(0.0) @map("home_clean_sheet_rate") awayCleanSheetRate Float @default(0.0) @map("away_clean_sheet_rate") homeScoringRate Float @default(0.0) @map("home_scoring_rate") awayScoringRate Float @default(0.0) @map("away_scoring_rate") homeWinStreak Int @default(0) @map("home_win_streak") awayWinStreak Int @default(0) @map("away_win_streak") impliedHome Float @default(0.33) @map("implied_home") impliedDraw Float @default(0.33) @map("implied_draw") impliedAway Float @default(0.33) @map("implied_away") impliedOver25 Float @default(0.5) @map("implied_over25") impliedBttsYes Float @default(0.5) @map("implied_btts_yes") oddsOverround Float @default(0.0) @map("odds_overround") homeAvgPossession Float @default(50.0) @map("home_avg_possession") awayAvgPossession Float @default(50.0) @map("away_avg_possession") homeAvgShotsOnTarget Float @default(0.0) @map("home_avg_shots_on_target") awayAvgShotsOnTarget Float @default(0.0) @map("away_avg_shots_on_target") homeShotConversion Float @default(0.0) @map("home_shot_conversion") awayShotConversion Float @default(0.0) @map("away_shot_conversion") homeAvgCorners Float @default(0.0) @map("home_avg_corners") awayAvgCorners Float @default(0.0) @map("away_avg_corners") h2hTotal Int @default(0) @map("h2h_total") h2hHomeWinRate Float @default(0.0) @map("h2h_home_win_rate") h2hAvgGoals Float @default(0.0) @map("h2h_avg_goals") h2hOver25Rate Float @default(0.0) @map("h2h_over25_rate") h2hBttsRate Float @default(0.0) @map("h2h_btts_rate") refereeAvgCards Float @default(0.0) @map("referee_avg_cards") refereeHomeBias Float @default(0.0) @map("referee_home_bias") refereeAvgGoals Float @default(0.0) @map("referee_avg_goals") leagueAvgGoals Float @default(0.0) @map("league_avg_goals") leagueHomeWinPct Float @default(0.0) @map("league_home_win_pct") leagueOver25Pct Float @default(0.0) @map("league_over25_pct") missingPlayersImpact Float @default(0.0) @map("missing_players_impact") oddsMovementHome Float? @map("odds_movement_home") oddsMovementDraw Float? @map("odds_movement_draw") oddsMovementAway Float? @map("odds_movement_away") oddsMovementO25 Float? @map("odds_movement_o25") oddsMovementBtts Float? @map("odds_movement_btts") oddsSharpness Float? @map("odds_sharpness") calculatorVer String @default("v2.0") @map("calculator_ver") updatedAt DateTime @updatedAt @map("updated_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) @@map("football_ai_features") } model BasketballAiFeature { matchId String @id @map("match_id") homeElo Float @default(1500.0) @map("home_elo") awayElo Float @default(1500.0) @map("away_elo") homeHomeElo Float @default(1500.0) @map("home_home_elo") awayAwayElo Float @default(1500.0) @map("away_away_elo") homeFormElo Float @default(1500.0) @map("home_form_elo") awayFormElo Float @default(1500.0) @map("away_form_elo") eloDiff Float @default(0.0) @map("elo_diff") homeFormScore Float @default(50.0) @map("home_form_score") awayFormScore Float @default(50.0) @map("away_form_score") homePtsAvg5 Float @default(0.0) @map("home_pts_avg_5") awayPtsAvg5 Float @default(0.0) @map("away_pts_avg_5") homeConcededAvg5 Float @default(0.0) @map("home_conceded_avg_5") awayConcededAvg5 Float @default(0.0) @map("away_conceded_avg_5") homeWinStreak Int @default(0) @map("home_win_streak") awayWinStreak Int @default(0) @map("away_win_streak") impliedHome Float @default(0.5) @map("implied_home") impliedAway Float @default(0.5) @map("implied_away") impliedOverTotal Float @default(0.5) @map("implied_over_total") impliedSpreadHome Float @default(0.5) @map("implied_spread_home") oddsOverround Float @default(0.0) @map("odds_overround") homeAvgPts Float @default(0.0) @map("home_avg_pts") awayAvgPts Float @default(0.0) @map("away_avg_pts") homeAvgRebounds Float @default(0.0) @map("home_avg_rebounds") awayAvgRebounds Float @default(0.0) @map("away_avg_rebounds") homeFgPct Float @default(0.0) @map("home_fg_pct") awayFgPct Float @default(0.0) @map("away_fg_pct") homeAvgThreePtMade Float @default(0.0) @map("home_avg_three_pt_made") awayAvgThreePtMade Float @default(0.0) @map("away_avg_three_pt_made") homeAvgTurnovers Float @default(0.0) @map("home_avg_turnovers") awayAvgTurnovers Float @default(0.0) @map("away_avg_turnovers") h2hTotal Int @default(0) @map("h2h_total") h2hHomeWinRate Float @default(0.0) @map("h2h_home_win_rate") h2hAvgPts Float @default(0.0) @map("h2h_avg_pts") h2hAvgMargin Float @default(0.0) @map("h2h_avg_margin") missingPlayersImpact Float @default(0.0) @map("missing_players_impact") calculatorVer String @default("v2.0") @map("calculator_ver") updatedAt DateTime @updatedAt @map("updated_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) @@map("basketball_ai_features") } model TeamEloRating { teamId String @id @map("team_id") overallElo Float @default(1500.0) @map("overall_elo") homeElo Float @default(1500.0) @map("home_elo") awayElo Float @default(1500.0) @map("away_elo") formElo Float @default(1500.0) @map("form_elo") matchesPlayed Int @default(0) @map("matches_played") recentForm String @default("") @map("recent_form") updatedAt DateTime @updatedAt @map("updated_at") team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@map("team_elo_ratings") } model MatchPlayerEvents { id Int @id @default(autoincrement()) matchId String @map("match_id") playerId String @map("player_id") teamId String @map("team_id") eventType EventType @map("event_type") eventSubtype String? @map("event_subtype") timeMinute String @map("time_minute") timeSeconds Int? @map("time_seconds") periodId Int? @map("period_id") assistPlayerId String? @map("assist_player_id") scoreAfter String? @map("score_after") playerOutId String? @map("player_out_id") position MatchPosition? createdAt DateTime @default(now()) @map("created_at") assistPlayer Player? @relation("AssistPlayer", fields: [assistPlayerId], references: [id]) match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) player Player @relation("EventPlayer", fields: [playerId], references: [id], onDelete: Cascade) substitutedOut Player? @relation("SubstitutedOut", fields: [playerOutId], references: [id]) team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@index([assistPlayerId]) @@index([eventType]) @@index([matchId]) @@index([playerId]) @@index([teamId]) @@map("match_player_events") } model MatchPlayerParticipation { id Int @id @default(autoincrement()) matchId String @map("match_id") playerId String @map("player_id") teamId String @map("team_id") position PlayerPosition? shirtNumber Int? @map("shirt_number") isStarting Boolean @default(true) @map("is_starting") createdAt DateTime @default(now()) @map("created_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) player Player @relation(fields: [playerId], references: [id], onDelete: Cascade) team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@unique([matchId, playerId, teamId]) @@index([matchId]) @@index([playerId]) @@index([teamId]) @@map("match_player_participation") } model BasketballPlayerStats { id Int @id @default(autoincrement()) matchId String @map("match_id") playerId String @map("player_id") teamId String @map("team_id") minutes String? points Int? rebounds Int? assists Int? steals Int? blocks Int? turnovers Int? fgMade Int? @map("fg_made") fgAttempted Int? @map("fg_attempted") threePtMade Int? @map("three_pt_made") threePtAttempted Int? @map("three_pt_attempted") ftMade Int? @map("ft_made") ftAttempted Int? @map("ft_attempted") fouls Int? createdAt DateTime @default(now()) @map("created_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) player Player @relation(fields: [playerId], references: [id], onDelete: Cascade) team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@unique([matchId, playerId, teamId]) @@index([matchId]) @@map("basketball_player_stats") } model FootballTeamStats { id Int @id @default(autoincrement()) matchId String @map("match_id") teamId String @map("team_id") possessionPercentage Float? @map("possession_percentage") shotsOnTarget Int? @map("shots_on_target") shotsOffTarget Int? @map("shots_off_target") totalShots Int? @map("total_shots") totalPasses Int? @map("total_passes") corners Int? fouls Int? offsides Int? createdAt DateTime @default(now()) @map("created_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@unique([matchId, teamId]) @@index([matchId]) @@index([teamId]) @@map("football_team_stats") } model BasketballTeamStats { id Int @id @default(autoincrement()) matchId String @map("match_id") teamId String @map("team_id") points Int? rebounds Int? assists Int? fgMade Int? @map("fg_made") fgAttempted Int? @map("fg_attempted") threePtMade Int? @map("three_pt_made") threePtAttempted Int? @map("three_pt_attempted") ftMade Int? @map("ft_made") ftAttempted Int? @map("ft_attempted") steals Int? blocks Int? turnovers Int? fouls Int? q1Score Int? @map("q1_score") q2Score Int? @map("q2_score") q3Score Int? @map("q3_score") q4Score Int? @map("q4_score") otScore Int? @map("ot_score") createdAt DateTime @default(now()) @map("created_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) team Team @relation(fields: [teamId], references: [id], onDelete: Cascade) @@unique([matchId, teamId]) @@index([matchId]) @@index([teamId]) @@map("basketball_team_stats") } model MatchOfficial { id Int @id @default(autoincrement()) matchId String @map("match_id") name String roleId Int @map("role_id") createdAt DateTime @default(now()) @map("created_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) role OfficialRole @relation(fields: [roleId], references: [id]) @@unique([matchId, name, roleId]) @@index([matchId]) @@index([roleId]) @@map("match_officials") } model OfficialRole { id Int @id @default(autoincrement()) name String @unique officials MatchOfficial[] @@map("official_roles") } // ───────────────────────────────────────────────────────────── // Odds & Predictions // ───────────────────────────────────────────────────────────── model OddCategory { dbId Int @id @default(autoincrement()) @map("db_id") matchId String @map("match_id") categoryJsonId Int? @map("category_json_id") name String? sport Sport? createdAt DateTime @default(now()) @map("created_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) selections OddSelection[] @@unique([matchId, name]) @@index([matchId]) @@index([sport]) @@map("odd_categories") } model OddSelection { dbId Int @id @default(autoincrement()) @map("db_id") categoryId Int @map("odd_category_db_id") name String? oddValue String? @map("odd_value") openingValue String? @map("opening_value") position String? sov Float? state String? sport Sport? createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @default(now()) @map("updated_at") category OddCategory @relation(fields: [categoryId], references: [dbId], onDelete: Cascade) history OddsHistory[] @@unique([categoryId, name]) @@index([categoryId]) @@index([sport]) @@map("odd_selections") } model OddsHistory { id BigInt @id @default(autoincrement()) selectionId Int @map("selection_id") matchId String @map("match_id") previousValue Float @map("previous_value") newValue Float @map("new_value") bookmaker String? @default("MACKOLIK") changeTime DateTime @default(now()) @map("change_time") selection OddSelection @relation(fields: [selectionId], references: [dbId], onDelete: Cascade) @@index([matchId, changeTime]) @@index([selectionId]) @@map("odds_history") } model Prediction { matchId String @id @map("match_id") predictionJson Json @map("prediction_json") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) @@map("predictions") } model PredictionRun { id BigInt @id @default(autoincrement()) matchId String @map("match_id") engineVersion String @map("engine_version") decisionTraceId String? @map("decision_trace_id") generatedAt DateTime @default(now()) @map("generated_at") oddsSnapshot Json? @map("odds_snapshot") payloadSummary Json @map("payload_summary") eventualOutcome String? @map("eventual_outcome") unitProfit Float? @map("unit_profit") @@index([matchId, generatedAt(sort: Desc)]) @@index([engineVersion, generatedAt(sort: Desc)]) @@map("prediction_runs") } model PredictionOutcome { id BigInt @id @default(autoincrement()) matchId String @map("match_id") market String pick String probability Float confidence Float odds Float? playable Boolean @default(false) engineVersion String @map("engine_version") generatedAt DateTime @default(now()) @map("generated_at") resolved Boolean @default(false) hit Boolean? resolvedAt DateTime? @map("resolved_at") match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) @@unique([matchId, market, engineVersion]) @@index([market, resolvedAt(sort: Desc)]) @@index([resolved, generatedAt]) @@index([playable, resolved]) @@map("prediction_outcomes") } model AiPredictionsLog { id Int @id @default(autoincrement()) matchId String @map("match_id") modelVersion String @map("model_version") recommendedBets Json? @map("recommended_bets") confidenceScore Float? @map("confidence_score") createdAt DateTime @default(now()) @map("created_at") isResolved Boolean @default(false) @map("is_resolved") actualResult String? @map("actual_result") isCorrect Boolean? @map("is_correct") accuracyScore Float? @map("accuracy_score") @@index([matchId]) @@index([createdAt(sort: Desc)]) @@map("ai_predictions_log") } // ───────────────────────────────────────────────────────────── // User Domain — Auth, Coupons, Usage // ───────────────────────────────────────────────────────────── model User { id String @id @default(uuid()) email String @unique passwordHash String @map("password_hash") firstName String? @map("first_name") lastName String? @map("last_name") role UserRole @default(user) subscriptionStatus SubscriptionStatus @default(free) @map("subscription_status") subscriptionExpiresAt DateTime? @map("subscription_expires_at") encryptedApiKey String? @map("encrypted_api_key") isActive Boolean @default(true) @map("is_active") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") deletedAt DateTime? @map("deleted_at") analyses Analysis[] refreshTokens RefreshToken[] usageLimit UsageLimit? subscription Subscription? coupons UserCoupon[] totoCoupons TotoCoupon[] @@index([email]) @@index([subscriptionStatus, subscriptionExpiresAt]) @@map("users") } model Subscription { id String @id @default(uuid()) userId String @unique @map("user_id") paddleSubscriptionId String? @unique @map("paddle_subscription_id") paddleCustomerId String? @map("paddle_customer_id") plan SubscriptionStatus @default(free) billingInterval BillingInterval? @map("billing_interval") currentPeriodStart DateTime? @map("current_period_start") currentPeriodEnd DateTime? @map("current_period_end") cancelledAt DateTime? @map("cancelled_at") cancelEffectiveDate DateTime? @map("cancel_effective_date") paddlePriceId String? @map("paddle_price_id") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([paddleSubscriptionId]) @@index([paddleCustomerId]) @@map("subscriptions") } model RefreshToken { id String @id @default(uuid()) token String @unique userId String @map("user_id") expiresAt DateTime @map("expires_at") createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([token]) @@index([userId]) @@map("refresh_tokens") } model UsageLimit { id Int @id @default(autoincrement()) userId String @unique @map("user_id") analysisCount Int @default(0) @map("analysis_count") couponCount Int @default(0) @map("coupon_count") maxAnalyses Int @default(3) @map("max_analyses") maxCoupons Int @default(1) @map("max_coupons") lastResetDate DateTime @map("last_reset_date") @db.Date createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([lastResetDate]) @@map("usage_limits") } model Analysis { id Int @id @default(autoincrement()) userId String @map("user_id") matchIds String @map("match_ids") analysisResultJson String @map("analysis_result_json") isDeleted Boolean @default(false) @map("is_deleted") createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([createdAt(sort: Desc)]) @@map("analyses") } model UserCoupon { id String @id @default(uuid()) userId String @map("user_id") strategy String totalOdds Float @map("total_odds") status String @default("PENDING") isPublic Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") couponItems UserCouponItem[] user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([status]) @@map("user_coupons") } model UserCouponItem { id Int @id @default(autoincrement()) couponId String @map("coupon_id") matchId String @map("match_id") selection String oddAtTime Float @map("odd_at_time") isCorrect Boolean? @map("is_correct") coupon UserCoupon @relation(fields: [couponId], references: [id], onDelete: Cascade) match Match @relation(fields: [matchId], references: [id], onDelete: Cascade) @@index([couponId]) @@map("user_coupon_items") } // ───────────────────────────────────────────────────────────── // Spor Toto Domain // ───────────────────────────────────────────────────────────── model TotoBulletin { id String @id @default(uuid()) gameCycleNo Int @unique @map("game_cycle_no") programName String? @map("program_name") season String? status TotoBulletinStatus @default(UPCOMING) payinBeginDate DateTime? @map("payin_begin_date") payinEndDate DateTime? @map("payin_end_date") poolTotal Float? @map("pool_total") rolloverAmount Float? @map("rollover_amount") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") matches TotoBulletinMatch[] result TotoResult? coupons TotoCoupon[] @@index([status]) @@map("toto_bulletins") } model TotoBulletinMatch { id Int @id @default(autoincrement()) bulletinId String @map("bulletin_id") matchOrder Int @map("match_order") homeTeamName String @map("home_team_name") awayTeamName String @map("away_team_name") leagueName String? @map("league_name") kickoffTime DateTime? @map("kickoff_time") matchId String? @map("match_id") result TotoMatchResult? isCancelled Boolean @default(false) @map("is_cancelled") drawResult TotoMatchResult? @map("draw_result") bulletin TotoBulletin @relation(fields: [bulletinId], references: [id], onDelete: Cascade) @@unique([bulletinId, matchOrder]) @@index([bulletinId]) @@index([matchId]) @@map("toto_bulletin_matches") } model TotoResult { id String @id @default(uuid()) bulletinId String @unique @map("bulletin_id") winners15 Int @default(0) @map("winners_15") prize15 Float? @map("prize_15") winners14 Int @default(0) @map("winners_14") prize14 Float? @map("prize_14") winners13 Int @default(0) @map("winners_13") prize13 Float? @map("prize_13") winners12 Int @default(0) @map("winners_12") prize12 Float? @map("prize_12") rolloverNext Float? @map("rollover_next") poolDistributed Float? @map("pool_distributed") createdAt DateTime @default(now()) @map("created_at") bulletin TotoBulletin @relation(fields: [bulletinId], references: [id], onDelete: Cascade) @@map("toto_results") } model TotoCoupon { id String @id @default(uuid()) userId String @map("user_id") bulletinId String @map("bulletin_id") strategy String? columnCount Int @map("column_count") totalCost Float @map("total_cost") status String @default("PENDING") totalPrize Float? @map("total_prize") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") columns TotoColumn[] user User @relation(fields: [userId], references: [id], onDelete: Cascade) bulletin TotoBulletin @relation(fields: [bulletinId], references: [id], onDelete: Cascade) @@index([userId]) @@index([bulletinId]) @@index([status]) @@map("toto_coupons") } model TotoColumn { id Int @id @default(autoincrement()) couponId String @map("coupon_id") predictions String @db.VarChar(15) correctCount Int? @map("correct_count") prizeAmount Float? @map("prize_amount") coupon TotoCoupon @relation(fields: [couponId], references: [id], onDelete: Cascade) @@index([couponId]) @@index([correctCount]) @@map("toto_columns") } // ───────────────────────────────────────────────────────────── // System & i18n // ───────────────────────────────────────────────────────────── model AppSetting { key String @id value String? updatedAt DateTime @default(now()) @updatedAt @map("updated_at") @@map("app_settings") } model Translation { id String @id @default(uuid()) key String locale String value String namespace String @default("common") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@unique([key, locale, namespace]) @@index([key]) @@index([locale]) @@index([namespace]) @@map("translations") } // ───────────────────────────────────────────────────────────── // Enums // ───────────────────────────────────────────────────────────── enum Sport { football basketball } enum UserRole { user superadmin } enum SubscriptionStatus { free plus premium past_due cancelled } enum BillingInterval { monthly yearly } enum PlayerPosition { goalkeeper defender midfielder striker } enum EventType { goal card substitute } enum MatchPosition { home away } enum TotoBulletinStatus { UPCOMING ACTIVE COMPLETED CANCELLED } enum TotoMatchResult { HOME_WIN DRAW AWAY_WIN }