Kashmir Train Timings
Kashmir Train Timings is an offline-first Android app that shows the live timetable and running status for trains across the valley, backed by a single Cloudflare Worker and fronted by a fully static marketing site. The app works from one cached blob, so it opens instantly and survives a backend outage, and the site generates a page per station pair so people searching a specific route actually find it.
- Started
- 2025
- Stack
- Flutter, Dart, Cloudflare Workers, R2, D1, KV, Firebase Cloud Messaging, Astro
- Kind
- Product
- Source
- Private
Why I built it
The valley line had no dependable public timetable. Station boards go stale and the official site skips the short-turn services locals actually ride, so there was no single source that stays correct on its own.
What it does
- Live running status merged into the timetable, with a day-aware schedule so Sunday-only specials never show on a Tuesday.
- Crowd-sourced delay flags, and push alerts when a train's schedule changes.
- Reads one cached blob, so it opens instantly and works offline from the last sync.
- A static site of around 523 pages, one per station pair, station, and train, so each route ranks on its own.
How it is built
A Flutter app (Riverpod, go_router, dio) consumes a single Cloudflare Worker that syncs the timetable from the railway data provider on a cron into R2, tracks budget and state in KV, and keeps crowd corrections in D1. The heavy sync never runs on a user request, which keeps it on the free tier. The marketing site is Astro, built to fully static HTML.
Endpoints
| GET | /version.json | Public build and config the app polls each launch. |
| GET | /data | The app blob, token gated. |
| POST | /flag | Crowd delay corrections; enough reports auto-refresh a train. |
| POST | /admin/refresh | Force a timetable sync. |
How it evolved
- StartTimetable as data
One committed timetable snapshot served as flat JSON, so the app and site build from a single source.
- BackendCloudflare Worker
A Worker syncs the live data on a cron into R2 and serves one gated blob, keeping the whole thing on the free tier.
- AppOffline-first Flutter app
The app runs from the cached blob with push alerts, so it opens instantly and a backend outage cannot take it down.
- NowSEO site
An Astro static site generates a page per station pair, so a search for one route lands on real HTML.
Built by Syed Tasavour. More at syedtasavour.com.