Preparación del Entorno de Desarrollo

Esta guía detallada te ayudará a configurar tu entorno de desarrollo local para trabajar en UnoSportClub.

Requisitos del Sistema

Software Requerido

  • Node.js: Versión 24.x (alineada con CI en .github/workflows/ci.yml)

  • npm: Versión 9 o superior

  • Git: Para control de versiones

  • PostgreSQL: Versión 14 o superior (local o acceso a instancia remota)

  • Angular CLI: Incluido como dependencia del proyecto

Verificar Instalaciones

node --version      # Debe ser v24.x (CI)
npm --version       # Debe ser 9.x o superior
git --version
psql --version      # Debe ser PostgreSQL 14+

Herramientas Recomendadas

  • Editor de código: Visual Studio Code (recomendado)

  • Extensiones VS Code:

  • Angular Language Service

  • ESLint

  • Prettier

  • GitLens

  • PostgreSQL

  • Cliente PostgreSQL: pgAdmin, DBeaver, o psql CLI

  • Cliente REST: Postman o Insomnia (para probar APIs)

Configuración Inicial del Proyecto

Clonar el Repositorio

git clone --branch develop git@github.com:cortex-ia-com-co/unosportclub.git
cd unosportclub

El repositorio es un monorepo único: functions/, docs/, projects/* y src/ viven en el mismo clone. No uses --recursive ni submódulos.

Instalar Dependencias

# Instalar dependencias del proyecto principal
npm install

# Instalar dependencias de Functions
cd functions
npm install
cd ..

El comando npm install en la raíz ejecutará automáticamente las migraciones de base de datos si las variables de entorno están configuradas.

Configuración de Base de Datos Local

Instalar PostgreSQL

Fedora/RHEL:

sudo dnf install postgresql postgresql-server postgresql-contrib
sudo postgresql-setup --initdb
sudo systemctl enable postgresql
sudo systemctl start postgresql

Ubuntu/Debian:

sudo apt update
sudo apt install postgresql postgresql-contrib
sudo systemctl start postgresql
sudo systemctl enable postgresql

macOS (Homebrew):

brew install postgresql@14
brew services start postgresql@14

Windows:

Descarga el instalador desde https://www.postgresql.org/download/windows/

Configurar Autenticación (Fedora/RHEL)

En Fedora, PostgreSQL usa autenticación ident por defecto. Para permitir autenticación por contraseña, configura pg_hba.conf:

# Obtener la ruta del archivo de configuración
sudo -u postgres psql -t -c "SHOW hba_file;"

# Hacer backup del archivo
sudo cp /var/lib/pgsql/data/pg_hba.conf /var/lib/pgsql/data/pg_hba.conf.backup

# Cambiar ident por md5 para conexiones locales
sudo sed -i 's/^host.*all.*all.*127.0.0.1\/32.*ident$/host    all             all             127.0.0.1\/32            md5/' /var/lib/pgsql/data/pg_hba.conf
sudo sed -i 's/^host.*all.*all.*::1\/128.*ident$/host    all             all             ::1\/128                 md5/' /var/lib/pgsql/data/pg_hba.conf

# Recargar PostgreSQL
sudo systemctl reload postgresql

Crear Usuario y Bases de Datos

# Conectar como usuario postgres
sudo -u postgres psql

# Crear usuario con contraseña
CREATE USER unosportclub WITH PASSWORD 'unosportclub_password';

# Crear bases de datos (desarrollo y test)
CREATE DATABASE unosportclub OWNER unosportclub;
CREATE DATABASE unosportclub_test OWNER unosportclub;

# Otorgar permisos
GRANT ALL PRIVILEGES ON DATABASE unosportclub TO unosportclub;
GRANT ALL PRIVILEGES ON DATABASE unosportclub_test TO unosportclub;

# Salir
\q

Instalar Extensión btree_gist

La extensión btree_gist es requerida para algunas migraciones:

# Fedora/RHEL: Instalar paquete contrib
sudo dnf install postgresql-contrib

# Crear extensión en ambas bases de datos
sudo -u postgres psql -d unosportclub -c "CREATE EXTENSION IF NOT EXISTS btree_gist;"
sudo -u postgres psql -d unosportclub_test -c "CREATE EXTENSION IF NOT EXISTS btree_gist;"

Configurar Variables de Entorno

Crea el archivo functions/.env:

cd functions
cp .env.example .env

Edita functions/.env con tu configuración local:

# Base de datos de desarrollo
DB_HOST=localhost
DB_PORT=5432
DB_NAME=unosportclub
DB_USER=unosportclub
DB_PASSWORD=unosportclub_password

# Base de datos de test
DB_TEST_HOST=localhost
DB_TEST_PORT=5432
DB_TEST_NAME=unosportclub_test
DB_TEST_USER=unosportclub
DB_TEST_PASSWORD=unosportclub_password

# SSL (false para desarrollo local)
DB_SSL=false

# Alternativa: Usar DATABASE_URL
# DATABASE_URL=postgresql://unosportclub:unosportclub_password@localhost:5432/unosportclub
# DATABASE_TEST_URL=postgresql://unosportclub:unosportclub_password@localhost:5432/unosportclub_test

Ejecutar Migraciones y Seeders

# Desde la raíz del proyecto
npm run db:migrate

Esto creará todas las tablas y cargará los datos iniciales.

Verificar Instalación de Base de Datos

# Verificar conexión
PGPASSWORD=unosportclub_password psql -h localhost -U unosportclub -d unosportclub -c "SELECT version();"

# Ver tablas creadas
PGPASSWORD=unosportclub_password psql -h localhost -U unosportclub -d unosportclub -c "\dt"

# O usando el script de prueba del proyecto
npm run db:test

Deberías ver las siguientes tablas:

  • user

  • client

  • document_type

  • court_type

  • court

  • reservation_type

  • reservation_status

  • reservation

  • tariff

  • tariff_class

  • payment_type

  • payment

  • discount

  • class

  • enrollment

  • schema_migrations

OAuth2 local y API

La autenticación usa OAuth2 local (OIDC discovery + JWT RS256). Configura las variables en functions/.env (OAUTH2_*, SIGNER_KEY, SALT_SEPARATOR).

Pruebas locales: Testing con OAuth2 local.

MCP (Cursor / clientes OAuth usuario)

El endpoint POST /api/mcp usa OAuth2 de usuario (authorization_code + PKCE), no credenciales M2M de /sudo/machines.

Variables en functions/.env:

MCP_OAUTH_CLIENT_ID=unosport-mcp
MCP_OAUTH_REDIRECT_URIS=http://localhost:*,http://localhost:*/callback,https://vscode.dev/redirect
UNOSPORT_PANEL_URL=http://localhost:6101

