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.
11 KiB
11 KiB
Phase 5: Functional Features — Backend
Status: ✅ Complete Parent plan: PLAN.md Domain: backend
Objective
Implement all backend services, API routes, and background jobs for the 8 functional features: favorites, recent apps, uptime dashboard, notifications, tags, multi-URL apps, API tokens, and audit log.
Tasks
5.1 Favorites Service & API
- Create
src/lib/server/services/favoriteService.tsgetUserFavorites(userId)— ordered list of user's favorite appsaddFavorite(userId, appId)— add app to favorites (append to end)removeFavorite(userId, appId)— remove from favoritesreorderFavorites(userId, favoriteIds[])— update order
- Create
src/routes/api/favorites/+server.ts— GET (list), POST (add), DELETE (remove) - Create
src/routes/api/favorites/reorder/+server.ts— PATCH (reorder)
5.2 Recent Apps Service & API
- Create
src/lib/server/services/recentAppsService.tsrecordClick(userId, appId)— add click recordgetRecentApps(userId, limit=10)— get most recent unique appsclearHistory(userId)— clear all click history for user
- Create
src/routes/api/recent-apps/+server.ts— GET (list), POST (record click), DELETE (clear)
5.3 Uptime Dashboard Service & API
- Create
src/lib/server/services/uptimeService.tsgetUptimeStats(appId, timeRange: '24h'|'7d'|'30d')— uptime percentage, avg response timegetUptimeTimeline(appId, timeRange)— status history with timestampsgetAllAppsUptime(timeRange)— aggregated uptime for all appsgetIncidents(appId?, timeRange)— list of down periods with duration- Queries AppStatus table, groups by time windows
- Create
src/routes/api/uptime/+server.ts— GET all apps uptime summary - Create
src/routes/api/uptime/[appId]/+server.ts— GET single app uptime + timeline
5.4 Notifications Service & API
- Create
src/lib/server/services/notificationService.ts- Channel management: create, update, delete, list channels for user
sendNotification(userId, appId, event, message)— create notification record + dispatch to channels- Dispatchers:
sendDiscord(webhookUrl, message),sendSlack(webhookUrl, message),sendTelegram(botToken, chatId, message),sendHttp(url, payload) getNotifications(userId, { unreadOnly?, limit?, offset? })— paginated notification listmarkAsRead(notificationId),markAllAsRead(userId)
- Create
src/routes/api/notifications/+server.ts— GET (list), PATCH (mark read) - Create
src/routes/api/notifications/channels/+server.ts— CRUD for notification channels - Create
src/routes/api/notifications/channels/[id]/+server.ts— single channel operations - Create
src/routes/api/notifications/channels/[id]/test/+server.ts— POST to send test notification - Integrate with healthcheck scheduler: trigger notifications when app status changes (online->offline, offline->online)
- Update
src/lib/server/jobs/healthcheckScheduler.tsto call notificationService on status change
- Update
5.5 Tags Service & API
- Create
src/lib/server/services/tagService.ts- CRUD for tags: create, update (name, color), delete, findAll
addTagToApp(appId, tagId),removeTagFromApp(appId, tagId)getAppsByTag(tagId)— apps with a specific taggetTagsForApp(appId)— tags for a specific app
- Create
src/routes/api/tags/+server.ts— GET (list), POST (create) - Create
src/routes/api/tags/[id]/+server.ts— PATCH (update), DELETE (delete) - Create
src/routes/api/apps/[id]/tags/+server.ts— GET (app's tags), POST (add tag), DELETE (remove tag)
5.6 Multi-URL Apps Service & API
- Extend
src/lib/server/services/appService.tsaddAppLink(appId, { label, url, icon, order })— add secondary URLupdateAppLink(linkId, { label?, url?, icon?, order? })— update linkremoveAppLink(linkId)— delete linkreorderAppLinks(appId, linkIds[])— update order- Include links in app queries (eager load)
- Create
src/routes/api/apps/[id]/links/+server.ts— CRUD for app links - Update existing app GET endpoints to include links in response
5.7 API Tokens Service & API
- Create
src/lib/server/services/apiTokenService.tsgenerateToken(userId, name, scope, expiresAt?)— generate random token, store hashrevokeToken(tokenId, userId)— delete tokenlistTokens(userId)— list tokens (without hash, with last used)validateToken(tokenString)— hash and compare, check expiry, update lastUsedAt
- Create
src/routes/api/tokens/+server.ts— GET (list), POST (generate) - Create
src/routes/api/tokens/[id]/+server.ts— DELETE (revoke) - Update auth middleware to also check for Bearer token in Authorization header
src/lib/server/middleware/authenticate.ts— add API token validation path
5.8 Audit Log Service & API
- Create
src/lib/server/services/auditLogService.tslogAction(userId, action, entityType, entityId, details?)— record audit eventgetAuditLogs({ action?, entityType?, userId?, startDate?, endDate?, limit?, offset? })— filtered, paginated querypruneOldLogs(retentionDays)— delete logs older than retention period
- Create
src/routes/api/admin/audit-log/+server.ts— GET (list, admin only) - Add audit log calls to existing admin operations:
- User CRUD, Board CRUD, App CRUD, Settings changes, Import/Export
- Update relevant services/routes to call
auditLogService.logAction()
- Add pruning cron job to healthcheck scheduler (or create separate job):
- Run daily, prune based on SystemSettings retention config (default 90 days)
Files to Modify/Create
src/lib/server/services/favoriteService.ts— newsrc/lib/server/services/recentAppsService.ts— newsrc/lib/server/services/uptimeService.ts— newsrc/lib/server/services/notificationService.ts— newsrc/lib/server/services/tagService.ts— newsrc/lib/server/services/apiTokenService.ts— newsrc/lib/server/services/auditLogService.ts— newsrc/lib/server/services/appService.ts— modify (multi-URL links)src/lib/server/middleware/authenticate.ts— modify (API token auth)src/lib/server/jobs/healthcheckScheduler.ts— modify (notification triggers)src/routes/api/favorites/+server.ts— newsrc/routes/api/favorites/reorder/+server.ts— newsrc/routes/api/recent-apps/+server.ts— newsrc/routes/api/uptime/+server.ts— newsrc/routes/api/uptime/[appId]/+server.ts— newsrc/routes/api/notifications/+server.ts— newsrc/routes/api/notifications/channels/+server.ts— newsrc/routes/api/notifications/channels/[id]/+server.ts— newsrc/routes/api/notifications/channels/[id]/test/+server.ts— newsrc/routes/api/tags/+server.ts— newsrc/routes/api/tags/[id]/+server.ts— newsrc/routes/api/apps/[id]/tags/+server.ts— newsrc/routes/api/apps/[id]/links/+server.ts— newsrc/routes/api/tokens/+server.ts— newsrc/routes/api/tokens/[id]/+server.ts— newsrc/routes/api/admin/audit-log/+server.ts— new- Various existing route files — modify (add audit logging)
Acceptance Criteria
- All services handle errors gracefully
- API token auth works alongside existing JWT auth (check both)
- Notification dispatchers handle webhook failures without crashing
- Audit logging doesn't slow down the operations it logs (fire-and-forget pattern)
- Uptime calculations handle edge cases (no data, all unknown, timezone issues)
- All new endpoints require appropriate auth (user-level or admin-level)
- Favorites and recent apps are per-user, properly isolated
Notes
- For notification dispatchers, use simple
fetch()calls — no need for a queue system at this scale - API token generation: use
crypto.randomBytes(32).toString('hex')for the token, store bcrypt hash - Audit logging should be non-blocking: catch and log errors but don't fail the parent operation
- Uptime calculation: group AppStatus records by time windows, calculate online/(online+offline) percentage
- Tag colors: store as hex string (e.g., '#ef4444')
Review Checklist
- All tasks completed
- 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
- Created 7 new backend services: favoriteService, recentAppsService, uptimeService, notificationService, tagService, apiTokenService, auditLogService
- Extended appService with multi-URL link management (addAppLink, updateAppLink, removeAppLink, reorderAppLinks, getAppLinks) and eager-loaded links in findAll/findById
- Created 16 new API route files across favorites, recent-apps, uptime, notifications (+ channels + test), tags, app tags, app links, tokens, admin audit-log
- Updated authenticate.ts middleware with extractBearerToken helper
- Updated hooks.server.ts to validate API tokens from Authorization header as fallback when no JWT session exists
- Updated healthcheckScheduler.ts to track status transitions and broadcast notifications on status changes (online/offline/degraded), plus added daily audit log pruning cron job
- Added audit logging calls to 8 existing route files: users CRUD, apps CRUD, boards CRUD, admin settings, admin import, admin export
What the next phase needs to know
- All new API endpoints require authentication via JWT cookie or Bearer API token
- Favorites and recent apps are per-user, isolated by userId
- Notification dispatchers are fire-and-forget — they catch errors and never throw
- Audit logging is non-blocking (void return, catches errors internally)
- API token validation iterates all tokens to bcrypt-compare; at scale this could be slow (consider indexing on a prefix for optimization)
- The
broadcastNotification()function sends to all users with enabled channels — used by healthcheck scheduler - Uptime stats return null for uptimePercentage/avgResponseTime when no data exists
- Tags use the AppTag junction table (not the legacy comma-separated App.tags field)
- App links are eager-loaded in appService.findAll() and findById() queries
- Audit log pruning runs daily at midnight with 90-day default retention
Potential concerns
- API token validation scans all tokens in the database for bcrypt comparison. For large numbers of tokens, consider a two-step lookup (store a non-secret prefix for indexing, then bcrypt the full token).
- The healthcheck scheduler tracks previous statuses in memory (Map). On server restart, the first check after restart will not detect transitions since the map is empty.
- Notification channel configs are stored as JSON strings — the dispatcher trusts the shape after JSON.parse. Invalid configs are silently skipped.