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>
959 lines
20 KiB
Markdown
959 lines
20 KiB
Markdown
# Fase 3: Analytics y Exploración Avanzada
|
|
|
|
## Estado: ✅ IMPLEMENTADO (Backend)
|
|
|
|
La Fase 3 añade capacidades avanzadas de análisis, exploración de rutas, planificación de viajes y exportación de datos.
|
|
|
|
---
|
|
|
|
## ✨ Características Implementadas
|
|
|
|
### Backend
|
|
|
|
#### Base de Datos
|
|
- ✅ Migración V6: Vistas materializadas para analytics
|
|
- ✅ Funciones para heatmaps, estadísticas y análisis
|
|
- ✅ Tablas para cache de exportaciones
|
|
- ✅ Vistas de sistema: traffic_by_hour, traffic_by_route, daily_statistics, route_performance
|
|
|
|
#### Workers
|
|
- ✅ Analytics Refresher: Refresco automático de vistas materializadas cada 15 minutos
|
|
|
|
#### API REST
|
|
- ✅ Analytics API (`/analytics`) - Heatmaps, estadísticas, performance
|
|
- ✅ Explorer API (`/explorer`) - Explorador de rutas, planificador de viajes, búsqueda
|
|
|
|
### Frontend
|
|
- ⏳ Componentes de Analytics (pendiente)
|
|
- ⏳ Heatmap de tráfico (pendiente)
|
|
- ⏳ Dashboard de estadísticas (pendiente)
|
|
- ⏳ Planificador de viajes UI (pendiente)
|
|
|
|
---
|
|
|
|
## 📁 Nuevos Archivos Phase 3
|
|
|
|
### Base de Datos
|
|
```
|
|
database/migrations/
|
|
└── V6__analytics_and_statistics.sql # Vistas y funciones de analytics
|
|
```
|
|
|
|
### Backend Workers
|
|
```
|
|
backend/src/worker/
|
|
└── analytics-refresher.js # Refresco de vistas materializadas
|
|
```
|
|
|
|
### Backend API
|
|
```
|
|
backend/src/api/routes/
|
|
├── analytics.js # Endpoints de analytics y exportación
|
|
└── explorer.js # Explorador de rutas y planificador
|
|
```
|
|
|
|
---
|
|
|
|
## 🚀 Ejecutar con Fase 3
|
|
|
|
### Usando Docker Compose
|
|
|
|
```bash
|
|
# 1. Ejecutar migraciones (incluye V6)
|
|
make migrate
|
|
|
|
# 2. Iniciar todos los servicios (incluye analytics-refresher)
|
|
make start
|
|
|
|
# El worker analytics-refresher se inicia automáticamente
|
|
# y refresca las vistas cada 15 minutos
|
|
```
|
|
|
|
### Desarrollo Local
|
|
|
|
```bash
|
|
cd backend
|
|
|
|
# Terminal 1: Analytics Refresher
|
|
npm run dev:analytics
|
|
|
|
# Terminal 2: API Server
|
|
npm run dev
|
|
```
|
|
|
|
---
|
|
|
|
## 📡 Nuevos Endpoints API
|
|
|
|
### Analytics - Traffic
|
|
|
|
#### GET /analytics/traffic/heatmap
|
|
Obtener datos de heatmap de tráfico.
|
|
|
|
**Query Parameters:**
|
|
- `start_date` (opcional): Fecha inicio (ISO 8601)
|
|
- `end_date` (opcional): Fecha fin (ISO 8601)
|
|
- `grid_size` (opcional): Tamaño de celda en grados (default: 0.1 ≈ 11km)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
# Heatmap últimos 7 días
|
|
curl http://localhost:3000/analytics/traffic/heatmap
|
|
|
|
# Heatmap con grid más fino
|
|
curl http://localhost:3000/analytics/traffic/heatmap?grid_size=0.05
|
|
|
|
# Rango personalizado
|
|
curl "http://localhost:3000/analytics/traffic/heatmap?start_date=2025-11-20T00:00:00Z&end_date=2025-11-27T23:59:59Z"
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"lat": 40.4,
|
|
"lon": -3.7,
|
|
"intensity": 125,
|
|
"avgSpeed": 78.5
|
|
},
|
|
{
|
|
"lat": 41.3,
|
|
"lon": 2.1,
|
|
"intensity": 98,
|
|
"avgSpeed": 65.3
|
|
}
|
|
]
|
|
```
|
|
|
|
#### GET /analytics/traffic/hourly
|
|
Obtener patrón de tráfico por hora del día.
|
|
|
|
**Query Parameters:**
|
|
- `days` (opcional): Número de días para analizar (default: 7)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/traffic/hourly?days=30
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"hour_of_day": 0,
|
|
"avg_trains": 15.3,
|
|
"avg_speed": 45.2,
|
|
"total_observations": 45230
|
|
},
|
|
{
|
|
"hour_of_day": 7,
|
|
"avg_trains": 87.5,
|
|
"avg_speed": 68.7,
|
|
"total_observations": 125890
|
|
}
|
|
]
|
|
```
|
|
|
|
#### GET /analytics/traffic/by-hour
|
|
Obtener estadísticas de tráfico agregadas por hora.
|
|
|
|
**Query Parameters:**
|
|
- `limit` (opcional): Número de horas (default: 24)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/traffic/by-hour?limit=48
|
|
```
|
|
|
|
#### GET /analytics/traffic/by-route
|
|
Obtener estadísticas de tráfico por ruta.
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/traffic/by-route
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"route_id": "AVE-MAD-BCN",
|
|
"route_name": "Madrid - Barcelona",
|
|
"route_type": "HIGH_SPEED",
|
|
"total_trains": 234,
|
|
"active_days": 30,
|
|
"avg_speed": 185.4,
|
|
"total_positions": 125890
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### Analytics - Statistics
|
|
|
|
#### GET /analytics/statistics/daily
|
|
Obtener estadísticas diarias del sistema.
|
|
|
|
**Query Parameters:**
|
|
- `days` (opcional): Número de días (default: 30)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/statistics/daily?days=90
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"date": "2025-11-27",
|
|
"unique_trains": 456,
|
|
"total_positions": 65432,
|
|
"avg_speed": 72.3,
|
|
"stopped_count": 12890,
|
|
"moving_count": 52542
|
|
}
|
|
]
|
|
```
|
|
|
|
#### GET /analytics/statistics/system
|
|
Obtener estado actual del sistema.
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/statistics/system
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"active_trains": 234,
|
|
"active_alerts": 5,
|
|
"delayed_trips": 12,
|
|
"avg_delay_seconds": 450,
|
|
"active_routes": 45,
|
|
"last_update": "2025-11-27T15:30:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Analytics - Performance
|
|
|
|
#### GET /analytics/performance/routes
|
|
Obtener métricas de rendimiento de rutas (puntualidad, retrasos).
|
|
|
|
**Query Parameters:**
|
|
- `limit` (opcional): Número de rutas (default: 20)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/performance/routes?limit=10
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"route_id": "AVE-MAD-BCN",
|
|
"route_name": "Madrid - Barcelona",
|
|
"total_trips": 345,
|
|
"delayed_trips": 23,
|
|
"on_time_trips": 322,
|
|
"avg_delay_seconds": 180,
|
|
"median_delay_seconds": 120,
|
|
"max_delay_seconds": 1800,
|
|
"punctuality_percentage": 93.33
|
|
}
|
|
]
|
|
```
|
|
|
|
#### GET /analytics/performance/route/:routeId
|
|
Obtener estadísticas detalladas de una ruta específica.
|
|
|
|
**Query Parameters:**
|
|
- `days` (opcional): Número de días para analizar (default: 7)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/performance/route/AVE-MAD-BCN?days=30
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"total_trips": 234,
|
|
"unique_trains": 45,
|
|
"avg_speed": 185.4,
|
|
"max_speed": 298.7,
|
|
"total_distance_km": 98765.4,
|
|
"avg_delay_seconds": 120,
|
|
"on_time_percentage": 92.5
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Analytics - Delays
|
|
|
|
#### GET /analytics/delays/top-routes
|
|
Obtener rutas con más retrasos.
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/delays/top-routes
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"route_id": "MD-MAD-VAL",
|
|
"route_name": "Madrid - Valencia",
|
|
"delayed_count": 45,
|
|
"avg_delay": 600,
|
|
"max_delay": 2400
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
### Analytics - Stations
|
|
|
|
#### GET /analytics/stations/busiest
|
|
Obtener estaciones más transitadas.
|
|
|
|
**Query Parameters:**
|
|
- `limit` (opcional): Número de estaciones (default: 20)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/stations/busiest?limit=10
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"stop_id": "MADRID-PUERTA-DE-ATOCHA",
|
|
"stop_name": "Madrid Puerta de Atocha",
|
|
"daily_trips": 456,
|
|
"routes_count": 34
|
|
}
|
|
]
|
|
```
|
|
|
|
#### GET /analytics/stations/:stationId/statistics
|
|
Obtener estadísticas de una estación específica.
|
|
|
|
**Query Parameters:**
|
|
- `days` (opcional): Número de días (default: 7)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/analytics/stations/MADRID-PUERTA-DE-ATOCHA/statistics?days=30
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"total_departures": 3450,
|
|
"total_arrivals": 3420,
|
|
"unique_routes": 45,
|
|
"avg_delay_minutes": 2.5,
|
|
"busiest_hour": 8
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Analytics - Trains
|
|
|
|
#### GET /analytics/trains/:trainId/distance
|
|
Calcular distancia recorrida por un tren.
|
|
|
|
**Query Parameters:**
|
|
- `start_time` (opcional): Timestamp inicio
|
|
- `end_time` (opcional): Timestamp fin
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl "http://localhost:3000/analytics/trains/12345/distance?start_time=2025-11-27T00:00:00Z&end_time=2025-11-27T23:59:59Z"
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"train_id": "12345",
|
|
"start_time": "2025-11-27T00:00:00Z",
|
|
"end_time": "2025-11-27T23:59:59Z",
|
|
"distance_km": 1234.56
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### Analytics - Export
|
|
|
|
#### GET /analytics/export
|
|
Exportar datos en diferentes formatos.
|
|
|
|
**Query Parameters:**
|
|
- `table` (requerido): Tabla a exportar
|
|
- `format` (opcional): json, csv, geojson (default: json)
|
|
- `start_date` (opcional): Fecha inicio
|
|
- `end_date` (opcional): Fecha fin
|
|
- `limit` (opcional): Límite de registros (default: 1000)
|
|
|
|
**Tablas permitidas:**
|
|
- train_positions
|
|
- trains
|
|
- routes
|
|
- stations
|
|
- alerts
|
|
- trip_updates
|
|
- traffic_by_hour
|
|
- daily_statistics
|
|
|
|
**Ejemplo JSON:**
|
|
```bash
|
|
curl "http://localhost:3000/analytics/export?table=trains&format=json"
|
|
```
|
|
|
|
**Ejemplo CSV:**
|
|
```bash
|
|
curl "http://localhost:3000/analytics/export?table=train_positions&format=csv&limit=5000" > positions.csv
|
|
```
|
|
|
|
**Ejemplo GeoJSON:**
|
|
```bash
|
|
curl "http://localhost:3000/analytics/export?table=stations&format=geojson" > stations.geojson
|
|
```
|
|
|
|
---
|
|
|
|
### Analytics - Refresh
|
|
|
|
#### POST /analytics/refresh
|
|
Refrescar manualmente las vistas materializadas.
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl -X POST http://localhost:3000/analytics/refresh
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Analytics views refreshed successfully",
|
|
"timestamp": "2025-11-27T15:30:00Z"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 📍 Explorer - Route Explorer
|
|
|
|
### GET /explorer/routes/:routeId
|
|
Obtener información completa de una ruta (trips, stops, shape).
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/explorer/routes/AVE-MAD-BCN
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"route": {
|
|
"route_id": "AVE-MAD-BCN",
|
|
"route_name": "Madrid - Barcelona",
|
|
"route_type": "HIGH_SPEED"
|
|
},
|
|
"trips": [
|
|
{
|
|
"trip_id": "trip_001",
|
|
"trip_headsign": "Barcelona Sants",
|
|
"direction_id": 0
|
|
}
|
|
],
|
|
"stops": [
|
|
{
|
|
"stop_id": "MADRID-PUERTA-DE-ATOCHA",
|
|
"stop_name": "Madrid Puerta de Atocha",
|
|
"stop_lat": 40.4067,
|
|
"stop_lon": -3.6906
|
|
}
|
|
],
|
|
"shape": {
|
|
"shape_id": "shape_001",
|
|
"points": [
|
|
{
|
|
"lat": 40.4067,
|
|
"lon": -3.6906,
|
|
"sequence": 1,
|
|
"distance": 0
|
|
}
|
|
]
|
|
},
|
|
"total_trips": 45,
|
|
"total_stops": 8
|
|
}
|
|
```
|
|
|
|
### GET /explorer/trips/:tripId/schedule
|
|
Obtener horario completo de un viaje.
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/explorer/trips/trip_12345/schedule
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"stop_id": "MADRID-PUERTA-DE-ATOCHA",
|
|
"stop_name": "Madrid Puerta de Atocha",
|
|
"arrival_time": "08:00:00",
|
|
"departure_time": "08:00:00",
|
|
"stop_sequence": 1
|
|
},
|
|
{
|
|
"stop_id": "BARCELONA-SANTS",
|
|
"stop_name": "Barcelona Sants",
|
|
"arrival_time": "10:45:00",
|
|
"departure_time": "10:45:00",
|
|
"stop_sequence": 3
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## 🚉 Explorer - Stations
|
|
|
|
### GET /explorer/stations/:stationId
|
|
Obtener información completa de una estación.
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl http://localhost:3000/explorer/stations/MADRID-PUERTA-DE-ATOCHA
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"station": {
|
|
"stop_id": "MADRID-PUERTA-DE-ATOCHA",
|
|
"stop_name": "Madrid Puerta de Atocha",
|
|
"stop_lat": 40.4067,
|
|
"stop_lon": -3.6906
|
|
},
|
|
"next_departures": [
|
|
{
|
|
"trip_id": "trip_001",
|
|
"route_id": "AVE-MAD-BCN",
|
|
"route_name": "Madrid - Barcelona",
|
|
"headsign": "Barcelona Sants",
|
|
"scheduled_departure": "15:00:00",
|
|
"estimated_delay": 180,
|
|
"status": "DELAYED"
|
|
}
|
|
],
|
|
"routes": [
|
|
{
|
|
"route_id": "AVE-MAD-BCN",
|
|
"route_name": "Madrid - Barcelona"
|
|
}
|
|
],
|
|
"statistics": {
|
|
"total_departures": 456,
|
|
"total_arrivals": 450,
|
|
"unique_routes": 34,
|
|
"avg_delay_minutes": 2.5,
|
|
"busiest_hour": 8
|
|
}
|
|
}
|
|
```
|
|
|
|
### GET /explorer/stations/:stationId/nearby
|
|
Obtener estaciones cercanas.
|
|
|
|
**Query Parameters:**
|
|
- `radius` (opcional): Radio en km (default: 5)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl "http://localhost:3000/explorer/stations/MADRID-PUERTA-DE-ATOCHA/nearby?radius=10"
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"stop_id": "MADRID-CHAMARTIN",
|
|
"stop_name": "Madrid Chamartín",
|
|
"stop_lat": 40.4728,
|
|
"stop_lon": -3.6797,
|
|
"distance_km": 7.8
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## 🗺️ Explorer - Trip Planner
|
|
|
|
### GET /explorer/planner
|
|
Planificador de viajes entre dos estaciones.
|
|
|
|
**Query Parameters:**
|
|
- `origin` (requerido): ID de estación origen
|
|
- `destination` (requerido): ID de estación destino
|
|
- `time` (opcional): Hora de salida (HH:MM:SS)
|
|
- `date` (opcional): Fecha (YYYY-MM-DD)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl "http://localhost:3000/explorer/planner?origin=MADRID-PUERTA-DE-ATOCHA&destination=BARCELONA-SANTS&time=08:00:00"
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
{
|
|
"origin": "MADRID-PUERTA-DE-ATOCHA",
|
|
"destination": "BARCELONA-SANTS",
|
|
"requested_time": "08:00:00",
|
|
"requested_date": "today",
|
|
"direct_trips": [
|
|
{
|
|
"trip_id": "trip_001",
|
|
"route_id": "AVE-MAD-BCN",
|
|
"route_name": "Madrid - Barcelona",
|
|
"trip_headsign": "Barcelona Sants",
|
|
"origin_departure": "08:00:00",
|
|
"destination_arrival": "10:45:00",
|
|
"duration_minutes": 165,
|
|
"delay": {
|
|
"delay_seconds": 180,
|
|
"schedule_relationship": "SCHEDULED"
|
|
}
|
|
}
|
|
],
|
|
"trips_with_transfer": [
|
|
{
|
|
"trip1_id": "trip_002",
|
|
"route1_name": "Madrid - Zaragoza",
|
|
"trip2_id": "trip_003",
|
|
"route2_name": "Zaragoza - Barcelona",
|
|
"origin_departure": "08:30:00",
|
|
"transfer_arrival": "09:50:00",
|
|
"transfer_departure": "10:10:00",
|
|
"destination_arrival": "11:30:00",
|
|
"transfer_station": "ZARAGOZA-DELICIAS",
|
|
"transfer_station_name": "Zaragoza Delicias",
|
|
"total_duration_minutes": 180
|
|
}
|
|
],
|
|
"total_options": 3
|
|
}
|
|
```
|
|
|
|
### GET /explorer/routes/between
|
|
Encontrar rutas que conectan dos estaciones.
|
|
|
|
**Query Parameters:**
|
|
- `origin` (requerido): ID de estación origen
|
|
- `destination` (requerido): ID de estación destino
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl "http://localhost:3000/explorer/routes/between?origin=MADRID-PUERTA-DE-ATOCHA&destination=BARCELONA-SANTS"
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"route_id": "AVE-MAD-BCN",
|
|
"route_name": "Madrid - Barcelona",
|
|
"route_type": "HIGH_SPEED",
|
|
"route_color": "FF6600",
|
|
"daily_trips": 25
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## 🔍 Explorer - Search
|
|
|
|
### GET /explorer/search
|
|
Buscar estaciones por nombre.
|
|
|
|
**Query Parameters:**
|
|
- `query` (requerido): Término de búsqueda (mínimo 2 caracteres)
|
|
- `limit` (opcional): Número de resultados (default: 10)
|
|
|
|
**Ejemplo:**
|
|
```bash
|
|
curl "http://localhost:3000/explorer/search?query=madrid&limit=5"
|
|
```
|
|
|
|
**Respuesta:**
|
|
```json
|
|
[
|
|
{
|
|
"stop_id": "MADRID-PUERTA-DE-ATOCHA",
|
|
"stop_name": "Madrid Puerta de Atocha",
|
|
"stop_lat": 40.4067,
|
|
"stop_lon": -3.6906,
|
|
"location_type": 1,
|
|
"parent_station": null
|
|
},
|
|
{
|
|
"stop_id": "MADRID-CHAMARTIN",
|
|
"stop_name": "Madrid Chamartín",
|
|
"stop_lat": 40.4728,
|
|
"stop_lon": -3.6797,
|
|
"location_type": 1,
|
|
"parent_station": null
|
|
}
|
|
]
|
|
```
|
|
|
|
---
|
|
|
|
## 🗄️ Vistas Materializadas
|
|
|
|
### traffic_by_hour
|
|
Tráfico agregado por hora (últimos 30 días).
|
|
|
|
**Columnas:**
|
|
- hour: Hora (timestamp)
|
|
- active_trains: Número de trenes activos
|
|
- total_positions: Total de posiciones registradas
|
|
- avg_speed: Velocidad promedio
|
|
- median_speed: Velocidad mediana
|
|
- max_speed: Velocidad máxima
|
|
|
|
### traffic_by_route
|
|
Tráfico por ruta (últimos 30 días).
|
|
|
|
**Columnas:**
|
|
- route_id, route_name, route_type
|
|
- total_trains: Total de trenes diferentes
|
|
- active_days: Días con actividad
|
|
- avg_speed: Velocidad promedio
|
|
- total_positions: Posiciones registradas
|
|
|
|
### daily_statistics
|
|
Estadísticas diarias del sistema (últimos 90 días).
|
|
|
|
**Columnas:**
|
|
- date: Fecha
|
|
- unique_trains: Trenes únicos
|
|
- total_positions: Posiciones totales
|
|
- avg_speed: Velocidad promedio
|
|
- stopped_count: Posiciones paradas
|
|
- moving_count: Posiciones en movimiento
|
|
|
|
### route_performance
|
|
Rendimiento y puntualidad por ruta (últimos 30 días).
|
|
|
|
**Columnas:**
|
|
- route_id, route_name
|
|
- total_trips: Total de viajes
|
|
- delayed_trips: Viajes retrasados
|
|
- on_time_trips: Viajes puntuales
|
|
- avg_delay_seconds: Retraso promedio
|
|
- median_delay_seconds: Retraso mediano
|
|
- max_delay_seconds: Retraso máximo
|
|
- punctuality_percentage: % de puntualidad
|
|
|
|
**Refresco:** Cada 15 minutos automáticamente via analytics-refresher worker.
|
|
|
|
---
|
|
|
|
## 🧪 Probar Phase 3
|
|
|
|
### 1. Verificar Analytics Refresher
|
|
|
|
```bash
|
|
# Ver logs del worker
|
|
docker-compose logs -f analytics-refresher
|
|
|
|
# Deberías ver cada 15 minutos:
|
|
# "Starting analytics views refresh..."
|
|
# "Analytics views refreshed successfully"
|
|
```
|
|
|
|
### 2. Probar Analytics API
|
|
|
|
```bash
|
|
# Sistema general
|
|
curl http://localhost:3000/analytics/statistics/system | jq
|
|
|
|
# Heatmap
|
|
curl http://localhost:3000/analytics/traffic/heatmap | jq
|
|
|
|
# Performance de rutas
|
|
curl http://localhost:3000/analytics/performance/routes | jq
|
|
|
|
# Rutas más retrasadas
|
|
curl http://localhost:3000/analytics/delays/top-routes | jq
|
|
|
|
# Estaciones más transitadas
|
|
curl http://localhost:3000/analytics/stations/busiest | jq
|
|
```
|
|
|
|
### 3. Probar Explorer API
|
|
|
|
```bash
|
|
# Buscar estación
|
|
curl "http://localhost:3000/explorer/search?query=madrid" | jq
|
|
|
|
# Info de estación
|
|
curl http://localhost:3000/explorer/stations/MADRID-PUERTA-DE-ATOCHA | jq
|
|
|
|
# Info de ruta
|
|
curl http://localhost:3000/explorer/routes/AVE-MAD-BCN | jq
|
|
|
|
# Planificar viaje
|
|
curl "http://localhost:3000/explorer/planner?origin=MADRID-PUERTA-DE-ATOCHA&destination=BARCELONA-SANTS" | jq
|
|
```
|
|
|
|
### 4. Probar Exportación
|
|
|
|
```bash
|
|
# Exportar a CSV
|
|
curl "http://localhost:3000/analytics/export?table=routes&format=csv" > routes.csv
|
|
|
|
# Exportar a GeoJSON
|
|
curl "http://localhost:3000/analytics/export?table=stations&format=geojson" > stations.geojson
|
|
|
|
# Exportar posiciones filtradas
|
|
curl "http://localhost:3000/analytics/export?table=train_positions&start_date=2025-11-27T00:00:00Z&limit=1000" > positions.json
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Use Cases
|
|
|
|
### Dashboard de Control
|
|
```bash
|
|
# Obtener datos para dashboard
|
|
curl http://localhost:3000/analytics/statistics/system
|
|
curl http://localhost:3000/analytics/traffic/by-route
|
|
curl http://localhost:3000/analytics/delays/top-routes
|
|
curl http://localhost:3000/analytics/stations/busiest?limit=5
|
|
```
|
|
|
|
### Análisis de Rendimiento
|
|
```bash
|
|
# Análisis de una ruta específica
|
|
curl http://localhost:3000/analytics/performance/route/AVE-MAD-BCN?days=30
|
|
|
|
# Estadísticas diarias últimos 30 días
|
|
curl http://localhost:3000/analytics/statistics/daily?days=30
|
|
|
|
# Distancia recorrida por tren
|
|
curl "http://localhost:3000/analytics/trains/12345/distance?start_time=2025-11-01T00:00:00Z"
|
|
```
|
|
|
|
### Planificación de Viajes
|
|
```bash
|
|
# Buscar estación
|
|
curl "http://localhost:3000/explorer/search?query=barcelona"
|
|
|
|
# Ver info completa de estación
|
|
curl http://localhost:3000/explorer/stations/BARCELONA-SANTS
|
|
|
|
# Planificar viaje
|
|
curl "http://localhost:3000/explorer/planner?origin=MADRID-PUERTA-DE-ATOCHA&destination=BARCELONA-SANTS&time=08:00:00"
|
|
|
|
# Ver rutas que conectan dos puntos
|
|
curl "http://localhost:3000/explorer/routes/between?origin=MADRID-PUERTA-DE-ATOCHA&destination=BARCELONA-SANTS"
|
|
```
|
|
|
|
---
|
|
|
|
## 🐛 Troubleshooting Phase 3
|
|
|
|
### Las vistas materializadas están vacías
|
|
|
|
**Causa**: No hay suficientes datos históricos o no se han refrescado.
|
|
|
|
**Solución**:
|
|
```bash
|
|
# Refrescar manualmente
|
|
curl -X POST http://localhost:3000/analytics/refresh
|
|
|
|
# Verificar en PostgreSQL
|
|
make psql
|
|
> SELECT COUNT(*) FROM traffic_by_hour;
|
|
> SELECT COUNT(*) FROM traffic_by_route;
|
|
```
|
|
|
|
### El planificador no encuentra viajes
|
|
|
|
**Causa**: Datos GTFS Static no cargados o formato de parámetros incorrecto.
|
|
|
|
**Solución**:
|
|
```bash
|
|
# Verificar que hay trips y stop_times
|
|
make psql
|
|
> SELECT COUNT(*) FROM trips;
|
|
> SELECT COUNT(*) FROM stop_times;
|
|
|
|
# Verificar formato de parámetros
|
|
curl "http://localhost:3000/explorer/planner?origin=STOP_ID_ORIGIN&destination=STOP_ID_DEST"
|
|
```
|
|
|
|
### Export devuelve error
|
|
|
|
**Causa**: Tabla no permitida o parámetros inválidos.
|
|
|
|
**Solución**:
|
|
```bash
|
|
# Ver tablas permitidas
|
|
curl "http://localhost:3000/analytics/export" | jq '.allowed_tables'
|
|
|
|
# Usar tabla válida
|
|
curl "http://localhost:3000/analytics/export?table=routes&format=json"
|
|
```
|
|
|
|
---
|
|
|
|
## 📝 Próximos Pasos
|
|
|
|
Funcionalidades pendientes de Phase 3:
|
|
|
|
- [ ] Frontend: Heatmap de tráfico en mapa
|
|
- [ ] Frontend: Dashboard de estadísticas con gráficos
|
|
- [ ] Frontend: UI del planificador de viajes
|
|
- [ ] Frontend: Explorador de rutas interactivo
|
|
- [ ] WebSocket para updates de analytics en tiempo real
|
|
- [ ] Overlay de infraestructura ADIF (WMS)
|
|
- [ ] Predicciones ML (Fase 4)
|
|
|
|
---
|
|
|
|
## 📚 Documentación Relacionada
|
|
|
|
- [Arquitectura Completa](arquitectura-sistema-tracking-trenes.md)
|
|
- [Fase 1 - MVP](FASE1-MVP.md)
|
|
- [Fase 2 - Enriquecimiento](FASE2-ENRIQUECIMIENTO.md)
|
|
- [Fuentes de Datos](FUENTES_DATOS.md)
|
|
- [README Principal](README.md)
|
|
|
|
---
|
|
|
|
**Estado**: Fase 3 - Backend Completo, Frontend Pendiente
|
|
**Fecha**: 27 noviembre 2025
|
|
**Próxima Fase**: Frontend Phase 3 + Fase 4 (ML y Predicciones)
|