Problem
When we break something on the GTFS-RT pipeline, the producer, or the PWA
itself, there is currently no channel to tell affected users. They just
see broken behaviour and leave. We also have no clean way to say
"fixed" once the issue is resolved.
We need a lightweight in-app banner that admins can publish, append
follow-ups to, and clear — without standing up a backend.
Proposal
A file-driven banner, served by Cloudflare Pages as a static asset and
fetched by the PWA at load time and on a short polling interval.
Data shape
A single JSON file, e.g. static/emergency.json:
{
"active": true,
"severity": "info" | "warning" | "critical",
"title": "Live vehicle positions are stale in Cluj-Napoca",
"body": "We are investigating. Last update ~30 min ago.",
"postedAt": "2026-07-06T18:00:00Z",
"updatedAt": "2026-07-06T18:00:00Z",
"followUps": [
{ "at": "2026-07-06T18:45:00Z", "body": "Root cause identified — GTFS-RT producer restart in progress." }
]
}
When active is false, or the file is absent, the PWA shows no banner.
PWA side
- Fetch
emergency.json on app load and every 60s while the app is
open (cache-busted with ?v=<updatedAt> or similar).
- If
active: true, render a banner above the main view:
info → neutral background
warning → amber background
critical → red background, dismissable in-session only
- Render
followUps as a collapsible thread under the main body so
users see progression (issue → updates → resolved), newest first.
- Banner is purely additive to the existing UI; no map / list changes.
Admin side — three operations, one file
The whole publisher is the JSON file plus (optionally) one workflow
file. No new service, no new secrets.
- Publish — write the JSON with
active: true, commit to main.
- Follow up — append a new entry to
followUps, bump updatedAt.
- Remove — set
active: false (or delete the file), commit.
The simplest path is edit static/emergency.json in the GitHub web
UI and commit — Cloudflare Pages auto-deploys on push to main.
The polished path is a .github/workflows/emergency-message.yml
workflow with workflow_dispatch inputs (action, severity, title,
body, followUp) that rewrites the JSON and commits it. Same end
state, but no hand-editing of JSON, and it works from the GitHub
mobile app.
Ship the file + PWA read path first, layer the workflow on top once we
are happy with the data shape.
Acceptance criteria
Out of scope (v1)
- Push notifications (web push, FCM)
- Per-feed / per-region targeting (one banner covers all users for now)
- Scheduled expiry of a banner (
expiresAt is a nice-to-have, not v1)
- Banner analytics (impressions, dismissals)
- Localisation (RO / EN) — English-only in v1
- In-app message centre / history of past messages
Problem
When we break something on the GTFS-RT pipeline, the producer, or the PWA
itself, there is currently no channel to tell affected users. They just
see broken behaviour and leave. We also have no clean way to say
"fixed" once the issue is resolved.
We need a lightweight in-app banner that admins can publish, append
follow-ups to, and clear — without standing up a backend.
Proposal
A file-driven banner, served by Cloudflare Pages as a static asset and
fetched by the PWA at load time and on a short polling interval.
Data shape
A single JSON file, e.g.
static/emergency.json:{ "active": true, "severity": "info" | "warning" | "critical", "title": "Live vehicle positions are stale in Cluj-Napoca", "body": "We are investigating. Last update ~30 min ago.", "postedAt": "2026-07-06T18:00:00Z", "updatedAt": "2026-07-06T18:00:00Z", "followUps": [ { "at": "2026-07-06T18:45:00Z", "body": "Root cause identified — GTFS-RT producer restart in progress." } ] }When
activeisfalse, or the file is absent, the PWA shows no banner.PWA side
emergency.jsonon app load and every 60s while the app isopen (cache-busted with
?v=<updatedAt>or similar).active: true, render a banner above the main view:info→ neutral backgroundwarning→ amber backgroundcritical→ red background, dismissable in-session onlyfollowUpsas a collapsible thread under the main body sousers see progression (issue → updates → resolved), newest first.
Admin side — three operations, one file
The whole publisher is the JSON file plus (optionally) one workflow
file. No new service, no new secrets.
active: true, commit tomain.followUps, bumpupdatedAt.active: false(or delete the file), commit.The simplest path is edit
static/emergency.jsonin the GitHub webUI and commit — Cloudflare Pages auto-deploys on push to
main.The polished path is a
.github/workflows/emergency-message.ymlworkflow with
workflow_dispatchinputs (action,severity,title,body,followUp) that rewrites the JSON and commits it. Same endstate, but no hand-editing of JSON, and it works from the GitHub
mobile app.
Ship the file + PWA read path first, layer the workflow on top once we
are happy with the data shape.
Acceptance criteria
static/emergency.jsonexists with the shape aboveactive: true, hidden foractive: falseormissing file
followUpsrendered as a collapsible list under the main body,newest first
critical(resets on reload)emergency-message.ymlsupports publish /follow-up / remove via
workflow_dispatchto the workflow)
docs/operations.md(or equivalent) with the threeoperations and an example payload
Out of scope (v1)
expiresAtis a nice-to-have, not v1)