feat(db): add tournament_admin role and ownership fields to schema

This commit is contained in:
2026-03-29 19:25:02 -07:00
parent 025b195800
commit 8f1f2bf196
4 changed files with 503 additions and 173 deletions
@@ -0,0 +1,232 @@
-- CreateTable
CREATE TABLE "players" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"rating" INTEGER NOT NULL DEFAULT 0,
"currentElo" INTEGER NOT NULL DEFAULT 1000,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "users" (
"id" TEXT NOT NULL PRIMARY KEY,
"email" TEXT NOT NULL,
"emailVerified" BOOLEAN NOT NULL DEFAULT false,
"name" TEXT,
"image" TEXT,
"role" TEXT NOT NULL DEFAULT 'player',
"playerId" INTEGER,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "users_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "players" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "events" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"event_id" INTEGER,
"name" TEXT NOT NULL,
"description" TEXT,
"eventDate" DATETIME,
"eventType" TEXT NOT NULL DEFAULT 'tournament',
"format" TEXT NOT NULL DEFAULT 'round_robin',
"status" TEXT NOT NULL DEFAULT 'planned',
"maxParticipants" INTEGER,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateTable
CREATE TABLE "event_participants" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"eventId" INTEGER NOT NULL,
"playerId" INTEGER NOT NULL,
"teamId" INTEGER,
"seed" INTEGER,
"status" TEXT NOT NULL DEFAULT 'registered',
"registrationDate" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "event_participants_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "teams" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "event_participants_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "event_participants_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "events" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "teams" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"eventId" INTEGER NOT NULL,
"teamName" TEXT,
"player1Id" INTEGER NOT NULL,
"player2Id" INTEGER NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "teams_player2Id_fkey" FOREIGN KEY ("player2Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "teams_player1Id_fkey" FOREIGN KEY ("player1Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "teams_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "events" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "tournament_rounds" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"eventId" INTEGER NOT NULL,
"roundNumber" INTEGER NOT NULL,
"status" TEXT NOT NULL DEFAULT 'pending',
"scheduledStart" DATETIME,
"actualStart" DATETIME,
"completedAt" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "tournament_rounds_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "events" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "bracket_matchups" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"roundId" INTEGER NOT NULL,
"eventId" INTEGER NOT NULL,
"team1Id" INTEGER,
"team2Id" INTEGER,
"matchId" INTEGER,
"tableNumber" INTEGER,
"bracketPosition" INTEGER,
"winnerTeamId" INTEGER,
"loserTeamId" INTEGER,
"status" TEXT NOT NULL DEFAULT 'pending',
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "bracket_matchups_matchId_fkey" FOREIGN KEY ("matchId") REFERENCES "matches" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "bracket_matchups_team2Id_fkey" FOREIGN KEY ("team2Id") REFERENCES "teams" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "bracket_matchups_team1Id_fkey" FOREIGN KEY ("team1Id") REFERENCES "teams" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "bracket_matchups_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "events" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "bracket_matchups_roundId_fkey" FOREIGN KEY ("roundId") REFERENCES "tournament_rounds" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "matches" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"eventId" INTEGER,
"playedAt" DATETIME,
"team1P1Id" INTEGER NOT NULL,
"team1P2Id" INTEGER NOT NULL,
"team2P1Id" INTEGER NOT NULL,
"team2P2Id" INTEGER NOT NULL,
"team1Score" INTEGER NOT NULL,
"team2Score" INTEGER NOT NULL,
"status" TEXT NOT NULL DEFAULT 'completed',
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "matches_team2P2Id_fkey" FOREIGN KEY ("team2P2Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_team2P1Id_fkey" FOREIGN KEY ("team2P1Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_team1P2Id_fkey" FOREIGN KEY ("team1P2Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_team1P1Id_fkey" FOREIGN KEY ("team1P1Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "events" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "elo_snapshots" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"playerId" INTEGER NOT NULL,
"matchId" INTEGER NOT NULL,
"ratingBefore" INTEGER NOT NULL,
"ratingAfter" INTEGER NOT NULL,
"ratingChange" INTEGER NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "elo_snapshots_matchId_fkey" FOREIGN KEY ("matchId") REFERENCES "matches" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "elo_snapshots_playerId_fkey" FOREIGN KEY ("playerId") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "partnership_games" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"player1Id" INTEGER NOT NULL,
"player2Id" INTEGER NOT NULL,
"matchId" INTEGER NOT NULL,
"teamNumber" INTEGER,
"wonMatch" INTEGER,
"player1EloChange" INTEGER,
"player2EloChange" INTEGER,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "partnership_games_matchId_fkey" FOREIGN KEY ("matchId") REFERENCES "matches" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "partnership_games_player2Id_fkey" FOREIGN KEY ("player2Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "partnership_games_player1Id_fkey" FOREIGN KEY ("player1Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "partnership_stats" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"player1Id" INTEGER NOT NULL,
"player2Id" INTEGER NOT NULL,
"gamesPlayed" INTEGER NOT NULL DEFAULT 0,
"wins" INTEGER NOT NULL DEFAULT 0,
"losses" INTEGER NOT NULL DEFAULT 0,
"totalEloChange" INTEGER NOT NULL DEFAULT 0,
"lastPlayed" DATETIME,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "partnership_stats_player2Id_fkey" FOREIGN KEY ("player2Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "partnership_stats_player1Id_fkey" FOREIGN KEY ("player1Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "session" (
"id" TEXT NOT NULL PRIMARY KEY,
"expiresAt" DATETIME NOT NULL,
"token" TEXT NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
"ipAddress" TEXT,
"userAgent" TEXT,
"userId" TEXT NOT NULL,
CONSTRAINT "session_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "account" (
"id" TEXT NOT NULL PRIMARY KEY,
"accountId" TEXT NOT NULL,
"providerId" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"accessToken" TEXT,
"refreshToken" TEXT,
"idToken" TEXT,
"accessTokenExpiresAt" DATETIME,
"refreshTokenExpiresAt" DATETIME,
"scope" TEXT,
"password" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "account_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
-- CreateTable
CREATE TABLE "verification" (
"id" TEXT NOT NULL PRIMARY KEY,
"identifier" TEXT NOT NULL,
"value" TEXT NOT NULL,
"expiresAt" DATETIME NOT NULL,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
-- CreateIndex
CREATE UNIQUE INDEX "players_name_key" ON "players"("name");
-- CreateIndex
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
-- CreateIndex
CREATE UNIQUE INDEX "users_playerId_key" ON "users"("playerId");
-- CreateIndex
CREATE INDEX "session_userId_idx" ON "session"("userId");
-- CreateIndex
CREATE UNIQUE INDEX "session_token_key" ON "session"("token");
-- CreateIndex
CREATE INDEX "account_userId_idx" ON "account"("userId");
-- CreateIndex
CREATE INDEX "verification_identifier_idx" ON "verification"("identifier");
@@ -0,0 +1,61 @@
-- RedefineTables
PRAGMA defer_foreign_keys=ON;
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_events" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"event_id" INTEGER,
"name" TEXT NOT NULL,
"description" TEXT,
"eventDate" DATETIME,
"eventType" TEXT NOT NULL DEFAULT 'tournament',
"format" TEXT NOT NULL DEFAULT 'round_robin',
"status" TEXT NOT NULL DEFAULT 'planned',
"maxParticipants" INTEGER,
"ownerId" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "events_ownerId_fkey" FOREIGN KEY ("ownerId") REFERENCES "users" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_events" ("createdAt", "description", "eventDate", "eventType", "event_id", "format", "id", "maxParticipants", "name", "status", "updatedAt") SELECT "createdAt", "description", "eventDate", "eventType", "event_id", "format", "id", "maxParticipants", "name", "status", "updatedAt" FROM "events";
DROP TABLE "events";
ALTER TABLE "new_events" RENAME TO "events";
CREATE TABLE "new_matches" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"eventId" INTEGER,
"playedAt" DATETIME,
"team1P1Id" INTEGER NOT NULL,
"team1P2Id" INTEGER NOT NULL,
"team2P1Id" INTEGER NOT NULL,
"team2P2Id" INTEGER NOT NULL,
"team1Score" INTEGER NOT NULL,
"team2Score" INTEGER NOT NULL,
"status" TEXT NOT NULL DEFAULT 'completed',
"createdById" TEXT,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL,
CONSTRAINT "matches_team2P2Id_fkey" FOREIGN KEY ("team2P2Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_team2P1Id_fkey" FOREIGN KEY ("team2P1Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_team1P2Id_fkey" FOREIGN KEY ("team1P2Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_team1P1Id_fkey" FOREIGN KEY ("team1P1Id") REFERENCES "players" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
CONSTRAINT "matches_eventId_fkey" FOREIGN KEY ("eventId") REFERENCES "events" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
CONSTRAINT "matches_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users" ("id") ON DELETE SET NULL ON UPDATE CASCADE
);
INSERT INTO "new_matches" ("createdAt", "eventId", "id", "playedAt", "status", "team1P1Id", "team1P2Id", "team1Score", "team2P1Id", "team2P2Id", "team2Score", "updatedAt") SELECT "createdAt", "eventId", "id", "playedAt", "status", "team1P1Id", "team1P2Id", "team1Score", "team2P1Id", "team2P2Id", "team2Score", "updatedAt" FROM "matches";
DROP TABLE "matches";
ALTER TABLE "new_matches" RENAME TO "matches";
CREATE TABLE "new_players" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"name" TEXT NOT NULL,
"rating" INTEGER NOT NULL DEFAULT 0,
"currentElo" INTEGER NOT NULL DEFAULT 1000,
"gamesPlayed" INTEGER NOT NULL DEFAULT 0,
"wins" INTEGER NOT NULL DEFAULT 0,
"losses" INTEGER NOT NULL DEFAULT 0,
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" DATETIME NOT NULL
);
INSERT INTO "new_players" ("createdAt", "currentElo", "id", "name", "rating", "updatedAt") SELECT "createdAt", "currentElo", "id", "name", "rating", "updatedAt" FROM "players";
DROP TABLE "players";
ALTER TABLE "new_players" RENAME TO "players";
PRAGMA foreign_keys=ON;
PRAGMA defer_foreign_keys=OFF;
+3
View File
@@ -0,0 +1,3 @@
# Please do not edit this file manually
# It should be added in your version-control system (e.g., Git)
provider = "sqlite"
+206 -172
View File
@@ -1,5 +1,3 @@
// EuchreCamp Database Schema
// Generated from existing Ruby/ROM implementation
generator client {
provider = "prisma-client-js"
@@ -10,192 +8,185 @@ datasource db {
url = env("DATABASE_URL")
}
// Player Model - Tracks individual player information
model Player {
id Int @id @default(autoincrement())
name String @unique
rating Int @default(0)
currentElo Int @default(1000)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relationships
users User[]
eventParticipants EventParticipant[]
teamsAsPlayer1 Team[] @relation("TeamPlayer1")
teamsAsPlayer2 Team[] @relation("TeamPlayer2")
matchesAsP1 Match[] @relation("MatchPlayer1")
matchesAsP2 Match[] @relation("MatchPlayer2")
matchesAsP3 Match[] @relation("MatchPlayer3")
matchesAsP4 Match[] @relation("MatchPlayer4")
id Int @id @default(autoincrement())
name String
rating Int @default(0) // Historical rating (used for rankings)
currentElo Int @default(1000) // Current Elo rating
gamesPlayed Int @default(0) // Total games played
wins Int @default(0) // Total wins
losses Int @default(0) // Total losses
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
eloSnapshots EloSnapshot[]
partnershipGames PartnershipGame[] @relation("PartnershipPlayer1")
partnershipGames2 PartnershipGame[] @relation("PartnershipPlayer2")
partnershipStats PartnershipStat[] @relation("StatPlayer1")
partnershipStats2 PartnershipStat[] @relation("StatPlayer2")
eventParticipants EventParticipant[]
matchesAsP4 Match[] @relation("MatchPlayer4")
matchesAsP3 Match[] @relation("MatchPlayer3")
matchesAsP2 Match[] @relation("MatchPlayer2")
matchesAsP1 Match[] @relation("MatchPlayer1")
partnershipGames2 PartnershipGame[] @relation("PartnershipPlayer2")
partnershipGames PartnershipGame[] @relation("PartnershipPlayer1")
partnershipStats2 PartnershipStat[] @relation("StatPlayer2")
partnershipStats PartnershipStat[] @relation("StatPlayer1")
teamsAsPlayer2 Team[] @relation("TeamPlayer2")
teamsAsPlayer1 Team[] @relation("TeamPlayer1")
user User?
@@map("players")
}
// User Model - Authentication and authorization
model User {
id Int @id @default(autoincrement())
playerId Int @unique
email String @unique
passwordDigest String
role String @default("player")
confirmed Boolean @default(false)
confirmationToken String?
confirmationSentAt DateTime?
resetPasswordToken String?
resetPasswordSentAt DateTime?
failedLoginAttempts Int @default(0)
lockedUntil DateTime?
lastLoginAt DateTime?
lastLoginIp String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
id String @id @default(cuid())
email String @unique
emailVerified Boolean @default(false)
name String?
image String?
role String @default("player") // player, tournament_admin, club_admin
player Player @relation(fields: [playerId], references: [id])
// Session and account references for Better Auth
sessions Session[]
accounts Account[]
// Link to EuchreCamp player (optional)
playerId Int? @unique
player Player? @relation(fields: [playerId], references: [id])
// Tournaments owned by this user
ownedTournaments Event[] @relation("TournamentOwner")
// Matches created by this user
createdMatches Match[] @relation("MatchCreator")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users")
}
// Event (Tournament) Model
model Event {
id Int @id @default(autoincrement())
event_id Int?
name String
description String?
eventDate DateTime?
eventType String @default("tournament")
format String @default("round_robin")
status String @default("planned")
id Int @id @default(autoincrement())
event_id Int?
name String
description String?
eventDate DateTime?
eventType String @default("tournament")
format String @default("round_robin")
status String @default("planned")
maxParticipants Int?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relationships
participants EventParticipant[]
teams Team[]
rounds TournamentRound[]
bracketMatchups BracketMatchup[]
matches Match[]
ownerId String? // User ID of the tournament owner (for tournament_admin)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
bracketMatchups BracketMatchup[]
participants EventParticipant[]
matches Match[]
teams Team[]
rounds TournamentRound[]
owner User? @relation("TournamentOwner", fields: [ownerId], references: [id])
@@map("events")
}
// EventParticipant Model
model EventParticipant {
id Int @id @default(autoincrement())
eventId Int
playerId Int
teamId Int?
seed Int?
status String @default("registered")
id Int @id @default(autoincrement())
eventId Int
playerId Int
teamId 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])
team Team? @relation(fields: [teamId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
team Team? @relation(fields: [teamId], references: [id])
player Player @relation(fields: [playerId], references: [id])
event Event @relation(fields: [eventId], references: [id])
@@map("event_participants")
}
// Team Model
model Team {
id Int @id @default(autoincrement())
eventId Int
teamName String?
player1Id Int
player2Id Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relationships
event Event @relation(fields: [eventId], references: [id])
player1 Player @relation("TeamPlayer1", fields: [player1Id], references: [id])
player2 Player @relation("TeamPlayer2", fields: [player2Id], references: [id])
eventParticipants EventParticipant[]
bracketMatchups1 BracketMatchup[] @relation("BracketTeam1")
bracketMatchups2 BracketMatchup[] @relation("BracketTeam2")
id Int @id @default(autoincrement())
eventId Int
teamName String?
player1Id Int
player2Id Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
bracketMatchups2 BracketMatchup[] @relation("BracketTeam2")
bracketMatchups1 BracketMatchup[] @relation("BracketTeam1")
eventParticipants EventParticipant[]
player2 Player @relation("TeamPlayer2", fields: [player2Id], references: [id])
player1 Player @relation("TeamPlayer1", fields: [player1Id], references: [id])
event Event @relation(fields: [eventId], references: [id])
@@map("teams")
}
// TournamentRound Model
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
event Event @relation(fields: [eventId], references: [id])
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")
}
// BracketMatchup Model
model BracketMatchup {
id Int @id @default(autoincrement())
roundId Int
eventId Int
team1Id Int?
team2Id Int?
matchId Int?
tableNumber Int?
id Int @id @default(autoincrement())
roundId Int
eventId Int
team1Id Int?
team2Id Int?
matchId Int?
tableNumber Int?
bracketPosition Int?
winnerTeamId Int?
loserTeamId Int?
status String @default("pending")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
round TournamentRound @relation(fields: [roundId], references: [id])
event Event @relation(fields: [eventId], references: [id])
team1 Team? @relation("BracketTeam1", fields: [team1Id], references: [id])
team2 Team? @relation("BracketTeam2", fields: [team2Id], references: [id])
match Match? @relation(fields: [matchId], references: [id])
winnerTeamId Int?
loserTeamId Int?
status String @default("pending")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
match Match? @relation(fields: [matchId], references: [id])
team2 Team? @relation("BracketTeam2", fields: [team2Id], references: [id])
team1 Team? @relation("BracketTeam1", fields: [team1Id], references: [id])
event Event @relation(fields: [eventId], references: [id])
round TournamentRound @relation(fields: [roundId], references: [id])
@@map("bracket_matchups")
}
// Match Model
model Match {
id Int @id @default(autoincrement())
eventId Int?
playedAt DateTime?
team1P1Id Int
team1P2Id Int
team2P1Id Int
team2P2Id Int
team1Score Int
team2Score Int
status String @default("completed")
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
event Event? @relation(fields: [eventId], references: [id])
team1P1 Player @relation("MatchPlayer1", fields: [team1P1Id], references: [id])
team1P2 Player @relation("MatchPlayer2", fields: [team1P2Id], references: [id])
team2P1 Player @relation("MatchPlayer3", fields: [team2P1Id], references: [id])
team2P2 Player @relation("MatchPlayer4", fields: [team2P2Id], references: [id])
eloSnapshots EloSnapshot[]
id Int @id @default(autoincrement())
eventId Int?
playedAt DateTime?
team1P1Id Int
team1P2Id Int
team2P1Id Int
team2P2Id Int
team1Score Int
team2Score Int
status String @default("completed")
createdById String? // User ID of the match creator (for tournament_admin)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
bracketMatchups BracketMatchup[]
eloSnapshots EloSnapshot[]
team2P2 Player @relation("MatchPlayer4", fields: [team2P2Id], references: [id])
team2P1 Player @relation("MatchPlayer3", fields: [team2P1Id], references: [id])
team1P2 Player @relation("MatchPlayer2", fields: [team1P2Id], references: [id])
team1P1 Player @relation("MatchPlayer1", fields: [team1P1Id], references: [id])
event Event? @relation(fields: [eventId], references: [id])
partnershipGames PartnershipGame[]
bracketMatchups BracketMatchup[]
createdBy User? @relation("MatchCreator", fields: [createdById], references: [id])
@@map("matches")
}
// EloSnapshot Model
model EloSnapshot {
id Int @id @default(autoincrement())
playerId Int
@@ -204,47 +195,90 @@ model EloSnapshot {
ratingAfter Int
ratingChange Int
createdAt DateTime @default(now())
player Player @relation(fields: [playerId], references: [id])
match Match @relation(fields: [matchId], references: [id])
match Match @relation(fields: [matchId], references: [id])
player Player @relation(fields: [playerId], references: [id])
@@map("elo_snapshots")
}
// PartnershipGame Model - Tracks each game played by a partnership
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())
player1 Player @relation("PartnershipPlayer1", fields: [player1Id], references: [id])
player2 Player @relation("PartnershipPlayer2", fields: [player2Id], references: [id])
match Match @relation(fields: [matchId], references: [id])
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])
player2 Player @relation("PartnershipPlayer2", fields: [player2Id], references: [id])
player1 Player @relation("PartnershipPlayer1", fields: [player1Id], references: [id])
@@map("partnership_games")
}
// PartnershipStat Model - Aggregated partnership statistics
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])
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
player2 Player @relation("StatPlayer2", fields: [player2Id], references: [id])
player1 Player @relation("StatPlayer1", fields: [player1Id], references: [id])
@@map("partnership_stats")
}
model Session {
id String @id
expiresAt DateTime
token String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
ipAddress String?
userAgent String?
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([token])
@@index([userId])
@@map("session")
}
model Account {
id String @id
accountId String
providerId String
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
accessToken String?
refreshToken String?
idToken String?
accessTokenExpiresAt DateTime?
refreshTokenExpiresAt DateTime?
scope String?
password String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@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")
}