This commit is contained in:
Executable
+785
@@ -0,0 +1,785 @@
|
||||
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?
|
||||
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")
|
||||
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")
|
||||
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")
|
||||
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 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?
|
||||
coupons UserCoupon[]
|
||||
totoCoupons TotoCoupon[]
|
||||
|
||||
@@index([email])
|
||||
@@index([subscriptionStatus, subscriptionExpiresAt])
|
||||
@@map("users")
|
||||
}
|
||||
|
||||
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")
|
||||
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
|
||||
active
|
||||
expired
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user