Files
Developer ca8927834e chore(openspec): archive completed changes
Move finished change directories to openspec/changes/archive/:
- configurable-dashboard-widgets
- decommission-monitoring-poller
- service-registry
- unify-tasks-on-services

All associated implementation has been merged to main.
2026-06-23 19:38:34 +00:00

5.2 KiB
Raw Permalink Blame History

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

  • Removed addon pages (/addons/:addonId, AddonPage.tsx, addons/*) — superseded by service pages.
  • 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.)
  • 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.
  • Registered /services route in both route trees + sidebar nav.
  • 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)

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)

  • Added jellyseerr service definition (integrations/jellyseerr.py) and registered it (6 service types total).
  • Added user_id to the Jellyfin service config.
  • 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).
  • SSH/Files transport (get_ssh_client) unchanged — still uses machine_id.
  • 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)

  • 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.
  • hooks/useDashboard.ts, hooks/useUsers.ts, hooks/useMedia.ts: renamed the selector param to jellyfinServiceId.
  • pages/Media.tsx + pages/Applications.tsx: select a jellyfin service instance via useServiceInstances("jellyfin") and persist jellyfin_service_id in the URL.
  • Dashboard (widget-based) and Users (default-instance) need no selector change.
  • 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)

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)