486 lines
10 KiB
Markdown
486 lines
10 KiB
Markdown
|
|
# Fase 1: MVP - Sistema de Tracking de Trenes en Tiempo Real
|
||
|
|
|
||
|
|
## Estado: ✅ COMPLETADO
|
||
|
|
|
||
|
|
La Fase 1 del roadmap ha sido implementada exitosamente. Este documento describe lo que se ha construido y cómo probarlo.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## ✨ Características Implementadas
|
||
|
|
|
||
|
|
### Backend
|
||
|
|
- ✅ Worker GTFS-RT que recolecta posiciones cada 30 segundos
|
||
|
|
- ✅ API REST con endpoints para trenes, rutas, estaciones y estadísticas
|
||
|
|
- ✅ WebSocket server para actualizaciones en tiempo real
|
||
|
|
- ✅ Integración con PostgreSQL + PostGIS
|
||
|
|
- ✅ Cache Redis para posiciones actuales
|
||
|
|
- ✅ Sistema de logs con Pino
|
||
|
|
- ✅ Gestión de errores y reconexión automática
|
||
|
|
|
||
|
|
### Frontend
|
||
|
|
- ✅ Mapa interactivo con Leaflet.js y OpenStreetMap
|
||
|
|
- ✅ Visualización de trenes en tiempo real
|
||
|
|
- ✅ Panel de información detallada de cada tren
|
||
|
|
- ✅ Conexión WebSocket con reconexión automática
|
||
|
|
- ✅ Timeline básico (UI preparado, funcionalidad fase 2)
|
||
|
|
- ✅ Estadísticas en header (trenes activos, última actualización)
|
||
|
|
- ✅ Diseño responsivo
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📁 Estructura del Proyecto
|
||
|
|
|
||
|
|
```
|
||
|
|
trenes/
|
||
|
|
├── backend/
|
||
|
|
│ ├── src/
|
||
|
|
│ │ ├── api/
|
||
|
|
│ │ │ ├── routes/
|
||
|
|
│ │ │ │ ├── trains.js # Endpoints de trenes
|
||
|
|
│ │ │ │ ├── routes.js # Endpoints de rutas
|
||
|
|
│ │ │ │ ├── stations.js # Endpoints de estaciones
|
||
|
|
│ │ │ │ └── stats.js # Endpoints de estadísticas
|
||
|
|
│ │ │ └── server.js # Servidor API + WebSocket
|
||
|
|
│ │ ├── worker/
|
||
|
|
│ │ │ └── gtfs-poller.js # Worker GTFS-RT
|
||
|
|
│ │ ├── lib/
|
||
|
|
│ │ │ ├── db.js # Cliente PostgreSQL
|
||
|
|
│ │ │ ├── redis.js # Cliente Redis
|
||
|
|
│ │ │ └── logger.js # Logger Pino
|
||
|
|
│ │ └── config/
|
||
|
|
│ │ └── index.js # Configuración
|
||
|
|
│ ├── package.json
|
||
|
|
│ ├── Dockerfile
|
||
|
|
│ └── .env.example
|
||
|
|
│
|
||
|
|
├── frontend/
|
||
|
|
│ ├── src/
|
||
|
|
│ │ ├── components/
|
||
|
|
│ │ │ ├── TrainMap.jsx # Mapa Leaflet
|
||
|
|
│ │ │ ├── TrainInfo.jsx # Panel de información
|
||
|
|
│ │ │ └── Timeline.jsx # Timeline (UI)
|
||
|
|
│ │ ├── hooks/
|
||
|
|
│ │ │ └── useTrains.js # Hook WebSocket
|
||
|
|
│ │ ├── styles/
|
||
|
|
│ │ │ └── index.css # Estilos globales
|
||
|
|
│ │ ├── App.jsx # Componente principal
|
||
|
|
│ │ └── main.jsx # Entry point
|
||
|
|
│ ├── package.json
|
||
|
|
│ ├── Dockerfile
|
||
|
|
│ └── vite.config.js
|
||
|
|
│
|
||
|
|
├── database/
|
||
|
|
│ ├── init/ # Scripts iniciales
|
||
|
|
│ └── migrations/ # Migraciones Flyway
|
||
|
|
│
|
||
|
|
├── docker-compose.yml
|
||
|
|
├── Makefile
|
||
|
|
└── README.md
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🚀 Cómo Ejecutar el MVP
|
||
|
|
|
||
|
|
### Prerrequisitos
|
||
|
|
- Docker y Docker Compose instalados
|
||
|
|
- Puerto 80, 3000, 5432, 6379 disponibles
|
||
|
|
- (Opcional) Make para comandos simplificados
|
||
|
|
|
||
|
|
### Opción 1: Usando Make (Recomendado)
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Configurar variables de entorno
|
||
|
|
cp .env.example .env
|
||
|
|
# Editar .env si es necesario
|
||
|
|
|
||
|
|
# 2. Ejecutar migraciones
|
||
|
|
make migrate
|
||
|
|
|
||
|
|
# 3. Iniciar todos los servicios
|
||
|
|
make start
|
||
|
|
|
||
|
|
# 4. Ver logs
|
||
|
|
make logs
|
||
|
|
```
|
||
|
|
|
||
|
|
### Opción 2: Docker Compose Manual
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 1. Configurar variables de entorno
|
||
|
|
cp .env.example .env
|
||
|
|
|
||
|
|
# 2. Ejecutar migraciones
|
||
|
|
docker-compose --profile migration up flyway
|
||
|
|
|
||
|
|
# 3. Iniciar servicios
|
||
|
|
docker-compose up -d
|
||
|
|
|
||
|
|
# 4. Ver logs
|
||
|
|
docker-compose logs -f
|
||
|
|
```
|
||
|
|
|
||
|
|
### Opción 3: Desarrollo Local (sin Docker)
|
||
|
|
|
||
|
|
#### Backend
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd backend
|
||
|
|
|
||
|
|
# Instalar dependencias
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# Configurar .env
|
||
|
|
cp .env.example .env
|
||
|
|
# Ajustar DATABASE_URL y REDIS_URL a localhost
|
||
|
|
|
||
|
|
# Ejecutar worker en una terminal
|
||
|
|
npm run dev:worker
|
||
|
|
|
||
|
|
# Ejecutar API en otra terminal
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
#### Frontend
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd frontend
|
||
|
|
|
||
|
|
# Instalar dependencias
|
||
|
|
npm install
|
||
|
|
|
||
|
|
# Ejecutar en modo desarrollo
|
||
|
|
npm run dev
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🌐 Acceder a la Aplicación
|
||
|
|
|
||
|
|
Una vez iniciados los servicios:
|
||
|
|
|
||
|
|
- **Aplicación Web**: http://localhost
|
||
|
|
- **API REST**: http://localhost/api o http://localhost:3000
|
||
|
|
- **Health Check**: http://localhost/health o http://localhost:3000/health
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📡 Endpoints de la API
|
||
|
|
|
||
|
|
### Trenes
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Obtener todos los trenes activos
|
||
|
|
GET /trains/current
|
||
|
|
|
||
|
|
# Obtener información de un tren específico
|
||
|
|
GET /trains/:id
|
||
|
|
|
||
|
|
# Obtener histórico de un tren
|
||
|
|
GET /trains/:id/history?from=2025-11-27T00:00:00Z&to=2025-11-27T23:59:59Z&limit=100
|
||
|
|
|
||
|
|
# Obtener trayectoria de un tren
|
||
|
|
GET /trains/:id/path?from=2025-11-27T10:00:00Z&to=2025-11-27T11:00:00Z
|
||
|
|
|
||
|
|
# Obtener trenes en un área geográfica
|
||
|
|
GET /trains/area?minLat=40.0&minLon=-4.0&maxLat=41.0&maxLon=-3.0
|
||
|
|
```
|
||
|
|
|
||
|
|
### Rutas
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Obtener todas las rutas
|
||
|
|
GET /routes
|
||
|
|
|
||
|
|
# Obtener ruta específica
|
||
|
|
GET /routes/:id
|
||
|
|
```
|
||
|
|
|
||
|
|
### Estaciones
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Obtener todas las estaciones
|
||
|
|
GET /stations
|
||
|
|
|
||
|
|
# Obtener estaciones por tipo
|
||
|
|
GET /stations?type=MAJOR
|
||
|
|
|
||
|
|
# Obtener estación específica
|
||
|
|
GET /stations/:id
|
||
|
|
```
|
||
|
|
|
||
|
|
### Estadísticas
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Obtener estadísticas del sistema
|
||
|
|
GET /stats
|
||
|
|
|
||
|
|
# Obtener estadísticas de un tren
|
||
|
|
GET /stats/train/:id?from=2025-11-27T00:00:00Z&to=2025-11-27T23:59:59Z
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🔌 WebSocket Events
|
||
|
|
|
||
|
|
### Cliente → Servidor
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Suscribirse a un tren específico
|
||
|
|
socket.emit('subscribe:train', trainId);
|
||
|
|
|
||
|
|
// Desuscribirse de un tren
|
||
|
|
socket.emit('unsubscribe:train', trainId);
|
||
|
|
```
|
||
|
|
|
||
|
|
### Servidor → Cliente
|
||
|
|
|
||
|
|
```javascript
|
||
|
|
// Actualización de todos los trenes (cada 2 segundos)
|
||
|
|
socket.on('trains:update', (positions) => {
|
||
|
|
console.log('Posiciones actualizadas:', positions);
|
||
|
|
});
|
||
|
|
|
||
|
|
// Actualización de un tren específico (si estás suscrito)
|
||
|
|
socket.on('train:update', (position) => {
|
||
|
|
console.log('Tren actualizado:', position);
|
||
|
|
});
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🧪 Probar el Sistema
|
||
|
|
|
||
|
|
### 1. Verificar que el Worker está funcionando
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Ver logs del worker
|
||
|
|
make logs-worker
|
||
|
|
|
||
|
|
# O con docker-compose
|
||
|
|
docker-compose logs -f worker
|
||
|
|
|
||
|
|
# Deberías ver mensajes como:
|
||
|
|
# "Polling GTFS-RT feed..."
|
||
|
|
# "Processed vehicle positions: {trains: 50, duration: 1234}"
|
||
|
|
```
|
||
|
|
|
||
|
|
### 2. Verificar API
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Health check
|
||
|
|
curl http://localhost:3000/health
|
||
|
|
|
||
|
|
# Obtener trenes actuales
|
||
|
|
curl http://localhost:3000/trains/current | jq
|
||
|
|
|
||
|
|
# Obtener estadísticas
|
||
|
|
curl http://localhost:3000/stats | jq
|
||
|
|
```
|
||
|
|
|
||
|
|
### 3. Verificar Base de Datos
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Conectar a PostgreSQL
|
||
|
|
make psql
|
||
|
|
|
||
|
|
# Ver trenes almacenados
|
||
|
|
SELECT COUNT(*) FROM trains;
|
||
|
|
|
||
|
|
# Ver posiciones de las últimas 24 horas
|
||
|
|
SELECT COUNT(*) FROM train_positions WHERE recorded_at > NOW() - INTERVAL '24 hours';
|
||
|
|
|
||
|
|
# Ver estaciones
|
||
|
|
SELECT * FROM stations LIMIT 10;
|
||
|
|
```
|
||
|
|
|
||
|
|
### 4. Verificar Redis
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Conectar a Redis
|
||
|
|
make redis-cli
|
||
|
|
|
||
|
|
# Ver trenes activos
|
||
|
|
SMEMBERS trains:active
|
||
|
|
|
||
|
|
# Ver posición actual de un tren
|
||
|
|
GET trains:current:TRAIN_ID
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🐛 Troubleshooting
|
||
|
|
|
||
|
|
### No se ven trenes en el mapa
|
||
|
|
|
||
|
|
**Causa**: El feed GTFS-RT puede no tener datos o el worker no está corriendo.
|
||
|
|
|
||
|
|
**Solución**:
|
||
|
|
```bash
|
||
|
|
# Verificar logs del worker
|
||
|
|
make logs-worker
|
||
|
|
|
||
|
|
# Verificar si hay trenes en Redis
|
||
|
|
make redis-cli
|
||
|
|
> SMEMBERS trains:active
|
||
|
|
|
||
|
|
# Si Redis está vacío, verificar PostgreSQL
|
||
|
|
make psql
|
||
|
|
> SELECT COUNT(*) FROM train_positions WHERE recorded_at > NOW() - INTERVAL '1 hour';
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error de conexión WebSocket
|
||
|
|
|
||
|
|
**Causa**: CORS o URL incorrecta.
|
||
|
|
|
||
|
|
**Solución**:
|
||
|
|
```bash
|
||
|
|
# Verificar que VITE_WS_URL está configurado correctamente
|
||
|
|
# En .env.testing o variables de entorno del frontend
|
||
|
|
|
||
|
|
# Debería ser: http://localhost:3000 (desarrollo) o ws://localhost/ws (producción)
|
||
|
|
```
|
||
|
|
|
||
|
|
### La base de datos no tiene datos
|
||
|
|
|
||
|
|
**Causa**: Migraciones no ejecutadas o feed GTFS-RT sin datos.
|
||
|
|
|
||
|
|
**Solución**:
|
||
|
|
```bash
|
||
|
|
# Ejecutar migraciones
|
||
|
|
make migrate
|
||
|
|
|
||
|
|
# Verificar estado de migraciones
|
||
|
|
make migrate-info
|
||
|
|
|
||
|
|
# Ver datos iniciales
|
||
|
|
make psql
|
||
|
|
> SELECT * FROM stations LIMIT 5;
|
||
|
|
```
|
||
|
|
|
||
|
|
### Error "PostgreSQL not connected"
|
||
|
|
|
||
|
|
**Causa**: PostgreSQL no está corriendo o configuración incorrecta.
|
||
|
|
|
||
|
|
**Solución**:
|
||
|
|
```bash
|
||
|
|
# Verificar que PostgreSQL está corriendo
|
||
|
|
docker-compose ps postgres
|
||
|
|
|
||
|
|
# Reiniciar PostgreSQL
|
||
|
|
docker-compose restart postgres
|
||
|
|
|
||
|
|
# Verificar logs
|
||
|
|
docker-compose logs postgres
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📊 Métricas y Monitorización
|
||
|
|
|
||
|
|
### Logs del Sistema
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Ver todos los logs
|
||
|
|
make logs
|
||
|
|
|
||
|
|
# Ver logs específicos
|
||
|
|
make logs-api # API
|
||
|
|
make logs-worker # Worker
|
||
|
|
make logs-db # PostgreSQL
|
||
|
|
```
|
||
|
|
|
||
|
|
### Estadísticas del Worker
|
||
|
|
|
||
|
|
El worker registra estadísticas cada 60 segundos:
|
||
|
|
|
||
|
|
```json
|
||
|
|
{
|
||
|
|
"totalPolls": 120,
|
||
|
|
"successfulPolls": 118,
|
||
|
|
"failedPolls": 2,
|
||
|
|
"totalTrains": 45,
|
||
|
|
"lastPollTime": "2025-11-27T10:30:00.000Z",
|
||
|
|
"successRate": "98.33%"
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
### Panel de Administración
|
||
|
|
|
||
|
|
Para acceder a herramientas de administración:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# Iniciar con modo debug
|
||
|
|
make debug-start
|
||
|
|
|
||
|
|
# Acceder a:
|
||
|
|
# - Adminer (PostgreSQL): http://localhost:8080
|
||
|
|
# - Redis Commander: http://localhost:8081
|
||
|
|
```
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🎯 Próximos Pasos (Fase 2)
|
||
|
|
|
||
|
|
La Fase 2 incluirá:
|
||
|
|
|
||
|
|
- [ ] Integración GTFS Static (rutas, horarios)
|
||
|
|
- [ ] Trip Updates (retrasos, cancelaciones)
|
||
|
|
- [ ] Service Alerts (incidencias)
|
||
|
|
- [ ] Timeline funcional con reproducción histórica
|
||
|
|
- [ ] Monitor de puntualidad
|
||
|
|
- [ ] Panel de incidencias
|
||
|
|
|
||
|
|
Para más información, consultar el [roadmap completo](arquitectura-sistema-tracking-trenes.md#roadmap-de-features).
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📝 Notas Técnicas
|
||
|
|
|
||
|
|
### Fuente de Datos
|
||
|
|
|
||
|
|
El sistema consume el feed GTFS-RT de Renfe:
|
||
|
|
- **URL**: https://gtfsrt.renfe.com/vehicle_positions.pb
|
||
|
|
- **Formato**: Protocol Buffer (GTFS Realtime)
|
||
|
|
- **Frecuencia**: 30 segundos
|
||
|
|
- **Cobertura**: Principalmente Cercanías
|
||
|
|
|
||
|
|
### Almacenamiento
|
||
|
|
|
||
|
|
- **PostgreSQL**: Histórico completo de posiciones (particionado por mes)
|
||
|
|
- **Redis**: Cache de últimas posiciones (TTL 5 minutos)
|
||
|
|
- **WebSocket**: Broadcast en tiempo real (cada 2 segundos)
|
||
|
|
|
||
|
|
### Rendimiento
|
||
|
|
|
||
|
|
- **Polling**: 30 segundos (configurable via `POLLING_INTERVAL`)
|
||
|
|
- **Broadcast WS**: 2 segundos
|
||
|
|
- **Particiones DB**: Mensuales (nov 2025 - mar 2027)
|
||
|
|
- **Retención**: 90 días (configurable, usar `cleanup_old_positions()`)
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 📚 Documentación Adicional
|
||
|
|
|
||
|
|
- [Arquitectura Completa](arquitectura-sistema-tracking-trenes.md)
|
||
|
|
- [Fuentes de Datos](FUENTES_DATOS.md)
|
||
|
|
- [README Principal](README.md)
|
||
|
|
- [Makefile Commands](Makefile) - Ver `make help`
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 🤝 Contribuir
|
||
|
|
|
||
|
|
Si encuentras bugs o quieres proponer mejoras:
|
||
|
|
|
||
|
|
1. Crea un issue describiendo el problema/mejora
|
||
|
|
2. Haz un fork del proyecto
|
||
|
|
3. Crea una rama para tu feature
|
||
|
|
4. Envía un pull request
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
**Estado**: Fase 1 MVP Completada ✅
|
||
|
|
**Fecha**: 27 noviembre 2025
|
||
|
|
**Próxima Fase**: Fase 2 - Enriquecimiento
|