Redesign Media Centre as a teletext broadcast information service
Replaces the neutral dark card-based theme with "Page 100": teletext's
locked eight colours at full saturation on pure black, numbered pages
reachable by typing the number (or the r/g/y/c fastext keys), and no
borders, boxes, or radius anywhere — grouping is carried by full-bleed
colour fields and row weight instead.
Chosen via the impeccable skill's replacement-world flow: seven visual
candidates derived from the audience's own world, a mandatory roll
assigned Ceefax/US-cable-guide teletext, six catalog challengers weighed
against it, and the user locked the assigned direction on the decision
page (seed aab4510e).
- New templates for all nine pages (home/watch/library/discover/
requests/system/activity/login/settings) behind a shared _shell.html
carrying the direction contract and _macros.html for the row/bar/tile
vocabulary; deletes the old single-page dashboard.html and its
dedicated stylesheets/script.
- static/css/base.css + teletext.css: the locked palette, a two-height
type scale (Chivo Mono / DotGothic16), and the five disciplines the
system is held to (no in-between tone, no enclosure, one shared bar
ruler, trend only where real history exists, pages weighted by state).
- static/js/service.js: header clock, page-number jump, fastext keys,
two-tap arm/confirm add, guarded live polling — replaces dashboard.js.
- app.py: nav_items now carry page numbers; fastext defaults added to
the page-chrome context processor; version bumped to 2.0.0.
- DESIGN.md + .impeccable/design.json regenerated from the built world
by the documenter pass; PRODUCT.md and CLAUDE.md updated to describe
the new system in place of the retired one.
- Fixed a live bug found along the way: settings.html called
url_for('dashboard'), an endpoint removed earlier in the branch, which
would have 500'd the Settings page.
- Fixed a One-Ruler violation the finish review's recapture request
surfaced: --bar-cells disagreed with the bar() macro's hardcoded cell
count below the 760px breakpoint, so a fill could land mid-cell on a
phone. Removed the mobile override; the ruler is now 20 cells at every
width, matching the macro unconditionally.
Passed two inspection rounds (desktop + true-390px mobile, via an
iframe harness since macOS Chrome clamps --window-size) and a finish
review; QA screenshots and interview logs are gitignored as scratch,
not shipped in the repo.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NBw1QodG8ZMYHrGeQfqyDS
This commit is contained in:
parent
9a277b9031
commit
4b19cbdfb2
25 changed files with 3002 additions and 2343 deletions
134
PRODUCT.md
Normal file
134
PRODUCT.md
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# Product
|
||||
|
||||
<!-- impeccable:product-schema 1 -->
|
||||
|
||||
## Platform
|
||||
|
||||
web
|
||||
|
||||
## Users
|
||||
|
||||
Single primary user: the self-hoster who administers the Sonarr/Radarr/
|
||||
SABnzbd/Tautulli/Prowlarr/Ombi stack and the Unraid server it runs on. They
|
||||
are both the audience and the operator — checking on the stack is also how
|
||||
they'd notice something needs fixing. Multi-user login support
|
||||
(`manage_users.py`) exists for credential hygiene / future-proofing, not
|
||||
because other people actively use the dashboard day to day.
|
||||
|
||||
Used mostly on a desktop/tablet-class screen at home, not primarily on a
|
||||
phone over cellular — though the 5-second parallel-fetch deadline and
|
||||
per-service error degradation mean it still has to stay usable and fast on
|
||||
a phone away from home when needed.
|
||||
|
||||
## Product Purpose
|
||||
|
||||
A single glanceable page (well, now a small set of focused pages) that
|
||||
answers "is my media stack healthy and what's new" without opening six
|
||||
different service UIs. It exists because Sonarr/Radarr/SABnzbd/Tautulli/
|
||||
Prowlarr/Ombi each have their own web UI with their own login, and none of
|
||||
them show "what's playing right now + what just finished downloading + is
|
||||
the array full" in one glance.
|
||||
|
||||
Success is a page that loads fast (parallel fetch, 5s wall-clock cap),
|
||||
degrades gracefully per-card when a service is offline rather than failing
|
||||
the whole page, and surfaces the handful of numbers that actually change
|
||||
day to day (active streams, queue, disk usage, new library adds, what's
|
||||
popular that isn't owned yet).
|
||||
|
||||
## Positioning
|
||||
|
||||
Not a general-purpose *arr dashboard project (like Organizr or Homarr) —
|
||||
this is a bespoke, single-tenant tool built around exactly this user's
|
||||
stack, their Unraid box, and their own judgment calls about what's worth
|
||||
surfacing (e.g. Rotten Tomatoes "popular but not owned yet" filtered
|
||||
against the actual library, not just a generic trending feed). It trades
|
||||
general configurability for being exactly right for one specific setup.
|
||||
|
||||
## Operating Context
|
||||
|
||||
Runs as a single Docker container (`arr-summary`) on the user's Unraid
|
||||
home server, deployed via Forgejo push-to-deploy. Fronted by Nginx Proxy
|
||||
Manager over HTTPS (DNS-01/Porkbun certs — port 80 is blocked by the ISP,
|
||||
so this is not optional). Session-based login (single shared password or
|
||||
per-user accounts) gates the whole app; there's no public/unauthenticated
|
||||
view.
|
||||
|
||||
**In-progress restructure (branch `meridian-marquee`):** the app is
|
||||
splitting from one long single-page dashboard into focused pages — Home
|
||||
("marquee": what's playing, one line of system state, what's new),
|
||||
Watch, Library, Discover, Requests, System, Activity — each answering one
|
||||
question well rather than one long scroll trying to show everything.
|
||||
This also resolves cases where a content-heavy section (e.g. the per-disk
|
||||
storage list) would otherwise force awkward row heights on a shared
|
||||
"Right now" strip. `_shell.html` and `_macros.html` are new shared-layout
|
||||
scaffolding for this split; `dashboard.html` is the outgoing single-page
|
||||
template being superseded by `home.html` + the per-page templates.
|
||||
|
||||
Each page fetches only the services it needs (e.g. `/watch` fetches only
|
||||
Tautulli) rather than the old single route's all-services-at-once fetch —
|
||||
narrower per-page payloads, same parallel-fetch/caching discipline
|
||||
described in CLAUDE.md.
|
||||
|
||||
## Capabilities and Constraints
|
||||
|
||||
- Aggregates: Sonarr, Radarr, SABnzbd, Tautulli, Prowlarr, Ombi, Unraid
|
||||
array stats, and scraped Rotten Tomatoes/IMDB "popular, not yet owned"
|
||||
data.
|
||||
- Per-service REST clients with independent, tuned cache TTLs; active
|
||||
streams and the SABnzbd queue are always live, never cached.
|
||||
- Every dev-machine service call fails by design (dev laptop isn't on the
|
||||
home network) — per-card error states are the expected local baseline,
|
||||
not a bug.
|
||||
- Can add missing titles directly to Radarr/Sonarr from the Discover
|
||||
flow (`/add-to-radarr`, `/add-to-sonarr`, lookup endpoints).
|
||||
- RT/IMDB data comes from HTML scraping, not an official API — brittle
|
||||
to upstream markup changes by nature; this is a known, accepted
|
||||
tradeoff, not a defect to "fix" by finding an API.
|
||||
- Reverse-proxy-subpath capable (`SCRIPT_NAME`) though currently deployed
|
||||
at domain root.
|
||||
|
||||
## Brand Commitments
|
||||
|
||||
Branded **"Media Centre"**. One committed visual identity, never a
|
||||
themeable shell — that has held across two redesigns and the five
|
||||
original novelty themes before them.
|
||||
|
||||
As of the 2026-08-29 redesign (v2.0.0) that identity is a **broadcast
|
||||
information service** in the teletext tradition. The visual system is
|
||||
DESIGN.md's business, not this file's; what belongs here is that pages
|
||||
are now numbered and reachable by typing their number, which makes the
|
||||
page-number model part of how the product is *navigated*, not merely how
|
||||
it looks — and that the earlier neutral card-based dark theme was
|
||||
deliberately replaced rather than refined.
|
||||
|
||||
Server-side project directory is `greendale`; container/repo are
|
||||
`arr-summary` — internal naming detail, not user-facing.
|
||||
|
||||
## Evidence on Hand
|
||||
|
||||
No real service data is reachable from the dev environment (see
|
||||
Operating Context / CLAUDE.md's "expect every service to be offline on
|
||||
the dev machine" note) — every card's real, non-error rendering must be
|
||||
checked either on the deployed Unraid box or by monkey-patching a
|
||||
fetcher locally per the CLAUDE.md recipe. Do not fabricate sample
|
||||
Sonarr/Radarr/Tautulli/etc. data as if it were representative; use
|
||||
realistic-shaped placeholders only when a card must be visually
|
||||
evaluated offline, and say so.
|
||||
|
||||
## Product Principles
|
||||
|
||||
1. **Never let one slow/offline service take down the page.** Parallel
|
||||
fetch with a hard deadline and per-card `service_error()` degradation
|
||||
is non-negotiable — a single point of failure defeats the purpose.
|
||||
2. **Show what changes, cache what doesn't.** Cache TTLs are tuned per
|
||||
service to how often that data actually moves; live-only data (active
|
||||
streams, download queue) stays live.
|
||||
3. **One focused question per page, not one page trying to answer all
|
||||
of them.** The meridian-marquee split exists to keep each page's
|
||||
"quietest state" reasonable, not to add navigation for its own sake.
|
||||
4. **Built for this one stack, not a general product.** Configurability
|
||||
that would matter for other people's setups is explicitly out of
|
||||
scope.
|
||||
5. **A committed visual identity, not a themeable shell.** "Media
|
||||
Centre"'s dark theme is the one look; don't reintroduce per-user or
|
||||
per-page theme switching.
|
||||
Loading…
Add table
Add a link
Reference in a new issue