8cdeadd6dd
PR 1 of 4 for the runtime service registry change. - Add Fernet encryption helper (services/secrets.py) with a required MANAGE_ENCRYPTION_KEY; validate it on startup. - Add closed integrations/ registry with Pydantic config + widget-config definitions for grafana, prometheus, jellyfin, nextcloud, and ssh_tasks. - Add services + service_task_runs tables and SettingsStore CRUD with cascade-delete (defensive until widgets carry service_id). - Add /api/services/types and /api/services/instances CRUD (encrypted secrets, secrets_set flags only; never plaintext). - Declare cryptography as a direct dependency. - Require MANAGE_ENCRYPTION_KEY in compose + .env.example + README. - Add 25 backend tests (registry, encryption, CRUD, cascade, task-run history). Verification: ruff clean; pytest 225 passed; frontend lint/build green.
3.7 KiB
3.7 KiB
Apply Progress: Runtime Service Registry
Change: service-registry
Apply run: PR 1 / Slice 1 — Backend service foundation
Date: 2026-06-19
Completed tasks (Slice 1)
- 1.1 Add encryption helper (
services/secrets.py) - 1.2 Add integrations base classes (
integrations/base.py) - 1.3 Add five service definitions + registry
- 1.4 Add
services+service_task_runstables + store CRUD with cascade delete - 1.5 Add service Pydantic models +
/api/services*router - 1.6 Validate
MANAGE_ENCRYPTION_KEYon startup - 1.7 Add backend tests (
tests/test_services.py) - 1.8 Verify (ruff + pytest green)
Files changed (Slice 1)
New files
backend/src/media_library_viewer_api/integrations/__init__.py— package marker.backend/src/media_library_viewer_api/integrations/base.py—ServiceConfigBase,WidgetConfigBase,SecretField,WidgetKind,ServiceDefinition,widget_kind(),validate_config().backend/src/media_library_viewer_api/integrations/{grafana,prometheus,jellyfin,nextcloud,ssh_tasks}.py— one Pydantic-config + widget-config definition per service.backend/src/media_library_viewer_api/integrations/registry.py— closedSERVICE_DEFINITIONS+ helpers.backend/src/media_library_viewer_api/services/secrets.py— Fernet encrypt/decrypt- key validation.
backend/src/media_library_viewer_api/models/services.py— request/response models.backend/src/media_library_viewer_api/routers/services.py—/api/services/types/api/services/instancesCRUD.
backend/tests/test_services.py— 25 tests.
Modified files
backend/src/media_library_viewer_api/services/settings_store.py—servicesandservice_task_runstables; service CRUD; cascade delete (defensive against the not-yet-presentdashboard_widgets.service_idcolumn); task-run history helpers.backend/src/media_library_viewer_api/main.py— registerservices_router; validate encryption key on startup.backend/pyproject.toml— declarecryptography>=42.0direct dependency.docker-compose.yml,docker-compose.dev.yml,.env.example,README.md— require and documentMANAGE_ENCRYPTION_KEY.
Verification (Slice 1)
cd backend
.venv/bin/ruff check . # All checks passed
PYTHONPATH=src .venv/bin/python -m pytest # 225 passed
cd ../frontend
npm run lint # 0 errors
npm run build # success
Smoke: encryption round-trip OK; missing MANAGE_ENCRYPTION_KEY raises on startup.
Deviations from design
- Service-config and widget-config schemas are derived from Pydantic models
(
model_json_schema()), matching the user's "proper pydantic config definitions" request. The design's hand-written JSON schemas were replaced by model-derived ones. - Service-table CRUD lives on
SettingsStore(not a separateservice_store.py) to match how widgets/saved_tasks/ssh_keys are already handled there. This keeps a single store owner for all tables. - The cascade delete defensively checks for
dashboard_widgets.service_id(added in Slice 2) so Slice 1 stays green without the column.
Remaining work
- Slice 2: Backend widget rebind to services (add
service_id/widget_kind, refactor adapters to take aServiceRecord, retire old widget registry, SSH run logging). - Slice 3: Frontend services runtime (types, API, hooks, frontend registry, service pages, route swap).
- Slice 4: Dashboard picker, settings rework, remove
grafana_url/prometheus_urlenv vars, stop default seeding, docs + changelog.