# Sistema de Tracking de Trenes en Tiempo Real - España ## Descripción del Proyecto Este es un sistema web full-stack para visualizar en tiempo real la posición de todos los trenes operados por Renfe en España, con capacidad de consultar histórico mediante un timeline slider. ## Stack Tecnológico ### Backend - **Runtime**: Node.js 20+ (ES Modules) - **API**: Express.js con WebSocket (Socket.io) - **Base de Datos**: PostgreSQL 15 + PostGIS (datos geoespaciales) - **Cache**: Redis 7 - **Parser GTFS-RT**: gtfs-realtime-bindings - **Logs**: Pino ### Frontend - **Framework**: React 18 + Vite - **Mapa**: Leaflet.js + React-Leaflet - **WebSocket**: Socket.io-client - **Estilos**: CSS vanilla (sin frameworks CSS) ### Infraestructura - **Contenedores**: Docker + Docker Compose - **Reverse Proxy**: Nginx - **Migraciones**: Flyway - **Gestión**: Makefile para comandos comunes ## Arquitectura ``` ┌─────────────┐ │ Frontend │ ← React + Leaflet + Socket.io │ (Vite) │ └──────┬──────┘ │ ┌───▼────┐ │ Nginx │ ← Reverse Proxy └───┬────┘ │ ┌──────▼──────┐ │ Backend │ ← Express + Socket.io │ API │ └─┬─────────┬─┘ │ │ ┌─▼─┐ ┌──▼───┐ │DB │ │Redis │ └───┘ └──────┘ ▲ │ ┌─┴──────┐ │ Worker │ ← Polling GTFS-RT cada 30seg └────────┘ ``` ## Fuente de Datos Principal - **URL**: https://gtfsrt.renfe.com/vehicle_positions.pb - **Formato**: Protocol Buffer (GTFS Realtime) - **Frecuencia**: Actualización cada 30 segundos - **Contenido**: Posiciones GPS de trenes en tiempo real ## Estructura del Proyecto ``` trenes/ ├── backend/ # Backend Node.js │ ├── src/ │ │ ├── api/ # API REST + WebSocket │ │ │ ├── routes/ # Endpoints (trains, routes, stations, stats) │ │ │ └── server.js # Servidor principal │ │ ├── worker/ # Workers de fondo │ │ │ └── gtfs-poller.js # Polling GTFS-RT │ │ ├── lib/ # Utilidades (db, redis, logger) │ │ └── config/ # Configuración │ ├── package.json │ └── Dockerfile │ ├── frontend/ # Frontend React │ ├── src/ │ │ ├── components/ # Componentes React │ │ │ ├── TrainMap.jsx # Mapa Leaflet │ │ │ ├── TrainInfo.jsx # Panel de info │ │ │ └── Timeline.jsx # Timeline │ │ ├── hooks/ # Custom hooks │ │ │ └── useTrains.js # Hook WebSocket │ │ ├── styles/ # CSS │ │ ├── App.jsx # Componente principal │ │ └── main.jsx # Entry point │ ├── package.json │ ├── vite.config.js │ └── Dockerfile │ ├── database/ │ ├── init/ # Scripts de inicialización │ └── migrations/ # Migraciones Flyway (V1, V2, V3, V4) │ ├── nginx/ # Configuración Nginx │ ├── nginx.conf │ └── conf.d/ │ ├── docker-compose.yml # Orquestación de servicios ├── Makefile # Comandos simplificados ├── .env.example # Variables de entorno └── README.md # Documentación principal ``` ## Base de Datos ### Tablas Principales 1. **train_positions** (particionada por mes) - Histórico de todas las posiciones GPS - Incluye: lat/lon, velocidad, dirección, estado, timestamp - Particiones: nov 2025 - mar 2027 2. **trains** - Catálogo de trenes - Estado activo/inactivo 3. **routes** - Rutas/líneas (AVE, Cercanías, etc.) 4. **stations** - Estaciones con coordenadas GPS - Datos de accesibilidad y servicios 5. **alerts** - Alertas e incidencias ### Vistas - **current_train_positions**: Última posición de cada tren - **active_trains**: Trenes activos en últimas 24h ### Funciones Útiles - `get_train_path(train_id, from, to)`: Trayectoria de un tren - `get_trains_in_area(minLat, minLon, maxLat, maxLon, time)`: Trenes en área - `calculate_train_statistics(train_id, from, to)`: Estadísticas de viaje - `cleanup_old_positions(days)`: Limpiar datos antiguos - `create_next_partition()`: Crear siguiente partición ## Redis Cache Estructura de claves: ``` trains:current:{train_id} → JSON con última posición (TTL 5min) trains:active → SET con IDs de trenes activos stats:last_update → Timestamp última actualización ``` ## API Endpoints ### Trenes - `GET /trains/current` - Todos los trenes activos - `GET /trains/:id` - Info de tren específico - `GET /trains/:id/history` - Histórico de posiciones - `GET /trains/:id/path` - Trayectoria entre fechas - `GET /trains/area` - Trenes en área geográfica ### Rutas - `GET /routes` - Todas las rutas - `GET /routes/:id` - Ruta específica ### Estaciones - `GET /stations` - Todas las estaciones - `GET /stations/:id` - Estación específica ### Estadísticas - `GET /stats` - Estadísticas del sistema - `GET /stats/train/:id` - Estadísticas de tren ## WebSocket Events ### Cliente → Servidor - `subscribe:train` - Suscribirse a actualizaciones de un tren - `unsubscribe:train` - Desuscribirse ### Servidor → Cliente - `trains:update` - Actualización masiva (todos los trenes) - `train:update` - Actualización individual (tren suscrito) ## Comandos Make Comunes ```bash make help # Ver todos los comandos disponibles make start # Iniciar servicios en producción make stop # Detener servicios make logs # Ver logs de todos los servicios make logs-api # Ver logs del API make logs-worker # Ver logs del worker make migrate # Ejecutar migraciones make psql # Conectar a PostgreSQL make redis-cli # Conectar a Redis make test-start # Iniciar entorno de testing make backup-db # Crear backup de BD make cleanup-old-data # Limpiar datos antiguos (>90 días) ``` ## Flujo de Datos 1. **Worker** hace polling a GTFS-RT cada 30 segundos 2. **Worker** parsea Protocol Buffer y extrae posiciones 3. **Worker** almacena en PostgreSQL (histórico) y Redis (cache) 4. **API** lee de Redis para requests y WebSocket 5. **WebSocket** broadcast a clientes cada 2 segundos 6. **Frontend** recibe updates y actualiza mapa en tiempo real ## Variables de Entorno Importantes ```bash # API PORT=3000 NODE_ENV=development # Database DATABASE_URL=postgresql://user:pass@host:5432/db # Redis REDIS_URL=redis://:pass@host:6379 # GTFS-RT GTFS_RT_URL=https://gtfsrt.renfe.com/vehicle_positions.pb POLLING_INTERVAL=30000 # CORS CORS_ORIGIN=http://localhost:3000,http://localhost:5173 # Frontend VITE_API_URL=http://localhost/api VITE_WS_URL=ws://localhost/ws ``` ## Estado Actual del Proyecto ### ✅ Fase 1: MVP (COMPLETADA) - [x] Arquitectura Docker completa - [x] Worker GTFS-RT Vehicle Positions - [x] API REST core - [x] WebSocket server - [x] Frontend React con mapa Leaflet - [x] Panel de información de tren - [x] Timeline básico (UI, funcionalidad pendiente) ### ⬜ Fase 2: Enriquecimiento (SIGUIENTE) - [ ] Integración GTFS Static (rutas, horarios) - [ ] Trip Updates (retrasos, cancelaciones) - [ ] Service Alerts (incidencias) - [ ] Monitor de puntualidad - [ ] Timeline funcional con histórico ## Documentación Relevante - **Arquitectura completa**: [arquitectura-sistema-tracking-trenes.md](arquitectura-sistema-tracking-trenes.md) - **Fuentes de datos**: [FUENTES_DATOS.md](FUENTES_DATOS.md) - **Fase 1 MVP**: [FASE1-MVP.md](FASE1-MVP.md) - **README principal**: [README.md](README.md) ## Tareas Comunes ### Añadir un nuevo endpoint 1. Crear ruta en `backend/src/api/routes/` 2. Importar y usar en `backend/src/api/server.js` 3. Documentar en README ### Añadir una nueva vista en BD 1. Crear migración en `database/migrations/V{N}__descripcion.sql` 2. Ejecutar `make migrate` 3. Documentar en arquitectura ### Añadir un componente React 1. Crear en `frontend/src/components/` 2. Importar en `App.jsx` o componente padre 3. Añadir estilos en `styles/index.css` ### Añadir una nueva fuente de datos 1. Crear worker en `backend/src/worker/` 2. Parsear y almacenar datos 3. Actualizar `docker-compose.yml` si es necesario 4. Documentar en FUENTES_DATOS.md ## Debugging ### Ver logs en tiempo real ```bash # Todos los servicios make logs # Servicio específico docker-compose logs -f worker docker-compose logs -f api docker-compose logs -f postgres ``` ### Inspeccionar base de datos ```bash # Conectar a PostgreSQL make psql # Ver últimas posiciones SELECT * FROM train_positions ORDER BY recorded_at DESC LIMIT 10; # Contar trenes activos SELECT COUNT(*) FROM trains WHERE is_active = true; ``` ### Inspeccionar Redis ```bash # Conectar a Redis make redis-cli # Ver trenes activos SMEMBERS trains:active # Ver posición de un tren GET trains:current:TRAIN_ID ``` ## Notas de Desarrollo ### Convenciones de Código - **Backend**: ES Modules, camelCase para variables, PascalCase para clases - **Frontend**: React funcional (hooks), componentes PascalCase - **SQL**: snake_case para tablas y columnas, UPPERCASE para SQL keywords - **Git**: Commits descriptivos en español ### Testing - Backend: Tests con Jest (pendiente) - Frontend: Tests con React Testing Library (pendiente) - E2E: Cypress (pendiente) ### Performance - **Particiones**: Crear nuevas particiones mensualmente - **Cleanup**: Ejecutar `cleanup_old_positions()` mensualmente - **Cache**: Redis TTL configurado a 5 minutos - **Pooling**: PostgreSQL pool size 2-10 ## Contacto y Recursos - **GTFS Spec**: https://gtfs.org/documentation/realtime/ - **Renfe Data**: https://data.renfe.com/ - **PostGIS Docs**: https://postgis.net/ - **Leaflet Docs**: https://leafletjs.com/ - **Socket.io Docs**: https://socket.io/ --- **Última actualización**: 27 noviembre 2025 **Versión**: 1.0.0 (Fase 1 MVP)