Completes the outstanding Plex flow in the #202 post-merge integration checklist against a disposable test Plex Media Server: pin-flow auth, server/library discovery (the 2026-07-13 gap that returned servers:[]), sync-preference persistence, and sign-out cleanup all passed. Records exact API state evidence and the test-admin credential reset. fixes #333 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
9.3 KiB
#202 post-merge manual integration validation — real-server flows
Issue #202's media-source management implementation shipped in PR #262 and the issue is closed. This checklist tracks outstanding post-merge integration validation, not unfinished #202 implementation; completion is tracked by follow-up issue #333.
The original live local E2E run (branch feat/202-media-sources, worktree
/Users/timothy/etv-worktrees/202-int) automated everything that a disposable local instance could
exercise (local library CRUD, scan, move-path, delete, dirty-guard, apiKey contract, remote-screen
render). The two flows below genuinely need a live Jellyfin/Emby server and a live Plex account.
Results from the homelab runs are recorded under each flow. Both flows are now complete. Jellyfin
validation finished on 2026-07-13. The Plex flow finished on 2026-07-16 against a disposable test Plex
Media Server: authorization, server/library discovery, sync-preference persistence, and sign-out
cleanup all passed. #333 is satisfied.
1. Jellyfin/Emby real-server connect
- Go to
/app/libraries/jellyfin(or/app/libraries/emby). - Click Connect, enter the homelab server's address + API key, submit.
- Confirm the Connection card flips to the connected state and shows
hasApiKey: truesemantics (i.e. the UI never echoes the raw key back — only an affordance to replace it). - Confirm the libraries list populates from the real server (sortable libraries editor) and that
toggling the Sync control (
shouldSyncItems) on/off persists across reload. - Open the path-replacements editor for this source; add a replacement pair (remote path prefix → local path prefix), save, reload, confirm it persisted.
- Return to the
/app/librarieshub, trigger a scan for one Jellyfin/Emby library there, and confirm item counts update in the SPA (this is the equivalent of the local-library scan flow, but through the real sync pipeline instead of the local FS scanner). - Re-enter a wrong API key and confirm the UI surfaces a clear connection-failure state rather than a silent success or an unhandled 500.
Result — 2026-07-13: passed
- Connected to the homelab Jellyfin server and confirmed the connected state and server address.
- Confirmed the secure-key contract:
hasApiKeyhelp was visible, the replacement input was empty andtype="password", and the raw API key was absent from the DOM and responses. - Toggled the Movies library off and back on. Both
PUT /api/v1/media-sources/jellyfin/2/librariesrequests returned 200, and both states persisted across reload. The original enabled state was restored. - Added
/etv-e2e-333/remote→/etv-e2e-333/local; the path replacement persisted across reload, then was removed and confirmed absent after another reload. - Launched Movies from the
/app/librarieshub.POST /api/v1/libraries/15/scanreturned 202, the SPA showed Scanning, and Last scan advanced from 20:28 to 20:29. The rendered item count remained 254 because the server contents did not change during the scan. - Submitted a deliberately wrong key. The connection request returned 422 Problem Details with
Response status code does not indicate success: 401 (Unauthorized).; the SPA showed that message and stayed on the editor. The original key was then restored with a 200 response and the source returned to its connected state.
The successful connection save also exposed a stale dirty-guard prompt during navigation. That failure is captured separately in #344. No unexpected page errors occurred; the only console error was the deliberately induced 422 request.
2. Plex interactive pin-flow auth
- Go to
/app/libraries/plex. - Click Sign in to Plex — confirm it opens the plex.tv auth flow in a new tab and shows the waiting-for-authorization, then finalizing/server-discovery states in the SPA while polling.
- Complete the plex.tv-side authorization in the opened tab/window.
- Confirm the SPA poll picks up the authorized state within a reasonable time (no manual refresh needed) and transitions out of "finalizing" into the signed-in state.
- Confirm
GET /api/v1/media-sources/plexnow reportsisAuthorized: trueand lists the discovered servers. - Pick a server, confirm its libraries populate, toggle sync on a library, save, reload, confirm persistence.
- Sign out / de-authorize and confirm the SPA correctly returns to the "Not signed in" state without leaving stale server/library data visible.
Result — 2026-07-13: partial; Plex server prerequisite remains
- Started a real plex.tv pin flow. The SPA opened the HTTPS authorization URL in a new tab and
displayed the waiting state while polling
GET /api/v1/media-sources/plex. - Completed authorization. Without a manual refresh, the SPA transitioned from Waiting for you
to authorize at 20:35:13 UTC to a terminal state at 20:35:55 UTC. The API then reported
isAuthorized: trueandisLocked: false. - Server discovery returned
servers: []. The bounded server log recorded successful Plex authentication and no discovery exception, but this test account/deployment exposed no eligible Plex server. Repeat with an owned, reachable Plex Media Server attached to the test account. - With no discovered server, the library list, sync-preference toggle, and persistence checks could not be exercised.
- Removed the temporary authorization through
POST /api/v1/media-sources/plex/sign-out(204). The API returned toisAuthorized: false,isLocked: false,servers: [], and the SPA showed Not signed in with no stale server rows.
The authorized/unlocked/zero-server state exposed a separate SPA defect: the pin status said Connected to Plex, the Connection card said Not signed in, and the UI offered another sign-in but no sign-out action. Cleanup therefore required the API. The exact request/state evidence and root-cause analysis are captured in #345.
Result — 2026-07-16: completed against a live Plex server
The Plex-server prerequisite from the 2026-07-13 run was resolved: a disposable test Plex Media
Server (plex container in the media-servers stack, reachable from ErsatzTV at http://plex:32400
and on the LAN at http://192.168.1.99:32400, claimed to the account and seeded with a Movies
library) was stood up specifically for this validation (#333 comment). Run against ersatztv-test
(:latest, host port 8410); API state verified out-of-band with the machine key against the
in-container port 8409.
- Real plex.tv pin flow completed. Server log recorded
Successfully authenticated with plex(21:33:27) with no discovery exception, and the SPA transitioned to the signed-in state without a manual refresh. - Server discovery succeeded (the 2026-07-13 gap):
GET /api/v1/media-sources/plexreportedisAuthorized: true,isLocked: false, andservers: [{ id: 3, name: "8d720a58d5d6", address: "http://192.168.1.99:32400" }]. - Libraries populated for the discovered server:
GET /api/v1/media-sources/plex/3/librariesreturned the Movies library (id: 16,mediaKind: Movies, initialshouldSyncItems: false). - Sync-preference persistence: toggled Sync on for Movies and saved in the SPA; the API then
reported
shouldSyncItems: true, and the value survived a full SPA reload. - Sign-out cleanup: signed out from the SPA (the Sign out affordance was present in the
with-server state, unlike the zero-server case in #345). The API returned to
isAuthorized: false,isLocked: false,servers: [];GET /api/v1/media-sources/plex/3/librariesthen returned 404 (no stale server/library data); the SPA showed Not signed in with no stale rows.
No unexpected page errors. This completes the outstanding Plex steps and the #202 real-server integration validation. Note: #345 (authorized/zero-server SPA state) was not re-exercised here — this run always had a discovered server — so that specific edge case remains as filed.
Test-environment note: the ersatztv-test local-admin credential (set by an earlier session and
unrecorded) was reset to admin / the homelab default for this run by clearing the three
auth.local_admin.* / auth.security_stamp ConfigElement rows and re-running first-run setup. The
disposable plex container should be removed from the media-servers stack now that this flow is
validated (server-management-owned compose change).
Notes for whoever runs this
- Use a throwaway/test Jellyfin or Emby API key if possible — the SPA's
hasApiKeycontract means the UI never displays the key back, so you won't be able to visually re-confirm which key is active beyond "a key is set." - The Plex pin-flow is time-limited (plex.tv auth PINs expire) — don't leave the tab idle mid-flow.
- A Plex account authorization alone is insufficient for the remaining validation. The account must expose at least one owned, reachable Plex Media Server so its libraries can be discovered and edited.
- If either flow 500s or the SPA console shows errors, capture the exact request/response (Network tab) and file a separate bug linked from #333.