Files
manage/CHANGELOG.md
T
Developer 67ca0fc3bc feat(prometheus-direct-charting): slice 3 — remove grafana + config rewrite + changelog
Remove the entire Grafana surface: integrations/grafana.py, GrafanaWidgetSource
(+ _fetch_chart, now redundant since prometheus chart exists), GrafanaLinkWidget,
LinksTab, get_grafana_status endpoint, useGrafanaStatus hook, GrafanaStatus type,
fetchGrafanaStatus client fn, registry/nav/tab entries (FE+BE). Rewrite
config.yaml thin-dashboard rule to match reality (recharts is sanctioned for
Prometheus-backed series). CHANGELOG migration note added.

Backend: 293 pytest pass, ruff clean. Frontend: build+lint green (0 errors).
SC-115/116 grep-clean (only prometheus_range.py migration comments + Dashboard.test
shortcut fixture remain — both spec-allowed).
2026-07-08 22:35:06 +00:00

147 lines
7.4 KiB
Markdown

# Changelog
All notable changes to Manage. Breaking changes are marked with **BREAKING**.
## [Unreleased]
### Added — Direct Prometheus charting
- **Prometheus is now the direct source for in-app charts.** New widget kinds
on the `prometheus` service: `chart` (multi-series line chart via recharts,
backed by `/api/v1/query_range`), `gauge` (instant scalar with configurable
threshold bands), and `mean` (client-side average over a time window).
### **BREAKING** — Grafana service type removed
- The `grafana` service type, Grafana link widget, Grafana chart widget, and
`GET /api/monitoring/grafana-status` endpoint were **removed**. Manage now
queries Prometheus directly for all chart data.
- **Migration:** Delete any existing Grafana service instances and create
Prometheus service instances instead (pointing at your Prometheus URL). Any
configured `grafana/chart` widgets must be recreated as `prometheus/chart`
widgets. Grafana link widgets are gone — use Prometheus chart/metric widgets
instead.
### Added — Observability service registry
- **Alertmanager is now a service type.** Configure Alertmanager, Grafana, and
Prometheus instances in the UI on the Services page; all three are first-class
service-registry entries with dashboard widgets (`active_alerts`, Grafana link,
Prometheus metric).
- New monitoring endpoints resolve the configured service instance and probe its
health: `GET /api/monitoring/grafana-status`, `/prometheus-status`. The
`/alerts` and `/alertmanager-status` endpoints now take an optional
`service_id` and pick the first enabled alertmanager instance by default.
- The Observability page discovers Grafana/Prometheus/Alertmanager from the
registry and renders health cards; the dashboard `active_alerts` widget sums
firing alerts by severity.
### Changed — Observability is now external only
- **Removed** all observability services from `docker-compose.yml` and
`docker-compose.dev.yml`. They now deploy **only** the backend and frontend.
The `monitoring` network and the `prometheus`/`loki`/`alloy`/`grafana`/
`alertmanager`/`node-exporter` services and their named volumes were deleted,
and the `GRAFANA_APP_HOST` Traefik rule was removed.
- Manage now connects to **existing** Grafana/Prometheus/Alertmanager instances
and never ships its own stack. The previous in-compose stack is preserved as
an optional, deploy-it-yourself example in `docker-compose.observability.yml`
(config under `monitoring/`, documented in `docs/observability-runbooks.md`).
- Removed the now-orphaned combined `monitoring/prometheus/prometheus.yml`; the
standalone stack uses `monitoring/prometheus/prometheus.standalone.yml`.
- Removed the Prometheus file-SD bridge (`PROMETHEUS_FILE_SD_DIR` + the
`write_prometheus_targets` file writer). External Prometheus instances now
consume node-exporter targets via `http_sd_configs` against
`GET /api/monitoring/prometheus-targets`. The webhook receiver is log-only.
### **BREAKING**
- Observability is configured entirely via the service registry; the backend
`alertmanager_url`/`alertmanager_webhook_url` and frontend
`VITE_GRAFANA_URL`/`VITE_PROMETHEUS_URL` environment variables, plus
`PROMETHEUS_FILE_SD_DIR`, were **removed**. Re-create your Alertmanager /
Grafana / Prometheus instances on the Services page after upgrading. The only
observability env var remaining is `PROMETHEUS_ENABLED` (toggles Manage's own
`/metrics` endpoint).
### 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**
- Saved Actions (server tasks) now target `ssh_tasks` service instances instead
of monitoring machines. The `default_machine_id` field on saved tasks was
replaced with `default_service_id`; the legacy `saved_task_runs` table was
dropped and run history now lives in `service_task_runs`. Re-create SSH task
runner services on the Services page and re-link saved actions after
upgrading.
- **`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.~~
**Done (2026-06-23):** Jellyfin is no longer a machine service, and the dead
machine-level `media_root`/`path_prefix` fields were removed. See the
Jellyfin migration entry in `docs/REQUIREMENTS.md`.
## Follow-up #2 — remove dead machine `media_root`/`path_prefix` + Jellyfin service
Completes the Jellyfin migration onto the service registry. Jellyfin is no
longer a machine `services` tag (`DEFAULT_SERVICES` is now `["monitoring",
"files"]`), and the dead machine-level `media_root`/`path_prefix` fields were
removed from the settings store, `MonitoringMachineInput`, frontend types, and
the Settings UI. Jellyfin is configured exclusively as a service-registry
instance. The global `REMOTE_MEDIA_ROOT`/`REMOTE_PATH_PREFIX` config properties
and `path_utils.py` remain (files/media-index still use them for Jellyfin→SSH
path resolution). Existing DB rows may still carry these keys in `config_json`;
they are inert and get dropped on the next machine save.
## 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.