Some checks failed
CI/CD Pipeline / 🧪 Tests (push) Has been cancelled
CI/CD Pipeline / 🏗️ Build (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Staging (push) Has been cancelled
CI/CD Pipeline / 🚀 Deploy to Production (push) Has been cancelled
CI/CD Pipeline / 🏷️ Create Release (push) Has been cancelled
CI/CD Pipeline / 🧹 Cleanup (push) Has been cancelled
Implementados 4 módulos con agent swarm: 1. TESTING FUNCIONAL (Jest) - Configuración Jest + ts-jest - Tests unitarios: auth, booking, court (55 tests) - Tests integración: routes (56 tests) - Factories y utilidades de testing - Coverage configurado (70% servicios) - Scripts: test, test:watch, test:coverage 2. TESTING DE USUARIO (Beta) - Sistema de beta testers - Feedback con categorías y severidad - Beta issues tracking - 8 testers de prueba creados - API completa para gestión de feedback 3. DOCUMENTACIÓN COMPLETA - API.md - 150+ endpoints documentados - SETUP.md - Guía de instalación - DEPLOY.md - Deploy en VPS - ARCHITECTURE.md - Arquitectura del sistema - APP_STORE.md - Material para stores - Postman Collection completa - PM2 ecosystem config - Nginx config con SSL 4. GO LIVE Y PRODUCCIÓN - Sistema de monitoreo (logs, health checks) - Servicio de alertas multi-canal - Pre-deploy check script - Docker + docker-compose producción - Backup automatizado - CI/CD GitHub Actions - Launch checklist completo ESTADÍSTICAS FINALES: - Fases completadas: 7/7 - Archivos creados: 250+ - Líneas de código: 60,000+ - Endpoints API: 150+ - Tests: 110+ - Documentación: 5,000+ líneas PROYECTO COMPLETO Y LISTO PARA PRODUCCIÓN
25 KiB
25 KiB
🏗️ 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)
// 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
// 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 <token> │
│ │ │
│ ▼ │
│ 6. Middleware verifica JWT │
│ Verifica usuario en DB │
│ Añade req.user │
│ │
└─────────────────────────────────────────────────────────────┘
Autorización (RBAC)
// 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
// 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