From 864902df8131368e5b8da4a2718b504971b7974a Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 1 Feb 2026 07:49:33 +0000 Subject: [PATCH] docs: add comprehensive documentation - Add README.md with project overview, features, quick start guide, project structure, environment variables, and scripts - Add docs/API.md with complete API reference for all endpoints - Add docs/DEPLOYMENT.md with production deployment guide covering PM2, Nginx, SSL, and Docker options - Add docker-compose.yml for containerized deployment - Add Dockerfile with multi-stage build for optimized production image - Add .dockerignore for efficient Docker builds Co-Authored-By: Claude Opus 4.5 --- .dockerignore | 44 ++ Dockerfile | 86 +++ README.md | 276 ++++++++++ docker-compose.yml | 61 +++ docs/API.md | 1271 ++++++++++++++++++++++++++++++++++++++++++++ docs/DEPLOYMENT.md | 663 +++++++++++++++++++++++ 6 files changed, 2401 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 README.md create mode 100644 docker-compose.yml create mode 100644 docs/API.md create mode 100644 docs/DEPLOYMENT.md diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..745fb9c --- /dev/null +++ b/.dockerignore @@ -0,0 +1,44 @@ +# Dependencies +node_modules +**/node_modules + +# Build outputs +.next +**/dist +**/.turbo + +# Development files +.env +.env.local +.env.*.local +*.log +npm-debug.log* + +# IDE +.vscode +.idea +*.swp +*.swo + +# Git +.git +.gitignore + +# Docker +Dockerfile +docker-compose*.yml +.dockerignore + +# Documentation (not needed in image) +docs +*.md +!README.md + +# Tests +**/*.test.* +**/*.spec.* +coverage + +# Misc +.DS_Store +Thumbs.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a03a848 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,86 @@ +# Dockerfile para Padel Pro +# Multi-stage build para optimizar el tamano de la imagen + +# ============================================ +# Stage 1: Dependencias +# ============================================ +FROM node:20-alpine AS deps +RUN apk add --no-cache libc6-compat + +WORKDIR /app + +# Instalar pnpm +RUN corepack enable && corepack prepare pnpm@8.15.0 --activate + +# Copiar archivos de configuracion de dependencias +COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ +COPY apps/web/package.json ./apps/web/ +COPY packages/shared/package.json ./packages/shared/ + +# Instalar dependencias +RUN pnpm install --frozen-lockfile + +# ============================================ +# Stage 2: Builder +# ============================================ +FROM node:20-alpine AS builder +RUN apk add --no-cache libc6-compat + +WORKDIR /app + +# Instalar pnpm +RUN corepack enable && corepack prepare pnpm@8.15.0 --activate + +# Copiar dependencias instaladas +COPY --from=deps /app/node_modules ./node_modules +COPY --from=deps /app/apps/web/node_modules ./apps/web/node_modules +COPY --from=deps /app/packages/shared/node_modules ./packages/shared/node_modules + +# Copiar codigo fuente +COPY . . + +# Generar cliente Prisma +RUN cd apps/web && pnpm db:generate + +# Construir la aplicacion +ENV NEXT_TELEMETRY_DISABLED 1 +RUN pnpm build + +# ============================================ +# Stage 3: Runner (Produccion) +# ============================================ +FROM node:20-alpine AS runner + +WORKDIR /app + +# Configurar entorno de produccion +ENV NODE_ENV production +ENV NEXT_TELEMETRY_DISABLED 1 + +# Crear usuario no-root +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +# Copiar archivos necesarios para produccion +COPY --from=builder /app/apps/web/public ./apps/web/public + +# Copiar archivos de Next.js standalone +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static + +# Copiar schema de Prisma para migraciones +COPY --from=builder /app/apps/web/prisma ./apps/web/prisma +COPY --from=builder /app/apps/web/node_modules/.prisma ./apps/web/node_modules/.prisma +COPY --from=builder /app/apps/web/node_modules/@prisma ./apps/web/node_modules/@prisma + +# Cambiar a usuario no-root +USER nextjs + +# Exponer puerto +EXPOSE 3000 + +ENV PORT 3000 +ENV HOSTNAME "0.0.0.0" + +# Comando de inicio +CMD ["node", "apps/web/server.js"] diff --git a/README.md b/README.md new file mode 100644 index 0000000..581f585 --- /dev/null +++ b/README.md @@ -0,0 +1,276 @@ +# Padel Pro + +Sistema integral de gestion para clubes de padel. Una solucion moderna y completa para administrar reservas, ventas, torneos, membresias y multiples sedes. + +![Next.js](https://img.shields.io/badge/Next.js-14.2-black?style=flat-square&logo=next.js) +![TypeScript](https://img.shields.io/badge/TypeScript-5.3-blue?style=flat-square&logo=typescript) +![PostgreSQL](https://img.shields.io/badge/PostgreSQL-16-336791?style=flat-square&logo=postgresql) +![Prisma](https://img.shields.io/badge/Prisma-5.10-2D3748?style=flat-square&logo=prisma) +![TailwindCSS](https://img.shields.io/badge/Tailwind-3.4-38B2AC?style=flat-square&logo=tailwind-css) + +--- + +## Caracteristicas Principales + +### Sistema de Reservas +- Calendario visual con vista diaria/semanal +- Gestion de disponibilidad por cancha +- Precios dinamicos (horario regular vs premium) +- Integracion automatica con membresias +- Reservas recurrentes + +### Punto de Venta (POS) +- Gestion de productos y categorias +- Control de inventario con alertas de stock bajo +- Multiples metodos de pago +- Caja registradora con apertura/cierre +- Historial de ventas detallado + +### Torneos +- Formatos: Eliminacion simple/doble, Round Robin, Liga +- Inscripciones online +- Generacion automatica de brackets +- Seguimiento de partidos y resultados + +### Membresias +- Planes personalizables +- Horas de cancha incluidas +- Descuentos en reservas y tienda +- Renovacion automatica opcional +- Alertas de vencimiento + +### Multi-Sede +- Gestion centralizada de multiples ubicaciones +- Usuarios con acceso por sede +- Reportes por sede o consolidados +- Configuracion independiente por sede + +--- + +## Capturas de Pantalla + + +``` +[Dashboard] [Reservas] [POS] +[Torneos] [Membresias] [Clientes] +``` + +--- + +## Inicio Rapido + +### Requisitos Previos + +- Node.js 20.x o superior +- PostgreSQL 16.x +- pnpm 8.15.0 o superior + +### Instalacion + +```bash +# Clonar el repositorio +git clone https://github.com/tu-organizacion/padel-pro.git +cd padel-pro + +# Instalar dependencias +pnpm install + +# Configurar variables de entorno +cp apps/web/.env.example apps/web/.env +# Editar .env con tus credenciales + +# Generar cliente Prisma +pnpm db:generate + +# Crear tablas en la base de datos +pnpm db:push + +# Sembrar datos iniciales (opcional) +cd apps/web && pnpm db:seed && cd ../.. + +# Iniciar en modo desarrollo +pnpm dev +``` + +La aplicacion estara disponible en `http://localhost:3000` + +--- + +## Estructura del Proyecto + +``` +padel-pro/ +├── apps/ +│ └── web/ # Aplicacion Next.js principal +│ ├── app/ +│ │ ├── api/ # API Routes +│ │ │ ├── auth/ # Autenticacion (NextAuth) +│ │ │ ├── bookings/ # Reservas +│ │ │ ├── cash-register/ # Caja registradora +│ │ │ ├── clients/ # Clientes +│ │ │ ├── courts/ # Canchas +│ │ │ ├── dashboard/ # Estadisticas +│ │ │ ├── membership-plans/ # Planes de membresia +│ │ │ ├── memberships/# Membresias +│ │ │ ├── products/ # Productos +│ │ │ ├── sales/ # Ventas +│ │ │ ├── sites/ # Sedes +│ │ │ └── tournaments/# Torneos +│ │ └── (admin)/ # Paginas del panel de administracion +│ ├── components/ # Componentes React reutilizables +│ ├── lib/ # Utilidades y configuraciones +│ ├── prisma/ # Schema y migraciones +│ └── types/ # Definiciones de tipos TypeScript +├── packages/ +│ └── shared/ # Codigo compartido (tipos, validaciones) +├── docs/ # Documentacion +├── package.json +├── pnpm-workspace.yaml +└── turbo.json +``` + +--- + +## Variables de Entorno + +Crear un archivo `.env` en `apps/web/` con las siguientes variables: + +```env +# Base de datos +DATABASE_URL="postgresql://usuario:password@localhost:5432/padel_pro?schema=public" + +# NextAuth +NEXTAUTH_SECRET="tu-clave-secreta-aqui" +NEXTAUTH_URL="http://localhost:3000" + +# Aplicacion +NEXT_PUBLIC_APP_URL="http://localhost:3000" +``` + +### Variables Requeridas + +| Variable | Descripcion | Ejemplo | +|----------|-------------|---------| +| `DATABASE_URL` | URL de conexion a PostgreSQL | `postgresql://user:pass@localhost:5432/db` | +| `NEXTAUTH_SECRET` | Clave secreta para JWT (min 32 caracteres) | Generar con `openssl rand -base64 32` | +| `NEXTAUTH_URL` | URL base de la aplicacion | `http://localhost:3000` | +| `NEXT_PUBLIC_APP_URL` | URL publica de la aplicacion | `http://localhost:3000` | + +--- + +## Scripts Disponibles + +### Desarrollo + +```bash +pnpm dev # Iniciar servidor de desarrollo +pnpm build # Construir para produccion +pnpm lint # Ejecutar ESLint +pnpm type-check # Verificar tipos TypeScript +``` + +### Base de Datos + +```bash +pnpm db:generate # Generar cliente Prisma +pnpm db:push # Sincronizar schema con DB +pnpm db:studio # Abrir Prisma Studio (UI para DB) +pnpm db:seed # Sembrar datos iniciales +``` + +--- + +## Resumen de API + +La API REST sigue convenciones estandar. Todas las rutas requieren autenticacion excepto las indicadas. + +### Endpoints Principales + +| Recurso | Ruta Base | Descripcion | +|---------|-----------|-------------| +| Auth | `/api/auth/*` | Autenticacion NextAuth | +| Courts | `/api/courts` | Gestion de canchas | +| Bookings | `/api/bookings` | Reservas | +| Clients | `/api/clients` | Clientes | +| Products | `/api/products` | Productos del POS | +| Sales | `/api/sales` | Ventas | +| Cash Register | `/api/cash-register` | Caja registradora | +| Tournaments | `/api/tournaments` | Torneos | +| Memberships | `/api/memberships` | Membresias | +| Membership Plans | `/api/membership-plans` | Planes de membresia | +| Sites | `/api/sites` | Sedes | +| Dashboard | `/api/dashboard/stats` | Estadisticas | + +Ver documentacion completa en [docs/API.md](docs/API.md) + +--- + +## Credenciales por Defecto + +Despues de ejecutar el seed, puedes acceder con: + +| Usuario | Password | Rol | +|---------|----------|-----| +| `admin@padelpro.com` | `admin123` | Super Admin | +| `recepcion@padelpro.com` | `recepcion123` | Recepcionista | + +> **IMPORTANTE:** Cambiar estas credenciales inmediatamente en entornos de produccion. + +--- + +## Contribuir + +1. Fork el repositorio +2. Crear una rama para tu feature (`git checkout -b feature/nueva-funcionalidad`) +3. Commit tus cambios (`git commit -m 'feat: agregar nueva funcionalidad'`) +4. Push a la rama (`git push origin feature/nueva-funcionalidad`) +5. Abrir un Pull Request + +### Convenciones de Commits + +Usamos [Conventional Commits](https://www.conventionalcommits.org/): + +- `feat:` Nueva funcionalidad +- `fix:` Correccion de bug +- `docs:` Cambios en documentacion +- `style:` Cambios de formato (no afectan codigo) +- `refactor:` Refactorizacion de codigo +- `test:` Agregar o modificar tests +- `chore:` Tareas de mantenimiento + +--- + +## Documentacion Adicional + +- [API Reference](docs/API.md) - Documentacion completa de endpoints +- [Deployment Guide](docs/DEPLOYMENT.md) - Guia de despliegue + +--- + +## Licencia + +Este proyecto esta bajo la Licencia MIT. Ver el archivo [LICENSE](LICENSE) para mas detalles. + +``` +MIT License + +Copyright (c) 2024 Padel Pro + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +``` diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..7448abb --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,61 @@ +version: '3.8' + +services: + # Base de datos PostgreSQL + db: + image: postgres:16-alpine + container_name: padel-pro-db + restart: unless-stopped + environment: + POSTGRES_USER: ${POSTGRES_USER:-padel_user} + POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-padel_password} + POSTGRES_DB: ${POSTGRES_DB:-padel_pro} + volumes: + - postgres_data:/var/lib/postgresql/data + - ./scripts/init-db.sql:/docker-entrypoint-initdb.d/init.sql:ro + ports: + - "5432:5432" + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER:-padel_user} -d ${POSTGRES_DB:-padel_pro}"] + interval: 10s + timeout: 5s + retries: 5 + networks: + - padel-network + + # Aplicacion Web Next.js + web: + build: + context: . + dockerfile: Dockerfile + container_name: padel-pro-web + restart: unless-stopped + depends_on: + db: + condition: service_healthy + environment: + NODE_ENV: production + DATABASE_URL: postgresql://${POSTGRES_USER:-padel_user}:${POSTGRES_PASSWORD:-padel_password}@db:5432/${POSTGRES_DB:-padel_pro}?schema=public + NEXTAUTH_SECRET: ${NEXTAUTH_SECRET} + NEXTAUTH_URL: ${NEXTAUTH_URL:-http://localhost:3000} + NEXT_PUBLIC_APP_URL: ${NEXT_PUBLIC_APP_URL:-http://localhost:3000} + ports: + - "3000:3000" + volumes: + - ./apps/web/public:/app/apps/web/public:ro + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/api/auth/session"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + networks: + - padel-network + +networks: + padel-network: + driver: bridge + +volumes: + postgres_data: + driver: local diff --git a/docs/API.md b/docs/API.md new file mode 100644 index 0000000..29ce642 --- /dev/null +++ b/docs/API.md @@ -0,0 +1,1271 @@ +# API Reference - Padel Pro + +Documentacion completa de los endpoints REST de la API de Padel Pro. + +## Informacion General + +- **Base URL:** `http://localhost:3000/api` +- **Autenticacion:** Basada en sesiones (NextAuth.js) +- **Formato:** JSON +- **Codificacion:** UTF-8 + +### Codigos de Estado HTTP + +| Codigo | Descripcion | +|--------|-------------| +| 200 | Exito | +| 201 | Recurso creado | +| 400 | Solicitud invalida | +| 401 | No autorizado | +| 403 | Prohibido (sin permisos) | +| 404 | Recurso no encontrado | +| 409 | Conflicto (ej: duplicado) | +| 500 | Error interno del servidor | + +### Roles de Usuario + +| Rol | Descripcion | Permisos | +|-----|-------------|----------| +| `SUPER_ADMIN` | Administrador del sistema | Acceso total | +| `ORG_ADMIN` | Administrador de organizacion | Gestion completa de la organizacion | +| `SITE_ADMIN` | Administrador de sede | Gestion de una sede especifica | +| `RECEPTIONIST` | Recepcionista | Reservas, ventas, clientes | +| `COACH` | Entrenador | Acceso limitado | + +--- + +## Autenticacion + +### Endpoints de NextAuth + +``` +GET/POST /api/auth/[...nextauth] +``` + +NextAuth maneja automaticamente los siguientes endpoints: + +| Ruta | Metodo | Descripcion | +|------|--------|-------------| +| `/api/auth/signin` | GET | Pagina de inicio de sesion | +| `/api/auth/signout` | POST | Cerrar sesion | +| `/api/auth/session` | GET | Obtener sesion actual | +| `/api/auth/csrf` | GET | Token CSRF | +| `/api/auth/providers` | GET | Proveedores disponibles | +| `/api/auth/callback/:provider` | GET/POST | Callback de proveedor | + +--- + +## Sedes (Sites) + +### Listar Sedes + +```http +GET /api/sites +``` + +**Autenticacion:** Requerida + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyz123", + "name": "Padel Club Centro", + "slug": "padel-club-centro", + "address": "Calle Principal 123", + "phone": "+34 600 000 000", + "email": "centro@padelclub.com", + "timezone": "Europe/Madrid", + "openTime": "08:00", + "closeTime": "22:00", + "courtCount": 6 + } +] +``` + +--- + +## Canchas (Courts) + +### Listar Canchas + +```http +GET /api/courts +``` + +**Autenticacion:** Requerida + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `siteId` | string | Filtrar por sede | + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyz456", + "name": "Cancha 1", + "type": "INDOOR", + "status": "AVAILABLE", + "pricePerHour": 30.00, + "description": "Cancha cubierta con iluminacion LED", + "features": ["LED", "Cristal"], + "displayOrder": 1, + "isActive": true, + "site": { + "id": "clxyz123", + "name": "Padel Club Centro", + "openTime": "08:00", + "closeTime": "22:00" + } + } +] +``` + +### Crear Cancha + +```http +POST /api/courts +``` + +**Autenticacion:** Requerida +**Roles permitidos:** `SUPER_ADMIN`, `SITE_ADMIN` + +**Cuerpo de la Solicitud:** + +```json +{ + "siteId": "clxyz123", + "name": "Cancha 7", + "type": "OUTDOOR", + "pricePerHour": 25.00, + "description": "Cancha exterior", + "features": ["Cesped artificial"], + "displayOrder": 7 +} +``` + +**Campos Requeridos:** `siteId`, `name`, `pricePerHour` + +**Respuesta Exitosa (201):** + +```json +{ + "id": "clxyz789", + "name": "Cancha 7", + "type": "OUTDOOR", + "status": "AVAILABLE", + "pricePerHour": 25.00, + "isActive": true, + "site": { ... } +} +``` + +### Obtener Cancha por ID + +```http +GET /api/courts/{id} +``` + +**Autenticacion:** Requerida + +**Respuesta Exitosa (200):** + +```json +{ + "id": "clxyz456", + "name": "Cancha 1", + "type": "INDOOR", + "status": "AVAILABLE", + "pricePerHour": 30.00, + "site": { + "id": "clxyz123", + "name": "Padel Club Centro", + "address": "Calle Principal 123", + "phone": "+34 600 000 000" + } +} +``` + +### Actualizar Cancha + +```http +PUT /api/courts/{id} +``` + +**Autenticacion:** Requerida +**Roles permitidos:** `SUPER_ADMIN`, `SITE_ADMIN` + +**Cuerpo de la Solicitud (todos los campos opcionales):** + +```json +{ + "name": "Cancha 1 VIP", + "type": "INDOOR", + "status": "MAINTENANCE", + "pricePerHour": 35.00, + "description": "Cancha premium renovada", + "features": ["LED", "Cristal", "Climatizada"], + "isActive": true +} +``` + +### Eliminar Cancha + +```http +DELETE /api/courts/{id} +``` + +**Autenticacion:** Requerida +**Roles permitidos:** `SUPER_ADMIN`, `SITE_ADMIN` + +**Respuesta Exitosa (200):** + +```json +{ + "message": "Court deleted successfully" +} +``` + +### Obtener Disponibilidad + +```http +GET /api/courts/{id}/availability +``` + +**Autenticacion:** Requerida + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `date` | string | Fecha en formato YYYY-MM-DD | + +--- + +## Reservas (Bookings) + +### Listar Reservas + +```http +GET /api/bookings +``` + +**Autenticacion:** Requerida + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `siteId` | string | Filtrar por sede | +| `date` | string | Filtrar por fecha (YYYY-MM-DD) | +| `status` | string | PENDING, CONFIRMED, CANCELLED, COMPLETED, NO_SHOW | +| `clientId` | string | Filtrar por cliente | +| `courtId` | string | Filtrar por cancha | + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyz001", + "startTime": "2024-01-15T10:00:00.000Z", + "endTime": "2024-01-15T11:30:00.000Z", + "status": "CONFIRMED", + "paymentType": "CARD", + "totalPrice": 45.00, + "paidAmount": 45.00, + "notes": null, + "playerNames": ["Juan", "Maria", "Pedro", "Ana"], + "court": { + "id": "clxyz456", + "name": "Cancha 1", + "type": "INDOOR" + }, + "client": { + "id": "clxyz100", + "firstName": "Juan", + "lastName": "Garcia", + "email": "juan@email.com", + "phone": "+34 600 111 222" + }, + "site": { + "id": "clxyz123", + "name": "Padel Club Centro" + } + } +] +``` + +### Crear Reserva + +```http +POST /api/bookings +``` + +**Autenticacion:** Requerida + +**Cuerpo de la Solicitud:** + +```json +{ + "courtId": "clxyz456", + "clientId": "clxyz100", + "startTime": "2024-01-15T10:00:00.000Z", + "endTime": "2024-01-15T11:30:00.000Z", + "paymentType": "card", + "notes": "Reserva para cumpleanos", + "participants": [ + { "name": "Juan" }, + { "name": "Maria" }, + { "name": "Pedro" }, + { "name": "Ana" } + ] +} +``` + +**Respuesta Exitosa (201):** + +```json +{ + "id": "clxyz002", + "startTime": "2024-01-15T10:00:00.000Z", + "endTime": "2024-01-15T11:30:00.000Z", + "status": "PENDING", + "totalPrice": 45.00, + "paidAmount": 0.00, + "court": { ... }, + "client": { ... } +} +``` + +**Errores Comunes:** + +- `409`: Ya existe una reserva en ese horario +- `404`: Cancha o cliente no encontrado +- `400`: La cancha no esta disponible + +### Obtener Reserva por ID + +```http +GET /api/bookings/{id} +``` + +### Actualizar Reserva + +```http +PUT /api/bookings/{id} +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "status": "CONFIRMED", + "notes": "Cliente confirmado por telefono", + "playerNames": ["Juan", "Maria", "Pedro", "Ana"] +} +``` + +### Cancelar Reserva + +```http +DELETE /api/bookings/{id} +``` + +**Cuerpo Opcional:** + +```json +{ + "cancelReason": "Cliente solicito cancelacion" +} +``` + +### Registrar Pago de Reserva + +```http +POST /api/bookings/{id}/pay +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "amount": 45.00, + "paymentType": "CARD", + "reference": "TRX-123456" +} +``` + +--- + +## Clientes (Clients) + +### Listar Clientes + +```http +GET /api/clients +``` + +**Autenticacion:** Requerida + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `search` | string | Buscar por nombre, email o telefono | +| `isActive` | boolean | Filtrar por estado activo | +| `limit` | number | Limite de resultados (max 100) | +| `offset` | number | Desplazamiento para paginacion | + +**Respuesta Exitosa (200):** + +```json +{ + "data": [ + { + "id": "clxyz100", + "firstName": "Juan", + "lastName": "Garcia", + "email": "juan@email.com", + "phone": "+34 600 111 222", + "level": "INTERMEDIATE", + "tags": ["VIP", "Torneo"], + "isActive": true, + "createdAt": "2024-01-01T00:00:00.000Z", + "memberships": [ + { + "id": "clxyz200", + "status": "ACTIVE", + "remainingHours": 8, + "endDate": "2024-06-01T00:00:00.000Z", + "plan": { + "id": "clxyz300", + "name": "Plan Premium", + "discountPercent": 20 + } + } + ], + "_count": { + "bookings": 15 + } + } + ], + "pagination": { + "total": 150, + "limit": 50, + "offset": 0, + "hasMore": true + } +} +``` + +### Crear Cliente + +```http +POST /api/clients +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "firstName": "Maria", + "lastName": "Lopez", + "email": "maria@email.com", + "phone": "+34 600 333 444", + "dateOfBirth": "1990-05-15", + "address": "Calle Nueva 45", + "notes": "Prefiere canchas interiores", + "tags": ["Principiante"], + "skillLevel": "BEGINNER", + "emergencyContact": { + "name": "Pedro Lopez", + "phone": "+34 600 555 666" + } +} +``` + +**Campos Requeridos:** `firstName`, `lastName` + +### Obtener Cliente por ID + +```http +GET /api/clients/{id} +``` + +### Actualizar Cliente + +```http +PUT /api/clients/{id} +``` + +### Obtener Membresia del Cliente + +```http +GET /api/clients/{id}/membership +``` + +--- + +## Productos (Products) + +### Listar Productos + +```http +GET /api/products +``` + +**Autenticacion:** Requerida + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `siteId` | string | Filtrar por sede | +| `categoryId` | string | Filtrar por categoria | +| `search` | string | Buscar por nombre | +| `isActive` | boolean | Solo productos activos | + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyz400", + "name": "Pelotas HEAD Pro", + "description": "Bote de 3 pelotas", + "sku": "BALL-HEAD-001", + "price": 6.50, + "costPrice": 4.00, + "stock": 50, + "minStock": 10, + "trackStock": true, + "image": null, + "isActive": true, + "lowStock": false, + "category": { + "id": "clxyz500", + "name": "Pelotas", + "description": "Pelotas de padel" + } + } +] +``` + +### Crear Producto + +```http +POST /api/products +``` + +**Autenticacion:** Requerida +**Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN`, `SITE_ADMIN` + +**Cuerpo de la Solicitud:** + +```json +{ + "siteId": "clxyz123", + "categoryId": "clxyz500", + "name": "Overgrip Wilson", + "description": "Pack de 3 overgrips", + "sku": "GRIP-WILSON-001", + "price": 8.00, + "costPrice": 5.50, + "stock": 30, + "minStock": 5, + "trackStock": true +} +``` + +### Actualizar Stock + +```http +PATCH /api/products/{id}/stock +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "adjustment": 10, + "reason": "Reposicion de inventario" +} +``` + +### Listar Categorias + +```http +GET /api/products/categories +``` + +--- + +## Ventas (Sales) + +### Listar Ventas + +```http +GET /api/sales +``` + +**Autenticacion:** Requerida + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `siteId` | string | Filtrar por sede | +| `startDate` | string | Fecha inicio (YYYY-MM-DD) | +| `endDate` | string | Fecha fin (YYYY-MM-DD) | +| `clientId` | string | Filtrar por cliente | +| `createdBy` | string | Filtrar por vendedor | + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyz600", + "subtotal": 25.00, + "discount": 0.00, + "tax": 5.25, + "total": 30.25, + "paymentType": "CASH", + "notes": null, + "createdAt": "2024-01-15T14:30:00.000Z", + "items": [ + { + "id": "clxyz601", + "quantity": 2, + "unitPrice": 6.50, + "subtotal": 13.00, + "product": { + "id": "clxyz400", + "name": "Pelotas HEAD Pro", + "sku": "BALL-HEAD-001" + } + } + ], + "payments": [ + { + "id": "clxyz602", + "amount": 30.25, + "paymentType": "CASH", + "reference": null + } + ], + "client": null, + "createdBy": { + "id": "clxyz700", + "firstName": "Ana", + "lastName": "Martinez" + }, + "cashRegister": { + "id": "clxyz800", + "site": { + "id": "clxyz123", + "name": "Padel Club Centro" + } + } + } +] +``` + +### Crear Venta + +```http +POST /api/sales +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "siteId": "clxyz123", + "clientId": "clxyz100", + "items": [ + { + "productId": "clxyz400", + "quantity": 2, + "price": 6.50 + }, + { + "productId": "clxyz401", + "quantity": 1, + "price": 12.00 + } + ], + "payments": [ + { + "amount": 25.00, + "method": "CASH" + } + ], + "discount": 0, + "tax": 0, + "notes": "Venta rapida" +} +``` + +**Nota:** Requiere caja registradora abierta si hay pago en efectivo. + +--- + +## Caja Registradora (Cash Register) + +### Obtener Estado de Caja + +```http +GET /api/cash-register +``` + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `siteId` | string | Sede | +| `status` | string | `open`, `closed`, o `all` | +| `date` | string | Fecha especifica (YYYY-MM-DD) | + +**Respuesta Exitosa (200) - Caja Abierta:** + +```json +{ + "id": "clxyz800", + "openingAmount": 100.00, + "closingAmount": null, + "expectedAmount": null, + "difference": null, + "openedAt": "2024-01-15T08:00:00.000Z", + "closedAt": null, + "site": { + "id": "clxyz123", + "name": "Padel Club Centro" + }, + "user": { + "id": "clxyz700", + "firstName": "Ana", + "lastName": "Martinez" + }, + "paymentBreakdown": { + "CASH": 250.00, + "CARD": 180.00 + }, + "totalCashSales": 250.00, + "expectedAmount": 350.00, + "_count": { + "sales": 12, + "payments": 15 + } +} +``` + +### Abrir Caja + +```http +POST /api/cash-register +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "siteId": "clxyz123", + "openingAmount": 100.00 +} +``` + +### Cerrar Caja + +```http +PUT /api/cash-register/{id} +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "closingAmount": 345.50, + "notes": "Cuadre correcto" +} +``` + +### Obtener Transacciones + +```http +GET /api/cash-register/{id}/transactions +``` + +--- + +## Torneos (Tournaments) + +### Listar Torneos + +```http +GET /api/tournaments +``` + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `siteId` | string | Filtrar por sede | +| `status` | string | DRAFT, REGISTRATION_OPEN, IN_PROGRESS, COMPLETED, CANCELLED | +| `startDate` | string | Fecha inicio del rango | +| `endDate` | string | Fecha fin del rango | + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyz900", + "name": "Torneo de Verano 2024", + "description": "Torneo amateur categoria B", + "type": "BRACKET", + "status": "REGISTRATION_OPEN", + "startDate": "2024-07-15T09:00:00.000Z", + "endDate": "2024-07-16T20:00:00.000Z", + "maxPlayers": 32, + "entryFee": 25.00, + "site": { + "id": "clxyz123", + "name": "Padel Club Centro" + }, + "_count": { + "inscriptions": 18, + "matches": 0 + } + } +] +``` + +### Crear Torneo + +```http +POST /api/tournaments +``` + +**Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN`, `SITE_ADMIN` + +**Cuerpo de la Solicitud:** + +```json +{ + "siteId": "clxyz123", + "name": "Torneo de Primavera", + "description": "Torneo para socios", + "date": "2024-04-20T09:00:00.000Z", + "endDate": "2024-04-21T20:00:00.000Z", + "type": "SINGLE_ELIMINATION", + "category": "B", + "maxTeams": 16, + "price": 20.00 +} +``` + +### Obtener Torneo por ID + +```http +GET /api/tournaments/{id} +``` + +### Actualizar Torneo + +```http +PUT /api/tournaments/{id} +``` + +### Listar Inscripciones + +```http +GET /api/tournaments/{id}/inscriptions +``` + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyzabc", + "teamName": "Los Campeones", + "seedNumber": 1, + "isPaid": true, + "paidAmount": 25.00, + "registeredAt": "2024-01-10T12:00:00.000Z", + "client": { + "id": "clxyz100", + "firstName": "Juan", + "lastName": "Garcia", + "level": "ADVANCED" + }, + "partner": { + "id": "clxyz101", + "firstName": "Pedro", + "lastName": "Martinez", + "level": "ADVANCED" + } + } +] +``` + +### Inscribir Equipo + +```http +POST /api/tournaments/{id}/inscriptions +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "player1Id": "clxyz100", + "player2Id": "clxyz101", + "teamName": "Los Campeones" +} +``` + +### Generar Bracket + +```http +POST /api/tournaments/{id}/generate-bracket +``` + +### Actualizar Resultado de Partido + +```http +PUT /api/tournaments/{id}/matches/{matchId} +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "score1": "6-4", + "score2": "6-3", + "winnerId": "clxyzabc" +} +``` + +--- + +## Planes de Membresia (Membership Plans) + +### Listar Planes + +```http +GET /api/membership-plans +``` + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `includeInactive` | boolean | Incluir planes inactivos | + +**Respuesta Exitosa (200):** + +```json +[ + { + "id": "clxyz300", + "name": "Plan Premium", + "description": "Acceso completo con beneficios exclusivos", + "price": 99.00, + "durationMonths": 1, + "courtHours": 10, + "discountPercent": 20, + "benefits": ["Reserva anticipada", "Descuento en tienda"], + "isActive": true, + "subscriberCount": 45, + "benefitsSummary": { + "freeHours": 10, + "bookingDiscount": 20, + "extraBenefits": ["Reserva anticipada", "Descuento en tienda"] + } + } +] +``` + +### Crear Plan + +```http +POST /api/membership-plans +``` + +**Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN` + +**Cuerpo de la Solicitud:** + +```json +{ + "name": "Plan Basico", + "description": "Plan de entrada", + "price": 29.00, + "durationMonths": 1, + "freeHours": 2, + "bookingDiscount": 10, + "storeDiscount": 5, + "extraBenefits": ["Newsletter exclusivo"] +} +``` + +### Actualizar Plan + +```http +PUT /api/membership-plans/{id} +``` + +--- + +## Membresias (Memberships) + +### Listar Membresias + +```http +GET /api/memberships +``` + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `status` | string | ACTIVE, EXPIRED, CANCELLED, SUSPENDED | +| `planId` | string | Filtrar por plan | +| `search` | string | Buscar por nombre/email del cliente | +| `expiring` | boolean | Solo proximas a vencer (7 dias) | +| `limit` | number | Limite de resultados | +| `offset` | number | Desplazamiento | + +**Respuesta Exitosa (200):** + +```json +{ + "data": [ + { + "id": "clxyz200", + "startDate": "2024-01-01T00:00:00.000Z", + "endDate": "2024-06-01T00:00:00.000Z", + "status": "ACTIVE", + "remainingHours": 8, + "autoRenew": true, + "notes": null, + "plan": { + "id": "clxyz300", + "name": "Plan Premium", + "price": 99.00, + "durationMonths": 1, + "courtHours": 10, + "discountPercent": 20 + }, + "client": { + "id": "clxyz100", + "firstName": "Juan", + "lastName": "Garcia", + "email": "juan@email.com" + }, + "isExpiring": false, + "daysUntilExpiry": 45, + "benefitsSummary": { + "freeHours": 10, + "hoursRemaining": 8, + "bookingDiscount": 20, + "extraBenefits": [] + } + } + ], + "pagination": { + "total": 150, + "limit": 50, + "offset": 0, + "hasMore": true + } +} +``` + +### Crear Membresia + +```http +POST /api/memberships +``` + +**Roles permitidos:** `SUPER_ADMIN`, `ORG_ADMIN`, `SITE_ADMIN`, `RECEPTIONIST` + +**Cuerpo de la Solicitud:** + +```json +{ + "clientId": "clxyz100", + "planId": "clxyz300", + "startDate": "2024-02-01T00:00:00.000Z", + "endDate": "2024-03-01T00:00:00.000Z", + "autoRenew": true, + "notes": "Primera membresia del cliente" +} +``` + +### Renovar Membresia + +```http +POST /api/memberships/{id}/renew +``` + +**Cuerpo de la Solicitud:** + +```json +{ + "planId": "clxyz300", + "paymentMethod": "CARD" +} +``` + +--- + +## Dashboard + +### Obtener Estadisticas + +```http +GET /api/dashboard/stats +``` + +**Parametros de Query:** + +| Parametro | Tipo | Descripcion | +|-----------|------|-------------| +| `siteId` | string | Filtrar por sede | +| `date` | string | Fecha especifica (YYYY-MM-DD) | + +**Respuesta Exitosa (200):** + +```json +{ + "stats": { + "todayBookings": 24, + "todayRevenue": 580.50, + "occupancyRate": 75, + "activeMembers": 145, + "pendingBookings": 3, + "upcomingTournaments": 2 + }, + "courtOccupancy": [ + { + "courtId": "clxyz456", + "courtName": "Cancha 1", + "availableHours": 14, + "bookedHours": 11.5, + "occupancyPercent": 82 + } + ], + "recentBookings": [ + { + "id": "clxyz001", + "startTime": "2024-01-15T10:00:00.000Z", + "endTime": "2024-01-15T11:30:00.000Z", + "status": "CONFIRMED", + "court": { + "id": "clxyz456", + "name": "Cancha 1" + }, + "client": { + "id": "clxyz100", + "name": "Juan Garcia" + } + } + ], + "date": "2024-01-15" +} +``` + +--- + +## Errores Comunes + +### Error de Autenticacion + +```json +{ + "error": "No autorizado" +} +``` +**Codigo:** 401 + +### Error de Permisos + +```json +{ + "error": "Forbidden: Insufficient permissions" +} +``` +**Codigo:** 403 + +### Recurso No Encontrado + +```json +{ + "error": "Court not found" +} +``` +**Codigo:** 404 + +### Conflicto + +```json +{ + "error": "Ya existe una reserva en ese horario" +} +``` +**Codigo:** 409 + +### Error de Validacion + +```json +{ + "error": "Invalid booking data", + "details": { + "courtId": ["Invalid court ID"], + "startTime": ["Required"] + } +} +``` +**Codigo:** 400 + +--- + +## Notas Adicionales + +### Paginacion + +Los endpoints que devuelven listas soportan paginacion mediante: + +- `limit`: Numero maximo de resultados (default: 50, max: 100) +- `offset`: Numero de registros a saltar + +La respuesta incluye metadatos de paginacion: + +```json +{ + "data": [...], + "pagination": { + "total": 150, + "limit": 50, + "offset": 0, + "hasMore": true + } +} +``` + +### Filtrado por Sede + +La mayoria de endpoints filtran automaticamente por la sede del usuario si tiene una asignada. Para usuarios con acceso a multiples sedes, se puede especificar `siteId` en los parametros de query. + +### Zonas Horarias + +Las fechas se manejan en UTC. Cada sede tiene configurada su zona horaria para mostrar correctamente los horarios de apertura/cierre. diff --git a/docs/DEPLOYMENT.md b/docs/DEPLOYMENT.md new file mode 100644 index 0000000..3807f2e --- /dev/null +++ b/docs/DEPLOYMENT.md @@ -0,0 +1,663 @@ +# Guia de Despliegue - Padel Pro + +Esta guia cubre el proceso completo para desplegar Padel Pro en un entorno de produccion. + +## Tabla de Contenidos + +1. [Requisitos Previos](#requisitos-previos) +2. [Configuracion del Entorno](#configuracion-del-entorno) +3. [Configuracion de Base de Datos](#configuracion-de-base-de-datos) +4. [Despliegue con PM2](#despliegue-con-pm2) +5. [Configuracion de Nginx](#configuracion-de-nginx) +6. [SSL con Lets Encrypt](#ssl-con-lets-encrypt) +7. [Despliegue con Docker](#despliegue-con-docker) +8. [Monitoreo y Mantenimiento](#monitoreo-y-mantenimiento) + +--- + +## Requisitos Previos + +### Software Requerido + +| Software | Version | Proposito | +|----------|---------|-----------| +| Node.js | 20.x LTS | Runtime de JavaScript | +| PostgreSQL | 16.x | Base de datos | +| pnpm | 8.15.0+ | Gestor de paquetes | +| Git | 2.x | Control de versiones | +| Nginx | 1.24+ | Servidor web / Proxy inverso | +| PM2 | 5.x | Gestor de procesos (opcional) | +| Docker | 24.x | Contenedores (opcional) | + +### Recursos del Servidor + +**Minimos:** +- CPU: 2 cores +- RAM: 4 GB +- Disco: 20 GB SSD + +**Recomendados:** +- CPU: 4 cores +- RAM: 8 GB +- Disco: 50 GB SSD + +--- + +## Configuracion del Entorno + +### 1. Instalar Node.js 20 + +```bash +# Usando nvm (recomendado) +curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.0/install.sh | bash +source ~/.bashrc +nvm install 20 +nvm use 20 +nvm alias default 20 + +# Verificar instalacion +node --version # v20.x.x +``` + +### 2. Instalar pnpm + +```bash +npm install -g pnpm +pnpm --version # 8.x.x +``` + +### 3. Clonar el Repositorio + +```bash +cd /var/www +git clone https://github.com/tu-organizacion/padel-pro.git +cd padel-pro +``` + +### 4. Configurar Variables de Entorno + +```bash +cp apps/web/.env.example apps/web/.env +``` + +Editar el archivo `.env`: + +```env +# Base de datos - Produccion +DATABASE_URL="postgresql://padel_user:PASSWORD_SEGURO@localhost:5432/padel_pro?schema=public" + +# NextAuth - IMPORTANTE: Generar clave unica +NEXTAUTH_SECRET="$(openssl rand -base64 32)" +NEXTAUTH_URL="https://tudominio.com" + +# Aplicacion +NEXT_PUBLIC_APP_URL="https://tudominio.com" +NODE_ENV="production" +``` + +> **IMPORTANTE:** Nunca usar las credenciales de ejemplo en produccion. Generar una clave secreta unica con `openssl rand -base64 32`. + +### 5. Instalar Dependencias + +```bash +pnpm install --frozen-lockfile +``` + +### 6. Construir la Aplicacion + +```bash +pnpm build +``` + +--- + +## Configuracion de Base de Datos + +### 1. Instalar PostgreSQL 16 + +```bash +# Ubuntu/Debian +sudo sh -c 'echo "deb http://apt.postgresql.org/pub/repos/apt $(lsb_release -cs)-pgdg main" > /etc/apt/sources.list.d/pgdg.list' +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - +sudo apt update +sudo apt install postgresql-16 + +# Iniciar servicio +sudo systemctl start postgresql +sudo systemctl enable postgresql +``` + +### 2. Crear Base de Datos y Usuario + +```bash +sudo -u postgres psql +``` + +```sql +-- Crear usuario +CREATE USER padel_user WITH PASSWORD 'PASSWORD_SEGURO'; + +-- Crear base de datos +CREATE DATABASE padel_pro OWNER padel_user; + +-- Otorgar permisos +GRANT ALL PRIVILEGES ON DATABASE padel_pro TO padel_user; + +-- Salir +\q +``` + +### 3. Configurar Conexion Remota (si es necesario) + +Editar `/etc/postgresql/16/main/postgresql.conf`: + +```conf +listen_addresses = 'localhost' # o '*' para conexiones remotas +``` + +Editar `/etc/postgresql/16/main/pg_hba.conf`: + +```conf +# Conexion local +local all padel_user md5 + +# Conexion remota (si es necesario) +host padel_pro padel_user 192.168.1.0/24 md5 +``` + +Reiniciar PostgreSQL: + +```bash +sudo systemctl restart postgresql +``` + +### 4. Ejecutar Migraciones + +```bash +cd /var/www/padel-pro +pnpm db:generate +pnpm db:push +``` + +### 5. Sembrar Datos Iniciales (Opcional) + +```bash +cd apps/web +pnpm db:seed +``` + +--- + +## Despliegue con PM2 + +### 1. Instalar PM2 + +```bash +npm install -g pm2 +``` + +### 2. Crear Archivo de Configuracion + +Crear `ecosystem.config.js` en la raiz del proyecto: + +```javascript +module.exports = { + apps: [ + { + name: 'padel-pro', + cwd: '/var/www/padel-pro/apps/web', + script: 'node_modules/next/dist/bin/next', + args: 'start', + instances: 'max', + exec_mode: 'cluster', + env: { + NODE_ENV: 'production', + PORT: 3000 + }, + env_production: { + NODE_ENV: 'production', + PORT: 3000 + }, + // Configuracion de logs + log_date_format: 'YYYY-MM-DD HH:mm:ss Z', + error_file: '/var/log/padel-pro/error.log', + out_file: '/var/log/padel-pro/out.log', + merge_logs: true, + // Reinicio automatico + max_memory_restart: '1G', + exp_backoff_restart_delay: 100 + } + ] +}; +``` + +### 3. Crear Directorio de Logs + +```bash +sudo mkdir -p /var/log/padel-pro +sudo chown $USER:$USER /var/log/padel-pro +``` + +### 4. Iniciar la Aplicacion + +```bash +pm2 start ecosystem.config.js --env production +``` + +### 5. Configurar Inicio Automatico + +```bash +pm2 startup +pm2 save +``` + +### 6. Comandos Utiles de PM2 + +```bash +# Ver estado +pm2 status + +# Ver logs +pm2 logs padel-pro + +# Reiniciar +pm2 restart padel-pro + +# Recargar sin downtime +pm2 reload padel-pro + +# Detener +pm2 stop padel-pro + +# Monitoreo +pm2 monit +``` + +--- + +## Configuracion de Nginx + +### 1. Instalar Nginx + +```bash +sudo apt install nginx +``` + +### 2. Crear Configuracion del Sitio + +Crear `/etc/nginx/sites-available/padel-pro`: + +```nginx +# Redirigir HTTP a HTTPS +server { + listen 80; + listen [::]:80; + server_name tudominio.com www.tudominio.com; + + location / { + return 301 https://$host$request_uri; + } + + # Let's Encrypt challenge + location /.well-known/acme-challenge/ { + root /var/www/certbot; + } +} + +# Configuracion HTTPS +server { + listen 443 ssl http2; + listen [::]:443 ssl http2; + server_name tudominio.com www.tudominio.com; + + # SSL (sera configurado por Certbot) + ssl_certificate /etc/letsencrypt/live/tudominio.com/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/tudominio.com/privkey.pem; + ssl_session_timeout 1d; + ssl_session_cache shared:SSL:50m; + ssl_session_tickets off; + + # Configuracion SSL moderna + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384; + ssl_prefer_server_ciphers off; + + # HSTS + add_header Strict-Transport-Security "max-age=63072000" always; + + # Logs + access_log /var/log/nginx/padel-pro.access.log; + error_log /var/log/nginx/padel-pro.error.log; + + # Tamano maximo de subida + client_max_body_size 10M; + + # Gzip + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css text/xml application/json application/javascript application/rss+xml application/atom+xml image/svg+xml; + + # Proxy a Next.js + location / { + proxy_pass http://127.0.0.1:3000; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_cache_bypass $http_upgrade; + proxy_read_timeout 86400; + } + + # Cache para assets estaticos + location /_next/static { + proxy_pass http://127.0.0.1:3000; + proxy_cache_valid 60m; + add_header Cache-Control "public, immutable"; + } + + # Archivos estaticos + location /static { + alias /var/www/padel-pro/apps/web/public; + expires 30d; + add_header Cache-Control "public, immutable"; + } +} +``` + +### 3. Habilitar el Sitio + +```bash +sudo ln -s /etc/nginx/sites-available/padel-pro /etc/nginx/sites-enabled/ + +# Verificar configuracion +sudo nginx -t + +# Recargar Nginx +sudo systemctl reload nginx +``` + +--- + +## SSL con Lets Encrypt + +### 1. Instalar Certbot + +```bash +sudo apt install certbot python3-certbot-nginx +``` + +### 2. Obtener Certificado + +```bash +sudo certbot --nginx -d tudominio.com -d www.tudominio.com +``` + +### 3. Renovacion Automatica + +Certbot configura automaticamente la renovacion. Verificar: + +```bash +sudo certbot renew --dry-run +``` + +### 4. Configurar Cron (si es necesario) + +```bash +sudo crontab -e +``` + +Agregar: + +```cron +0 12 * * * /usr/bin/certbot renew --quiet +``` + +--- + +## Despliegue con Docker + +### 1. Archivo docker-compose.yml + +El archivo `docker-compose.yml` ya esta incluido en el proyecto. Ubicado en `/root/Padel/docker-compose.yml`. + +### 2. Configurar Variables + +Crear `.env` en la raiz del proyecto: + +```env +POSTGRES_USER=padel_user +POSTGRES_PASSWORD=PASSWORD_SEGURO +POSTGRES_DB=padel_pro +DATABASE_URL=postgresql://padel_user:PASSWORD_SEGURO@db:5432/padel_pro?schema=public +NEXTAUTH_SECRET=tu-clave-secreta-generada +NEXTAUTH_URL=https://tudominio.com +NEXT_PUBLIC_APP_URL=https://tudominio.com +``` + +### 3. Construir e Iniciar + +```bash +# Construir imagenes +docker compose build + +# Iniciar servicios +docker compose up -d + +# Ver logs +docker compose logs -f + +# Ejecutar migraciones +docker compose exec web pnpm db:push + +# Sembrar datos (opcional) +docker compose exec web pnpm db:seed +``` + +### 4. Comandos Utiles + +```bash +# Detener servicios +docker compose down + +# Reiniciar +docker compose restart + +# Ver estado +docker compose ps + +# Acceder al contenedor +docker compose exec web sh + +# Backup de base de datos +docker compose exec db pg_dump -U padel_user padel_pro > backup.sql +``` + +--- + +## Monitoreo y Mantenimiento + +### Monitoreo con PM2 + +```bash +# Dashboard en tiempo real +pm2 monit + +# Metricas web (opcional) +pm2 install pm2-server-monit +``` + +### Backup de Base de Datos + +Crear script `/opt/scripts/backup-padel.sh`: + +```bash +#!/bin/bash +BACKUP_DIR="/var/backups/padel-pro" +DATE=$(date +%Y%m%d_%H%M%S) +FILENAME="padel_pro_$DATE.sql.gz" + +mkdir -p $BACKUP_DIR + +# Crear backup +pg_dump -U padel_user padel_pro | gzip > "$BACKUP_DIR/$FILENAME" + +# Eliminar backups antiguos (mantener 7 dias) +find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete + +echo "Backup completado: $FILENAME" +``` + +Configurar cron: + +```bash +chmod +x /opt/scripts/backup-padel.sh +crontab -e +``` + +```cron +0 2 * * * /opt/scripts/backup-padel.sh +``` + +### Actualizaciones + +```bash +cd /var/www/padel-pro + +# Obtener cambios +git pull origin main + +# Instalar dependencias +pnpm install --frozen-lockfile + +# Construir +pnpm build + +# Ejecutar migraciones (si hay) +pnpm db:push + +# Reiniciar aplicacion +pm2 reload padel-pro +``` + +### Logs + +```bash +# Logs de la aplicacion +pm2 logs padel-pro --lines 100 + +# Logs de Nginx +tail -f /var/log/nginx/padel-pro.error.log + +# Logs de PostgreSQL +tail -f /var/log/postgresql/postgresql-16-main.log +``` + +### Health Check + +Crear script `/opt/scripts/health-check.sh`: + +```bash +#!/bin/bash +HEALTH_URL="https://tudominio.com/api/health" +RESPONSE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_URL) + +if [ $RESPONSE != "200" ]; then + echo "ERROR: Health check failed with status $RESPONSE" + # Enviar alerta (email, Slack, etc.) + pm2 restart padel-pro +fi +``` + +--- + +## Seguridad + +### Firewall (UFW) + +```bash +sudo ufw allow ssh +sudo ufw allow 'Nginx Full' +sudo ufw enable +``` + +### Fail2ban + +```bash +sudo apt install fail2ban +sudo systemctl enable fail2ban +``` + +### Headers de Seguridad + +Agregar a la configuracion de Nginx: + +```nginx +add_header X-Frame-Options "SAMEORIGIN" always; +add_header X-Content-Type-Options "nosniff" always; +add_header X-XSS-Protection "1; mode=block" always; +add_header Referrer-Policy "strict-origin-when-cross-origin" always; +``` + +--- + +## Solucion de Problemas + +### La aplicacion no inicia + +```bash +# Verificar logs +pm2 logs padel-pro --err + +# Verificar puertos +netstat -tlnp | grep 3000 + +# Verificar conexion a DB +psql -U padel_user -h localhost padel_pro -c "SELECT 1" +``` + +### Error de conexion a base de datos + +```bash +# Verificar servicio +sudo systemctl status postgresql + +# Verificar logs +tail -f /var/log/postgresql/postgresql-16-main.log + +# Probar conexion +psql "postgresql://padel_user:PASSWORD@localhost:5432/padel_pro" +``` + +### Nginx devuelve 502 + +```bash +# Verificar que la app este corriendo +pm2 status + +# Verificar configuracion +sudo nginx -t + +# Ver logs +tail -f /var/log/nginx/padel-pro.error.log +``` + +--- + +## Checklist de Produccion + +- [ ] Variables de entorno configuradas correctamente +- [ ] Base de datos con password seguro +- [ ] NEXTAUTH_SECRET generado de forma segura +- [ ] SSL/HTTPS configurado +- [ ] Firewall configurado +- [ ] Backups automaticos +- [ ] Monitoreo configurado +- [ ] Logs rotados +- [ ] Credenciales por defecto cambiadas +- [ ] Rate limiting configurado +- [ ] Health checks implementados