feat(backups): wire up routes, nav, dashboard widget, and docs

- Add /backups route and navigation tab in App.tsx
- Add BackupDashboardWidget to Dashboard page
- Document backup monitoring feature in REQUIREMENTS.md
This commit is contained in:
2026-05-11 21:54:50 +02:00
parent a7a66ff370
commit 322b3d1a3b
10 changed files with 156 additions and 8 deletions
+8
View File
@@ -0,0 +1,8 @@
{"blockedId":"el-1hq","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:25:05.357Z","createdBy":"el-2rt3"}
{"blockedId":"el-5r1","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:27:55.342Z","createdBy":"el-2rt3"}
{"blockedId":"el-3qf","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:27:55.727Z","createdBy":"el-2rt3"}
{"blockedId":"el-32h","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:27:56.147Z","createdBy":"el-2rt3"}
{"blockedId":"el-1fr","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:27:56.551Z","createdBy":"el-2rt3"}
{"blockedId":"el-580","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:27:56.956Z","createdBy":"el-2rt3"}
{"blockedId":"el-3ub","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:27:57.377Z","createdBy":"el-2rt3"}
{"blockedId":"el-2oe","blockerId":"el-401","type":"parent-child","createdAt":"2026-05-11T19:27:57.816Z","createdBy":"el-2rt3"}
File diff suppressed because one or more lines are too long
@@ -0,0 +1,50 @@
<h2>UI Redesign Exploration</h2>
<p class="subtitle">Let's figure out the direction for your complete UI redesign</p>
<div class="section">
<h3>Current App Overview</h3>
<p>Manage is a media operations dashboard with these main areas:</p>
<ul>
<li><strong>Dashboard</strong> — Jellyfin activity, monitoring overview, shortcuts</li>
<li><strong>Monitoring</strong> — Per-machine CPU/RAM/IO charts, collector controls</li>
<li><strong>Applications</strong> — Jellyfin media library browsing</li>
<li><strong>Users</strong> — Jellyfin user list with Jellyseerr enrichment</li>
<li><strong>Actions</strong> — Saved server tasks and job execution</li>
<li><strong>Files</strong> — Remote SSH file browser with ffprobe</li>
<li><strong>Settings</strong> — Machine definitions, SSH keys, configuration</li>
</ul>
</div>
<div class="section">
<h3>Current Design Characteristics</h3>
<ul>
<li>Material UI (MUI) with custom theme</li>
<li>Two-row header with logo + navigation tabs</li>
<li>Card-based layout with section containers</li>
<li>Dark mode support (auto-detects system preference)</li>
<li>Compact admin-console styling</li>
<li>AG Grid for data tables</li>
<li>D3 charts for monitoring</li>
</ul>
</div>
<div class="mockup">
<div class="mockup-header">Current App Shell</div>
<div class="mockup-body">
<div class="mock-nav">Logo "Manage" | version chips | user | logout</div>
<div style="display: flex; border-top: 1px solid #ccc;">
<div style="padding: 8px 16px; background: #e3f2fd;">Dashboard</div>
<div style="padding: 8px 16px;">Monitoring</div>
<div style="padding: 8px 16px;">Applications</div>
<div style="padding: 8px 16px;">Users</div>
<div style="padding: 8px 16px;">Actions</div>
<div style="padding: 8px 16px;">Files</div>
<div style="padding: 8px 16px;">Settings</div>
</div>
<div class="placeholder" style="height: 200px; margin-top: 16px;">
Page content area (cards, tables, charts)
</div>
</div>
</div>
<p class="subtitle">Ready to start exploring redesign options. Answer the questions in your terminal!</p>
@@ -0,0 +1,38 @@
<h2>Visual Direction</h2>
<p class="subtitle">What aesthetic feel do you want for the new design?</p>
<div class="options">
<div class="option" data-choice="minimal" onclick="toggleSelect(this)">
<div class="letter">A</div>
<div class="content">
<h3>Minimal & Clean</h3>
<p>Lots of whitespace, subtle borders, muted colors, content-first. Think Linear, Notion, or modern SaaS dashboards.</p>
</div>
</div>
<div class="option" data-choice="bold" onclick="toggleSelect(this)">
<div class="letter">B</div>
<div class="content">
<h3>Bold & Expressive</h3>
<p>Strong colors, distinct visual personality, custom illustrations or iconography. Think Vercel, Stripe, or gaming dashboards.</p>
</div>
</div>
<div class="option" data-choice="professional" onclick="toggleSelect(this)">
<div class="letter">C</div>
<div class="content">
<h3>Professional & Enterprise</h3>
<p>Polished but conservative, clear hierarchy, familiar patterns. Think AWS console, Datadog, or enterprise admin tools.</p>
</div>
</div>
<div class="option" data-choice="dark-dramatic" onclick="toggleSelect(this)">
<div class="letter">D</div>
<div class="content">
<h3>Dark & Dramatic</h3>
<p>Deep dark backgrounds, neon accents, high contrast. Think cyberpunk, developer tools, or media center aesthetics.</p>
</div>
</div>
</div>
<p class="subtitle">Click your preferred style in the browser, or tell me in the terminal if you want something else entirely.</p>
@@ -0,0 +1,3 @@
<div style="display:flex;align-items:center;justify-content:center;min-height:60vh">
<p class="subtitle">Continuing in terminal...</p>
</div>
@@ -0,0 +1 @@
{"type":"server-started","port":52977,"host":"127.0.0.1","url_host":"localhost","url":"http://localhost:52977","screen_dir":"/home/alex/projects/media_library_viewer/.superpowers/brainstorm/435525-1778528804/content","state_dir":"/home/alex/projects/media_library_viewer/.superpowers/brainstorm/435525-1778528804/state"}
@@ -0,0 +1 @@
435537
+29
View File
@@ -279,3 +279,32 @@ Phase 1: Jellyfin media index, SSH-based remote filesystem inspection, server mo
- 2026-05-07: The SSH machine editor should expose a validation button that tests banner/auth flow and records the host key before save so users get clear feedback when a host is unreachable.
- 2026-05-07: Saving a monitoring-capable machine should validate the banner/auth flow, update the backend-managed known_hosts entry for the current host, and start the remote resource collector so charts populate without a separate manual step.
- 2026-05-07: Machine settings should visually separate Connection, Monitoring / Files, Jellyfin, Jellyseerr, and Notes into clearly labeled sections.
## Backup Monitoring
### Overview
The system receives backup execution reports from an external backup tool via HTTP API, stores job and run history, and provides alerting on failures, missed schedules, and anomalies.
### API
- `POST /api/backups/report` — Submit backup run (Bearer token auth)
- `POST /api/backups/report/start` — Mark backup as in_progress
- `GET /api/backups/jobs` — List jobs
- `GET /api/backups/runs` — List runs
- `GET /api/backups/alerts` — List alerts
- `POST /api/backups/alerts/{id}/acknowledge` — Acknowledge alert
- `GET /api/dashboard/backups` — Dashboard summary
### Data Model
- **BackupJob**: id, name, source, target, schedule_interval_seconds, created_at
- **BackupRun**: id, job_id, started_at, ended_at, status, bytes_transferred, duration_ms, error_message, details_json
- **BackupAlert**: id, job_id, run_id, alert_type, severity, message, acknowledged, resolved_at
### Alert Types
- `failed_status` — Backup reported failure (critical)
- `missed_schedule` — No run within 1.5x expected interval (warning)
- `anomaly_size` — Size is 0 or <10% / >300% of 7-day median (warning)
- `anomaly_duration` — Duration >300% of 7-day median (warning)
### Authentication
- Backup tool uses auto-generated Bearer API key
- Frontend uses existing OIDC/JWT auth
+15 -7
View File
@@ -36,6 +36,7 @@ import { Settings } from "./pages/Settings";
import { UsersPage } from "./pages/Users";
import { FileBrowser } from "./pages/FileBrowser";
import { Actions } from "./pages/Actions";
import BackupsPage from "./components/BackupsPage";
import { getAppTheme } from "./theme";
import { getOidcConfig, isOidcConfigured, setAccessToken } from "./auth";
import { fetchAppVersion } from "./api/client";
@@ -209,13 +210,19 @@ function Shell({
component={NavLink}
to="/actions"
/>
<Tab value="/files" label="Files" component={NavLink} to="/files" />
<Tab
value="/settings"
label="Settings"
component={NavLink}
to="/settings"
/>
<Tab value="/files" label="Files" component={NavLink} to="/files" />
<Tab
value="/backups"
label="Backups"
component={NavLink}
to="/backups"
/>
<Tab
value="/settings"
label="Settings"
component={NavLink}
to="/settings"
/>
</Tabs>
</Box>
</AppBar>
@@ -231,6 +238,7 @@ function Shell({
<Route path="/users" element={<UsersPage />} />
<Route path="/actions" element={<Actions />} />
<Route path="/files" element={<FileBrowser />} />
<Route path="/backups" element={<BackupsPage />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Container>
+3
View File
@@ -35,6 +35,7 @@ import { NowPlaying } from "../components/NowPlaying";
import { MonitoringOverviewTable } from "../components/MonitoringOverviewTable";
import { SectionCard } from "../components/SectionCard";
import { DialogFooter } from "../components/DialogFooter";
import BackupDashboardWidget from "../components/BackupDashboardWidget";
function emptyShortcut(): DashboardShortcutInput {
return {
@@ -444,6 +445,8 @@ export function Dashboard() {
<MonitoringOverviewTable overview={monitoringOverview} embedded />
</SectionCard>
<BackupDashboardWidget />
<ShortcutDialog
open={shortcutDialogOpen}
draft={shortcutDraft}