Build ErsatzTV Image / Docs update reminder (push) Has been skipped
Build ErsatzTV Image / decisions.md append-only (push) Has been skipped
Build ErsatzTV Image / API docs in sync (OpenAPI + endpoint index) (push) Has been skipped
Build ErsatzTV Image / Formatting (changed .cs conform to .editorconfig) (push) Has been skipped
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (push) Successful in 4m25s
Build ErsatzTV Image / Build & test (.NET) (push) Successful in 5m25s
Build ErsatzTV Image / Functional E2E (curl contracts) (push) Has been cancelled
Build ErsatzTV Image / Build & push image (amd64) (push) Has been cancelled
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>
136 lines
9.3 KiB
Markdown
136 lines
9.3 KiB
Markdown
# #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](https://gitea.tblindustries.be/timothy/ersatztv/issues/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
|
|
|
|
1. Go to `/app/libraries/jellyfin` (or `/app/libraries/emby`).
|
|
2. Click **Connect**, enter the homelab server's address + API key, submit.
|
|
3. Confirm the Connection card flips to the connected state and shows `hasApiKey: true` semantics
|
|
(i.e. the UI never echoes the raw key back — only an affordance to replace it).
|
|
4. Confirm the libraries list populates from the real server (sortable libraries editor) and that
|
|
toggling the **Sync** control (`shouldSyncItems`) on/off persists across reload.
|
|
5. Open the **path-replacements** editor for this source; add a replacement pair (remote path prefix →
|
|
local path prefix), save, reload, confirm it persisted.
|
|
6. Return to the `/app/libraries` hub, 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).
|
|
7. 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
|
|
|
|
- [x] Connected to the homelab Jellyfin server and confirmed the connected state and server address.
|
|
- [x] Confirmed the secure-key contract: `hasApiKey` help was visible, the replacement input was empty
|
|
and `type="password"`, and the raw API key was absent from the DOM and responses.
|
|
- [x] Toggled the Movies library off and back on. Both
|
|
`PUT /api/v1/media-sources/jellyfin/2/libraries` requests returned 200, and both states persisted
|
|
across reload. The original enabled state was restored.
|
|
- [x] Added `/etv-e2e-333/remote` → `/etv-e2e-333/local`; the path replacement persisted across
|
|
reload, then was removed and confirmed absent after another reload.
|
|
- [x] Launched Movies from the `/app/libraries` hub. `POST /api/v1/libraries/15/scan` returned 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.
|
|
- [x] 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](https://gitea.tblindustries.be/timothy/ersatztv/issues/344).
|
|
No unexpected page errors occurred; the only console error was the deliberately induced 422 request.
|
|
|
|
## 2. Plex interactive pin-flow auth
|
|
|
|
1. Go to `/app/libraries/plex`.
|
|
2. 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.
|
|
3. Complete the plex.tv-side authorization in the opened tab/window.
|
|
4. 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.
|
|
5. Confirm `GET /api/v1/media-sources/plex` now reports `isAuthorized: true` and lists the discovered
|
|
servers.
|
|
6. Pick a server, confirm its libraries populate, toggle sync on a library, save, reload, confirm
|
|
persistence.
|
|
7. 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
|
|
|
|
- [x] 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`.
|
|
- [x] 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: true` and `isLocked: 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.
|
|
- [x] Removed the temporary authorization through
|
|
`POST /api/v1/media-sources/plex/sign-out` (204). The API returned to `isAuthorized: 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](https://gitea.tblindustries.be/timothy/ersatztv/issues/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.
|
|
|
|
- [x] 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.
|
|
- [x] **Server discovery succeeded** (the 2026-07-13 gap): `GET /api/v1/media-sources/plex` reported
|
|
`isAuthorized: true`, `isLocked: false`, and `servers: [{ id: 3, name: "8d720a58d5d6",
|
|
address: "http://192.168.1.99:32400" }]`.
|
|
- [x] Libraries populated for the discovered server:
|
|
`GET /api/v1/media-sources/plex/3/libraries` returned the **Movies** library
|
|
(`id: 16`, `mediaKind: Movies`, initial `shouldSyncItems: false`).
|
|
- [x] 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.
|
|
- [x] 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/libraries` then 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 `hasApiKey` contract 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.
|