diff --git a/plans/database-backup/CONTEXT.md b/plans/database-backup/CONTEXT.md deleted file mode 100644 index 8538d06..0000000 --- a/plans/database-backup/CONTEXT.md +++ /dev/null @@ -1,40 +0,0 @@ -# Feature Context: Database Backup & Restore - -## Configuration -- **Development mode:** Automated -- **Execution mode:** Direct -- **Strategy:** Big Bang -- **Build:** `npm run build` -- **Test:** `npm run test` -- **Lint:** `npm run lint` -- **Dev server:** `npm run dev` (port: 5173) - -## Current State -Starting implementation. Existing import/export code is still in place — will be removed in Phase 4. - -## Tech Stack -- SvelteKit 5 + TypeScript -- Prisma ORM with SQLite (`data/launcher.db`) -- node-cron (already a dependency, used by healthcheckScheduler) -- Zod validation -- Tailwind CSS + bits-ui components -- svelte-i18n for localization -- lucide-svelte for icons - -## Key Patterns from Codebase -- Services in `src/lib/server/services/` — pure functions, Prisma transactions -- API routes follow SvelteKit conventions with admin auth guards -- Scheduler pattern: `src/lib/server/jobs/healthcheckScheduler.ts` — cron start/stop, wired in hooks.server.ts -- Admin components in `src/lib/components/admin/` -- Audit logging via `auditLogService.ts` - -## Cross-Phase Dependencies -- Phase 2 depends on Phase 1 (backupService) -- Phase 3 depends on Phases 1+2 (API endpoints) -- Phase 4 is independent cleanup - -## Implementation Notes -- Using `VACUUM INTO` for safe backup creation (no locking) -- Backups stored in `data/backups/` directory -- Restore requires Prisma disconnect → file swap → reconnect -- SystemSettings gets new fields: backupEnabled, backupCronExpression, backupMaxCount diff --git a/plans/database-backup/PLAN.md b/plans/database-backup/PLAN.md deleted file mode 100644 index 042211b..0000000 --- a/plans/database-backup/PLAN.md +++ /dev/null @@ -1,39 +0,0 @@ -# Feature: Database Backup & Restore - -**Branch:** `feature/database-backup` -**Base branch:** `master` -**Created:** 2026-04-02 -**Status:** 🟡 In Progress -**Strategy:** Big Bang -**Mode:** Automated -**Execution:** Direct - -## Summary -Replace JSON import/export with SQLite file-copy backup system. Support manual on-demand backups, optional periodic scheduling via node-cron, configurable retention (max backup count), download capability, and full database restore. - -## Build & Test Commands -- **Build:** `npm run build` -- **Test:** `npm run test` -- **Lint:** `npm run lint` - -## Phases - -- [ ] Phase 1: Backup Service & API Endpoints [domain: backend] → [subplan](./phase-1-backup-service.md) -- [ ] Phase 2: Periodic Backup Scheduler [domain: backend] → [subplan](./phase-2-backup-scheduler.md) -- [ ] Phase 3: Frontend BackupPanel [domain: frontend] → [subplan](./phase-3-backup-panel.md) -- [ ] Phase 4: Cleanup Import/Export [domain: fullstack] → [subplan](./phase-4-cleanup.md) - -## Phase Progress Log - -| Phase | Domain | Status | Review | Build | Committed | -|-------|--------|--------|--------|-------|-----------| -| Phase 1: Backup Service & API | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 2: Backup Scheduler | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 3: BackupPanel UI | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 4: Cleanup | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ | - -## Final Review -- [ ] Comprehensive code review -- [ ] Full build passes -- [ ] Full test suite passes -- [ ] Merged to `master` diff --git a/plans/mvp-web-app-launcher/CONTEXT.md b/plans/mvp-web-app-launcher/CONTEXT.md deleted file mode 100644 index d265f0a..0000000 --- a/plans/mvp-web-app-launcher/CONTEXT.md +++ /dev/null @@ -1,43 +0,0 @@ -# Feature Context: Web App Launcher — MVP - -## Current State - -Phase 8 (Integration, Testing & Deployment) is complete. All build errors, type errors, and lint errors resolved. 115 tests pass across 10 test files covering all services, utilities, and validators. Key fixes: (1) Created `src/lib/utils/zod-adapter.ts` to wrap sveltekit-superforms zod adapter for zod 3.25+ compatibility — the new zod version's stricter type inference makes `z.object()` return types incompatible with superforms' `ZodObjectType` constraint; (2) Fixed JWT `expiresIn` type cast in authService; (3) Reordered private field initialization in ThemeStore to fix `$derived` referencing `#systemPreference` before init; (4) Fixed curly brace escaping in SettingsForm placeholder; (5) Added `{#each}` keys across 6 components; (6) Removed unused imports; (7) Disabled `svelte/no-navigation-without-resolve` lint rule for static routes; (8) Changed vitest environment from jsdom to node. Seed script expanded with regular demo user, 7 sample apps (Plex, Nextcloud, Gitea, Home Assistant, Grafana, Portainer, Pi-hole), 3 sections, idempotent re-seeding. Dockerfile updated with prisma migrate on container startup. All four checks pass: `npm run build`, `npm run check` (0 errors), `npm run lint` (0 errors), `npm test` (115/115 pass). - -Phase 7 (UI Polish & Ambient Backgrounds) is complete. All 24 tasks implemented. Three Svelte 5 rune-based stores created: `theme.svelte.ts` (dark/light/system mode cycling, HSL primary color with `--primary-h`/`--primary-s`/`--primary-l` CSS variables set via JS, background type selection, all persisted to localStorage, auto-applies `dark`/`light` class to ``), `ui.svelte.ts` (sidebar collapsed/hidden state with responsive breakpoint detection at 768px), `search.svelte.ts` (Cmd/Ctrl+K hotkey binding, debounced fetch to `/api/search`, results grouped by type). Layout system: `MainLayout.svelte` composes sidebar + header + ambient background + search dialog + page content; `Sidebar.svelte` is collapsible (full on desktop, icons-only when collapsed, hidden on mobile with hamburger overlay); `Header.svelte` has sticky top bar with search trigger, background effect dropdown, theme toggle, and user avatar menu with logout; login/register pages bypass the layout and render their own `AmbientBackground`. Three ambient background effects: `MeshGradient` (4 SVG circles with requestAnimationFrame drift + Gaussian blur at 12% opacity), `ParticleField` (70 canvas particles with connection lines at configurable distance), `AuroraEffect` (3 CSS gradient bands with `aurora-shift` keyframe animation at varying speeds/directions). Search: `SearchDialog` modal with grouped results (apps open in new tab, boards navigate internally), `SearchTrigger` shows shortcut hint. CSS enhancements in `app.css`: HSL-based `--primary` using JS-settable variables, `status-pulse` keyframe on `.status-online`, `.card-hover` class (scale 1.02 + elevated shadow), `.skeleton` shimmer animation, `aurora-shift` keyframe, smooth `background-color`/`color` transition on body, custom scrollbar styling. `app.html` includes inline FOUC-prevention script reading localStorage before first paint. Page transitions via `{#key $page.url.pathname}` + Svelte `fade`. All pages converted from hardcoded gray/indigo colors to semantic CSS variable-based theming. Skeleton components created: `CardSkeleton`, `BoardSkeleton`, `SectionSkeleton`. `+layout.server.ts` extended to fetch sidebar board list filtered by user role/guest status. - -Phase 4 (App Registry & Healthcheck) is complete. All app CRUD API routes are implemented at `/api/apps` (GET/POST) and `/api/apps/[id]` (GET/PATCH/DELETE) with Zod validation and auth middleware. Status history is served from `/api/apps/[id]/status`. The healthcheck service performs HTTP HEAD/GET requests with AbortController timeouts, mapping responses to online/offline/degraded/unknown. The scheduler uses node-cron (default: every 60 seconds) with an initial delayed check on startup. Icon resolution supports lucide, simple-icons (CDN), direct URL, and emoji types. The app registry UI at `/apps` renders cards in a responsive grid with category filtering and an inline Superforms create form. Custom icon uploads are handled at `/api/uploads` with type (SVG/PNG/JPG/WebP) and size (<1MB) validation, saving to `static/uploads/`. A Docker healthcheck endpoint at `/api/health` returns 200 with no auth. All Svelte components use runes mode ($state, $derived, $props). - -Phase 3 (Authentication System) is complete. The full local authentication flow is implemented: login, registration, logout, and JWT token refresh. `hooks.server.ts` validates access tokens on every request, injects `event.locals.user`/`session`, and silently rotates expired tokens via refresh tokens. Protected routes redirect to `/login`; guest-accessible board routes are exempt. Login and registration pages use Superforms + Zod with inline validation errors. Registration respects the `SystemSettings.registrationEnabled` toggle. Reusable middleware helpers (`requireAuth`, `requireAdmin`, `requireRole`) are available for downstream phases. The root layout injects user session into all page data. The root page redirects to the default board or login. `jwt.ts` and `password.ts` are thin re-exports from `authService` (no duplication). Build does not pass yet (Big Bang strategy — expected). - -Phase 5 (Board, Section & Widget System) is complete. All 20 tasks implemented: 5 API route files for board/section/widget CRUD (`/api/boards`, `/api/boards/[id]`, `/api/boards/[id]/sections`, `/api/boards/[id]/sections/[sid]`, `/api/boards/[id]/sections/[sid]/widgets`), 3 page routes for board list (`/boards`), board view (`/boards/[boardId]`), and board editor (`/boards/[boardId]/edit`), plus 9 Svelte components across board/section/widget directories. Board list API filters by permissions: admins see all, regular users see boards where they have VIEW+ permission via `permissionService.checkPermission()`, guests see only `isGuestAccessible` boards. Board view loads the full hierarchy (board -> sections -> widgets -> app -> latest status) via `boardService.findBoardById`. The board editor uses SvelteKit form actions (updateBoard, addSection/updateSection/deleteSection, addWidget/deleteWidget) with `use:enhance` for progressive enhancement. Section collapse uses Svelte's built-in `slide` transition. Widget grid is responsive CSS grid (2 cols mobile, 3 tablet, 4 desktop). `AppWidget` reuses `AppHealthBadge` for status display. - -Phase 6 (Admin Panel) is complete. All 18 tasks implemented: admin layout with `requireAdmin` guard in `+layout.server.ts` and nav bar linking Users/Groups/Settings plus Back to Dashboard. User management at `/admin/users` supports full CRUD via Superforms (create with email/displayName/password/role, inline role editing, delete with confirmation) plus group membership management (add/remove users from groups). Group management at `/admin/groups` supports CRUD with inline editing, member count display, and default-group toggle. System settings at `/admin/settings` configures auth mode (local/oauth/both), registration toggle, OAuth fields (stored, non-functional in MVP), default theme (dark/light), default primary color (hex), and healthcheck defaults (JSON). Four admin components created: `UserTable.svelte`, `GroupTable.svelte`, `SettingsForm.svelte`, and `PermissionEditor.svelte` (reusable with `onGrant`/`onRevoke` callback props for entity/target/level selection). Six REST API route files added: `/api/users` (GET/POST), `/api/users/[id]` (GET/PATCH/DELETE), `/api/groups` (GET/POST), `/api/groups/[id]` (GET/PATCH/DELETE), `/api/admin/settings` (GET/PATCH) — all admin-only. Global search endpoint at `/api/search?q=term` searches apps by name/description/category and boards by name/description, filtering results by user permissions via `permissionService.checkPermission`. Self-deletion protection prevents admin from deleting their own account. All forms use Superforms + Zod validation schemas from `$lib/utils/validators.ts`. - -## Temporary Workarounds - -- Permission model uses polymorphic pattern (entityType/targetType strings) without FK relations to avoid SQLite dual-FK constraint issues. Queries are done manually in `permissionService.ts`. -- JSON fields (backgroundConfig, config, healthcheckDefaults) are stored as String in SQLite and parsed at the application layer. -- `package.json` `prisma.seed` config triggers a deprecation warning — migrate to `prisma.config.ts` when upgrading to Prisma 7. - -## Cross-Phase Dependencies - -- Phase 2 depends on Phase 1 (project scaffolding, Prisma setup) -- Phase 3 depends on Phase 2 (user/group models, auth service) ✅ -- Phase 4 depends on Phase 2 (app model, services layer) -- Phase 5 depends on Phase 2 (board/section/widget models) and Phase 4 (app widget references apps) -- Phase 6 depends on Phases 3-5 (admin needs auth, app, board entities) -- Phase 7 depends on Phase 1 (Tailwind, shadcn-svelte) and Phase 5 (board layout to polish) -- Phase 8 depends on all prior phases - -## Implementation Notes - -- Big Bang strategy: intermediate phases may not build/pass tests. Only Phase 8 must result in a fully working build. -- SQLite with Prisma — single file DB at `data/launcher.db` -- All env config via environment variables; `.env.example` provided as template -- Svelte 5 runes mode: use `$state`, `$derived`, `$effect` — NOT legacy stores for component state -- shadcn-svelte uses Bits UI primitives — each component is a local file, not a library import -- `App.Locals` uses `email` + `displayName` fields (aligned with User model, updated in Phase 2) -- Prisma client singleton at `src/lib/server/prisma.ts` — use this for all DB access -- Services export pure async functions (not classes), use immutable patterns -- `tsx` devDependency added for running the seed script diff --git a/plans/mvp-web-app-launcher/PLAN.md b/plans/mvp-web-app-launcher/PLAN.md deleted file mode 100644 index 6ab2576..0000000 --- a/plans/mvp-web-app-launcher/PLAN.md +++ /dev/null @@ -1,60 +0,0 @@ -# Feature: Web App Launcher — MVP - -**Branch:** `feature/mvp-web-app-launcher` -**Base branch:** `master` -**Created:** 2026-03-24 -**Status:** 🟡 In Progress -**Strategy:** Big Bang -**Mode:** Automated -**Execution:** Orchestrator - -## Summary - -Build a self-hosted web application launcher/dashboard for a TrueNAS server environment. The MVP includes local auth + guest mode, app CRUD with healthchecks, a single default board with sections and app widgets, an admin panel, dark theme with ambient backgrounds, and Docker deployment with Gitea CI. - -## Build & Test Commands - -- **Build:** `npm run build` -- **Test:** `npm test` -- **Lint:** `npm run lint` -- **Type Check:** `npm run check` - -## Tech Stack - -- **Framework:** SvelteKit (Svelte 5 runes mode) + TypeScript strict -- **UI:** Tailwind CSS v4 + shadcn-svelte (Bits UI) + Lucide Svelte + Simple Icons -- **Data:** Prisma ORM + SQLite + Superforms + Zod -- **Auth:** bcrypt + JWT (HTTP-only cookies) + refresh token rotation -- **Background Jobs:** node-cron -- **DevOps:** Docker (multi-stage) + docker-compose + Gitea Actions - -## Phases - -- [x] Phase 1: Project Scaffolding & Tooling [backend] → [subplan](./phase-1-scaffolding.md) -- [x] Phase 2: Database Schema & Services Layer [backend] → [subplan](./phase-2-database-services.md) -- [x] Phase 3: Authentication System [fullstack] → [subplan](./phase-3-authentication.md) -- [x] Phase 4: App Registry & Healthcheck [fullstack] → [subplan](./phase-4-app-healthcheck.md) -- [x] Phase 5: Board, Section & Widget System [fullstack] → [subplan](./phase-5-board-widgets.md) -- [x] Phase 6: Admin Panel [fullstack] → [subplan](./phase-6-admin-panel.md) -- [x] Phase 7: UI Polish & Ambient Backgrounds [frontend] → [subplan](./phase-7-ui-polish.md) -- [x] Phase 8: Integration, Testing & Deployment [fullstack] → [subplan](./phase-8-integration-deploy.md) - -## Phase Progress Log - -| Phase | Domain | Status | Review | Build | Committed | -| ----------------------------- | --------- | ----------- | ------ | ----- | --------- | -| Phase 1: Scaffolding | backend | ✅ Complete | ✅ | ⬜ | ⬜ | -| Phase 2: Database & Services | backend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 3: Authentication | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 4: App & Healthcheck | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 5: Board & Widgets | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 6: Admin Panel | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 7: UI Polish | frontend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 8: Integration & Deploy | fullstack | ✅ Complete | ✅ | ✅ | ⬜ | - -## Final Review - -- [ ] Comprehensive code review -- [ ] Full build passes -- [ ] Full test suite passes -- [ ] Merged to `master` diff --git a/plans/mvp-web-app-launcher/phase-1-scaffolding.md b/plans/mvp-web-app-launcher/phase-1-scaffolding.md deleted file mode 100644 index 1ed3c60..0000000 --- a/plans/mvp-web-app-launcher/phase-1-scaffolding.md +++ /dev/null @@ -1,85 +0,0 @@ -# Phase 1: Project Scaffolding & Tooling - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective - -Initialize the SvelteKit project with the full toolchain: TypeScript strict, Svelte 5, Tailwind CSS v4, shadcn-svelte, Prisma + SQLite, Vitest, ESLint, Prettier. Create the Docker and CI configuration. - -## Tasks - -- [x] Task 1: Initialize SvelteKit project with TypeScript, Svelte 5 adapter-node -- [x] Task 2: Install and configure Tailwind CSS v4 -- [x] Task 3: Install and configure shadcn-svelte (Bits UI primitives) -- [x] Task 4: Install Prisma, configure SQLite provider, create initial empty schema -- [x] Task 5: Install Vitest and configure for SvelteKit -- [x] Task 6: Configure ESLint + Prettier for Svelte/TS -- [x] Task 7: Install runtime dependencies: lucide-svelte, simple-icons, superforms, zod, bcryptjs, jsonwebtoken, node-cron -- [x] Task 8: Create `.env.example` with all required env vars -- [x] Task 9: Create `Dockerfile` (multi-stage build) -- [x] Task 10: Create `docker-compose.yml` -- [x] Task 11: Create `.gitea/workflows/ci.yml` (lint, type-check, test, Docker build) -- [x] Task 12: Create `app.css` with Tailwind base + CSS custom properties for theming -- [x] Task 13: Create `app.d.ts` with SvelteKit type augmentation (Locals, Session) - -## Files to Modify/Create - -- `package.json` — project config with all dependencies and scripts -- `svelte.config.js` — SvelteKit config with adapter-node -- `vite.config.ts` — Vite config with Vitest -- `tsconfig.json` — TypeScript strict config -- `tailwind.config.ts` — Tailwind v4 config -- `src/app.css` — Tailwind imports + theme variables -- `src/app.d.ts` — SvelteKit type augmentation -- `src/app.html` — HTML template -- `prisma/schema.prisma` — empty schema with SQLite datasource -- `.env.example` — template env vars -- `Dockerfile` — multi-stage Node build -- `docker-compose.yml` — single-service deployment -- `.gitea/workflows/ci.yml` — CI pipeline -- `eslint.config.js` — ESLint flat config -- `.prettierrc` — Prettier config - -## Acceptance Criteria - -- `npm install` succeeds -- Project structure matches SvelteKit conventions -- All config files are valid -- Dockerfile builds (structure-wise, not the app itself yet) - -## Notes - -- Use `@sveltejs/adapter-node` for Docker deployment -- Svelte 5 runes mode is the default in latest SvelteKit — no special config needed -- Tailwind v4 uses the new CSS-based config approach -- ⚠️ Big Bang: build will not pass yet — no routes or components exist - -## Review Checklist - -- [ ] All tasks completed -- [ ] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -Phase 1 scaffolding is complete. All tooling is configured and `npm install` succeeds. - -**What's ready for Phase 2:** - -- Prisma is installed with SQLite datasource configured at `prisma/schema.prisma` — add models there. -- `@prisma/client` is a devDependency; run `npx prisma generate` after adding models. -- `DATABASE_URL` defaults to `file:../data/launcher.db` (see `.env.example`). -- SvelteKit project structure is in place: `src/routes/+page.svelte`, `src/app.html`, `src/app.css`, `src/app.d.ts`. -- `App.Locals` type augmentation defines `user` and `session` — align with the User model in Phase 2. -- shadcn-svelte is configured via `components.json` — add UI components with `npx shadcn-svelte@latest add `. -- `src/lib/utils/cn.ts` provides the `cn()` class-merge utility used by shadcn-svelte components. - -**Known gaps (expected for Big Bang strategy):** - -- `npm run build` will fail until SvelteKit routes and server hooks are wired up. -- `npm run check` will fail until `.svelte-kit/` is generated via `svelte-kit sync`. -- No tests exist yet — `npm test` will pass vacuously (no test files). diff --git a/plans/mvp-web-app-launcher/phase-2-database-services.md b/plans/mvp-web-app-launcher/phase-2-database-services.md deleted file mode 100644 index 1c5d4c7..0000000 --- a/plans/mvp-web-app-launcher/phase-2-database-services.md +++ /dev/null @@ -1,82 +0,0 @@ -# Phase 2: Database Schema & Services Layer - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective - -Define the full Prisma database schema, run migrations, and build the core server-side services layer with shared Zod validation schemas and TypeScript type definitions. - -## Tasks - -- [x] Task 1: Define Prisma schema with all models: User, Group, UserGroup, App, AppStatus, Board, Section, Widget, Permission, SystemSettings -- [x] Task 2: Run `prisma migrate dev` to create initial migration -- [x] Task 3: Create TypeScript type definitions in `src/lib/types/` (auth, app, board, widget, user, group, permission) -- [x] Task 4: Create shared Zod validation schemas in `src/lib/utils/validators.ts` -- [x] Task 5: Create API response envelope utility in `src/lib/server/utils/response.ts` -- [x] Task 6: Implement `authService.ts` — password hashing, JWT sign/verify, refresh token management -- [x] Task 7: Implement `userService.ts` — CRUD, findByEmail, role management -- [x] Task 8: Implement `groupService.ts` — CRUD, user-group membership -- [x] Task 9: Implement `appService.ts` — CRUD, search, status updates -- [x] Task 10: Implement `boardService.ts` — CRUD with sections and widgets, default board -- [x] Task 11: Implement `permissionService.ts` — check/grant/revoke permissions, hierarchical resolution -- [x] Task 12: Create `src/lib/utils/constants.ts` — shared constants (roles, status values, defaults) -- [x] Task 13: Create `prisma/seed.ts` — seed admin user, default groups, default board, sample apps - -## Files to Modify/Create - -- `prisma/schema.prisma` — full schema definition -- `prisma/seed.ts` — seed script -- `src/lib/types/*.ts` — type definitions -- `src/lib/utils/validators.ts` — Zod schemas -- `src/lib/utils/constants.ts` — constants -- `src/lib/server/utils/response.ts` — API envelope -- `src/lib/server/services/authService.ts` -- `src/lib/server/services/userService.ts` -- `src/lib/server/services/groupService.ts` -- `src/lib/server/services/appService.ts` -- `src/lib/server/services/boardService.ts` -- `src/lib/server/services/permissionService.ts` - -## Acceptance Criteria - -- Prisma schema validates and migration runs -- All services export clean async functions with proper types -- Zod schemas match Prisma models -- Seed script creates demo data -- No circular dependencies between services - -## Notes - -- SystemSettings is a singleton row — use upsert pattern -- Permission resolution: User-level > Group-level > Default -- Widget config is JSON — stored as String in SQLite, parsed at application layer -- OAuth fields in SystemSettings should be encrypted at rest (handle in Phase 3) -- Permission model uses polymorphic pattern (entityType/targetType) without FK relations to avoid SQLite constraints -- ⚠️ Big Bang: services won't be wired to routes yet - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -**What's ready for Phase 3:** - -- Prisma schema is defined and migrated. SQLite DB created at `data/launcher.db`. -- Prisma client is generated and available via `src/lib/server/prisma.ts` singleton. -- `authService.ts` provides: `hashPassword`, `verifyPassword`, `signAccessToken`, `verifyAccessToken`, `generateRefreshToken`, `saveRefreshToken`, `validateRefreshToken`, `revokeRefreshToken`, `rotateTokens`. -- `userService.ts` provides: `findAll`, `findById`, `findByEmail`, `create`, `update`, `remove`, `updateRole`, `getUserGroups`, `count`. -- `groupService.ts` provides: `findAll`, `findById`, `findByName`, `findDefaultGroups`, `create`, `update`, `remove`, `addUser`, `removeUser`, `getGroupMembers`, `addUserToDefaultGroups`. -- `App.Locals` updated to use `email` + `displayName` (aligned with User model). -- Zod validators available for all form/API input validation. -- API response envelope (`success`, `error`, `paginated`) in `src/lib/server/utils/response.ts`. -- Seed data includes: admin user (admin@localhost / admin123), admin + user groups, 5 sample apps, default board with 2 sections and widgets. -- Constants exported from `src/lib/utils/constants.ts` for roles, statuses, widget types, permission levels. -- `tsx` added as devDependency for running seed script. -- `package.json` has `prisma.seed` config (deprecated warning — migrate to `prisma.config.ts` in future). diff --git a/plans/mvp-web-app-launcher/phase-3-authentication.md b/plans/mvp-web-app-launcher/phase-3-authentication.md deleted file mode 100644 index d8eeeae..0000000 --- a/plans/mvp-web-app-launcher/phase-3-authentication.md +++ /dev/null @@ -1,89 +0,0 @@ -# Phase 3: Authentication System - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Implement the full local authentication flow: login, registration, session management with JWT + refresh tokens in HTTP-only cookies, auth middleware in hooks.server.ts, and guest mode support. - -## Tasks - -- [x] Task 1: Implement `src/lib/server/utils/jwt.ts` — thin re-export from authService (already implemented in Phase 2) -- [x] Task 2: Implement `src/lib/server/utils/password.ts` — thin re-export from authService (already implemented in Phase 2) -- [x] Task 3: Implement `src/hooks.server.ts` — auth middleware, session injection into `event.locals` -- [x] Task 4: Create `src/routes/login/+page.server.ts` — login form action (Superforms + Zod) -- [x] Task 5: Create `src/routes/login/+page.svelte` — login page UI -- [x] Task 6: Create `src/routes/register/+page.server.ts` — registration form action (respects admin toggle) -- [x] Task 7: Create `src/routes/register/+page.svelte` — registration page UI -- [x] Task 8: Create `src/routes/auth/refresh/+server.ts` — token refresh endpoint -- [x] Task 9: Create `src/routes/+layout.server.ts` — root layout load: inject user session -- [x] Task 10: Create `src/routes/+layout.svelte` — root layout shell (minimal, polished in Phase 7) -- [x] Task 11: Implement `src/lib/server/middleware/authenticate.ts` — reusable auth check helper -- [x] Task 12: Implement `src/lib/server/middleware/authorize.ts` — role-based access check -- [x] Task 13: Implement `src/lib/server/middleware/guestAccess.ts` — guest mode board visibility -- [x] Task 14: Create `src/routes/+page.svelte` — root page (redirect to default board or login) -- [x] Task 15: Create logout endpoint/action — invalidate refresh token, clear cookies - -## Files to Modify/Create - -- `src/hooks.server.ts` — auth middleware -- `src/lib/server/utils/jwt.ts` — JWT utilities -- `src/lib/server/utils/password.ts` — password utilities -- `src/lib/server/middleware/authenticate.ts` -- `src/lib/server/middleware/authorize.ts` -- `src/lib/server/middleware/guestAccess.ts` -- `src/routes/login/+page.svelte` -- `src/routes/login/+page.server.ts` -- `src/routes/register/+page.svelte` -- `src/routes/register/+page.server.ts` -- `src/routes/auth/refresh/+server.ts` -- `src/routes/+layout.server.ts` -- `src/routes/+layout.svelte` -- `src/routes/+page.svelte` -- `src/app.d.ts` — augment `Locals` with user session type (already done in Phase 2) - -## Acceptance Criteria - -- Users can register (when enabled) and log in with email/password -- JWT access token + refresh token issued in HTTP-only cookies -- `hooks.server.ts` validates tokens on every request and injects user into `event.locals` -- Refresh token rotation works (old token invalidated) -- Logout clears cookies and invalidates refresh token -- Guest mode: unauthenticated users can access guest-accessible boards -- Protected routes redirect to login -- Form validation with Superforms + Zod shows errors inline - -## Notes - -- Access token expiry: 15 minutes; Refresh token expiry: 7 days -- Store refresh tokens in DB (User model) for server-side invalidation -- OAuth is deferred to Phase 2 of the project (post-MVP) -- Registration toggle is read from SystemSettings -- Big Bang: login page will be functional but unstyled/minimal until Phase 7 - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -**What's ready for Phase 4:** - -- Full local auth flow is implemented: login, registration, logout, token refresh. -- `hooks.server.ts` validates JWT access tokens on every request and injects `event.locals.user` and `event.locals.session`. Expired access tokens are silently refreshed via refresh token rotation. -- Protected routes (anything except `/login`, `/register`, `/auth/*`, `/api/health`) redirect unauthenticated users to `/login`. -- Guest mode support: `guestAccess.ts` middleware checks `isGuestAccessible` on boards; hooks allow unauthenticated access to guest-accessible board routes. -- Reusable middleware helpers available: `requireAuth()`, `isAuthenticated()`, `requireRole()`, `requireAdmin()`. -- Login/register pages use Superforms + Zod with inline error display. -- Registration respects `SystemSettings.registrationEnabled` toggle. -- Root layout (`+layout.server.ts`) injects `user` into all page data. -- Root page (`+page.server.ts`) redirects to default board (authenticated) or guest board (unauthenticated) or `/login`. -- Logout endpoint at `POST /auth/logout` revokes refresh token and clears all auth cookies. -- `jwt.ts` and `password.ts` are thin re-exports from `authService` (no duplication). -- A `refresh_user_id` cookie is used alongside `refresh_token` to identify the user during token rotation (since refresh tokens are stored hashed per-user). diff --git a/plans/mvp-web-app-launcher/phase-4-app-healthcheck.md b/plans/mvp-web-app-launcher/phase-4-app-healthcheck.md deleted file mode 100644 index 3a5626c..0000000 --- a/plans/mvp-web-app-launcher/phase-4-app-healthcheck.md +++ /dev/null @@ -1,80 +0,0 @@ -# Phase 4: App Registry & Healthcheck - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Build the app (service) registry with CRUD operations, the icon resolution system, healthcheck scheduler with node-cron, and status APIs. Create the app management UI. - -## Tasks - -- [x] Task 1: Create `src/routes/api/apps/+server.ts` — GET (list), POST (create) -- [x] Task 2: Create `src/routes/api/apps/[id]/+server.ts` — GET, PATCH, DELETE -- [x] Task 3: Create `src/routes/api/apps/[id]/status/+server.ts` — GET healthcheck status -- [x] Task 4: Implement `src/lib/server/services/healthcheckService.ts` — perform HTTP health checks -- [x] Task 5: Implement `src/lib/server/jobs/healthcheckScheduler.ts` — node-cron scheduled pings -- [x] Task 6: Implement `src/lib/server/utils/iconResolver.ts` — resolve icon by type (Lucide, Simple Icons, Dashboard Icons CDN, upload path) -- [x] Task 7: Create `src/routes/apps/+page.server.ts` — load app list -- [x] Task 8: Create `src/routes/apps/+page.svelte` — app registry list page -- [x] Task 9: Create `src/lib/components/app/AppCard.svelte` — app card with status indicator -- [x] Task 10: Create `src/lib/components/app/AppForm.svelte` — create/edit app form (Superforms) -- [x] Task 11: Create `src/lib/components/app/AppIconPicker.svelte` — icon selection UI -- [x] Task 12: Create `src/lib/components/app/AppHealthBadge.svelte` — status badge (online/offline/degraded/unknown) -- [x] Task 13: Create `src/routes/api/health/+server.ts` — app health endpoint for Docker healthcheck -- [x] Task 14: Handle custom icon uploads — file upload endpoint + static serving from `static/uploads/` - -## Files to Modify/Create - -- `src/routes/api/apps/+server.ts` -- `src/routes/api/apps/[id]/+server.ts` -- `src/routes/api/apps/[id]/status/+server.ts` -- `src/routes/api/health/+server.ts` -- `src/lib/server/services/healthcheckService.ts` -- `src/lib/server/jobs/healthcheckScheduler.ts` -- `src/lib/server/utils/iconResolver.ts` -- `src/routes/apps/+page.server.ts` -- `src/routes/apps/+page.svelte` -- `src/lib/components/app/AppCard.svelte` -- `src/lib/components/app/AppForm.svelte` -- `src/lib/components/app/AppIconPicker.svelte` -- `src/lib/components/app/AppHealthBadge.svelte` - -## Acceptance Criteria - -- Apps can be created, read, updated, deleted via API -- Healthcheck scheduler runs on configured intervals per app -- Status is correctly derived: online/offline/degraded/unknown -- Icon resolver correctly maps all icon types to renderable output -- App list page displays apps with status badges -- Docker health endpoint returns 200 when server is running - -## Notes - -- Healthcheck runs in-process via node-cron (no external job runner) -- Default healthcheck: HTTP HEAD to app URL, expect 200, 5s timeout, 60s interval -- Store last N status records in AppStatus for history (sparklines are post-MVP) -- Custom icon uploads go to `static/uploads/` (Docker volume mount) -- ⚠️ Big Bang: pages will be functional but minimally styled until Phase 7 - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -All 14 tasks are implemented. Key artifacts available for Phase 5: - -- **API routes:** `/api/apps` (GET/POST), `/api/apps/[id]` (GET/PATCH/DELETE), `/api/apps/[id]/status` (GET), `/api/health` (GET), `/api/uploads` (POST) -- **Services:** `healthcheckService.ts` provides `checkAppHealth()` and `checkAllApps()`; `healthcheckScheduler.ts` provides `startScheduler()`/`stopScheduler()` using node-cron -- **Icon resolution:** `iconResolver.ts` maps all 4 icon types (lucide, simple, url, emoji) to renderable objects; `AppCard.svelte` renders them with CDN fallback for simple-icons -- **UI components:** `AppCard`, `AppForm` (Superforms), `AppIconPicker`, `AppHealthBadge` are ready for embedding in board widgets -- **File uploads:** `/api/uploads` validates SVG/PNG/JPG/WebP under 1MB, saves to `static/uploads/` -- **Page:** `/apps` lists all registered apps with category filtering, search, and inline create form - -Phase 5 can reference apps via `appId` in widgets. The `appService.findAll()` and `appService.findById()` include latest status in responses. The healthcheck scheduler should be started from `hooks.server.ts` or a startup hook in Phase 8. diff --git a/plans/mvp-web-app-launcher/phase-5-board-widgets.md b/plans/mvp-web-app-launcher/phase-5-board-widgets.md deleted file mode 100644 index a1f1ff0..0000000 --- a/plans/mvp-web-app-launcher/phase-5-board-widgets.md +++ /dev/null @@ -1,92 +0,0 @@ -# Phase 5: Board, Section & Widget System - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Build the board/section/widget system — the core UI of the dashboard. Implement CRUD APIs, the board view page with collapsible sections and app widgets in a responsive grid, and the board editor. - -## Tasks - -- [x] Task 1: Create `src/routes/api/boards/+server.ts` — GET (list, filtered by permissions), POST -- [x] Task 2: Create `src/routes/api/boards/[id]/+server.ts` — GET, PATCH, DELETE -- [x] Task 3: Create `src/routes/api/boards/[id]/sections/+server.ts` — GET, POST -- [x] Task 4: Create `src/routes/api/boards/[id]/sections/[sid]/+server.ts` — GET, PATCH, DELETE -- [x] Task 5: Create `src/routes/api/boards/[id]/sections/[sid]/widgets/+server.ts` — GET, POST, PATCH, DELETE -- [x] Task 6: Create `src/routes/boards/+page.server.ts` — load board list -- [x] Task 7: Create `src/routes/boards/+page.svelte` — board list page -- [x] Task 8: Create `src/routes/boards/[boardId]/+page.server.ts` — load board with sections, widgets, app data -- [x] Task 9: Create `src/routes/boards/[boardId]/+page.svelte` — board view page -- [x] Task 10: Create `src/routes/boards/[boardId]/edit/+page.server.ts` — board editor data + actions -- [x] Task 11: Create `src/routes/boards/[boardId]/edit/+page.svelte` — board editor page -- [x] Task 12: Create `src/lib/components/board/Board.svelte` — board container -- [x] Task 13: Create `src/lib/components/board/BoardHeader.svelte` — board title, description, actions -- [x] Task 14: Create `src/lib/components/board/BoardCard.svelte` — board card for list view -- [x] Task 15: Create `src/lib/components/section/Section.svelte` — section container -- [x] Task 16: Create `src/lib/components/section/SectionHeader.svelte` — section title with collapse toggle -- [x] Task 17: Create `src/lib/components/section/SectionCollapsible.svelte` — collapsible wrapper -- [x] Task 18: Create `src/lib/components/widget/AppWidget.svelte` — app widget displaying icon, name, status -- [x] Task 19: Create `src/lib/components/widget/WidgetContainer.svelte` — generic widget wrapper -- [x] Task 20: Create `src/lib/components/widget/WidgetGrid.svelte` — responsive grid layout for widgets - -## Files to Modify/Create - -- `src/routes/api/boards/+server.ts` -- `src/routes/api/boards/[id]/+server.ts` -- `src/routes/api/boards/[id]/sections/+server.ts` -- `src/routes/api/boards/[id]/sections/[sid]/+server.ts` -- `src/routes/api/boards/[id]/sections/[sid]/widgets/+server.ts` -- `src/routes/boards/+page.server.ts` -- `src/routes/boards/+page.svelte` -- `src/routes/boards/[boardId]/+page.server.ts` -- `src/routes/boards/[boardId]/+page.svelte` -- `src/routes/boards/[boardId]/edit/+page.server.ts` -- `src/routes/boards/[boardId]/edit/+page.svelte` -- `src/lib/components/board/*.svelte` -- `src/lib/components/section/*.svelte` -- `src/lib/components/widget/*.svelte` - -## Acceptance Criteria - -- Boards can be created, listed, viewed, edited, deleted -- Sections within boards support CRUD and ordering -- Widgets within sections support CRUD and ordering -- Board view renders sections with collapsible behavior -- App widgets show icon, name, status dot, and link to app URL -- Responsive grid adapts to screen size -- Default board is accessible from root page - -## Notes - -- MVP supports only AppWidget type; schema should have `type` field for future widget types -- Widget config is JSON: `{ appId: string }` for AppWidget -- Section collapse uses Svelte `slide` transition -- Board editor is a form-based editor (drag-and-drop is post-MVP Phase 2) -- Permission filtering on board list uses permissionService -- Big Bang: functional but minimally styled until Phase 7 - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -Phase 5 is complete. All board, section, and widget CRUD APIs are implemented with permission-based filtering (admin sees all, regular users see permitted boards, guests see guest-accessible boards only). The board view page loads the full board hierarchy (board -> sections -> widgets -> app + status) via `boardService.findBoardById`. The board editor provides form-based management of board properties, sections (add/delete), and widgets (add app widgets from a dropdown, remove). All Svelte components use runes mode and follow existing patterns: - -- `Board.svelte` renders sections in order -- `Section.svelte` uses `SectionHeader` (chevron toggle) + `SectionCollapsible` (Svelte `slide` transition) -- `WidgetGrid.svelte` uses a responsive CSS grid (2/3/4 cols) -- `AppWidget.svelte` displays app icon, name, and health status badge (reuses `AppHealthBadge`) -- `BoardCard.svelte` shows board summary with section count, default/guest badges - -Key files for Phase 6 (Admin Panel): - -- Board API routes at `/api/boards/**` are ready for admin operations -- Permission checking via `permissionService.checkPermission()` is integrated into all write operations -- Board editor at `/boards/[boardId]/edit` is functional for admin use diff --git a/plans/mvp-web-app-launcher/phase-6-admin-panel.md b/plans/mvp-web-app-launcher/phase-6-admin-panel.md deleted file mode 100644 index 3dea5f0..0000000 --- a/plans/mvp-web-app-launcher/phase-6-admin-panel.md +++ /dev/null @@ -1,93 +0,0 @@ -# Phase 6: Admin Panel - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Build the admin panel with user management, group management, app management, board management, and system settings configuration. - -## Tasks - -- [x] Task 1: Create `src/routes/admin/+layout.server.ts` — admin auth guard (role check) -- [x] Task 2: Create `src/routes/admin/+layout.svelte` — admin layout with nav -- [x] Task 3: Create `src/routes/api/users/+server.ts` — GET (list), POST (create user) -- [x] Task 4: Create `src/routes/api/users/[id]/+server.ts` — GET, PATCH, DELETE -- [x] Task 5: Create `src/routes/api/groups/+server.ts` — GET (list), POST (create group) -- [x] Task 6: Create `src/routes/api/groups/[id]/+server.ts` — GET, PATCH, DELETE -- [x] Task 7: Create `src/routes/api/admin/settings/+server.ts` — GET, PATCH system settings -- [x] Task 8: Create `src/routes/admin/users/+page.server.ts` — load users -- [x] Task 9: Create `src/routes/admin/users/+page.svelte` — user management page -- [x] Task 10: Create `src/routes/admin/groups/+page.server.ts` — load groups -- [x] Task 11: Create `src/routes/admin/groups/+page.svelte` — group management page -- [x] Task 12: Create `src/routes/admin/settings/+page.server.ts` — load/update settings -- [x] Task 13: Create `src/routes/admin/settings/+page.svelte` — system settings page -- [x] Task 14: Create `src/lib/components/admin/UserTable.svelte` — user list with actions -- [x] Task 15: Create `src/lib/components/admin/GroupTable.svelte` — group list with actions -- [x] Task 16: Create `src/lib/components/admin/SettingsForm.svelte` — settings form -- [x] Task 17: Create `src/lib/components/admin/PermissionEditor.svelte` — permission assignment UI -- [x] Task 18: Create `src/routes/api/search/+server.ts` — global search endpoint (searches apps + boards) - -## Files to Modify/Create - -- `src/routes/admin/+layout.server.ts` -- `src/routes/admin/+layout.svelte` -- `src/routes/admin/users/+page.server.ts` -- `src/routes/admin/users/+page.svelte` -- `src/routes/admin/groups/+page.server.ts` -- `src/routes/admin/groups/+page.svelte` -- `src/routes/admin/settings/+page.server.ts` -- `src/routes/admin/settings/+page.svelte` -- `src/routes/api/users/+server.ts` -- `src/routes/api/users/[id]/+server.ts` -- `src/routes/api/groups/+server.ts` -- `src/routes/api/groups/[id]/+server.ts` -- `src/routes/api/admin/settings/+server.ts` -- `src/routes/api/search/+server.ts` -- `src/lib/components/admin/*.svelte` - -## Acceptance Criteria - -- Admin-only routes are protected (non-admin users get 403/redirect) -- Users can be created, edited, deleted, assigned to groups -- Groups can be created, edited, deleted -- System settings can be viewed and updated (auth mode, registration, theme defaults, healthcheck defaults) -- Search API returns matching apps and boards filtered by user permissions -- All forms use Superforms + Zod validation - -## Notes - -- Admin role is checked in `+layout.server.ts` — redirect non-admins -- User creation by admin sets password directly (no email verification in MVP) -- OAuth config fields in settings are stored but non-functional until post-MVP Phase 2 -- Permission editor UI: simple select dropdowns for entity + target + level -- ⚠️ Big Bang: functional but minimally styled until Phase 7 - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -**What was built:** - -- Admin layout with auth guard (`requireAdmin`) and navigation (Users/Groups/Settings + Back to Dashboard) -- User management: full CRUD via Superforms, inline role editing, group membership management (add/remove), delete with confirmation -- Group management: full CRUD via Superforms, inline editing, member count display, default group toggle -- System settings: auth mode selector (local/oauth/both), registration toggle, OAuth config fields (stored, non-functional), theme defaults (dark/light + hex color), healthcheck defaults (JSON) -- Permission editor: reusable component with entity type/entity, target type/target, and level selectors, grant/revoke actions, existing permissions table -- Search API: `GET /api/search?q=term` searches apps (name, description, category) and boards (name, description), filters results by user permissions (admins see all, regular users filtered via `permissionService.checkPermission`) -- All API routes use the existing response envelope (`success`/`error` from `$lib/server/utils/response.ts`) and Zod validation schemas -- Admin API routes: `/api/users` (GET/POST), `/api/users/[id]` (GET/PATCH/DELETE), `/api/groups` (GET/POST), `/api/groups/[id]` (GET/PATCH/DELETE), `/api/admin/settings` (GET/PATCH) -- Self-deletion protection: admin cannot delete their own account - -**Available for Phase 7:** - -- All admin components in `src/lib/components/admin/` (UserTable, GroupTable, SettingsForm, PermissionEditor) — ready for UI polish -- Admin layout nav bar — can be styled with active states, icons -- PermissionEditor is a reusable client-side component with callback props (`onGrant`/`onRevoke`) — can be integrated into any admin page diff --git a/plans/mvp-web-app-launcher/phase-7-ui-polish.md b/plans/mvp-web-app-launcher/phase-7-ui-polish.md deleted file mode 100644 index 52cf2d9..0000000 --- a/plans/mvp-web-app-launcher/phase-7-ui-polish.md +++ /dev/null @@ -1,112 +0,0 @@ -# Phase 7: UI Polish & Ambient Backgrounds - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Objective - -Polish the entire UI: implement the root layout with sidebar and header, dark/light/system theme with HSL customization, ambient animated backgrounds, page transitions, animations, skeleton loading states, and responsive design. - -## Tasks - -- [x] Task 1: Create `src/lib/components/layout/MainLayout.svelte` — root layout wrapper -- [x] Task 2: Create `src/lib/components/layout/Sidebar.svelte` — collapsible sidebar with board list -- [x] Task 3: Create `src/lib/components/layout/Header.svelte` — top bar with search trigger, user menu, theme toggle -- [x] Task 4: Create `src/lib/components/layout/ThemeToggle.svelte` — dark/light/system toggle -- [x] Task 5: Create `src/lib/stores/theme.svelte.ts` — Svelte 5 rune-based theme store (HSL primary color, mode) -- [x] Task 6: Create `src/lib/stores/ui.svelte.ts` — sidebar state, layout preferences -- [x] Task 7: Create `src/lib/stores/search.svelte.ts` — search dialog state -- [x] Task 8: Update `src/app.css` — complete theme system with CSS custom properties, HSL-based colors, dark/light variants -- [x] Task 9: Create `src/lib/components/background/AmbientBackground.svelte` — background switcher component -- [x] Task 10: Create `src/lib/components/background/MeshGradient.svelte` — animated mesh gradient using tweened/spring -- [x] Task 11: Create `src/lib/components/background/ParticleField.svelte` — canvas-based particle animation -- [x] Task 12: Create `src/lib/components/background/AuroraEffect.svelte` — aurora borealis CSS animation -- [x] Task 13: Create `src/lib/components/search/SearchDialog.svelte` — Cmd/Ctrl+K search dialog -- [x] Task 14: Create `src/lib/components/search/SearchResult.svelte` — search result item -- [x] Task 15: Create `src/lib/components/search/SearchTrigger.svelte` — search bar trigger in header -- [x] Task 16: Add page transitions to `+layout.svelte` — fade/fly transitions between routes -- [x] Task 17: Add section expand/collapse animations (Svelte slide transition) -- [x] Task 18: Add card hover effects — subtle scale + shadow lift via CSS + spring -- [x] Task 19: Add status indicator pulse animation (CSS @keyframes) -- [x] Task 20: Add skeleton loading states for boards, apps, sections -- [x] Task 21: Ensure fully responsive design — desktop, tablet, mobile breakpoints -- [x] Task 22: Update `src/routes/+layout.svelte` — integrate MainLayout, AmbientBackground, theme system -- [x] Task 23: Polish login and register pages with consistent styling -- [x] Task 24: Polish all existing pages (apps, boards, admin) with consistent component styling - -## Files to Modify/Create - -- `src/lib/components/layout/MainLayout.svelte` -- `src/lib/components/layout/Sidebar.svelte` -- `src/lib/components/layout/Header.svelte` -- `src/lib/components/layout/ThemeToggle.svelte` -- `src/lib/stores/theme.svelte.ts` -- `src/lib/stores/ui.svelte.ts` -- `src/lib/stores/search.svelte.ts` -- `src/app.css` — update -- `src/lib/components/background/AmbientBackground.svelte` -- `src/lib/components/background/MeshGradient.svelte` -- `src/lib/components/background/ParticleField.svelte` -- `src/lib/components/background/AuroraEffect.svelte` -- `src/lib/components/search/SearchDialog.svelte` -- `src/lib/components/search/SearchResult.svelte` -- `src/lib/components/search/SearchTrigger.svelte` -- `src/routes/+layout.svelte` — update -- Various existing component files — add animations, polish styling - -## Acceptance Criteria - -- Dark/Light/System theme works with smooth CSS transitions -- HSL-based primary color customization works -- At least one ambient background (mesh gradient) animates smoothly -- Sidebar is collapsible and shows board list -- Header has search trigger, user menu, theme toggle -- Cmd/Ctrl+K opens search dialog -- Page transitions are smooth -- Section collapse is animated -- Card hover has scale + shadow effect -- Status dots pulse when online -- Skeleton loaders appear during data fetches -- Layout is responsive at desktop (>1024px), tablet (768-1024px), mobile (<768px) - -## Notes - -- Use Svelte 5 runes for stores, NOT legacy `writable`/`readable` -- Use `svelte/motion` (tweened, spring) for ambient animations -- AmbientBackground should be configurable and toggleable -- Search dialog uses the `/api/search` endpoint from Phase 6 -- Keep animations performant — prefer CSS transforms/opacity over layout-triggering properties -- Use Tailwind utility classes as primary styling approach - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -Phase 7 (UI Polish & Ambient Backgrounds) is complete. All 24 tasks implemented: - -**Stores (3 files):** Three Svelte 5 rune-based stores created — `theme.svelte.ts` (dark/light/system mode, HSL primary color, background type, localStorage persistence, auto-applies classes to ``), `ui.svelte.ts` (sidebar collapsed/hidden state, responsive breakpoint detection, localStorage persistence), `search.svelte.ts` (Cmd/Ctrl+K hotkey, debounced fetch to `/api/search`, grouped results by type). - -**Layout (4 components):** `MainLayout.svelte` wraps the entire app with sidebar + header + content + ambient background + search dialog. `Sidebar.svelte` is collapsible (icons-only on tablet, hidden on mobile with hamburger toggle), shows navigation links and board list with active-state highlighting, admin link for admin users. `Header.svelte` provides sticky top bar with mobile hamburger, search trigger, background selector dropdown, theme toggle, and user avatar menu with logout. `ThemeToggle.svelte` cycles through light/dark/system modes. - -**Backgrounds (4 components):** `AmbientBackground.svelte` switches between three effects. `MeshGradient.svelte` renders 4 SVG blobs with requestAnimationFrame-driven drift, blurred, at low opacity, colored by HSL primary. `ParticleField.svelte` draws 70 particles on a canvas with connection lines between nearby particles. `AuroraEffect.svelte` uses CSS gradient animation on three skewed bands with the aurora-shift keyframe. - -**Search (3 components):** `SearchDialog.svelte` is a modal overlay with text input, debounced search, results grouped by apps/boards, loading spinner, empty state. `SearchResult.svelte` displays individual results with type badge. `SearchTrigger.svelte` shows a search button in the header with Cmd/Ctrl+K shortcut hint. - -**CSS/Theme:** `app.css` updated with HSL-based `--primary` using `--primary-h`/`--primary-s`/`--primary-l` variables (JS-settable), status-pulse keyframe for online dots, card-hover utility class (scale + shadow), skeleton shimmer animation, aurora-shift keyframe, scrollbar styling, smooth body background transition. `app.html` includes inline FOUC-prevention script that reads localStorage before first paint. - -**Animations:** Page transitions via `{#key}` + Svelte `fade` in `+layout.svelte`. Section collapse uses existing Svelte `slide` transition. Card hover via `.card-hover` CSS class on AppCard, BoardCard, AppWidget. Status pulse via `.status-online` CSS class on AppHealthBadge. - -**Skeletons:** Three skeleton components — `CardSkeleton`, `BoardSkeleton`, `SectionSkeleton` — using the `.skeleton` shimmer CSS class. - -**Page Polish:** All pages updated to use semantic theme variables (no hardcoded gray/indigo colors). Login and register pages enhanced with logo icon, backdrop blur, smoother input styling. Board pages, edit page, and admin layout all converted from hardcoded dark colors to CSS variable-based theming. Admin layout uses pill-style active nav tabs. - -**Responsive:** Sidebar hidden on mobile (<768px) with hamburger toggle; collapsed to icons on tablet; expanded on desktop. Widget grids use responsive grid-cols. Login/register are centered and full-width on mobile. - -**Layout server:** `+layout.server.ts` now fetches sidebar board list (admin: all boards, regular users: all boards, guests: guest-accessible only). diff --git a/plans/mvp-web-app-launcher/phase-8-integration-deploy.md b/plans/mvp-web-app-launcher/phase-8-integration-deploy.md deleted file mode 100644 index b3a13fd..0000000 --- a/plans/mvp-web-app-launcher/phase-8-integration-deploy.md +++ /dev/null @@ -1,106 +0,0 @@ -# Phase 8: Integration, Testing & Deployment - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Integrate all phases into a fully working application. Fix all build errors, add test coverage, verify Docker deployment, and finalize the CI pipeline. This is the Big Bang convergence phase — everything must work after this. - -## Tasks - -- [x] Task 1: Fix all TypeScript/build errors across the entire codebase -- [x] Task 2: Verify `npm run build` succeeds with adapter-node output -- [x] Task 3: Verify `npm run check` (svelte-check) passes -- [x] Task 4: Verify `npm run lint` passes -- [x] Task 5: Write unit tests for services (authService, appService, boardService, groupService, userService, permissionService) -- [x] Task 6: Write unit tests for utilities (response envelope, validators, constants, cn) -- [ ] Task 7: Write integration tests for API endpoints (auth, apps, boards, admin) -- [ ] Task 8: Write component tests for key Svelte components (AppWidget, Board, Section) -- [ ] Task 9: Verify test coverage >= 80% -- [x] Task 10: Update `prisma/seed.ts` with comprehensive demo data -- [x] Task 11: Verify Docker build config (Dockerfile reviewed, added migrate on startup) -- [ ] Task 12: Verify `docker-compose up` starts the app correctly (requires Docker runtime) -- [ ] Task 13: Verify healthcheck endpoint works in Docker (requires Docker runtime) -- [ ] Task 14: Finalize `.gitea/workflows/ci.yml` — ensure all CI steps pass -- [ ] Task 15: Create `.env.example` with documentation for all env vars -- [ ] Task 16: End-to-end smoke test: register -> login -> view board -> add app -> verify healthcheck - -## Files Modified/Created - -### Build fixes - -- `src/lib/components/admin/SettingsForm.svelte` — Fixed JSON curly brace escaping in placeholder -- `src/lib/server/services/authService.ts` — Fixed JWT `expiresIn` type cast for zod 3.25+ -- `src/lib/stores/theme.svelte.ts` — Reordered `#systemPreference` initialization before `$derived` -- `src/lib/utils/zod-adapter.ts` — **NEW** Wrapper for sveltekit-superforms zod adapter (zod 3.25 compat) -- `src/routes/admin/groups/+page.server.ts` — Updated zod import to use adapter -- `src/routes/admin/settings/+page.server.ts` — Updated zod import to use adapter -- `src/routes/admin/users/+page.server.ts` — Updated zod import to use adapter -- `src/routes/apps/+page.server.ts` — Updated zod import to use adapter -- `src/routes/login/+page.server.ts` — Updated zod import to use adapter -- `src/routes/register/+page.server.ts` — Updated zod import to use adapter -- `src/lib/components/app/AppForm.svelte` — Fixed iconType type cast - -### Lint fixes - -- `eslint.config.js` — Disabled `svelte/no-navigation-without-resolve` for static routes -- `src/lib/components/admin/PermissionEditor.svelte` — Added `{#each}` keys -- `src/lib/components/admin/UserTable.svelte` — Added `{#each}` key -- `src/lib/components/background/MeshGradient.svelte` — Added `{#each}` key, removed unused var -- `src/lib/components/layout/Header.svelte` — Added `{#each}` key -- `src/routes/admin/+layout.svelte` — Added `{#each}` key -- `src/routes/apps/+page.svelte` — Added `{#each}` key, removed unused import -- `src/routes/boards/[boardId]/edit/+page.server.ts` — Removed unused `redirect` import - -### Tests (NEW) - -- `src/lib/utils/__tests__/cn.test.ts` — cn() utility tests -- `src/lib/utils/__tests__/constants.test.ts` — Constants coverage tests -- `src/lib/utils/__tests__/validators.test.ts` — Zod schema validation tests (35 tests) -- `src/lib/server/utils/__tests__/response.test.ts` — API response envelope tests -- `src/lib/server/services/__tests__/authService.test.ts` — Auth service tests (JWT, password, tokens) -- `src/lib/server/services/__tests__/appService.test.ts` — App service CRUD tests -- `src/lib/server/services/__tests__/boardService.test.ts` — Board/section/widget service tests -- `src/lib/server/services/__tests__/groupService.test.ts` — Group service tests -- `src/lib/server/services/__tests__/userService.test.ts` — User service tests -- `src/lib/server/services/__tests__/permissionService.test.ts` — Permission service tests - -### Docker & config - -- `Dockerfile` — Added prisma migrate deploy on container startup -- `vite.config.ts` — Changed test environment from jsdom to node -- `prisma/seed.ts` — Expanded with regular user, 7 apps, 3 sections, idempotent seeding - -## Acceptance Criteria - -- [x] `npm run build` succeeds -- [x] `npm run check` passes with 0 errors (9 warnings only) -- [x] `npm run lint` passes with 0 errors -- [x] `npm test` passes — 115 tests across 10 test files, all green -- [x] Docker config reviewed and updated -- [x] Seed script creates comprehensive demo data - -## Notes - -The main convergence issue was **zod 3.25 incompatibility** with sveltekit-superforms v2's `ZodObjectType` constraint. Fixed with a typed wrapper in `src/lib/utils/zod-adapter.ts` that preserves type inference while bypassing the constraint boundary. - -## Review Checklist - -- [x] All critical tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [x] Build passes -- [x] Tests pass (new + existing) - -## Handoff - -Phase 8 core tasks complete. Remaining items for future iteration: - -- API integration tests and component tests (Tasks 7-8) -- Full coverage analysis (Task 9) -- Docker runtime verification (Tasks 12-13) -- CI pipeline finalization (Task 14) -- .env.example creation (Task 15) -- Full E2E smoke test (Task 16) diff --git a/plans/phase-2-enhanced-features/CONTEXT.md b/plans/phase-2-enhanced-features/CONTEXT.md deleted file mode 100644 index 44a9d8e..0000000 --- a/plans/phase-2-enhanced-features/CONTEXT.md +++ /dev/null @@ -1,100 +0,0 @@ -# Feature Context: Phase 2 — Enhanced Features - -## Current State - -All 6 phases complete. The codebase is fully integrated and passing all checks. - -- `npm run build` succeeds -- `npm run check` passes (0 errors) -- `npm run lint` passes (0 errors) -- `npm test` passes (175 tests, 14 test files) - -## Temporary Workarounds - -- None yet - -## Cross-Phase Dependencies - -- Phase 1 (OAuth) is independent — touches auth system only -- Phase 2 (DnD) is independent — touches board editor UI only -- Phase 3 (Widgets) depends on existing widget system from MVP -- Phase 4 (Access Control) depends on existing permission system from MVP -- Phase 5 (Integration) depends on all prior phases - -## Implementation Notes - -- Big Bang strategy: intermediate phases may not build. Phase 6 is the convergence phase. -- OAuth uses `openid-client` (already installed in MVP dependencies) -- DnD uses `svelte-dnd-action` (installed in Phase 2) -- New widget types extend the existing Widget model's `type` and `config` JSON fields - -## Phase 2 (DnD) — Completed - -- Installed `svelte-dnd-action` package -- Created `DraggableBoard.svelte`, `DraggableSection.svelte`, `DraggableWidget.svelte` component hierarchy -- Board edit page now uses DnD for section and widget reordering (including cross-section widget moves) -- Added `PUT /api/boards/[id]/reorder` and `PUT /api/boards/[id]/sections/[sid]/reorder` endpoints -- Extended `boardService.ts` with `reorderSections()`, `reorderWidgets()`, `moveWidget()` using Prisma transactions -- Visual drag handles (grip dots) and dashed drop zone indicators added via Tailwind -- Edit page actions (add/delete section/widget) use `invalidateAll()` for data refresh; DnD uses optimistic fetch - -## Phase 4 (Additional Widget Types) — Completed - -- Installed `marked` package for markdown rendering -- WidgetType enum already had BOOKMARK, NOTE, EMBED, STATUS from MVP constants -- Added per-type Zod config schemas in `validators.ts`: `appWidgetConfigSchema`, `bookmarkWidgetConfigSchema`, `noteWidgetConfigSchema`, `embedWidgetConfigSchema`, `statusWidgetConfigSchema` -- Updated `src/lib/types/widget.ts` config interfaces to match spec (BookmarkWidgetConfig, NoteWidgetConfig, EmbedWidgetConfig, StatusWidgetConfig) -- Created 4 new widget components: - - `BookmarkWidget.svelte` — clickable card with icon, label, description, opens URL in new tab - - `NoteWidget.svelte` — renders markdown via `marked` with basic HTML sanitization - - `EmbedWidget.svelte` — iframe with configurable height, sandbox security, loading spinner - - `StatusWidget.svelte` — aggregated status bar with online/offline/degraded/unknown counts, expandable per-app detail -- Created `WidgetRenderer.svelte` — universal type-switch component dispatching to correct widget by type -- Updated `WidgetGrid.svelte` to use WidgetRenderer; note/embed/status widgets span full grid width -- Updated `DraggableSection.svelte` with widget type selector dropdown and type-specific config forms (app selector, bookmark URL/label/icon/desc, note textarea with format, embed URL/height, status multi-select apps) -- `onAddWidget` callback changed from `(sectionId, appId)` to `(sectionId, widgetDataJson)` across DraggableBoard and edit page -- Board view server (`[boardId]/+page.server.ts`) now loads all apps via `appService.findAll()` for StatusWidget -- Plumbed `allApps` prop through Board -> Section -> WidgetGrid -> WidgetRenderer -> StatusWidget -- Edit server action `addWidget` now handles `configJson` form field for non-app widget types - -## Phase 3 (Localization EN/RU) — Completed - -- Installed `svelte-i18n` package for i18n support -- Created `src/lib/i18n/en.json` and `src/lib/i18n/ru.json` with ~180 translation keys covering all UI strings -- Created `src/lib/i18n/index.ts` with locale detection (localStorage > browser navigator > fallback 'en') and `storeLocale()` helper -- Created `LanguageSwitcher.svelte` — EN/RU toggle button added to Header, persists preference to localStorage key `wal-locale` -- Root `+layout.svelte` imports `$lib/i18n/index.js` to initialize i18n before any component renders -- Extracted all hardcoded strings from: layout (Header, Sidebar, MainLayout, ThemeToggle), auth pages (login, register), board/section/widget components, app components (AppForm, AppHealthBadge, AppIconPicker), admin pages (users, groups, settings, PermissionEditor), search components (SearchDialog, SearchTrigger), home page, and DnD components -- Translation key structure uses dot-notation grouped by feature: `nav.*`, `auth.*`, `board.*`, `section.*`, `widget.*`, `app.*`, `admin.*`, `search.*`, `common.*`, `status.*`, `theme.*`, `bg.*`, `sidebar.*`, `home.*` -- All status labels (online/offline/degraded/unknown) are now translated via `$t('status.*')` in AppHealthBadge -- Phase 4 widget type form labels (bookmark, note, embed, status fields) are partially untranslated — can be addressed in Phase 6 - -## Phase 5 (Per-Board Access Control UI) — Completed - -- Created `src/lib/components/board/BoardAccessControl.svelte` — self-contained board permission manager with search/autocomplete for users and groups, fetches permissions from `/api/boards/[id]/permissions` -- Created `src/lib/components/board/BoardShareDialog.svelte` — modal dialog with copy link, guest access toggle, quick permission grant, and current access list -- Created `src/routes/api/boards/[id]/permissions/+server.ts` — REST endpoint for GET (list), POST (grant), DELETE (revoke) board permissions with proper auth checks -- Enhanced `src/lib/components/admin/PermissionEditor.svelte` — replaced plain select dropdowns with search/autocomplete inputs (onfocus/onblur managed dropdowns) -- Updated `src/lib/components/board/BoardCard.svelte` — added globe icon for guest-accessible boards, lock icon for private boards, users icon for boards with shared permissions -- Updated `src/routes/boards/+page.server.ts` — computes `hasSharedPermissions` flag per board for access indicators -- Updated `src/routes/boards/[boardId]/edit/+page.svelte` — added dedicated "Guest Access" section with status preview and "Permissions" section with `BoardAccessControl` component -- Updated `src/routes/boards/[boardId]/edit/+page.server.ts` — loads users and groups for permission editor, computes `canManagePermissions` flag -- Updated `src/lib/components/board/BoardHeader.svelte` — added "Share" button that triggers share dialog callback -- Updated `src/routes/boards/[boardId]/+page.svelte` — integrated `BoardShareDialog` with guest toggle via PATCH API -- Updated `src/routes/boards/[boardId]/+page.server.ts` — loads users/groups for share dialog when user can edit -- Added ~20 new i18n keys (`board.access_*`, `board.share_*`, `board.guest_access_*`, `board.permissions_*`, `admin.perm_search_placeholder`) to both `en.json` and `ru.json` -- Big Bang strategy: no build/test verification performed — Phase 6 integration may be needed - -## Phase 6 (Integration & Polish) — Completed - -- Installed missing `svelte-i18n` dependency -- Fixed `oauthService.ts` type error: undefined sub claim now guarded before `fetchUserInfo` call -- Fixed `DynamicIcon.svelte`: replaced deprecated `` with Svelte 5 dynamic component pattern -- Fixed lint errors: removed unused imports (`error` in oauth test, `WidgetType` in edit page), suppressed `@html` lint rule on sanitized content, marked unused `boardId` prop in DraggableSection -- Disabled `svelte/prefer-writable-derived` ESLint rule for Svelte files (DnD requires `$state` + `$effect` pattern) -- Wrote 60 new tests across 4 test files: - - `oauthService.test.ts` (10 tests) — PKCE, auth URL, callback, cache invalidation - - `widgetValidators.test.ts` (28 tests) — all 5 widget config schemas - - `boardReorder.test.ts` (9 tests) — section/widget reorder, cross-section move - - `permissions.test.ts` (13 tests) — GET/POST/DELETE board permissions API -- Updated `prisma/seed.ts` with bookmark, note, embed, status widgets + team board with user/group permissions diff --git a/plans/phase-2-enhanced-features/PLAN.md b/plans/phase-2-enhanced-features/PLAN.md deleted file mode 100644 index 8ca9c98..0000000 --- a/plans/phase-2-enhanced-features/PLAN.md +++ /dev/null @@ -1,47 +0,0 @@ -# Feature: Phase 2 — Enhanced Features - -**Branch:** `feature/phase-2-enhanced-features` -**Base branch:** `master` -**Created:** 2026-03-24 -**Status:** Done -**Strategy:** Big Bang -**Mode:** Automated -**Execution:** Orchestrator - -## Summary - -Add OAuth/Authentik integration, drag-and-drop reordering, localization (EN/RU), additional widget types (bookmark, note, embed, status), and per-board access control UI. - -## Build & Test Commands - -- **Build:** `npm run build` -- **Test:** `npm test` -- **Lint:** `npm run lint` -- **Type Check:** `npm run check` - -## Phases - -- [x] Phase 1: OAuth/Authentik Integration [fullstack] → [subplan](./phase-1-oauth.md) -- [x] Phase 2: Drag-and-Drop Reordering [frontend] → [subplan](./phase-2-dnd.md) -- [x] Phase 3: Localization EN/RU [fullstack] → [subplan](./phase-3-localization.md) -- [x] Phase 4: Additional Widget Types [fullstack] → [subplan](./phase-4-widgets.md) -- [x] Phase 5: Per-Board Access Control UI [fullstack] → [subplan](./phase-5-access-control.md) -- [x] Phase 6: Integration & Polish [fullstack] → [subplan](./phase-6-integration.md) - -## Phase Progress Log - -| Phase | Domain | Status | Review | Build | Committed | -| ----------------------- | --------- | ------ | ------ | ----- | --------- | -| Phase 1: OAuth | fullstack | Done | ⬜ | ⬜ | ⬜ | -| Phase 2: DnD | frontend | Done | ⬜ | ⬜ | ⬜ | -| Phase 3: Localization | fullstack | Done | ⬜ | ⬜ | ⬜ | -| Phase 4: Widgets | fullstack | Done | ⬜ | ⬜ | ⬜ | -| Phase 5: Access Control | fullstack | Done | ⬜ | ⬜ | ⬜ | -| Phase 6: Integration | fullstack | Done | ⬜ | ⬜ | ⬜ | - -## Final Review - -- [ ] Comprehensive code review -- [ ] Full build passes -- [ ] Full test suite passes -- [ ] Merged to `master` diff --git a/plans/phase-2-enhanced-features/phase-1-oauth.md b/plans/phase-2-enhanced-features/phase-1-oauth.md deleted file mode 100644 index a8c95db..0000000 --- a/plans/phase-2-enhanced-features/phase-1-oauth.md +++ /dev/null @@ -1,70 +0,0 @@ -# Phase 1: OAuth/Authentik Integration - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Add OIDC/OAuth2 authentication via Authentik, including redirect/callback flows, auto-provisioning users, and admin configuration UI. - -## Tasks - -- [x] Task 1: Create `src/lib/server/services/oauthService.ts` — OIDC client setup, discovery, token exchange -- [x] Task 2: Create `src/routes/auth/oauth/authorize/+server.ts` — redirect to Authentik with PKCE -- [x] Task 3: Create `src/routes/auth/oauth/callback/+server.ts` — handle callback, exchange code, provision user -- [x] Task 4: Update `src/lib/server/services/userService.ts` — add `findOrCreateByOAuth()` for auto-provisioning -- [x] Task 5: Update `src/routes/login/+page.svelte` — show OAuth button when auth mode is OAUTH or BOTH -- [x] Task 6: Update `src/routes/login/+page.server.ts` — load auth mode from SystemSettings -- [x] Task 7: Update `src/routes/admin/settings/+page.svelte` — make OAuth config fields functional (client ID, secret, discovery URL) -- [x] Task 8: Update `src/lib/components/admin/SettingsForm.svelte` — add OAuth test connection button -- [x] Task 9: Update `src/hooks.server.ts` — handle OAuth sessions alongside local JWT sessions (no changes needed — existing JWT hook handles OAuth users transparently) -- [x] Task 10: Add env vars to `.env.example` — OAUTH_CLIENT_ID, OAUTH_CLIENT_SECRET, OAUTH_DISCOVERY_URL, OAUTH_REDIRECT_URI - -## Files to Modify/Create - -- `src/lib/server/services/oauthService.ts` — NEW -- `src/routes/auth/oauth/authorize/+server.ts` — NEW -- `src/routes/auth/oauth/callback/+server.ts` — NEW -- `src/lib/server/services/userService.ts` — MODIFY -- `src/routes/login/+page.svelte` — MODIFY -- `src/routes/login/+page.server.ts` — MODIFY -- `src/routes/admin/settings/+page.svelte` — MODIFY -- `src/lib/components/admin/SettingsForm.svelte` — MODIFY -- `src/hooks.server.ts` — MODIFY -- `.env.example` — MODIFY - -## Acceptance Criteria - -- OAuth login redirects to Authentik and returns with valid session -- New OAuth users are auto-provisioned with correct role/groups -- Existing users can link OAuth identity -- Admin can configure OAuth provider in settings -- Auth mode selector (local/oauth/both) controls which login options appear -- Login page shows appropriate buttons based on auth mode - -## Notes - -- Use `openid-client` for OIDC discovery and token exchange -- Store OAuth state/nonce in HTTP-only cookies for CSRF protection -- Map Authentik groups to local groups by name -- OAuth users have nullable password field -- ⚠️ Big Bang: may not fully work until Phase 5 integration - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -- Installed `openid-client` v6.8.2 as a runtime dependency. -- OAuth flow issues local JWT tokens, so hooks.server.ts required no changes. -- New API endpoint `POST /api/admin/oauth/test` added for the test connection button in SettingsForm. -- `findOrCreateByOAuth()` syncs OAuth groups to local groups by name (groups must pre-exist locally). -- Login page conditionally renders OAuth button and/or local form based on `authMode` from SystemSettings. -- OIDC discovery result is cached in-memory and invalidated when the admin tests the connection. -- Phase 2 (DnD) and Phase 3 (Localization) are independent and can proceed in parallel. diff --git a/plans/phase-2-enhanced-features/phase-2-dnd.md b/plans/phase-2-enhanced-features/phase-2-dnd.md deleted file mode 100644 index 3f3aebf..0000000 --- a/plans/phase-2-enhanced-features/phase-2-dnd.md +++ /dev/null @@ -1,70 +0,0 @@ -# Phase 2: Drag-and-Drop Reordering - -**Status:** Done -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Objective - -Add drag-and-drop reordering for sections within boards and widgets within/across sections using svelte-dnd-action. - -## Tasks - -- [x] Task 1: Install `svelte-dnd-action` package -- [x] Task 2: Create `src/lib/components/board/DraggableBoard.svelte` — board with draggable sections -- [x] Task 3: Create `src/lib/components/section/DraggableSection.svelte` — section with draggable widgets -- [x] Task 4: Create `src/lib/components/widget/DraggableWidget.svelte` — draggable widget wrapper -- [x] Task 5: Update `src/routes/boards/[boardId]/edit/+page.svelte` — replace static editor with DnD editor -- [x] Task 6: Create `src/routes/api/boards/[id]/reorder/+server.ts` — API to persist section order changes -- [x] Task 7: Create `src/routes/api/boards/[id]/sections/[sid]/reorder/+server.ts` — API to persist widget order changes -- [x] Task 8: Update `src/lib/server/services/boardService.ts` — add `reorderSections()` and `reorderWidgets()` functions -- [x] Task 9: Add visual drag handles and drop zone indicators -- [x] Task 10: Support moving widgets between sections via cross-section DnD - -## Files to Modify/Create - -- `package.json` — add svelte-dnd-action -- `src/lib/components/board/DraggableBoard.svelte` — NEW -- `src/lib/components/section/DraggableSection.svelte` — NEW -- `src/lib/components/widget/DraggableWidget.svelte` — NEW -- `src/routes/boards/[boardId]/edit/+page.svelte` — MODIFY -- `src/routes/api/boards/[id]/reorder/+server.ts` — NEW -- `src/routes/api/boards/[id]/sections/[sid]/reorder/+server.ts` — NEW -- `src/lib/server/services/boardService.ts` — MODIFY - -## Acceptance Criteria - -- Sections can be reordered via drag-and-drop in the board editor -- Widgets can be reordered within a section -- Widgets can be moved between sections -- Order changes persist via API calls -- Drag handles are visible and accessible -- Drop zones are visually indicated during drag - -## Notes - -- `svelte-dnd-action` works well with Svelte 5 -- Use optimistic updates — reorder in UI immediately, sync to server in background -- Reorder APIs should accept an array of IDs in the new order -- Big Bang: may need integration fixes in Phase 6 - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -Phase 2 DnD is complete. Key additions: - -- `svelte-dnd-action` installed and integrated with Svelte 5 (`use:dndzone`, `onconsider`/`onfinalize` event pattern) -- Board editor (`/boards/[boardId]/edit`) now uses `DraggableBoard` > `DraggableSection` > `DraggableWidget` component hierarchy -- Sections support drag-and-drop reordering with grip-dot handles; widgets support reordering within and across sections -- Two new PUT API endpoints: `/api/boards/[id]/reorder` (section order) and `/api/boards/[id]/sections/[sid]/reorder` (widget order) -- `boardService.ts` extended with `reorderSections()`, `reorderWidgets()`, and `moveWidget()` — all using `$transaction` for atomicity -- Edit page uses `invalidateAll()` for server actions (add/delete) while DnD reorder uses optimistic fetch calls -- Drop zones use dashed borders; drag handles use grip-dot SVG icons with hover opacity transitions -- No changes to auth, admin, or view-mode components diff --git a/plans/phase-2-enhanced-features/phase-3-localization.md b/plans/phase-2-enhanced-features/phase-3-localization.md deleted file mode 100644 index 55b41e9..0000000 --- a/plans/phase-2-enhanced-features/phase-3-localization.md +++ /dev/null @@ -1,98 +0,0 @@ -# Phase 3: Localization (EN/RU) - -**Status:** Done -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Add internationalization (i18n) support with English and Russian locales. All UI strings should be translatable. Users can switch language in settings or header. - -## Tasks - -- [x] Task 1: Install `svelte-i18n` — Svelte 5 compatible i18n library -- [x] Task 2: Create locale files: `src/lib/i18n/en.json` and `src/lib/i18n/ru.json` -- [x] Task 3: Create `src/lib/i18n/index.ts` — i18n setup, locale detection, initialize with both locales -- [x] Task 4: Create `src/lib/components/layout/LanguageSwitcher.svelte` — language toggle (EN/RU) in header -- [x] Task 5: Extract all hardcoded strings from layout components (Sidebar, Header, MainLayout, ThemeToggle) -- [x] Task 6: Extract all hardcoded strings from auth pages (login, register) -- [x] Task 7: Extract all hardcoded strings from board/section/widget components -- [x] Task 8: Extract all hardcoded strings from app components (AppCard, AppForm, AppIconPicker, AppHealthBadge) -- [x] Task 9: Extract all hardcoded strings from admin pages (users, groups, settings, PermissionEditor) -- [x] Task 10: Extract all hardcoded strings from search components (SearchDialog, SearchTrigger) -- [x] Task 11: Add locale preference storage in localStorage (key: `wal-locale`) -- [x] Task 12: Update Header.svelte to include LanguageSwitcher -- [x] Task 13: Translate all strings to Russian in ru.json - -## Files to Modify/Create - -- `src/lib/i18n/en.json` — NEW -- `src/lib/i18n/ru.json` — NEW -- `src/lib/i18n/index.ts` — NEW -- `src/lib/components/layout/LanguageSwitcher.svelte` — NEW -- `src/lib/components/layout/Header.svelte` — MODIFIED -- `src/lib/components/layout/Sidebar.svelte` — MODIFIED -- `src/lib/components/layout/MainLayout.svelte` — MODIFIED -- `src/lib/components/layout/ThemeToggle.svelte` — MODIFIED -- `src/routes/+layout.svelte` — MODIFIED (i18n import) -- `src/routes/+page.svelte` — MODIFIED -- `src/routes/login/+page.svelte` — MODIFIED -- `src/routes/register/+page.svelte` — MODIFIED -- `src/routes/boards/+page.svelte` — MODIFIED -- `src/routes/boards/[boardId]/+page.svelte` — MODIFIED -- `src/routes/boards/new/+page.svelte` — MODIFIED -- `src/routes/boards/[boardId]/edit/+page.svelte` — MODIFIED -- `src/routes/apps/+page.svelte` — MODIFIED -- `src/routes/admin/+layout.svelte` — MODIFIED -- `src/routes/admin/users/+page.svelte` — MODIFIED -- `src/routes/admin/groups/+page.svelte` — MODIFIED -- `src/routes/admin/settings/+page.svelte` — MODIFIED -- `src/lib/components/board/Board.svelte` — MODIFIED -- `src/lib/components/board/BoardCard.svelte` — MODIFIED -- `src/lib/components/board/BoardHeader.svelte` — MODIFIED -- `src/lib/components/board/DraggableBoard.svelte` — MODIFIED -- `src/lib/components/section/DraggableSection.svelte` — MODIFIED -- `src/lib/components/widget/WidgetGrid.svelte` — MODIFIED -- `src/lib/components/widget/WidgetRenderer.svelte` — MODIFIED -- `src/lib/components/app/AppCard.svelte` — (no visible strings to extract) -- `src/lib/components/app/AppForm.svelte` — MODIFIED -- `src/lib/components/app/AppHealthBadge.svelte` — MODIFIED -- `src/lib/components/app/AppIconPicker.svelte` — MODIFIED -- `src/lib/components/search/SearchDialog.svelte` — MODIFIED -- `src/lib/components/search/SearchTrigger.svelte` — MODIFIED -- `src/lib/components/admin/UserTable.svelte` — MODIFIED -- `src/lib/components/admin/GroupTable.svelte` — MODIFIED -- `src/lib/components/admin/SettingsForm.svelte` — MODIFIED -- `src/lib/components/admin/PermissionEditor.svelte` — MODIFIED - -## Acceptance Criteria - -- All user-visible strings are translatable (no hardcoded text in components) -- English and Russian translations are complete -- Language switcher in the header toggles between EN/RU -- Locale preference persists across sessions (localStorage key `wal-locale`) - -## Notes - -- Uses flat key structure: `{ "nav.boards": "Boards", "nav.apps": "Apps", ... }` -- Translation keys are semantic and grouped by feature -- `svelte-i18n` installed as a dependency -- i18n initialized in root `+layout.svelte` via import of `$lib/i18n/index.js` -- Locale auto-detected from browser navigator, with localStorage override -- Phase 4 widget types (bookmark, note, embed, status) form labels in DraggableSection left partially untranslated as they are highly technical; core UI strings extracted - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -- `svelte-i18n` added as dependency. All components import `{ t }` from `svelte-i18n` and use `$t('key')` for strings. -- Locale files at `src/lib/i18n/en.json` and `src/lib/i18n/ru.json` contain ~180 translation keys. -- `LanguageSwitcher` component added to the Header, toggles EN/RU and persists to localStorage. -- Root layout imports `$lib/i18n/index.js` to initialize i18n before any component renders. -- Phase 4 widget form labels (bookmark URL, note content, embed height, etc.) are partially untranslated; they can be addressed in Phase 6 integration. diff --git a/plans/phase-2-enhanced-features/phase-4-widgets.md b/plans/phase-2-enhanced-features/phase-4-widgets.md deleted file mode 100644 index bb7e2cd..0000000 --- a/plans/phase-2-enhanced-features/phase-4-widgets.md +++ /dev/null @@ -1,87 +0,0 @@ -# Phase 3: Additional Widget Types - -**Status:** Done -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Add four new widget types: Bookmark, Note, Embed, and Status. Extend the widget system with type-specific rendering and configuration. - -## Tasks - -- [x] Task 1: Update `src/lib/utils/constants.ts` — ensure WidgetType enum has BOOKMARK, NOTE, EMBED, STATUS -- [x] Task 2: Update `src/lib/utils/validators.ts` — add Zod schemas for each widget type's config -- [x] Task 3: Create `src/lib/components/widget/BookmarkWidget.svelte` — URL + label + optional icon, no healthcheck -- [x] Task 4: Create `src/lib/components/widget/NoteWidget.svelte` — markdown/rich text display with edit mode -- [x] Task 5: Create `src/lib/components/widget/EmbedWidget.svelte` — iframe embed with configurable URL and height -- [x] Task 6: Create `src/lib/components/widget/StatusWidget.svelte` — aggregated status of multiple apps (green/red/yellow summary) -- [x] Task 7: Create `src/lib/components/widget/WidgetRenderer.svelte` — universal widget renderer that switches by type -- [x] Task 8: Update `src/lib/components/widget/WidgetGrid.svelte` — use WidgetRenderer instead of hardcoded AppWidget -- [x] Task 9: Update board editor — add widget type selector when adding widgets -- [x] Task 10: Update `src/routes/boards/[boardId]/edit/+page.svelte` — type-specific config forms for each widget type -- [x] Task 11: Update `src/routes/boards/[boardId]/edit/+page.server.ts` — handle different widget types in create action -- [x] Task 12: Install `marked` for Note widget markdown rendering - -## Files to Modify/Create - -- `src/lib/utils/constants.ts` — MODIFY (already had all types) -- `src/lib/utils/validators.ts` — MODIFY -- `src/lib/types/widget.ts` — MODIFY -- `src/lib/components/widget/BookmarkWidget.svelte` — NEW -- `src/lib/components/widget/NoteWidget.svelte` — NEW -- `src/lib/components/widget/EmbedWidget.svelte` — NEW -- `src/lib/components/widget/StatusWidget.svelte` — NEW -- `src/lib/components/widget/WidgetRenderer.svelte` — NEW -- `src/lib/components/widget/WidgetGrid.svelte` — MODIFY -- `src/lib/components/board/Board.svelte` — MODIFY -- `src/lib/components/board/DraggableBoard.svelte` — MODIFY -- `src/lib/components/section/Section.svelte` — MODIFY -- `src/lib/components/section/DraggableSection.svelte` — MODIFY -- `src/routes/boards/[boardId]/+page.svelte` — MODIFY -- `src/routes/boards/[boardId]/+page.server.ts` — MODIFY -- `src/routes/boards/[boardId]/edit/+page.svelte` — MODIFY -- `src/routes/boards/[boardId]/edit/+page.server.ts` — MODIFY - -## Acceptance Criteria - -- All four widget types render correctly in the board view -- Each widget type has a type-specific config form in the board editor -- Bookmark: displays URL with label and optional icon, opens in new tab -- Note: renders markdown content, supports inline editing -- Embed: renders iframe with configurable URL, shows loading state -- Status: shows aggregate health of selected apps (count online/offline/total) -- WidgetRenderer correctly dispatches to the right component by type - -## Notes - -- Widget config JSON structure per type: - - APP: `{ appId: string }` - - BOOKMARK: `{ url: string, label: string, icon?: string, description?: string }` - - NOTE: `{ content: string, format: 'markdown' | 'text' }` - - EMBED: `{ url: string, height: number, sandbox?: string }` - - STATUS: `{ appIds: string[], label?: string }` -- Embed widget should use sandbox attribute for security -- Big Bang strategy: may need integration fixes in Phase 6 - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -- Installed `marked` package for markdown rendering in NoteWidget -- `WidgetType` enum already had all 5 types from MVP -- Updated `validators.ts` with per-type config Zod schemas (appWidgetConfigSchema, bookmarkWidgetConfigSchema, noteWidgetConfigSchema, embedWidgetConfigSchema, statusWidgetConfigSchema) -- Created 4 new widget components: BookmarkWidget, NoteWidget, EmbedWidget, StatusWidget -- Created WidgetRenderer as the universal type-switch component -- Updated WidgetGrid to use WidgetRenderer; note/embed/status widgets span full width -- Updated DraggableSection with widget type selector dropdown and type-specific config forms -- Updated board view page server to load all apps (needed by StatusWidget) -- Plumbed `allApps` prop through Board -> Section -> WidgetGrid -> WidgetRenderer -> StatusWidget -- Edit page `handleAddWidget` now sends JSON widget data; server action parses `configJson` field -- `onAddWidget` callback signature changed from `(sectionId, appId)` to `(sectionId, widgetDataJson)` throughout DraggableBoard/DraggableSection diff --git a/plans/phase-2-enhanced-features/phase-5-access-control.md b/plans/phase-2-enhanced-features/phase-5-access-control.md deleted file mode 100644 index 92f1060..0000000 --- a/plans/phase-2-enhanced-features/phase-5-access-control.md +++ /dev/null @@ -1,72 +0,0 @@ -# Phase 4: Per-Board Access Control UI - -**Status:** Done -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Add a user-friendly access control interface for boards, allowing admins to manage per-board permissions with user/group pickers and visual indicators. - -## Tasks - -- [x] Task 1: Create `src/lib/components/board/BoardAccessControl.svelte` — inline permission editor for boards -- [x] Task 2: Add access control tab/section to board editor page -- [x] Task 3: Create `src/routes/api/boards/[id]/permissions/+server.ts` — GET/POST/DELETE permissions for a board -- [x] Task 4: Update `src/lib/components/admin/PermissionEditor.svelte` — enhance with user/group search/autocomplete -- [x] Task 5: Update `src/lib/components/board/BoardCard.svelte` — show access level indicator (icon/badge) -- [x] Task 6: Update `src/routes/boards/+page.svelte` — show access indicators on board list -- [x] Task 7: Add guest access toggle with preview description to board editor -- [x] Task 8: Create `src/lib/components/board/BoardShareDialog.svelte` — quick share dialog for boards - -## Files to Modify/Create - -- `src/lib/components/board/BoardAccessControl.svelte` — NEW -- `src/lib/components/board/BoardShareDialog.svelte` — NEW -- `src/routes/api/boards/[id]/permissions/+server.ts` — NEW -- `src/routes/boards/[boardId]/edit/+page.svelte` — MODIFY -- `src/routes/boards/[boardId]/edit/+page.server.ts` — MODIFY -- `src/lib/components/admin/PermissionEditor.svelte` — MODIFY -- `src/lib/components/board/BoardCard.svelte` — MODIFY -- `src/routes/boards/+page.svelte` — MODIFY (server only — +page.server.ts) -- `src/routes/boards/[boardId]/+page.svelte` — MODIFY -- `src/routes/boards/[boardId]/+page.server.ts` — MODIFY -- `src/lib/components/board/BoardHeader.svelte` — MODIFY -- `src/lib/i18n/en.json` — MODIFY -- `src/lib/i18n/ru.json` — MODIFY - -## Acceptance Criteria - -- Board editor has a permissions section for managing access -- Admins can grant/revoke view/edit/admin permissions per user or group -- Board list shows access indicators (shared icon, guest badge, etc.) -- Quick share dialog allows easy permission granting -- Guest access toggle works with visual feedback - -## Notes - -- The permission system already exists from MVP (permissionService) -- This phase adds the UI layer on top of existing backend -- ⚠️ Big Bang: may need integration fixes in Phase 6 - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes -- [ ] Tests pass (new + existing) - -## Handoff to Next Phase - -- Created `BoardAccessControl.svelte` — self-contained board permission manager with search/autocomplete, fetches from `/api/boards/[id]/permissions` -- Created `BoardShareDialog.svelte` — modal dialog for quick sharing with copy link, guest toggle, and permission management -- Created `/api/boards/[id]/permissions` API endpoint with GET/POST/DELETE for board-scoped permissions -- Enhanced `PermissionEditor.svelte` with search/autocomplete inputs replacing plain dropdowns -- Updated `BoardCard.svelte` with globe (guest), lock (private), and users (shared) icons -- Updated board editor with dedicated Guest Access and Permissions sections -- Updated `BoardHeader.svelte` with Share button that opens the share dialog -- Updated board view page (`[boardId]/+page.svelte`) and its server load to support share dialog with user/group data -- Updated boards list server to compute `hasSharedPermissions` flag per board -- Added ~20 new i18n keys in both `en.json` and `ru.json` for all new UI strings -- Big Bang strategy: no build/test verification — Phase 6 integration may be needed diff --git a/plans/phase-2-enhanced-features/phase-6-integration.md b/plans/phase-2-enhanced-features/phase-6-integration.md deleted file mode 100644 index 010e65d..0000000 --- a/plans/phase-2-enhanced-features/phase-6-integration.md +++ /dev/null @@ -1,66 +0,0 @@ -# Phase 6: Integration & Polish - -**Status:** Done -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Objective - -Integrate all Phase 2 features, fix all build/type/lint errors, write tests, and ensure everything works together. - -## Tasks - -- [x] Task 1: Fix all TypeScript/build errors across the codebase -- [x] Task 2: Verify `npm run build` succeeds -- [x] Task 3: Verify `npm run check` passes -- [x] Task 4: Verify `npm run lint` passes -- [x] Task 5: Write tests for oauthService -- [x] Task 6: Write tests for new widget types (validators, rendering logic) -- [x] Task 7: Write tests for reorder APIs -- [x] Task 8: Write tests for board permissions API -- [x] Task 9: Update seed script with example data for new widget types -- [x] Task 10: Verify all existing tests still pass -- [ ] Task 11: Update `.env.example` with all new env vars documented - -## Files Modified/Created - -- `src/lib/server/services/oauthService.ts` — fixed undefined sub claim type error -- `src/lib/components/ui/DynamicIcon.svelte` — fixed Svelte 5 deprecated svelte:component + type error -- `src/lib/components/board/DraggableBoard.svelte` — removed unused eslint-disable -- `src/lib/components/section/DraggableSection.svelte` — fixed unused boardId variable -- `src/lib/components/widget/NoteWidget.svelte` — disabled @html lint rule (content is sanitized) -- `src/routes/api/admin/oauth/test/+server.ts` — removed unused `error` import -- `src/routes/boards/[boardId]/edit/+page.svelte` — removed unused `WidgetType` import -- `eslint.config.js` — disabled `svelte/prefer-writable-derived` (needed for DnD pattern) -- `src/lib/server/services/__tests__/oauthService.test.ts` — **NEW** (10 tests) -- `src/lib/utils/__tests__/widgetValidators.test.ts` — **NEW** (28 tests) -- `src/lib/server/services/__tests__/boardReorder.test.ts` — **NEW** (9 tests) -- `src/routes/api/boards/[id]/permissions/__tests__/permissions.test.ts` — **NEW** (13 tests) -- `prisma/seed.ts` — added bookmark, note, embed, status widgets + team board with permissions - -## Acceptance Criteria - -- [x] `npm run build` succeeds -- [x] `npm run check` passes (0 errors, 18 warnings) -- [x] `npm run lint` passes -- [x] `npm test` passes — 175 tests across 14 test files (115 existing + 60 new) -- [x] All Phase 2 features integrated -- [x] Seed script includes all widget types and board with permissions - -## Notes - -- Installed missing `svelte-i18n` dependency (was used but not in package.json) -- Circular dependency warnings from `typebox` and `zod-v3-to-json-schema` are from node_modules, not our code -- Svelte check warnings are about `state_referenced_locally` in superForm usage patterns (safe to ignore) - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [x] Build passes -- [x] Tests pass (new + existing) - -## Handoff - -Phase 6 complete. All build, type, lint, and test checks pass. The codebase is fully integrated with 175 passing tests. Phase 2 enhanced features are production-ready. diff --git a/plans/phase-3-advanced-features/CONTEXT.md b/plans/phase-3-advanced-features/CONTEXT.md deleted file mode 100644 index 2b4a4a0..0000000 --- a/plans/phase-3-advanced-features/CONTEXT.md +++ /dev/null @@ -1,44 +0,0 @@ -# Feature Context: Phase 3 — Advanced Features - -## Current State - -Phase 7 (Integration & Polish) is complete. 222 tests across 20 test files, full build passes, `npm run check` 0 errors, `npm run lint` 0 errors. All phases 1-7 are done. - -### Phase 1 (Import/Export) Summary - -exportService, importService, admin API endpoints, ImportExportPanel UI, Zod validation schema, i18n EN/RU translations. - -### Phase 2 (Sparklines) Summary - -- History API at `/api/apps/[id]/history` — returns last 288 status records with uptime percentage -- `SparklineChart.svelte` — inline SVG bar chart with color-coded status bars (green/red/yellow/gray) -- `AppWidget.svelte` and `AppCard.svelte` updated to fetch and display sparklines on mount -- `pruneOldStatuses()` in healthcheck service — deletes records >24h, caps at 288 per app -- Hourly cleanup cron job in healthcheck scheduler -- i18n keys: `app.uptime`, `app.history_loading` (EN/RU) - -### Phase 3 (User Theme Overrides) Summary - -- Prisma migration: added `themeMode`, `primaryHue`, `primarySaturation`, `backgroundType`, `locale` nullable fields to User model -- Preferences API at `/api/users/me/preferences` — GET returns preferences, PATCH updates subset -- Settings page at `/settings` with `ThemeCustomizer.svelte` — hue/saturation sliders, mode toggle (dark/light/system), background selector, locale picker, save button -- Theme store `loadFromServer(prefs)` method applies server preferences over localStorage defaults -- `+layout.server.ts` passes `userPreferences` in layout data; `+layout.svelte` applies them on mount -- Header user menu includes "Settings" link -- i18n keys: `settings.title`, `settings.theme`, `settings.primary_color`, `settings.hue`, `settings.saturation`, `settings.background`, `settings.language`, `settings.save`, `settings.saving`, `settings.saved` (EN/RU) - -### Phase 7 (Integration & Polish) Summary - -- Prisma client regenerated with user preference fields -- Fixed lint errors: SvelteSet for reactive Set in DiscoveryPanel, `{#each}` keys in DiscoveryPanel/SparklineChart, unused vars in ThemeCustomizer/AppWidget -- 46 new tests: exportService (4), importService (9), discoveryService (10), preferences API (11), quick-add API (8), broadcastSync (4) -- Seed script updated: user preferences on admin/regular user, quick-add style Wiki.js app -- Final state: 222 tests, 0 build errors, 0 type errors, 0 lint errors - -## Cross-Phase Dependencies - -- Phases 1-3 are independent (import/export, sparklines, user themes) -- Phase 4 (PWA) is independent -- Phase 5 (auto-discovery) is independent -- Phase 6 (bookmarklet/sync) depends on existing API -- Phase 7 (integration) depends on all prior phases diff --git a/plans/phase-3-advanced-features/PLAN.md b/plans/phase-3-advanced-features/PLAN.md deleted file mode 100644 index 2d94501..0000000 --- a/plans/phase-3-advanced-features/PLAN.md +++ /dev/null @@ -1,49 +0,0 @@ -# Feature: Phase 3 — Advanced Features - -**Branch:** `feature/phase-3-advanced-features` -**Base branch:** `master` -**Created:** 2026-03-25 -**Status:** 🟡 In Progress -**Strategy:** Big Bang -**Mode:** Automated -**Execution:** Orchestrator - -## Summary - -Add import/export, ping history sparklines, user theme overrides, PWA support, Docker/Traefik auto-discovery, quick-add bookmarklet, and multi-tab sync. - -## Build & Test Commands - -- **Build:** `npm run build` -- **Test:** `npm test` -- **Lint:** `npm run lint` -- **Type Check:** `npm run check` - -## Phases - -- [x] Phase 1: Import/Export [fullstack] → [subplan](./phase-1-import-export.md) -- [ ] Phase 2: Ping History Sparklines [fullstack] → [subplan](./phase-2-sparklines.md) -- [x] Phase 3: User Theme Overrides [fullstack] → [subplan](./phase-3-user-themes.md) -- [ ] Phase 4: PWA Support [frontend] → [subplan](./phase-4-pwa.md) -- [ ] Phase 5: Auto-Discovery Docker/Traefik [backend] → [subplan](./phase-5-autodiscovery.md) -- [ ] Phase 6: Bookmarklet & Multi-Tab Sync [fullstack] → [subplan](./phase-6-bookmarklet-sync.md) -- [x] Phase 7: Integration & Polish [fullstack] → [subplan](./phase-7-integration.md) - -## Phase Progress Log - -| Phase | Domain | Status | Review | Build | Committed | -| ------------------------- | --------- | -------------- | ------ | ----- | --------- | -| Phase 1: Import/Export | fullstack | ✅ Done | ⬜ | ⬜ | ⬜ | -| Phase 2: Sparklines | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 3: User Themes | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 4: PWA | frontend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 5: Auto-Discovery | backend | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 6: Bookmarklet/Sync | fullstack | ⬜ Not Started | ⬜ | ⬜ | ⬜ | -| Phase 7: Integration | fullstack | ✅ Complete | ✅ | ✅ | ⬜ | - -## Final Review - -- [ ] Comprehensive code review -- [ ] Full build passes -- [ ] Full test suite passes -- [ ] Merged to `master` diff --git a/plans/phase-3-advanced-features/phase-1-import-export.md b/plans/phase-3-advanced-features/phase-1-import-export.md deleted file mode 100644 index 12b19a4..0000000 --- a/plans/phase-3-advanced-features/phase-1-import-export.md +++ /dev/null @@ -1,20 +0,0 @@ -# Phase 1: Import/Export - -**Status:** ✅ Done -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Tasks - -- [x] Task 1: Create `src/lib/server/services/exportService.ts` — export all data (apps, boards, sections, widgets, groups, settings) as JSON -- [x] Task 2: Create `src/lib/server/services/importService.ts` — import JSON with conflict resolution (skip/overwrite) -- [x] Task 3: Create `src/routes/api/admin/export/+server.ts` — GET endpoint, returns JSON file download -- [x] Task 4: Create `src/routes/api/admin/import/+server.ts` — POST endpoint, accepts JSON upload -- [x] Task 5: Update admin settings page — add Import/Export section with download button and file upload -- [x] Task 6: Create `src/lib/components/admin/ImportExportPanel.svelte` — UI with export button, file picker, preview, and import button -- [x] Task 7: Add Zod schema for validating import data structure -- [x] Task 8: Add i18n translations for import/export strings (EN/RU) - -## Handoff to Next Phase - -All import/export functionality implemented. Export service gathers all apps, boards (with sections/widgets), groups, and system settings into a versioned JSON structure. Import service validates with Zod, supports skip/overwrite conflict resolution, and runs in a Prisma transaction. Admin-only API endpoints with Content-Disposition for file download. UI panel with file upload, JSON preview, mode selector, and status feedback. diff --git a/plans/phase-3-advanced-features/phase-2-sparklines.md b/plans/phase-3-advanced-features/phase-2-sparklines.md deleted file mode 100644 index dd25193..0000000 --- a/plans/phase-3-advanced-features/phase-2-sparklines.md +++ /dev/null @@ -1,20 +0,0 @@ -# Phase 2: Ping History Sparklines - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Tasks - -- [x] Task 1: Create `src/routes/api/apps/[id]/history/+server.ts` — GET last 24h of healthcheck results -- [x] Task 2: Create `src/lib/components/app/SparklineChart.svelte` — tiny inline SVG sparkline (green=up, red=down) -- [x] Task 3: Update `src/lib/components/widget/AppWidget.svelte` — show sparkline below status badge -- [x] Task 4: Update `src/lib/components/app/AppCard.svelte` — show sparkline on app cards -- [x] Task 5: Calculate and display uptime percentage (last 24h) -- [x] Task 6: Update healthcheck service to retain last 288 records per app (24h at 5min intervals) -- [x] Task 7: Add cleanup job to prune old AppStatus records beyond retention period -- [x] Task 8: Add i18n translations (EN/RU) - -## Handoff to Next Phase - -All sparkline features implemented. History API returns last 288 records with uptime percentage. SparklineChart renders color-coded bars (green/red/yellow/gray). Cleanup job prunes records older than 24h hourly. Both AppWidget and AppCard fetch and display sparklines with uptime percentage on mount. diff --git a/plans/phase-3-advanced-features/phase-3-user-themes.md b/plans/phase-3-advanced-features/phase-3-user-themes.md deleted file mode 100644 index 1880c4a..0000000 --- a/plans/phase-3-advanced-features/phase-3-user-themes.md +++ /dev/null @@ -1,21 +0,0 @@ -# Phase 3: User Theme Overrides - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Tasks - -- [x] Task 1: Add `themeMode`, `primaryHue`, `primarySaturation`, `backgroundType`, `locale` fields to User model (Prisma migration) -- [x] Task 2: Create `src/routes/api/users/me/preferences/+server.ts` — GET/PATCH user preferences -- [x] Task 3: Create `src/routes/settings/+page.server.ts` — user settings page data -- [x] Task 4: Create `src/routes/settings/+page.svelte` — user settings page with theme customization -- [x] Task 5: Create `src/lib/components/settings/ThemeCustomizer.svelte` — HSL color picker, background selector, mode toggle -- [x] Task 6: Update theme store to load user preferences from server on login -- [x] Task 7: Update `+layout.server.ts` to pass user preferences -- [x] Task 8: Add user settings link to header user menu -- [x] Task 9: Add i18n translations (EN/RU) - -## Handoff to Next Phase - -Phase 3 (User Theme Overrides) complete. Added nullable preference fields to User model, preferences API (GET/PATCH), settings page with ThemeCustomizer component (hue/saturation sliders, mode toggle, background selector, locale picker), server-side preference loading in layout, and Settings link in Header user menu. i18n translations added for EN and RU. diff --git a/plans/phase-3-advanced-features/phase-4-pwa.md b/plans/phase-3-advanced-features/phase-4-pwa.md deleted file mode 100644 index 8adfc8f..0000000 --- a/plans/phase-3-advanced-features/phase-4-pwa.md +++ /dev/null @@ -1,18 +0,0 @@ -# Phase 4: PWA Support - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Tasks - -- [ ] Task 1: Create `static/manifest.json` — web app manifest with name, icons, theme color, display: standalone -- [ ] Task 2: Create app icons in `static/` — 192x192 and 512x512 PNG (simple grid icon) -- [ ] Task 3: Create `src/service-worker.ts` — SvelteKit service worker with cache-first for static assets, network-first for API -- [ ] Task 4: Update `src/app.html` — add manifest link, theme-color meta, apple-mobile-web-app meta tags -- [ ] Task 5: Create offline fallback page — show when no network and no cache -- [ ] Task 6: Add install prompt UI — detect `beforeinstallprompt` event, show install banner - -## Handoff to Next Phase - - diff --git a/plans/phase-3-advanced-features/phase-5-autodiscovery.md b/plans/phase-3-advanced-features/phase-5-autodiscovery.md deleted file mode 100644 index 66d5fee..0000000 --- a/plans/phase-3-advanced-features/phase-5-autodiscovery.md +++ /dev/null @@ -1,26 +0,0 @@ -# Phase 5: Auto-Discovery (Docker/Traefik) - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Tasks - -- [ ] Task 1: Create `src/lib/server/services/discoveryService.ts` — Docker socket scanning and Traefik API parsing -- [ ] Task 2: Create `src/routes/api/admin/discover/+server.ts` — POST triggers discovery scan, returns found services -- [ ] Task 3: Create `src/routes/api/admin/discover/approve/+server.ts` — POST approves discovered apps (creates them) -- [ ] Task 4: Create `src/lib/components/admin/DiscoveryPanel.svelte` — UI to trigger scan, review results, approve/reject -- [ ] Task 5: Add discovery settings to SystemSettings (Docker socket path, Traefik API URL, auto-scan toggle) -- [ ] Task 6: Update admin settings page with discovery configuration section -- [ ] Task 7: Add env vars: DOCKER_SOCKET_PATH, TRAEFIK_API_URL -- [ ] Task 8: Add i18n translations (EN/RU) - -## Notes - -- Docker discovery: read from `/var/run/docker.sock` (or configured path), list containers, extract labels for name/URL -- Traefik discovery: query Traefik API `/api/http/routers` and `/api/http/services` -- Both are optional — gracefully handle when Docker socket or Traefik API is unavailable - -## Handoff to Next Phase - - diff --git a/plans/phase-3-advanced-features/phase-6-bookmarklet-sync.md b/plans/phase-3-advanced-features/phase-6-bookmarklet-sync.md deleted file mode 100644 index 874f254..0000000 --- a/plans/phase-3-advanced-features/phase-6-bookmarklet-sync.md +++ /dev/null @@ -1,24 +0,0 @@ -# Phase 6: Quick-Add Bookmarklet & Multi-Tab Sync - -**Status:** ⬜ Not Started -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Tasks - -- [ ] Task 1: Create `src/routes/api/apps/quick-add/+server.ts` — POST endpoint that accepts URL + title, creates app with defaults -- [ ] Task 2: Create `src/lib/components/admin/BookmarkletGenerator.svelte` — generates bookmarklet JS code with user's API token -- [ ] Task 3: Add bookmarklet section to user settings page -- [ ] Task 4: Create `src/lib/utils/broadcastSync.ts` — BroadcastChannel wrapper for cross-tab sync -- [ ] Task 5: Sync theme changes across tabs (dark/light toggle, primary color) -- [ ] Task 6: Sync board changes across tabs (new boards appear in sidebar) -- [ ] Task 7: Add i18n translations (EN/RU) - -## Notes - -- Bookmarklet: `javascript:void(fetch('ORIGIN/api/apps/quick-add',{method:'POST',headers:{'Content-Type':'application/json','Authorization':'Bearer TOKEN'},body:JSON.stringify({url:location.href,name:document.title})}))` -- BroadcastChannel: create channel 'wal-sync', post messages on theme/board changes, listen in layout - -## Handoff to Next Phase - - diff --git a/plans/phase-3-advanced-features/phase-7-integration.md b/plans/phase-3-advanced-features/phase-7-integration.md deleted file mode 100644 index 2de75f0..0000000 --- a/plans/phase-3-advanced-features/phase-7-integration.md +++ /dev/null @@ -1,31 +0,0 @@ -# Phase 7: Integration & Polish - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** fullstack - -## Tasks - -- [x] Task 1: Fix all TypeScript/build errors -- [x] Task 2: Verify `npm run build` succeeds -- [x] Task 3: Verify `npm run check` passes (0 errors, warnings only) -- [x] Task 4: Verify `npm run lint` passes (0 errors) -- [x] Task 5: Write tests for export/import services -- [x] Task 6: Write tests for discovery service (mocked Docker/Traefik) -- [x] Task 7: Write tests for user preferences API -- [x] Task 8: Write tests for quick-add API -- [x] Task 9: Write tests for broadcastSync utility -- [x] Task 10: Update seed script with sample data (user preferences, quick-add style app) -- [x] Task 11: Run Prisma generate (migrations already applied) -- [x] Task 12: Verify all 222 tests pass across 20 test files - -## Changes Made - -- `prisma generate` — regenerated client with user preference fields -- Fixed lint: SvelteSet for reactive Set in DiscoveryPanel, `{#each}` keys, unused vars -- New tests: exportService (4), importService (9), discoveryService (10), preferences API (11), quick-add API (8), broadcastSync (4) = 46 new tests -- Updated seed.ts: user preferences on admin/regular user, quick-add style Wiki.js app - -## Handoff - - diff --git a/plans/phase-4-7-full-expansion/CONTEXT.md b/plans/phase-4-7-full-expansion/CONTEXT.md deleted file mode 100644 index 4f4a18a..0000000 --- a/plans/phase-4-7-full-expansion/CONTEXT.md +++ /dev/null @@ -1,105 +0,0 @@ -# Feature Context: Phases 4–7 — Full Feature Expansion - -## Configuration - -- **Development mode:** Automated -- **Execution mode:** Orchestrator -- **Strategy:** Big Bang -- **Build:** `npm run build` -- **Test:** `npm test` -- **Lint:** `npm run lint` -- **Type Check:** `npm run check` -- **Dev server:** `npm run dev` (port: 5181) - -## Current State - -All 8 phases are complete. Phase 8 (Integration & Polish) fixed all build, type, lint, and test errors. Build, check, lint, and tests all pass. -All 10 new Prisma models created, existing models extended, migration applied, Prisma client regenerated. -Widget types now include 13 values: app, bookmark, note, embed, status, clock, system_stats, rss, calendar, markdown, metric, link_group, camera. -New constants added: CardSize, NotificationType, NotificationEvent, ApiTokenScope, AuditAction, BackgroundType. -5 new type files created, 4 existing type files extended, validators.ts has 19 new Zod schemas. -6 new widget services created: weatherService, systemStatsService, rssFeedService, calendarService, metricService, cameraService. -7 new API routes under /api/widgets/: weather, system-stats, rss, calendar, metric, camera, data (aggregation). -boardService updated with widget config validation on create/update and new theme/visual field passthrough. -Theme system uses HSL CSS variables with dark/light/system modes. -Auth system: local + OAuth with JWT cookies + API token bearer auth. -7 new functional services created: favoriteService, recentAppsService, uptimeService, notificationService, tagService, apiTokenService, auditLogService. -16 new API routes for: favorites, recent-apps, uptime, notifications (channels, test), tags (app-tags), app-links, tokens, admin audit-log. -appService extended with multi-URL link management and eager-loaded links. -Healthcheck scheduler now triggers notifications on status transitions and prunes audit logs daily. -Audit logging integrated into user CRUD, app CRUD, board CRUD, settings, import, and export routes. -8 new widget UI components created: ClockWeatherWidget, SystemStatsWidget, RssFeedWidget, CalendarWidget, MarkdownWidget, MetricWidget, LinkGroupWidget, CameraStreamWidget. -WidgetRenderer routes all 13 widget types to their components. WidgetCreationForm has config forms for all 13 types. -WidgetGrid updated with new full-width types (system_stats, rss, calendar, markdown, camera). -Phase 6 functional frontend complete: 2 new stores (favorites, notifications), 22 new/modified component files, 6 new routes. -FavoritesBar with drag-and-drop reordering, RecentAppsSection with time-ago display, Status page at /status with uptime summary. -NotificationBell in header with unread badge and 60s polling, NotificationChannelForm with Discord/Slack/Telegram/HTTP support. -TagManager admin CRUD, TagBadge component, TagFilter for board filtering. -AppWidget updated with expandable multi-URL links, context menu for favorites, and click recording. -API Token management at /settings/api-tokens with create/revoke form actions. -AuditLogTable with filters, expandable JSON details, CSV export, and pagination. -Phase 7 quality-of-life complete: onboarding wizard (5-step overlay with admin creation, auth mode, theme, board setup), URL preview (test connection with favicon/title extraction), board templates (4 builtins + user CRUD + import/export), keyboard shortcuts (j/k nav, 1-9 boards, ?-overlay, f-favorites, e-edit). -New services: onboardingService, templateService. New stores: keyboard.svelte.ts. 3 new API route groups: /api/onboarding, /api/apps/preview, /api/templates. - -## Temporary Workarounds - -(none yet) - -## Cross-Phase Dependencies - -- Phase 1 (schema) must complete before Phase 2 (widget backend) and Phase 5 (functional backend) -- Phase 2 (widget backend) must complete before Phase 3 (widget frontend) -- Phase 5 (functional backend) must complete before Phase 6 (functional frontend) -- Phase 4 (visual) is independent — can run parallel with Phase 2 or 3 -- Phase 7 (QoL) depends on Phases 5+6 for some features (onboarding references tags, templates) -- Phase 8 (integration) depends on all prior phases - -## Deferred Work - -(none yet) - -## Failed Approaches - -(none yet) - -## Review Findings Log - -(none yet) - -## Visual Decisions (Phase 4) - -- Glassmorphism uses `color-mix(in srgb, ...)` for semi-transparent backgrounds (works across light/dark modes) -- Card style classes (`.card-solid`, `.card-glass`, `.card-outline`) are global CSS in `app.css`, applied via `card-${theme.cardStyle}` derived class -- Board theme overrides apply at `:root` level (not scoped) for maximum CSS variable reach; cleanup restores global store values -- AnimatedStatusRing uses SVG `stroke-dasharray`/`stroke-dashoffset` animations, scales via `size` prop -- Card size grid columns: compact=6col, medium=4col, large=3col (responsive breakpoints) -- Custom CSS sanitization is regex-based (strips script tags, javascript: URLs, expression(), @import, behavior:, -moz-binding) -- `updateBoardSchema` backgroundType uses inline enum `['mesh', 'particles', 'aurora', 'wallpaper', 'none']` instead of BackgroundType constant - -## Phase Execution Log - -| Phase | Agent Used | Test Writer | Parallel | Notes | -| ------- | ----------------- | --------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------- | -| Phase 1 | phase-implementer | ⏭️ Skipped (Big Bang) | — | Schema & types only | -| Phase 2 | phase-implementer | ⏭️ Skipped (Big Bang) | — | 6 services, 7 API routes, boardService updated | -| Phase 5 | phase-implementer | ⏭️ Skipped (Big Bang) | — | 7 services, 16 API routes, appService/healthcheckScheduler/hooks.server/authenticate extended, audit logging integrated | -| Phase 3 | phase-implementer | ⏭️ Skipped (Big Bang) | — | 8 widget components, WidgetRenderer + WidgetCreationForm + WidgetGrid updated | -| Phase 4 | phase-implementer | ⏭️ Skipped (Big Bang) | — | 6 visual features, fixes to server action + validator + theme restore | -| Phase 6 | phase-implementer | ⏭️ Skipped (Big Bang) | — | 8 functional frontend features: favorites, recent apps, status page, notifications, tags, multi-URL cards, API tokens, audit log | -| Phase 7 | phase-implementer | ⏭️ Skipped (Big Bang) | — | 4 QoL features: onboarding wizard, URL preview, board templates, keyboard shortcuts | - -## Environment & Runtime Notes - -- SQLite database at file:/app/data/launcher.db -- Prisma ORM with cuid IDs -- Svelte 5 runes mode ($state, $derived, $props) -- Tailwind CSS v4 with @theme inline in app.css - -## Implementation Notes - -- Existing widget types defined in WidgetType constant (src/lib/utils/constants.ts) -- Widget configs stored as JSON string in Widget.config column -- All Zod schemas in src/lib/utils/validators.ts -- Type definitions in src/lib/types/\*.ts -- API routes use consistent envelope: { success, data, error, meta } -- Services in src/lib/server/services/\*.ts — no business logic in routes diff --git a/plans/phase-4-7-full-expansion/PLAN.md b/plans/phase-4-7-full-expansion/PLAN.md deleted file mode 100644 index bbf8179..0000000 --- a/plans/phase-4-7-full-expansion/PLAN.md +++ /dev/null @@ -1,65 +0,0 @@ -# Feature: Phases 4–7 — Full Feature Expansion - -**Branch:** `feature/phase-4-7-full-expansion` -**Base branch:** `master` -**Created:** 2026-03-25 -**Status:** 🟡 In Progress -**Strategy:** Big Bang -**Mode:** Automated -**Execution:** Orchestrator - -## Summary - -Implement all remaining features from the project roadmap: 8 new widget types, 6 visual/styling enhancements, 8 functional features, and 4 quality-of-life improvements — 26 features total across 8 implementation phases. - -## Build & Test Commands - -- **Build:** `npm run build` -- **Test:** `npm test` -- **Lint:** `npm run lint` -- **Type Check:** `npm run check` - -## Tech Stack - -- **Framework:** SvelteKit (Svelte 5 runes mode) + TypeScript strict -- **UI:** Tailwind CSS v4 + shadcn-svelte (Bits UI) + Lucide Svelte + Simple Icons -- **Data:** Prisma ORM + SQLite + Superforms + Zod -- **Auth:** bcrypt + JWT (HTTP-only cookies) + refresh token rotation -- **Background Jobs:** node-cron -- **DevOps:** Docker (multi-stage) + docker-compose + Gitea Actions - -## Phases - -- [ ] Phase 1: Database Schema & Type Foundation [backend] → [subplan](./phase-1-schema-types.md) -- [ ] Phase 2: New Widget Services & APIs [backend] → [subplan](./phase-2-widget-backend.md) -- [ ] Phase 3: New Widget Components [frontend] → [subplan](./phase-3-widget-frontend.md) -- [ ] Phase 4: Visual & Styling Enhancements [frontend] → [subplan](./phase-4-visual-styling.md) -- [ ] Phase 5: Functional Features — Backend [backend] → [subplan](./phase-5-functional-backend.md) -- [ ] Phase 6: Functional Features — Frontend [frontend] → [subplan](./phase-6-functional-frontend.md) -- [ ] Phase 7: Quality of Life [fullstack] → [subplan](./phase-7-quality-of-life.md) -- [ ] Phase 8: Integration & Polish [fullstack] → [subplan](./phase-8-integration-polish.md) - -## Phase Progress Log - -| Phase | Domain | Status | Review | Build | Committed | -| ----------------------------- | --------- | -------------- | ------ | ----- | --------- | -| Phase 1: Schema & Types | backend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 2: Widget Backend | backend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 3: Widget Frontend | frontend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 4: Visual & Styling | frontend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 5: Functional Backend | backend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 6: Functional Frontend | frontend | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 7: Quality of Life | fullstack | ✅ Complete | ⬜ | ⬜ | ⬜ | -| Phase 8: Integration & Polish | fullstack | ✅ Complete | ⬜ | ✅ | ⬜ | - -## Parallelizable Phases - -- Phases 2 & 4 (backend widget services + visual frontend) — no shared files -- Phases 5 & 3 (functional backend + widget frontend) — minimal overlap - -## Final Review - -- [ ] Comprehensive code review -- [ ] Full build passes -- [ ] Full test suite passes -- [ ] Merged to `master` diff --git a/plans/phase-4-7-full-expansion/phase-1-schema-types.md b/plans/phase-4-7-full-expansion/phase-1-schema-types.md deleted file mode 100644 index dd622b2..0000000 --- a/plans/phase-4-7-full-expansion/phase-1-schema-types.md +++ /dev/null @@ -1,155 +0,0 @@ -# Phase 1: Database Schema & Type Foundation - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective - -Define all new database models, extend existing models, add new widget type constants, create TypeScript type definitions, and write Zod validation schemas for every new entity across Phases 4–7. - -## Tasks - -### 1.1 Extend Prisma schema with new models - -- [x] Add `Tag` model (id, name, color, createdAt) -- [x] Add `AppTag` junction model (appId, tagId) -- [x] Add `AppLink` model (id, appId, label, url, icon, order) -- [x] Add `UserFavorite` model (id, userId, appId, order) -- [x] Add `AppClick` model (id, userId, appId, clickedAt) -- [x] Add `NotificationChannel` model (id, userId, type, config JSON, enabled, createdAt) -- [x] Add `Notification` model (id, userId, appId, event, message, sentAt, readAt) -- [x] Add `ApiToken` model (id, userId, name, tokenHash, scope, lastUsedAt, expiresAt, createdAt) -- [x] Add `AuditLog` model (id, userId, action, entityType, entityId, details JSON, createdAt) -- [x] Add `BoardTemplate` model (id, name, description, icon, config JSON, isBuiltin, createdById, createdAt) - -### 1.2 Extend existing Prisma models - -- [x] `Board`: add `themeHue` (Int?), `themeSaturation` (Int?), `backgroundType` (String?), `cardSize` (String?), `wallpaperUrl` (String?), `wallpaperBlur` (Int?), `wallpaperOverlay` (Float?), `customCss` (String?) -- [x] `Section`: add `cardSize` (String?) -- [x] `User`: add `onboardingComplete` (Boolean, default false), `trackRecentApps` (Boolean, default true) -- [x] `SystemSettings`: add `customCss` (String?), `onboardingComplete` (Boolean, default false) - -### 1.3 Add relations to existing models - -- [x] `App` → `tags` (via AppTag), `links` (AppLink[]), `clicks` (AppClick[]), `notifications` (Notification[]) -- [x] `User` → `favorites` (UserFavorite[]), `clicks` (AppClick[]), `notificationChannels` (NotificationChannel[]), `notifications` (Notification[]), `apiTokens` (ApiToken[]), `auditLogs` (AuditLog[]), `boardTemplates` (BoardTemplate[]) -- [x] `Board` → (themeHue, themeSaturation etc. are scalar fields, no new relations needed) - -### 1.4 Generate and apply Prisma migration - -- [x] Run `npx prisma migrate dev --name phase4-7-schema` to create migration -- [x] Run `npx prisma generate` to update Prisma client - -### 1.5 Extend widget type constants - -- [x] Add to `WidgetType` in `src/lib/utils/constants.ts`: `CLOCK`, `SYSTEM_STATS`, `RSS`, `CALENDAR`, `MARKDOWN`, `METRIC`, `LINK_GROUP`, `CAMERA` -- [x] Add `CardSize` constant: `COMPACT`, `MEDIUM`, `LARGE` -- [x] Add `NotificationType` constant: `DISCORD`, `SLACK`, `TELEGRAM`, `HTTP` -- [x] Add `NotificationEvent` constant: `APP_ONLINE`, `APP_OFFLINE`, `APP_DEGRADED` -- [x] Add `ApiTokenScope` constant: `READ`, `WRITE`, `ADMIN` -- [x] Add `AuditAction` constant: `USER_CREATED`, `USER_DELETED`, `USER_UPDATED`, `BOARD_CREATED`, `BOARD_DELETED`, `APP_CREATED`, `APP_DELETED`, `SETTINGS_UPDATED`, `IMPORT`, `EXPORT` -- [x] Add `BackgroundType` extension if needed (wallpaper type) - -### 1.6 Create TypeScript type definitions - -- [x] Create `src/lib/types/tag.ts` — Tag, AppTag, CreateTagInput, UpdateTagInput -- [x] Create `src/lib/types/notification.ts` — NotificationChannel, Notification, CreateChannelInput, NotificationPreferences -- [x] Create `src/lib/types/apiToken.ts` — ApiToken, CreateTokenInput, TokenScope -- [x] Create `src/lib/types/auditLog.ts` — AuditLog, AuditAction, CreateAuditLogInput -- [x] Create `src/lib/types/template.ts` — BoardTemplate, CreateTemplateInput -- [x] Extend `src/lib/types/widget.ts` — add config interfaces for all 8 new widget types: - - ClockWeatherWidgetConfig: { timezone, showWeather, latitude?, longitude?, clockStyle } - - SystemStatsWidgetConfig: { sourceUrl, sourceType, metrics[], refreshInterval } - - RssWidgetConfig: { feedUrl, maxItems, showSummary } - - CalendarWidgetConfig: { icalUrls: Array<{url, color, label}>, daysAhead } - - MarkdownWidgetConfig: { content, syntaxTheme } - - MetricWidgetConfig: { label, source, value?, url?, jsonPath?, query?, unit?, refreshInterval } - - LinkGroupWidgetConfig: { links: Array<{label, url, icon?}>, collapsible } - - CameraWidgetConfig: { streamUrl, type, refreshInterval, aspectRatio } -- [x] Extend `src/lib/types/app.ts` — add AppLink type, extend App type with links[] and tags[] -- [x] Extend `src/lib/types/user.ts` — add UserFavorite, AppClick, extend User with new fields -- [x] Extend `src/lib/types/board.ts` — add theme/visual fields to Board type - -### 1.7 Create Zod validation schemas - -- [x] Add widget config schemas in `src/lib/utils/validators.ts` for all 8 new widget types -- [x] Add `createTagSchema`, `updateTagSchema` -- [x] Add `createAppLinkSchema`, `updateAppLinkSchema` -- [x] Add `createNotificationChannelSchema`, `updateNotificationChannelSchema` -- [x] Add `createApiTokenSchema` -- [x] Add `createBoardTemplateSchema` -- [x] Add `auditLogQuerySchema` (filters: action, entityType, dateRange) -- [x] Update `createWidgetSchema` to accept new widget type values -- [x] Update `updateBoardSchema` to accept new theme/visual fields -- [x] Update `updateSectionSchema` to accept cardSize -- [x] Update `updateUserSchema` to accept onboardingComplete, trackRecentApps - -## Files to Modify/Create - -- `prisma/schema.prisma` — extend with all new models and fields -- `src/lib/utils/constants.ts` — new constant objects -- `src/lib/types/tag.ts` — new file -- `src/lib/types/notification.ts` — new file -- `src/lib/types/apiToken.ts` — new file -- `src/lib/types/auditLog.ts` — new file -- `src/lib/types/template.ts` — new file -- `src/lib/types/widget.ts` — extend with 8 new config interfaces -- `src/lib/types/app.ts` — extend with AppLink, tags -- `src/lib/types/user.ts` — extend with favorites, clicks, new fields -- `src/lib/types/board.ts` — extend with visual/theme fields -- `src/lib/utils/validators.ts` — all new Zod schemas - -## Acceptance Criteria - -- All new Prisma models have correct fields, types, relations, and indexes -- Migration applies cleanly to a fresh SQLite database -- Prisma client generates without errors -- All TypeScript types use `readonly` for immutability -- All Zod schemas validate correct inputs and reject invalid ones -- New widget types are added to WidgetType constant -- Existing code is not broken by schema additions (additive changes only) - -## Notes - -- All new fields on existing models must be optional or have defaults to avoid breaking existing data -- Use `cuid()` for all new model IDs consistent with existing schema -- Store JSON configs as String in Prisma (SQLite limitation), parse with Zod on read -- Keep immutable patterns — all type interfaces use `readonly` - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [x] No unintended side effects -- [ ] Build passes (Big Bang: code quality check only) -- [ ] Tests pass (Big Bang: skipped for intermediate phase) - -## Handoff to Next Phase - -### What was done - -- Extended Prisma schema with 10 new models: Tag, AppTag, AppLink, UserFavorite, AppClick, NotificationChannel, Notification, ApiToken, AuditLog, BoardTemplate -- Extended existing models (User, Board, Section, SystemSettings) with new fields -- Added all relations between new and existing models -- Migration `20260325092024_phase4_7_schema` created and applied successfully -- Prisma client regenerated -- Added 7 new constant objects: CardSize, NotificationType, NotificationEvent, ApiTokenScope, AuditAction, BackgroundType, plus 8 new widget types -- Created 5 new type files: tag.ts, notification.ts, apiToken.ts, auditLog.ts, template.ts -- Extended 4 existing type files: widget.ts (8 new config interfaces), app.ts (AppLink + AppWithRelations), user.ts (UserFavorite, AppClick, UserWithPreferences), board.ts (theme/visual fields) -- Added 19 new Zod schemas and updated 4 existing schemas in validators.ts - -### What the next phase needs to know - -- All new Prisma models are available via the generated client -- Widget type enum in constants.ts now has 13 values (5 original + 8 new) -- All widget config Zod schemas follow the naming pattern `{type}WidgetConfigSchema` -- New entity schemas follow the naming pattern `create{Entity}Schema` / `update{Entity}Schema` -- `auditLogQuerySchema` supports pagination (page, limit) and date filtering (dateFrom, dateTo) -- `App` model still has legacy `tags` string field; the new `AppTag` junction table provides structured tagging -- All changes are additive — no breaking changes to existing API contracts - -### Potential concerns - -- The legacy `App.tags` (comma-separated string) field still exists alongside the new `AppTag` junction. Later phases should decide whether to migrate data and deprecate the string field. -- `updateSystemSettingsSchema` was extended with `customCss` and `onboardingComplete` — existing settings API route handlers will need to pass these through. diff --git a/plans/phase-4-7-full-expansion/phase-2-widget-backend.md b/plans/phase-4-7-full-expansion/phase-2-widget-backend.md deleted file mode 100644 index 32d02bf..0000000 --- a/plans/phase-4-7-full-expansion/phase-2-widget-backend.md +++ /dev/null @@ -1,152 +0,0 @@ -# Phase 2: New Widget Services & APIs - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** backend - -## Objective - -Implement backend services and API routes for all 8 new widget types. Each widget type that fetches external data needs a dedicated service for data fetching, caching, and error handling. - -## Tasks - -### 2.1 Clock/Weather service - -- [x] Create `src/lib/server/services/weatherService.ts` - - Fetch weather from OpenMeteo API (no API key required): `https://api.open-meteo.com/v1/forecast` - - Accept latitude/longitude, return current temp, condition, icon - - Cache responses for 30 minutes (in-memory Map with TTL) - - Graceful fallback when API is unreachable -- [x] Create `src/routes/api/widgets/weather/+server.ts` — GET endpoint with lat/lng query params - -### 2.2 System Stats service - -- [x] Create `src/lib/server/services/systemStatsService.ts` - - Adapter pattern: `TrueNasAdapter`, `GlancesAdapter`, `CustomAdapter` - - Each adapter fetches metrics (CPU, RAM, disk) from its source URL - - Return normalized `{ metric: string, value: number, unit: string }[]` - - Configurable refresh interval, in-memory cache per source URL -- [x] Create `src/routes/api/widgets/system-stats/+server.ts` — GET with sourceUrl, sourceType params - -### 2.3 RSS/Feed service - -- [x] Create `src/lib/server/services/rssFeedService.ts` - - Fetch and parse RSS/Atom feeds (use built-in XML parsing or lightweight lib) - - Return `{ title, link, pubDate, summary }[]` limited to maxItems - - Cache feeds for 15 minutes per URL - - Handle malformed feeds gracefully -- [x] Create `src/routes/api/widgets/rss/+server.ts` — GET with feedUrl, maxItems params - -### 2.4 Calendar service - -- [x] Create `src/lib/server/services/calendarService.ts` - - Fetch and parse iCal (.ics) files from URLs - - Extract events within daysAhead range - - Return `{ summary, start, end, location?, calendarLabel, calendarColor }[]` - - Cache per URL for 30 minutes - - Handle multiple calendar URLs, merge and sort by start time -- [x] Create `src/routes/api/widgets/calendar/+server.ts` — POST with icalUrls[], daysAhead - -### 2.5 Metric/Counter service - -- [x] Create `src/lib/server/services/metricService.ts` - - `fetchHttpMetric(url, jsonPath)` — fetch JSON endpoint, extract value via JSONPath - - `fetchPrometheusMetric(url, query)` — query Prometheus API, extract instant value - - `getStaticMetric(value)` — passthrough for static values - - Store previous value for trend calculation (up/down/flat) - - Cache per source for configurable interval -- [x] Create `src/routes/api/widgets/metric/+server.ts` — GET with source type params - -### 2.6 Camera/Stream proxy - -- [x] Create `src/lib/server/services/cameraService.ts` - - `fetchSnapshot(url)` — proxy HTTP request to camera URL, return image buffer - - Validate URL is http/https only - - Timeout after 10s - - Rate limit: max 1 request per 5s per URL -- [x] Create `src/routes/api/widgets/camera/+server.ts` — GET with streamUrl param, returns proxied image - -### 2.7 Widget data aggregation endpoint - -- [x] Create `src/routes/api/widgets/data/+server.ts` — generic endpoint that routes to the correct service based on widget type and config - - POST with `{ widgetType, config }` body - - Routes to weatherService, systemStatsService, etc. based on type - - Returns unified response format - -### 2.8 Update existing widget service - -- [x] Update `src/lib/server/services/boardService.ts` to handle new widget types in create/update operations -- [x] Ensure new widget type configs are validated with the correct Zod schema on create/update - -## Files to Modify/Create - -- `src/lib/server/services/weatherService.ts` — new -- `src/lib/server/services/systemStatsService.ts` — new -- `src/lib/server/services/rssFeedService.ts` — new -- `src/lib/server/services/calendarService.ts` — new -- `src/lib/server/services/metricService.ts` — new -- `src/lib/server/services/cameraService.ts` — new -- `src/routes/api/widgets/weather/+server.ts` — new -- `src/routes/api/widgets/system-stats/+server.ts` — new -- `src/routes/api/widgets/rss/+server.ts` — new -- `src/routes/api/widgets/calendar/+server.ts` — new -- `src/routes/api/widgets/metric/+server.ts` — new -- `src/routes/api/widgets/camera/+server.ts` — new -- `src/routes/api/widgets/data/+server.ts` — new -- `src/lib/server/services/boardService.ts` — modify - -## Acceptance Criteria - -- Each service handles errors gracefully (network failures, malformed responses, timeouts) -- In-memory caching prevents excessive external API calls -- All API routes use consistent envelope response format -- All user inputs validated with Zod schemas from Phase 1 -- Camera proxy validates URLs and prevents SSRF (allowlist http/https, no private IPs) -- Services are stateless (cache is ephemeral, no DB state needed for widget data) - -## Notes - -- OpenMeteo API is free, no key needed: `https://api.open-meteo.com/v1/forecast?latitude=X&longitude=Y¤t_weather=true` -- For RSS parsing, consider using a lightweight approach (DOMParser or regex) to avoid adding a heavy dependency. If needed, `fast-xml-parser` is a good lightweight option. -- iCal parsing: use `node-ical` or hand-parse VEVENT blocks -- JSONPath extraction: use simple dot-notation traversal rather than a full JSONPath library -- SSRF protection for camera proxy: reject private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, ::1) - -## Review Checklist - -- [x] All tasks completed -- [x] Code follows project conventions -- [ ] No unintended side effects -- [ ] Build passes (Big Bang: code quality check only) -- [ ] Tests pass (Big Bang: skipped for intermediate phase) - -## Handoff to Next Phase - -### What was done - -- Created 6 new backend services: weatherService, systemStatsService, rssFeedService, calendarService, metricService, cameraService -- Created 7 new API routes under `/api/widgets/`: weather, system-stats, rss, calendar, metric, camera, data (aggregation) -- Updated boardService to validate widget configs against Zod schemas on create/update -- Updated boardService to pass through new theme/visual fields (themeHue, themeSaturation, backgroundType, cardSize, wallpaperUrl, wallpaperBlur, wallpaperOverlay, customCss) and section cardSize -- All services use in-memory caching with TTL (Map + expiry timestamps) -- Camera proxy includes SSRF protection (blocks private IPs, localhost, link-local) and rate limiting (1 req/5s per URL) -- RSS service uses lightweight regex-based XML parsing (no external dependency) -- Calendar service uses hand-parsed VEVENT blocks from iCal text (no external dependency) -- Metric service supports dot-notation JSONPath extraction (no external dependency) - -### What the next phase needs to know - -- All widget data endpoints follow the pattern: `/api/widgets/{type}` with GET (or POST for calendar) -- The aggregation endpoint `/api/widgets/data` accepts POST with `{ widgetType, config }` and routes to the correct service -- Camera endpoint returns raw image binary (not JSON envelope) for direct `` src usage -- Markdown and LinkGroup widget types return no-op from the aggregation endpoint (they are client-side only) -- Clock widget without weather enabled also returns no-op (time is client-side) -- All services export a `clearCache()` function for testing/manual refresh -- The `validateStreamUrl()` function on cameraService is exported for reuse (used by aggregation endpoint) - -### Potential concerns - -- RSS/Atom XML parsing uses regex, which handles common feeds but may fail on exotic feed formats. If issues arise, consider adding `fast-xml-parser` as a dependency. -- iCal parsing handles standard VEVENT blocks but does not support RRULE (recurring events). A future enhancement could add recurrence expansion. -- SSRF protection checks IP format only at the URL level — DNS rebinding attacks could bypass hostname checks. For production hardening, consider resolving DNS before connecting. -- System stats adapters assume specific API shapes for Glances and Prometheus. Custom adapter is a generic JSON fallback. diff --git a/plans/phase-4-7-full-expansion/phase-3-widget-frontend.md b/plans/phase-4-7-full-expansion/phase-3-widget-frontend.md deleted file mode 100644 index ddfe33d..0000000 --- a/plans/phase-4-7-full-expansion/phase-3-widget-frontend.md +++ /dev/null @@ -1,178 +0,0 @@ -# Phase 3: New Widget Components - -**Status:** ✅ Complete -**Parent plan:** [PLAN.md](./PLAN.md) -**Domain:** frontend - -## Objective - -Build all 8 new widget UI components with polished design, integrate them into the existing WidgetRenderer and WidgetCreationForm, and ensure they work with the drag-and-drop system. - -## Tasks - -### 3.1 Clock/Weather Widget - -- [x] Create `src/lib/components/widget/ClockWeatherWidget.svelte` - - Digital clock: large time display with configurable timezone, date below - - Analog clock: SVG clock face with hour/minute/second hands, smooth animation via $effect - - Weather section (optional): current temp, condition icon (Lucide), location label - - Fetches weather from `/api/widgets/weather` on mount + interval - - Config-driven: clockStyle (analog|digital), showWeather, timezone - -### 3.2 System Stats Widget - -- [x] Create `src/lib/components/widget/SystemStatsWidget.svelte` - - Donut/gauge charts for each metric (CPU, RAM, disk) using SVG - - Threshold coloring: green (<60%), yellow (60-85%), red (>85%) via CSS classes - - Auto-refresh at configurable interval - - Fetches from `/api/widgets/system-stats` - - Compact layout: metrics side-by-side with labels below - -### 3.3 RSS/Feed Widget - -- [x] Create `src/lib/components/widget/RssFeedWidget.svelte` - - List of feed items: title + relative date - - Expandable summary on click (slide transition) - - Link icon to open in new tab - - Fetches from `/api/widgets/rss` - - Loading skeleton while fetching - - Empty state when feed has no items - -### 3.4 Calendar Widget - -- [x] Create `src/lib/components/widget/CalendarWidget.svelte` - - Compact event list grouped by day (Today, Tomorrow, then dates) - - Color dot per calendar source - - Time range display (or "All day") - - Location shown if available - - Fetches from `/api/widgets/calendar` - - Empty state: "No upcoming events" - -### 3.5 Markdown Widget - -- [x] Create `src/lib/components/widget/MarkdownWidget.svelte` - - Rendered markdown view (default) using `marked` + `isomorphic-dompurify` - - Edit mode: split-pane with textarea left, preview right - - Syntax highlighting for code blocks (use existing `marked` setup or add `highlight.js`) - - Toggle edit/view mode button - - Save updates config via API - - Proper typography styling for headers, lists, code, blockquotes - -### 3.6 Metric/Counter Widget - -- [x] Create `src/lib/components/widget/MetricWidget.svelte` - - Large centered number with unit suffix - - Label below the number - - Trend arrow: up (green), down (red), flat (gray) — SVG arrow icon - - Auto-refresh at interval - - Fetches from `/api/widgets/metric` - - Number formatting (locale-aware, abbreviate large numbers) - -### 3.7 Link Group Widget - -- [x] Create `src/lib/components/widget/LinkGroupWidget.svelte` - - Compact vertical list of links with optional icons - - Each link: icon (Lucide or none) + label, opens in new tab - - Collapsible header if config.collapsible is true (slide transition) - - Hover highlight on each link row - - No external data fetching — config-driven only - -### 3.8 Camera/Stream Widget - -- [x] Create `src/lib/components/widget/CameraStreamWidget.svelte` - - Snapshot mode: `` tag refreshed at interval via `/api/widgets/camera` - - MJPEG mode: direct `` (continuous stream) - - HLS mode: `