FASE 1 COMPLETADA: Fundamentos y Core del Backend

- API REST completa con Node.js + Express + TypeScript
- Autenticación JWT con roles (Player/Admin)
- CRUD completo de canchas
- Sistema de reservas con validaciones
- Base de datos SQLite con Prisma ORM
- Notificaciones por email (Nodemailer)
- Seed de datos de prueba
- Documentación de arquitectura

Endpoints implementados:
- Auth: register, login, refresh, me
- Courts: CRUD + disponibilidad
- Bookings: CRUD + confirmación/cancelación

Credenciales de prueba:
- admin@padel.com / admin123
- user@padel.com / user123
This commit is contained in:
2026-01-31 08:11:53 +00:00
parent a83f4f39e9
commit b558372810
35 changed files with 7428 additions and 10 deletions

View File

@@ -0,0 +1,131 @@
// 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?
// 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?
// Estado
isActive Boolean @default(true)
isVerified Boolean @default(false)
lastLogin DateTime?
// Relaciones
bookings Booking[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users")
}
// 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[]
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
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([userId])
@@index([courtId])
@@index([date])
@@map("bookings")
}