- 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>
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 horario404: Cancha o cliente no encontrado400: 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.