Real-time tracker for Finnish trains, built on Fintraffic's Digitraffic open rail data. It ingests live train events, tracks delays per train, station and route, and shows them on a live dashboard. An AI assistant explains why a train is late, based on its own event history.
Status: in development. Live demo link will be added here.
Digitraffic publishes every train's timetable, live position and actual arrival and departure times as open data. This project treats that feed as a real production event stream: unreliable network, duplicate and out-of-order messages, high volume during rush hour. It shows how to build a correct, observable and secure event-driven system on top of it.
flowchart LR
DT[Digitraffic rail\nMQTT over WebSocket + REST] --> ING[ingest-service\nSpring Boot, Java 21]
ING -->|train events| BUS[(Kafka)]
BUS --> DLY[delay-service\nconsumers]
DLY --> DB[(PostgreSQL + TimescaleDB)]
DB --> API[api-service\nREST + WebSocket]
API --> UI[Angular dashboard\nsignals, live map]
API --> AI[AI explainer\nLLM over event history]
ING & DLY & API --> OBS[Prometheus / Grafana / Loki]
| Layer | Choice |
|---|---|
| Backend | Java 21 (virtual threads), Spring Boot, Spring Kafka, Spring Data JPA, Flyway |
| Events | Kafka (keyed by train number + departure date for per-train ordering) |
| Storage | PostgreSQL with TimescaleDB for time-series delay data |
| Frontend | Angular (standalone components, signals), MapLibre for the map |
| AI | LLM summary of a train's delay history ("why is IC 27 late?") |
| Delivery | Docker, GitHub Actions, Trivy image scanning, OWASP dependency check, Traefik |
| Observability | Prometheus, Grafana, Loki |
- At-least-once delivery, idempotent consumers. MQTT and Kafka can both redeliver. Each event has a natural key (train, departure date, station, event type, version), and writes are upserts on that key.
- Ordering. Kafka partitions are keyed per train, so one train's events stay in order.
- Backpressure. The ingest service buffers and reconnects with backoff; the REST API is used to backfill gaps after a reconnect.
- Security. Read-only public API with rate limiting, no secrets in the repo, non-root containers, image scanning in CI.
See issues for the detailed plan.
- Ingest: Spring Boot service subscribing to Digitraffic rail MQTT, publishing to Kafka
- Delays: consumers that compute delay per train, station and route
- API: REST and WebSocket endpoints
- Dashboard: Angular live map and delay rankings
- AI explainer
- Secure CI/CD and public deployment
- Write-up: architecture post on Medium
docker compose up -d # Kafka, PostgreSQL/TimescaleDB, Grafana
./mvnw spring-boot:run # once the services existRail data from Fintraffic / Digitraffic, licensed under CC BY 4.0. Source: Fintraffic / digitraffic.fi.
Code licensed under MIT.