ERES LEYENDA
MAPA DE ARQUITECTURA & DESARROLLADOR
📄 Ver Versión Markdown (.md) 🚀 Abrir Portal SPA (/app/)
⚡ SaaS Multi-Deporte & Multi-Tenant

Mapa de Arquitectura, Módulos y Referencia Técnica

Guía viva e interactiva para cualquier desarrollador que asuma el mantenimiento, extensión o despliegue de nodeapp. Integra cronometraje oficial por splits, telemetría GPS con WebSockets y UDP, gestión logística de kits, soporte PQRS y sincronización directa con WordPress.

48+
Endpoints API REST
14
Tablas Relacionales
6
Servicios Centrales
4
Roles de Acceso (RBAC)

🌳 Estructura de Directorios en Disco

nodeapp/
├── server.js                      # Inicializador HTTP, Express, WebSockets y receptor UDP (:5005)
├── package.json                   # Dependencias y scripts de ejecución (start, dev, build:frontend)
├── .env / .env.example            # Variables de entorno (DB_DIALECT, puertos, JWT_SECRET)
├── ARCHITECTURE_MAP.md            # Mapa de arquitectura en formato Markdown
├── README.md                      # Resumen ejecutivo de instalación rápida
│
├── config/
│   └── database.js                # Abstracción agnóstica de base de datos (SQLite / MySQL)
│
├── data/
│   └── eresleyenda.db             # Archivo de base de datos local SQLite
│
├── db/
│   ├── schema.sql                 # Esquema DDL con 14 tablas relacionales e índices
│   └── seeds.js                   # Semillas de demostración, ruta Guatapé y credenciales RBAC
│
├── middleware/
│   ├── authMiddleware.js          # Validación JWT, requireRole(['staff','admin',...]) y API Keys
│   └── tenantMiddleware.js        # Detección y aislamiento de Marcas Blancas por slug/dominio
│
├── services/
│   ├── telemetryService.js        # Normalización GPS, geocercas, buffer en memoria y Socket.io
│   ├── timingEngine.js            # Reglas de Half Triatlón, distancias Haversine y cálculo de Pace
│   ├── gpxParserService.js        # Parser XML GPX/TCX y detector de atajos / cortes de ruta
│   ├── gpsSummaryService.js       # Ingesta dual CSV/XML de resúmenes de tiempos y splits oficiales
│   ├── simulatorService.js        # Generador de estrés concurrente (10 a 300 atletas simultáneos)
│   └── wpSyncService.js           # Mapeo de campos de WooCommerce e ingesta de inscripciones
│
├── routes/api/
│   ├── auth.js                    # Registro, Login, perfil /me y edición de usuario
│   ├── athlete.js                 # Historial de carreras, splits y visor del track individual
│   ├── athletes.js                # CRUD administrativo del padrón de atletas
│   ├── staff.js                   # Búsqueda en carpa, entrega de kits, retorno de GPS e incidentes
│   ├── tickets.js                 # Sistema PQRS / Soporte con hilos de mensajería
│   ├── admin.js                   # Gestión de personal de staff y alta de eventos
│   ├── events.js                  # Listado de eventos y cambio de estados (scheduled/live/finished)
│   ├── tenants.js                 # CRUD de inquilinos, cuotas y estilos de marca blanca
│   ├── telemetry.js               # Ingesta HTTP de coordenadas GPS y estadísticas
│   ├── gpx.js                     # Subida de tracks GPX/TCX y auditoría de atajos
│   ├── leaderboard.js             # Tabla de posiciones y tiempos oficiales por disciplina
│   ├── simulator.js               # Controladores de inicio/parada de la simulación masiva
│   ├── wpSync.js                  # Webhooks e importación masiva de WordPress
│   └── certificate.js             # Extracción de datos para diploma oficial de finalista
│
├── frontend/                      # SPA moderna en Vue 3 + Pinia + Vite
│   ├── index.html                 # Template base de Vite
│   ├── package.json               # Dependencias del frontend
│   ├── vite.config.js             # Configuración de compilación con base '/app/'
│   └── src/
│       ├── main.js                # Bootstrap de Vue 3, Pinia y Router
│       ├── App.vue                # Componente raíz con Layout dinámico
│       ├── style.css              # Estilos globales y paleta de diseño deportivo
│       ├── router/
│       │   └── index.js           # Vue Router con Navigation Guards y roles RBAC
│       ├── stores/
│       │   ├── auth.js            # Estado reactivo del usuario y roles
│       │   └── tenant.js          # Estado de la Marca Blanca e identidad visual
│       ├── Layouts/
│       │   └── AdminLayout.vue    # Layout con barra de navegación y menú RBAC
│       └── views/
│           ├── auth/              # LoginView.vue y RegisterView.vue
│           ├── athlete/           # Profile, Races, Performance, Track, Tickets
│           ├── staff/             # Checkin (kits/chips), Returns y Reporte de Incidentes
│           ├── admin/             # Gestión de Eventos, Staff, Atletas y PQRS
│           └── superadmin/        # SuperAdminView.vue (Gestor SaaS de Marcas Blancas)
│
├── public/                        # Archivos estáticos servidos directamente por Express
│   ├── app/                       # Compilado de producción de la SPA Vue 3 (/app/*)
│   ├── index.html                 # Dashboard y hub central con arquitectura de menú lateral
│   ├── architecture_map.html      # Este mapa interactivo de arquitectura
│   ├── live.html                  # Visor cartográfico en tiempo real con Leaflet
│   ├── leaderboard.html           # Tabla de posiciones y tiempos en vivo con menú lateral
│   ├── certificate.html           # Diploma digital de finalista para impresión/descarga
│   ├── admin.html                 # Consola de dirección de carrera con menú lateral y tabs reactivos
│   ├── superadmin.html            # Consola SaaS con menú lateral y simulador de 300 atletas
│   ├── css/                       # Estilos (main.css, admin.css, live.css, sidebar-layout.css)
│   └── js/                        # Scripts (live-tracker.js, leaderboard.js, admin.js, sidebar.js)
│
├── docker/
│   ├── Dockerfile                 # Contenedor Node.js optimizado
│   └── docker-compose.yml         # Orquestación con contenedor MySQL y Node
│
└── uploads/                       # Directorio de subida temporal de archivos GPX/TCX

