feat(service-integrations): phase 2 — integration widget & app form UI
- Add 6 renderer components: StatCard, Gauge, List, Progress, AlertBanner, Chart - Add IntegrationWidget container with auto-refresh, loading, error states - Add IntegrationAlertOverlay for layout-level critical alerts - Add IntegrationConfigFields for dynamic form generation from Zod schemas - Register integration type in WidgetRenderer - Extend WidgetCreationForm with integration app/endpoint pickers - Extend AppForm with integration config section and test connection button - Add /api/integrations/alerts endpoint
This commit is contained in:
@@ -0,0 +1,57 @@
|
||||
# Feature Context: Service Integrations
|
||||
|
||||
## Configuration
|
||||
- **Development mode:** Automated
|
||||
- **Execution mode:** Orchestrator
|
||||
- **Strategy:** Big Bang
|
||||
- **Build:** `npm run build`
|
||||
- **Test:** `npm test`
|
||||
- **Lint:** `npm run lint`
|
||||
- **Check:** `npm run check`
|
||||
- **Dev server:** `npm run dev` (port: 5173)
|
||||
|
||||
## Current State
|
||||
Feature not yet started. Codebase is stable on master with 14 widget types, full app CRUD, healthcheck system, and notification infrastructure.
|
||||
|
||||
## Existing Patterns to Follow
|
||||
- **Service pattern**: See `appService.ts`, `metricService.ts`, `systemStatsService.ts` for adapter/client/transform pattern
|
||||
- **Caching**: `metricService.ts` has TTL-based cache — reuse for integration data
|
||||
- **API envelope**: All routes use `success()`, `error()`, `paginated()` from response helpers
|
||||
- **Zod validation**: All inputs validated via Zod schemas in `validators.ts`
|
||||
- **Widget rendering**: `WidgetRenderer.svelte` dispatches to type-specific components
|
||||
- **Config storage**: Widget configs stored as stringified JSON in `Widget.config`
|
||||
- **Encrypted JSON**: `SystemSettings.oauthConfig` pattern for storing credentials
|
||||
|
||||
## Temporary Workarounds
|
||||
(none yet)
|
||||
|
||||
## Cross-Phase Dependencies
|
||||
- Phase 1 (architecture) must complete before all other phases
|
||||
- Phase 2 (UI) must complete before Phase 10 (polish)
|
||||
- Phases 3-9 (individual integrations) depend only on Phase 1
|
||||
- Phase 10 depends on all prior phases
|
||||
|
||||
## Deferred Work
|
||||
(none yet)
|
||||
|
||||
## Failed Approaches
|
||||
(none yet)
|
||||
|
||||
## Review Findings Log
|
||||
(none yet)
|
||||
|
||||
## Phase Execution Log
|
||||
| Phase | Agent Used | Test Writer | Parallel | Notes |
|
||||
|-------|-----------|-------------|----------|-------|
|
||||
| (not started) | | | | |
|
||||
|
||||
## Environment & Runtime Notes
|
||||
- Platform: Windows 10, Git Bash shell
|
||||
- Database: SQLite via Prisma
|
||||
- NUT integration requires raw TCP socket (Node `net` module)
|
||||
- Deluge uses JSON-RPC, NPM uses session-based auth
|
||||
|
||||
## Implementation Notes
|
||||
- Integration credentials stored encrypted in `integrationConfig` (JSON string on App model)
|
||||
- NUT is the only non-HTTP integration — uses direct TCP protocol
|
||||
- Alert banners (NUT on-battery, Authentik brute-force) need layout-level rendering, not just widget-level
|
||||
@@ -0,0 +1,57 @@
|
||||
# Feature: Service Integrations
|
||||
|
||||
**Branch:** `feature/service-integrations`
|
||||
**Base branch:** `master`
|
||||
**Created:** 2026-03-25
|
||||
**Status:** 🟡 In Progress
|
||||
**Strategy:** Big Bang
|
||||
**Mode:** Automated
|
||||
**Execution:** Orchestrator
|
||||
|
||||
## Summary
|
||||
|
||||
Transform the dashboard from a link page into a real-time command center by pulling live data from self-hosted services. Integrations are associated with apps — when you register Pi-hole as an app, you attach the "Pi-hole" integration to it. A new `integration` widget type displays live data endpoints with specialized renderers (gauges, stat cards, lists, charts, progress bars, alert banners).
|
||||
|
||||
## Build & Test Commands
|
||||
- **Build:** `npm run build`
|
||||
- **Test:** `npm test`
|
||||
- **Lint:** `npm run lint`
|
||||
- **Check:** `npm run check`
|
||||
|
||||
## Phases
|
||||
|
||||
- [ ] Phase 1: Integration Architecture Foundation [domain: backend] → [subplan](./phase-1-architecture.md)
|
||||
- [ ] Phase 2: Integration Widget & App Form UI [domain: frontend] → [subplan](./phase-2-widget-ui.md)
|
||||
- [ ] Phase 3: NUT/UPS Integration [domain: backend] → [subplan](./phase-3-nut.md)
|
||||
- [ ] Phase 4: Pi-hole Integration [domain: backend] → [subplan](./phase-4-pihole.md)
|
||||
- [ ] Phase 5: Portainer Integration [domain: backend] → [subplan](./phase-5-portainer.md)
|
||||
- [ ] Phase 6: Gitea Integration [domain: backend] → [subplan](./phase-6-gitea.md)
|
||||
- [ ] Phase 7: Nginx Proxy Manager Integration [domain: backend] → [subplan](./phase-7-npm.md)
|
||||
- [ ] Phase 8: Authentik Integration [domain: backend] → [subplan](./phase-8-authentik.md)
|
||||
- [ ] Phase 9: Media Integrations (Emby + Immich + Deluge + MeTube) [domain: backend] → [subplan](./phase-9-media.md)
|
||||
- [ ] Phase 10: Planka Integration + Polish [domain: fullstack] → [subplan](./phase-10-planka.md)
|
||||
|
||||
## Phase Progress Log
|
||||
|
||||
| Phase | Domain | Status | Review | Build | Committed |
|
||||
|-------|--------|--------|--------|-------|-----------|
|
||||
| Phase 1: Architecture | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 2: Widget & App Form UI | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 3: NUT/UPS | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 4: Pi-hole | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 5: Portainer | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 6: Gitea | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 7: Nginx Proxy Manager | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 8: Authentik | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 9: Media (Emby+Immich+Deluge+MeTube) | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
| Phase 10: Planka + Polish | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ |
|
||||
|
||||
## Parallel Execution Plan
|
||||
|
||||
Phases 3+4 (NUT + Pi-hole), 5+6 (Portainer + Gitea), and 7+8 (NPM + Authentik) are independent pairs that can run in parallel.
|
||||
|
||||
## Final Review
|
||||
- [ ] Comprehensive code review
|
||||
- [ ] Full build passes
|
||||
- [ ] Full test suite passes
|
||||
- [ ] Merged to `master`
|
||||
@@ -0,0 +1,62 @@
|
||||
# Phase 1: Integration Architecture Foundation
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Build the core integration framework: TypeScript interfaces, registry pattern, shared cache, Prisma schema changes, API routes, and updated app service. This phase unlocks all subsequent integration phases.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/types.ts` — Define `Integration`, `IntegrationEndpoint`, `IntegrationData`, `IntegrationConfig` interfaces. Each integration has: id, name, icon, authConfigSchema (Zod), extraConfigSchema (optional Zod), endpoints array, testConnection method, fetchData method.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/registry.ts` — Registry singleton with `register(integration)`, `get(id)`, `list()`, `getForApp(app)` methods. Auto-imports integrations from subdirectories.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/cache.ts` — TTL-based cache for integration data. Key: `${appId}:${endpointId}`, configurable TTL per endpoint. Reuse pattern from `metricService.ts`.
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/encryption.ts` — Encrypt/decrypt integration config JSON using AES-256-GCM with key from `INTEGRATION_ENCRYPTION_KEY` env var (fallback to `JWT_SECRET` for dev).
|
||||
- [ ] Task 5: Update Prisma schema — Add `integrationType String?`, `integrationConfig String?`, `integrationEnabled Boolean @default(false)` to `App` model. Run `npx prisma db push`.
|
||||
- [ ] Task 6: Update `src/lib/types/app.ts` — Add integration fields to `AppRecord` interface.
|
||||
- [ ] Task 7: Update `src/lib/server/services/appService.ts` — Handle integration fields on create/update. Encrypt `integrationConfig` before storing, decrypt on read.
|
||||
- [ ] Task 8: Update `src/lib/utils/validators.ts` — Add `integration` to `WidgetType` enum. Add Zod schema for integration widget config: `{ appId: string, endpointId: string, refreshInterval?: number }`.
|
||||
- [ ] Task 9: Create API route `src/routes/api/integrations/+server.ts` — `GET` returns list of available integration types with their endpoints and config schemas.
|
||||
- [ ] Task 10: Create API route `src/routes/api/integrations/test/+server.ts` — `POST { appId, integrationType, config }` tests connection to the service.
|
||||
- [ ] Task 11: Create API route `src/routes/api/integrations/[appId]/data/[endpointId]/+server.ts` — `GET` fetches live data from integration endpoint, uses cache.
|
||||
- [ ] Task 12: Create `src/lib/server/integrations/base.ts` — Abstract base class or helper functions for common integration patterns (HTTP fetch with timeout, error wrapping, response parsing).
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/types.ts` — new: core interfaces
|
||||
- `src/lib/server/integrations/registry.ts` — new: integration registry
|
||||
- `src/lib/server/integrations/cache.ts` — new: TTL cache
|
||||
- `src/lib/server/integrations/encryption.ts` — new: config encryption
|
||||
- `src/lib/server/integrations/base.ts` — new: shared helpers
|
||||
- `prisma/schema.prisma` — modify: add 3 fields to App model
|
||||
- `src/lib/types/app.ts` — modify: add integration fields
|
||||
- `src/lib/server/services/appService.ts` — modify: handle integration fields
|
||||
- `src/lib/utils/validators.ts` — modify: add integration widget type + config schema
|
||||
- `src/routes/api/integrations/+server.ts` — new: list integrations
|
||||
- `src/routes/api/integrations/test/+server.ts` — new: test connection
|
||||
- `src/routes/api/integrations/[appId]/data/[endpointId]/+server.ts` — new: fetch data
|
||||
|
||||
## Acceptance Criteria
|
||||
- Integration interfaces are well-typed and extensible
|
||||
- Registry can register and retrieve integrations
|
||||
- Cache prevents repeated API calls within TTL
|
||||
- Prisma schema has integration fields, migration runs clean
|
||||
- App service encrypts/decrypts integration config transparently
|
||||
- API routes return proper envelope responses
|
||||
- All Zod schemas validate correctly
|
||||
|
||||
## Notes
|
||||
- Encryption key: use `INTEGRATION_ENCRYPTION_KEY` env var, fallback to `JWT_SECRET` for development simplicity
|
||||
- The registry should be designed so adding a new integration is just: create a directory, implement the interface, register it
|
||||
- Cache should handle concurrent requests to the same endpoint gracefully
|
||||
- Big Bang strategy: build/tests may not pass after this phase since the integration widget type is registered but has no frontend renderer yet
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Code follows project conventions
|
||||
- [ ] No unintended side effects
|
||||
- [ ] Types are comprehensive and well-documented
|
||||
- [ ] Encryption is properly implemented (no plaintext secrets in DB)
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,59 @@
|
||||
# Phase 10: Planka Integration + Polish
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** fullstack
|
||||
|
||||
## Objective
|
||||
Implement the Planka integration for task/project management visibility, then polish all integration components with proper error states, loading skeletons, empty states, and consistent styling.
|
||||
|
||||
## Tasks
|
||||
|
||||
### Planka Integration
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/planka/schema.ts` — Auth config: `{ email: string, password: string }`.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/planka/client.ts` — HTTP client. Session-based auth (POST `/api/access-tokens` → Bearer token). Endpoints: `/api/cards`, `/api/boards`.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/planka/transform.ts` — My cards → list with board/list context, overdue → list (red highlight), board summary → stat-card (card counts by list).
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/planka/index.ts` — Endpoints: `my-cards` (list), `overdue` (list), `board-summary` (stat-card).
|
||||
- [ ] Task 5: Register Planka integration in registry.
|
||||
|
||||
### Polish & Error Handling
|
||||
- [ ] Task 6: Add loading skeleton states to all renderer components (StatCard, Gauge, List, Progress, Chart).
|
||||
- [ ] Task 7: Add empty state messaging to all renderers ("No data available", "No active torrents", etc.).
|
||||
- [ ] Task 8: Add error state handling to IntegrationWidget — show error message with retry button when fetch fails.
|
||||
- [ ] Task 9: Verify all integrations handle network timeouts, invalid credentials, and unexpected response formats gracefully.
|
||||
- [ ] Task 10: Add integration type icons to the app form dropdown and widget creation form.
|
||||
- [ ] Task 11: Ensure all renderers respect card sizes (compact/medium/large) and are responsive.
|
||||
- [ ] Task 12: Review and standardize all integration endpoint refresh intervals (sensible defaults).
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/planka/{schema,client,transform,index}.ts` — new (4 files)
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register Planka
|
||||
- `src/lib/components/widget/integration/*.svelte` — modify: add loading/empty/error states
|
||||
- `src/lib/components/widget/integration/IntegrationWidget.svelte` — modify: error handling + retry
|
||||
- `src/lib/components/app/AppForm.svelte` — modify: integration type icons
|
||||
|
||||
## Acceptance Criteria
|
||||
- Planka: my cards list, overdue cards highlighted, board summary
|
||||
- All renderers have loading, empty, and error states
|
||||
- All integrations handle network errors gracefully
|
||||
- Consistent styling across all integration components
|
||||
- Responsive layout on mobile
|
||||
- Build passes, tests pass, lint clean
|
||||
|
||||
## Notes
|
||||
- Planka uses session-based auth similar to NPM — reuse the pattern
|
||||
- This is the final phase — build and tests MUST pass here (Big Bang strategy final gate)
|
||||
- Polish should cover ALL renderers and integrations, not just Planka
|
||||
- Overdue detection: compare card due date to current date, highlight in red
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Code follows project conventions
|
||||
- [ ] No unintended side effects
|
||||
- [ ] Build passes
|
||||
- [ ] Tests pass (new + existing)
|
||||
- [ ] All integrations tested end-to-end
|
||||
- [ ] Loading/error/empty states verified
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Final phase — no handoff needed -->
|
||||
@@ -0,0 +1,65 @@
|
||||
# Phase 2: Integration Widget & App Form UI
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** frontend
|
||||
|
||||
## Objective
|
||||
Build the frontend components: IntegrationWidget with all endpoint renderers, extend AppForm with integration configuration UI, and update WidgetCreationForm to support integration widgets.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/components/widget/integration/IntegrationWidget.svelte` — Container component that resolves integration type from app, fetches endpoint data via `/api/integrations/[appId]/data/[endpointId]`, handles loading/error states, delegates to appropriate renderer.
|
||||
- [ ] Task 2: Create `src/lib/components/widget/integration/StatCardRenderer.svelte` — Single big number with label, optional trend arrow (up/down/flat), color-coded by threshold. Used for: query counts, session counts, library stats, etc.
|
||||
- [ ] Task 3: Create `src/lib/components/widget/integration/GaugeRenderer.svelte` — Circular SVG gauge (0-100%). Color-coded: green (<60%), yellow (60-85%), red (>85%). Used for: battery %, CPU %, disk usage.
|
||||
- [ ] Task 4: Create `src/lib/components/widget/integration/ListRenderer.svelte` — Scrollable list of items with icon, title, subtitle, optional badge. Used for: recent commits, top blocked domains, container list, etc.
|
||||
- [ ] Task 5: Create `src/lib/components/widget/integration/ProgressRenderer.svelte` — Multiple progress bars with labels and percentages. Used for: torrent downloads, download queue.
|
||||
- [ ] Task 6: Create `src/lib/components/widget/integration/AlertBannerRenderer.svelte` — Full-width alert banner with icon, message, severity (info/warning/critical). Used for: UPS on battery, brute force detection.
|
||||
- [ ] Task 7: Create `src/lib/components/widget/integration/ChartRenderer.svelte` — Simple bar or line chart using SVG. Used for: query history, uptime charts.
|
||||
- [ ] Task 8: Register `integration` widget type in `src/lib/components/widget/WidgetRenderer.svelte` — Import IntegrationWidget, add case to the type switch.
|
||||
- [ ] Task 9: Extend `src/lib/components/app/AppForm.svelte` — Add collapsible "Integration" section with: type dropdown (from `/api/integrations`), dynamic auth config fields rendered from Zod schema, "Test Connection" button, enable/disable toggle.
|
||||
- [ ] Task 10: Create `src/lib/components/app/IntegrationConfigFields.svelte` — Dynamic form field generator that renders input fields based on a Zod schema (string → text input, number → number input, boolean → toggle). Used by AppForm.
|
||||
- [ ] Task 11: Update `src/lib/components/widget/WidgetCreationForm.svelte` — Add integration widget option: app picker (only apps with integration enabled) → endpoint picker → refresh interval.
|
||||
- [ ] Task 12: Create `src/lib/components/widget/integration/IntegrationAlertOverlay.svelte` — Layout-level component that polls for critical alerts (UPS on battery, brute force) and renders AlertBannerRenderer at the top of the page. Add to root layout.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/components/widget/integration/IntegrationWidget.svelte` — new
|
||||
- `src/lib/components/widget/integration/StatCardRenderer.svelte` — new
|
||||
- `src/lib/components/widget/integration/GaugeRenderer.svelte` — new
|
||||
- `src/lib/components/widget/integration/ListRenderer.svelte` — new
|
||||
- `src/lib/components/widget/integration/ProgressRenderer.svelte` — new
|
||||
- `src/lib/components/widget/integration/AlertBannerRenderer.svelte` — new
|
||||
- `src/lib/components/widget/integration/ChartRenderer.svelte` — new
|
||||
- `src/lib/components/widget/integration/IntegrationAlertOverlay.svelte` — new
|
||||
- `src/lib/components/widget/WidgetRenderer.svelte` — modify: add integration case
|
||||
- `src/lib/components/app/AppForm.svelte` — modify: add integration section
|
||||
- `src/lib/components/app/IntegrationConfigFields.svelte` — new
|
||||
- `src/lib/components/widget/WidgetCreationForm.svelte` — modify: add integration option
|
||||
- `src/routes/+layout.svelte` — modify: add IntegrationAlertOverlay
|
||||
|
||||
## Acceptance Criteria
|
||||
- IntegrationWidget fetches data and renders correct renderer based on endpoint type
|
||||
- All 6 renderers handle loading, error, and empty states gracefully
|
||||
- AppForm shows integration config only when a type is selected
|
||||
- Dynamic form fields match the integration's auth schema
|
||||
- Test Connection button validates and shows success/failure
|
||||
- WidgetCreationForm allows creating integration widgets
|
||||
- Alert overlay polls and shows critical alerts at layout level
|
||||
|
||||
## Notes
|
||||
- Renderers should be visually consistent with existing widget styles (card sizes, colors, typography)
|
||||
- Use Svelte 5 runes ($state, $derived) for all reactive state
|
||||
- Auto-refresh: IntegrationWidget should poll at the endpoint's refreshInterval
|
||||
- Big Bang: this phase depends on Phase 1 types but the renderers can be built with mock data initially
|
||||
- ⚠️ Temporary breakage: Integration widget type is registered but no real integrations exist yet — widgets will show "no data" until Phase 3+
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Code follows project conventions
|
||||
- [ ] No unintended side effects
|
||||
- [ ] Responsive design (mobile + desktop)
|
||||
- [ ] Loading/error/empty states handled
|
||||
- [ ] Accessible (keyboard nav, screen reader labels)
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,51 @@
|
||||
# Phase 3: NUT/UPS Integration
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Implement the NUT/UPS integration using direct TCP protocol to communicate with NUT servers. This is the only non-HTTP integration — it connects directly to the NUT daemon on port 3493.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/nut/schema.ts` — Zod schemas for auth config (`{ nutHost: string, nutPort: number, upsName: string }`) and endpoint responses.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/nut/client.ts` — NUT TCP protocol client using Node `net` module. Implement commands: `LIST UPS`, `LIST VAR <upsName>`, `GET VAR <upsName> <varName>`. Parse NUT protocol responses. Handle connection timeout and cleanup.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/nut/transform.ts` — Transform raw NUT variables to widget-ready data. Map: `battery.charge` → gauge %, `ups.load` → gauge %, `battery.runtime` → stat-card (formatted as Xh Ym), `ups.status` → alert level (OL=ok, OB=warning, LB=critical).
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/nut/index.ts` — Integration implementation. Register with registry. Endpoints: `battery-status` (gauge), `load` (gauge), `runtime` (stat-card), `ups-status` (alert-banner). testConnection: attempt TCP connect + `LIST UPS`.
|
||||
- [ ] Task 5: Register NUT integration in `src/lib/server/integrations/registry.ts`.
|
||||
- [ ] Task 6: Create API route for NUT alerts `src/routes/api/integrations/alerts/+server.ts` — `GET` returns active critical alerts across all apps with integrations (UPS on battery, etc.). Used by IntegrationAlertOverlay.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/nut/schema.ts` — new
|
||||
- `src/lib/server/integrations/nut/client.ts` — new
|
||||
- `src/lib/server/integrations/nut/transform.ts` — new
|
||||
- `src/lib/server/integrations/nut/index.ts` — new
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register NUT
|
||||
- `src/routes/api/integrations/alerts/+server.ts` — new
|
||||
|
||||
## Acceptance Criteria
|
||||
- NUT client connects to NUT server via TCP and retrieves UPS variables
|
||||
- Battery charge displayed as percentage gauge
|
||||
- Load displayed as percentage gauge
|
||||
- Runtime formatted as human-readable time
|
||||
- Status correctly maps OL/OB/LB to alert levels
|
||||
- Alert banner fires when status is OB or LB
|
||||
- Connection test validates TCP connectivity
|
||||
- Handles connection timeouts and refused connections gracefully
|
||||
|
||||
## Notes
|
||||
- NUT protocol is text-based over TCP: send `GET VAR <ups> <var>\n`, receive `VAR <ups> <var> "<value>"\n`
|
||||
- Default port: 3493
|
||||
- Does NOT use app.url — uses nutHost/nutPort/upsName from extraConfig
|
||||
- TCP connections should be short-lived (connect, query, disconnect) — don't keep persistent connections
|
||||
- Common UPS variables: battery.charge, battery.runtime, ups.load, ups.status, input.voltage, output.voltage
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] TCP client handles timeouts and errors
|
||||
- [ ] No resource leaks (sockets always closed)
|
||||
- [ ] Code follows project conventions
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Phase 4: Pi-hole Integration
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Implement Pi-hole integration using its admin API to display DNS blocking statistics, top blocked domains, and query logs.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/pihole/schema.ts` — Zod schemas for auth config (`{ apiToken: string }`) and endpoint responses (summary stats, top items, query log).
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/pihole/client.ts` — HTTP client for Pi-hole API. Endpoints: `{app.url}/admin/api.php?summary`, `?topItems=N`, `?getAllQueries=N`, `?getQuerySources`. Include auth token as `&auth=<token>`.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/pihole/transform.ts` — Transform API responses: summary → stat-card data (total queries, blocked, block %, clients), topItems → list data, queries → list with allow/block indicator.
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/pihole/index.ts` — Integration implementation. Endpoints: `stats-summary` (stat-card), `top-blocked` (list), `query-log` (list), `gravity-status` (stat-card). testConnection: fetch summary endpoint.
|
||||
- [ ] Task 5: Register Pi-hole integration in registry.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/pihole/schema.ts` — new
|
||||
- `src/lib/server/integrations/pihole/client.ts` — new
|
||||
- `src/lib/server/integrations/pihole/transform.ts` — new
|
||||
- `src/lib/server/integrations/pihole/index.ts` — new
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register Pi-hole
|
||||
|
||||
## Acceptance Criteria
|
||||
- Stats summary shows: total queries, blocked queries, block percentage, unique clients
|
||||
- Top blocked domains list with counts
|
||||
- Query log with domain, client, allow/block status
|
||||
- Gravity status shows last update time and blocklist count
|
||||
- Test connection validates API token
|
||||
- Handles Pi-hole v5 and v6 API differences gracefully
|
||||
|
||||
## Notes
|
||||
- Pi-hole API is simple GET-based with auth token as query parameter
|
||||
- Some endpoints require authentication (topItems, queries), summary is often public
|
||||
- Response format is flat JSON — easy to parse
|
||||
- Consider Pi-hole v6 (new API format) — detect version and adapt
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] API responses properly validated
|
||||
- [ ] Code follows project conventions
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,44 @@
|
||||
# Phase 5: Portainer Integration
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Implement Portainer integration to display container and stack status from Docker environments managed by Portainer.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/portainer/schema.ts` — Zod schemas for auth config (`{ apiKey: string, endpointId: number }`) and endpoint responses.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/portainer/client.ts` — HTTP client for Portainer API. Auth via `X-API-Key` header. Endpoints: `/api/endpoints/{id}/docker/containers/json`, `/api/stacks`, `/api/endpoints/{id}/docker/containers/{cid}/json`.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/portainer/transform.ts` — Transform: containers → summary (running/stopped/error counts as stat-card), container list with state + CPU/memory, stacks → list with up/down status.
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/portainer/index.ts` — Integration implementation. Endpoints: `container-summary` (stat-card), `container-list` (list), `stack-status` (list). testConnection: fetch endpoints list.
|
||||
- [ ] Task 5: Register Portainer integration in registry.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/portainer/schema.ts` — new
|
||||
- `src/lib/server/integrations/portainer/client.ts` — new
|
||||
- `src/lib/server/integrations/portainer/transform.ts` — new
|
||||
- `src/lib/server/integrations/portainer/index.ts` — new
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register Portainer
|
||||
|
||||
## Acceptance Criteria
|
||||
- Container summary shows running/stopped/error counts
|
||||
- Container list shows name, state, image, CPU/memory usage
|
||||
- Stack status shows stack names with up/down indicators
|
||||
- Test connection validates API key and endpoint ID
|
||||
- Handles multiple Portainer endpoints
|
||||
|
||||
## Notes
|
||||
- Portainer API uses API key in `X-API-Key` header
|
||||
- Container stats (CPU/memory) require a separate API call per container — limit to top N for performance
|
||||
- Stack status comes from a separate endpoint
|
||||
- endpointId is required — Portainer manages multiple Docker hosts
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Performance: limited container stats calls
|
||||
- [ ] Code follows project conventions
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Phase 6: Gitea Integration
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Implement Gitea integration to display recent commits, open pull requests, CI/CD status, and releases from Gitea instances.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/gitea/schema.ts` — Zod schemas for auth config (`{ apiToken: string, repos?: string[] }`) and endpoint responses.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/gitea/client.ts` — HTTP client for Gitea API v1. Auth via `Authorization: token <apiToken>` header. Endpoints: `/api/v1/repos/search`, `/api/v1/repos/{owner}/{repo}/commits`, `/api/v1/repos/{owner}/{repo}/pulls`, `/api/v1/repos/{owner}/{repo}/releases`, `/api/v1/repos/{owner}/{repo}/actions/runners`.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/gitea/transform.ts` — Transform: commits → list with author/message/date, PRs → stat-card (open count) + list, CI → list with pass/fail badges, releases → list with tag/date.
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/gitea/index.ts` — Integration implementation. Endpoints: `recent-commits` (list), `open-prs` (stat-card), `ci-status` (list), `releases` (list). testConnection: fetch authenticated user.
|
||||
- [ ] Task 5: Register Gitea integration in registry.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/gitea/schema.ts` — new
|
||||
- `src/lib/server/integrations/gitea/client.ts` — new
|
||||
- `src/lib/server/integrations/gitea/transform.ts` — new
|
||||
- `src/lib/server/integrations/gitea/index.ts` — new
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register Gitea
|
||||
|
||||
## Acceptance Criteria
|
||||
- Recent commits across repos with author, message, timestamp
|
||||
- Open PR count as stat-card, PR list with title/author/repo
|
||||
- CI/CD status with workflow name and pass/fail badge
|
||||
- Releases list with tag, name, and date
|
||||
- Optional repo filter (if configured, only show data from those repos)
|
||||
- Test connection validates API token
|
||||
|
||||
## Notes
|
||||
- If `repos` config is empty, auto-discover all accessible repos
|
||||
- Limit commits/PRs to last N per repo for performance
|
||||
- CI status depends on Gitea Actions being enabled (act-runner)
|
||||
- API pagination: use `?limit=N&page=1` parameters
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Handles empty repos list (auto-discovery)
|
||||
- [ ] Code follows project conventions
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Phase 7: Nginx Proxy Manager Integration
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Implement Nginx Proxy Manager integration to display proxy hosts, SSL certificate expiry warnings, and upstream reachability status.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/npm/schema.ts` — Zod schemas for auth config (`{ email: string, password: string }`) and endpoint responses.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/npm/client.ts` — HTTP client for NPM API. Session-based auth: POST `/api/tokens` with email+password → get JWT → use for subsequent requests. Endpoints: `/api/nginx/proxy-hosts`, `/api/nginx/certificates`, `/api/nginx/proxy-hosts/{id}`. Cache session token.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/npm/transform.ts` — Transform: proxy hosts → list with domain/status/SSL info, certificates → list with expiry countdown (red <7d, yellow <14d, green >14d), upstream → list with reachable/unreachable indicator.
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/npm/index.ts` — Integration implementation. Endpoints: `proxy-hosts` (list), `ssl-certificates` (list), `upstream-status` (list). testConnection: authenticate and fetch proxy hosts.
|
||||
- [ ] Task 5: Register NPM integration in registry.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/npm/schema.ts` — new
|
||||
- `src/lib/server/integrations/npm/client.ts` — new
|
||||
- `src/lib/server/integrations/npm/transform.ts` — new
|
||||
- `src/lib/server/integrations/npm/index.ts` — new
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register NPM
|
||||
|
||||
## Acceptance Criteria
|
||||
- Proxy hosts list with domain name, enabled/disabled status
|
||||
- SSL certificates with expiry date and color-coded countdown
|
||||
- Upstream status shows reachable/unreachable per host
|
||||
- Session-based auth works (login → token → API calls)
|
||||
- Handles expired session token (re-authenticate automatically)
|
||||
- Test connection validates email/password credentials
|
||||
|
||||
## Notes
|
||||
- NPM uses session-based auth, not API keys — need to login first, cache the JWT
|
||||
- SSL expiry is the highest-value feature here — highlight expiring certs prominently
|
||||
- The session token has a limited lifetime — handle re-authentication on 401 responses
|
||||
- NPM API is relatively simple and well-documented
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Session token caching and re-auth implemented
|
||||
- [ ] Code follows project conventions
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,45 @@
|
||||
# Phase 8: Authentik Integration
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Implement Authentik integration for security monitoring: active sessions, login events, brute force detection, and user/group statistics.
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/authentik/schema.ts` — Zod schemas for auth config (`{ apiToken: string }`) and endpoint responses.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/authentik/client.ts` — HTTP client for Authentik API v3. Auth via `Authorization: Bearer <apiToken>` header. Endpoints: `/api/v3/core/sessions/`, `/api/v3/events/events/?action=login`, `/api/v3/events/events/?action=login_failed`, `/api/v3/core/users/`, `/api/v3/core/groups/`.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/authentik/transform.ts` — Transform: sessions → stat-card (count), login events → list with username/IP/timestamp/success, failed logins → brute force detection (>5 failures from same IP in 10 min = alert), user/group stats → stat-card.
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/authentik/index.ts` — Integration implementation. Endpoints: `sessions` (stat-card), `login-events` (list), `security-alerts` (alert-banner), `user-stats` (stat-card). testConnection: fetch authenticated user info.
|
||||
- [ ] Task 5: Register Authentik integration in registry.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/authentik/schema.ts` — new
|
||||
- `src/lib/server/integrations/authentik/client.ts` — new
|
||||
- `src/lib/server/integrations/authentik/transform.ts` — new
|
||||
- `src/lib/server/integrations/authentik/index.ts` — new
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register Authentik
|
||||
|
||||
## Acceptance Criteria
|
||||
- Active sessions count displayed as stat-card
|
||||
- Login events list with username, IP, timestamp, success/failure
|
||||
- Brute force detection: alert when >5 failed logins from same IP within 10 minutes
|
||||
- User/group stats displayed as stat-card
|
||||
- Security alerts surface via alert banner system
|
||||
- Test connection validates API token
|
||||
|
||||
## Notes
|
||||
- Authentik API v3 uses pagination — handle `?page=N&page_size=N`
|
||||
- Brute force detection is computed client-side from event data, not a native Authentik feature
|
||||
- The threshold (5 failures / 10 min) should be configurable via extra config
|
||||
- Security alerts should integrate with the alert banner overlay from Phase 2
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Brute force detection logic is sound
|
||||
- [ ] Code follows project conventions
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
@@ -0,0 +1,69 @@
|
||||
# Phase 9: Media Integrations (Emby + Immich + Deluge + MeTube)
|
||||
|
||||
**Status:** ⬜ Not Started
|
||||
**Parent plan:** [PLAN.md](./PLAN.md)
|
||||
**Domain:** backend
|
||||
|
||||
## Objective
|
||||
Implement four media-related integrations bundled together since each is relatively small: Emby (media server), Immich (photo management), Deluge (torrent client), and MeTube (video downloader).
|
||||
|
||||
## Tasks
|
||||
|
||||
### Emby
|
||||
- [ ] Task 1: Create `src/lib/server/integrations/emby/schema.ts` — Auth config: `{ apiKey: string }`.
|
||||
- [ ] Task 2: Create `src/lib/server/integrations/emby/client.ts` — HTTP client. Endpoints: `/emby/Sessions?api_key=<key>`, `/emby/Items/Counts?api_key=<key>`, `/emby/Items/Latest?api_key=<key>`.
|
||||
- [ ] Task 3: Create `src/lib/server/integrations/emby/transform.ts` — Now playing → list (user, title, transcode/direct, quality), library stats → stat-card (movies, shows, episodes), recently added → list with titles.
|
||||
- [ ] Task 4: Create `src/lib/server/integrations/emby/index.ts` — Endpoints: `now-playing` (list), `library-stats` (stat-card), `recently-added` (list), `active-streams` (stat-card).
|
||||
|
||||
### Immich
|
||||
- [ ] Task 5: Create `src/lib/server/integrations/immich/schema.ts` — Auth config: `{ apiKey: string }`.
|
||||
- [ ] Task 6: Create `src/lib/server/integrations/immich/client.ts` — HTTP client. Auth via `x-api-key` header. Endpoints: `/api/server-info/statistics`, `/api/assets?order=desc&limit=10`, `/api/memories`.
|
||||
- [ ] Task 7: Create `src/lib/server/integrations/immich/transform.ts` — Library stats → stat-card (photos, videos, storage), recent uploads → list, memory of day → stat-card.
|
||||
- [ ] Task 8: Create `src/lib/server/integrations/immich/index.ts` — Endpoints: `library-stats` (stat-card), `recent-uploads` (list), `memory-of-day` (stat-card).
|
||||
|
||||
### Deluge
|
||||
- [ ] Task 9: Create `src/lib/server/integrations/deluge/schema.ts` — Auth config: `{ password: string }`.
|
||||
- [ ] Task 10: Create `src/lib/server/integrations/deluge/client.ts` — JSON-RPC client at `{app.url}/json`. Auth flow: call `auth.login` first, then `web.update_ui` / `core.get_torrents_status`. Handle session cookie.
|
||||
- [ ] Task 11: Create `src/lib/server/integrations/deluge/transform.ts` — Active torrents → progress list (name, %, speed), transfer speed → gauge, disk space → gauge.
|
||||
- [ ] Task 12: Create `src/lib/server/integrations/deluge/index.ts` — Endpoints: `active-torrents` (progress), `transfer-speed` (gauge), `disk-space` (gauge).
|
||||
|
||||
### MeTube
|
||||
- [ ] Task 13: Create `src/lib/server/integrations/metube/schema.ts` — Auth config: `{}` (no auth).
|
||||
- [ ] Task 14: Create `src/lib/server/integrations/metube/client.ts` — HTTP client. Endpoint: `/api/history`, `/api/queue`.
|
||||
- [ ] Task 15: Create `src/lib/server/integrations/metube/transform.ts` — Download queue → progress list (title, %, status).
|
||||
- [ ] Task 16: Create `src/lib/server/integrations/metube/index.ts` — Endpoints: `download-queue` (progress).
|
||||
|
||||
### Registration
|
||||
- [ ] Task 17: Register all four integrations in registry.
|
||||
|
||||
## Files to Modify/Create
|
||||
- `src/lib/server/integrations/emby/{schema,client,transform,index}.ts` — new (4 files)
|
||||
- `src/lib/server/integrations/immich/{schema,client,transform,index}.ts` — new (4 files)
|
||||
- `src/lib/server/integrations/deluge/{schema,client,transform,index}.ts` — new (4 files)
|
||||
- `src/lib/server/integrations/metube/{schema,client,transform,index}.ts` — new (4 files)
|
||||
- `src/lib/server/integrations/registry.ts` — modify: register all four
|
||||
|
||||
## Acceptance Criteria
|
||||
- All four integrations fetch and transform data correctly
|
||||
- Emby: now playing, library stats, recently added
|
||||
- Immich: library stats, recent uploads, memory of day
|
||||
- Deluge: active torrents with progress, transfer speed, disk space
|
||||
- MeTube: download queue with progress
|
||||
- Deluge JSON-RPC auth flow handles session cookies
|
||||
- MeTube works without any auth
|
||||
- All test connections validate properly
|
||||
|
||||
## Notes
|
||||
- Deluge JSON-RPC is the trickiest — requires auth.login call first, then session cookie for subsequent calls
|
||||
- MeTube has a very limited API — may need to poll /api/queue for real-time data
|
||||
- Immich API versions change frequently — target current stable
|
||||
- Emby API key goes in query string, not header
|
||||
|
||||
## Review Checklist
|
||||
- [ ] All tasks completed
|
||||
- [ ] Deluge session handling is robust
|
||||
- [ ] Code follows project conventions
|
||||
- [ ] Each integration is self-contained in its directory
|
||||
|
||||
## Handoff to Next Phase
|
||||
<!-- Filled in after completion -->
|
||||
Reference in New Issue
Block a user