# 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 `
` instead of a single `` tag (to support the expandable links section below the link). This changes the click behavior slightly -- the primary URL is still the main ``, 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.