feat: Initial commit - Train tracking system
Some checks failed
Auto Tag on Merge to Main / auto-tag (push) Successful in 27s
CI - Lint and Build / lint-backend (push) Failing after 30s
CI - Lint and Build / lint-frontend (push) Failing after 2s
CI - Lint and Build / build-frontend (push) Has been skipped
CI - Lint and Build / docker-build-test (push) Has been skipped
Some checks failed
Auto Tag on Merge to Main / auto-tag (push) Successful in 27s
CI - Lint and Build / lint-backend (push) Failing after 30s
CI - Lint and Build / lint-frontend (push) Failing after 2s
CI - Lint and Build / build-frontend (push) Has been skipped
CI - Lint and Build / docker-build-test (push) Has been skipped
Complete real-time train tracking system for Spanish railways (Renfe/Cercanías): - Backend API (Node.js/Express) with GTFS-RT polling workers - Frontend dashboard (React/Vite) with Leaflet maps - Real-time updates via Socket.io WebSocket - PostgreSQL/PostGIS database with Flyway migrations - Redis caching layer - Docker Compose configuration for development and production - Gitea CI/CD workflows (lint, auto-tag, release) - Production deployment with nginx + Let's Encrypt SSL 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
703
FASE2-ENRIQUECIMIENTO.md
Normal file
703
FASE2-ENRIQUECIMIENTO.md
Normal file
@@ -0,0 +1,703 @@
|
||||
# Fase 2: Enriquecimiento - GTFS Static, Trip Updates y Service Alerts
|
||||
|
||||
## Estado: 🚧 EN DESARROLLO
|
||||
|
||||
La Fase 2 añade enriquecimiento de datos mediante GTFS Static, actualizaciones de viajes en tiempo real (Trip Updates) y alertas de servicio (Service Alerts).
|
||||
|
||||
---
|
||||
|
||||
## ✨ Características Implementadas
|
||||
|
||||
### Backend
|
||||
|
||||
#### Base de Datos
|
||||
- ✅ Migración V5: Tablas GTFS Static (trips, stop_times, calendar, shapes)
|
||||
- ✅ Tablas para Trip Updates y Stop Time Updates
|
||||
- ✅ Vistas: active_trips_today, delayed_trips
|
||||
- ✅ Funciones: get_trip_schedule, get_next_departures
|
||||
|
||||
#### Workers
|
||||
- ✅ GTFS Static Syncer: Sincronización diaria de datos estáticos
|
||||
- ✅ Trip Updates Poller: Polling de retrasos y actualizaciones de viajes
|
||||
- ✅ Service Alerts Poller: Polling de alertas e incidencias
|
||||
|
||||
#### API REST
|
||||
- ✅ Endpoints de Alertas (`/alerts`)
|
||||
- ✅ Endpoints de Trips y Delays (`/trips`)
|
||||
|
||||
### Frontend
|
||||
- ⏳ Componente de Alertas (pendiente)
|
||||
- ⏳ Monitor de Puntualidad (pendiente)
|
||||
- ⏳ Timeline Funcional (pendiente)
|
||||
|
||||
---
|
||||
|
||||
## 📁 Nuevos Archivos Phase 2
|
||||
|
||||
### Base de Datos
|
||||
```
|
||||
database/migrations/
|
||||
└── V5__gtfs_static_tables.sql # Tablas GTFS Static + Trip Updates
|
||||
```
|
||||
|
||||
### Backend Workers
|
||||
```
|
||||
backend/src/worker/
|
||||
├── gtfs-static-syncer.js # Sincronización GTFS Static
|
||||
├── trip-updates-poller.js # Polling Trip Updates
|
||||
└── alerts-poller.js # Polling Service Alerts
|
||||
```
|
||||
|
||||
### Backend API
|
||||
```
|
||||
backend/src/api/routes/
|
||||
├── alerts.js # Endpoints de alertas
|
||||
└── trips.js # Endpoints de trips y delays
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Ejecutar con Fase 2
|
||||
|
||||
### Usando Docker Compose
|
||||
|
||||
```bash
|
||||
# 1. Ejecutar migraciones (incluye V5)
|
||||
make migrate
|
||||
|
||||
# 2. Iniciar todos los servicios (incluye nuevos workers)
|
||||
make start
|
||||
|
||||
# Los nuevos workers se inician automáticamente:
|
||||
# - gtfs-static-syncer (sincronización diaria a las 3 AM)
|
||||
# - trip-updates-poller (polling cada 30s)
|
||||
# - alerts-poller (polling cada 30s)
|
||||
```
|
||||
|
||||
### Desarrollo Local
|
||||
|
||||
```bash
|
||||
cd backend
|
||||
|
||||
# Terminal 1: GTFS Static Syncer
|
||||
npm run dev:gtfs-static
|
||||
|
||||
# Terminal 2: Trip Updates Poller
|
||||
npm run dev:trip-updates
|
||||
|
||||
# Terminal 3: Service Alerts Poller
|
||||
npm run dev:alerts
|
||||
|
||||
# Terminal 4: API Server
|
||||
npm run dev
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📡 Nuevos Endpoints API
|
||||
|
||||
### Alertas
|
||||
|
||||
#### GET /alerts
|
||||
Obtener todas las alertas activas con filtros opcionales.
|
||||
|
||||
**Query Parameters:**
|
||||
- `route_id` (opcional): Filtrar por ruta
|
||||
- `severity` (opcional): Filtrar por severidad (LOW, MEDIUM, HIGH, CRITICAL)
|
||||
- `type` (opcional): Filtrar por tipo (DELAY, CANCELLATION, INCIDENT, etc.)
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
# Todas las alertas activas
|
||||
curl http://localhost:3000/alerts
|
||||
|
||||
# Alertas de una ruta específica
|
||||
curl http://localhost:3000/alerts?route_id=AVE-MAD-BCN
|
||||
|
||||
# Alertas críticas
|
||||
curl http://localhost:3000/alerts?severity=CRITICAL
|
||||
|
||||
# Alertas de cancelaciones
|
||||
curl http://localhost:3000/alerts?type=CANCELLATION
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"alert_id": 1,
|
||||
"alert_type": "DELAY",
|
||||
"severity": "MEDIUM",
|
||||
"cause": "TECHNICAL_PROBLEM",
|
||||
"effect": "SIGNIFICANT_DELAYS",
|
||||
"header_text": "Retraso en AVE 03055",
|
||||
"description_text": "Retraso de 15 minutos debido a problemas técnicos",
|
||||
"url": null,
|
||||
"route_id": "AVE-MAD-BCN",
|
||||
"trip_id": "trip_12345",
|
||||
"train_id": null,
|
||||
"start_time": "2025-11-27T10:00:00Z",
|
||||
"end_time": null,
|
||||
"created_at": "2025-11-27T10:05:00Z",
|
||||
"updated_at": "2025-11-27T10:05:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### GET /alerts/:id
|
||||
Obtener una alerta específica.
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
curl http://localhost:3000/alerts/1
|
||||
```
|
||||
|
||||
#### GET /alerts/route/:routeId
|
||||
Obtener todas las alertas activas de una ruta.
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
curl http://localhost:3000/alerts/route/AVE-MAD-BCN
|
||||
```
|
||||
|
||||
#### GET /alerts/train/:trainId
|
||||
Obtener todas las alertas activas de un tren.
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
curl http://localhost:3000/alerts/train/12345
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Trips y Delays
|
||||
|
||||
#### GET /trips
|
||||
Obtener todos los viajes activos del día.
|
||||
|
||||
**Query Parameters:**
|
||||
- `route_id` (opcional): Filtrar por ruta
|
||||
- `service_id` (opcional): Filtrar por servicio
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
# Todos los viajes activos hoy
|
||||
curl http://localhost:3000/trips
|
||||
|
||||
# Viajes de una ruta específica
|
||||
curl http://localhost:3000/trips?route_id=AVE-MAD-BCN
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"trip_id": "trip_12345",
|
||||
"route_id": "AVE-MAD-BCN",
|
||||
"service_id": "weekday",
|
||||
"trip_headsign": "Barcelona Sants",
|
||||
"direction_id": 0,
|
||||
"block_id": null,
|
||||
"shape_id": "shape_001"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
#### GET /trips/:id
|
||||
Obtener detalles completos de un viaje incluyendo su horario.
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
curl http://localhost:3000/trips/trip_12345
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"trip_id": "trip_12345",
|
||||
"route_id": "AVE-MAD-BCN",
|
||||
"service_id": "weekday",
|
||||
"trip_headsign": "Barcelona Sants",
|
||||
"direction_id": 0,
|
||||
"schedule": [
|
||||
{
|
||||
"stop_id": "MADRID-PUERTA-DE-ATOCHA",
|
||||
"stop_sequence": 1,
|
||||
"arrival_time": "08:00:00",
|
||||
"departure_time": "08:00:00",
|
||||
"stop_headsign": null
|
||||
},
|
||||
{
|
||||
"stop_id": "ZARAGOZA-DELICIAS",
|
||||
"stop_sequence": 2,
|
||||
"arrival_time": "09:25:00",
|
||||
"departure_time": "09:27:00",
|
||||
"stop_headsign": null
|
||||
},
|
||||
{
|
||||
"stop_id": "BARCELONA-SANTS",
|
||||
"stop_sequence": 3,
|
||||
"arrival_time": "10:45:00",
|
||||
"departure_time": "10:45:00",
|
||||
"stop_headsign": null
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### GET /trips/:id/updates
|
||||
Obtener actualizaciones en tiempo real de un viaje (retrasos, cancelaciones).
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
curl http://localhost:3000/trips/trip_12345/updates
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"trip_id": "trip_12345",
|
||||
"has_updates": true,
|
||||
"update_id": 1,
|
||||
"delay_seconds": 900,
|
||||
"schedule_relationship": "SCHEDULED",
|
||||
"start_date": "20251127",
|
||||
"received_at": "2025-11-27T10:15:00Z",
|
||||
"stop_time_updates": [
|
||||
{
|
||||
"stop_sequence": 2,
|
||||
"stop_id": "ZARAGOZA-DELICIAS",
|
||||
"arrival_delay": 900,
|
||||
"departure_delay": 900,
|
||||
"schedule_relationship": "SCHEDULED"
|
||||
},
|
||||
{
|
||||
"stop_sequence": 3,
|
||||
"stop_id": "BARCELONA-SANTS",
|
||||
"arrival_delay": 900,
|
||||
"departure_delay": null,
|
||||
"schedule_relationship": "SCHEDULED"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### GET /trips/:id/delays
|
||||
Obtener información resumida de retrasos de un viaje.
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
curl http://localhost:3000/trips/trip_12345/delays
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
{
|
||||
"trip_id": "trip_12345",
|
||||
"delay_status": "MODERATE_DELAY",
|
||||
"delay_seconds": 900,
|
||||
"delay_formatted": "15 min 0 s",
|
||||
"schedule_relationship": "SCHEDULED",
|
||||
"received_at": "2025-11-27T10:15:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Estados de Delay:**
|
||||
- `NO_DATA`: Sin información de retrasos
|
||||
- `ON_TIME`: Puntual (0 segundos)
|
||||
- `MINOR_DELAY`: Retraso menor (1-5 minutos)
|
||||
- `MODERATE_DELAY`: Retraso moderado (5-15 minutos)
|
||||
- `MAJOR_DELAY`: Retraso mayor (>15 minutos)
|
||||
- `EARLY`: Adelantado
|
||||
|
||||
#### GET /trips/route/:routeId
|
||||
Obtener todos los viajes de una ruta.
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
curl http://localhost:3000/trips/route/AVE-MAD-BCN
|
||||
```
|
||||
|
||||
#### GET /trips/delayed/all
|
||||
Obtener todos los viajes actualmente retrasados.
|
||||
|
||||
**Query Parameters:**
|
||||
- `min_delay` (opcional): Retraso mínimo en segundos (default: 0)
|
||||
|
||||
**Ejemplo:**
|
||||
```bash
|
||||
# Todos los viajes retrasados
|
||||
curl http://localhost:3000/trips/delayed/all
|
||||
|
||||
# Solo retrasos mayores a 5 minutos
|
||||
curl http://localhost:3000/trips/delayed/all?min_delay=300
|
||||
```
|
||||
|
||||
**Respuesta:**
|
||||
```json
|
||||
[
|
||||
{
|
||||
"trip_id": "trip_12345",
|
||||
"route_id": "AVE-MAD-BCN",
|
||||
"trip_headsign": "Barcelona Sants",
|
||||
"delay_seconds": 900,
|
||||
"schedule_relationship": "SCHEDULED",
|
||||
"received_at": "2025-11-27T10:15:00Z"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🔌 Nuevos WebSocket Events (Planeados)
|
||||
|
||||
### Servidor → Cliente
|
||||
|
||||
```javascript
|
||||
// Nueva alerta creada
|
||||
socket.on('alert:new', (alert) => {
|
||||
console.log('Nueva alerta:', alert);
|
||||
});
|
||||
|
||||
// Alerta actualizada
|
||||
socket.on('alert:update', (alert) => {
|
||||
console.log('Alerta actualizada:', alert);
|
||||
});
|
||||
|
||||
// Retraso detectado
|
||||
socket.on('trip:delay', (delayInfo) => {
|
||||
console.log('Retraso en viaje:', delayInfo);
|
||||
});
|
||||
|
||||
// Cancelación de viaje
|
||||
socket.on('trip:cancelled', (tripInfo) => {
|
||||
console.log('Viaje cancelado:', tripInfo);
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🗄️ Estructura de Datos
|
||||
|
||||
### Tablas GTFS Static
|
||||
|
||||
#### trips
|
||||
Información de viajes planificados.
|
||||
|
||||
```sql
|
||||
CREATE TABLE trips (
|
||||
trip_id VARCHAR(100) PRIMARY KEY,
|
||||
route_id VARCHAR(50),
|
||||
service_id VARCHAR(50),
|
||||
trip_headsign VARCHAR(200),
|
||||
trip_short_name VARCHAR(50),
|
||||
direction_id INTEGER,
|
||||
block_id VARCHAR(50),
|
||||
shape_id VARCHAR(100),
|
||||
wheelchair_accessible INTEGER,
|
||||
bikes_allowed INTEGER
|
||||
);
|
||||
```
|
||||
|
||||
#### stop_times
|
||||
Horarios de parada de cada viaje.
|
||||
|
||||
```sql
|
||||
CREATE TABLE stop_times (
|
||||
trip_id VARCHAR(100),
|
||||
arrival_time TIME,
|
||||
departure_time TIME,
|
||||
stop_id VARCHAR(100),
|
||||
stop_sequence INTEGER,
|
||||
stop_headsign VARCHAR(200),
|
||||
pickup_type INTEGER,
|
||||
drop_off_type INTEGER,
|
||||
shape_dist_traveled FLOAT,
|
||||
PRIMARY KEY (trip_id, stop_sequence)
|
||||
);
|
||||
```
|
||||
|
||||
#### calendar
|
||||
Calendario de servicio (días de operación).
|
||||
|
||||
```sql
|
||||
CREATE TABLE calendar (
|
||||
service_id VARCHAR(50) PRIMARY KEY,
|
||||
monday BOOLEAN,
|
||||
tuesday BOOLEAN,
|
||||
wednesday BOOLEAN,
|
||||
thursday BOOLEAN,
|
||||
friday BOOLEAN,
|
||||
saturday BOOLEAN,
|
||||
sunday BOOLEAN,
|
||||
start_date DATE,
|
||||
end_date DATE
|
||||
);
|
||||
```
|
||||
|
||||
#### shapes
|
||||
Geometría de las rutas (trayectorias).
|
||||
|
||||
```sql
|
||||
CREATE TABLE shapes (
|
||||
shape_id VARCHAR(100),
|
||||
shape_pt_lat DOUBLE PRECISION,
|
||||
shape_pt_lon DOUBLE PRECISION,
|
||||
shape_pt_sequence INTEGER,
|
||||
shape_dist_traveled FLOAT,
|
||||
PRIMARY KEY (shape_id, shape_pt_sequence)
|
||||
);
|
||||
```
|
||||
|
||||
### Tablas de Actualizaciones en Tiempo Real
|
||||
|
||||
#### trip_updates
|
||||
Actualizaciones de viajes (retrasos, cancelaciones).
|
||||
|
||||
```sql
|
||||
CREATE TABLE trip_updates (
|
||||
update_id SERIAL PRIMARY KEY,
|
||||
trip_id VARCHAR(100),
|
||||
route_id VARCHAR(50),
|
||||
start_date VARCHAR(10),
|
||||
schedule_relationship VARCHAR(20),
|
||||
delay_seconds INTEGER,
|
||||
received_at TIMESTAMP DEFAULT NOW()
|
||||
);
|
||||
```
|
||||
|
||||
#### stop_time_updates
|
||||
Actualizaciones de paradas específicas.
|
||||
|
||||
```sql
|
||||
CREATE TABLE stop_time_updates (
|
||||
update_id INTEGER REFERENCES trip_updates(update_id),
|
||||
stop_sequence INTEGER,
|
||||
stop_id VARCHAR(100),
|
||||
arrival_delay INTEGER,
|
||||
departure_delay INTEGER,
|
||||
schedule_relationship VARCHAR(20),
|
||||
PRIMARY KEY (update_id, stop_sequence)
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🧪 Probar Phase 2
|
||||
|
||||
### 1. Verificar GTFS Static Sync
|
||||
|
||||
```bash
|
||||
# Ver logs del syncer
|
||||
docker-compose logs -f gtfs-static-syncer
|
||||
|
||||
# Deberías ver:
|
||||
# "Starting GTFS Static synchronization..."
|
||||
# "GTFS data downloaded successfully"
|
||||
# "Imported X routes, Y trips, Z stops"
|
||||
|
||||
# Verificar datos en PostgreSQL
|
||||
make psql
|
||||
> SELECT COUNT(*) FROM trips;
|
||||
> SELECT COUNT(*) FROM stop_times;
|
||||
> SELECT * FROM active_trips_today LIMIT 5;
|
||||
```
|
||||
|
||||
### 2. Verificar Trip Updates
|
||||
|
||||
```bash
|
||||
# Ver logs del poller
|
||||
docker-compose logs -f trip-updates-poller
|
||||
|
||||
# Deberías ver:
|
||||
# "Polling Trip Updates..."
|
||||
# "Processed X trip updates"
|
||||
|
||||
# Verificar en PostgreSQL
|
||||
make psql
|
||||
> SELECT * FROM delayed_trips;
|
||||
> SELECT * FROM trip_updates ORDER BY received_at DESC LIMIT 5;
|
||||
```
|
||||
|
||||
### 3. Verificar Service Alerts
|
||||
|
||||
```bash
|
||||
# Ver logs del poller
|
||||
docker-compose logs -f alerts-poller
|
||||
|
||||
# Deberías ver:
|
||||
# "Polling Service Alerts..."
|
||||
# "Processed X alerts"
|
||||
|
||||
# Probar API
|
||||
curl http://localhost:3000/alerts | jq
|
||||
curl http://localhost:3000/alerts?severity=HIGH | jq
|
||||
```
|
||||
|
||||
### 4. Verificar Trip Delays API
|
||||
|
||||
```bash
|
||||
# Obtener viajes retrasados
|
||||
curl http://localhost:3000/trips/delayed/all | jq
|
||||
|
||||
# Obtener delay de un viaje específico
|
||||
curl http://localhost:3000/trips/trip_12345/delays | jq
|
||||
|
||||
# Obtener schedule completo
|
||||
curl http://localhost:3000/trips/trip_12345 | jq
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🐛 Troubleshooting Phase 2
|
||||
|
||||
### No hay datos de GTFS Static
|
||||
|
||||
**Causa**: El syncer no se ha ejecutado o el ZIP no está disponible.
|
||||
|
||||
**Solución**:
|
||||
```bash
|
||||
# Ejecutar sync manual
|
||||
docker-compose exec gtfs-static-syncer node src/worker/gtfs-static-syncer.js
|
||||
|
||||
# Verificar logs
|
||||
docker-compose logs gtfs-static-syncer
|
||||
|
||||
# Verificar conectividad
|
||||
curl -I https://data.renfe.com/dataset/horarios-trenes-largo-recorrido-ave/resource/horarios-trenes-largo-recorrido-ave-gtfs.zip
|
||||
```
|
||||
|
||||
### No se reciben Trip Updates
|
||||
|
||||
**Causa**: Feed GTFS-RT no disponible o URL incorrecta.
|
||||
|
||||
**Solución**:
|
||||
```bash
|
||||
# Verificar logs
|
||||
docker-compose logs trip-updates-poller
|
||||
|
||||
# Probar feed manualmente
|
||||
curl https://gtfsrt.renfe.com/trip_updates.pb > /tmp/test.pb
|
||||
file /tmp/test.pb # Debe ser "data" (Protocol Buffer)
|
||||
|
||||
# Verificar variables de entorno
|
||||
docker-compose exec trip-updates-poller env | grep GTFS
|
||||
```
|
||||
|
||||
### Alerts no aparecen
|
||||
|
||||
**Causa**: No hay alertas activas o el poller no está corriendo.
|
||||
|
||||
**Solución**:
|
||||
```bash
|
||||
# Verificar worker
|
||||
docker-compose ps alerts-poller
|
||||
|
||||
# Ver logs
|
||||
docker-compose logs alerts-poller
|
||||
|
||||
# Verificar en BD
|
||||
make psql
|
||||
> SELECT COUNT(*) FROM alerts WHERE end_time IS NULL OR end_time > NOW();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 Monitorización Phase 2
|
||||
|
||||
### Logs de Workers
|
||||
|
||||
```bash
|
||||
# Todos los workers Phase 2
|
||||
docker-compose logs -f gtfs-static-syncer trip-updates-poller alerts-poller
|
||||
|
||||
# Worker específico
|
||||
docker-compose logs -f trip-updates-poller
|
||||
```
|
||||
|
||||
### Estadísticas en Redis
|
||||
|
||||
```bash
|
||||
make redis-cli
|
||||
|
||||
# Viajes retrasados
|
||||
> SMEMBERS trips:delayed
|
||||
|
||||
# Alertas activas por ruta
|
||||
> SMEMBERS alerts:route:AVE-MAD-BCN
|
||||
|
||||
# Última sincronización GTFS
|
||||
> GET gtfs:last_sync
|
||||
```
|
||||
|
||||
### Métricas en PostgreSQL
|
||||
|
||||
```sql
|
||||
-- Total de viajes del día
|
||||
SELECT COUNT(*) FROM active_trips_today;
|
||||
|
||||
-- Viajes retrasados
|
||||
SELECT COUNT(*) FROM delayed_trips;
|
||||
|
||||
-- Alertas activas
|
||||
SELECT alert_type, COUNT(*)
|
||||
FROM alerts
|
||||
WHERE end_time IS NULL OR end_time > NOW()
|
||||
GROUP BY alert_type;
|
||||
|
||||
-- Retraso promedio
|
||||
SELECT AVG(delay_seconds) / 60 as avg_delay_minutes
|
||||
FROM trip_updates
|
||||
WHERE received_at > NOW() - INTERVAL '1 hour';
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 🎯 Próximos Pasos
|
||||
|
||||
Funcionalidades pendientes de Phase 2:
|
||||
|
||||
- [ ] WebSocket events para alertas y delays en tiempo real
|
||||
- [ ] Frontend: Componente de alertas
|
||||
- [ ] Frontend: Monitor de puntualidad
|
||||
- [ ] Frontend: Timeline funcional con reproducción histórica
|
||||
- [ ] Frontend: Panel de incidencias
|
||||
- [ ] Notificaciones push (opcional)
|
||||
- [ ] Exportar reportes de puntualidad (opcional)
|
||||
|
||||
---
|
||||
|
||||
## 📝 Notas Técnicas
|
||||
|
||||
### Fuentes de Datos Phase 2
|
||||
|
||||
- **GTFS Static**: https://data.renfe.com/dataset/horarios-trenes-largo-recorrido-ave/resource/horarios-trenes-largo-recorrido-ave-gtfs.zip
|
||||
- **Trip Updates**: https://gtfsrt.renfe.com/trip_updates.pb
|
||||
- **Service Alerts**: https://gtfsrt.renfe.com/service_alerts.pb
|
||||
|
||||
### Frecuencias
|
||||
|
||||
- **GTFS Static Sync**: Diariamente a las 3 AM (configurable via `SYNC_SCHEDULE`)
|
||||
- **Trip Updates**: Cada 30 segundos
|
||||
- **Service Alerts**: Cada 30 segundos
|
||||
|
||||
### Retención de Datos
|
||||
|
||||
- **Trip Updates**: 7 días (usar función `cleanup_old_trip_updates()`)
|
||||
- **Alerts**: Se mantienen hasta `end_time` + 7 días
|
||||
- **GTFS Static**: Se sobrescribe en cada sync
|
||||
|
||||
---
|
||||
|
||||
## 📚 Documentación Relacionada
|
||||
|
||||
- [Arquitectura Completa](arquitectura-sistema-tracking-trenes.md)
|
||||
- [Fase 1 - MVP](FASE1-MVP.md)
|
||||
- [Fuentes de Datos](FUENTES_DATOS.md)
|
||||
- [README Principal](README.md)
|
||||
|
||||
---
|
||||
|
||||
**Estado**: Fase 2 - Backend Completo, Frontend Pendiente
|
||||
**Fecha**: 27 noviembre 2025
|
||||
**Próxima Fase**: Frontend Phase 2 + Fase 3 (Analytics)
|
||||
Reference in New Issue
Block a user