GITHUB_TOKEN doesn't have container registry permissions in Gitea. Use dedicated REGISTRY_USERNAME and REGISTRY_PASSWORD secrets. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
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)
# 1. Clonar el repositorio
git clone <repository-url>
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
git clone <repository-url>
cd trenes
2. Configurar variables de entorno
cp .env.example .env
Editar .env y configurar las contraseñas y secretos:
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
# 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
docker-compose up -d
5. Verificar que todo está funcionando
# 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
# 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)
# 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:
# 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)
# 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
# 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
# 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
// 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
-- 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 inicialV2__create_partitions.sql- Versión 2: Crear particiones- etc.
Crear Nueva Migración
-
Crear archivo en
database/migrations/siguiendo la convención:V5__add_train_operators.sql -
Aplicar migración:
docker-compose --profile migration up flyway
Comandos de Flyway
# 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
# 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
# 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
# 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:
# Backend
cd backend
npm install
npm run dev
# Frontend
cd frontend
npm install
npm run dev
Estructura de Logs
# 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
# 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
# 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
-
Verificar que el worker está recolectando datos:
docker-compose logs worker -
Verificar que hay datos en la base de datos:
docker-compose exec postgres psql -U trenes_user -d trenes_db -c "SELECT COUNT(*) FROM train_positions;" -
Verificar que el API responde:
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
# 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
# 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:
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:
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:
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:
frontend:
build:
args:
VITE_API_URL: https://tu-dominio.com/api
VITE_WS_URL: https://tu-dominio.com
Y en el Dockerfile del frontend:
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:
# 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
# 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
-
Fase 1: MVP ✅ COMPLETADA
- Arquitectura y Docker Compose
- Backend API y Worker GTFS-RT
- Frontend con mapa Leaflet
- WebSocket en tiempo real
- Timeline slider (UI básica)
-
Fase 2: Enriquecimiento ✅ BACKEND COMPLETADO
- GTFS Static Syncer (sync diario)
- Trip Updates Poller (retrasos)
- Service Alerts Poller (alertas)
- API de Alertas y Trips
- Frontend: componentes de alertas y puntualidad
-
Fase 3: Analytics ✅ BACKEND COMPLETADO
- Analytics API (heatmaps, estadísticas)
- Explorer API (planificador de viajes)
- 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:
- Fork el proyecto
- Crea una rama para tu feature (
git checkout -b feature/AmazingFeature) - Commit tus cambios (
git commit -m 'Add some AmazingFeature') - Push a la rama (
git push origin feature/AmazingFeature) - Abre un Pull Request