Files
app-padel/backend/src/index.ts
Ivan Alcaraz b558372810 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
2026-01-31 08:11:53 +00:00

117 lines
2.6 KiB
TypeScript

import express from 'express';
import cors from 'cors';
import helmet from 'helmet';
import morgan from 'morgan';
import rateLimit from 'express-rate-limit';
import path from 'path';
import config from './config';
import logger from './config/logger';
import { connectDB } from './config/database';
import routes from './routes';
import { errorHandler, notFoundHandler } from './middleware/errorHandler';
const app = express();
// Crear directorio de logs si no existe
const fs = require('fs');
const logsDir = path.join(__dirname, '../logs');
if (!fs.existsSync(logsDir)) {
fs.mkdirSync(logsDir);
}
// Middleware de seguridad
app.use(helmet());
// CORS
app.use(cors({
origin: config.FRONTEND_URL,
credentials: true,
}));
// Rate limiting
const limiter = rateLimit({
windowMs: config.RATE_LIMIT.WINDOW_MS,
max: config.RATE_LIMIT.MAX_REQUESTS,
message: {
success: false,
message: 'Demasiadas peticiones, por favor intenta más tarde',
},
});
app.use('/api/', limiter);
// Logging HTTP
app.use(morgan('combined', {
stream: {
write: (message: string) => logger.info(message.trim()),
},
}));
// Parsing de body
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
// Rutas API
app.use('/api/v1', routes);
// Ruta raíz
app.get('/', (_req, res) => {
res.json({
success: true,
message: '🎾 API de Canchas de Pádel',
version: '1.0.0',
docs: '/api/v1/health',
});
});
// Handler de rutas no encontradas
app.use(notFoundHandler);
// Handler de errores global
app.use(errorHandler);
// Conectar a BD y iniciar servidor
const startServer = async () => {
try {
// Conectar a base de datos
await connectDB();
// Iniciar servidor
app.listen(config.PORT, () => {
logger.info(`🚀 Servidor corriendo en http://localhost:${config.PORT}`);
logger.info(`📚 API disponible en http://localhost:${config.PORT}/api/v1`);
logger.info(`🏥 Health check: http://localhost:${config.PORT}/api/v1/health`);
});
} catch (error) {
logger.error('Error al iniciar el servidor:', error);
process.exit(1);
}
};
// Manejo de errores no capturados
process.on('uncaughtException', (error) => {
logger.error('Uncaught Exception:', error);
process.exit(1);
});
process.on('unhandledRejection', (reason) => {
logger.error('Unhandled Rejection:', reason);
process.exit(1);
});
// Graceful shutdown
process.on('SIGTERM', async () => {
logger.info('SIGTERM recibido, cerrando servidor...');
process.exit(0);
});
process.on('SIGINT', async () => {
logger.info('SIGINT recibido, cerrando servidor...');
process.exit(0);
});
// Iniciar
startServer();
export default app;