Flujo local:

  1. El cliente MCP (p. ej. Cursor) abre GET /api/authorize?client_id=…​&redirect_uri=…​&response_type=code&code_challenge=…​&code_challenge_method=S256&scope=mcp+panel+openid.

  2. Redirección al login del panel (/login?oauth_state=…​).

  3. Tras login, el panel llama POST /oauth/authorize/complete y redirige al redirect_uri con code.

  4. Intercambio en POST /oauth/token (grant_type=authorization_code, code_verifier, client_id).

  5. Llamadas MCP con Authorization: Bearer (JWT de usuario con scope mcp y permiso panel).

Metadatos RFC 9728: GET /.well-known/oauth-protected-resource/mcp.

Descubrimiento OIDC: GET /.well-known/openid-configuration (incluye authorization_endpoint, grant_types_supported con authorization_code, scope mcp).

Desarrollo local (todas las apps)

Desde la raíz del monorepo:

npm run dev:serve

Levanta API (:6000) y las cinco SPAs (:6100:6104). Alternativa por proyecto: npm start, npm run start:panel, npm run start:trainer, npm run start:sudo, npm run start:accounting.

Configuración del Editor

Visual Studio Code

Crea o edita .vscode/settings.json:

{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
  "typescript.preferences.importModuleSpecifier": "relative",
  "files.exclude": {
    "**/.git": true,
    "**/.DS_Store": true,
    "**/node_modules": true,
    "**/dist": true
  },
  "search.exclude": {
    "**/node_modules": true,
    "**/dist": true,
    "**/.angular": true
  }
}

Configuración de ESLint

El proyecto usa ESLint con configuración de Google. Asegúrate de tener la extensión instalada y que respete las reglas del proyecto.

Configuración de Prettier

El proyecto incluye configuración de Prettier en package.json. Asegúrate de que tu editor lo respete.

Estructura del Proyecto

Directorios Principales

unosportclub/
├── src/                    # App cliente (6100)
├── projects/
│   ├── panel/              # Panel operador (6101)
│   ├── trainer/            # Panel entrenador (6102)
│   ├── sudo/               # Panel sudo (6103)
│   ├── accounting/         # Contabilidad NIIF (6104)
│   └── common/             # @cortex-ia-com-co/common
├── functions/              # API Express (6000)
│   ├── server.js
│   ├── routes/
│   ├── db/
│   └── utils/
├── docs/                   # Antora
├── docker/                 # Imagen unificada
└── Dockerfile

