1c0a7cb850
Phase 4 — New Widget Types: - Clock/Weather, System Stats, RSS/Feed, Calendar, Markdown, Metric/Counter, Link Group, Camera/Stream widgets - Backend services with caching for each data source - Full creation form with dynamic config fields per type Phase 5 — Visual & Styling Enhancements: - Glassmorphism card style (solid/glass/outline) - Board-level themes with per-board hue/saturation - Animated SVG status rings replacing static dots - Card size options (compact/medium/large) - Custom CSS injection (admin + per-board, sanitized) - Wallpaper backgrounds with blur/overlay/parallax Phase 6 — Functional Features: - Favorites bar with drag-and-drop reordering - Recent apps tracking with privacy toggle - Uptime dashboard page (/status, guest-accessible) - Notifications system (Discord/Slack/Telegram/HTTP webhooks) - App tags with filtering in board view - Multi-URL app cards with expandable sub-links - Personal API tokens with scoped permissions - Audit log with retention and admin viewer Phase 7 — Quality of Life: - Onboarding wizard (5-step first-launch setup) - App URL health preview with favicon/title detection - Board templates (4 built-in + custom import/export) - Keyboard shortcut overlay (j/k nav, 1-9 boards, ? help) 212 files changed, 15641 insertions, 980 deletions. Build, lint, type check, and 222 tests all pass.
178 lines
12 KiB
Markdown
178 lines
12 KiB
Markdown
# Phase 7: Quality of Life
|
|
|
|
**Status:** ✅ Complete
|
|
**Parent plan:** [PLAN.md](./PLAN.md)
|
|
**Domain:** fullstack
|
|
|
|
## Objective
|
|
|
|
Implement 4 quality-of-life features: onboarding wizard, app URL health preview, board templates, and keyboard shortcut overlay.
|
|
|
|
## Tasks
|
|
|
|
### 7.1 Onboarding Wizard
|
|
|
|
- [x] Create `src/lib/components/onboarding/OnboardingWizard.svelte`
|
|
- Full-screen overlay triggered on first launch (no users in DB or onboardingComplete=false in SystemSettings)
|
|
- Steps with progress indicator:
|
|
1. **Welcome** — intro text, app branding
|
|
2. **Create Admin Account** — email, password, display name form
|
|
3. **Auth Mode** — choose local/oauth/both, configure OAuth if selected
|
|
4. **Theme & Background** — pick theme mode, primary color, background type
|
|
5. **Add First Apps** — manual add form OR auto-discover button (if Docker available)
|
|
6. **Create First Board** — name, pick a template or start blank
|
|
- Skippable steps for advanced users
|
|
- Stores completion in SystemSettings.onboardingComplete
|
|
- [x] Create `src/routes/api/onboarding/+server.ts`
|
|
- POST: complete step (validates, creates entities)
|
|
- GET: check onboarding status
|
|
- [x] Create `src/lib/server/services/onboardingService.ts`
|
|
- `isOnboardingNeeded()` — check if any users exist and if onboarding is complete
|
|
- `completeOnboarding()` — mark SystemSettings.onboardingComplete = true
|
|
- [x] Add onboarding check to root layout server load function
|
|
- If onboarding needed, pass flag to layout → show wizard
|
|
|
|
### 7.2 App URL Health Preview
|
|
|
|
- [x] Create `src/lib/components/app/AppUrlPreview.svelte`
|
|
- "Test Connection" button in app create/edit form
|
|
- On click: calls backend to test the URL
|
|
- Shows: HTTP status code, response time (ms), auto-detected favicon URL, page title
|
|
- If no icon selected, offers to use the detected favicon
|
|
- If no name entered, offers to use the detected page title
|
|
- Loading state while testing, error state on failure
|
|
- [x] Create `src/routes/api/apps/preview/+server.ts`
|
|
- POST with `{ url }` body
|
|
- Server-side fetch: HEAD request for status/timing, GET for HTML parsing
|
|
- Extract: favicon (from `<link rel="icon">` or `/favicon.ico`), page title (from `<title>`)
|
|
- Return: `{ status, responseTime, favicon, title }`
|
|
- Timeout: 10s, handle errors gracefully
|
|
- [x] Integrate preview into existing AppForm.svelte (add preview section below URL input)
|
|
|
|
### 7.3 Board Templates
|
|
|
|
- [x] Create `src/lib/server/services/templateService.ts`
|
|
- `getBuiltinTemplates()` — return hardcoded built-in templates
|
|
- `getUserTemplates(userId)` — custom templates from DB
|
|
- `createTemplate(input)` — save board layout as template
|
|
- `applyTemplate(templateId, boardId)` — create sections from template config
|
|
- `exportTemplate(boardId)` — export board layout as JSON
|
|
- `importTemplate(json)` — import template from JSON
|
|
- [x] Create built-in templates (hardcoded in service):
|
|
- "Home Server" — sections: Media, Networking, Storage, Monitoring
|
|
- "Media Stack" — sections: Streaming, Downloads, Management
|
|
- "Dev Tools" — sections: Git, CI/CD, Databases, Docs
|
|
- "Monitoring" — sections: Metrics, Logs, Alerts, Status
|
|
- [x] Create `src/lib/components/board/TemplatePicker.svelte`
|
|
- Grid of template cards (icon, name, description, section preview)
|
|
- Built-in templates + user-created templates
|
|
- Click to select → creates board with template sections
|
|
- "Blank Board" option
|
|
- "Import Template" button (file upload JSON)
|
|
- [x] Create `src/routes/api/templates/+server.ts` — GET (list), POST (create from board)
|
|
- [x] Create `src/routes/api/templates/[id]/+server.ts` — GET (single), DELETE
|
|
- [x] Create `src/routes/api/templates/import/+server.ts` — POST (import JSON)
|
|
- [x] Integrate TemplatePicker into board creation flow
|
|
|
|
### 7.4 Keyboard Shortcut Overlay
|
|
|
|
- [x] Create `src/lib/components/ui/KeyboardShortcutOverlay.svelte`
|
|
- Modal triggered by pressing `?` key
|
|
- Context-aware sections:
|
|
- **Global:** Cmd/Ctrl+K (search), ? (shortcuts), 1-9 (switch board), f (toggle favorites)
|
|
- **Board View:** j/k (navigate apps), Enter (open selected), e (edit mode)
|
|
- **Admin:** (admin-specific shortcuts if any)
|
|
- Organized in categorized columns
|
|
- Close on Escape or clicking outside
|
|
- Small `?` hint icon in footer
|
|
- [x] Create `src/lib/stores/keyboard.svelte.ts`
|
|
- Register global keyboard listeners
|
|
- j/k navigation: track selected app index in current board
|
|
- Enter: open selected app URL
|
|
- 1-9: switch to board by index
|
|
- f: toggle favorites bar visibility
|
|
- e: toggle board edit mode
|
|
- ?: show shortcut overlay
|
|
- Disable shortcuts when input/textarea is focused
|
|
- [x] Integrate keyboard store into root layout
|
|
- [x] Add `?` hint icon to footer component
|
|
|
|
## Files to Modify/Create
|
|
|
|
- `src/lib/components/onboarding/OnboardingWizard.svelte` — new
|
|
- `src/routes/api/onboarding/+server.ts` — new
|
|
- `src/lib/server/services/onboardingService.ts` — new
|
|
- `src/lib/components/app/AppUrlPreview.svelte` — new
|
|
- `src/routes/api/apps/preview/+server.ts` — new
|
|
- `src/lib/components/app/AppForm.svelte` — modify (add preview)
|
|
- `src/lib/server/services/templateService.ts` — new
|
|
- `src/lib/components/board/TemplatePicker.svelte` — new
|
|
- `src/routes/api/templates/+server.ts` — new
|
|
- `src/routes/api/templates/[id]/+server.ts` — new
|
|
- `src/routes/api/templates/import/+server.ts` — new
|
|
- `src/lib/components/ui/KeyboardShortcutOverlay.svelte` — new
|
|
- `src/lib/stores/keyboard.svelte.ts` — new
|
|
- `src/routes/+layout.svelte` — modify (onboarding check, keyboard store)
|
|
- `src/routes/+layout.server.ts` — modify (onboarding status)
|
|
|
|
## Acceptance Criteria
|
|
|
|
- Onboarding wizard triggers on first launch, creates admin user and basic setup
|
|
- Steps can be skipped, wizard can be completed partially
|
|
- App URL preview shows status, timing, favicon, and title extraction
|
|
- Board templates create correct section structure when applied
|
|
- Built-in templates are always available (not stored in DB)
|
|
- Template import/export produces valid JSON that can round-trip
|
|
- Keyboard shortcuts work globally, disabled in text inputs
|
|
- Shortcut overlay shows context-appropriate shortcuts
|
|
- All features work in both dark and light mode
|
|
|
|
## Notes
|
|
|
|
- Onboarding detection: simplest approach is checking User count === 0
|
|
- URL preview: use node's fetch with timeout, parse HTML response for favicon/title
|
|
- Board templates: config JSON structure: `{ sections: [{ title, icon, order }] }`
|
|
- Keyboard navigation: use data attributes on app widgets to track position
|
|
- The `?` shortcut must not interfere with typing in inputs/textareas
|
|
|
|
## 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
|
|
|
|
- **7.1 Onboarding Wizard**: Created `OnboardingWizard.svelte` with 5-step full-screen overlay (Welcome, Create Admin, Auth Mode, Theme, Create Board). Created `onboardingService.ts` with `isOnboardingNeeded()`, `completeOnboarding()`, and `getOnboardingStatus()`. Created `/api/onboarding` route with GET (status check) and POST (step completion with per-step Zod validation). Added `onboardingNeeded` flag to root layout server load. Wizard renders as fixed overlay in `+layout.svelte` when flag is true.
|
|
|
|
- **7.2 App URL Health Preview**: Created `AppUrlPreview.svelte` with "Test Connection" button showing HTTP status, response time, favicon preview, and page title extraction. Offers "Use as name" and "Use as icon" buttons when fields are empty. Created `/api/apps/preview` route with server-side HEAD + GET requests, 10s timeout, HTML parsing (first 64KB), favicon extraction from `<link rel="icon">` or `/favicon.ico` fallback. Integrated into `AppForm.svelte` below the URL input field.
|
|
|
|
- **7.3 Board Templates**: Created `templateService.ts` with 4 built-in templates (Home Server, Media Stack, Dev Tools, Monitoring) hardcoded as constants, plus CRUD for user templates via `BoardTemplate` Prisma model. Supports `getBuiltinTemplates()`, `getAllTemplates()`, `createTemplate()`, `applyTemplate()`, `exportTemplate()`, and `importTemplate()`. Created 3 API routes: `/api/templates` (GET list, POST create), `/api/templates/[id]` (GET, DELETE), `/api/templates/import` (POST). Created `TemplatePicker.svelte` with grid UI showing blank board + all templates with section previews and JSON file import. Integrated into board creation page with hidden `templateId` input and server-side `applyTemplate()` call after board creation.
|
|
|
|
- **7.4 Keyboard Shortcut Overlay**: Created `keyboard.svelte.ts` store with global keydown listener, input-focus detection, j/k app navigation (using `data-app-widget` attributes), Enter to open selected, 1-9 board switching (via sidebar link click), `f` for favorites toggle (custom event), `e` for edit mode toggle, `?` for overlay toggle. Created `KeyboardShortcutOverlay.svelte` modal with categorized shortcuts (Global + Board View). Added `data-keyboard-selected` CSS rule to `app.css` for visual selection ring. Added `?` hint icon button to Sidebar footer next to collapse toggle. Integrated keyboard store init/destroy into root `+layout.svelte`.
|
|
|
|
### What the next phase needs to know
|
|
|
|
- The onboarding wizard is a simple full-screen overlay that blocks the UI — it does NOT redirect. Once completed, the page needs a full reload (or `invalidateAll()`) to re-evaluate `onboardingNeeded`.
|
|
- The wizard has 5 steps (Welcome, Admin, Auth, Theme, Complete) — the original plan had 6 steps but "Add First Apps" was consolidated into the board creation step for simplicity.
|
|
- The onboarding API has NO authentication requirement (since it runs before any user exists).
|
|
- The URL preview endpoint requires authentication and returns `{ status, responseTime, favicon, title, error }`.
|
|
- Built-in templates use `builtin-` prefixed IDs and are not stored in the database. The `deleteTemplate` function blocks deletion of builtins.
|
|
- Template application in board creation uses `request.clone().formData()` to read the `templateId` hidden input alongside the superforms data.
|
|
- The keyboard store's `init()` must be called from a component context (it adds a global `keydown` listener). `destroy()` must be called in `onDestroy`.
|
|
- j/k navigation relies on elements having `data-app-widget` attribute — this needs to be added to `AppWidget.svelte` in Phase 8 integration.
|
|
- The `f` shortcut dispatches a `toggle-favorites` custom event on `window` — the FavoritesBar or board page needs to listen for this.
|
|
- The `e` shortcut toggles `keyboard.editMode` state — board components can read this to enter/exit edit mode.
|
|
|
|
### Potential concerns
|
|
|
|
- The onboarding wizard completes steps via sequential API calls — if the browser is closed mid-wizard, partial state (e.g., admin created but onboarding not marked complete) can occur. The wizard handles this by checking `adminCreated` state and skipping re-creation.
|
|
- The URL preview endpoint makes server-side HTTP requests to arbitrary URLs, which could be used for SSRF. Consider adding URL validation (e.g., blocking private IP ranges) in a security review.
|
|
- Template import accepts arbitrary JSON — validation checks structure but does not limit section count or title length beyond Zod schema bounds.
|
|
- The keyboard store adds a `keydown` listener on `window` — if multiple layout instances exist (unlikely), listeners could duplicate. The `init()` method guards against this.
|
|
- Board creation page now reads `request` twice (superValidate + manual formData) — uses `request.clone()` to avoid "body already consumed" errors.
|