✅ 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
This commit is contained in:
@@ -21,6 +21,8 @@ model User {
|
||||
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
|
||||
@@ -28,6 +30,13 @@ model User {
|
||||
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)
|
||||
@@ -35,13 +44,58 @@ model User {
|
||||
lastLogin DateTime?
|
||||
|
||||
// Relaciones
|
||||
bookings Booking[]
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
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())
|
||||
@@ -66,6 +120,7 @@ model Court {
|
||||
// Relaciones
|
||||
bookings Booking[]
|
||||
schedules CourtSchedule[]
|
||||
recurringBookings RecurringBooking[]
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -120,6 +175,13 @@ model Booking {
|
||||
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
|
||||
@@ -127,5 +189,195 @@ model Booking {
|
||||
@@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")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user