Is my route affected now, later today, or this weekend?
LineWatchTO is an unofficial transit dashboard for Toronto's TTC subway/LRT and GO/UP rail networks. It brings service disruptions, planned advisories, station information, and saved commute checks into a map you can use on desktop or your phone. Built and maintained as a personal full-stack project, it serves riders who want to understand how a disruption affects their usual route.
Open the dashboard · Run locally · Architecture · Contributing
Captured from linewatchto.ca on September 30, 2026 at 7:23 p.m. EDT, with fresh TTC service data. Screenshots are dated snapshots; open the dashboard for current conditions. Click any image to view it at full resolution.
| Rider question | What the dashboard provides |
|---|---|
| Where is service affected? | TTC and GO/UP schematic maps, a geographic map option, and direction-aware disruption overlays. |
| Will it affect my usual route? | My Commutes matches disruptions to saved routes, with separate outbound/return legs and optional Web Push rules. |
| What is happening at my station? | Station details, source-labeled live or scheduled arrivals, surface connections, accessibility outages, and My Stations bookmarks. |
| What is coming up? | Planned advisories, searchable service notices, and station-specific information. |
| What has happened over time? | Alert lifecycle history and disruption analytics with coverage and confidence boundaries. |
| Phone dashboard | Union station and live arrivals |
|---|---|
![]() |
![]() |
Public production views captured during the same session, without an account. The station detail is a deliberate close-up; the desktop overviews show the full network. Arrival predictions and scheduled departures retain their source labels.
See the GO/UP regional rail dashboard
Captured at 7:23 p.m. EDT with fresh regional service data. TTC and regional source availability were checked independently.
The difficult part is turning several feeds into a consistent rider experience while keeping uncertainty visible.
| Problem | Implementation and tradeoff |
|---|---|
| A healthy feed can coexist with a failed one. | Independent source and feature gates keep TTC, regional alerts, arrivals, schedules, and train markers from borrowing each other's live status. |
| A closure on a line may miss a rider's route or direction. | Weighted path calculation and segment/direction matching evaluate each commute leg. The feature monitors routes within one network; it does not recommend detours or plan cross-network journeys. |
| Large schedule archives can overwhelm a small server. | The GTFS importer streams input and batches stop-time writes, rather than keeping the complete feed in memory. |
| Detailed SVG maps are expensive to redraw during gestures. | Pre-rendered map planes carry static artwork while React overlays handle changing impacts and selections. Geographic mode uses MapLibre GL JS and OpenFreeMap. |
| A saved dashboard can look live after connectivity fails. | Separate public snapshots retain each network for up to seven days, label saved context, and make current status unknown. The service worker excludes API responses and account pages from its offline cache. |
flowchart TB
subgraph sources[Transit sources]
alerts[TTC / Metrolinx alerts]
realtime[GTFS realtime]
schedules[Static GTFS]
end
subgraph server[Server boundary]
ingest["Poll / normalize<br/>Check freshness"]
importer["Streaming<br/>schedule import"]
database[(PostgreSQL / PostGIS)]
cache[(Redis cache)]
api["REST API / domain services<br/>Dashboard, accounts,<br/>commute matching"]
push[Optional Web Push]
ingest --> database
ingest -->|invalidate on success| cache
importer --> database
database --> api
cache --> api
api -->|eligible route / line rules| push
end
subgraph browser[Browser]
web["Next.js dashboard<br/>Interactive maps"]
saved["Public offline snapshots<br/>PWA shell"]
notifications[Device notifications]
web --> saved
end
alerts --> ingest
realtime --> ingest
schedules --> importer
api -->|public / authenticated responses| web
push --> notifications
Provider credentials and retained raw source records stay on the server. Public responses expose normalized rider information; authenticated features use session cookies. Operator endpoints are disabled by default and blocked at the production edge.
| Layer | Technologies |
|---|---|
| Web | Next.js App Router, React, TypeScript, Tailwind CSS, MapLibre GL JS |
| API | Java 21, Spring Boot 4.1, Spring Data JPA / Hibernate Spatial, Flyway |
| Storage | PostgreSQL with PostGIS, Redis |
| Delivery | Docker Compose, ARM64 container images, Caddy |
| Verification | Node test runner, Playwright, Maven, GitHub Actions |
Exact dependency versions live in frontend/package.json, frontend/package-lock.json, and backend/pom.xml.
flowchart TD
connection{Backend reachable?}
connection -->|Yes| fresh{"This feature / network:<br/>enabled provider and fresh<br/>successful mapped data?"}
fresh -->|Yes| source["Source-backed results<br/>Source and timestamps"]
fresh -->|No| schedule{"Arrival request with<br/>an active static schedule?"}
schedule -->|Yes| scheduled["Scheduled arrivals<br/>Explicitly labeled"]
schedule -->|No| unknown["Current state unknown / unavailable<br/>Suppress live claims"]
connection -->|No| snapshot{"Saved network snapshot<br/>within seven days?"}
snapshot -->|Yes| offline["Offline saved context<br/>Current status unknown"]
offline --> suppressed["Hide arrivals, train markers,<br/>and current commute checks"]
snapshot -->|No| fallback["Labeled fixtures /<br/>unavailable state"]
Fresh alerts do not establish live arrivals or train positions. Estimated train markers are conservative schematic placements, not physical GPS tracking, and are omitted from geographic mode. Surface notices and accessibility outages do not become rail disruption overlays or commute impacts. See the domain invariants for the exact boundaries.
Use Node.js 24 LTS and npm. No database, backend, account, or provider key is needed to explore the map and fixture fallback.
npm --prefix frontend ci
npm --prefix frontend run devOpen localhost:3000. Without a backend, current service is unknown and demo data is labeled. Account persistence, live arrivals, and push delivery require their configured backend services.
You also need Java 21, Maven 3.9+, and Docker Compose. The checked-in .env.example contains local defaults and empty or placeholder provider credentials.
cp .env.example .env
docker compose up -d postgres redis
mvn -f backend/pom.xml spring-boot:runIn another terminal, run npm --prefix frontend run dev. Alert ingestion is disabled by default. For opt-in live development, use scripts/dev-live-backend.sh; keep provider credentials in ignored local environment files. See the operations guide for source configuration and isolated alert scenarios.
npm --prefix frontend run test:fast
npm --prefix frontend run typecheck
npm --prefix frontend run lint
mvn -f backend/pom.xml testThe testing guide describes browser smoke, offline, map-fit, lifecycle, and release gates. Test counts and timings depend on the checkout and environment; a historical passing run is not a claim that the current checkout has been verified.
frontend/ Dashboard, maps, typed fixtures, PWA, web tests
backend/ REST API, source ingestion, schedules, accounts, persistence, API tests
mobile/ Reserved native workspace; no native app yet
docs/ Domain rules, architecture references, runbooks, publication evidence
scripts/ Development scenarios, data/asset tooling, operational commands
infra/ Optional infrastructure configuration
| Start here | Purpose |
|---|---|
| Contributing / agent guide | Local workflow, safe fixtures, ownership, and proportional checks |
| Domain invariants / feature reference | Behavior and source boundaries |
| Operations / script inventory | Setup variants, scenarios, deployment, and tooling |
| Security policy / publication audit | Private reporting and the scope of the latest repository audit |
| Source launch gates | Source, map, and naming approval requirements |
Project code and original documentation are licensed under MIT. This code license does not grant rights to third-party transit data, adapted map artwork, names, or marks. Bundled fonts retain their own license notices.
LineWatchTO is independent and unofficial. It is not affiliated with, endorsed by, or operated by TTC or Metrolinx. The project author drew the schematic maps in Inkscape, using the TTC route map and Metrolinx GO system map as visual references. See credits and third-party notices.
Contains information licensed under the Open Government Licence – Toronto.
That attribution applies to identified City of Toronto open-data inputs, including TTC GTFS Realtime. TTC Live Alerts, TTC website material, and Metrolinx API records have separate source terms. Committed alert examples are synthetic; provider credentials and downloaded source responses stay outside Git.



