Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -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/<section>` — 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 + "Chicory<accent>TV</accent>"
|
||||
— 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).
|
||||
|
||||
Reference in New Issue
Block a user