From 6dc5e015683a04d53e9c52d47ebd23141c00b76b Mon Sep 17 00:00:00 2001 From: Olin Osborne III Date: Fri, 20 Mar 2026 13:04:32 -0400 Subject: [PATCH 01/14] chore(sprint): mark v1.1.0 and v2.0.0 complete, add v3.0.0 sprint tickets Update ROADMAP.md to reflect current version v2.0.0 with Phases 1 and 2 marked complete. Add 13 sprint tickets for Phase 3 frontend modernization (Angular + PrimeNG): 8 core tickets plus 5 SPIKEs. --- ROADMAP.md | 6 +- .../FRONT-001-angular-project-scaffold.md | 110 +++++++++++++++ .../v3.0.0/FRONT-002-primeng-theme-layout.md | 110 +++++++++++++++ sprints/v3.0.0/FRONT-003-api-service-layer.md | 119 +++++++++++++++++ sprints/v3.0.0/FRONT-004-dashboard-module.md | 116 ++++++++++++++++ sprints/v3.0.0/FRONT-005-plugins-module.md | 115 ++++++++++++++++ sprints/v3.0.0/FRONT-006-settings-module.md | 126 ++++++++++++++++++ .../v3.0.0/FRONT-007-logs-store-modules.md | 115 ++++++++++++++++ .../v3.0.0/FRONT-008-htmx-removal-cleanup.md | 122 +++++++++++++++++ sprints/v3.0.0/README.md | 123 +++++++++++++++++ .../SPIKE-001-angular-unit-test-setup.md | 90 +++++++++++++ sprints/v3.0.0/SPIKE-002-raw-json-editor.md | 82 ++++++++++++ .../SPIKE-003-operation-history-view.md | 68 ++++++++++ sprints/v3.0.0/SPIKE-004-ci-angular-build.md | 82 ++++++++++++ .../v3.0.0/SPIKE-005-starlark-config-ui.md | 68 ++++++++++ 15 files changed, 1449 insertions(+), 3 deletions(-) create mode 100644 sprints/v3.0.0/FRONT-001-angular-project-scaffold.md create mode 100644 sprints/v3.0.0/FRONT-002-primeng-theme-layout.md create mode 100644 sprints/v3.0.0/FRONT-003-api-service-layer.md create mode 100644 sprints/v3.0.0/FRONT-004-dashboard-module.md create mode 100644 sprints/v3.0.0/FRONT-005-plugins-module.md create mode 100644 sprints/v3.0.0/FRONT-006-settings-module.md create mode 100644 sprints/v3.0.0/FRONT-007-logs-store-modules.md create mode 100644 sprints/v3.0.0/FRONT-008-htmx-removal-cleanup.md create mode 100644 sprints/v3.0.0/README.md create mode 100644 sprints/v3.0.0/SPIKE-001-angular-unit-test-setup.md create mode 100644 sprints/v3.0.0/SPIKE-002-raw-json-editor.md create mode 100644 sprints/v3.0.0/SPIKE-003-operation-history-view.md create mode 100644 sprints/v3.0.0/SPIKE-004-ci-angular-build.md create mode 100644 sprints/v3.0.0/SPIKE-005-starlark-config-ui.md diff --git a/ROADMAP.md b/ROADMAP.md index 6cf95d652..714e67255 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -3,11 +3,11 @@ This document tracks planned improvements, features, and large-scale refactors for the LEDMatrix project. Items are organized into versioned phases. Each phase delivers a cohesive set of changes before the next begins. -Current version: **v1.1.0** +Current version: **v2.0.0** --- -## Phase 1 — Foundation `v1.1.0` +## Phase 1 — Foundation `v1.1.0` COMPLETE > Python modernization, developer tooling, and CI infrastructure. No breaking changes to public APIs or behavior. @@ -44,7 +44,7 @@ Current version: **v1.1.0** --- -## Phase 2 — Backend Modernization `v2.0.0` +## Phase 2 — Backend Modernization `v2.0.0` COMPLETE > Full Flask → FastAPI rewrite. Breaking change: API response formats and endpoint paths may change. diff --git a/sprints/v3.0.0/FRONT-001-angular-project-scaffold.md b/sprints/v3.0.0/FRONT-001-angular-project-scaffold.md new file mode 100644 index 000000000..7a3a6e9a5 --- /dev/null +++ b/sprints/v3.0.0/FRONT-001-angular-project-scaffold.md @@ -0,0 +1,110 @@ +# FRONT-001 — Angular Project Scaffold + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** _(none -- start here)_ +**Blocks:** [FRONT-002](FRONT-002-primeng-theme-layout.md), [FRONT-003](FRONT-003-api-service-layer.md), [FRONT-004](FRONT-004-dashboard-module.md) + +--- + +## Context + +Phase 3 replaces the Jinja2/HTMX frontend (`web_interface/templates/`, `web_interface/static/`) with an Angular 17+ single-page application. This ticket creates the Angular project skeleton in `frontend/` using Angular CLI, configures the build pipeline to output to `frontend/dist/`, and wires FastAPI to serve the built SPA. + +The FastAPI backend is complete (`src/api/`) with typed Pydantic models, OpenAPI docs at `/docs`, and CORS already configured for `http://localhost:4200`. The API surface is stable at `/api/v3/`. + +**Key constraints:** +- The HTMX pages router (`src/api/routers/pages.py`) and `web_interface/` static files must continue to work during the transition. They are removed in FRONT-008. +- The Angular app must be buildable independently (`ng build`) and also servable by FastAPI in production. +- Use Angular 17+ with standalone components (not NgModules) for new code. + +--- + +## Acceptance Criteria + +- [ ] `frontend/` directory contains a valid Angular 17+ project created via `ng new` +- [ ] `angular.json` configures output to `frontend/dist/ledmatrix/` +- [ ] `ng build` produces a production bundle in `frontend/dist/ledmatrix/` +- [ ] `ng serve` starts dev server on port 4200 with proxy to FastAPI at port 5000 +- [ ] `proxy.conf.json` routes `/api/v3/*` and `/stream/*` to `http://localhost:5000` +- [ ] `package.json` includes scripts: `start`, `build`, `test`, `lint` +- [ ] `.gitignore` in `frontend/` ignores `node_modules/`, `dist/`, `.angular/` + +--- + +## Implementation Checklist + +### 1. Generate Angular project + +- [ ] Run `ng new ledmatrix --directory frontend --routing --style scss --ssr false --standalone` +- [ ] Verify Angular version is 17+ in `package.json` +- [ ] Remove default Angular boilerplate content from `app.component.html` + +### 2. Configure build output + +- [ ] Edit `angular.json` to set `outputPath` to `dist/ledmatrix` +- [ ] Verify `ng build` produces `frontend/dist/ledmatrix/browser/index.html` + +### 3. Configure dev proxy + +- [ ] Create `frontend/proxy.conf.json` routing `/api/v3` and `/stream` to `http://localhost:5000` +- [ ] Update `angular.json` serve target to use `proxyConfig: "proxy.conf.json"` +- [ ] Verify `ng serve` proxies API calls to FastAPI + +### 4. Add environment files + +- [ ] Create `frontend/src/environments/environment.ts` with `apiBase: '/api/v3'` +- [ ] Create `frontend/src/environments/environment.prod.ts` with same `apiBase` + +### 5. Wire FastAPI to serve SPA in production + +- [ ] Update `src/api/main.py` to mount `frontend/dist/ledmatrix/browser/` at `/` when the directory exists +- [ ] Add a catch-all route for Angular client-side routing (returns `index.html` for non-API, non-static paths) +- [ ] Keep existing `/static/` mount and `/v3` page routes working alongside the SPA mount + +### 6. Commit + +```bash +git add frontend/ src/api/main.py +git commit -m "feat(frontend): scaffold Angular 17 project with FastAPI SPA serving" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Angular project structure exists +test -f frontend/package.json && echo "OK: package.json" +test -f frontend/angular.json && echo "OK: angular.json" +test -f frontend/src/app/app.component.ts && echo "OK: app.component.ts" +test -f frontend/proxy.conf.json && echo "OK: proxy.conf.json" +test -f frontend/src/environments/environment.ts && echo "OK: environment.ts" + +# 2. Angular CLI builds successfully +cd frontend && npm install && npx ng build && echo "OK: ng build succeeded" + +# 3. Production bundle exists +test -f frontend/dist/ledmatrix/browser/index.html && echo "OK: index.html in dist" + +# 4. Proxy config is valid JSON +python3 -c "import json; json.load(open('frontend/proxy.conf.json')); print('OK: proxy config valid')" + +# 5. FastAPI SPA mount code exists +grep -q "frontend/dist" src/api/main.py && echo "OK: SPA mount configured" +``` + +--- + +## Notes + +- Node.js and npm are required for Angular development. The distrobox may need Node 18+ installed. This does NOT affect the Python venv. +- The Angular project uses standalone components (Angular 17+ default), not NgModules. This simplifies lazy loading in subsequent tickets. +- Do NOT add PrimeNG in this ticket -- that is FRONT-002. +- The SPA catch-all route must NOT intercept `/api/v3/`, `/docs`, `/redoc`, `/static/`, or `/v3/` paths. +- The `web_interface/` directory is preserved until FRONT-008. diff --git a/sprints/v3.0.0/FRONT-002-primeng-theme-layout.md b/sprints/v3.0.0/FRONT-002-primeng-theme-layout.md new file mode 100644 index 000000000..8e71cd247 --- /dev/null +++ b/sprints/v3.0.0/FRONT-002-primeng-theme-layout.md @@ -0,0 +1,110 @@ +# FRONT-002 — PrimeNG Integration and Dark Theme Layout + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** [FRONT-001](FRONT-001-angular-project-scaffold.md) +**Blocks:** [FRONT-004](FRONT-004-dashboard-module.md), [FRONT-005](FRONT-005-plugins-module.md), [FRONT-006](FRONT-006-settings-module.md) + +--- + +## Context + +The ROADMAP specifies a dark-first theme using PrimeNG's theming API, with a responsive layout usable on phone/tablet. This ticket installs PrimeNG, configures the dark theme, and builds the application shell layout (sidebar navigation, top bar, content area) that all feature modules will render into. + +The current HTMX UI uses Tailwind CSS with a light theme. The new Angular UI switches to PrimeNG components for consistency and accessibility, with a dark-first design appropriate for an LED matrix controller (often viewed in low-light environments). + +--- + +## Acceptance Criteria + +- [ ] PrimeNG and PrimeIcons are installed and configured in the Angular project +- [ ] A dark theme is active by default (Aura Dark or Lara Dark) +- [ ] Application shell contains: collapsible sidebar, top bar with system status, main content area +- [ ] Sidebar navigation has entries for: Dashboard, Plugins, Settings, Logs, Store +- [ ] Layout is responsive -- sidebar collapses to hamburger menu on mobile +- [ ] Loading, error, and empty state components exist as reusable shared components +- [ ] `ng build` still produces a valid production bundle + +--- + +## Implementation Checklist + +### 1. Install PrimeNG dependencies + +- [ ] `npm install primeng primeicons @primeng/themes` +- [ ] Import PrimeNG styles in `angular.json` styles array or `styles.scss` +- [ ] Configure dark theme preset in `app.config.ts` using `providePrimeNG({ theme: { preset: Aura } })` + +### 2. Create application shell layout + +- [ ] Create `src/app/layout/` directory for shell components +- [ ] Create `AppLayoutComponent` with sidebar + topbar + router-outlet structure +- [ ] Use PrimeNG `Sidebar` or `Drawer` for navigation panel +- [ ] Use PrimeNG `Toolbar` for top bar +- [ ] Add router-outlet in the main content area + +### 3. Build sidebar navigation + +- [ ] Create `SidebarComponent` with PrimeNG `Menu` or `PanelMenu` +- [ ] Navigation items: Dashboard (`/`), Plugins (`/plugins`), Settings (`/settings`), Logs (`/logs`), Store (`/store`) +- [ ] Use PrimeIcons for each nav item +- [ ] Highlight active route using `routerLinkActive` + +### 4. Make layout responsive + +- [ ] Sidebar visible by default on desktop (>= 768px) +- [ ] Sidebar hidden behind hamburger toggle on mobile (< 768px) +- [ ] Content area fills remaining width +- [ ] Test at 375px, 768px, and 1024px breakpoints + +### 5. Create shared state components + +- [ ] `LoadingComponent` -- spinner overlay with optional message +- [ ] `ErrorStateComponent` -- error icon, message, retry button +- [ ] `EmptyStateComponent` -- icon, message, optional action button +- [ ] Export all from a `SharedModule` or shared barrel export + +### 6. Commit + +```bash +git add frontend/ +git commit -m "feat(frontend): integrate PrimeNG with dark theme and app shell layout" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. PrimeNG is in dependencies +cd frontend && grep -q "primeng" package.json && echo "OK: primeng installed" + +# 2. Build succeeds with PrimeNG +cd frontend && npx ng build && echo "OK: build with PrimeNG" + +# 3. Layout component exists +test -f frontend/src/app/layout/app-layout.component.ts && echo "OK: layout component" + +# 4. Shared components exist +test -f frontend/src/app/shared/loading/loading.component.ts && echo "OK: loading component" +test -f frontend/src/app/shared/error-state/error-state.component.ts && echo "OK: error-state component" +test -f frontend/src/app/shared/empty-state/empty-state.component.ts && echo "OK: empty-state component" + +# 5. Navigation routes defined +grep -q "Dashboard" frontend/src/app/layout/sidebar/sidebar.component.ts && echo "OK: nav items defined" +``` + +--- + +## Notes + +- PrimeNG 17+ uses standalone component imports -- no `PrimeNGModule` needed. Import individual components like `ButtonModule`, `MenuModule`, etc. +- The Aura Dark theme is the recommended default. If Aura is not available in the installed version, use Lara Dark. +- Do NOT build any feature module content in this ticket. The Dashboard, Plugins, Settings, Logs, and Store modules are separate tickets. +- PrimeNG theming is configured via `providePrimeNG()` in `app.config.ts`, not via CSS imports (PrimeNG v17+ style). +- PrimeFlex (utility CSS) is optional. Use it if helpful for layout, but do not duplicate Tailwind patterns. diff --git a/sprints/v3.0.0/FRONT-003-api-service-layer.md b/sprints/v3.0.0/FRONT-003-api-service-layer.md new file mode 100644 index 000000000..49fb36d40 --- /dev/null +++ b/sprints/v3.0.0/FRONT-003-api-service-layer.md @@ -0,0 +1,119 @@ +# FRONT-003 — API Service Layer and SSE Client + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** [FRONT-001](FRONT-001-angular-project-scaffold.md) +**Blocks:** [FRONT-004](FRONT-004-dashboard-module.md), [FRONT-005](FRONT-005-plugins-module.md), [FRONT-006](FRONT-006-settings-module.md), [FRONT-007](FRONT-007-logs-store-modules.md) + +--- + +## Context + +All feature modules need to communicate with the FastAPI backend at `/api/v3/`. Rather than scatter `HttpClient` calls throughout components, this ticket creates a centralized service layer with typed TypeScript interfaces matching the Pydantic response models, an SSE service for real-time streams, and proper error handling. + +The backend provides: +- REST endpoints at `/api/v3/system/*`, `/api/v3/config/*`, `/api/v3/plugins/*`, `/api/v3/fonts/*`, `/api/v3/wifi/*`, `/api/v3/starlark/*` +- SSE streams at `/api/v3/stream/stats`, `/api/v3/stream/display`, `/api/v3/stream/logs` +- OpenAPI schema at `/docs` (can be used to verify TypeScript interfaces) + +--- + +## Acceptance Criteria + +- [ ] TypeScript interfaces exist for all API response types (matching Pydantic models) +- [ ] `ApiService` wraps `HttpClient` with base URL, error handling, and typed responses +- [ ] `SseService` wraps `EventSource` with auto-reconnect, typed events, and Observable streams +- [ ] `SystemService` provides methods for system status, health, version +- [ ] `PluginService` provides methods for plugin CRUD, toggle, config, store operations +- [ ] `ConfigService` provides methods for config get/update (main, schedule, secrets) +- [ ] All services are injectable via Angular DI (`providedIn: 'root'`) +- [ ] Error responses are parsed into a typed `ApiError` class + +--- + +## Implementation Checklist + +### 1. Create TypeScript interfaces + +- [ ] Create `frontend/src/app/core/models/` directory +- [ ] `system.model.ts` -- `SystemStatus`, `SystemVersion`, `HealthResponse` +- [ ] `plugin.model.ts` -- `PluginInfo`, `PluginConfig`, `PluginToggleRequest`, `StorePlugin` +- [ ] `config.model.ts` -- `SystemConfig`, `ScheduleConfig`, `ConfigUpdateRequest` +- [ ] `common.model.ts` -- `SuccessResponse`, `ErrorResponse`, `PaginatedResponse` +- [ ] `stream.model.ts` -- `StatsEvent`, `DisplayEvent`, `LogEvent` + +### 2. Create base API service + +- [ ] Create `frontend/src/app/core/services/api.service.ts` +- [ ] Inject `HttpClient`, use `environment.apiBase` for base URL +- [ ] Generic `get()`, `post()`, `put()`, `delete()` methods with typed returns +- [ ] Error interceptor that maps HTTP errors to `ApiError` instances +- [ ] Include `X-Request-ID` header on all requests (UUID) + +### 3. Create SSE service + +- [ ] Create `frontend/src/app/core/services/sse.service.ts` +- [ ] `connect(endpoint: string): Observable` -- creates EventSource, wraps in Observable +- [ ] Auto-reconnect with exponential backoff on connection loss +- [ ] `statsStream$`, `displayStream$`, `logStream$` as lazy-initialized Observables +- [ ] Clean up EventSource on unsubscribe + +### 4. Create domain services + +- [ ] `system.service.ts` -- `getStatus()`, `getHealth()`, `getVersion()`, `performAction(action)` +- [ ] `plugin.service.ts` -- `list()`, `get(id)`, `getConfig(id)`, `updateConfig(id, config)`, `toggle(id, enabled)`, `install(id)`, `uninstall(id)`, `getStorePlugins()` +- [ ] `config.service.ts` -- `getMainConfig()`, `updateMainConfig(config)`, `getSchedule()`, `updateSchedule(schedule)` + +### 5. Add HTTP interceptor for error handling + +- [ ] Create `frontend/src/app/core/interceptors/error.interceptor.ts` +- [ ] Log errors to console in development +- [ ] Convert 4xx/5xx responses to typed `ApiError` +- [ ] Register interceptor in `app.config.ts` + +### 6. Commit + +```bash +git add frontend/src/app/core/ +git commit -m "feat(frontend): add typed API service layer and SSE client" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Core service files exist +test -f frontend/src/app/core/services/api.service.ts && echo "OK: api service" +test -f frontend/src/app/core/services/sse.service.ts && echo "OK: sse service" +test -f frontend/src/app/core/services/system.service.ts && echo "OK: system service" +test -f frontend/src/app/core/services/plugin.service.ts && echo "OK: plugin service" +test -f frontend/src/app/core/services/config.service.ts && echo "OK: config service" + +# 2. Model files exist +test -f frontend/src/app/core/models/system.model.ts && echo "OK: system models" +test -f frontend/src/app/core/models/plugin.model.ts && echo "OK: plugin models" +test -f frontend/src/app/core/models/common.model.ts && echo "OK: common models" +test -f frontend/src/app/core/models/stream.model.ts && echo "OK: stream models" + +# 3. Build succeeds +cd frontend && npx ng build && echo "OK: build with services" + +# 4. Interceptor registered +grep -q "error.interceptor" frontend/src/app/app.config.ts && echo "OK: interceptor registered" +``` + +--- + +## Notes + +- TypeScript interfaces should mirror the Pydantic models in `src/api/models/`. When in doubt, check the OpenAPI schema at `/docs`. +- The SSE service uses native `EventSource`, NOT a WebSocket library. The backend uses `sse-starlette`. +- For the display preview stream, the backend sends base64-encoded PNG images. The SSE service should expose these as `Observable` (base64 data URLs). +- Do NOT add WebSocket support in this ticket. The ROADMAP mentions WebSocket for display preview, but the current backend only supports SSE. WebSocket can be a future enhancement. +- All services use `providedIn: 'root'` for tree-shakeable singleton injection. diff --git a/sprints/v3.0.0/FRONT-004-dashboard-module.md b/sprints/v3.0.0/FRONT-004-dashboard-module.md new file mode 100644 index 000000000..ab4057c34 --- /dev/null +++ b/sprints/v3.0.0/FRONT-004-dashboard-module.md @@ -0,0 +1,116 @@ +# FRONT-004 — Dashboard Feature Module + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** [FRONT-002](FRONT-002-primeng-theme-layout.md), [FRONT-003](FRONT-003-api-service-layer.md) +**Blocks:** _(none)_ + +--- + +## Context + +The Dashboard is the landing page of the Angular SPA. It replaces the HTMX "Overview" partial (`web_interface/templates/v3/partials/overview.html`) which shows system stats cards (CPU, memory, temperature, disk), active plugin info, and a live display preview. + +The new Dashboard must: +- Show real-time system metrics via the SSE `/api/v3/stream/stats` stream +- Show the active plugin and display state +- Show a live display preview via the SSE `/api/v3/stream/display` stream +- Use PrimeNG components for cards, charts, and layout + +The existing HTMX overview uses vanilla JavaScript with `EventSource` to update DOM elements by ID. The Angular version replaces this with reactive `Observable` subscriptions through `SseService`. + +--- + +## Acceptance Criteria + +- [ ] Dashboard route is lazy-loaded at `/` (default route) +- [ ] System stats cards display CPU, memory, temperature, disk usage with real-time updates +- [ ] Stats update via SSE stream (not polling) +- [ ] Active plugin card shows current plugin name, version, and display mode +- [ ] Live display preview shows the LED matrix image, updating at ~2 Hz via SSE +- [ ] Quick action buttons: restart display service, toggle brightness +- [ ] Dashboard handles SSE disconnection gracefully (shows stale data indicator) + +--- + +## Implementation Checklist + +### 1. Create dashboard module structure + +- [ ] Create `frontend/src/app/features/dashboard/` directory +- [ ] Create `DashboardComponent` as the route entry point +- [ ] Add lazy route in `app.routes.ts`: `{ path: '', loadComponent: () => import(...) }` + +### 2. Build system stats cards + +- [ ] Create `StatsCardsComponent` with 4 PrimeNG `Card` components +- [ ] Subscribe to `SseService.statsStream$` for real-time CPU, memory, temp, disk +- [ ] Display values with color-coded thresholds (green < 60%, yellow < 80%, red >= 80%) +- [ ] Show "Connecting..." placeholder while SSE stream initializes + +### 3. Build active plugin card + +- [ ] Create `ActivePluginComponent` showing current plugin info +- [ ] Fetch active plugin from `GET /api/v3/plugins` (filter by active/displayed state) +- [ ] Show plugin name, version, display duration remaining +- [ ] Link to plugin config page + +### 4. Build live display preview + +- [ ] Create `DisplayPreviewComponent` subscribing to `SseService.displayStream$` +- [ ] Render base64 PNG images in an `` tag, updating on each SSE event +- [ ] Scale image to fit the card while preserving aspect ratio +- [ ] Show placeholder when no preview data available + +### 5. Add quick actions + +- [ ] Create `QuickActionsComponent` with PrimeNG `Button` components +- [ ] "Restart Display" button calls `POST /api/v3/system/action` with `{ action: "restart" }` +- [ ] Show confirmation dialog before destructive actions using PrimeNG `ConfirmDialog` + +### 6. Handle SSE lifecycle + +- [ ] Unsubscribe from SSE streams on component destroy +- [ ] Show "Connection lost" indicator when SSE disconnects +- [ ] Resume display on reconnect without user action + +### 7. Commit + +```bash +git add frontend/src/app/features/dashboard/ +git commit -m "feat(frontend): add dashboard module with live stats and display preview" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Dashboard component exists +test -f frontend/src/app/features/dashboard/dashboard.component.ts && echo "OK: dashboard component" + +# 2. Sub-components exist +test -f frontend/src/app/features/dashboard/stats-cards/stats-cards.component.ts && echo "OK: stats cards" +test -f frontend/src/app/features/dashboard/display-preview/display-preview.component.ts && echo "OK: display preview" + +# 3. Lazy route configured +grep -q "dashboard" frontend/src/app/app.routes.ts && echo "OK: dashboard route" + +# 4. Build succeeds +cd frontend && npx ng build && echo "OK: build with dashboard" +``` + +--- + +## Notes + +- The SSE stats stream sends JSON with fields: `cpu_percent`, `memory_used_percent`, `cpu_temp`, `disk_used_percent` every ~10 seconds. +- The SSE display stream sends `{ "image": "" }` at ~2 Hz. On resource-constrained Pi hardware, the Angular app should throttle rendering if frames arrive faster than the browser can paint. +- The current HTMX overview also shows display service status (running/stopped) from `systemctl`. This is available via `GET /api/v3/system/status` field `service_active`. +- PrimeNG `Card`, `Button`, `ConfirmDialog`, and `Tag` components are the primary building blocks here. +- Do NOT implement the full plugin list or config editing in this ticket -- that is FRONT-005. diff --git a/sprints/v3.0.0/FRONT-005-plugins-module.md b/sprints/v3.0.0/FRONT-005-plugins-module.md new file mode 100644 index 000000000..efa96eae3 --- /dev/null +++ b/sprints/v3.0.0/FRONT-005-plugins-module.md @@ -0,0 +1,115 @@ +# FRONT-005 — Plugins Feature Module + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** [FRONT-002](FRONT-002-primeng-theme-layout.md), [FRONT-003](FRONT-003-api-service-layer.md) +**Blocks:** _(none)_ + +--- + +## Context + +The Plugins module replaces the HTMX "Plugins" partial (`web_interface/templates/v3/partials/plugins.html` and `plugin_config.html`). It provides a grid/list view of all installed plugins with enable/disable toggles, and a detail view for editing individual plugin configuration against its JSON Schema. + +The backend provides: +- `GET /api/v3/plugins` -- list all plugins with status +- `GET /api/v3/plugins/{id}` -- single plugin info +- `GET /api/v3/plugins/{id}/config` -- plugin config + schema +- `PUT /api/v3/plugins/{id}/config` -- update plugin config +- `POST /api/v3/plugins/{id}/toggle` -- enable/disable +- `GET /api/v3/plugins/{id}/health` -- plugin health metrics + +--- + +## Acceptance Criteria + +- [ ] Plugins route is lazy-loaded at `/plugins` +- [ ] Plugin list view shows all installed plugins in a responsive grid +- [ ] Each plugin card shows: name, version, enabled status, description +- [ ] Enable/disable toggle sends `POST /api/v3/plugins/{id}/toggle` and updates UI optimistically +- [ ] Plugin detail view at `/plugins/:id` shows full config form +- [ ] Config form is dynamically generated from the plugin's `config_schema.json` +- [ ] Config changes are saved via `PUT /api/v3/plugins/{id}/config` +- [ ] Success/error toast notifications on save + +--- + +## Implementation Checklist + +### 1. Create plugins module structure + +- [ ] Create `frontend/src/app/features/plugins/` directory +- [ ] Add lazy route in `app.routes.ts`: `{ path: 'plugins', loadComponent: () => import(...) }` +- [ ] Add child route: `{ path: ':id', loadComponent: () => import(...) }` for detail view + +### 2. Build plugin list view + +- [ ] Create `PluginListComponent` as the route entry point +- [ ] Fetch plugins from `PluginService.list()` +- [ ] Display in PrimeNG `DataView` with grid/list toggle +- [ ] Each card: plugin icon (from `/api/v3/plugins/assets/{id}/icon` or default), name, version, description +- [ ] PrimeNG `ToggleSwitch` for enable/disable with optimistic update +- [ ] Search/filter bar using PrimeNG `InputText` with debounced filtering + +### 3. Build plugin detail / config view + +- [ ] Create `PluginConfigComponent` for the `:id` route +- [ ] Fetch config and schema from `PluginService.getConfig(id)` +- [ ] Dynamically generate form fields from JSON Schema using a `SchemaFormComponent` +- [ ] Support field types: string (InputText), number (InputNumber), boolean (ToggleSwitch), enum (Dropdown), object (nested fieldset) +- [ ] Show plugin health metrics (last update time, error count) from `/api/v3/plugins/{id}/health` + +### 4. Implement schema-driven form generator + +- [ ] Create `frontend/src/app/shared/schema-form/schema-form.component.ts` +- [ ] Input: JSON Schema object + current values +- [ ] Output: form value changes as `EventEmitter>` +- [ ] Handle `required` fields, `default` values, `description` as help text +- [ ] Validate against schema constraints (min, max, pattern, enum) + +### 5. Add save and notification + +- [ ] Save button calls `PluginService.updateConfig(id, formValues)` +- [ ] Show PrimeNG `Toast` on success ("Config saved") and error ("Save failed: ...") +- [ ] Disable save button while request is in-flight (loading state) + +### 6. Commit + +```bash +git add frontend/src/app/features/plugins/ frontend/src/app/shared/schema-form/ +git commit -m "feat(frontend): add plugins module with dynamic config forms" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Plugin components exist +test -f frontend/src/app/features/plugins/plugin-list/plugin-list.component.ts && echo "OK: plugin list" +test -f frontend/src/app/features/plugins/plugin-config/plugin-config.component.ts && echo "OK: plugin config" + +# 2. Schema form component exists +test -f frontend/src/app/shared/schema-form/schema-form.component.ts && echo "OK: schema form" + +# 3. Routes configured +grep -q "plugins" frontend/src/app/app.routes.ts && echo "OK: plugins route" + +# 4. Build succeeds +cd frontend && npx ng build && echo "OK: build with plugins module" +``` + +--- + +## Notes + +- The JSON Schema form generator is the most complex piece of this ticket. Keep it simple for v3.0.0 -- support flat schemas with basic types. Deeply nested schemas or `$ref` support can be deferred. +- Plugin icons may not exist for all plugins. Use a default icon (PrimeIcons `pi-puzzle-piece`) as fallback. +- The HTMX version uses Alpine.js for dynamic form behavior. The Angular version replaces this entirely with reactive forms. +- Optimistic UI updates for toggle: update the UI immediately, then roll back if the API call fails. +- Plugin config includes standard fields (`enabled`, `display_duration`, `transition`) plus plugin-specific fields. The schema form must handle both. diff --git a/sprints/v3.0.0/FRONT-006-settings-module.md b/sprints/v3.0.0/FRONT-006-settings-module.md new file mode 100644 index 000000000..e2151b45f --- /dev/null +++ b/sprints/v3.0.0/FRONT-006-settings-module.md @@ -0,0 +1,126 @@ +# FRONT-006 — Settings Feature Module + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** [FRONT-002](FRONT-002-primeng-theme-layout.md), [FRONT-003](FRONT-003-api-service-layer.md) +**Blocks:** _(none)_ + +--- + +## Context + +The Settings module replaces multiple HTMX partials: `general.html`, `display.html`, `durations.html`, `schedule.html`, `weather.html`, `stocks.html`, `fonts.html`, `wifi.html`, and `cache.html`. These configure system-wide settings for the LED matrix display. + +The backend provides: +- `GET/POST /api/v3/config/main` -- full config (display, schedule, brightness, plugin durations) +- `GET/POST /api/v3/config/schedule` -- on/off schedule +- `GET/POST /api/v3/config/dim-schedule` -- brightness schedule +- `GET /api/v3/config/secrets` -- API keys (redacted) +- `GET /api/v3/fonts` -- font list +- `POST /api/v3/fonts/upload` -- font upload +- `GET /api/v3/wifi/scan` -- Wi-Fi networks +- `POST /api/v3/wifi/connect` -- connect to network + +--- + +## Acceptance Criteria + +- [ ] Settings route is lazy-loaded at `/settings` +- [ ] Tabbed interface with sections: General, Display, Schedule, Fonts, Wi-Fi +- [ ] General tab: brightness, rotation, display dimensions config +- [ ] Display tab: plugin durations, transition settings +- [ ] Schedule tab: on/off times, dim schedule with time picker +- [ ] Fonts tab: list installed fonts, upload new fonts +- [ ] Wi-Fi tab: scan networks, connect to a network +- [ ] All settings saved via config API with toast notifications + +--- + +## Implementation Checklist + +### 1. Create settings module structure + +- [ ] Create `frontend/src/app/features/settings/` directory +- [ ] Add lazy route in `app.routes.ts`: `{ path: 'settings', loadComponent: () => import(...) }` + +### 2. Build tabbed layout + +- [ ] Create `SettingsComponent` using PrimeNG `TabView` with tab panels +- [ ] Each tab is a standalone child component for separation of concerns + +### 3. General settings tab + +- [ ] Create `GeneralSettingsComponent` +- [ ] Brightness slider using PrimeNG `Slider` +- [ ] Rotation dropdown (0, 90, 180, 270 degrees) +- [ ] Matrix dimensions display (read-only, from system config) + +### 4. Display settings tab + +- [ ] Create `DisplaySettingsComponent` +- [ ] Plugin duration configuration per-plugin using PrimeNG `InputNumber` +- [ ] Transition type dropdown (redraw, fade, slide) +- [ ] Transition speed slider + +### 5. Schedule settings tab + +- [ ] Create `ScheduleSettingsComponent` +- [ ] On/off schedule with PrimeNG `Calendar` time pickers +- [ ] Dim schedule entries with time range and brightness level +- [ ] Add/remove dim schedule entries + +### 6. Fonts tab + +- [ ] Create `FontsSettingsComponent` +- [ ] List installed fonts from `GET /api/v3/fonts` +- [ ] Upload font via PrimeNG `FileUpload` to `POST /api/v3/fonts/upload` +- [ ] Show upload progress and success/error feedback + +### 7. Wi-Fi tab + +- [ ] Create `WifiSettingsComponent` +- [ ] Scan button triggers `GET /api/v3/wifi/scan` +- [ ] Display available networks in PrimeNG `Table` +- [ ] Connect dialog with password input using PrimeNG `Dialog` + `Password` + +### 8. Commit + +```bash +git add frontend/src/app/features/settings/ +git commit -m "feat(frontend): add settings module with tabbed config UI" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Settings components exist +test -f frontend/src/app/features/settings/settings.component.ts && echo "OK: settings component" +test -f frontend/src/app/features/settings/general/general-settings.component.ts && echo "OK: general tab" +test -f frontend/src/app/features/settings/display/display-settings.component.ts && echo "OK: display tab" +test -f frontend/src/app/features/settings/schedule/schedule-settings.component.ts && echo "OK: schedule tab" +test -f frontend/src/app/features/settings/fonts/fonts-settings.component.ts && echo "OK: fonts tab" +test -f frontend/src/app/features/settings/wifi/wifi-settings.component.ts && echo "OK: wifi tab" + +# 2. Route configured +grep -q "settings" frontend/src/app/app.routes.ts && echo "OK: settings route" + +# 3. Build succeeds +cd frontend && npx ng build && echo "OK: build with settings module" +``` + +--- + +## Notes + +- The existing HTMX partials make heavy use of `hx-post` for inline saves. The Angular version uses explicit Save buttons with form validation. +- Wi-Fi scan may not work in emulator/development environments. Handle the 503 response gracefully with a "Wi-Fi not available" message. +- Font upload uses multipart form data. PrimeNG `FileUpload` handles this natively. +- The raw JSON editor (`raw_json.html` in HTMX) is deferred to SPIKE-002 -- it is a power-user feature. +- Schedule times should use 24-hour format for consistency with the backend config. diff --git a/sprints/v3.0.0/FRONT-007-logs-store-modules.md b/sprints/v3.0.0/FRONT-007-logs-store-modules.md new file mode 100644 index 000000000..1da65673a --- /dev/null +++ b/sprints/v3.0.0/FRONT-007-logs-store-modules.md @@ -0,0 +1,115 @@ +# FRONT-007 — Logs and Store Feature Modules + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** [FRONT-003](FRONT-003-api-service-layer.md), [FRONT-002](FRONT-002-primeng-theme-layout.md) +**Blocks:** _(none)_ + +--- + +## Context + +Two remaining feature modules from the ROADMAP: Logs (live log stream viewer) and Store (plugin marketplace). These replace the HTMX `logs.html` partial and the plugin store functionality in the existing UI. + +**Logs:** The backend streams log entries via SSE at `/api/v3/stream/logs` (every ~5 seconds) and provides historical logs via `GET /api/v3/logs`. The current HTMX version renders logs as a scrolling text area with auto-scroll. + +**Store:** The backend provides store operations at `/api/v3/plugins/store/` for browsing available plugins, installing, updating, and uninstalling. The current HTMX version uses `plugins_manager.js` for store interactions. + +--- + +## Acceptance Criteria + +- [ ] Logs route is lazy-loaded at `/logs` +- [ ] Logs view shows live streaming log entries via SSE +- [ ] Log entries are syntax-highlighted by level (error=red, warn=yellow, info=default, debug=gray) +- [ ] Auto-scroll to bottom with toggle to pause auto-scroll +- [ ] Log level filter (all, error, warn, info, debug) +- [ ] Store route is lazy-loaded at `/store` +- [ ] Store view lists available plugins from the registry with search +- [ ] Each store card shows: name, description, version, installed status +- [ ] Install button triggers `POST /api/v3/plugins/store/install` +- [ ] Update button visible when newer version available + +--- + +## Implementation Checklist + +### 1. Create logs module + +- [ ] Create `frontend/src/app/features/logs/` directory +- [ ] Add lazy route in `app.routes.ts`: `{ path: 'logs', loadComponent: () => import(...) }` +- [ ] Create `LogViewerComponent` as the main component + +### 2. Build log viewer + +- [ ] Subscribe to `SseService.logStream$` for live log entries +- [ ] Display in a virtual-scroll container (PrimeNG `VirtualScroller` or custom) +- [ ] Color-code log entries by level using CSS classes +- [ ] Auto-scroll to newest entry by default +- [ ] "Pause scroll" toggle button (PrimeNG `ToggleButton`) to freeze scroll position +- [ ] Log level filter dropdown using PrimeNG `Dropdown` +- [ ] "Clear" button to reset the displayed log buffer (client-side only) + +### 3. Create store module + +- [ ] Create `frontend/src/app/features/store/` directory +- [ ] Add lazy route in `app.routes.ts`: `{ path: 'store', loadComponent: () => import(...) }` +- [ ] Create `StoreComponent` as the main component + +### 4. Build store plugin browser + +- [ ] Fetch available plugins from `GET /api/v3/plugins/store/available` +- [ ] Display in PrimeNG `DataView` with grid layout +- [ ] Search bar with PrimeNG `InputText` filtering by name and description +- [ ] Each card shows: plugin name, description, latest version, author +- [ ] "Installed" badge on plugins that are already installed +- [ ] "Update available" badge when installed version < store version + +### 5. Add install/update/uninstall actions + +- [ ] Install button calls `POST /api/v3/plugins/store/install` with `{ plugin_id: ... }` +- [ ] Update button calls `POST /api/v3/plugins/store/update` with `{ plugin_id: ... }` +- [ ] Uninstall button with confirmation dialog calls `POST /api/v3/plugins/store/uninstall` +- [ ] Show PrimeNG `ProgressSpinner` during install/update operations +- [ ] Toast notification on success/failure + +### 6. Commit + +```bash +git add frontend/src/app/features/logs/ frontend/src/app/features/store/ +git commit -m "feat(frontend): add logs viewer and plugin store modules" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Log components exist +test -f frontend/src/app/features/logs/log-viewer/log-viewer.component.ts && echo "OK: log viewer" + +# 2. Store components exist +test -f frontend/src/app/features/store/store.component.ts && echo "OK: store component" + +# 3. Routes configured +grep -q "logs" frontend/src/app/app.routes.ts && echo "OK: logs route" +grep -q "store" frontend/src/app/app.routes.ts && echo "OK: store route" + +# 4. Build succeeds +cd frontend && npx ng build && echo "OK: build with logs and store" +``` + +--- + +## Notes + +- The log stream SSE sends batches of log lines every ~5 seconds. Parse the JSON payload to extract individual log entries. +- Virtual scrolling is important for logs performance. Without it, accumulating thousands of log entries will degrade browser performance. Cap the client-side buffer at ~5000 entries and discard oldest. +- The store API may return a 503 if the registry is unreachable. Show an "Unable to reach plugin store" empty state. +- Install/update operations can take 10-30 seconds (pip install + dependency resolution). The UI must remain responsive during this time. +- The `operation-history` partial from HTMX is deferred to SPIKE-003 -- it shows recent store operations. diff --git a/sprints/v3.0.0/FRONT-008-htmx-removal-cleanup.md b/sprints/v3.0.0/FRONT-008-htmx-removal-cleanup.md new file mode 100644 index 000000000..b4f98f357 --- /dev/null +++ b/sprints/v3.0.0/FRONT-008-htmx-removal-cleanup.md @@ -0,0 +1,122 @@ +# FRONT-008 — HTMX Removal and Legacy Frontend Cleanup + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Chore +**Depends on:** [FRONT-004](FRONT-004-dashboard-module.md), [FRONT-005](FRONT-005-plugins-module.md), [FRONT-006](FRONT-006-settings-module.md), [FRONT-007](FRONT-007-logs-store-modules.md) +**Blocks:** _(none)_ + +--- + +## Context + +Once all feature modules are implemented in Angular, the legacy Jinja2/HTMX frontend can be removed. This ticket deletes the old templates, static files, and the pages router, and updates FastAPI to serve only the Angular SPA. + +Files to remove: +- `web_interface/templates/` -- all Jinja2 templates +- `web_interface/static/` -- all CSS, JS, images (HTMX, Alpine.js, Tailwind, app.js, etc.) +- `src/api/routers/pages.py` -- HTMX page routes +- HTMX/Alpine.js references in any remaining code + +Files to preserve: +- `web_interface/cache.py` -- if still used by backend services +- `web_interface/__init__.py` -- if used as a Python package + +--- + +## Acceptance Criteria + +- [ ] `web_interface/templates/` directory is deleted +- [ ] `web_interface/static/` directory is deleted +- [ ] `src/api/routers/pages.py` is deleted +- [ ] `pages_router` removed from `src/api/main.py` router includes +- [ ] `/v3` route no longer serves HTMX content +- [ ] `GET /` redirects to Angular SPA (or serves `index.html`) +- [ ] `htmx`, `alpinejs`, and related JS libraries removed from the project +- [ ] `Jinja2` dependency removed from `pyproject.toml` if no longer used elsewhere + +--- + +## Implementation Checklist + +### 1. Verify Angular SPA is complete + +- [ ] Confirm all 5 feature modules (Dashboard, Plugins, Settings, Logs, Store) are functional +- [ ] Run `ng build` to produce the production bundle +- [ ] Verify SPA serves correctly from FastAPI + +### 2. Remove HTMX pages router + +- [ ] Delete `src/api/routers/pages.py` +- [ ] Remove `pages_router` import and `app.include_router(pages_router)` from `src/api/main.py` +- [ ] Remove `"pages"` from `openapi_tags` in `src/api/main.py` + +### 3. Delete legacy frontend files + +- [ ] Delete `web_interface/templates/` directory entirely +- [ ] Delete `web_interface/static/` directory entirely +- [ ] Check if `web_interface/cache.py` is still imported elsewhere; if not, delete it too + +### 4. Update FastAPI static file mounts + +- [ ] Remove the `web_interface/static` mount from `src/api/main.py` +- [ ] Ensure the Angular SPA mount at `/` is the primary file server +- [ ] Update the root redirect: `GET /` serves `index.html` (Angular handles routing) + +### 5. Clean up dependencies + +- [ ] Check if `Jinja2` is still needed by any code (FastAPI uses it for `Jinja2Templates`) +- [ ] If Jinja2 is no longer needed, remove it from `pyproject.toml` +- [ ] Remove `python-multipart` only if no longer used by file upload routes (it likely IS still used) + +### 6. Update tests + +- [ ] Remove or update any tests that reference HTMX endpoints (`/v3/*`) +- [ ] Update any test fixtures that assume `web_interface/templates/` exists +- [ ] Ensure all remaining API tests still pass + +### 7. Commit + +```bash +git add -A +git commit -m "chore(frontend): remove HTMX templates and legacy static files" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Legacy directories are gone +test ! -d web_interface/templates && echo "OK: templates removed" +test ! -d web_interface/static && echo "OK: static removed" + +# 2. Pages router is gone +test ! -f src/api/routers/pages.py && echo "OK: pages router removed" + +# 3. No HTMX references remain +! grep -r "htmx" src/ frontend/ --include="*.py" --include="*.ts" && echo "OK: no htmx refs" + +# 4. Angular SPA serves correctly +test -f frontend/dist/ledmatrix/browser/index.html && echo "OK: SPA bundle exists" + +# 5. API still works (imports OK) +python3 -c "from src.api.main import app; print(f'Routes: {len(app.routes)}'); print('OK: app loads')" + +# 6. Tests pass +# distrobox enter debian-trixie -- bash -c 'uv sync --extra test --extra dev --extra emulator && EMULATOR=true .venv/bin/pytest test/ -q --override-ini="addopts=" --ignore=test/plugins' +``` + +--- + +## Notes + +- This is a destructive operation. Ensure all Angular feature modules are complete and tested before executing this ticket. +- The `web_interface/` directory may still be needed as a Python package if other code imports from it. Check for imports before deleting `__init__.py`. +- The `web_interface_v2` compatibility shim (created in Phase 2, SPIKE-001) lives in `src/web_interface/` or `web_interface_v2.py` -- do NOT remove it. It is needed until Phase 9. +- If `Jinja2` is still used by any backend code (error pages, email templates, etc.), keep it as a dependency. +- The `Jinja2Templates` import in `src/api/` should be removed along with the pages router. diff --git a/sprints/v3.0.0/README.md b/sprints/v3.0.0/README.md new file mode 100644 index 000000000..64630fef4 --- /dev/null +++ b/sprints/v3.0.0/README.md @@ -0,0 +1,123 @@ +# Sprint v3.0.0 -- Frontend Modernization + +**Goal:** Replace the Jinja2/HTMX frontend with an Angular 17+ SPA using PrimeNG, featuring lazy-loaded feature modules, real-time SSE streams, and a dark-first responsive design. + +**ROADMAP phase:** Phase 3 + +--- + +## Tickets + +| ID | Title | Status | Depends On | +|---|---|---|---| +| [FRONT-001](FRONT-001-angular-project-scaffold.md) | Angular project scaffold | Open | -- | +| [FRONT-002](FRONT-002-primeng-theme-layout.md) | PrimeNG integration and dark theme layout | Open | FRONT-001 | +| [FRONT-003](FRONT-003-api-service-layer.md) | API service layer and SSE client | Open | FRONT-001 | +| [FRONT-004](FRONT-004-dashboard-module.md) | Dashboard feature module | Open | FRONT-002, FRONT-003 | +| [FRONT-005](FRONT-005-plugins-module.md) | Plugins feature module | Open | FRONT-002, FRONT-003 | +| [FRONT-006](FRONT-006-settings-module.md) | Settings feature module | Open | FRONT-002, FRONT-003 | +| [FRONT-007](FRONT-007-logs-store-modules.md) | Logs and Store feature modules | Open | FRONT-002, FRONT-003 | +| [FRONT-008](FRONT-008-htmx-removal-cleanup.md) | HTMX removal and legacy frontend cleanup | Open | FRONT-004, FRONT-005, FRONT-006, FRONT-007 | +| [SPIKE-001](SPIKE-001-angular-unit-test-setup.md) | Angular unit test setup | Open | FRONT-001 | +| [SPIKE-002](SPIKE-002-raw-json-editor.md) | Raw JSON config editor | Open | FRONT-006 | +| [SPIKE-003](SPIKE-003-operation-history-view.md) | Operation history view | Open | FRONT-007 | +| [SPIKE-004](SPIKE-004-ci-angular-build.md) | CI pipeline for Angular build and tests | Open | FRONT-001, SPIKE-001 | +| [SPIKE-005](SPIKE-005-starlark-config-ui.md) | Starlark configuration UI | Open | FRONT-006 | + +## Dependency Graph + +``` +FRONT-001 (Angular scaffold) + +-- FRONT-002 (PrimeNG + dark theme layout) + | +-- FRONT-004 (Dashboard module) + | +-- FRONT-005 (Plugins module) + | +-- FRONT-006 (Settings module) + | | +-- SPIKE-002 (Raw JSON editor) + | | +-- SPIKE-005 (Starlark config UI) + | +-- FRONT-007 (Logs + Store modules) + | +-- SPIKE-003 (Operation history) + +-- FRONT-003 (API service layer + SSE) + | +-- FRONT-004 (Dashboard module) + | +-- FRONT-005 (Plugins module) + | +-- FRONT-006 (Settings module) + | +-- FRONT-007 (Logs + Store modules) + +-- SPIKE-001 (Angular test setup) + | +-- SPIKE-004 (CI Angular build) + +-- SPIKE-004 (CI Angular build) + +FRONT-004 + FRONT-005 + FRONT-006 + FRONT-007 + +-- FRONT-008 (HTMX removal + cleanup) +``` + +## Definition of Done (Phase 3) + +- [ ] Angular 17+ SPA in `frontend/` with PrimeNG component library +- [ ] Dark-first theme active by default, responsive layout (mobile/tablet/desktop) +- [ ] Five lazy-loaded feature modules: Dashboard, Plugins, Settings, Logs, Store +- [ ] Dashboard shows real-time system metrics and display preview via SSE +- [ ] Plugin config forms dynamically generated from JSON Schema +- [ ] All HTMX templates and legacy static files removed +- [ ] `src/api/routers/pages.py` (HTMX page routes) removed +- [ ] FastAPI serves the built Angular SPA from `/` +- [ ] `ng build` produces a valid production bundle +- [ ] Angular unit tests pass in CI (headless Chrome) +- [ ] No regressions in backend Python tests +- [ ] Plugin impact: none (Phase 3 is frontend-only; no plugin API changes) + +## Architecture Notes + +### New directory structure after Phase 3 + +``` +frontend/ + angular.json + package.json + proxy.conf.json + src/ + app/ + app.component.ts + app.config.ts + app.routes.ts + core/ + models/ # TypeScript interfaces matching Pydantic models + services/ # ApiService, SseService, SystemService, etc. + interceptors/ # Error interceptor + layout/ + app-layout.component.ts + sidebar/ + topbar/ + features/ + dashboard/ # System stats, active plugin, display preview + plugins/ # Plugin list, config editor, schema-driven forms + settings/ # Tabbed config: general, display, schedule, fonts, wifi + logs/ # Live log stream viewer + store/ # Plugin marketplace browser + shared/ + loading/ + error-state/ + empty-state/ + schema-form/ # Dynamic JSON Schema form generator + environments/ + dist/ + ledmatrix/ + browser/ # Production build output, served by FastAPI +``` + +### Files removed in Phase 3 + +- `web_interface/templates/` -- all Jinja2/HTMX templates (16 files) +- `web_interface/static/` -- all CSS, JS, images (htmx, alpine, tailwind, app.js) +- `src/api/routers/pages.py` -- HTMX page router + +### Files preserved + +- `web_interface/cache.py` -- if still used by backend services +- `web_interface_v2.py` / `src/web_interface/` -- compatibility shim (until Phase 9) + +### Key technical decisions + +- **Angular 17+ standalone components** -- no NgModules, simplifies lazy loading +- **PrimeNG v17+** -- standalone component imports, Aura Dark theme preset +- **SSE via native EventSource** -- no WebSocket (backend only supports SSE currently) +- **Dynamic JSON Schema forms** -- plugin config forms generated from `config_schema.json` +- **SPA serving** -- FastAPI mounts `frontend/dist/` with catch-all for client-side routing diff --git a/sprints/v3.0.0/SPIKE-001-angular-unit-test-setup.md b/sprints/v3.0.0/SPIKE-001-angular-unit-test-setup.md new file mode 100644 index 000000000..4a4a2a45e --- /dev/null +++ b/sprints/v3.0.0/SPIKE-001-angular-unit-test-setup.md @@ -0,0 +1,90 @@ +# SPIKE-001 — Angular Unit Test Setup + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Chore +**Depends on:** [FRONT-001](FRONT-001-angular-project-scaffold.md) +**Blocks:** _(none)_ + +--- + +## Context + +Angular CLI generates a Karma/Jasmine test setup by default. This ticket ensures the test infrastructure works, configures code coverage reporting, and establishes patterns for testing components and services. This enables TDD for the feature module tickets (FRONT-004 through FRONT-007). + +--- + +## Acceptance Criteria + +- [ ] `ng test` runs successfully with default test runner +- [ ] Coverage report is generated (Istanbul/Karma coverage reporter) +- [ ] At least one service test exists (e.g., `ApiService` smoke test) +- [ ] At least one component test exists (e.g., `AppComponent` renders) +- [ ] `HttpClientTestingModule` pattern documented for API service tests +- [ ] CI-compatible headless browser configuration (Chrome headless) + +--- + +## Implementation Checklist + +### 1. Verify default test setup + +- [ ] Run `ng test --watch=false --browsers=ChromeHeadless` and confirm it passes +- [ ] Fix any configuration issues with Karma or test runner + +### 2. Configure coverage + +- [ ] Add `--code-coverage` flag to test script in `package.json` +- [ ] Configure `karma.conf.js` coverage reporter to output `lcov` format +- [ ] Verify coverage report generates in `frontend/coverage/` + +### 3. Add service test pattern + +- [ ] Create `frontend/src/app/core/services/api.service.spec.ts` +- [ ] Test that `ApiService` is injectable +- [ ] Test that `get()` sends HTTP request with correct base URL +- [ ] Use `HttpClientTestingModule` and `HttpTestingController` + +### 4. Add component test pattern + +- [ ] Verify `app.component.spec.ts` exists and passes +- [ ] Add test that app component renders without errors + +### 5. Configure headless CI mode + +- [ ] Ensure `karma.conf.js` has a headless Chrome configuration +- [ ] Add `npm run test:ci` script: `ng test --watch=false --browsers=ChromeHeadless --code-coverage` + +### 6. Commit + +```bash +git add frontend/ +git commit -m "chore(frontend): configure Angular test infrastructure with coverage" +``` + +--- + +## Verification Steps + +Run these commands after implementation; every one must pass before closing this ticket. + +```bash +# 1. Tests run and pass +cd frontend && npx ng test --watch=false --browsers=ChromeHeadless && echo "OK: tests pass" + +# 2. Coverage directory generated +test -d frontend/coverage && echo "OK: coverage generated" + +# 3. CI test script exists +grep -q "test:ci" frontend/package.json && echo "OK: ci test script" +``` + +--- + +## Notes + +- Angular 17+ projects may use either Karma/Jasmine or the newer `@angular/testing` with Jest-like APIs. Use whatever `ng new` generated by default. +- Headless Chrome may need to be installed in the distrobox or CI environment. Document any required system dependencies. +- This ticket does NOT require high coverage. It establishes the infrastructure; coverage will grow as feature modules are implemented. diff --git a/sprints/v3.0.0/SPIKE-002-raw-json-editor.md b/sprints/v3.0.0/SPIKE-002-raw-json-editor.md new file mode 100644 index 000000000..6d7bda573 --- /dev/null +++ b/sprints/v3.0.0/SPIKE-002-raw-json-editor.md @@ -0,0 +1,82 @@ +# SPIKE-002 — Raw JSON Config Editor + +> **For Claude:** Use `superpowers:writing-plans` before touching any files. Use `superpowers:test-driven-development` for any logic you add. + +**Status:** Open +**Phase:** v3.0.0 — Frontend Modernization +**Type:** Feat +**Depends on:** [FRONT-006](FRONT-006-settings-module.md) +**Blocks:** _(none)_ + +--- + +## Context + +The HTMX frontend had a "Raw JSON" editor (`web_interface/templates/v3/partials/raw_json.html`) that allows power users to directly edit the full `config.json` and `config_secrets.json` files. This is a power-user feature that should be preserved in the Angular SPA. + +The backend provides: +- `POST /api/v3/config/raw/main` -- overwrite full config with raw JSON +- `POST /api/v3/config/raw/secrets` -- overwrite full secrets with raw JSON + +--- + +## Acceptance Criteria + +- [ ] Raw JSON editor accessible from Settings page (new tab or sub-route) +- [ ] Code editor component with JSON syntax highlighting +- [ ] JSON validation before save (parse check + optional schema validation) +- [ ] Separate editors for main config and secrets config +- [ ] Confirmation dialog before overwriting ("This will replace the entire config") +- [ ] Success/error toast on save + +--- + +## Implementation Checklist + +### 1. Add code editor dependency + +- [ ] Install a JSON editor library (e.g., `monaco-editor` via `ngx-monaco-editor` or PrimeNG `Editor`) +- [ ] If Monaco is too heavy, use a simple `