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.
28 KiB
Web App Launcher — Implementation Plan Prompt
Project Overview
Build a self-hosted web application launcher / dashboard for a TrueNAS server environment. The app serves as a centralized portal to organize, discover, and navigate to self-hosted services (Plex, Nextcloud, Gitea, Home Assistant, etc.) via customizable boards with live health indicators.
Repository: https://git.dolgolyov-family.by/alexei.dolgolyov/web-app-launcher
Git user: alexei.dolgolyov / dolgolyov.alexei@gmail.com (Gitea instance)
Tech Stack
Framework (Full-Stack)
- SvelteKit — all-in-one framework: SSR, routing, API routes (
+server.ts), form actions — single process, no separate backend needed - Svelte 5 (runes mode) —
$state,$derived,$effectfor reactive state; compiler-based, no virtual DOM, minimal runtime - TypeScript — strict mode throughout
UI & Styling
- Tailwind CSS v4 — utility-first styling with smooth animation support
- shadcn-svelte (Bits UI primitives) — accessible, unstyled component library; each component is a separate file
- Svelte built-in transitions —
transition:,animate:,in:/out:directives for page transitions, expand/collapse, hover effects - svelte/motion —
tweenedandspringstores for ambient background animations
Data & State
- SvelteKit load functions — server-side data loading with automatic invalidation
- Svelte runes (
$state,$derived) — client-side reactive state (theme, sidebar, UI) - Superforms + Zod — type-safe form handling with progressive enhancement and server-side validation
- Prisma ORM — type-safe database access, migrations, seeding
- SQLite — zero-config, file-based, perfect for single-server deployment (easy Docker volume mount, simple backups). Migrate to PostgreSQL later if needed.
Auth
- openid-client — Authentik OIDC/OAuth2 integration
- bcrypt + JWT — local auth with refresh token rotation via HTTP-only cookies
- SvelteKit hooks (
handle) — auth middleware, session management
Icons
- Lucide Svelte — 1500+ clean SVG icons for UI chrome
- Simple Icons (via
simple-iconsnpm package) — 3000+ brand/service icons (Plex, Nextcloud, Docker, Grafana, etc.) — perfect for self-hosted app logos - Dashboard Icons (CDN fallback) — community-maintained self-hosted app icon set
- Custom upload — allow users to upload SVG/PNG icons as a fallback
- No emojis — strictly SVG/image icons only
Background Jobs
- node-cron — scheduled healthcheck pings (runs in SvelteKit server process)
DevOps
- Docker — multi-stage build (SvelteKit build → Node adapter → lightweight runtime)
- docker-compose.yml — single-command deployment with volume mounts for SQLite + uploads
- Gitea Actions — CI/CD workflows (lint, type-check, test, Docker image push to Gitea Container Registry)
Functional Requirements
1. Authentication & Authorization
Auth Modes (Admin-Configurable)
The system supports three auth modes, selectable by admin in settings:
- OAuth only — all users authenticate via Authentik (OIDC/OAuth2)
- Local only — email/password login with optional registration
- Both — user chooses OAuth or local login on the login page
- Guest mode — unauthenticated users see boards marked as
guest-accessible
User Management
- Admin can create/edit/delete users manually
- Self-registration is disabled by default; admin toggles it on/off
- OAuth auto-provisions users on first login (maps Authentik groups to local groups)
- Users have:
id,email,displayName,avatarUrl,authProvider,role,groupIds[]
Groups & Access Control
- Default groups:
admin,user - Admin can create custom groups
- Permissions are hierarchical: User-level overrides > Group-level > Default
- Permission model per entity (board, section, app):
view— can see the entityedit— can modify the entityadmin— full control (delete, manage access)
- Guest access is a separate boolean flag per board
Session Management
- JWT access tokens stored in HTTP-only cookies (managed by SvelteKit hooks)
- Refresh token rotation (7-day expiry)
- Server-side session validation in
hooks.server.ts - Logout invalidates refresh token
2. Apps (Service Registry)
Each app represents a self-hosted service:
- url (required) — base URL of the service
- name (required) — display name
- icon — one of: Simple Icons slug, Lucide icon name, Dashboard Icons ID, or uploaded image path
- description (optional) — short text shown on hover/expand
- category/tags (optional) — for filtering/search
- healthcheck configuration:
enabled(default: true)interval(default: 60s, min: 10s, max: 3600s)method— HTTP HEAD/GET to the URL (or custom endpoint)expectedStatus— default 200, configurable (e.g., 401 is "alive" for auth-protected services)timeout— max wait before marking as down (default: 5s)
- Status:
online | offline | degraded | unknown— derived from healthcheck results - Backend runs healthchecks on a per-app schedule; results are cached and pushed to frontend via polling (SvelteKit invalidation) or SSE
3. Boards
Boards are the primary organizational unit — each board is a full-page layout of sections and widgets.
Board Properties
name,icon,descriptionaccessLevel— per-user, per-group, guest-accessible (boolean)isDefault— one board can be marked as the landing pagelayout— grid-based responsive layoutbackgroundConfig— ambient background settings (see Appearance)
Sections (Groups)
- Collapsible/expandable containers within a board
- Properties:
title,icon,isExpanded(default state),order - Contain an ordered list of widgets
- Smooth expand/collapse animation (Svelte
slidetransition)
Widgets
Widgets are the atomic content units inside sections.
App Widget (MVP):
- Displays app icon, name, status indicator (colored dot/ring), optional description
- Click opens the app URL in a new tab
- Hover shows description tooltip + last healthcheck time
- Visual states: online (green pulse), offline (red), degraded (yellow), unknown (gray)
Future widget types (post-MVP, design the schema to support them):
- Bookmark widget — simple URL + label (no healthcheck)
- Note widget — rich text or markdown note
- Embed widget — iframe embed of a service
- Status widget — aggregated status of multiple apps
4. Search & Navigation
- Global search bar (Cmd/Ctrl+K) — searches across all accessible apps and boards
- Keyboard navigation support
- Sidebar with board list (collapsible)
- Breadcrumb navigation within nested views
5. Admin Panel
- User management (CRUD, group assignment)
- Group management (CRUD, permission templates)
- App management (CRUD, healthcheck config, bulk import/export)
- Board management (CRUD, access control)
- System settings:
- Auth mode selection
- Registration toggle
- OAuth provider configuration (client ID, secret, discovery URL)
- Default theme / primary color
- Healthcheck global defaults
Non-Functional Requirements
Appearance & UX
- Modern, clean design — inspired by Homarr / Heimdall / Organizr but with smoother polish
- Ambient animated backgrounds — subtle mesh gradient, particle field, or aurora effect (configurable, can be disabled); implemented with Svelte
tweened/spring+ CSS/Canvas - Customizable primary color — HSL-based theme system; admin sets default, users can override
- Dark / Light / System theme — with smooth CSS transition
- Smooth animations everywhere (using Svelte built-in transitions):
- Page transitions (
in:fade,out:fly) - Section expand/collapse (
transition:slide) - Card hover effects (subtle scale + shadow lift via CSS + Svelte
spring) - Status indicator pulse (CSS
@keyframes) - Skeleton loading states
- Page transitions (
- Responsive — works on desktop, tablet, and mobile
- No emojis as icons — use SVG icon libraries exclusively
File Structure (Modularity)
SvelteKit route-based structure with one component per file:
src/
routes/
+layout.svelte # Root layout (sidebar, header, ambient bg)
+layout.server.ts # Root auth check, load user session
+page.svelte # Dashboard / default board redirect
login/
+page.svelte # Login page
+page.server.ts # Login form action
register/
+page.svelte # Registration page (if enabled)
+page.server.ts # Register form action
auth/
oauth/
authorize/+server.ts # Redirect to Authentik
callback/+server.ts # Handle OAuth callback
refresh/+server.ts # Token refresh
boards/
+page.svelte # Board list
+page.server.ts # Load boards (filtered by permissions)
[boardId]/
+page.svelte # Board view
+page.server.ts # Load board with sections/widgets
edit/
+page.svelte # Board editor
+page.server.ts # Board update actions
apps/
+page.svelte # App registry list
+page.server.ts # Load apps
[appId]/
+server.ts # App CRUD API
status/+server.ts # Healthcheck status API
admin/
+layout.svelte # Admin layout (admin-only guard)
+layout.server.ts # Admin auth check
users/
+page.svelte # User management
+page.server.ts # User CRUD actions
groups/
+page.svelte # Group management
+page.server.ts # Group CRUD actions
settings/
+page.svelte # System settings
+page.server.ts # Settings update actions
api/
apps/+server.ts # App CRUD REST endpoints
apps/[id]/+server.ts # Single app operations
apps/[id]/status/+server.ts # Healthcheck status
boards/+server.ts # Board CRUD
boards/[id]/+server.ts # Single board operations
boards/[id]/sections/+server.ts # Section CRUD
boards/[id]/sections/[sid]/+server.ts # Single section
boards/[id]/sections/[sid]/widgets/+server.ts # Widget CRUD
users/+server.ts # User management (admin)
groups/+server.ts # Group management (admin)
admin/settings/+server.ts # System settings (admin)
search/+server.ts # Global search
health/+server.ts # App healthcheck endpoint
lib/
components/
ui/ # shadcn-svelte primitives (Button, Dialog, etc.)
layout/
Sidebar.svelte
Header.svelte
MainLayout.svelte
ThemeToggle.svelte
board/
Board.svelte
BoardHeader.svelte
BoardCard.svelte
section/
Section.svelte
SectionHeader.svelte
SectionCollapsible.svelte
widget/
AppWidget.svelte
AppWidgetStatus.svelte
WidgetContainer.svelte
WidgetGrid.svelte
app/
AppForm.svelte
AppIconPicker.svelte
AppHealthBadge.svelte
AppCard.svelte
auth/
LoginForm.svelte
OAuthButton.svelte
RegisterForm.svelte
admin/
UserTable.svelte
GroupTable.svelte
SettingsForm.svelte
PermissionEditor.svelte
search/
SearchDialog.svelte
SearchResult.svelte
SearchTrigger.svelte
background/
AmbientBackground.svelte
MeshGradient.svelte
ParticleField.svelte
AuroraEffect.svelte
server/
services/
authService.ts
appService.ts
boardService.ts
healthcheckService.ts
userService.ts
groupService.ts
permissionService.ts
middleware/
authenticate.ts
authorize.ts
guestAccess.ts
jobs/
healthcheckScheduler.ts
utils/
jwt.ts
password.ts
iconResolver.ts
stores/
theme.svelte.ts # Svelte 5 rune-based store
ui.svelte.ts
search.svelte.ts
utils/
constants.ts
validators.ts
helpers.ts
types/
auth.ts
app.ts
board.ts
widget.ts
user.ts
group.ts
permission.ts
hooks.server.ts # Auth middleware, session injection
hooks.client.ts # Client-side error handling
app.css # Tailwind base + theme variables
app.d.ts # SvelteKit type augmentation (locals, session)
prisma/
schema.prisma
migrations/
seed.ts
static/
uploads/ # User-uploaded icons
Database Schema (Prisma)
Key models:
User— id, email, password (nullable for OAuth), displayName, avatarUrl, authProvider, roleGroup— id, name, description, isDefaultUserGroup— userId, groupId (many-to-many)App— id, name, url, icon, iconType, description, category, healthcheckEnabled, healthcheckInterval, healthcheckMethod, healthcheckExpectedStatus, healthcheckTimeout, createdByIdAppStatus— id, appId, status, responseTime, checkedAt (latest N records for history)Board— id, name, icon, description, isDefault, isGuestAccessible, backgroundConfig (JSON), createdByIdSection— id, boardId, title, icon, order, isExpandedByDefaultWidget— id, sectionId, type, order, config (JSON — for AppWidget:{ appId })Permission— id, entityType (board/app), entityId, targetType (user/group), targetId, level (view/edit/admin)SystemSettings— singleton row: authMode, registrationEnabled, oauthConfig (encrypted JSON), defaultTheme, defaultPrimaryColor, healthcheckDefaults (JSON)
API Design
RESTful JSON API via SvelteKit +server.ts routes with consistent envelope:
{
"success": true,
"data": { ... },
"error": null,
"meta": { "total": 100, "page": 1, "limit": 20 }
}
Key endpoints (all under src/routes/api/):
POST /api/auth/login— local loginGET /api/auth/oauth/authorize— redirect to AuthentikGET /api/auth/oauth/callback— handle OAuth callbackPOST /api/auth/register— self-registration (if enabled)POST /api/auth/refresh— token refreshGET/POST/PATCH/DELETE /api/apps— app CRUDGET /api/apps/:id/status— latest healthcheck statusGET/POST/PATCH/DELETE /api/boards— board CRUD (filtered by user permissions)GET/POST/PATCH/DELETE /api/boards/:id/sections— section CRUDGET/POST/PATCH/DELETE /api/boards/:id/sections/:sid/widgets— widget CRUDGET/POST/PATCH/DELETE /api/users— user management (admin)GET/POST/PATCH/DELETE /api/groups— group management (admin)GET/PATCH /api/admin/settings— system settings (admin)GET /api/search?q=...— global searchGET /api/health— app health endpoint for Docker healthcheck
Docker Deployment
# Multi-stage: build SvelteKit with Node adapter → slim runtime
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npx prisma generate
RUN npm run build
FROM node:22-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/build ./build
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
COPY --from=builder /app/prisma ./prisma
EXPOSE 3000
HEALTHCHECK CMD wget -q --spider http://localhost:3000/api/health || exit 1
ENTRYPOINT ["sh", "-c", "npx prisma migrate deploy && node build"]
# docker-compose.yml
services:
web-app-launcher:
build: .
ports:
- '3000:3000'
volumes:
- ./data:/app/data # SQLite DB
- ./uploads:/app/uploads # Custom icons
environment:
- DATABASE_URL=file:/app/data/launcher.db
- JWT_SECRET=changeme
- OAUTH_CLIENT_ID=
- OAUTH_CLIENT_SECRET=
- OAUTH_DISCOVERY_URL=
- ORIGIN=http://localhost:3000
restart: unless-stopped
CI/CD (Gitea Actions)
.gitea/workflows/ci.yml:
- On push to any branch: lint (
eslint), type-check (svelte-check), unit tests (vitest) - On push to main: build Docker image, push to Gitea Container Registry (
git.dolgolyov-family.by/alexei.dolgolyov/web-app-launcher) - On tag (vX.Y.Z): build + push tagged image, create Gitea release
Additional Features
Cool Ideas (Included in Phases)
- Drag-and-drop board editor — reorder sections and widgets with
svelte-dnd-action(Svelte-native, accessible, performant) - Auto-discovery — scan a Docker socket or Traefik API to auto-register running containers as apps
- Favicon auto-fetch — if no icon is selected, attempt to fetch the favicon from the app's URL
- Ping history sparkline — tiny inline SVG chart showing uptime over last 24h per app
- Import/Export — JSON export of entire config for backup/migration
- PWA support — installable on mobile home screen with offline shell (SvelteKit service worker support)
- Multi-tab sync — broadcast theme/board changes across tabs via BroadcastChannel API
- Quick-add bookmarklet — browser bookmarklet that adds current page as an app via the API
- Keyboard-first navigation — Vim-style
j/kto move between apps,Enterto open
MVP Scope (Phase 1)
To avoid scope creep, the MVP should include:
- Local auth + guest mode (OAuth in Phase 2)
- App CRUD + healthcheck with status display
- Single default board with sections and app widgets
- Admin panel (user/app/board management)
- Dark theme + ambient background
- Docker deployment
- Basic Gitea CI
Phase 2
- OAuth/Authentik integration
- Multi-board support with per-board access control
- Custom groups + granular permissions
- Drag-and-drop reordering
- Global search (Cmd+K)
- Additional widget types
Phase 3 (DONE)
Auto-discovery (Docker/Traefik)DONEImport/ExportDONEPWADONEPing history sparklinesDONEUser theme overridesDONEQuick-add bookmarkletDONEMulti-tab syncDONE
Phase 4 — New Widget Types
New widget types to expand dashboard capabilities beyond app launching:
-
Clock / Weather Widget
- Local time display with configurable timezone
- Optional weather via free OpenMeteo API (no API key required)
- Analog or digital clock face, minimal design
- Config:
{ timezone: string, showWeather: boolean, latitude?: number, longitude?: number, clockStyle: 'analog' | 'digital' }
-
System Stats Widget
- CPU, RAM, disk usage pulled from TrueNAS API or Glances API
- Tiny gauge/donut charts with auto-refresh
- Threshold coloring: green (< 60%) → yellow (60-85%) → red (> 85%)
- Config:
{ sourceUrl: string, sourceType: 'truenas' | 'glances' | 'custom', metrics: string[], refreshInterval: number }
-
RSS/Feed Widget
- Subscribe to any RSS/Atom feed (release notes, changelogs, security advisories)
- Shows latest N items with title + date, expandable to show summary
- Config:
{ feedUrl: string, maxItems: number, showSummary: boolean }
-
Calendar Widget
- iCal URL subscription (Nextcloud, Google Calendar, etc.)
- Compact list of today's + upcoming events
- Color-coded by calendar source
- Config:
{ icalUrls: Array<{ url: string, color: string, label: string }>, daysAhead: number }
-
Markdown Widget (upgrade from existing Note widget)
- Full markdown rendering with syntax highlighting (via
shikiorhighlight.js) - Live preview split-pane edit mode
- Useful for runbooks, quick-reference docs, IP tables, cheat sheets
- Config:
{ content: string, syntaxTheme: string }
- Full markdown rendering with syntax highlighting (via
-
Metric/Counter Widget
- Single big number with label (e.g., "12 containers running", "99.7% uptime")
- Data source: static value, HTTP JSON endpoint + JSONPath, or Prometheus PromQL query
- Trend arrow (up/down/flat vs last poll)
- Config:
{ label: string, source: 'static' | 'http' | 'prometheus', value?: string, url?: string, jsonPath?: string, query?: string, unit?: string, refreshInterval: number }
-
Link Group Widget
- Compact list of related URLs (lighter than full app cards)
- Example: "Documentation" group with links to wikis, API docs, Swagger pages
- Collapsible, optional numbering and icons per link
- Config:
{ links: Array<{ label: string, url: string, icon?: string }>, collapsible: boolean }
-
Camera/Stream Widget
- MJPEG or HLS stream thumbnail from security cameras or media servers
- Click to open fullscreen stream in modal or new tab
- Auto-refresh snapshot at configurable interval
- Config:
{ streamUrl: string, type: 'mjpeg' | 'hls' | 'snapshot', refreshInterval: number, aspectRatio: string }
Phase 5 — Visual & Styling Enhancements
Polish the visual experience with advanced theming and card styles:
-
Glassmorphism Card Style
- Frosted glass effect on cards (
backdrop-filter: blur(12px)+ semi-transparent bg) - Ambient background effect bleeds through cards
- Toggle between
solid/glass/outlinecard styles in theme settings - Applies globally or per-board
- Frosted glass effect on cards (
-
Board-Level Themes
- Each board gets its own color accent (hue/saturation) + background effect
- Example: "Work" = blue + mesh gradient, "Media" = purple + aurora, "Infra" = green + particles
- Board theme overrides global theme when viewing that board
- Smooth transition when switching boards
- Schema: add
themeHue,themeSaturation,backgroundTypeto Board model
-
Animated Status Ring
- Replace the static status dot with an SVG ring around the app icon
- Online = animated green fill sweep, Offline = pulsing red ring, Degraded = partial yellow arc, Unknown = gray dashed
- More visually striking, scales well with different card sizes
-
Card Size Options
- Three sizes:
compact(icon + name),medium(current),large(icon + name + description + sparkline + tags) - Configurable per-section or per-board
- Responsive: auto-downsizes on mobile
- Schema: add
cardSizeto Section and Board models
- Three sizes:
-
Custom CSS Injection
- Admin-level custom CSS textarea in system settings
- Per-board CSS overrides field
- Sanitized (strip
<script>, limit selectors to app scope) - Power users can tweak anything without touching source code
-
Wallpaper Backgrounds
- Upload custom image as board background (in addition to procedural effects)
- Options: blur amount, overlay opacity, parallax scroll, fixed/scroll position
- Optional Unsplash integration: random daily wallpaper from a user-defined collection (requires free API key)
- Schema: add
wallpaperUrl,wallpaperBlur,wallpaperOverlayto Board backgroundConfig
Phase 6 — Functional Features
New capabilities that improve daily usage and operational value:
-
Pinned / Favorites Bar
- Users pin most-used apps to a persistent "Favorites" bar at the top of every board
- Per-user, survives board navigation
- Drag-and-drop reordering within the favorites bar
- Schema: new
UserFavoritemodel (userId, appId, order)
-
Recent Apps
- Track which apps each user clicks (last 10)
- Auto-generated "Recently Used" section at top of default board
- Privacy toggle: users can disable click tracking in their settings
- Schema: new
AppClickmodel (userId, appId, clickedAt)
-
Uptime Dashboard Page
- Dedicated
/statuspublic page showing all app statuses - Time range selector: 24h / 7d / 30d uptime percentages
- Incident timeline: when apps went down, how long, recovery time
- Can be shared as a team/family status page (guest-accessible, separate from boards)
- Larger sparkline charts with hover tooltips showing exact timestamps
- Dedicated
-
Notifications System
- In-app toast notifications when a monitored app goes offline/online
- Webhook integrations: Discord, Slack, Telegram, generic HTTP POST
- Notification preferences per user: which apps to watch, which channels to use
- Notification history page with read/unread state
- Schema: new
NotificationChannelmodel (userId, type, config),Notificationmodel (userId, appId, event, sentAt, readAt)
-
App Tags + Filtering
- Tag apps with labels:
media,infra,dev,monitoring, etc. - Filter bar within boards to show/hide apps by tag
- Tag-based auto-sections: dynamically group apps by tag
- Tag management in admin panel (CRUD, color per tag)
- Schema: new
Tagmodel,AppTagmany-to-many
- Tag apps with labels:
-
Multi-URL Apps
- Some services have multiple entry points (Grafana dashboards, Portainer envs, Proxmox nodes)
- App card expands on hover/click to reveal sub-links
- Primary URL (main click) + secondary URLs list with labels
- Schema: new
AppLinkmodel (appId, label, url, order)
-
Two-Factor Authentication (TOTP)(DEFERRED — not in current scope)- Optional 2FA for local accounts using TOTP (Google Authenticator / Authy compatible)
- QR code setup flow in user settings with
otpauth://URI - Backup codes (one-time use, 10 generated at setup)
- Enforced 2FA option for admin accounts
- Schema: add
totpSecret,totpEnabled,backupCodesto User model
-
Personal API Tokens
- Generate API tokens in user settings for programmatic access
- Scoped permissions:
read,write,admin - Token listing with last-used timestamp, revocation
- Used by external scripts, CLI tools, or future mobile apps
- Schema: new
ApiTokenmodel (userId, name, tokenHash, scope, lastUsedAt, expiresAt)
-
Audit Log
- Track admin actions: user created/deleted, board modified, settings changed, apps imported
- Viewable in admin panel with date range + action type filters
- Retention policy configurable: 30/60/90 days (auto-pruned by cron job)
- Schema: new
AuditLogmodel (userId, action, entityType, entityId, details JSON, createdAt)
Phase 7 — Quality of Life
Onboarding, discoverability, and power-user conveniences:
-
Onboarding Wizard
- Triggered on first launch (no users exist in DB)
- Steps: create admin account → configure auth mode → pick theme + background → add first apps (manual or auto-discover) → create first board
- Progress indicator, skippable steps for advanced users
- Stores completion flag in SystemSettings
-
App URL Health Preview
- When adding/editing an app, fetch the URL server-side and show:
- HTTP status code + response time
- Auto-detected favicon (if no icon chosen)
- Page title extraction for auto-filling app name
- "Test Connection" button in the app form
- Reuse existing healthcheckService logic
- When adding/editing an app, fetch the URL server-side and show:
-
Board Templates
- Pre-built board layouts shipped with the app:
- "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)
- User picks a template when creating a new board → creates board + empty sections
- Community-shareable: export a board as template JSON, import others' templates
- Pre-built board layouts shipped with the app:
-
Keyboard Shortcut Overlay
- Press
?anywhere to show all available shortcuts in a modal - Context-aware: shows different shortcuts on board view vs admin vs search
- Shortcuts include:
Cmd/Ctrl+K— searchj/k— navigate between appsEnter— open selected appe— edit mode1-9— switch to board by numberf— toggle favorites bar?— show this overlay
- Discoverable: small
?hint icon in footer
- Press
Constraints & Preferences
- Immutable data patterns — never mutate objects in place; return new copies
- Small files — one component/service per file, 200-400 lines typical, 800 max
- Comprehensive error handling — every API call, every user action
- Input validation — Zod schemas shared between client (Superforms) and server
- No hardcoded secrets — all sensitive config via environment variables
- Conventional commits —
feat:,fix:,refactor:, etc. - 80%+ test coverage target — unit tests with Vitest, integration tests for API routes, E2E with Playwright
- Progressive enhancement — SvelteKit form actions work without JavaScript where possible