Admin TV share links
Kiosk wall = Grafana omi-tv (same board as /dashboard), opened via a
secret URL. No custom metrics board.
| Surface | Auth | Role |
|---|---|---|
/dashboard |
Firebase admin | Grafana embed (edit chrome) |
/dashboard/tv-links |
Firebase admin | Create / list / copy / revoke |
/tv/view/<token> |
Capability token | Kiosk Grafana (&kiosk) |
GET/POST /api/omi/tv-links |
Firebase admin | Manage |
DELETE /api/omi/tv-links/[id] |
Firebase admin | Revoke (await props.params) |
POST /api/grafana/tv-embed |
Capability token | Mint kiosk embed for a validated link |
Optional query on the kiosk URL: ?tv=0.55 (Fire TV scale). While the
legacy board is still framed, &platform=macos|mobile selects that legacy
platform board; the private v2 embed is the single combined canonical board
and ignores platform.
Firestore admin_tv_links; doc id = sha256 hex; store tokenHash + token.
Default TTL 90d. TV tokens unlock the kiosk page only. While the private
Grafana cutover flag is off and the legacy board still serves anonymous
readers, the kiosk keeps framing legacy /grafana/d/omi-tv. Once the cutover
is enabled — or legacy goes private for any reason — the kiosk mints a
short-lived Business embed through POST /api/grafana/tv-embed (token
re-validated server-side, identity namespaced per link) and never frames
Grafana's login page; revocation/expiry of the link stops new embeds.
AuthProvider must skip admin check/sign-out/redirect on /tv/view/*.
Local: NEXT_PUBLIC_DEV_BYPASS_AUTH=1 npm run dev. Kiosk without Firestore:
/tv/view/dev-kiosk. Mint/revoke still needs FIREBASE_* Admin SDK env.