Files
alexei.dolgolyov 1c0a7cb850 feat: Phases 4-7 — Full Feature Expansion (26 features)
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.
2026-03-25 14:18:10 +03:00

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, $effect for 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 transitionstransition:, animate:, in:/out: directives for page transitions, expand/collapse, hover effects
  • svelte/motiontweened and spring stores 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-icons npm 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 entity
    • edit — can modify the entity
    • admin — 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, description
  • accessLevel — per-user, per-group, guest-accessible (boolean)
  • isDefault — one board can be marked as the landing page
  • layout — grid-based responsive layout
  • backgroundConfig — 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 slide transition)

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
  • 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, role
  • Group — id, name, description, isDefault
  • UserGroup — userId, groupId (many-to-many)
  • App — id, name, url, icon, iconType, description, category, healthcheckEnabled, healthcheckInterval, healthcheckMethod, healthcheckExpectedStatus, healthcheckTimeout, createdById
  • AppStatus — id, appId, status, responseTime, checkedAt (latest N records for history)
  • Board — id, name, icon, description, isDefault, isGuestAccessible, backgroundConfig (JSON), createdById
  • Section — id, boardId, title, icon, order, isExpandedByDefault
  • Widget — 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 login
  • GET /api/auth/oauth/authorize — redirect to Authentik
  • GET /api/auth/oauth/callback — handle OAuth callback
  • POST /api/auth/register — self-registration (if enabled)
  • POST /api/auth/refresh — token refresh
  • GET/POST/PATCH/DELETE /api/apps — app CRUD
  • GET /api/apps/:id/status — latest healthcheck status
  • GET/POST/PATCH/DELETE /api/boards — board CRUD (filtered by user permissions)
  • GET/POST/PATCH/DELETE /api/boards/:id/sections — section CRUD
  • GET/POST/PATCH/DELETE /api/boards/:id/sections/:sid/widgets — widget CRUD
  • GET/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 search
  • GET /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)

  1. Drag-and-drop board editor — reorder sections and widgets with svelte-dnd-action (Svelte-native, accessible, performant)
  2. Auto-discovery — scan a Docker socket or Traefik API to auto-register running containers as apps
  3. Favicon auto-fetch — if no icon is selected, attempt to fetch the favicon from the app's URL
  4. Ping history sparkline — tiny inline SVG chart showing uptime over last 24h per app
  5. Import/Export — JSON export of entire config for backup/migration
  6. PWA support — installable on mobile home screen with offline shell (SvelteKit service worker support)
  7. Multi-tab sync — broadcast theme/board changes across tabs via BroadcastChannel API
  8. Quick-add bookmarklet — browser bookmarklet that adds current page as an app via the API
  9. Keyboard-first navigation — Vim-style j/k to move between apps, Enter to 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) DONE
  • Import/Export DONE
  • PWA DONE
  • Ping history sparklines DONE
  • User theme overrides DONE
  • Quick-add bookmarklet DONE
  • Multi-tab sync DONE

Phase 4 — New Widget Types

New widget types to expand dashboard capabilities beyond app launching:

  1. 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' }
  2. 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 }
  3. 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 }
  4. 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 }
  5. Markdown Widget (upgrade from existing Note widget)

    • Full markdown rendering with syntax highlighting (via shiki or highlight.js)
    • Live preview split-pane edit mode
    • Useful for runbooks, quick-reference docs, IP tables, cheat sheets
    • Config: { content: string, syntaxTheme: string }
  6. 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 }
  7. 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 }
  8. 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:

  1. 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 / outline card styles in theme settings
    • Applies globally or per-board
  2. 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, backgroundType to Board model
  3. 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
  4. 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 cardSize to Section and Board models
  5. 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
  6. 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, wallpaperOverlay to Board backgroundConfig

Phase 6 — Functional Features

New capabilities that improve daily usage and operational value:

  1. 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 UserFavorite model (userId, appId, order)
  2. 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 AppClick model (userId, appId, clickedAt)
  3. Uptime Dashboard Page

    • Dedicated /status public 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
  4. 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 NotificationChannel model (userId, type, config), Notification model (userId, appId, event, sentAt, readAt)
  5. 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 Tag model, AppTag many-to-many
  6. 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 AppLink model (appId, label, url, order)
  7. 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, backupCodes to User model
  8. 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 ApiToken model (userId, name, tokenHash, scope, lastUsedAt, expiresAt)
  9. 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 AuditLog model (userId, action, entityType, entityId, details JSON, createdAt)

Phase 7 — Quality of Life

Onboarding, discoverability, and power-user conveniences:

  1. 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
  2. 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
  3. 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
  4. 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 — search
      • j/k — navigate between apps
      • Enter — open selected app
      • e — edit mode
      • 1-9 — switch to board by number
      • f — toggle favorites bar
      • ? — show this overlay
    • Discoverable: small ? hint icon in footer

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 commitsfeat:, 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