Archivos Importantes

  • package.json: Scripts raíz (dev:serve, test, build:production:all)

  • functions/package.json: API y tests backend

  • angular.json: Cinco aplicaciones Angular

  • functions/.env: Variables de entorno (no versionado)

Scripts de Desarrollo

Scripts Principales

npm run dev:serve          # API + 5 SPAs (recomendado)
npm start                  # Solo app cliente
npm run start:panel        # Solo panel
npm test                   # Suite completa (common + functions + Angular)
npm run build:production:all
npm run db:migrate         # Migraciones + seeders

Scripts del Backend

cd functions

# Desarrollo
node server.js            # API en :6000 (o server_wrapper.js con --watch)
npm run lint              # Verificar código con ESLint

# Testing
npm test                  # Ejecutar tests
npm run test:watch        # Tests en modo watch
npm run test:coverage     # Tests con cobertura

Variables de Entorno del Backend

El servidor backend requiere las siguientes variables de entorno en functions/.env:

# Base de datos
DATABASE_URL=postgresql://usuario:password@host:puerto/database

# Redis (opcional, para escalado horizontal del Relay)
REDIS_URL=redis://localhost:6379

# Sistema Relay (opcional)
REALTIME_ENABLED=true

# Puerto del servidor (opcional, default: 6000)
PORT=6000

Almacenamiento de comprobantes de pago (S3/R2)

Los comprobantes de pago de reserva (payment.foto) se guardan en un bucket S3-compatible mediante PaymentReceiptStorage (functions/services/payment-receipt-storage.js). El bucket debe permanecer privado; el panel y las integraciones descargan la imagen con GET /admin/booking/{bookingId}/payment/{paymentId}/foto.

En functions/.env (ver también functions/.env.example):

AWS_ACCESS_KEY_ID=your-key-id
AWS_SECRET_ACCESS_KEY=your-secret-access-key
AWS_DEFAULT_REGION=us-east-1
AWS_BUCKET=your-bucket-name
AWS_ENDPOINT=https://your-account.r2.cloudflarestorage.com
AWS_USE_PATH_STYLE_ENDPOINT=true
AWS_PUBLIC_BASE_URL=
  • AWS_BUCKET: nombre del bucket (obligatorio para subida/descarga).

  • AWS_ENDPOINT + AWS_USE_PATH_STYLE_ENDPOINT=true: habitual en Cloudflare R2.

  • AWS_PUBLIC_BASE_URL: opcional; si se define, la URL guardada en BD usa ese prefijo en lugar del endpoint path-style.

Tras configurar, aplica migraciones (npm run db:migrate en functions/) para la columna payment.foto.

Prueba manual (multipart):

  1. Obtén sesión y CSRF: GET /api/admin/…​ con Bearer; lee cookie XSRF-TOKEN.

  2. POST /api/admin/booking/{id}/payment con -F foto=@archivo.jpg y campos de pago (ver Comprobantes de pago).

  3. Verifica en el panel /booking/payment/:id con Ver, o GET …​/payment/{paymentId}/foto.

  4. Para quitar el comprobante: DELETE …​/payment/{paymentId}/foto (elimina el objeto en el bucket y pone payment.foto = null).

  5. Para eliminar el pago completo: DELETE …​/payment/{paymentId} (si payment.foto tiene valor, también elimina el objeto en el bucket).

Si S3 no está configurado, POST multipart, GET …​/foto, DELETE …​/foto y DELETE …​/payment/{paymentId} (con comprobante) responden 503.

Servidor Backend Local

Iniciar Servidor Backend

cd functions
node server.js

El servidor estará disponible en: * API REST: http://localhost:6000/api * Health Check: http://localhost:6000/health * Swagger Docs: http://localhost:6000/api/api-docs * Sistema Relay: http://localhost:6000/realtime (si está habilitado)

Iniciar con PM2 (Producción Local)

cd functions
pm2 start server.js --name unosportclub-api
pm2 logs unosportclub-api

Flujo de Trabajo de Desarrollo

1. Crear una Rama

git checkout -b feature/nombre-de-la-feature

2. Desarrollo Local

# Terminal 1: Servidor Angular
npm start

# Terminal 2: Servidor Backend (Express)
cd functions
node server.js

# Terminal 3: Base de datos (si es necesario)
psql -U unosportclub -d unosportclub

# Opcional: Redis (si usas escalado horizontal del Relay)
redis-server

3. Ejecutar Tests

# Tests de Angular
npm test

# Tests de Functions
cd functions
npm test

4. Verificar Código

# Lint de Functions
cd functions
npm run lint

# Build para verificar errores de TypeScript
npm run build

5. Commit y Push

git add .
git commit -m "feat: descripción del cambio"
git push origin feature/nombre-de-la-feature

