Files
web-app-launcher/plans/phase-4-7-full-expansion/phase-6-functional-frontend.md
T
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

208 lines
13 KiB
Markdown

# Phase 6: Functional Features — Frontend
**Status:** ✅ Complete
**Parent plan:** [PLAN.md](./PLAN.md)
**Domain:** frontend
## Objective
Build all frontend UI for the 8 functional features: favorites bar, recent apps, uptime dashboard page, notifications, tag management + filtering, multi-URL app cards, API token management, and audit log viewer.
## Tasks
### 6.1 Favorites Bar
- [x] Create `src/lib/components/layout/FavoritesBar.svelte`
- Horizontal bar at top of board view, below header
- Shows favorite app icons in compact format (icon + name)
- Drag-and-drop reordering within the bar (svelte-dnd-action)
- Click opens app URL; right-click or long-press to remove
- Add-to-favorites button on app widget context menu
- [x] Create `src/lib/stores/favorites.svelte.ts`
- Fetch favorites from `/api/favorites` on init
- Methods: add, remove, reorder (optimistic updates with API sync)
- [x] Integrate FavoritesBar into board layout (show when user has favorites)
### 6.2 Recent Apps Section
- [x] Create `src/lib/components/board/RecentAppsSection.svelte`
- Auto-generated section at top of default board
- Shows last 10 unique apps the user clicked
- Compact app cards (icon + name + last used time)
- "Clear history" button
- Respects user's `trackRecentApps` preference
- [x] Update app click handling to record clicks via `/api/recent-apps` POST
- [x] Add privacy toggle in user settings (trackRecentApps)
### 6.3 Uptime Dashboard Page
- [x] Create `src/routes/status/+page.svelte` — public status page
- [x] Create `src/routes/status/+page.server.ts` — load uptime data (guest-accessible)
- Time range selector: 24h / 7d / 30d
- Per-app: name, current status, uptime percentage, avg response time
- Sparkline chart (larger than widget version) with hover tooltips
- Incident timeline: colored blocks showing up/down periods
- Summary header: total apps, apps online, overall uptime %
- [x] Add "Status Page" link to sidebar navigation
### 6.4 Notifications UI
- [x] Create `src/lib/components/notifications/NotificationBell.svelte`
- Bell icon in header with unread count badge
- Click opens notification dropdown/panel
- List of recent notifications with read/unread state
- "Mark all as read" button
- Link to full notification history
- [x] Create `src/lib/components/notifications/NotificationHistory.svelte`
- Full page or modal with paginated notification list
- Filter by app, event type
- Timestamp, app name, event description
- [x] Create `src/lib/components/notifications/NotificationChannelForm.svelte`
- Form to add/edit notification channels
- Dynamic fields based on channel type (Discord: webhook URL, Slack: webhook URL, Telegram: bot token + chat ID, HTTP: URL + method)
- "Send Test" button
- Enable/disable toggle per channel
- [x] Create `src/routes/settings/notifications/+page.svelte` — notification preferences page
- [x] Create `src/lib/stores/notifications.svelte.ts`
- Track unread count, poll for new notifications
### 6.5 Tag Management & Filtering
- [x] Create `src/lib/components/admin/TagManager.svelte`
- Admin page to CRUD tags (name + color picker)
- Table/grid of existing tags with edit/delete
- [x] Create `src/lib/components/app/TagBadge.svelte`
- Small colored badge showing tag name
- Used in app cards (large card size) and app edit forms
- [x] Create `src/lib/components/board/TagFilter.svelte`
- Filter bar within board view
- Toggle buttons for each tag (active/inactive)
- When active, only show apps with selected tags
- "Clear filters" button
- [x] Add tag assignment to app edit form (multi-select from existing tags)
- [x] Add tag management page to admin panel navigation
### 6.6 Multi-URL App Cards
- [x] Update `src/lib/components/widget/AppWidget.svelte`
- If app has secondary links, show expand indicator
- On hover/click expand to reveal sub-links list
- Each sub-link: icon + label, click opens in new tab
- Primary URL is the main card click target
- Smooth expand/collapse animation (slide transition)
- [x] Create `src/lib/components/app/AppLinksEditor.svelte`
- Used in app edit form
- Add/remove/reorder secondary links
- Each link: label input + URL input + optional icon picker
- Drag-and-drop reorder
### 6.7 API Token Management
- [x] Create `src/routes/settings/api-tokens/+page.svelte`
- [x] Create `src/routes/settings/api-tokens/+page.server.ts`
- [x] Create `src/lib/components/settings/ApiTokenList.svelte`
- Table of user's API tokens: name, scope, created, last used, expires
- Revoke button per token
- [x] Create `src/lib/components/settings/ApiTokenCreateForm.svelte`
- Form: name, scope (read/write/admin dropdown), expiry (optional date picker)
- On submit: show generated token ONCE (copyable, warning: won't be shown again)
- [x] Add "API Tokens" link to user settings navigation
### 6.8 Audit Log Viewer
- [x] Create `src/routes/admin/audit-log/+page.svelte`
- [x] Create `src/routes/admin/audit-log/+page.server.ts`
- [x] Create `src/lib/components/admin/AuditLogTable.svelte`
- Paginated table: timestamp, user, action, entity, details
- Filters: action type dropdown, entity type dropdown, user select, date range
- Details column: expandable JSON view for action details
- Export to CSV button
- [x] Add "Audit Log" link to admin panel navigation
## Files to Modify/Create
- `src/lib/components/layout/FavoritesBar.svelte` — new
- `src/lib/stores/favorites.svelte.ts` — new
- `src/lib/components/board/RecentAppsSection.svelte` — new
- `src/routes/status/+page.svelte` — new
- `src/routes/status/+page.server.ts` — new
- `src/lib/components/notifications/NotificationBell.svelte` — new
- `src/lib/components/notifications/NotificationHistory.svelte` — new
- `src/lib/components/notifications/NotificationChannelForm.svelte` — new
- `src/routes/settings/notifications/+page.svelte` — new
- `src/lib/stores/notifications.svelte.ts` — new
- `src/lib/components/admin/TagManager.svelte` — new
- `src/lib/components/app/TagBadge.svelte` — new
- `src/lib/components/board/TagFilter.svelte` — new
- `src/lib/components/widget/AppWidget.svelte` — modify
- `src/lib/components/app/AppLinksEditor.svelte` — new
- `src/routes/settings/api-tokens/+page.svelte` — new
- `src/routes/settings/api-tokens/+page.server.ts` — new
- `src/lib/components/settings/ApiTokenList.svelte` — new
- `src/lib/components/settings/ApiTokenCreateForm.svelte` — new
- `src/routes/admin/audit-log/+page.svelte` — new
- `src/routes/admin/audit-log/+page.server.ts` — new
- `src/lib/components/admin/AuditLogTable.svelte` — new
- Various existing layout/navigation components — modify
## Acceptance Criteria
- Favorites bar persists across board navigation, syncs with backend
- Recent apps section shows only when user has click history and tracking enabled
- Uptime dashboard is guest-accessible and shows meaningful uptime data
- Notification bell shows unread count, dropdown works correctly
- Tags are assignable to apps and filterable in board view
- Multi-URL app cards expand/collapse smoothly
- API token is shown only once on creation, copyable
- Audit log shows paginated, filterable history for admin
- All UIs are responsive and work in dark/light mode
## Notes
- Follow existing component patterns (Svelte 5 runes, Tailwind, Bits UI primitives)
- Favorites bar uses svelte-dnd-action like existing widget reordering
- Notification polling: check every 60s for new notifications (simple setInterval)
- Status page is a new top-level route, not nested under boards
- API token display: show once in a modal with copy button, then redirect to token list
## 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
- **6.1 Favorites Bar**: Created `FavoritesBar.svelte` with drag-and-drop reordering (svelte-dnd-action), compact icon+name display, remove button, and right-click remove. Created `favorites.svelte.ts` store with load/add/remove/reorder methods and optimistic updates. Integrated favorites loading in root `+layout.svelte`. Added context menu to AppWidget with "Add to favorites" / "Remove from favorites" toggle.
- **6.2 Recent Apps**: Created `RecentAppsSection.svelte` showing last 10 clicked apps with time-ago formatting, collapsible section, and clear history button. Respects `trackRecentApps` preference. Updated AppWidget to record clicks via `POST /api/recent-apps` on every app link click.
- **6.3 Uptime Dashboard**: Created `/status` route with `+page.server.ts` (loads uptime data, guest-accessible) and `+page.svelte` with summary cards (total/online/uptime%), time range selector (24h/7d/30d), per-app status rows with sparklines, and incidents section. Added "Status" link to sidebar navigation.
- **6.4 Notifications UI**: Created `NotificationBell.svelte` (bell icon in header with unread badge, dropdown with notification list, mark all as read). Created `NotificationHistory.svelte` (paginated table with event type filter). Created `NotificationChannelForm.svelte` (dynamic form for Discord/Slack/Telegram/HTTP with send test button). Created `/settings/notifications` page with channels tab and history tab. Created `notifications.svelte.ts` store with 60s polling. Added bell to Header for authenticated users.
- **6.5 Tag Management & Filtering**: Created `TagManager.svelte` (admin CRUD with color picker, inline edit, delete confirmation). Created `TagBadge.svelte` (colored badge with optional remove button). Created `TagFilter.svelte` (toggle buttons for each tag, clear filters). Added tags display to AppWidget large card size. Added `/admin/tags` page and nav link.
- **6.6 Multi-URL App Cards**: Updated `AppWidget.svelte` to show expandable sub-links with slide transition for all card sizes (compact/medium/large). Links section shows expand/collapse chevron with count. Created `AppLinksEditor.svelte` with drag-and-drop reorder, add/remove links, and save to API.
- **6.7 API Token Management**: Created `/settings/api-tokens` route with `+page.server.ts` (list tokens, create with form action, revoke with form action). Created `ApiTokenList.svelte` (table with scope badges, expiry status, revoke with confirmation). Created `ApiTokenCreateForm.svelte` (name, scope dropdown, optional expiry). Token shown once after creation with copy button and warning. Added API Tokens link to user menu and settings page.
- **6.8 Audit Log Viewer**: Created `/admin/audit-log` route with `+page.server.ts` (paginated, filtered query). Created `AuditLogTable.svelte` (filterable table with action/entity/date filters, expandable JSON details, CSV export, pagination). Added "Audit Log" link to admin navigation.
### What the next phase needs to know
- FavoritesBar is a standalone component but not yet integrated into the board view page -- the root layout loads favorites, and the component can be placed in Board.svelte or the board page.
- RecentAppsSection is a standalone component that needs to be placed in the board view page (e.g., above the sections in Board.svelte).
- The NotificationBell is now in the Header and polls every 60 seconds when authenticated.
- TagFilter component takes `activeTags` and `onFilterChange` props but the filtering logic (hiding apps without selected tags) needs to be wired into the Board or Section component.
- AppWidget now depends on `favorites` store (imported at module level) -- this is safe since the store is a singleton.
- The `trackRecentApps` user preference is available via the User model but is not yet exposed in a settings toggle UI -- it defaults to `true`.
- API token page uses SvelteKit form actions (`?/create` and `?/revoke`) with `use:enhance`.
- The admin layout now has 5 nav items: Users, Groups, Tags, Audit Log, Settings.
- Status page is guest-accessible (no auth required in the server loader).
### Potential concerns
- The favorites store is loaded eagerly in `+layout.svelte` for all authenticated users. If the user has no favorites, this is a wasted API call (returns empty array). Consider lazy loading.
- The context menu for AppWidget favorites uses `position: fixed` with client coordinates, which may not position correctly when the page is scrolled. A more robust solution would use a popover library.
- AppWidget now wraps medium/large cards in a `<div>` instead of a single `<a>` tag (to support the expandable links section below the link). This changes the click behavior slightly -- the primary URL is still the main `<a>`, but the outer container is not a link anymore.
- NotificationBell polling could accumulate if multiple instances are mounted (unlikely with current layout, but worth noting).
- The AuditLogTable CSV export only exports the currently loaded page of results, not all results.