Files
manage/openspec/changes/service-registry/apply-progress.md
Developer cbb703341e feat(services): select Jellyfin via jellyfin_service_id on the frontend
Slice 4b frontend half. Jellyfin-touching pages now select a Jellyfin service
instance instead of a machine.

- api/client.ts: Jellyfin-backed calls (counts/libraries/activity/users, media
  status/build/stop/force-stop, queryMedia) send jellyfin_service_id.
- hooks/useDashboard, useUsers, useMedia: selector param renamed to
  jellyfinServiceId.
- pages/Media + Applications: list jellyfin service instances and persist
  jellyfin_service_id in the URL.
- Dashboard (widgets) and Users (default instance) need no selector change.
- Update Applications + Media tests for the new hook/param.

Files/SSH transport keeps machine_id. Verification: frontend lint 0 errors,
build success, 70 tests; backend ruff clean, 222 tests.
2026-06-23 12:10:27 +00:00

120 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Apply Progress: Runtime Service Registry
**Change:** `service-registry`
**Apply run:** PRs #7#10 (Slices 14a)
**Date:** 2026-06-19
## Slices 13 (MERGED)
- Slice 1 (#7): backend service foundation — encryption, integrations registry,
services + service_task_runs tables, `/api/services*` CRUD.
- Slice 2 (#8): backend widget rebind — service_id + widget_kind, ServiceRecord
adapters, built-ins, SSH run logging, retired old widget registry.
- Slice 3 (#9): frontend services runtime — types/API/hooks, frontend registry,
ServicePage, route swap, reconciled widget components + config dialog.
## Slice 4a — Cleanup + services admin UI + docs (this PR)
### Completed tasks
- [x] Removed addon pages (`/addons/:addonId`, `AddonPage.tsx`, `addons/*`) —
superseded by service pages.
- [x] Removed `grafana_url` / `prometheus_url` from `config.py`, both compose
files, `.env.example`, and README. (Frontend `VITE_GRAFANA_URL` /
`VITE_PROMETHEUS_URL` deep-link vars retained.)
- [x] Added a **Services page** (`/services`) with create/list/delete and a nav
entry, so service pages are reachable and services are configurable in the
tool itself.
- [x] Registered `/services` route in both route trees + sidebar nav.
- [x] Updated `docs/REQUIREMENTS.md` (service registry section) and added
`CHANGELOG.md` with the breaking-upgrade note.
### Decision resolved mid-slice
"Full machine migration" was scoped into **4a (cleanup) + 4b (Jellyfin/Jellyseerr
migration)** because removing machine-level Jellyfin/Jellyseerr fields is deeply
coupled to the Media/Users/Files pages (load-bearing) and there is no
`jellyseerr` service definition yet. 4a ships the safe cleanup + the services
admin UI; 4b does the machine-app-field migration as its own reviewable change.
### Files changed (Slice 4a)
- Backend: `config.py` (removed grafana_url/prometheus_url).
- Compose/env/docs: `docker-compose.yml`, `docker-compose.dev.yml`,
`.env.example`, `README.md`, `docs/REQUIREMENTS.md`, `CHANGELOG.md` (new).
- Frontend: new `pages/ServicesPage.tsx`; `App.tsx` (routes + nav); removed
`pages/AddonPage.tsx`, `addons/*`.
### Verification (Slice 4a)
```bash
cd backend
.venv/bin/ruff check . # clean
PYTHONPATH=src .venv/bin/python -m pytest # 222 passed
cd ../frontend
npm run lint # 0 errors
npm run build # success
npm run test # 70 passed
```
## Slice 4b — Jellyfin/Jellyseerr → services migration (in progress)
### Completed (backend, this PR)
- [x] Added `jellyseerr` service definition (`integrations/jellyseerr.py`) and
registered it (6 service types total).
- [x] Added `user_id` to the Jellyfin service config.
- [x] `dependencies.py`: new `_request_jellyfin_service_id` + `_service_record`
(decrypt-on-read). Rewrote `get_jellyfin_client`, `get_jellyseerr_client`,
and `get_user_id` to resolve against the service registry via the
`jellyfin_service_id` query param (first enabled instance as fallback).
- [x] SSH/Files transport (`get_ssh_client`) unchanged — still uses
`machine_id`.
- [x] Updated service-registry tests for 6 types.
### Selection model (decided)
Split query params: `?jellyfin_service_id=` selects the Jellyfin/Jellyseerr
instance; `?machine_id=` selects SSH/Files transport. Pages that need both pass
both.
### Remaining (frontend, next PR)
- Thread `jellyfinServiceId` through Media / Applications / Dashboard / Users:
list `jellyfin` service instances instead of `useMonitoringSettings()`
Jellyfin machines; pass `jellyfin_service_id` to Jellyfin API calls.
- Files page keeps `machine_id`.
- Settings UI: remove machine-level Jellyfin/Jellyseerr fields.
- Remove machine app fields from `settings_store.py` + `routers/settings.py`
once the UI no longer writes them.
### Frontend half (this PR)
- [x] `api/client.ts`: Jellyfin-backed calls (`fetchCounts`, `fetchLibraries`,
`fetchActivity`, `fetchUsers`, Media status/build/stop/force-stop, and
`queryMedia`) now send `jellyfin_service_id` instead of `machine_id`.
- [x] `hooks/useDashboard.ts`, `hooks/useUsers.ts`, `hooks/useMedia.ts`: renamed
the selector param to `jellyfinServiceId`.
- [x] `pages/Media.tsx` + `pages/Applications.tsx`: select a `jellyfin` service
instance via `useServiceInstances("jellyfin")` and persist
`jellyfin_service_id` in the URL.
- [x] Dashboard (widget-based) and Users (default-instance) need no selector
change.
- [x] Updated Applications + Media tests for the new hook/param.
### Deferred (explicit follow-up)
- Remove machine-level Jellyfin/Jellyseerr fields from `settings_store.py`,
`routers/settings.py`, and the Settings UI. Low urgency now that the runtime
reads from services; the machine fields are simply unused for Jellyfin.
### Verification (backend half)
```bash
cd backend
.venv/bin/ruff check . # clean
PYTHONPATH=src .venv/bin/python -m pytest # 222 passed
cd ../frontend
npm run lint && npm run build && npm run test # green (unchanged)
```