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.
This commit is contained in:
+176
-6
@@ -17,6 +17,8 @@ model User {
|
||||
role String @default("user") // admin | user
|
||||
refreshToken String?
|
||||
refreshTokenExpiresAt DateTime?
|
||||
onboardingComplete Boolean @default(false)
|
||||
trackRecentApps Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -26,9 +28,16 @@ model User {
|
||||
backgroundType String?
|
||||
locale String?
|
||||
|
||||
groups UserGroup[]
|
||||
createdApps App[]
|
||||
boards Board[]
|
||||
groups UserGroup[]
|
||||
createdApps App[]
|
||||
boards Board[]
|
||||
favorites UserFavorite[]
|
||||
clicks AppClick[]
|
||||
notificationChannels NotificationChannel[]
|
||||
notifications Notification[]
|
||||
apiTokens ApiToken[]
|
||||
auditLogs AuditLog[]
|
||||
boardTemplates BoardTemplate[]
|
||||
|
||||
@@index([email])
|
||||
}
|
||||
@@ -75,9 +84,14 @@ model App {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
|
||||
statuses AppStatus[]
|
||||
widgets Widget[]
|
||||
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
|
||||
statuses AppStatus[]
|
||||
widgets Widget[]
|
||||
appTags AppTag[]
|
||||
links AppLink[]
|
||||
clicks AppClick[]
|
||||
notifications Notification[]
|
||||
favorites UserFavorite[]
|
||||
|
||||
@@index([name])
|
||||
@@index([category])
|
||||
@@ -105,6 +119,14 @@ model Board {
|
||||
isDefault Boolean @default(false)
|
||||
isGuestAccessible Boolean @default(false)
|
||||
backgroundConfig String? // JSON stored as string for SQLite
|
||||
themeHue Int?
|
||||
themeSaturation Int?
|
||||
backgroundType String?
|
||||
cardSize String?
|
||||
wallpaperUrl String?
|
||||
wallpaperBlur Int?
|
||||
wallpaperOverlay Float?
|
||||
customCss String?
|
||||
createdById String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
@@ -122,6 +144,7 @@ model Section {
|
||||
icon String?
|
||||
order Int @default(0)
|
||||
isExpandedByDefault Boolean @default(true)
|
||||
cardSize String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@ -173,6 +196,153 @@ model SystemSettings {
|
||||
defaultTheme String @default("dark")
|
||||
defaultPrimaryColor String @default("#6366f1")
|
||||
healthcheckDefaults String @default("{}") // JSON stored as string for SQLite
|
||||
customCss String?
|
||||
onboardingComplete Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
}
|
||||
|
||||
// --- New models for Phases 4-7 ---
|
||||
|
||||
model Tag {
|
||||
id String @id @default(cuid())
|
||||
name String @unique
|
||||
color String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
appTags AppTag[]
|
||||
|
||||
@@index([name])
|
||||
}
|
||||
|
||||
model AppTag {
|
||||
id String @id @default(cuid())
|
||||
appId String
|
||||
tagId String
|
||||
|
||||
app App @relation(fields: [appId], references: [id], onDelete: Cascade)
|
||||
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([appId, tagId])
|
||||
@@index([appId])
|
||||
@@index([tagId])
|
||||
}
|
||||
|
||||
model AppLink {
|
||||
id String @id @default(cuid())
|
||||
appId String
|
||||
label String
|
||||
url String
|
||||
icon String?
|
||||
order Int @default(0)
|
||||
|
||||
app App @relation(fields: [appId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([appId])
|
||||
}
|
||||
|
||||
model UserFavorite {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
appId String
|
||||
order Int @default(0)
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
app App @relation(fields: [appId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@unique([userId, appId])
|
||||
@@index([userId])
|
||||
@@index([appId])
|
||||
}
|
||||
|
||||
model AppClick {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
appId String
|
||||
clickedAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
app App @relation(fields: [appId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
@@index([appId])
|
||||
@@index([clickedAt])
|
||||
}
|
||||
|
||||
model NotificationChannel {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
type String // discord | slack | telegram | http
|
||||
config String @default("{}") // JSON stored as string for SQLite
|
||||
enabled Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
}
|
||||
|
||||
model Notification {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
appId String?
|
||||
event String // app_online | app_offline | app_degraded
|
||||
message String
|
||||
sentAt DateTime @default(now())
|
||||
readAt DateTime?
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
app App? @relation(fields: [appId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([userId])
|
||||
@@index([appId])
|
||||
@@index([sentAt])
|
||||
}
|
||||
|
||||
model ApiToken {
|
||||
id String @id @default(cuid())
|
||||
userId String
|
||||
name String
|
||||
tokenHash String @unique
|
||||
scope String // read | write | admin
|
||||
lastUsedAt DateTime?
|
||||
expiresAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
@@index([userId])
|
||||
@@index([tokenHash])
|
||||
}
|
||||
|
||||
model AuditLog {
|
||||
id String @id @default(cuid())
|
||||
userId String?
|
||||
action String // user_created | user_deleted | etc.
|
||||
entityType String
|
||||
entityId String
|
||||
details String @default("{}") // JSON stored as string for SQLite
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([userId])
|
||||
@@index([action])
|
||||
@@index([entityType, entityId])
|
||||
@@index([createdAt])
|
||||
}
|
||||
|
||||
model BoardTemplate {
|
||||
id String @id @default(cuid())
|
||||
name String
|
||||
description String?
|
||||
icon String?
|
||||
config String @default("{}") // JSON stored as string for SQLite
|
||||
isBuiltin Boolean @default(false)
|
||||
createdById String?
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
|
||||
|
||||
@@index([createdById])
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user