Backstage, reviewedlive feeds · proper lifecycles · honest UI
The original /backstage
is a descriptive document — what the dashboard is supposed to do.
Three of its four named endpoints have been 403'd by the upstream
Metaculus API since 2026-05-13, so what the doc names mostly does
not run. What does run is the HTML dashboard itself — the
rendered page at /. It is embedded below as the primary
view. The lifecycle table and per-endpoint status are kept for
completeness, demoted to a footer.
The dashboard, embedded direct iframe · the upstream's own JS reaches its own API
The iframe below points at metaculus.raindesk.dev/
directly (not through the Caddy proxy on this origin). This is
intentional: the dashboard's own JS issues fetches to
/api/* relative to its origin; routing those through
the proxy here would point them at endpoints that don't exist. The
cost of direct embedding is the possibility of X-Frame-Options
refusal; if the iframe is empty for you, the upstream is refusing
to be embedded and a "open in new tab" fallback is shown.
Lifecycle vocabulary the framework for the status footer below
Per-endpoint status three of four feeds 403'd since 2026-05-13
Each feed below was named in /backstage as part of the
dashboard's architecture. The page probes them from your browser
and reports the truth. The three that have been failing for days are
failing because the upstream Metaculus API rejects the dashboard's
unauthenticated requests; that is not a problem in the proxy or the
page.
Architecture preserved from original /backstage
What "reviewed" means here
The original /backstage describes endpoints; this page
shows their behaviour. The difference matters because
endpoints lie about themselves. /api/questions on the
live dashboard returns 500 most of the day because its upstream
(metaculus.com API) frequently 403s — the original doc does not
acknowledge this. The reviewed page surfaces the failure state in the
UI with a specific error code and timestamp.
Each feed has four lifecycle states. The page favours showing stale over showing nothing, because the previous successful response is usually more useful than a spinner.
Defences in this page
- AbortController + setTimeout for fetch cancellation (no
AbortSignal.timeoutdependency). - Same-origin proxy via hub2 Caddy so we can read response bodies (not opaque). Path:
/upstream/*→metaculus.raindesk.dev/*. - Freshness window 60s — beyond that the feed flips to stale, never silently. Re-fetch is explicit.
- Auto-refresh every 90s on a single shared timer (no per-feed storms).
- Pause when tab hidden via
visibilitychange; resume on return. - Error preserves last-good — fetch failure does not wipe the previously shown body.
- JSON pretty-printed when content-type allows; text-stream feeds (
/text) shown verbatim.