ChicoryTV SPA: Settings screen (prototype → implement) #93

Closed
opened 2026-07-02 01:08:43 +02:00 by timothy · 3 comments
Owner

The Settings screen is not yet designed. It will be the first screen to exercise the new workflow: prototype it in Claude Design, pull via /design-sync (#92), then implement in the SPA — no zip.

Scope TBD (likely: general/server settings, streaming/FFmpeg defaults, media sources, playout/scheduling defaults, XMLTV/M3U output, appearance/theme, auth/API keys). Define during prototyping.

Acceptance: Settings screen prototyped in Claude Design and implemented in the SPA via the design-sync workflow.

The Settings screen is **not yet designed**. It will be the first screen to exercise the new workflow: prototype it in Claude Design, pull via `/design-sync` (#92), then implement in the SPA — no zip. Scope TBD (likely: general/server settings, streaming/FFmpeg defaults, media sources, playout/scheduling defaults, XMLTV/M3U output, appearance/theme, auth/API keys). Define during prototyping. **Acceptance:** Settings screen prototyped in Claude Design and implemented in the SPA via the design-sync workflow.
timothy added the frontend label 2026-07-02 01:08:43 +02:00
timothy added a new dependency 2026-07-02 01:08:43 +02:00
timothy added a new dependency 2026-07-02 01:08:43 +02:00
Author
Owner

Scope (signed off with Timothy, 2026-07-06)

API inventory finding: there is currently no settings REST API — all 7 legacy Blazor settings pages (FFmpeg, HDHR, Playout, XMLTV, Scanner, Logging, UI) call MediatR in-process. Only FFmpeg profiles have full CRUD (/api/ffmpeg/profiles). Watermarks/fillers/resolutions/media-sources are GET-only.

Agreed scope for #93:

  1. Backend: thin /api/settings/* controllers wrapping the existing Get*/Update* MediatR handlers (pattern: FFmpegProfileController) for all 7 groups:
    • GET/PUT /api/settings/ffmpeg (paths, default profile, subtitle/interlace flags, global watermark/fallback filler, HLS segmenter tuning, HLS-direct output format, MPEG-TS script)
    • GET/PUT /api/settings/hdhr (tuner count; UUID read-only)
    • GET/PUT /api/settings/playout (days to build, skip missing, scripted timeout)
    • GET/PUT /api/settings/xmltv (days, time zone, block behavior)
    • GET/PUT /api/settings/scanner (library refresh interval)
    • GET/PUT /api/settings/logging (6 Serilog min levels)
    • GET/PUT /api/settings/ui (theme, language — legacy Blazor UI prefs)
    • Custom resolutions add/delete if the FFmpeg section needs it (else read-only + follow-up)
  2. Frontend: Settings screen with left sub-navigation (General, Streaming, Playout, Guide/XMLTV, Scanner, Logging, System) in the ChicoryTV admin shell. FFmpeg profiles appear as list + default-profile picker only — a full profile editor is a follow-up issue. Read-only panels (media sources, system info/health/version) with "managed in legacy UI" callouts where the API can't write.
  3. Out of scope: API-key management (no endpoint exists), watermark/filler/media-source CRUD, full FFmpeg profile editor.

Workflow per the issue: prototype in Claude Design → /design-sync pull (#92) → implement in web/ on branch feat/93-settings.

## Scope (signed off with Timothy, 2026-07-06) **API inventory finding:** there is currently **no settings REST API** — all 7 legacy Blazor settings pages (FFmpeg, HDHR, Playout, XMLTV, Scanner, Logging, UI) call MediatR in-process. Only FFmpeg *profiles* have full CRUD (`/api/ffmpeg/profiles`). Watermarks/fillers/resolutions/media-sources are GET-only. **Agreed scope for #93:** 1. **Backend**: thin `/api/settings/*` controllers wrapping the existing `Get*`/`Update*` MediatR handlers (pattern: `FFmpegProfileController`) for all 7 groups: - `GET/PUT /api/settings/ffmpeg` (paths, default profile, subtitle/interlace flags, global watermark/fallback filler, HLS segmenter tuning, HLS-direct output format, MPEG-TS script) - `GET/PUT /api/settings/hdhr` (tuner count; UUID read-only) - `GET/PUT /api/settings/playout` (days to build, skip missing, scripted timeout) - `GET/PUT /api/settings/xmltv` (days, time zone, block behavior) - `GET/PUT /api/settings/scanner` (library refresh interval) - `GET/PUT /api/settings/logging` (6 Serilog min levels) - `GET/PUT /api/settings/ui` (theme, language — legacy Blazor UI prefs) - Custom resolutions add/delete if the FFmpeg section needs it (else read-only + follow-up) 2. **Frontend**: Settings screen with **left sub-navigation** (General, Streaming, Playout, Guide/XMLTV, Scanner, Logging, System) in the ChicoryTV admin shell. FFmpeg profiles appear as **list + default-profile picker only** — a full profile editor is a follow-up issue. Read-only panels (media sources, system info/health/version) with "managed in legacy UI" callouts where the API can't write. 3. **Out of scope**: API-key management (no endpoint exists), watermark/filler/media-source CRUD, full FFmpeg profile editor. Workflow per the issue: prototype in Claude Design → `/design-sync` pull (#92) → implement in `web/` on branch `feat/93-settings`.
Author
Owner

Implementation complete → PR #138.

Workflow as designed: prototyped Settings.jsx in the ChicoryTV admin template + design_handoff_settings/ spec bundle, synced to the Claude Design project via DesignSync (no zip), then implemented in the SPA from the handoff.

Notable along the way:

  • Live E2E on a fresh server caught GET /api/media-sources 500ing on any empty database (Dapper + SQLite COUNT(*)-as-BLOB inference with zero rows) — fixed with EF LINQ + regression test in the PR.
  • The same E2E caught the screen hanging on one failed reference call — reference data now loads via allSettled with per-resource failure notes.
  • A fresh critical advisory against Scriban < 7.0.0 (GHSA-5wr9-m6jw-xx44) broke ALL CI mid-session (NU1904 as error) — fixed separately in PR #137 (merged, main green).
  • Three-lens adversarial review + fork verification: 401 contract annotations, delete 404/422 split, exhaustive enum switches, silent-failure UX fixes, partial-save consistency.

Deviations (documented in the handoff/PR): MPEG-TS script / audio language / UI language are free-text (no enumeration endpoints — follow-up material); media-source rows omit the StatusDot (no status signal in the API); full FFmpeg profile editor stays a follow-up per agreed scope.

Implementation complete → PR #138. **Workflow as designed**: prototyped `Settings.jsx` in the ChicoryTV admin template + `design_handoff_settings/` spec bundle, synced to the Claude Design project via DesignSync (no zip), then implemented in the SPA from the handoff. **Notable along the way**: - Live E2E on a fresh server caught `GET /api/media-sources` 500ing on any empty database (Dapper + SQLite `COUNT(*)`-as-BLOB inference with zero rows) — fixed with EF LINQ + regression test in the PR. - The same E2E caught the screen hanging on one failed reference call — reference data now loads via `allSettled` with per-resource failure notes. - A fresh critical advisory against Scriban < 7.0.0 (GHSA-5wr9-m6jw-xx44) broke ALL CI mid-session (NU1904 as error) — fixed separately in PR #137 (merged, main green). - Three-lens adversarial review + fork verification: 401 contract annotations, delete 404/422 split, exhaustive enum switches, silent-failure UX fixes, partial-save consistency. **Deviations (documented in the handoff/PR)**: MPEG-TS script / audio language / UI language are free-text (no enumeration endpoints — follow-up material); media-source rows omit the StatusDot (no status signal in the API); full FFmpeg profile editor stays a follow-up per agreed scope.
Author
Owner

Closing — merged in PR #138 (main 17f49304)

What was done: Settings screen prototyped in Claude Design (synced via DesignSync, design_handoff_settings/ bundle in-repo) and implemented in the SPA per the agreed scope (comment above): backend GET/PUT /api/settings/* for all 7 groups + custom-resolutions CRUD; frontend SettingsScreen with linkable sub-sections, floating save bar (changed-groups-only PUTs), graceful degradation, legacy-UI callouts.

Root cause (drive-by bug): GET /api/media-sources 500'd on every fresh database — Dapper infers SQLite COUNT(*) as BLOB when the result set is empty, producing an incompatible deserializer. Fixed with EF LINQ + empty-DB regression test.

Files: ErsatzTV/Controllers/Api/{SettingsController,ResolutionController}.cs, ErsatzTV.Core/Api/Settings/*, request DTOs, ErsatzTV.Application/MediaSources + Resolutions handlers, web/src/screens/SettingsScreen.tsx, web/src/api/settings.ts, tests both sides (ErsatzTV.Tests 495, web 145), design-system/ prototype + handoff.

Deferred / follow-up material (not filed as issues yet): full FFmpeg profile editor screen; enumeration endpoints for MPEG-TS scripts / language codes / UI cultures (fields are free-text meanwhile); media-source status signal in the API (StatusDot omitted); watermark/filler/media-source CRUD endpoints.

Docs updated: docs/handoffs/chicorytv-issue-queue.md (next: #90 rebrand). Related: PR #137 (Scriban GHSA fix) merged during this session to unblock CI.

## Closing — merged in PR #138 (main 17f49304) **What was done**: Settings screen prototyped in Claude Design (synced via DesignSync, `design_handoff_settings/` bundle in-repo) and implemented in the SPA per the agreed scope (comment above): backend `GET/PUT /api/settings/*` for all 7 groups + custom-resolutions CRUD; frontend `SettingsScreen` with linkable sub-sections, floating save bar (changed-groups-only PUTs), graceful degradation, legacy-UI callouts. **Root cause (drive-by bug)**: `GET /api/media-sources` 500'd on every fresh database — Dapper infers SQLite `COUNT(*)` as BLOB when the result set is empty, producing an incompatible deserializer. Fixed with EF LINQ + empty-DB regression test. **Files**: `ErsatzTV/Controllers/Api/{SettingsController,ResolutionController}.cs`, `ErsatzTV.Core/Api/Settings/*`, request DTOs, `ErsatzTV.Application/MediaSources` + `Resolutions` handlers, `web/src/screens/SettingsScreen.tsx`, `web/src/api/settings.ts`, tests both sides (ErsatzTV.Tests 495, web 145), `design-system/` prototype + handoff. **Deferred / follow-up material** (not filed as issues yet): full FFmpeg profile editor screen; enumeration endpoints for MPEG-TS scripts / language codes / UI cultures (fields are free-text meanwhile); media-source status signal in the API (StatusDot omitted); watermark/filler/media-source CRUD endpoints. **Docs updated**: `docs/handoffs/chicorytv-issue-queue.md` (next: #90 rebrand). Related: PR #137 (Scriban GHSA fix) merged during this session to unblock CI.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: timothy/ersatztv#93