# πŸ—οΈ Arquitectura del Sistema - App Canchas de PΓ‘del DocumentaciΓ³n de la arquitectura tΓ©cnica del proyecto. --- ## πŸ“ Diagrama de Arquitectura ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ CLIENTES β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ Web App β”‚ Mobile App β”‚ Admin β”‚ Terceros β”‚ β”‚ (React) β”‚ (React β”‚ Dashboard β”‚ (MercadoPago) β”‚ β”‚ β”‚ Native) β”‚ (React) β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ API GATEWAY (Nginx) β”‚ β”‚ β€’ SSL/TLS Termination β€’ Rate Limiting β€’ Load Balancing β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ BACKEND API (Node.js) β”‚ β”‚ Express + TypeScript + Prisma β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚ Auth β”‚ β”‚ Core β”‚ β”‚ Modules β”‚ β”‚ β”‚ β”‚ Module β”‚ β”‚ Services β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ Bookings β”‚ β”‚ β”‚ β”‚ β€’ JWT Auth β”‚ β”‚ β€’ Database β”‚ β”‚ β€’ Tournaments β”‚ β”‚ β”‚ β”‚ β€’ OAuth β”‚ β”‚ β€’ Email β”‚ β”‚ β€’ Leagues β”‚ β”‚ β”‚ β”‚ β€’ RBAC β”‚ β”‚ β€’ Logger β”‚ β”‚ β€’ Payments β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ Queue β”‚ β”‚ β€’ Subscriptions β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β€’ Analytics β”‚ β”‚ β”‚ β”‚ β€’ Notifications β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β€’ Social β”‚ β”‚ β”‚ β”‚ Middleware β”‚ β”‚ Validators β”‚ β”‚ β€’ Extras β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ Auth β”‚ β”‚ β€’ Zod β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ RateLimit β”‚ β”‚ β€’ Sanitize β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β€’ Errors β”‚ β”‚ β€’ Transform β”‚ β”‚ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ DATA LAYER β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ PostgreSQL β”‚ Redis β”‚ File Storage β”‚ β”‚ (Primary DB) β”‚ (Cache/Queue) β”‚ (Uploads/Logs) β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β€’ Users β”‚ β€’ Sessions β”‚ β€’ Avatars β”‚ β”‚ β€’ Bookings β”‚ β€’ Cache β”‚ β€’ Tournament Images β”‚ β”‚ β€’ Tournaments β”‚ β€’ Rate Limit β”‚ β€’ Documents β”‚ β”‚ β€’ Payments β”‚ β€’ Pub/Sub β”‚ β€’ Backups β”‚ β”‚ β€’ Analytics β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ—‚οΈ Estructura de Directorios ``` app-padel/ β”œβ”€β”€ backend/ # API REST Backend β”‚ β”œβ”€β”€ src/ β”‚ β”‚ β”œβ”€β”€ config/ # Configuraciones β”‚ β”‚ β”‚ β”œβ”€β”€ database.ts # Prisma/DB config β”‚ β”‚ β”‚ β”œβ”€β”€ logger.ts # Winston logger β”‚ β”‚ β”‚ └── mercadopago.ts # MP config β”‚ β”‚ β”œβ”€β”€ controllers/ # Controladores HTTP β”‚ β”‚ β”‚ β”œβ”€β”€ auth.controller.ts β”‚ β”‚ β”‚ β”œβ”€β”€ booking.controller.ts β”‚ β”‚ β”‚ └── ... β”‚ β”‚ β”œβ”€β”€ middleware/ # Middlewares Express β”‚ β”‚ β”‚ β”œβ”€β”€ auth.ts # JWT auth β”‚ β”‚ β”‚ β”œβ”€β”€ errorHandler.ts β”‚ β”‚ β”‚ └── validate.ts # Zod validation β”‚ β”‚ β”œβ”€β”€ routes/ # DefiniciΓ³n de rutas β”‚ β”‚ β”‚ β”œβ”€β”€ index.ts # Router principal β”‚ β”‚ β”‚ β”œβ”€β”€ auth.routes.ts β”‚ β”‚ β”‚ └── ... β”‚ β”‚ β”œβ”€β”€ services/ # LΓ³gica de negocio β”‚ β”‚ β”‚ β”œβ”€β”€ auth.service.ts β”‚ β”‚ β”‚ β”œβ”€β”€ booking.service.ts β”‚ β”‚ β”‚ └── ... β”‚ β”‚ β”œβ”€β”€ validators/ # Esquemas Zod β”‚ β”‚ β”‚ β”œβ”€β”€ auth.validator.ts β”‚ β”‚ β”‚ └── ... β”‚ β”‚ └── utils/ # Utilidades β”‚ β”‚ β”œβ”€β”€ constants.ts # Constantes/enums β”‚ β”‚ β”œβ”€β”€ jwt.ts # JWT utils β”‚ β”‚ └── ... β”‚ β”œβ”€β”€ prisma/ β”‚ β”‚ └── schema.prisma # Esquema de BD β”‚ β”œβ”€β”€ logs/ # Archivos de log β”‚ └── ecosystem.config.js # PM2 config β”‚ β”œβ”€β”€ frontend/ # Web App (React) β”‚ β”œβ”€β”€ src/ β”‚ β”‚ β”œβ”€β”€ components/ β”‚ β”‚ β”œβ”€β”€ pages/ β”‚ β”‚ β”œβ”€β”€ hooks/ β”‚ β”‚ β”œβ”€β”€ services/ β”‚ β”‚ └── store/ β”‚ └── public/ β”‚ β”œβ”€β”€ mobile/ # Mobile App (React Native) β”‚ β”œβ”€β”€ src/ β”‚ β”‚ β”œβ”€β”€ components/ β”‚ β”‚ β”œβ”€β”€ screens/ β”‚ β”‚ β”œβ”€β”€ navigation/ β”‚ β”‚ └── services/ β”‚ └── assets/ β”‚ β”œβ”€β”€ database/ # Scripts de base de datos β”‚ β”œβ”€β”€ migrations/ β”‚ └── seeds/ β”‚ β”œβ”€β”€ docs/ # DocumentaciΓ³n β”‚ β”œβ”€β”€ API.md β”‚ β”œβ”€β”€ SETUP.md β”‚ β”œβ”€β”€ DEPLOY.md β”‚ └── ... β”‚ └── scripts/ # Scripts de utilidad └── deploy.sh ``` --- ## πŸ”„ Flujo de Datos ### Flujo de AutenticaciΓ³n ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Client │────▢│ Login │────▢│ Auth │────▢│ JWT β”‚ β”‚ β”‚ β”‚ Route β”‚ β”‚ Service β”‚ β”‚ Utils β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β–² β”‚ β”‚ β–Ό β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ Database β”‚ β”‚ β”‚ (User) β”‚ β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β–Ό β”‚β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” └─ Response │◀───── Generate │◀───── Validate β”‚ β”‚ Tokens β”‚ β”‚ Tokens β”‚ β”‚ User β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Flujo de Reserva ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Client │────▢│ Create │────▢│ Validate │────▢│ Check β”‚ β”‚ β”‚ β”‚ Booking β”‚ β”‚ Input β”‚ β”‚Conflict β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β–² β”‚ β”‚ β–Ό β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ └─────┼────────── Save │◀───── Calculate│◀────── β”‚ β”‚ Booking β”‚ β”‚ Price β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ └────────── Response β”‚ β”‚ Notify β”‚β—€β”€β”€β”€β”€β”€β”˜ β”‚ Success β”‚ β”‚ User β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### Flujo de Pago ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Client │────▢│ Create │────▢│ Mercado │────▢│ Preferenceβ”‚ β”‚ β”‚ β”‚Preferenceβ”‚ β”‚ Pago β”‚ β”‚ Created β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β–² β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ β–Ό β”‚β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” └─ Redirect │────▢│ User │────▢│ Mercado β”‚ β”‚ MP β”‚ β”‚ Pays β”‚ β”‚ Pago β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ Webhook β–Ό β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Update β”‚ β”‚ Status β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ›‘οΈ Patrones de DiseΓ±o ### MVC (Model-View-Controller) ``` Request ──▢ Routes ──▢ Controllers ──▢ Services ──▢ Database β”‚ β–Ό Validators (Zod) ``` ### Repository Pattern (via Prisma) ```typescript // services/user.service.ts export class UserService { async findById(id: string) { return prisma.user.findUnique({ where: { id }, include: { profile: true } }); } async create(data: CreateUserDTO) { return prisma.user.create({ data }); } } ``` ### Middleware Pattern ```typescript // middleware/auth.ts export const authenticate = async (req, res, next) => { const token = extractToken(req); const user = await verifyToken(token); req.user = user; next(); }; ``` --- ## πŸ“Š Modelo de Datos (Simplificado) ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ User β”‚ β”‚ Booking β”‚ β”‚ Court β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ id (PK) │◀────│ userId (FK) │────▢│ id (PK) β”‚ β”‚ email β”‚ β”‚ courtId (FK) │────▢│ name β”‚ β”‚ password β”‚ β”‚ date β”‚ β”‚ type β”‚ β”‚ role β”‚ β”‚ startTime β”‚ β”‚ pricePerHour β”‚ β”‚ level β”‚ β”‚ endTime β”‚ β”‚ isActive β”‚ β”‚ createdAt β”‚ β”‚ status β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ totalPrice β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ Tournament β”‚ β”‚ Participant β”‚ β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ │─────────────▢│ id (PK) │◀────│ tournamentId(FK)β”‚ β”‚ β”‚ name β”‚ β”‚ userId (FK) β”‚ β”‚ β”‚ type β”‚ β”‚ status β”‚ β”‚ β”‚ status β”‚ β”‚ paymentStatus β”‚ β”‚ β”‚ maxParticipants β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” └─────────────▢│ League β”‚ β”‚ LeagueTeam β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ id (PK) │◀────│ leagueId (FK) β”‚ β”‚ name β”‚ β”‚ name β”‚ β”‚ format β”‚ β”‚ members[] β”‚ β”‚ status β”‚ β”‚ points β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Payment β”‚ β”‚ Subscription β”‚ β”‚ SubscriptionPlanβ”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ id (PK) │◀────│ userId (FK) │────▢│ id (PK) β”‚ β”‚ userId (FK) β”‚ β”‚ planId (FK) │────▢│ name β”‚ β”‚ type β”‚ β”‚ status β”‚ β”‚ type β”‚ β”‚ amount β”‚ β”‚ startDate β”‚ β”‚ price β”‚ β”‚ status β”‚ β”‚ endDate β”‚ β”‚ features[] β”‚ β”‚ provider β”‚ β”‚ autoRenew β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ Match β”‚ β”‚ Ranking β”‚ β”‚ Achievement β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ id (PK) β”‚ β”‚ id (PK) β”‚ β”‚ id (PK) β”‚ β”‚ bookingId (FK) β”‚ β”‚ userId (FK) │◀────│ code β”‚ β”‚ team1Players[] β”‚ β”‚ points β”‚ β”‚ name β”‚ β”‚ team2Players[] β”‚ β”‚ level β”‚ β”‚ category β”‚ β”‚ score β”‚ β”‚ period β”‚ β”‚ requirement β”‚ β”‚ winner β”‚ β”‚ position β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ”’ Seguridad ### AutenticaciΓ³n ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ AUTHENTICATION FLOW β”‚ β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ β”‚ β”‚ β”‚ 1. Client envΓ­a credenciales β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ 2. Server valida con bcrypt β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ 3. Genera Access Token (JWT, 7d) β”‚ β”‚ Genera Refresh Token (JWT, 30d) β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ 4. Client almacena tokens β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ 5. Requests incluyen: Authorization: Bearer β”‚ β”‚ β”‚ β”‚ β”‚ β–Ό β”‚ β”‚ 6. Middleware verifica JWT β”‚ β”‚ Verifica usuario en DB β”‚ β”‚ AΓ±ade req.user β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` ### AutorizaciΓ³n (RBAC) ```typescript // Roles hierarchy SUPERADMIN > ADMIN > PLAYER // Permission matrix Resource β”‚ Create β”‚ Read β”‚ Update β”‚ Delete ────────────┼────────┼──────┼────────┼─────── Users β”‚ S β”‚ S β”‚ SA β”‚ S Courts β”‚ A β”‚ All β”‚ A β”‚ A Bookings β”‚ P β”‚ P/Ownβ”‚ P/Own β”‚ P/Own Tournaments β”‚ A β”‚ All β”‚ A β”‚ A Payments β”‚ P β”‚ P/Ownβ”‚ A β”‚ S Analytics β”‚ - β”‚ A β”‚ - β”‚ - S = SuperAdmin, A = Admin, P = Player, Own = Own records ``` --- ## ⚑ Performance ### Optimizaciones Implementadas | TΓ©cnica | ImplementaciΓ³n | Beneficio | |---------|---------------|-----------| | Connection Pooling | Prisma default | Reutiliza conexiones DB | | Rate Limiting | express-rate-limit | Previene abuso | | Response Compression | gzip | Reduce tamaΓ±o respuesta | | Query Optimization | Prisma selects | Solo datos necesarios | | Indexing | DB indexes | BΓΊsquedas rΓ‘pidas | | Caching | Redis ready | Datos frecuentes en memoria | ### Escalabilidad ``` β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ LOAD BALANCER β”‚ β”‚ (Nginx/CloudFlare) β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β” β”‚ API Node 1 β”‚ β”‚ API Node 2 β”‚ ... (scale horizontally) β”‚ (PM2 inst) β”‚ β”‚ (PM2 inst) β”‚ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ SHARED RESOURCES β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”‚PostgreSQLβ”‚ β”‚ Redis β”‚ β”‚Storage β”‚ β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ ``` --- ## πŸ“ Convenciones de CΓ³digo ### Nomenclatura | Elemento | ConvenciΓ³n | Ejemplo | |----------|-----------|---------| | Archivos | kebab-case | `auth.controller.ts` | | Clases | PascalCase | `AuthController` | | Funciones | camelCase | `createBooking` | | Variables | camelCase | `userId` | | Constantes | UPPER_SNAKE | `JWT_SECRET` | | Enums | PascalCase | `UserRole` | | Interfaces | PascalCase | `BookingDTO` | ### Estructura de Endpoint ```typescript // routes/example.routes.ts import { Router } from 'express'; import { ExampleController } from '../controllers/example.controller'; import { authenticate } from '../middleware/auth'; import { validate } from '../middleware/validate'; import { exampleSchema } from '../validators/example.validator'; const router = Router(); // GET /examples - Listar router.get('/', ExampleController.getAll); // GET /examples/:id - Obtener uno router.get('/:id', ExampleController.getById); // POST /examples - Crear (protegido + validado) router.post( '/', authenticate, validate(exampleSchema), ExampleController.create ); export default router; ``` --- *Última actualizaciΓ³n: Enero 2026*