Files
app-padel/docs/API.md
Ivan 864902df81 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 <noreply@anthropic.com>
2026-02-01 07:49:33 +00:00

22 KiB

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

GET /api/sites

Autenticacion: Requerida

Respuesta Exitosa (200):

[
  {
    "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

GET /api/courts

Autenticacion: Requerida

Parametros de Query:

Parametro Tipo Descripcion
siteId string Filtrar por sede

Respuesta Exitosa (200):

[
  {
    "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

POST /api/courts

Autenticacion: Requerida Roles permitidos: SUPER_ADMIN, SITE_ADMIN

Cuerpo de la Solicitud:

{
  "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):

{
  "id": "clxyz789",
  "name": "Cancha 7",
  "type": "OUTDOOR",
  "status": "AVAILABLE",
  "pricePerHour": 25.00,
  "isActive": true,
  "site": { ... }
}

Obtener Cancha por ID

GET /api/courts/{id}

Autenticacion: Requerida

Respuesta Exitosa (200):

{
  "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

PUT /api/courts/{id}

Autenticacion: Requerida Roles permitidos: SUPER_ADMIN, SITE_ADMIN

Cuerpo de la Solicitud (todos los campos opcionales):

{
  "name": "Cancha 1 VIP",
  "type": "INDOOR",
  "status": "MAINTENANCE",
  "pricePerHour": 35.00,
  "description": "Cancha premium renovada",
  "features": ["LED", "Cristal", "Climatizada"],
  "isActive": true
}

Eliminar Cancha

DELETE /api/courts/{id}

Autenticacion: Requerida Roles permitidos: SUPER_ADMIN, SITE_ADMIN

Respuesta Exitosa (200):

{
  "message": "Court deleted successfully"
}

Obtener Disponibilidad

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

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):

[
  {
    "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

POST /api/bookings

Autenticacion: Requerida

Cuerpo de la Solicitud:

{
  "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):

{
  "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

GET /api/bookings/{id}

Actualizar Reserva

PUT /api/bookings/{id}

Cuerpo de la Solicitud:

{
  "status": "CONFIRMED",
  "notes": "Cliente confirmado por telefono",
  "playerNames": ["Juan", "Maria", "Pedro", "Ana"]
}

Cancelar Reserva

DELETE /api/bookings/{id}

Cuerpo Opcional:

{
  "cancelReason": "Cliente solicito cancelacion"
}

Registrar Pago de Reserva

POST /api/bookings/{id}/pay

Cuerpo de la Solicitud:

{
  "amount": 45.00,
  "paymentType": "CARD",
  "reference": "TRX-123456"
}

Clientes (Clients)

Listar Clientes

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):

{
  "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

POST /api/clients

Cuerpo de la Solicitud:

{
  "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

GET /api/clients/{id}

Actualizar Cliente

PUT /api/clients/{id}

Obtener Membresia del Cliente

GET /api/clients/{id}/membership

Productos (Products)

Listar Productos

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):

[
  {
    "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

POST /api/products

Autenticacion: Requerida Roles permitidos: SUPER_ADMIN, ORG_ADMIN, SITE_ADMIN

Cuerpo de la Solicitud:

{
  "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

PATCH /api/products/{id}/stock

Cuerpo de la Solicitud:

{
  "adjustment": 10,
  "reason": "Reposicion de inventario"
}

Listar Categorias

GET /api/products/categories

Ventas (Sales)

Listar Ventas

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):

[
  {
    "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

POST /api/sales

Cuerpo de la Solicitud:

{
  "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

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:

{
  "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

POST /api/cash-register

Cuerpo de la Solicitud:

{
  "siteId": "clxyz123",
  "openingAmount": 100.00
}

Cerrar Caja

PUT /api/cash-register/{id}

Cuerpo de la Solicitud:

{
  "closingAmount": 345.50,
  "notes": "Cuadre correcto"
}

Obtener Transacciones

GET /api/cash-register/{id}/transactions

Torneos (Tournaments)

Listar Torneos

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):

[
  {
    "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

POST /api/tournaments

Roles permitidos: SUPER_ADMIN, ORG_ADMIN, SITE_ADMIN

Cuerpo de la Solicitud:

{
  "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

GET /api/tournaments/{id}

Actualizar Torneo

PUT /api/tournaments/{id}

Listar Inscripciones

GET /api/tournaments/{id}/inscriptions

Respuesta Exitosa (200):

[
  {
    "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

POST /api/tournaments/{id}/inscriptions

Cuerpo de la Solicitud:

{
  "player1Id": "clxyz100",
  "player2Id": "clxyz101",
  "teamName": "Los Campeones"
}

Generar Bracket

POST /api/tournaments/{id}/generate-bracket

Actualizar Resultado de Partido

PUT /api/tournaments/{id}/matches/{matchId}

Cuerpo de la Solicitud:

{
  "score1": "6-4",
  "score2": "6-3",
  "winnerId": "clxyzabc"
}

Planes de Membresia (Membership Plans)

Listar Planes

GET /api/membership-plans

Parametros de Query:

Parametro Tipo Descripcion
includeInactive boolean Incluir planes inactivos

Respuesta Exitosa (200):

[
  {
    "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

POST /api/membership-plans

Roles permitidos: SUPER_ADMIN, ORG_ADMIN

Cuerpo de la Solicitud:

{
  "name": "Plan Basico",
  "description": "Plan de entrada",
  "price": 29.00,
  "durationMonths": 1,
  "freeHours": 2,
  "bookingDiscount": 10,
  "storeDiscount": 5,
  "extraBenefits": ["Newsletter exclusivo"]
}

Actualizar Plan

PUT /api/membership-plans/{id}

Membresias (Memberships)

Listar Membresias

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):

{
  "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

POST /api/memberships

Roles permitidos: SUPER_ADMIN, ORG_ADMIN, SITE_ADMIN, RECEPTIONIST

Cuerpo de la Solicitud:

{
  "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

POST /api/memberships/{id}/renew

Cuerpo de la Solicitud:

{
  "planId": "clxyz300",
  "paymentMethod": "CARD"
}

Dashboard

Obtener Estadisticas

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):

{
  "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

{
  "error": "No autorizado"
}

Codigo: 401

Error de Permisos

{
  "error": "Forbidden: Insufficient permissions"
}

Codigo: 403

Recurso No Encontrado

{
  "error": "Court not found"
}

Codigo: 404

Conflicto

{
  "error": "Ya existe una reserva en ese horario"
}

Codigo: 409

Error de Validacion

{
  "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:

{
  "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.