⚙️ Servidor Central (server.js)

Punto de convergencia en tiempo real donde conviven 3 protocolos de transporte:

  • Servidor HTTP Express: Expone la API REST en /api/* y sirve la SPA Vue 3 en /app/*.
  • Servidor Socket.io: Canal bidireccional que transmite eventos a clientes suscritos por sala de carrera (event_{id}).
  • Receptor UDP en Puerto 5005: Escucha datagramas directos de chips GPS 4G con decodificación de tramas JSON y CSV (IMEI,lat,lon,speed,bat).
  • Bootstrap Secuencial: Ejecuta db.initSchema() seguido de seedDatabase() asegurando que la base de datos esté lista antes de aceptar tráfico.

🗄️ Capa de Base de Datos Relacional

💡
Compatibilidad Agnóstica (MariaDB / MySQL & SQLite): El archivo config/database.js abstrae las operaciones con métodos unificados con Promesas: all(), get(), run() y exec(). Actualmente configurado y conectado a MariaDB (DBngin) en 127.0.0.1:3306 con la base de datos legend_tracker (usuario root), con SQLite disponible como respaldo transparente si DB_DIALECT=sqlite.
tenants Multi-Tenant

Marcas blancas con slug, dominio, cuota de atletas y paleta de colores personalizada.

events & segments Competición

Eventos deportivos con modalidad (Half Triatlón, Aguas Abiertas, etc.), ruta GPX y disciplinas.

checkpoints Geocercas

Puntos de control con latitud, longitud y radio en metros para registrar splits automáticos.

users, judge_assignments, athletes & teams Padrón, Jueces, Relevos & RBAC

Usuarios con roles RBAC (athlete, judge, staff, admin, superadmin), asignación de jueces por carrera específica (judge_assignments), equipos de relevos (teams) y atletas con avance por punto de control.

kit_deliveries Logística

Registro de entrega de kit, notas de entrega (delivery_notes), serial GPS asignado, devolución y notas de recepción (return_notes).

support_tickets PQRS

Sistema de tickets y mensajes bidireccionales de soporte entre competidores, staff y dirección.

🛡️ Middlewares y Control de Acceso

tenantMiddleware.js

Resuelve el inquilino correspondiente inspeccionando en orden:

  • 1. Parámetro ?tenant=slug
  • 2. Headers x-tenant-slug o x-tenant-id
  • 3. Subdominio del Host HTTP
  • 4. Fallback al inquilino maestro eres-leyenda
authMiddleware.js

Seguridad por capas con JSON Web Tokens:

  • authenticateToken: Valida cabecera Bearer y actividad del usuario.
  • requireRole(['staff','admin',...]): Protección RBAC con bypass para superadmin.
  • requireTenant: Impide el acceso cruzado entre distintas marcas blancas.

🚀 Servicios y Motores de Negocio

telemetryService.js

Cerebro de la ingesta en vivo. Normaliza datos de proveedores GPS, comprueba geocercas geodésicas, actualiza al atleta y emite por WebSockets.

processTelemetry() setSocketIO() getStats()
timingEngine.js

Motor de reglas deportivas. Calcula ritmo en min/100m (nado), km/h (bici) o min/km (carrera), distancias Haversine y categorías etarias.

formatDuration() formatPace() calculateDistanceMeters()
gpxParserService.js

Procesador asíncrono de tracks XML. Extrae métricas de desnivel y ejecuta auditoría de paso obligatorio por checkpoints para detectar recortes de ruta.

parseGpxFile()
simulatorService.js

Generador de estrés para pruebas de carga. Simula hasta 300 competidores emitiendo paquetes concurrentes a velocidad configurable.

startSimulation() stopSimulation() interpolateRoutePosition()
gpsSummaryService.js

Parser dual CSV/XML de hojas de tiempos del proveedor (Final.csv/Final.xml). Concilia dorsales, genera splits oficiales y actualiza tiempos de llegada.

importGpsSummary() parseSummaryFile() parseTimeStrToSeconds()
wpSyncService.js

Integración con WooCommerce y el plugin carreras_checkout_by_sgl. Mapea metadatos sanitizados y asigna dorsales en tiempo real.

mapCheckoutMetadata() ingestAthleteFromCheckout()

🌐 Catálogo de Endpoints de la API REST

Método Endpoint URL Rol Mínimo Módulo Propósito / Descripción
POST /api/auth/login Público auth.js Autentica por correo o documento y entrega Token JWT.
POST /api/auth/register Público auth.js Registro de nuevos competidores.
GET /api/auth/me Autenticado auth.js Devuelve usuario en sesión y su ficha atlética vinculada.
PUT /api/auth/profile Autenticado auth.js Actualiza datos de contacto, EPS, foto y ficha médica.
POST /api/auth/avatar Autenticado auth.js Sube y actualiza la foto de perfil (avatar_url) del atleta o usuario.
DELETE /api/auth/avatar Autenticado auth.js Elimina la foto de perfil actual y restaura el avatar por iniciales.
GET /api/athlete/races athlete athlete.js Historial de carreras inscritas con estado de kit y chip.
GET /api/athlete/performance/:eventId athlete athlete.js Tiempos parciales por split, ritmo, posición en podio e incidentes.
GET /api/athlete/track/:eventId athlete athlete.js Ruta oficial del evento y puntos de telemetría personal en mapa.
GET /api/judge/my-events judge judge.js Retorna únicamente las carreras específicas asignadas al juez autenticado con sus checkpoints.
GET /api/judge/events/:eventId/athletes judge judge.js Lista atletas de la carrera asignada al juez con su avance actual y splits registrados.
POST /api/judge/events/:eventId/progress judge judge.js Registra el avance del atleta (punto de control, segmento, km, tiempo parcial/acumulado, llegada a meta o DNF/DQ).
POST /api/admin/judges/assign admin admin.js Asigna un juez de carrera a una competencia específica (event_id) y punto de control opcional.
DELETE /api/admin/judges/assign/:assignmentId admin admin.js Retira la asignación de un juez a una carrera específica.
GET /api/staff/athletes staff staff.js Búsqueda en carpa para entrega y devolución de kits.
POST /api/staff/kit-delivery staff staff.js Registra entrega de kit, notas de entrega (delivery_notes) y asocia serial GPS en vivo.
POST /api/staff/kit-return staff staff.js Registra recepción del chip GPS en meta con notas de devolución (return_notes).
POST /api/staff/manual-split staff staff.js Registro manual de tiempos y avances por jueces/staff en checkpoints con notas.
POST /api/staff/incidents staff staff.js Reporte de emergencias médicas, mecánicas, penalización o DNF.
GET /api/staff/incidents staff staff.js Lista de incidentes reportados en la carrera.
GET /api/tickets Autenticado tickets.js Listado de solicitudes PQRS del usuario o del inquilino.
POST /api/tickets Autenticado tickets.js Apertura de nuevo ticket (Petición, Queja, Reclamo, Soporte).
GET /api/tickets/:id Autenticado tickets.js Detalle de ticket y trazabilidad completa de mensajes.
POST /api/tickets/:id/messages Autenticado tickets.js Envía una respuesta dentro del hilo de mensajería.
PATCH /api/tickets/:id/status staff tickets.js Cambia el estado de un ticket (en progreso, resuelto, cerrado).
GET /api/admin/staff admin admin.js Lista todo el personal de logística del inquilino.
POST /api/admin/staff admin admin.js Da de alta un nuevo miembro de staff con contraseña bcrypt.
PATCH /api/admin/staff/:id/toggle admin admin.js Habilita o inhabilita credenciales de un miembro de staff.
POST /api/admin/events admin admin.js Crea un nuevo evento con segmentos y checkpoints predefinidos.
GET /api/events Público events.js Catálogo de eventos activos de la marca blanca.
PUT /api/events/:id/status admin events.js Modifica estado del evento (draft, scheduled, live, finished).
GET /api/athletes admin athletes.js Padrón completo de competidores inscritos con filtros.
POST /api/telemetry/ingest API Key telemetry.js Ingesta de paquete GPS y retransmisión por WebSockets.
GET /api/telemetry/stats Público telemetry.js Métricas de throughput en tiempo real (paquetes por segundo).
GET /api/leaderboard/:eventId Público leaderboard.js Clasificaciones oficiales, ritmos por disciplina y gaps.
POST /api/gpx/upload Autenticado gpx.js Carga y análisis asíncrono de tracks GPX con auditoría de atajos.
POST /api/gpx/import-summary admin gpx.js Importa resumen de tiempos del proveedor (Final.csv o Final.xml) y genera splits oficiales.
POST /api/gpx/athlete-track athlete gpx.js Carga track individual GPX del atleta, persiste archivo en disco y audita cortes de ruta.
GET /api/certificate/:athleteId Público certificate.js Datos oficiales para renderizado del diploma de finalista.
POST /api/simulator/start admin simulator.js Inicia simulación masiva (conteo de atletas y multiplicador de velocidad).
POST /api/simulator/stop admin simulator.js Detiene inmediatamente el generador de telemetría simulada.
GET /api/tenants/my-branding admin tenants.js Obtiene subdominio, logotipo, colores y métricas exclusivas de la empresa del Administrador.
PUT /api/tenants/my-branding admin tenants.js Personaliza el subdominio único, logotipo y colores corporativos de la empresa activa.
POST /api/tenants/my-branding/logo admin tenants.js Sube un archivo de logotipo (PNG/JPG/WEBP/SVG) para la empresa organizadora.
GET /api/tenants superadmin tenants.js Exclusivo SuperAdmin: Lista todas las empresas del sistema SaaS (aislado de otros roles).
POST /api/tenants superadmin tenants.js Exclusivo SuperAdmin: Crea una nueva empresa con subdominio, logo, colores y su Admin inicial.
POST /api/sync/wordpress/webhook API Key / Púb. wpSync.js Webhook de compras de carreras_checkout_by_sgl y WooCommerce (individuales y relevos).
GET /api/sync/wordpress/config admin, superadmin wpSync.js Consulta el estado de las credenciales API REST de WooCommerce definidas en .env.
POST /api/sync/wordpress/pull admin, superadmin wpSync.js 🔒 Importación desde API REST de WooCommerce usando WC_CONSUMER_KEY y WC_CONSUMER_SECRET de .env (con recarga en caliente de .env).

💻 Frontend SPA Moderno (Vue 3 + Pinia + Vite)

Ubicado en frontend/ y servido en producción desde public/app/ bajo la ruta base /app/*.

Pinia Stores

stores/auth.js: Token JWT, usuario activo, cierre de sesión y helpers reactivos (isAthlete, isStaff, isAdmin, isSuperAdmin).

stores/tenant.js: Identidad visual, colores primarios/secundarios y logos del inquilino activo.

Navigation Guards & Menú RBAC Estricto

router/index.js & Layouts/AdminLayout.vue: Aislamiento estricto por rol en menú lateral, barra superior y rutas (ningún usuario visualiza enlaces ni accede a vistas que no correspondan a su rol: athlete, staff, admin, superadmin).

public/js/sidebar.js: Aplica directivas [data-require-role] sin parpadeo y redirige automáticamente si un visitante o usuario sin permisos intenta abrir admin.html, superadmin.html o architecture_map.html.

📡 Protocolos de Telemetría

1. Receptor UDP (Puerto 5005)

Admite tramas de dispositivos de telemetría física con formato CSV o JSON:

CHIP-GPS-101,6.2338,-75.1612,38.5,92

2. WebSockets (Socket.io)

Eventos emitidos hacia visores Leaflet y pantallas de meta:

  • telemetry:point: Posición, velocidad, batería y distancia actualizada.
  • checkpoint:crossed: Disparado automáticamente cuando el competidor entra al radio de la geocerca.
  • athlete:finished: Cruce de la meta oficial.

📘 Guía Práctica para Nuevos Desarrolladores

¿Cómo extender la aplicación de forma segura?

  1. Agregar una nueva disciplina deportiva: Editar services/timingEngine.js y registrar la fórmula de ritmo (pace) dentro de formatPace().
  2. Crear un nuevo endpoint API: Crear o modificar la ruta en routes/api/ y aplicar los middlewares authenticateToken y requireRole(['...']).
  3. Compilar el Frontend: Tras modificar cualquier vista Vue en frontend/src/views/, ejecutar desde la raíz de nodeapp:
    npm run build:frontend
  4. Regla de Oro de Documentación: Siempre que añadas o modifiques rutas, tablas o servicios, actualiza tanto ARCHITECTURE_MAP.md como este archivo public/architecture_map.html.