// This is your Prisma schema file, // learn more about it in the docs: https://pris.ly/d/prisma-schema generator client { provider = "prisma-client-js" } datasource db { provider = "sqlite" url = env("DATABASE_URL") } // Modelo de Usuario model User { id String @id @default(uuid()) email String @unique password String // Datos personales firstName String lastName String phone String? avatarUrl String? city String? birthDate DateTime? // Datos de juego (usamos String para simular enums en SQLite) role String @default("PLAYER") // PLAYER, ADMIN, SUPERADMIN playerLevel String @default("BEGINNER") // BEGINNER, ELEMENTARY, INTERMEDIATE, ADVANCED, COMPETITION, PROFESSIONAL handPreference String @default("RIGHT") // RIGHT, LEFT, BOTH positionPreference String @default("BOTH") // DRIVE, BACKHAND, BOTH bio String? yearsPlaying Int? // Estadísticas globales matchesPlayed Int @default(0) matchesWon Int @default(0) matchesLost Int @default(0) totalPoints Int @default(0) // Estado isActive Boolean @default(true) isVerified Boolean @default(false) lastLogin DateTime? // Relaciones bookings Booking[] levelHistory LevelHistory[] // Relaciones con MatchResult team1Player1Matches MatchResult[] @relation("Team1Player1") team1Player2Matches MatchResult[] @relation("Team1Player2") team2Player1Matches MatchResult[] @relation("Team2Player1") team2Player2Matches MatchResult[] @relation("Team2Player2") // Relación con UserStats userStats UserStats[] // Amistades friendsSent Friend[] @relation("FriendRequestsSent") friendsReceived Friend[] @relation("FriendRequestsReceived") // Grupos 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 @@map("users") } // Modelo de Historial de Niveles model LevelHistory { id String @id @default(uuid()) // Niveles oldLevel String newLevel String // Referencias user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String // Quién realizó el cambio (admin) changedBy String // Metadata reason String? createdAt DateTime @default(now()) @@index([userId]) @@map("level_history") } // Modelo de Cancha model Court { id String @id @default(uuid()) name String @unique description String? // Características type String @default("PANORAMIC") // PANORAMIC, OUTDOOR, INDOOR, SINGLE isIndoor Boolean @default(false) hasLighting Boolean @default(true) hasParking Boolean @default(false) // Precio por hora (en centavos para evitar decimales) pricePerHour Int @default(2000) // Imagen imageUrl String? // Estado isActive Boolean @default(true) // Relaciones bookings Booking[] schedules CourtSchedule[] recurringBookings RecurringBooking[] leagueMatches LeagueMatch[] tournamentMatches TournamentMatch[] createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@map("courts") } // Modelo de Horarios de Cancha (días y horas de operación) model CourtSchedule { id String @id @default(uuid()) // Día de la semana (0=Domingo, 1=Lunes, ..., 6=Sábado) dayOfWeek Int // Horario openTime String closeTime String // Precio especial para esta franja (opcional) priceOverride Int? // Relación court Court @relation(fields: [courtId], references: [id], onDelete: Cascade) courtId String @@unique([courtId, dayOfWeek]) @@map("court_schedules") } // Modelo de Reserva model Booking { id String @id @default(uuid()) // Fecha y hora date DateTime startTime String endTime String // Estado (PENDING, CONFIRMED, CANCELLED, COMPLETED, NO_SHOW) status String @default("PENDING") // Precio totalPrice Int // Notas notes String? // Relaciones user User @relation(fields: [userId], references: [id]) userId String court Court @relation(fields: [courtId], references: [id]) courtId String // Relación con MatchResult matchResult MatchResult? // Referencia a reserva recurrente (si aplica) recurringBooking RecurringBooking? @relation(fields: [recurringBookingId], references: [id]) recurringBookingId String? // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId]) @@index([courtId]) @@index([date]) @@index([recurringBookingId]) @@map("bookings") } // Modelo de Amistad model Friend { id String @id @default(uuid()) // Quien envía la solicitud requester User @relation("FriendRequestsSent", fields: [requesterId], references: [id]) requesterId String // Quien recibe la solicitud addressee User @relation("FriendRequestsReceived", fields: [addresseeId], references: [id]) addresseeId String // Estado (PENDING, ACCEPTED, REJECTED, BLOCKED) status String @default("PENDING") // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([requesterId, addresseeId]) @@index([requesterId]) @@index([addresseeId]) @@index([status]) @@map("friends") } // Modelo de Grupo model Group { id String @id @default(uuid()) name String description String? // Creador del grupo createdBy User @relation("GroupsCreated", fields: [createdById], references: [id]) createdById String // Relaciones members GroupMember[] // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([createdById]) @@map("groups") } // Modelo de Miembro de Grupo model GroupMember { id String @id @default(uuid()) // Grupo group Group @relation(fields: [groupId], references: [id], onDelete: Cascade) groupId String // Usuario user User @relation("GroupMemberships", fields: [userId], references: [id]) userId String // Rol (ADMIN, MEMBER) role String @default("MEMBER") // Fecha de unión joinedAt DateTime @default(now()) @@unique([groupId, userId]) @@index([groupId]) @@index([userId]) @@map("group_members") } // Modelo de Reserva Recurrente model RecurringBooking { id String @id @default(uuid()) // Usuario que crea la reserva recurrente user User @relation(fields: [userId], references: [id]) userId String // Cancha court Court @relation(fields: [courtId], references: [id]) courtId String // Día de la semana (0=Domingo, 1=Lunes, ..., 6=Sábado) dayOfWeek Int // Horario startTime String endTime String // Rango de fechas startDate DateTime endDate DateTime? // Estado isActive Boolean @default(true) // Relaciones bookings Booking[] // Timestamps createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([userId]) @@index([courtId]) @@index([dayOfWeek]) @@index([isActive]) @@map("recurring_bookings") } // Modelo de Resultado de Partido model MatchResult { id String @id @default(uuid()) // Relación opcional con reserva booking Booking? @relation(fields: [bookingId], references: [id], onDelete: SetNull) bookingId String? @unique // Jugadores del Equipo 1 team1Player1 User @relation("Team1Player1", fields: [team1Player1Id], references: [id]) team1Player1Id String team1Player2 User @relation("Team1Player2", fields: [team1Player2Id], references: [id]) team1Player2Id String // Jugadores del Equipo 2 team2Player1 User @relation("Team2Player1", fields: [team2Player1Id], references: [id]) team2Player1Id String team2Player2 User @relation("Team2Player2", fields: [team2Player2Id], references: [id]) team2Player2Id String // Resultado team1Score Int team2Score Int winner String // TEAM1, TEAM2, DRAW // Fecha en que se jugó el partido playedAt DateTime // Confirmaciones (JSON array de userIds) confirmedBy String @default("[]") // Timestamps createdAt DateTime @default(now()) @@index([team1Player1Id]) @@index([team1Player2Id]) @@index([team2Player1Id]) @@index([team2Player2Id]) @@index([playedAt]) @@map("match_results") } // Modelo de Estadísticas de Usuario por Período model UserStats { id String @id @default(uuid()) // Usuario user User @relation(fields: [userId], references: [id], onDelete: Cascade) userId String // Período (MONTH, YEAR, ALL_TIME) period String // Valor del período (ej: "2024-01" para mes, "2024" para año) periodValue String // Estadísticas de partidos matchesPlayed Int @default(0) matchesWon Int @default(0) matchesLost Int @default(0) // Estadísticas de torneos tournamentsPlayed Int @default(0) tournamentsWon Int @default(0) // Puntos para ranking points Int @default(0) // Timestamps updatedAt DateTime @updatedAt @@unique([userId, period, periodValue]) @@index([userId]) @@index([period, periodValue]) @@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") }