Configuración de Git

.gitignore

El proyecto incluye un .gitignore que excluye:

  • node_modules/

  • dist/

  • .env y functions/.env

  • Archivos de build y cache

  • Archivos del IDE

Hooks de Git (Opcional)

Puedes configurar pre-commit hooks para ejecutar lint y tests automáticamente usando herramientas como husky.

Solución de Problemas Comunes

Error: Puerto ya en uso

Si el puerto 4200 (Angular) o 6000 (Backend) está en uso:

# Encontrar proceso usando el puerto
lsof -i :4200
lsof -i :6000

# Matar el proceso
kill -9 <PID>

# O cambiar el puerto del backend
cd functions
PORT=3001 node server.js

Error: Variables de Entorno No Cargadas

Asegúrate de que: * El archivo functions/.env existe * Las variables están correctamente formateadas * No hay espacios alrededor del = en las variables

Error: Base de Datos No Conecta

Verifica: * PostgreSQL está corriendo: sudo systemctl status postgresql * Las credenciales en .env son correctas * El usuario tiene permisos: GRANT ALL PRIVILEGES ON DATABASE unosportclub TO unosportclub; * En Fedora, verifica que pg_hba.conf use md5 en lugar de ident para conexiones locales * La extensión btree_gist está instalada: sudo dnf install postgresql-contrib

Error: Migraciones No Se Ejecutan

# Ejecutar manualmente
npm run db:migrate

# Ver estado de migraciones
psql -U unosportclub -d unosportclub -c "SELECT * FROM schema_migrations;"

Error: Build de Angular Falla

# Limpiar cache
rm -rf node_modules .angular dist
npm install
npm run build

Contabilidad y cierre de caja

El módulo accounting (DB_NAME_ACCOUNTING) gestiona períodos contables y el cierre NIIF (IAS 1).

Período contable y caja (panel)

  • Cada cierre de caja en el panel registra un asiento contable (bóveda ↔ cajero) solo si existe un período abierto que cubra la fecha de cierre.

  • Si no hay período, la API responde con un mensaje en español indicando que debe abrirse o extenderse un período en contabilidad.

  • El cierre de período en accounting valida: balance de comprobación, cierre de resultados (4.x/5.x → 3.1) y ecuación patrimonial.

Cierre de período (flujo operativo)

  1. Operaciones del período: pagos (D cajero/banco, C 4.1), cierres de caja (traslados 1.x).

  2. Cierre de resultados: saldar ingresos/gastos y trasladar utilidad a patrimonio (cuenta 3.1).

  3. Cierre administrativo: bloquear nuevos asientos cuando activo + pasivo + patrimonio = 0.

API relevante:

  • GET /accounting/periods/:id/close-readiness — checklist previo al cierre.

  • POST /accounting/periods/:id/close-results — cierre explícito de resultados a patrimonio.

  • POST /accounting/periods/:id/close — cierra el período (ejecuta cierre de resultados si aplica).

Instalación BD contabilidad: node functions/db/install-accounting.js (ver functions/db/README.md).

Hora mural y zonas horarias

Las columnas reservation.checking y checkout son TIMESTAMP WITHOUT TIME ZONE con hora mural América/Bogotá.

  • Backend: serialización con TO_CHAR (checking_date, checking_time, …); entrada normalizada con normalizeTimestampForDb.

  • Frontend: utilidades reservation-wall-time en @cortex-ia-com-co/common.

  • No usar new Date(cadenaConZ).toLocaleString() para mostrar horarios de cancha o eventos.

Referencias: xref:api-reference.adoc#_fechas_y_horas_hora_mural, xref:data-model.adoc#_2_8_reservation, xref:coding-standards.adoc#_fechas_de_reserva_y_eventos.

Publicación de releases

Este checklist operativo forma parte del marco descrito en Entornos, versiones y ciclos de lanzamiento. Pipeline técnico: CI/CD y DevOps.

  1. Commit chore(release): vX.Y.Z en rama de línea (ej. 0.4) actualizando RELEASE_NOTES.md y package.json.

  2. Push de la rama 0.4.

  3. gh release create vX.Y.Z — el tag dispara jobs build y release (imagen GHCR).

  4. Sincronizar develop con la rama de release.

Documentación Antora (docs/): añadir entrada en docs/RELEASE_NOTES.md y ejecutar npm run build:local antes de publicar.

Próximos Pasos

Una vez configurado tu entorno:

  1. Revisa la Arquitectura del Software

  2. Familiarízate con el Modelo de Datos

  3. Explora la Referencia de API

  4. Revisa los Flujos de Trabajo principales

  5. Consulta el Metodología de Desarrollo Ágil