✅ FASE 3 COMPLETADA: Torneos y Ligas
Implementados 3 módulos con agent swarm: 1. SISTEMA DE TORNEOS - Tipos: Eliminación, Round Robin, Suizo, Consolación - Categorías: Masculina, Femenina, Mixta - Inscripciones con validación de niveles - Gestión de pagos y estados 2. CUADROS Y PARTIDOS - Generación automática de cuadros - Algoritmos: Circle method (Round Robin), Swiss pairing - Avance automático de ganadores - Asignación de canchas y horarios - Registro y confirmación de resultados 3. LIGAS POR EQUIPOS - Creación de equipos con capitán - Calendario round-robin automático - Tabla de clasificación con desempates - Estadísticas por equipo Modelos DB: - Tournament, TournamentParticipant, TournamentMatch - League, LeagueTeam, LeagueTeamMember, LeagueMatch, LeagueStanding Nuevos endpoints: - /tournaments/* - Gestión de torneos - /tournaments/:id/draw/* - Cuadros - /tournaments/:id/matches/* - Partidos de torneo - /leagues/* - Ligas - /league-teams/* - Equipos - /league-schedule/* - Calendario - /league-standings/* - Clasificación - /league-matches/* - Partidos de liga Datos de prueba: - Torneo de Verano 2024 (Eliminatoria) - Liga de Invierno (Round Robin) - Liga de Club 2024
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,258 @@
|
||||
-- CreateTable
|
||||
CREATE TABLE "tournaments" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"type" TEXT NOT NULL,
|
||||
"category" TEXT NOT NULL,
|
||||
"allowedLevels" TEXT NOT NULL,
|
||||
"maxParticipants" INTEGER NOT NULL,
|
||||
"registrationStartDate" DATETIME NOT NULL,
|
||||
"registrationEndDate" DATETIME NOT NULL,
|
||||
"startDate" DATETIME NOT NULL,
|
||||
"endDate" DATETIME NOT NULL,
|
||||
"courtIds" TEXT NOT NULL,
|
||||
"price" INTEGER NOT NULL DEFAULT 0,
|
||||
"status" TEXT NOT NULL DEFAULT 'DRAFT',
|
||||
"createdById" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "tournaments_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "tournament_participants" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"tournamentId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"registrationDate" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"paymentStatus" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"seed" INTEGER,
|
||||
"status" TEXT NOT NULL DEFAULT 'REGISTERED',
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "tournament_participants_tournamentId_fkey" FOREIGN KEY ("tournamentId") REFERENCES "tournaments" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "tournament_participants_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "tournament_matches" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"tournamentId" TEXT NOT NULL,
|
||||
"round" INTEGER NOT NULL,
|
||||
"matchNumber" INTEGER NOT NULL,
|
||||
"position" INTEGER NOT NULL,
|
||||
"team1Player1Id" TEXT,
|
||||
"team1Player2Id" TEXT,
|
||||
"team2Player1Id" TEXT,
|
||||
"team2Player2Id" TEXT,
|
||||
"courtId" TEXT,
|
||||
"scheduledDate" DATETIME,
|
||||
"scheduledTime" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'PENDING',
|
||||
"team1Score" INTEGER,
|
||||
"team2Score" INTEGER,
|
||||
"winner" TEXT,
|
||||
"nextMatchId" TEXT,
|
||||
"confirmedBy" TEXT NOT NULL DEFAULT '[]',
|
||||
"metadata" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "tournament_matches_tournamentId_fkey" FOREIGN KEY ("tournamentId") REFERENCES "tournaments" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "tournament_matches_team1Player1Id_fkey" FOREIGN KEY ("team1Player1Id") REFERENCES "tournament_participants" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "tournament_matches_team1Player2Id_fkey" FOREIGN KEY ("team1Player2Id") REFERENCES "tournament_participants" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "tournament_matches_team2Player1Id_fkey" FOREIGN KEY ("team2Player1Id") REFERENCES "tournament_participants" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "tournament_matches_team2Player2Id_fkey" FOREIGN KEY ("team2Player2Id") REFERENCES "tournament_participants" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "tournament_matches_courtId_fkey" FOREIGN KEY ("courtId") REFERENCES "courts" ("id") ON DELETE SET NULL ON UPDATE CASCADE,
|
||||
CONSTRAINT "tournament_matches_nextMatchId_fkey" FOREIGN KEY ("nextMatchId") REFERENCES "tournament_matches" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "leagues" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"type" TEXT NOT NULL DEFAULT 'TEAM_LEAGUE',
|
||||
"format" TEXT NOT NULL DEFAULT 'DOUBLE_ROUND_ROBIN',
|
||||
"matchesPerMatchday" INTEGER NOT NULL DEFAULT 2,
|
||||
"startDate" DATETIME,
|
||||
"endDate" DATETIME,
|
||||
"status" TEXT NOT NULL DEFAULT 'DRAFT',
|
||||
"createdById" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "leagues_createdById_fkey" FOREIGN KEY ("createdById") REFERENCES "users" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "league_teams" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"name" TEXT NOT NULL,
|
||||
"description" TEXT,
|
||||
"leagueId" TEXT NOT NULL,
|
||||
"captainId" TEXT NOT NULL,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
CONSTRAINT "league_teams_leagueId_fkey" FOREIGN KEY ("leagueId") REFERENCES "leagues" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "league_teams_captainId_fkey" FOREIGN KEY ("captainId") REFERENCES "users" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "league_team_members" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"teamId" TEXT NOT NULL,
|
||||
"userId" TEXT NOT NULL,
|
||||
"isActive" BOOLEAN NOT NULL DEFAULT true,
|
||||
"joinedAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "league_team_members_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "league_teams" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "league_team_members_userId_fkey" FOREIGN KEY ("userId") REFERENCES "users" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "league_matches" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"leagueId" TEXT NOT NULL,
|
||||
"matchday" INTEGER NOT NULL,
|
||||
"team1Id" TEXT NOT NULL,
|
||||
"team2Id" TEXT NOT NULL,
|
||||
"courtId" TEXT,
|
||||
"scheduledDate" DATETIME,
|
||||
"scheduledTime" TEXT,
|
||||
"status" TEXT NOT NULL DEFAULT 'SCHEDULED',
|
||||
"team1Score" INTEGER,
|
||||
"team2Score" INTEGER,
|
||||
"setDetails" TEXT,
|
||||
"winner" TEXT,
|
||||
"completedAt" DATETIME,
|
||||
"notes" TEXT,
|
||||
"createdAt" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "league_matches_leagueId_fkey" FOREIGN KEY ("leagueId") REFERENCES "leagues" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "league_matches_team1Id_fkey" FOREIGN KEY ("team1Id") REFERENCES "league_teams" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "league_matches_team2Id_fkey" FOREIGN KEY ("team2Id") REFERENCES "league_teams" ("id") ON DELETE RESTRICT ON UPDATE CASCADE,
|
||||
CONSTRAINT "league_matches_courtId_fkey" FOREIGN KEY ("courtId") REFERENCES "courts" ("id") ON DELETE SET NULL ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "league_standings" (
|
||||
"id" TEXT NOT NULL PRIMARY KEY,
|
||||
"leagueId" TEXT NOT NULL,
|
||||
"teamId" TEXT NOT NULL,
|
||||
"matchesPlayed" INTEGER NOT NULL DEFAULT 0,
|
||||
"matchesWon" INTEGER NOT NULL DEFAULT 0,
|
||||
"matchesLost" INTEGER NOT NULL DEFAULT 0,
|
||||
"matchesDrawn" INTEGER NOT NULL DEFAULT 0,
|
||||
"setsFor" INTEGER NOT NULL DEFAULT 0,
|
||||
"setsAgainst" INTEGER NOT NULL DEFAULT 0,
|
||||
"gamesFor" INTEGER NOT NULL DEFAULT 0,
|
||||
"gamesAgainst" INTEGER NOT NULL DEFAULT 0,
|
||||
"points" INTEGER NOT NULL DEFAULT 0,
|
||||
"position" INTEGER NOT NULL DEFAULT 0,
|
||||
"updatedAt" DATETIME NOT NULL,
|
||||
CONSTRAINT "league_standings_leagueId_fkey" FOREIGN KEY ("leagueId") REFERENCES "leagues" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT "league_standings_teamId_fkey" FOREIGN KEY ("teamId") REFERENCES "league_teams" ("id") ON DELETE CASCADE ON UPDATE CASCADE
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournaments_status_idx" ON "tournaments"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournaments_createdById_idx" ON "tournaments"("createdById");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournaments_startDate_idx" ON "tournaments"("startDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournaments_registrationStartDate_idx" ON "tournaments"("registrationStartDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_participants_tournamentId_idx" ON "tournament_participants"("tournamentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_participants_userId_idx" ON "tournament_participants"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_participants_paymentStatus_idx" ON "tournament_participants"("paymentStatus");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_participants_status_idx" ON "tournament_participants"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "tournament_participants_tournamentId_userId_key" ON "tournament_participants"("tournamentId", "userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_matches_tournamentId_idx" ON "tournament_matches"("tournamentId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_matches_round_idx" ON "tournament_matches"("round");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_matches_status_idx" ON "tournament_matches"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_matches_courtId_idx" ON "tournament_matches"("courtId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_matches_nextMatchId_idx" ON "tournament_matches"("nextMatchId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "tournament_matches_tournamentId_round_idx" ON "tournament_matches"("tournamentId", "round");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "leagues_status_idx" ON "leagues"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "leagues_createdById_idx" ON "leagues"("createdById");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "leagues_startDate_idx" ON "leagues"("startDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_teams_leagueId_idx" ON "league_teams"("leagueId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_teams_captainId_idx" ON "league_teams"("captainId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "league_teams_leagueId_name_key" ON "league_teams"("leagueId", "name");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_team_members_teamId_idx" ON "league_team_members"("teamId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_team_members_userId_idx" ON "league_team_members"("userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "league_team_members_teamId_userId_key" ON "league_team_members"("teamId", "userId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_matches_leagueId_idx" ON "league_matches"("leagueId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_matches_matchday_idx" ON "league_matches"("matchday");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_matches_team1Id_idx" ON "league_matches"("team1Id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_matches_team2Id_idx" ON "league_matches"("team2Id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_matches_status_idx" ON "league_matches"("status");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_matches_scheduledDate_idx" ON "league_matches"("scheduledDate");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "league_standings_teamId_key" ON "league_standings"("teamId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_standings_leagueId_idx" ON "league_standings"("leagueId");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_standings_position_idx" ON "league_standings"("position");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "league_standings_points_idx" ON "league_standings"("points");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "league_standings_leagueId_teamId_key" ON "league_standings"("leagueId", "teamId");
|
||||
@@ -64,9 +64,18 @@ model User {
|
||||
groupsCreated Group[] @relation("GroupsCreated")
|
||||
groupMembers GroupMember[] @relation("GroupMemberships")
|
||||
|
||||
// Ligas
|
||||
leaguesCreated League[] @relation("LeaguesCreated") // Ligas creadas por el usuario
|
||||
teamCaptain LeagueTeam[] @relation("TeamCaptain") // Equipos donde es capitán
|
||||
leagueTeamMembers LeagueTeamMember[] // Membresías de equipo en liga
|
||||
|
||||
// Reservas recurrentes
|
||||
recurringBookings RecurringBooking[]
|
||||
|
||||
// Torneos
|
||||
tournamentsCreated Tournament[] @relation("TournamentsCreated")
|
||||
tournamentParticipations TournamentParticipant[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -121,6 +130,8 @@ model Court {
|
||||
bookings Booking[]
|
||||
schedules CourtSchedule[]
|
||||
recurringBookings RecurringBooking[]
|
||||
leagueMatches LeagueMatch[]
|
||||
tournamentMatches TournamentMatch[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -381,3 +392,368 @@ model UserStats {
|
||||
@@index([points])
|
||||
@@map("user_stats")
|
||||
}
|
||||
|
||||
// Modelo de Torneo
|
||||
model Tournament {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
description String?
|
||||
|
||||
// Tipo de torneo
|
||||
type String // ELIMINATION, ROUND_ROBIN, SWISS, CONSOLATION
|
||||
|
||||
// Categoría
|
||||
category String // MEN, WOMEN, MIXED
|
||||
|
||||
// Niveles permitidos (almacenados como JSON string)
|
||||
allowedLevels String
|
||||
|
||||
// Capacidad
|
||||
maxParticipants Int
|
||||
|
||||
// Fechas importantes
|
||||
registrationStartDate DateTime
|
||||
registrationEndDate DateTime
|
||||
startDate DateTime
|
||||
endDate DateTime
|
||||
|
||||
// Canchas asignadas (almacenadas como JSON string de IDs)
|
||||
courtIds String
|
||||
|
||||
// Precio de inscripción (en centavos)
|
||||
price Int @default(0)
|
||||
|
||||
// Estado del torneo
|
||||
status String @default("DRAFT") // DRAFT, OPEN, CLOSED, IN_PROGRESS, FINISHED, CANCELLED
|
||||
|
||||
// Creador (admin)
|
||||
createdBy User @relation("TournamentsCreated", fields: [createdById], references: [id])
|
||||
createdById String
|
||||
|
||||
// Relaciones
|
||||
participants TournamentParticipant[] @relation("TournamentParticipants")
|
||||
matches TournamentMatch[]
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([status])
|
||||
@@index([createdById])
|
||||
@@index([startDate])
|
||||
@@index([registrationStartDate])
|
||||
@@map("tournaments")
|
||||
}
|
||||
|
||||
// Modelo de Participante de Torneo
|
||||
model TournamentParticipant {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Torneo
|
||||
tournament Tournament @relation("TournamentParticipants", fields: [tournamentId], references: [id], onDelete: Cascade)
|
||||
tournamentId String
|
||||
|
||||
// Usuario (jugador individual)
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
|
||||
// Fecha de inscripción
|
||||
registrationDate DateTime @default(now())
|
||||
|
||||
// Estado del pago
|
||||
paymentStatus String @default("PENDING") // PENDING, PAID, REFUNDED
|
||||
|
||||
// Número de cabeza de serie (opcional)
|
||||
seed Int?
|
||||
|
||||
// Estado de la inscripción
|
||||
status String @default("REGISTERED") // REGISTERED, CONFIRMED, WITHDRAWN
|
||||
|
||||
// Timestamps
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
// Relaciones con partidos (como jugador individual)
|
||||
team1Player1Matches TournamentMatch[] @relation("T1P1")
|
||||
team1Player2Matches TournamentMatch[] @relation("T1P2")
|
||||
team2Player1Matches TournamentMatch[] @relation("T2P1")
|
||||
team2Player2Matches TournamentMatch[] @relation("T2P2")
|
||||
|
||||
@@unique([tournamentId, userId])
|
||||
@@index([tournamentId])
|
||||
@@index([userId])
|
||||
@@index([paymentStatus])
|
||||
@@index([status])
|
||||
@@map("tournament_participants")
|
||||
}
|
||||
|
||||
// Modelo de Partido de Torneo
|
||||
model TournamentMatch {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Torneo
|
||||
tournament Tournament @relation(fields: [tournamentId], references: [id], onDelete: Cascade)
|
||||
tournamentId String
|
||||
|
||||
// Ronda (1=final, 2=semifinal, etc. o número de ronda en liga)
|
||||
round Int
|
||||
|
||||
// Número de partido en la ronda
|
||||
matchNumber Int
|
||||
|
||||
// Posición en el cuadro
|
||||
position Int
|
||||
|
||||
// Equipo 1 (pareja o individual)
|
||||
team1Player1 TournamentParticipant? @relation("T1P1", fields: [team1Player1Id], references: [id], onDelete: SetNull)
|
||||
team1Player1Id String?
|
||||
team1Player2 TournamentParticipant? @relation("T1P2", fields: [team1Player2Id], references: [id], onDelete: SetNull)
|
||||
team1Player2Id String?
|
||||
|
||||
// Equipo 2 (pareja o individual)
|
||||
team2Player1 TournamentParticipant? @relation("T2P1", fields: [team2Player1Id], references: [id], onDelete: SetNull)
|
||||
team2Player1Id String?
|
||||
team2Player2 TournamentParticipant? @relation("T2P2", fields: [team2Player2Id], references: [id], onDelete: SetNull)
|
||||
team2Player2Id String?
|
||||
|
||||
// Cancha asignada
|
||||
court Court? @relation(fields: [courtId], references: [id], onDelete: SetNull)
|
||||
courtId String?
|
||||
|
||||
// Fecha y hora programada
|
||||
scheduledDate DateTime?
|
||||
scheduledTime String?
|
||||
|
||||
// Estado del partido
|
||||
status String @default("PENDING") // PENDING, SCHEDULED, IN_PROGRESS, FINISHED, CANCELLED, BYE
|
||||
|
||||
// Resultado
|
||||
team1Score Int?
|
||||
team2Score Int?
|
||||
winner String? // TEAM1, TEAM2, DRAW
|
||||
|
||||
// Avance en cuadro
|
||||
nextMatch TournamentMatch? @relation("NextMatch", fields: [nextMatchId], references: [id], onDelete: SetNull)
|
||||
nextMatchId String?
|
||||
parentMatches TournamentMatch[] @relation("NextMatch")
|
||||
|
||||
// Confirmaciones del resultado (JSON array de userIds)
|
||||
confirmedBy String @default("[]")
|
||||
|
||||
// Metadatos adicionales (para sistemas suizo, round robin, etc)
|
||||
metadata String? // JSON string con datos adicionales
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([tournamentId])
|
||||
@@index([round])
|
||||
@@index([status])
|
||||
@@index([courtId])
|
||||
@@index([nextMatchId])
|
||||
@@index([tournamentId, round])
|
||||
@@map("tournament_matches")
|
||||
}
|
||||
|
||||
|
||||
// ============================================
|
||||
// Modelos de Liga por Equipos (Fase 3.3)
|
||||
// ============================================
|
||||
|
||||
// Modelo de Liga
|
||||
model League {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
description String?
|
||||
|
||||
// Tipo y formato
|
||||
type String @default("TEAM_LEAGUE") // TEAM_LEAGUE, INDIVIDUAL_LEAGUE
|
||||
format String @default("DOUBLE_ROUND_ROBIN") // SINGLE_ROUND_ROBIN, DOUBLE_ROUND_ROBIN, etc.
|
||||
|
||||
// Configuración de partidos por jornada
|
||||
matchesPerMatchday Int @default(2) // Número de partidos entre dos equipos por jornada
|
||||
|
||||
// Fechas
|
||||
startDate DateTime?
|
||||
endDate DateTime?
|
||||
|
||||
// Estado
|
||||
status String @default("DRAFT") // DRAFT, ACTIVE, FINISHED, CANCELLED
|
||||
|
||||
// Creador (admin)
|
||||
createdBy User @relation("LeaguesCreated", fields: [createdById], references: [id])
|
||||
createdById String
|
||||
|
||||
// Relaciones
|
||||
teams LeagueTeam[]
|
||||
matches LeagueMatch[]
|
||||
standings LeagueStanding[]
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([status])
|
||||
@@index([createdById])
|
||||
@@index([startDate])
|
||||
@@map("leagues")
|
||||
}
|
||||
|
||||
// Modelo de Equipo en Liga
|
||||
model LeagueTeam {
|
||||
id String @id @default(uuid())
|
||||
name String
|
||||
description String?
|
||||
|
||||
// Liga
|
||||
league League @relation(fields: [leagueId], references: [id], onDelete: Cascade)
|
||||
leagueId String
|
||||
|
||||
// Capitán del equipo
|
||||
captain User @relation("TeamCaptain", fields: [captainId], references: [id])
|
||||
captainId String
|
||||
|
||||
// Relaciones
|
||||
members LeagueTeamMember[]
|
||||
|
||||
// Partidos como equipo 1 o 2
|
||||
matchesAsTeam1 LeagueMatch[] @relation("Team1Matches")
|
||||
matchesAsTeam2 LeagueMatch[] @relation("Team2Matches")
|
||||
|
||||
// Clasificación
|
||||
standing LeagueStanding?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@unique([leagueId, name])
|
||||
@@index([leagueId])
|
||||
@@index([captainId])
|
||||
@@map("league_teams")
|
||||
}
|
||||
|
||||
// Modelo de Miembro de Equipo
|
||||
model LeagueTeamMember {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Equipo
|
||||
team LeagueTeam @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||||
teamId String
|
||||
|
||||
// Usuario
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
userId String
|
||||
|
||||
// Estado
|
||||
isActive Boolean @default(true)
|
||||
|
||||
// Fecha de unión
|
||||
joinedAt DateTime @default(now())
|
||||
|
||||
// Timestamps
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([teamId, userId])
|
||||
@@index([teamId])
|
||||
@@index([userId])
|
||||
@@map("league_team_members")
|
||||
}
|
||||
|
||||
// Modelo de Partido de Liga
|
||||
model LeagueMatch {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Liga
|
||||
league League @relation(fields: [leagueId], references: [id], onDelete: Cascade)
|
||||
leagueId String
|
||||
|
||||
// Jornada
|
||||
matchday Int // Número de jornada
|
||||
|
||||
// Equipos
|
||||
team1 LeagueTeam @relation("Team1Matches", fields: [team1Id], references: [id])
|
||||
team1Id String
|
||||
team2 LeagueTeam @relation("Team2Matches", fields: [team2Id], references: [id])
|
||||
team2Id String
|
||||
|
||||
// Cancha y horario (opcional)
|
||||
court Court? @relation(fields: [courtId], references: [id], onDelete: SetNull)
|
||||
courtId String?
|
||||
|
||||
scheduledDate DateTime? // Fecha programada
|
||||
scheduledTime String? // Hora programada (formato HH:mm)
|
||||
|
||||
// Estado
|
||||
status String @default("SCHEDULED") // SCHEDULED, CONFIRMED, IN_PROGRESS, COMPLETED, CANCELLED, POSTPONED, WALKOVER
|
||||
|
||||
// Resultado
|
||||
team1Score Int? // Sets ganados por equipo 1
|
||||
team2Score Int? // Sets ganados por equipo 2
|
||||
|
||||
// Detalle de sets (almacenado como JSON)
|
||||
// Ej: [{team1Games: 6, team2Games: 4}, {team1Games: 6, team2Games: 2}]
|
||||
setDetails String?
|
||||
|
||||
// Ganador
|
||||
winner String? // TEAM1, TEAM2, DRAW
|
||||
|
||||
// Fecha de finalización
|
||||
completedAt DateTime?
|
||||
|
||||
// Notas
|
||||
notes String?
|
||||
|
||||
// Timestamps
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@index([leagueId])
|
||||
@@index([matchday])
|
||||
@@index([team1Id])
|
||||
@@index([team2Id])
|
||||
@@index([status])
|
||||
@@index([scheduledDate])
|
||||
@@map("league_matches")
|
||||
}
|
||||
|
||||
// Modelo de Clasificación
|
||||
model LeagueStanding {
|
||||
id String @id @default(uuid())
|
||||
|
||||
// Liga
|
||||
league League @relation(fields: [leagueId], references: [id], onDelete: Cascade)
|
||||
leagueId String
|
||||
|
||||
// Equipo
|
||||
team LeagueTeam @relation(fields: [teamId], references: [id], onDelete: Cascade)
|
||||
teamId String @unique
|
||||
|
||||
// Partidos
|
||||
matchesPlayed Int @default(0)
|
||||
matchesWon Int @default(0)
|
||||
matchesLost Int @default(0)
|
||||
matchesDrawn Int @default(0)
|
||||
|
||||
// Sets
|
||||
setsFor Int @default(0)
|
||||
setsAgainst Int @default(0)
|
||||
|
||||
// Games (opcional)
|
||||
gamesFor Int @default(0)
|
||||
gamesAgainst Int @default(0)
|
||||
|
||||
// Puntos
|
||||
points Int @default(0)
|
||||
|
||||
// Posición actual
|
||||
position Int @default(0)
|
||||
|
||||
// Timestamps
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@unique([leagueId, teamId])
|
||||
@@index([leagueId])
|
||||
@@index([position])
|
||||
@@index([points])
|
||||
@@map("league_standings")
|
||||
}
|
||||
|
||||
96
backend/prisma/seed-fase3.ts
Normal file
96
backend/prisma/seed-fase3.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
async function main() {
|
||||
console.log('🌱 Seeding Fase 3 - Torneos y Ligas...\n');
|
||||
|
||||
const admin = await prisma.user.findUnique({ where: { email: 'admin@padel.com' } });
|
||||
|
||||
if (!admin) {
|
||||
console.log('❌ Admin no encontrado. Ejecuta seed.ts primero.');
|
||||
return;
|
||||
}
|
||||
|
||||
const courts = await prisma.court.findMany({ where: { isActive: true }, take: 2 });
|
||||
const courtIds = JSON.stringify(courts.map(c => c.id));
|
||||
|
||||
// Crear torneo de eliminatoria
|
||||
const tournament1 = await prisma.tournament.upsert({
|
||||
where: { id: 'tour-1' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'tour-1',
|
||||
name: 'Torneo de Verano 2024',
|
||||
description: 'Torneo eliminatorio mixto para todos los niveles',
|
||||
type: 'ELIMINATION',
|
||||
category: 'MIXED',
|
||||
allowedLevels: JSON.stringify(['BEGINNER', 'ELEMENTARY', 'INTERMEDIATE']),
|
||||
maxParticipants: 16,
|
||||
registrationStartDate: new Date(),
|
||||
registrationEndDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||
startDate: new Date(Date.now() + 14 * 24 * 60 * 60 * 1000),
|
||||
endDate: new Date(Date.now() + 21 * 24 * 60 * 60 * 1000),
|
||||
courtIds: courtIds,
|
||||
price: 2000,
|
||||
status: 'OPEN',
|
||||
createdById: admin.id,
|
||||
},
|
||||
});
|
||||
console.log(`✅ Torneo creado: ${tournament1.name}`);
|
||||
|
||||
// Crear torneo round robin
|
||||
const tournament2 = await prisma.tournament.upsert({
|
||||
where: { id: 'tour-2' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'tour-2',
|
||||
name: 'Liga de Invierno - Individual',
|
||||
description: 'Liga todos contra todos',
|
||||
type: 'ROUND_ROBIN',
|
||||
category: 'MEN',
|
||||
allowedLevels: JSON.stringify(['INTERMEDIATE', 'ADVANCED', 'COMPETITION']),
|
||||
maxParticipants: 8,
|
||||
registrationStartDate: new Date(),
|
||||
registrationEndDate: new Date(Date.now() + 10 * 24 * 60 * 60 * 1000),
|
||||
startDate: new Date(Date.now() + 17 * 24 * 60 * 60 * 1000),
|
||||
endDate: new Date(Date.now() + 60 * 24 * 60 * 60 * 1000),
|
||||
courtIds: courtIds,
|
||||
price: 3000,
|
||||
status: 'DRAFT',
|
||||
createdById: admin.id,
|
||||
},
|
||||
});
|
||||
console.log(`✅ Torneo creado: ${tournament2.name}`);
|
||||
|
||||
// Crear una liga por equipos
|
||||
const league = await prisma.league.upsert({
|
||||
where: { id: 'league-1' },
|
||||
update: {},
|
||||
create: {
|
||||
id: 'league-1',
|
||||
name: 'Liga de Club 2024',
|
||||
description: 'Liga interna del club por equipos',
|
||||
format: 'SINGLE_ROUND_ROBIN',
|
||||
startDate: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000),
|
||||
endDate: new Date(Date.now() + 90 * 24 * 60 * 60 * 1000),
|
||||
status: 'DRAFT',
|
||||
createdById: admin.id,
|
||||
},
|
||||
});
|
||||
console.log(`✅ Liga creada: ${league.name}`);
|
||||
|
||||
console.log('\n🎾 Fase 3 seed completado!');
|
||||
console.log('\nDatos creados:');
|
||||
console.log(` - 2 Torneos (Eliminatoria, Round Robin)`);
|
||||
console.log(` - 1 Liga por equipos`);
|
||||
}
|
||||
|
||||
main()
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
process.exit(1);
|
||||
})
|
||||
.finally(async () => {
|
||||
await prisma.$disconnect();
|
||||
});
|
||||
Reference in New Issue
Block a user