363 lines
13 KiB
Plaintext
363 lines
13 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
}
|
|
|
|
model Player {
|
|
id Int @id @default(autoincrement())
|
|
name String
|
|
rating Int @default(0)
|
|
currentElo Int @default(1000)
|
|
gamesPlayed Int @default(0)
|
|
wins Int @default(0)
|
|
losses Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
normalizedName String @unique
|
|
eloSnapshots EloSnapshot[]
|
|
eventParticipants EventParticipant[]
|
|
matchesAsP1 Match[] @relation("MatchPlayer1")
|
|
matchesAsP2 Match[] @relation("MatchPlayer2")
|
|
matchesAsP3 Match[] @relation("MatchPlayer3")
|
|
matchesAsP4 Match[] @relation("MatchPlayer4")
|
|
partnershipGames PartnershipGame[] @relation("PartnershipPlayer1")
|
|
partnershipGames2 PartnershipGame[] @relation("PartnershipPlayer2")
|
|
partnershipStats PartnershipStat[] @relation("StatPlayer1")
|
|
partnershipStats2 PartnershipStat[] @relation("StatPlayer2")
|
|
activities Activity[]
|
|
user User?
|
|
eloRating EloRating?
|
|
glicko2Rating Glicko2Rating?
|
|
openSkillRating OpenSkillRating?
|
|
bracketMatchupsAsP1P1 BracketMatchup[] @relation("BracketMatchupPlayer1P1")
|
|
bracketMatchupsAsP1P2 BracketMatchup[] @relation("BracketMatchupPlayer1P2")
|
|
bracketMatchupsAsP2P1 BracketMatchup[] @relation("BracketMatchupPlayer2P1")
|
|
bracketMatchupsAsP2P2 BracketMatchup[] @relation("BracketMatchupPlayer2P2")
|
|
|
|
@@map("players")
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
emailVerified Boolean @default(false)
|
|
name String?
|
|
image String?
|
|
role String @default("player")
|
|
playerId Int? @unique
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
accounts Account[]
|
|
ownedTournaments Event[] @relation("TournamentOwner")
|
|
createdMatches Match[] @relation("MatchCreator")
|
|
sessions Session[]
|
|
activities Activity[]
|
|
player Player? @relation(fields: [playerId], references: [id])
|
|
|
|
@@map("users")
|
|
}
|
|
|
|
model Event {
|
|
id Int @id @default(autoincrement())
|
|
event_id Int?
|
|
name String
|
|
description String?
|
|
eventDate DateTime?
|
|
eventType String @default("tournament")
|
|
tournamentType String @default("individual")
|
|
format String @default("round_robin")
|
|
status String @default("planned")
|
|
maxParticipants Int?
|
|
ownerId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
targetScore Int?
|
|
allowTies Boolean @default(false)
|
|
bracketMatchups BracketMatchup[]
|
|
participants EventParticipant[]
|
|
owner User? @relation("TournamentOwner", fields: [ownerId], references: [id])
|
|
matches Match[]
|
|
rounds TournamentRound[]
|
|
activities Activity[]
|
|
|
|
// Team configuration fields
|
|
teamDurability String @default("permanent") // permanent, variable, per_round
|
|
partnerRotation String @default("none") // none, minimize_repeat, maximize_even, elo_based
|
|
allowByes Boolean @default(true)
|
|
teamConfiguration Json? // Additional configuration options
|
|
maxRosterChanges Int? // Maximum roster changes per player
|
|
requireAdminVerify Boolean @default(false) // For match score verification
|
|
|
|
@@map("events")
|
|
}
|
|
|
|
model EventParticipant {
|
|
id Int @id @default(autoincrement())
|
|
eventId Int
|
|
playerId Int
|
|
seed Int?
|
|
status String @default("registered")
|
|
registrationDate DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
event Event @relation(fields: [eventId], references: [id])
|
|
player Player @relation(fields: [playerId], references: [id])
|
|
|
|
@@unique([eventId, playerId])
|
|
@@map("event_participants")
|
|
}
|
|
|
|
model TournamentRound {
|
|
id Int @id @default(autoincrement())
|
|
eventId Int
|
|
roundNumber Int
|
|
status String @default("pending")
|
|
scheduledStart DateTime?
|
|
actualStart DateTime?
|
|
completedAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
bracketMatchups BracketMatchup[]
|
|
event Event @relation(fields: [eventId], references: [id])
|
|
|
|
@@map("tournament_rounds")
|
|
}
|
|
|
|
model BracketMatchup {
|
|
id Int @id @default(autoincrement())
|
|
roundId Int
|
|
eventId Int
|
|
player1P1Id Int?
|
|
player1P2Id Int?
|
|
player2P1Id Int?
|
|
player2P2Id Int?
|
|
matchId Int?
|
|
tableNumber Int?
|
|
bracketPosition Int?
|
|
winnerTeamId Int?
|
|
loserTeamId Int?
|
|
status String @default("pending")
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
event Event @relation(fields: [eventId], references: [id])
|
|
match Match? @relation(fields: [matchId], references: [id], onDelete: Cascade)
|
|
round TournamentRound @relation(fields: [roundId], references: [id])
|
|
player1P1 Player? @relation("BracketMatchupPlayer1P1", fields: [player1P1Id], references: [id])
|
|
player1P2 Player? @relation("BracketMatchupPlayer1P2", fields: [player1P2Id], references: [id])
|
|
player2P1 Player? @relation("BracketMatchupPlayer2P1", fields: [player2P1Id], references: [id])
|
|
player2P2 Player? @relation("BracketMatchupPlayer2P2", fields: [player2P2Id], references: [id])
|
|
|
|
@@map("bracket_matchups")
|
|
}
|
|
|
|
model Match {
|
|
id Int @id @default(autoincrement())
|
|
eventId Int?
|
|
playedAt DateTime?
|
|
player1P1Id Int?
|
|
player1P2Id Int?
|
|
player2P1Id Int?
|
|
player2P2Id Int?
|
|
team1Score Int
|
|
team2Score Int
|
|
status String @default("completed")
|
|
createdById String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
isCasual Boolean @default(false)
|
|
bracketMatchups BracketMatchup[]
|
|
eloSnapshots EloSnapshot[]
|
|
activities Activity[]
|
|
createdBy User? @relation("MatchCreator", fields: [createdById], references: [id])
|
|
event Event? @relation(fields: [eventId], references: [id], onDelete: Cascade)
|
|
player1P1 Player? @relation("MatchPlayer1", fields: [player1P1Id], references: [id])
|
|
player1P2 Player? @relation("MatchPlayer2", fields: [player1P2Id], references: [id])
|
|
player2P1 Player? @relation("MatchPlayer3", fields: [player2P1Id], references: [id])
|
|
player2P2 Player? @relation("MatchPlayer4", fields: [player2P2Id], references: [id])
|
|
partnershipGames PartnershipGame[]
|
|
|
|
@@map("matches")
|
|
}
|
|
|
|
model EloSnapshot {
|
|
id Int @id @default(autoincrement())
|
|
playerId Int
|
|
matchId Int
|
|
ratingBefore Int
|
|
ratingAfter Int
|
|
ratingChange Int
|
|
createdAt DateTime @default(now())
|
|
match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)
|
|
player Player @relation(fields: [playerId], references: [id])
|
|
|
|
@@map("elo_snapshots")
|
|
}
|
|
|
|
model PartnershipGame {
|
|
id Int @id @default(autoincrement())
|
|
player1Id Int
|
|
player2Id Int
|
|
matchId Int
|
|
teamNumber Int?
|
|
wonMatch Int?
|
|
player1EloChange Int?
|
|
player2EloChange Int?
|
|
createdAt DateTime @default(now())
|
|
match Match @relation(fields: [matchId], references: [id], onDelete: Cascade)
|
|
player1 Player @relation("PartnershipPlayer1", fields: [player1Id], references: [id])
|
|
player2 Player @relation("PartnershipPlayer2", fields: [player2Id], references: [id])
|
|
|
|
@@map("partnership_games")
|
|
}
|
|
|
|
model PartnershipStat {
|
|
id Int @id @default(autoincrement())
|
|
player1Id Int
|
|
player2Id Int
|
|
gamesPlayed Int @default(0)
|
|
wins Int @default(0)
|
|
losses Int @default(0)
|
|
totalEloChange Int @default(0)
|
|
lastPlayed DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
player1 Player @relation("StatPlayer1", fields: [player1Id], references: [id])
|
|
player2 Player @relation("StatPlayer2", fields: [player2Id], references: [id])
|
|
|
|
@@unique([player1Id, player2Id], name: "partnership_stats_player1Id_player2Id_key")
|
|
@@map("partnership_stats")
|
|
}
|
|
|
|
model Session {
|
|
id String @id
|
|
expiresAt DateTime
|
|
token String @unique
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
ipAddress String?
|
|
userAgent String?
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@map("session")
|
|
}
|
|
|
|
model Account {
|
|
id String @id
|
|
accountId String
|
|
providerId String
|
|
userId String
|
|
accessToken String?
|
|
refreshToken String?
|
|
idToken String?
|
|
accessTokenExpiresAt DateTime?
|
|
refreshTokenExpiresAt DateTime?
|
|
scope String?
|
|
password String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@map("account")
|
|
}
|
|
|
|
model Verification {
|
|
id String @id
|
|
identifier String
|
|
value String
|
|
expiresAt DateTime
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@index([identifier])
|
|
@@map("verification")
|
|
}
|
|
|
|
model EloRating {
|
|
id Int @id @default(autoincrement())
|
|
playerId Int @unique
|
|
rating Int @default(1000)
|
|
volatility Float @default(0) // Optional: for advanced Elo variants
|
|
gamesPlayed Int @default(0)
|
|
wins Int @default(0)
|
|
losses Int @default(0)
|
|
draws Int @default(0)
|
|
lastUpdated DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
player Player @relation(fields: [playerId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("elo_ratings")
|
|
}
|
|
|
|
model Glicko2Rating {
|
|
id Int @id @default(autoincrement())
|
|
playerId Int @unique
|
|
rating Float @default(1500.0) // mu
|
|
deviation Float @default(350.0) // phi
|
|
volatility Float @default(0.05) // sigma
|
|
gamesPlayed Int @default(0)
|
|
wins Int @default(0)
|
|
losses Int @default(0)
|
|
draws Int @default(0)
|
|
lastUpdated DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
player Player @relation(fields: [playerId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("glicko2_ratings")
|
|
}
|
|
|
|
model OpenSkillRating {
|
|
id Int @id @default(autoincrement())
|
|
playerId Int @unique
|
|
rating Float @default(25.0) // mu
|
|
deviation Float @default(8.33) // sigma (std dev)
|
|
gamesPlayed Int @default(0)
|
|
wins Int @default(0)
|
|
losses Int @default(0)
|
|
draws Int @default(0)
|
|
lastUpdated DateTime @default(now())
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
player Player @relation(fields: [playerId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("open_skill_ratings")
|
|
}
|
|
|
|
model Activity {
|
|
id Int @id @default(autoincrement())
|
|
type String // "player_registration", "tournament_created", "match_completed", "partnership_recorded"
|
|
description String
|
|
userId String?
|
|
playerId Int?
|
|
eventId Int?
|
|
matchId Int?
|
|
createdAt DateTime @default(now())
|
|
|
|
user User? @relation(fields: [userId], references: [id])
|
|
player Player? @relation(fields: [playerId], references: [id])
|
|
event Event? @relation(fields: [eventId], references: [id])
|
|
match Match? @relation(fields: [matchId], references: [id])
|
|
|
|
@@map("activities")
|
|
}
|
|
|
|
model ClubSettings {
|
|
id Int @id @default(autoincrement())
|
|
clubName String @default("Euchre Club")
|
|
defaultEloRating Int @default(1200)
|
|
partnershipEnabled Boolean @default(true)
|
|
notificationsEnabled Boolean @default(true)
|
|
matchVerification Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@map("club_settings")
|
|
}
|