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

121
backend/prisma/seed.ts Normal file
View File

@@ -0,0 +1,121 @@
import { PrismaClient } from '@prisma/client';
import { hashPassword } from '../src/utils/password';
import { UserRole, PlayerLevel, CourtType } from '../src/utils/constants';
const prisma = new PrismaClient();
async function main() {
console.log('🌱 Seeding database...');
// Crear usuario admin
const adminPassword = await hashPassword('admin123');
const admin = await prisma.user.upsert({
where: { email: 'admin@padel.com' },
update: {},
create: {
email: 'admin@padel.com',
password: adminPassword,
firstName: 'Admin',
lastName: 'Sistema',
role: UserRole.ADMIN,
playerLevel: PlayerLevel.PROFESSIONAL,
isActive: true,
},
});
console.log('✅ Admin creado:', admin.email);
// Crear usuario de prueba
const userPassword = await hashPassword('user123');
const user = await prisma.user.upsert({
where: { email: 'user@padel.com' },
update: {},
create: {
email: 'user@padel.com',
password: userPassword,
firstName: 'Juan',
lastName: 'García',
role: UserRole.PLAYER,
playerLevel: PlayerLevel.INTERMEDIATE,
isActive: true,
},
});
console.log('✅ Usuario creado:', user.email);
// Crear canchas
const courts = [
{
name: 'Cancha 1 - Panorámica',
description: 'Cancha panorámica premium con cristal 360°',
type: CourtType.PANORAMIC,
isIndoor: true,
hasLighting: true,
pricePerHour: 2500,
},
{
name: 'Cancha 2 - Panorámica',
description: 'Cancha panorámica premium con cristal 360°',
type: CourtType.PANORAMIC,
isIndoor: true,
hasLighting: true,
pricePerHour: 2500,
},
{
name: 'Cancha 3 - Exterior',
description: 'Cancha exterior con iluminación nocturna',
type: CourtType.OUTDOOR,
isIndoor: false,
hasLighting: true,
pricePerHour: 2000,
},
{
name: 'Cancha 4 - Cubierta',
description: 'Cancha cubierta sin cristal',
type: CourtType.INDOOR,
isIndoor: true,
hasLighting: true,
pricePerHour: 2200,
},
];
for (const courtData of courts) {
const court = await prisma.court.upsert({
where: { name: courtData.name },
update: {},
create: courtData,
});
console.log('✅ Cancha creada:', court.name);
// Crear horarios para cada cancha (Lunes a Domingo, 8:00 - 23:00)
for (let day = 0; day <= 6; day++) {
await prisma.courtSchedule.upsert({
where: {
courtId_dayOfWeek: {
courtId: court.id,
dayOfWeek: day,
},
},
update: {},
create: {
courtId: court.id,
dayOfWeek: day,
openTime: '08:00',
closeTime: '23:00',
},
});
}
}
console.log('\n🎾 Database seeded successfully!');
console.log('\nCredenciales de prueba:');
console.log(' Admin: admin@padel.com / admin123');
console.log(' User: user@padel.com / user123');
}
main()
.catch((e) => {
console.error(e);
process.exit(1);
})
.finally(async () => {
await prisma.$disconnect();
});