# Changelog All notable changes to Manage. Breaking changes are marked with **BREAKING**. ## [Unreleased] ### Added — Service registry - Runtime **service registry** persisted in the backend SQLite database. External services (Grafana, Prometheus, Jellyfin, Nextcloud, SSH task runner) are now configured in the app instead of via environment variables. - Services page (`/services`) to create, list, and delete service instances. - Service detail pages (`/services/:serviceType/:serviceId`) to edit name/enabled state, rotate secrets, and view the widgets a service provides. - Service definitions live as Pydantic modules in `backend/.../integrations/`, each declaring its config schema, secret fields, and widget kinds. - Multi-instance support: multiple Grafana/Jellyfin/etc. instances per type. - SSH task runner service records run history in a new `service_task_runs` table, shown on the runner's service page. ### Changed - Dashboard widgets are now **service-bound** (reference a service instance + widget kind) or **built-in** (backups, static text). The "Add widget" flow is pick-service → pick-widget-kind → configure. - Deleting a service cascade-deletes widgets that reference it. ### Security - Service secrets (API keys, tokens, passphrases) are **encrypted at rest** with Fernet. ### **BREAKING** - **`MANAGE_ENCRYPTION_KEY` is now required** to start the backend. Generate one with: ```bash python -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())" ``` - The `GRAFANA_URL` and `PROMETHEUS_URL` backend environment variables were removed; Grafana/Prometheus URLs now live on service records configured in the UI. Re-create them on the Services page after upgrading. - The legacy widget/addon-pages model (`/addons/:addonId`, `/api/widgets/types`, `/api/widgets/sources`) was removed in favor of the service registry. - Default dashboard widget seeding was removed; a fresh install starts with an empty dashboard. Add widgets from the dashboard's edit dialog after configuring services. ### Notes / follow-ups - Machine-level Jellyfin/Jellyseerr app config still powers the Media/Users/Files pages. Migrating those onto the service registry is a separate follow-up change (see `openspec/changes/service-registry/design.md` §12.5). ## Follow-up #1 — remove dead machine Jellyfin/Jellyseerr fields With Jellyfin/Jellyseerr now resolved from the service registry, the machine-level Jellyfin/Jellyseerr fields are dead config. Removed from `dependencies.py` (dead `_jellyseerr_client_for`; `_resolve_machine` simplified to SSH-only), `services/settings_store.py`, `routers/settings.py` (`MachineInput`), frontend types, the `Settings.tsx` form, and frontend test fixtures. Existing DB rows may still carry these keys in `config_json`; they are inert and get dropped on the next machine save. No data migration required.