# Sistema de Tracking de Trenes en Tiempo Real Sistema web 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. ## Características - 🚄 **Visualización en tiempo real** de posiciones de trenes en mapa OpenStreetMap - 📊 **Información detallada** de cada tren (velocidad, dirección, estado, ruta) - ⏱️ **Timeline slider** para navegar por el histórico de posiciones - 🗺️ **Datos geoespaciales** usando PostGIS - 🔄 **Actualización automática** cada 30 segundos desde feed GTFS-RT - 📡 **WebSocket** para actualizaciones en tiempo real sin polling - 🎨 **Interfaz moderna** con React + Leaflet.js ## Stack Tecnológico ### Frontend - React + JavaScript (JSX) - Leaflet.js para mapas (OpenStreetMap) - Socket.io client para WebSocket - Vite como bundler ### Backend - Node.js + Express/Fastify - Socket.io para WebSocket server - Parser GTFS-RT (gtfs-realtime-bindings) ### Infraestructura - PostgreSQL 15 + PostGIS (datos geoespaciales) - Redis (caché de posiciones actuales) - Nginx (reverse proxy) - Flyway (migraciones de base de datos) - Docker + Docker Compose ## Requisitos Previos - Docker >= 20.10 - Docker Compose >= 2.0 - Make (opcional, pero recomendado) - Git ## Instalación Rápida ### Usando Make (Recomendado) ```bash # 1. Clonar el repositorio git clone cd trenes # 2. Ver comandos disponibles make help # 3. Configurar variables de entorno cp .env.example .env # Editar .env con tus credenciales # 4. Ejecutar migraciones make migrate # 5. Iniciar servicios make start ``` ### Instalación Manual (sin Make) #### 1. Clonar el repositorio ```bash git clone cd trenes ``` #### 2. Configurar variables de entorno ```bash cp .env.example .env ``` Editar `.env` y configurar las contraseñas y secretos: ```env POSTGRES_PASSWORD=tu_password_seguro REDIS_PASSWORD=tu_redis_password JWT_SECRET=tu_jwt_secret_minimo_32_caracteres ``` #### 3. Ejecutar migraciones de base de datos ```bash # Primera vez: ejecutar migraciones docker-compose --profile migration up flyway # Verificar que las migraciones se aplicaron correctamente docker-compose logs flyway ``` #### 4. Iniciar todos los servicios ```bash docker-compose up -d ``` #### 5. Verificar que todo está funcionando ```bash # Ver logs de todos los servicios docker-compose logs -f # Verificar estado de los servicios docker-compose ps ``` ## Acceso a los Servicios Una vez iniciado, el sistema estará disponible en: - **Aplicación Web**: http://localhost - **API REST**: http://localhost/api - **WebSocket**: ws://localhost/ws - **Adminer** (DB admin): http://localhost:8080 (solo en modo debug) - **Redis Commander**: http://localhost:8081 (solo en modo debug) ## Uso ### Comandos Make Disponibles ```bash # Ver todos los comandos disponibles make help # Comandos de Producción make start # Iniciar servicios make stop # Detener servicios make restart # Reiniciar servicios make logs # Ver logs make status # Ver estado de servicios make migrate # Ejecutar migraciones make debug-start # Iniciar con herramientas de debug # Comandos de Testing make test-start # Iniciar entorno de testing make test-stop # Detener entorno de testing make test-logs # Ver logs de testing make test-clean # Limpiar datos de testing make test-reset # Reset completo de testing # Utilidades make psql # Conectar a PostgreSQL make redis-cli # Conectar a Redis make backup-db # Crear backup de BD make cleanup-old-data # Limpiar datos antiguos ``` ### Modo Normal (Producción) ```bash # Usando Make make start # Iniciar todos los servicios make logs # Ver logs make stop # Detener servicios # O manualmente con docker-compose docker-compose up -d docker-compose logs -f docker-compose down ``` ### Modo Testing El entorno de testing usa el archivo `.env.testing` que incluye configuraciones específicas para pruebas: ```bash # Iniciar entorno de testing make test-start # Ver logs make test-logs # Detener y limpiar make test-clean ``` El entorno de testing incluye: - Configuración de desarrollo con logs detallados - Polling más frecuente (15 segundos) - Debug endpoints habilitados - Rate limiting deshabilitado - Herramientas de administración (Adminer, Redis Commander) activadas por defecto ### Modo Debug (con herramientas de administración) ```bash # Usando Make make debug-start # O manualmente docker-compose --profile debug up -d # Acceder a Adminer: http://localhost:8080 # - Sistema: PostgreSQL # - Servidor: postgres # - Usuario: trenes_user # - Contraseña: [tu POSTGRES_PASSWORD] # - Base de datos: trenes_db ``` ### Ejecutar Migraciones ```bash # Usando Make make migrate # Aplicar migraciones make migrate-info # Ver información make migrate-validate # Validar migraciones # O manualmente docker-compose --profile migration up flyway docker-compose --profile migration run --rm flyway info docker-compose --profile migration run --rm flyway validate ``` ## Estructura del Proyecto ``` trenes/ ├── backend/ # Backend Node.js │ ├── src/ │ │ ├── api/ # API REST │ │ │ └── server.js │ │ └── worker/ # Worker GTFS-RT polling │ │ └── gtfs-poller.js │ ├── Dockerfile │ └── package.json │ ├── frontend/ # Frontend React │ ├── src/ │ │ ├── components/ │ │ ├── hooks/ │ │ └── App.jsx │ ├── Dockerfile │ ├── nginx.conf # Configuración nginx del contenedor │ └── package.json │ ├── database/ │ ├── init/ # Scripts de inicialización (solo primera vez) │ │ ├── 01-init-extensions.sql │ │ ├── 02-create-schema.sql │ │ └── 03-seed-data.sql │ └── migrations/ # Migraciones versionadas (Flyway) │ ├── V1__initial_schema.sql │ ├── V2__create_partitions.sql │ ├── V3__create_views_and_functions.sql │ └── V4__seed_initial_data.sql │ ├── nginx/ # Configuración Nginx (reverse proxy) │ ├── nginx.conf │ └── conf.d/ │ └── default.conf │ ├── docker-compose.yml ├── .env.example └── README.md ``` ## API Endpoints ### Posiciones de Trenes ```bash # Obtener posiciones actuales de todos los trenes GET /api/trains/current # Obtener histórico de un tren GET /api/trains/history?train_id=XXX&from=TIMESTAMP&to=TIMESTAMP # Obtener información de un tren específico GET /api/trains/:id # Obtener rutas disponibles GET /api/routes # Obtener estaciones GET /api/stations ``` ### WebSocket Events ```javascript // Conectar al WebSocket const socket = io('ws://localhost/ws'); // Escuchar actualizaciones de posiciones socket.on('train:update', (position) => { console.log('Nueva posición:', position); }); // Suscribirse a un tren específico socket.emit('subscribe', { train_id: 'AVE-03041' }); ``` ## Base de Datos ### Tablas Principales - **trains**: Catálogo de trenes - **train_positions**: Histórico de posiciones (particionada por mes) - **routes**: Rutas y líneas - **stations**: Estaciones - **alerts**: Alertas e incidencias ### Vistas - **current_train_positions**: Última posición de cada tren - **active_trains**: Trenes activos en las últimas 24 horas ### Funciones Útiles ```sql -- Limpiar posiciones antiguas (mayores a 90 días) SELECT cleanup_old_positions(90); -- Crear siguiente partición mensual SELECT create_next_partition(); -- Obtener trayectoria de un tren SELECT * FROM get_train_path('AVE-03041', '2025-01-01', '2025-01-02'); -- Obtener trenes en un área SELECT * FROM get_trains_in_area(40.0, -4.0, 41.0, -3.0); -- Calcular estadísticas de un tren SELECT * FROM calculate_train_statistics('AVE-03041', '2025-01-01', '2025-01-02'); ``` ## Gestión de Migraciones Este proyecto usa **Flyway** para gestionar las migraciones de base de datos de forma versionada y reproducible. ### Convención de Nombres Las migraciones siguen el formato: `V{version}__{description}.sql` - `V1__initial_schema.sql` - Versión 1: Schema inicial - `V2__create_partitions.sql` - Versión 2: Crear particiones - etc. ### Crear Nueva Migración 1. Crear archivo en `database/migrations/` siguiendo la convención: ``` V5__add_train_operators.sql ``` 2. Aplicar migración: ```bash docker-compose --profile migration up flyway ``` ### Comandos de Flyway ```bash # Ver estado de migraciones docker-compose --profile migration run --rm flyway info # Validar migraciones docker-compose --profile migration run --rm flyway validate # Limpiar base de datos (¡CUIDADO! Borra todo) docker-compose --profile migration run --rm flyway clean # Reparar tabla de migraciones docker-compose --profile migration run --rm flyway repair ``` ## Mantenimiento ### Backup de Base de Datos ```bash # Crear backup docker-compose exec postgres pg_dump -U trenes_user trenes_db > backup.sql # Restaurar backup docker-compose exec -T postgres psql -U trenes_user trenes_db < backup.sql ``` ### Limpiar Datos Antiguos ```bash # Conectar a PostgreSQL docker-compose exec postgres psql -U trenes_user -d trenes_db # Ejecutar función de limpieza (elimina datos > 90 días) SELECT cleanup_old_positions(90); ``` ### Crear Nuevas Particiones ```bash # Conectar a PostgreSQL docker-compose exec postgres psql -U trenes_user -d trenes_db # Crear próxima partición SELECT create_next_partition(); ``` ## Desarrollo ### Modo Desarrollo Para desarrollo local con hot-reload: ```bash # Backend cd backend npm install npm run dev # Frontend cd frontend npm install npm run dev ``` ### Estructura de Logs ```bash # Ver logs de un servicio específico docker-compose logs -f api docker-compose logs -f worker docker-compose logs -f frontend # Ver logs de todos los servicios docker-compose logs -f ``` ## Troubleshooting ### El worker no puede conectar con GTFS-RT ```bash # Verificar que el worker está corriendo docker-compose logs worker # Probar manualmente el endpoint curl -I https://gtfsrt.renfe.com/vehicle_positions.pb ``` ### La base de datos no inicia ```bash # Ver logs de PostgreSQL docker-compose logs postgres # Verificar permisos de volúmenes ls -la postgres_data/ # Reiniciar contenedor docker-compose restart postgres ``` ### No se ven los trenes en el mapa 1. Verificar que el worker está recolectando datos: ```bash docker-compose logs worker ``` 2. Verificar que hay datos en la base de datos: ```bash docker-compose exec postgres psql -U trenes_user -d trenes_db -c "SELECT COUNT(*) FROM train_positions;" ``` 3. Verificar que el API responde: ```bash curl http://localhost/api/trains/current ``` ## Despliegue en Producción ### Requisitos del Servidor - Linux (Debian/Ubuntu recomendado) - Docker >= 20.10 - Docker Compose >= 2.0 - Mínimo 2GB RAM, 20GB disco - Puerto 80 y 443 abiertos - Dominio apuntando al servidor ### Despliegue Rápido ```bash # 1. Copiar proyecto al servidor rsync -avz --exclude 'node_modules' --exclude '.git' --exclude 'postgres_data' \ ./ root@tu-servidor:/opt/trenes/ # 2. En el servidor, crear archivo .env de producción cat > /opt/trenes/.env << 'EOF' POSTGRES_USER=trenes POSTGRES_PASSWORD=TU_PASSWORD_SEGURO_GENERADO POSTGRES_DB=trenes DATABASE_URL=postgres://trenes:${POSTGRES_PASSWORD}@postgres:5432/trenes REDIS_URL=redis://redis:6379 NODE_ENV=production PORT=3000 CORS_ORIGINS=https://tu-dominio.com EOF # 3. Iniciar servicios cd /opt/trenes docker compose -f docker-compose.prod.yml up -d ``` ### Configuración SSL con Let's Encrypt ```bash # 1. Iniciar nginx temporal para obtener certificado docker run -d --name temp-nginx -p 80:80 \ -v /opt/trenes/nginx/prod.conf:/etc/nginx/conf.d/default.conf:ro \ -v certbot_webroot:/var/www/certbot nginx:alpine # 2. Obtener certificado docker run --rm \ -v trenes_certbot_certs:/etc/letsencrypt \ -v certbot_webroot:/var/www/certbot \ certbot/certbot certonly --webroot \ --webroot-path=/var/www/certbot \ --email tu-email@dominio.com \ --agree-tos --no-eff-email \ -d tu-dominio.com # 3. Detener nginx temporal docker stop temp-nginx && docker rm temp-nginx # 4. Iniciar servicios completos docker compose -f docker-compose.prod.yml up -d ``` ### Lecciones Aprendidas del Despliegue #### 1. PostgreSQL/PostGIS - Compatibilidad de Versiones **Problema**: Error `FATAL: database files are incompatible with server` al usar datos existentes. **Solución**: Asegurar que la versión de PostgreSQL en producción coincida con la de desarrollo. Si los datos fueron creados con PostgreSQL 16, usar `postgis/postgis:16-3.4-alpine` en producción. #### 2. Socket.io - Configuración de URL **Problema**: Error "Invalid namespace" al conectar WebSocket. **Causa**: Socket.io añade automáticamente `/socket.io/` al path. Si `VITE_WS_URL=wss://dominio.com/ws`, intentará conectar a `/ws/socket.io/`. **Solución**: Configurar `VITE_WS_URL=https://dominio.com` (sin path adicional) para que Socket.io conecte correctamente a `/socket.io/`. #### 3. Nginx - Variables y Proxy Pass **Problema**: Cuando se usan variables en `proxy_pass`, nginx NO hace sustitución automática de URI. **Solución**: Usar `rewrite` explícito: ```nginx location /api/ { set $backend api:3000; rewrite ^/api/(.*)$ /$1 break; proxy_pass http://$backend; } ``` #### 4. Nginx - Resolución DNS de Contenedores **Problema**: Error `host not found in upstream` al iniciar nginx antes que otros servicios. **Solución**: Usar el resolver DNS de Docker: ```nginx resolver 127.0.0.11 valid=30s; ``` #### 5. Nginx - Directiva HTTP/2 **Problema**: Warning `the "listen ... http2" directive is deprecated`. **Solución**: Cambiar de `listen 443 ssl http2;` a: ```nginx listen 443 ssl; http2 on; ``` #### 6. Variables VITE en Docker **Problema**: Las variables `VITE_*` del `.env` no se aplican en el build de Docker. **Solución**: Pasar las variables como build args en docker-compose: ```yaml frontend: build: args: VITE_API_URL: https://tu-dominio.com/api VITE_WS_URL: https://tu-dominio.com ``` Y en el Dockerfile del frontend: ```dockerfile ARG VITE_API_URL ARG VITE_WS_URL ENV VITE_API_URL=${VITE_API_URL} ENV VITE_WS_URL=${VITE_WS_URL} ``` #### 7. Migración de Datos **Comando para exportar e importar datos históricos**: ```bash # Exportar desde desarrollo docker compose exec -T postgres pg_dump -U trenes_user -d trenes_db \ --data-only --exclude-table='flyway_schema_history' | gzip > backup.sql.gz # Copiar al servidor scp backup.sql.gz root@servidor:/tmp/ # Importar en producción gunzip -c /tmp/backup.sql.gz | docker exec -i trenes-postgres \ psql -U trenes -d trenes ``` ### Verificación del Despliegue ```bash # Verificar servicios docker ps --format "table {{.Names}}\t{{.Status}}" # Test API curl https://tu-dominio.com/api/health # Test Dashboard curl https://tu-dominio.com/api/dashboard/current # Test WebSocket (debe devolver sid) curl "https://tu-dominio.com/socket.io/?EIO=4&transport=polling" ``` ## Roadmap - [x] **Fase 1: MVP** ✅ COMPLETADA - [x] Arquitectura y Docker Compose - [x] Backend API y Worker GTFS-RT - [x] Frontend con mapa Leaflet - [x] WebSocket en tiempo real - [x] Timeline slider (UI básica) - [x] **Fase 2: Enriquecimiento** ✅ BACKEND COMPLETADO - [x] GTFS Static Syncer (sync diario) - [x] Trip Updates Poller (retrasos) - [x] Service Alerts Poller (alertas) - [x] API de Alertas y Trips - [ ] Frontend: componentes de alertas y puntualidad - [x] **Fase 3: Analytics** ✅ BACKEND COMPLETADO - [x] Analytics API (heatmaps, estadísticas) - [x] Explorer API (planificador de viajes) - [x] Exportación de datos (CSV, JSON, GeoJSON) - [ ] Frontend: dashboard de analytics - [ ] **Fase 4: ML y Predicciones** (Futuro) - [ ] Predicción de retrasos - [ ] Detección de anomalías - [ ] Correlación con meteorología ## Licencia MIT ## Contribuir Las contribuciones son bienvenidas. Por favor: 1. Fork el proyecto 2. Crea una rama para tu feature (`git checkout -b feature/AmazingFeature`) 3. Commit tus cambios (`git commit -m 'Add some AmazingFeature'`) 4. Push a la rama (`git push origin feature/AmazingFeature`) 5. Abre un Pull Request ## Recursos - [GTFS Realtime Specification](https://gtfs.org/documentation/realtime/) - [Renfe Data Portal](https://data.renfe.com/) - [PostGIS Documentation](https://postgis.net/) - [Leaflet.js](https://leafletjs.com/) - [Flyway Documentation](https://flywaydb.org/documentation/)