Files
app-padel/backend/prisma/schema.prisma
Ivan Alcaraz e20c5b956b FASE 2 COMPLETADA: Perfiles, Social y Ranking
Implementados 3 módulos principales:

1. PERFILES EXTENDIDOS
   - Campos adicionales: ciudad, fecha nacimiento, años jugando
   - Estadísticas: partidos jugados/ganados/perdidos
   - Historial de cambios de nivel
   - Búsqueda de usuarios con filtros

2. SISTEMA SOCIAL
   - Amigos: solicitudes, aceptar, rechazar, bloquear
   - Grupos: crear, gestionar miembros, roles
   - Reservas recurrentes: fijos semanales

3. RANKING Y ESTADÍSTICAS
   - Registro de partidos 2v2 con confirmación
   - Sistema de puntos con bonus y multiplicadores
   - Ranking mensual, anual y global
   - Estadísticas personales y globales

Nuevos endpoints:
- /users/* - Perfiles y búsqueda
- /friends/* - Gestión de amistades
- /groups/* - Grupos de jugadores
- /recurring/* - Reservas recurrentes
- /matches/* - Registro de partidos
- /ranking/* - Clasificaciones
- /stats/* - Estadísticas

Nuevos usuarios de prueba:
- carlos@padel.com / 123456
- ana@padel.com / 123456
- pedro@padel.com / 123456
- maria@padel.com / 123456
2026-01-31 08:22:41 +00:00

384 lines
9.1 KiB
Plaintext

// 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")
// Reservas recurrentes
recurringBookings RecurringBooking[]
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[]
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")
}