From b564545ff7fe7bc7ca82ada6fee1ef751afef9ac Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 7 Jul 2026 10:20:36 +0200 Subject: [PATCH] docs: advance ChicoryTV issue queue past #90 (PR #139, tagged v26.4.0); next prompt = #91 cutover Co-Authored-By: Claude Fable 5 --- docs/handoffs/chicorytv-issue-queue.md | 146 ++++++++++++++----------- 1 file changed, 81 insertions(+), 65 deletions(-) diff --git a/docs/handoffs/chicorytv-issue-queue.md b/docs/handoffs/chicorytv-issue-queue.md index 2f6a046d8..917b040cc 100644 --- a/docs/handoffs/chicorytv-issue-queue.md +++ b/docs/handoffs/chicorytv-issue-queue.md @@ -8,9 +8,10 @@ builds are limited to 2–3 concurrent, never wide fan-outs. Backend gaps all la 2026-07-04 (PRs #113–#119); merge pass PR #120; live-data screens: #109 Dashboard (PR #123), #84 Channels (PR #124), #86 Schedule editor (PR #125), #87 Playouts (PR #127), #88 Libraries (PR #128), #85 Guide/EPG (PR #129); #62 prerequisites: #65 (PR #130), #64 (PR #133), #63 -(PR #134) — epic #62 COMPLETE; #89 Channel Builder (PR #136); **#93 Settings (PR #138) — +(PR #134) — epic #62 COMPLETE; #89 Channel Builder (PR #136); #93 Settings (PR #138) — first screen through the full design-first workflow; #92 design-sync round-trip verified and -documented (`docs/design-sync.md`)**. +documented (`docs/design-sync.md`); **#90 rebrand (PR #139) — SPA fully presents as +ChicoryTV; v26.4.0 tagged at this merge (first app-change release → prod)**. **PROCESS (2026-07-06, binding — supersedes 07-05)**: Claude Code ONLY — Codex is retired (usage exhausted). Fable is the orchestrator in the main session and is EXPENSIVE — use it @@ -31,30 +32,27 @@ can't see (see Lessons: local-run recipe). **RELEASE CHECKPOINT (standing, added 2026-07-06)**: prod cutover to the fork is DONE — prod container `ersatztv` on bumblebee runs `192.168.1.95:3000/timothy/ersatztv:prod` (= v26.3.1, app-identical to upstream 26.3.0); `ersatztv-test` tracks `:latest` (main). -Prod only advances on `v*` tags. At every milestone merge, FLAG THE USER: is this slice -worth tagging **v26.4.0** (reserved for the first app-change release)? Latest sensible tag -point is #91 (cutover); earlier if a stable API slice should reach prod sooner. Tagging -needs explicit user consent; NEVER `[skip ci]` a commit you'll tag. (Flagged again at the -#93 merge, 2026-07-07 — builder + settings + full API is a very plausible v26.4.0 slice; -#90 rebrand would make it present as ChicoryTV.) +Prod only advances on `v*` tags. **v26.4.0 TAGGED 2026-07-07** on 65b1a5e3 (the #90 merge, +user-consented) — first app-change release; prod image = full API + all SPA screens + +ChicoryTV branding. At future milestone merges, flag the user for the NEXT tag +(v26.4.1/v26.5.0 — #91 cutover is the obvious next tag point). Tagging needs explicit user +consent; NEVER `[skip ci]` a commit you'll tag. -**Session state (2026-07-07, post-#93)**: main = 17f49304 (PR #138 merged): **Settings** is -live at `/app/settings/
` — backend `GET/PUT /api/settings/{ffmpeg,playout,xmltv, -scanner,logging,ui,hdhr}` + `/api/settings/resolutions` CRUD (`SettingsController`, DTOs in -`ErsatzTV.Core/Api/Settings`), frontend `web/src/screens/SettingsScreen.tsx` + -`web/src/api/settings.ts` (tiered loader: settings groups gate the screen, reference data -via allSettled with per-resource failure notes). App.tsx `ScreenRoute` gained an opt-in -`allowSubPaths` flag (settings only); the screen parses its own URL suffix. Design-first -workflow proven end-to-end: prototype `design-system/templates/chicorytv-admin/Settings.jsx` -+ handoff bundle `design-system/design_handoff_settings/` synced both directions with the -DesignSync MCP (main session only) — workflow documented in `docs/design-sync.md`, #92 -CLOSED. Also this session: **PR #137** — Scriban.Signed 6.5.2→7.2.5 (GHSA-5wr9-m6jw-xx44 -sandbox escape; the fresh advisory made NuGetAudit fail EVERY CI restore, merged first to -unblock); media-sources fresh-DB 500 fixed (Dapper→EF, see Lessons). Review: 3 lenses → -11 findings (2 backend contract clusters + frontend silent-failure/partial-save cluster), -fixed by 2 parallel subagents, fork-verified SHIP. Baselines: ErsatzTV.Tests **495**, -Core.Tests **493** (+1 skip), **web tests 145** (was 112). All #93 worktrees removed; -main checkout still sits on docs/59-ui-redesign-brief — do NOT touch it. +**Session state (2026-07-07, post-#90)**: main = **65b1a5e3** (PR #139 merged, **tagged +v26.4.0**). #90 rebrand landed: inventory showed most SPA naming was ALREADY ChicoryTV from +earlier screen work; the actual gaps were (a) NO favicon at all → `web/public/favicon.svg` +(byte-copy of `design-system/assets/chicorytv-icon.svg`; Vite rebases the absolute +`/favicon.svg` href to `/app/favicon.svg` at build — verified in built output, served by +Startup.cs static files), (b) no description/theme-color meta (theme-color = `#12100E` = +`--ctv-bg`, NOT the icon's `#171A21`), (c) sidebar used the dark-square `chicorytv-icon.svg` +→ switched to the canonical transparent `chicory-mark.svg` per the design-system lockup +(`brand-logo.card.html` / admin template Shell.jsx), (d) Channel Builder default group +`'ErsatzTV'`→`'ChicoryTV'` (+2 test assertions). Backend/Blazor strings untouched. Remaining +intentional "Ersatz" in web/: vite.config outDir path + one backend-file code comment +(App.tsx). Review: single fable fork (ship; it live-verified the favicon path by building). +Baselines unchanged: ErsatzTV.Tests **495**, Core.Tests **493** (+1 skip), **web tests 145**. +Worktree .worktrees/issue-90-rebrand now sits on main (used for the doc commit) — remove it +next session. Main checkout still sits on docs/59-ui-redesign-brief — do NOT touch it. **Lessons for all remaining prompts** (accumulated): - NEW (#93) — Local live-E2E recipe: `npm run build` (outputs to gitignored @@ -193,49 +191,63 @@ main checkout still sits on docs/59-ui-redesign-brief — do NOT touch it. --- -# PROMPT — #90: ChicoryTV rebrand (assets + naming) +# PROMPT — #91: Blazor → SPA cutover (retire old UI) You are Fable, the ORCHESTRATOR in the main Claude Code session (Codex is retired — Claude -Code only). Fable is EXPENSIVE: delegate implementation to fitting subagents (this issue is -mostly mechanical — haiku/sonnet territory; fable only for the review fork). Read CLAUDE.md -and the PROCESS + Lessons sections of this file first. +Code only). Fable is EXPENSIVE: delegate to fitting subagents (recon → Explore/haiku; +mechanical deletions → sonnet; routing/Startup surgery → opus; fable for the hardest design +calls + review forks). Read CLAUDE.md and the PROCESS + Lessons sections of this file first. HARD CONSTRAINTS: -- `git worktree add .worktrees/issue-90-rebrand -b feat/90-rebrand origin/main`; never touch - the main checkout (it sits on docs/59-ui-redesign-brief). `cd web && npm ci` first. -- Max 2–3 concurrent builds; ONE dotnet build at a time. Frontend-only expected — if backend - strings turn out to be in scope, they're NOT (deeper product rebrand is epic #59). -- NEVER set ETV_UPDATE_GOLDENS. -- Review before PR: this is a small mechanical issue — a single fable correctness/design fork - over the diff suffices (skip the 3-lens panel unless the diff grows); fixes via subagents. - Merge needs an in-conversation consent question. +- `git worktree add .worktrees/issue-91-cutover -b feat/91-cutover origin/main`; never touch + the main checkout (docs/59-ui-redesign-brief). Also REMOVE the stale merged worktree + .worktrees/issue-90-rebrand first (`git worktree remove`). `cd web && npm ci`. +- Max 2–3 concurrent builds; ONE dotnet build at a time. NEVER set ETV_UPDATE_GOLDENS. +- This issue is BIG (deleting the Blazor UI + MudBlazor + root-route change). STAGE IT: + recon may conclude it should split into 2 PRs — (a) root-route flip + legacy redirects, + (b) Blazor/MudBlazor removal. Prefer the split; land (a) first — it's small, reversible, + and immediately user-visible. +- Full review before each PR (3 lenses: fable correctness fork + contract/tests lens + + design/UX lens for the routing UX) — this is NOT a mechanical issue. Live-E2E per the + #93 recipe (build SPA → symlink wwwroot/app into bin → run fresh server) and manually hit + `/`, `/app/...`, a legacy Blazor route, `/iptv/*`, `/api/*`, swagger. Merge consent + in-conversation per PR. ## Task -Issue #90: apply the ChicoryTV rebrand across the SPA surface. Naming (ErsatzTV → ChicoryTV -in user-facing UI copy), favicon/app icon/wordmark from `design-system/assets/` -(chicory-mark.svg, chicorytv-icon.svg, chicorytv-wordmark.svg), page title/meta. -Acceptance: the SPA presents consistently as ChicoryTV. (Product-wide rebrand = epic #59.) +Issue #91: complete the Blazor→SPA transition. Make the SPA the default UI (root route); +redirect legacy Blazor page routes; remove Blazor pages/components + MudBlazor deps once +nothing user-facing depends on them; update CLAUDE.md/docs (infra → server-management). +Acceptance: no user-facing MudBlazor screens remain; ChicoryTV SPA is THE UI. ## Approach notes -1. Inventory first (delegate to Explore): every user-facing "ErsatzTV" in web/ (index.html - title/meta/favicon, shell header, empty states, aria-labels, App.test.tsx copy - assertions), what web/index.html currently ships as favicon, how the shell renders the - brand mark today (the admin template uses chicory-mark.svg + "ChicoryTV" - — mirror that), and whether vite needs assets in web/public/ vs imported. -2. Do NOT rename API strings, C# namespaces, Docker images, or docs — SPA surface only. - The legacy Blazor UI stays ErsatzTV. -3. Favicon: derive from chicorytv-icon.svg (SVG favicon is fine for modern browsers; add a - PNG fallback only if trivial). -4. Tests: update copy assertions; baseline 145 web tests must stay green (some assert brand - strings). dotnet suites should be untouched (frontend-only): ErsatzTV.Tests 495, - Core.Tests 493 (+1 skip). -5. PR → main: "feat(web): ChicoryTV rebrand (#90)", `closes #90`; poll CI by head SHA; ask - "merge?"; verify main post-merge run. -6. RELEASE CHECKPOINT: after #90 merges, the SPA is feature-complete-enough AND branded — - this is the strongest v26.4.0 tag point before #91. Ask the user explicitly whether to - tag v26.4.0 now (never `[skip ci]` the tagged commit). -7. Update THIS handoff: pop #90, next = #91 cutover; record PR + main SHA + baselines. - Commit to main. Print the next prompt in a fenced block. +1. RECON [Explore]: how Startup.cs/Program.cs wire Blazor (MapBlazorHub, fallback page, + `/app` static files + SPA fallback); every Blazor @page route and whether an SPA + equivalent exists (screens shipped: dashboard/channels/schedule/playouts/libraries/EPG/ + builder/settings); what NON-page infrastructure lives in ErsatzTV/ that must SURVIVE + (controllers, SignalR?, background services, OIDC/auth wiring); MudBlazor/BlazorSortable + package references; what `/iptv`, `/api`, swagger, and the v1.json generator depend on. + Decide: is anything still Blazor-ONLY (no SPA equivalent)? If yes → those routes keep a + legacy escape hatch (e.g. `/legacy/...`) or the gap gets filed as a blocking sub-issue. +2. Phase (a): root `/` serves/redirects to the SPA; legacy Blazor routes 301 to SPA + equivalents (map table from recon); keep Blazor reachable under a legacy prefix ONLY if + recon found Blazor-only functionality. Mind deep links + the SPA's own client routing. +3. Phase (b): delete Pages/Shared/component dirs, drop MudBlazor+BlazorSortable from + Directory.Packages.props + csproj, prune Startup DI, _Imports, CSS/static assets. + Expect dotnet test fallout in ErsatzTV.Tests (495 baseline) — anything referencing + Blazor bits. Goldens must NOT change. +4. Docs: CLAUDE.md says "Blazor Server UI (MudBlazor)" + "Keep Blazor pages thin" — update + architecture/conventions inline with the PR; docs/contributing.md Blazor sections too. + ~/homelab-docs/Docker/ErsatzTV.md mentions the UI → update after merge. +5. PRs → main: "feat(web): SPA cutover — root route (#91)" then "feat!: remove Blazor UI + (#91)" (closes #91 on the second). Poll CI by head SHA; consent per merge; verify main + post-merge runs. +6. RELEASE CHECKPOINT: v26.4.0 shipped at #90 (prod now runs the branded SPA at /app, root + still Blazor). After #91 lands, flag the user: tag v26.5.0 (next release-seq — the + breaking UI swap deserves its own release, not a patch). +7. Update THIS handoff: pop #91; next = post-cutover housekeeping (queue item 2). Record + PRs + main SHA + new baselines (ErsatzTV.Tests count will DROP with Blazor tests gone — + record the new number as baseline). Commit to main. Print the next prompt in a fenced + block. --- @@ -245,9 +257,13 @@ Acceptance: the SPA presents consistently as ChicoryTV. (Product-wide rebrand = Renovate/dep PRs (#21, #48, #49, #61, #131 security, #132) — cheap batch-merge pass when convenient (note: Scriban already bumped to 7.2.5 by PR #137). MCP PR #76 (#58) still needs its rebase/refresh pass — good parallel track. -1. #90 rebrand ← PROMPT above (small, mechanical; strongest v26.4.0 tag point at its merge). -2. #91 cutover (+ tag v26.4.0 at the latest here — see RELEASE CHECKPOINT). +1. #91 cutover ← PROMPT above (BIG; stage into root-flip PR + Blazor-removal PR; flag + v26.5.0 after it lands). +2. Post-cutover housekeeping: verify prod/test containers on the tagged image (v26.4.0 built + by run on 65b1a5e3 → `:prod`; watchtower or manual pull on bumblebee — infra side = + server-management); dep-PR batch pass; MCP PR #76 refresh; then triage epic #59 remainder + (backend rebrand scope, #66/#67 image pipeline, #68). Cross-refs: #66/#67 remain open image-pipeline nice-to-haves; #68 unblocked-independent. -Done recently: PR #136 (#89 Channel Builder), **PR #138 (#93 Settings — closed 2026-07-07, -main 17f49304; web tests 112 → 145, ErsatzTV.Tests 447 → 495), PR #137 (Scriban GHSA -CI-unblock), #92 design-sync round-trip closed (docs/design-sync.md)**. +Done recently: **PR #139 (#90 rebrand — closed 2026-07-07, main 65b1a5e3, TAGGED v26.4.0)**, +PR #138 (#93 Settings, first design-first screen), PR #137 (Scriban GHSA CI-unblock), +#92 design-sync closed (docs/design-sync.md), PR #136 (#89 Channel Builder).