You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Produced by a multi-agent feature review: 9 feature areas inventoried (backend + frontend), then 6 lenses (UX, security, automation, integrations, observability, novel) proposed 38 features, ranked into the roadmap below. Pure correctness/bug fixes are tracked in the companion bugs issue; this issue is net-new capability and the data-plumbing that enables it. Effort = S/M/L/XL, Impact = high/med/low.
Where apt-ui stands
A mature, feature-broad fleet patcher. Biggest opportunities: (a) data that's collected but never shown/acted on (ServerStats time series, snapshot capability, per-package security flags, CVE fix-versions); (b) trust/safety (no actor attribution, no auth-event log, no rate limiting, no rollback); (c) fleet-scale ergonomics (no bulk selection, no density view, no trends); (d) automation depth (rollouts aren't durable/observable; no canary-verify).
Deferred to dedicated PRs (large/architectural, externally-dependent, or blocked): durable rollout state machine, persistent job-queue control plane, CVE remediation planner (blocked on the empty CVE pipeline — bugs issue #61), and OIDC/SSO. Rationale in the comment below.
Persist per-package is_security/is_kernel/is_new into upgrade history (backend/upgrade_manager.py:571) — S / high. One additive-JSON write unblocks the digest (kills the substring heuristic in backend/notifier.py:1053) and the dead security:0 Stats series at frontend/src/pages/ServerDetail.tsx:1833.
Dashboard density / compact-list view toggle (frontend/src/pages/Dashboard.tsx) — S / medium. The fixed 4-col card grid is overwhelming on large fleets; add a list/table density mode (persist like dashboard:sortBy).
Slack as a first-class weekly-digest channel (backend/notifier.py, frontend/src/pages/Settings.tsx) — S / medium. Digest currently lacks a Slack delivery option (the missing badge color is in the bugs issue).
Schedule-config self-heal banner + scheduler-health metric (backend/scheduler.py) — S–M / medium. Reconcile registered jobs on startup/save; surface a banner if an "enabled" job isn't actually scheduled. Pairs with the cron-validation bug fix.
Cap concurrency + record history for template apply (backend/routers/templates.py) — S / medium. Reuse upgrade_concurrency and respect locks/windows in ws_template_apply.
Fleet pending-updates: aggregate endpoint + export (frontend/src/pages/Dashboard.tsx:691-832) — M / medium. Replace the sequential per-server /packages loop with one backend aggregate; add CSV/copy export and in-modal filter.
🎯 High-impact bets (M/L)
Unified actor attribution + auth-event log (M/L) — Thread the authenticated username through run_command/upgrade_manager/WS handlers (everything logs initiated_by='system' today, backend/ssh_manager.py:176); add an AuthEventLog table (logins/failures/token use/role changes) as a 4th History sub-tab. "Who rebooted prod at 2am" is currently unanswerable; prerequisite for lockout alerting, CVE triage, change records.
Login + 2FA brute-force protection with lockout & alerting (M) — Per-(username, ip) backoff/lockout, TOTP replay protection (totp_last_counter), real-time alert on lockout (backend/routers/auth.py:27-61). Zero rate limiting today = bcrypt+TOTP is brute-forceable; the most exploitable hole for an exposed deploy.
Dashboard bulk selection + sticky action bar (L) — Reuse the selectedIds pattern from frontend/src/pages/Settings.tsx:325 on each ServerCard; act on a subset (check/upgrade/reboot/enable-disable/tag) via parallel per-server calls honoring upgrade_concurrency. Top fleet-UX gap — today every action is per-card or whole-fleet.
Enforce maintenance windows as change-control gates on all mutating actions (M) — Move get_active_window_for_server into the shared upgrade/reboot/template entry points with an audited admin override_window; add an "allow-only" window mode (backend/routers/upgrades.py:629). Freezes are advisory for humans today.
Fleet snapshot history table + trend charts (M) — New FleetSnapshot table written from _job_check_all (excluded from log-purge), GET /api/stats/trend, and Dashboard trend lines (pending packages, security debt, % up-to-date over time). The donut is point-in-time only; raw rows get purged.
Snapshot-and-rollback safety net (L) — Auto-snapshot btrfs/zfs hosts before apt (capability already detected and wasted at backend/update_checker.py:174), record the snapshot on UpdateHistory, add an admin-gated "rollback to pre-upgrade snapshot" button. Turns dead-end detection into a real safety net.
Canary-first auto-upgrade with health verification (L) — After apt, run the existing health probe (failed units / boot errors), compare before/after, require the ring's first server to pass before promoting (backend/upgrade_manager.py:98-311). Today success = apt exit code only.
App-wide toast + styled confirm system (M) — Zustand toast store + <ToastHost> + promise-based useConfirm(), migrating ~27 native alert()/confirm() sites, with opt-in undo for reversible actions. Unblocks the bulk bar and palette actions; replaces unthemeable blocking dialogs.
Multi-target notifications + on-call adapters (L) — NotificationDestination table with per-event routing + Discord/Mattermost/ntfy/PagerDuty/Opsgenie adapters (Discord/Mattermost reuse the existing Block-Kit shape, backend/notifier.py:159/201). Add notification dedup to avoid alert storms.
Inbound automation API (/api/v1) + scoped/expiring tokens (L) — REST wrappers over the WS-only ops returning a pollable job_id; token scopes (read/check/upgrade/calendar) + settable expires_at (backend/routers/auth.py:120, backend/models.py:83). Also fixes that a leaked calendar URL is currently a full-admin credential.
Eliminate the shared latest-row N+1 (M) — One correlated-subquery/window fetch of latest UpdateCheck+ServerStats per server, reused by /stats/overview, /status.json, reports/*, /metrics, list_servers (backend/routers/stats.py:33). The hottest path in the app.
🚀 Ambitious / longer-term (L/XL)
Durable, observable staged rollouts (XL) — Replace the in-process await asyncio.sleep(24h) (backend/scheduler.py:156) with a persisted Rollout/RolloutStep state machine driven by DateTrigger jobs, startup reconciliation, rollout-scoped failure detection, and a promote-now/abort/pause UI. Unifies auto-upgrade staging and ws_reboot_all.
Persistent job queue / control plane (L) — A Task table + single worker pool replacing module-global progress dicts and fire-and-forget gather: bounded concurrency, cancel/abort, restart recovery, accurate "what's running", and finally drives the defined-but-unused upgrading status.
CVE remediation planner (L) — Once the CVE pipeline is fixed, compute per-server the upgradable packages satisfying a USN's binary fixed-version and "remediate everywhere" via the selective-upgrade engine, with MTTR tracking (backend/routers/security.py, backend/upgrade_manager.py:314).
OIDC/OAuth2 SSO with group→role mapping (L) — Authentik/Keycloak/Google/Entra, JIT provisioning defaulting to read-only, local admin as break-glass. Table-stakes for team adoption.
Self-updating EOL data (L) — Daily sync from endoflife.date (ubuntu/debian/proxmox-ve) with the bundled backend/eol_data.py table as offline fallback + a coverage test. The hardcoded table already misses Debian 13, PVE 9/PBS 4/PMG 9, and has a likely-wrong PVE 8 date.
Dependency / anti-affinity-aware upgrade ordering (L) — DAG + affinity groups so HA pairs and DB primary/replica patch in safe order; best built atop the durable-rollout engine.
✨ Novel ideas
Upgrade impact preview — Pre-flight panel: parsed dry-run plan + on-demand apt-get changelog for security/kernel packages + needrestart -b to show which services restart and whether a reboot is truly required (replacing the hardcoded frontend regex with ground truth). backend/routers/upgrades.py:550, backend/update_checker.py:40.
Maintenance change-record / exportable patch report — Bracket each window into an auditable change ticket (planned vs actual, packages, reboots, failures, who approved) exportable to Markdown/CSV and surfaced as a completed iCal event. Depends on window enforcement + persisted security flags.
Safe fleet command runner — Run an admin-allowlisted (raw mode admin-gated + audited) command across selected servers and group identical outputs ("47 said X, 3 said Y"). Built on the existing audited run_command fan-out.
Configuration drift detection — Cheap per-check fingerprints (dpkg --verify, abandoned .dpkg-dist/.ucf-dist files, enabled units) to flag "3 servers have unreconciled conffile changes" and compare a server against its group/ring peers. Surfaces the most common post-patch breakage cause, invisible today.
HTTP/webhook hook type — Let pre/post hooks call out from apt-ui (drain from HAProxy/Traefik, create an Alertmanager silence, open/close a ticket) since the box is about to reboot — with the same SSRF guards as validate-deb-url (backend/routers/hooks.py, backend/upgrade_manager.py).
Sequencing: land the S-effort correctness fixes (in the bugs issue) first — several are prerequisites: security flags → trends/digest; audit attribution → change records & remediation; CVE pipeline → triage & remediation planner; durable rollouts → dependency ordering & canary.
Generated from a multi-agent feature review. Bug fixes tracked in the companion issue.
Enhancement roadmap — prioritized new features
Produced by a multi-agent feature review: 9 feature areas inventoried (backend + frontend), then 6 lenses (UX, security, automation, integrations, observability, novel) proposed 38 features, ranked into the roadmap below. Pure correctness/bug fixes are tracked in the companion bugs issue; this issue is net-new capability and the data-plumbing that enables it. Effort = S/M/L/XL, Impact = high/med/low.
Where apt-ui stands
A mature, feature-broad fleet patcher. Biggest opportunities: (a) data that's collected but never shown/acted on (ServerStats time series, snapshot capability, per-package security flags, CVE fix-versions); (b) trust/safety (no actor attribution, no auth-event log, no rate limiting, no rollback); (c) fleet-scale ergonomics (no bulk selection, no density view, no trends); (d) automation depth (rollouts aren't durable/observable; no canary-verify).
⚡ Quick wins (S/M)
is_security/is_kernel/is_newinto upgrade history (backend/upgrade_manager.py:571) — S / high. One additive-JSON write unblocks the digest (kills the substring heuristic inbackend/notifier.py:1053) and the deadsecurity:0Stats series atfrontend/src/pages/ServerDetail.tsx:1833.frontend/src/pages/Dashboard.tsx) — S / medium. The fixed 4-col card grid is overwhelming on large fleets; add a list/table density mode (persist likedashboard:sortBy).backend/notifier.py,frontend/src/pages/Settings.tsx) — S / medium. Digest currently lacks a Slack delivery option (the missing badge color is in the bugs issue).backend/scheduler.py) — S–M / medium. Reconcile registered jobs on startup/save; surface a banner if an "enabled" job isn't actually scheduled. Pairs with the cron-validation bug fix.backend/routers/templates.py) — S / medium. Reuseupgrade_concurrencyand respect locks/windows inws_template_apply.frontend/src/pages/Dashboard.tsx:691-832) — M / medium. Replace the sequential per-server/packagesloop with one backend aggregate; add CSV/copy export and in-modal filter.🎯 High-impact bets (M/L)
run_command/upgrade_manager/WS handlers (everything logsinitiated_by='system'today,backend/ssh_manager.py:176); add anAuthEventLogtable (logins/failures/token use/role changes) as a 4th History sub-tab. "Who rebooted prod at 2am" is currently unanswerable; prerequisite for lockout alerting, CVE triage, change records.totp_last_counter), real-time alert on lockout (backend/routers/auth.py:27-61). Zero rate limiting today = bcrypt+TOTP is brute-forceable; the most exploitable hole for an exposed deploy.selectedIdspattern fromfrontend/src/pages/Settings.tsx:325on each ServerCard; act on a subset (check/upgrade/reboot/enable-disable/tag) via parallel per-server calls honoringupgrade_concurrency. Top fleet-UX gap — today every action is per-card or whole-fleet.get_active_window_for_serverinto the shared upgrade/reboot/template entry points with an audited adminoverride_window; add an "allow-only" window mode (backend/routers/upgrades.py:629). Freezes are advisory for humans today.FleetSnapshottable written from_job_check_all(excluded from log-purge),GET /api/stats/trend, and Dashboard trend lines (pending packages, security debt, % up-to-date over time). The donut is point-in-time only; raw rows get purged.backend/update_checker.py:174), record the snapshot onUpdateHistory, add an admin-gated "rollback to pre-upgrade snapshot" button. Turns dead-end detection into a real safety net.backend/upgrade_manager.py:98-311). Today success = apt exit code only.<ToastHost>+ promise-baseduseConfirm(), migrating ~27 nativealert()/confirm()sites, with opt-in undo for reversible actions. Unblocks the bulk bar and palette actions; replaces unthemeable blocking dialogs.NotificationDestinationtable with per-event routing + Discord/Mattermost/ntfy/PagerDuty/Opsgenie adapters (Discord/Mattermost reuse the existing Block-Kit shape,backend/notifier.py:159/201). Add notification dedup to avoid alert storms./api/v1) + scoped/expiring tokens (L) — REST wrappers over the WS-only ops returning a pollablejob_id; token scopes (read/check/upgrade/calendar) + settableexpires_at(backend/routers/auth.py:120,backend/models.py:83). Also fixes that a leaked calendar URL is currently a full-admin credential.UpdateCheck+ServerStatsper server, reused by/stats/overview,/status.json,reports/*,/metrics,list_servers(backend/routers/stats.py:33). The hottest path in the app.🚀 Ambitious / longer-term (L/XL)
await asyncio.sleep(24h)(backend/scheduler.py:156) with a persistedRollout/RolloutStepstate machine driven by DateTrigger jobs, startup reconciliation, rollout-scoped failure detection, and a promote-now/abort/pause UI. Unifies auto-upgrade staging andws_reboot_all.Tasktable + single worker pool replacing module-global progress dicts and fire-and-forgetgather: bounded concurrency, cancel/abort, restart recovery, accurate "what's running", and finally drives the defined-but-unusedupgradingstatus.backend/routers/security.py,backend/upgrade_manager.py:314).backend/eol_data.pytable as offline fallback + a coverage test. The hardcoded table already misses Debian 13, PVE 9/PBS 4/PMG 9, and has a likely-wrong PVE 8 date.✨ Novel ideas
apt-get changelogfor security/kernel packages +needrestart -bto show which services restart and whether a reboot is truly required (replacing the hardcoded frontend regex with ground truth).backend/routers/upgrades.py:550,backend/update_checker.py:40.run_commandfan-out.dpkg --verify, abandoned.dpkg-dist/.ucf-distfiles, enabled units) to flag "3 servers have unreconciled conffile changes" and compare a server against its group/ring peers. Surfaces the most common post-patch breakage cause, invisible today.validate-deb-url(backend/routers/hooks.py,backend/upgrade_manager.py).Sequencing: land the S-effort correctness fixes (in the bugs issue) first — several are prerequisites: security flags → trends/digest; audit attribution → change records & remediation; CVE pipeline → triage & remediation planner; durable rollouts → dependency ordering & canary.
Generated from a multi-agent feature review. Bug fixes tracked in the companion issue.