c6a7de895d
- JSON import/export with conflict resolution (skip/overwrite) + admin UI - Ping history sparklines on AppWidget and AppCard (24h, 288 points) - Hourly cleanup job for old AppStatus records - User theme preferences (hue, saturation, mode, background, locale) - Settings page with ThemeCustomizer (sliders, toggles, live preview) - Prisma migration for user preference fields - i18n translations for all new strings (EN/RU)
179 lines
5.3 KiB
Plaintext
179 lines
5.3 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "sqlite"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
email String @unique
|
|
password String?
|
|
displayName String
|
|
avatarUrl String?
|
|
authProvider String @default("local") // local | oauth
|
|
role String @default("user") // admin | user
|
|
refreshToken String?
|
|
refreshTokenExpiresAt DateTime?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
themeMode String?
|
|
primaryHue Int?
|
|
primarySaturation Int?
|
|
backgroundType String?
|
|
locale String?
|
|
|
|
groups UserGroup[]
|
|
createdApps App[]
|
|
boards Board[]
|
|
|
|
@@index([email])
|
|
}
|
|
|
|
model Group {
|
|
id String @id @default(cuid())
|
|
name String @unique
|
|
description String?
|
|
isDefault Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
users UserGroup[]
|
|
}
|
|
|
|
model UserGroup {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
groupId String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, groupId])
|
|
@@index([userId])
|
|
@@index([groupId])
|
|
}
|
|
|
|
model App {
|
|
id String @id @default(cuid())
|
|
name String
|
|
url String
|
|
icon String?
|
|
iconType String @default("lucide") // lucide | simple | url | emoji
|
|
description String?
|
|
category String?
|
|
tags String @default("") // comma-separated
|
|
healthcheckEnabled Boolean @default(false)
|
|
healthcheckInterval Int @default(300) // seconds
|
|
healthcheckMethod String @default("GET")
|
|
healthcheckExpectedStatus Int @default(200)
|
|
healthcheckTimeout Int @default(5000) // milliseconds
|
|
createdById String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
|
|
statuses AppStatus[]
|
|
widgets Widget[]
|
|
|
|
@@index([name])
|
|
@@index([category])
|
|
@@index([createdById])
|
|
}
|
|
|
|
model AppStatus {
|
|
id String @id @default(cuid())
|
|
appId String
|
|
status String @default("unknown") // online | offline | degraded | unknown
|
|
responseTime Int? // milliseconds
|
|
checkedAt DateTime @default(now())
|
|
|
|
app App @relation(fields: [appId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([appId])
|
|
@@index([checkedAt])
|
|
}
|
|
|
|
model Board {
|
|
id String @id @default(cuid())
|
|
name String
|
|
icon String?
|
|
description String?
|
|
isDefault Boolean @default(false)
|
|
isGuestAccessible Boolean @default(false)
|
|
backgroundConfig String? // JSON stored as string for SQLite
|
|
createdById String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
createdBy User? @relation(fields: [createdById], references: [id], onDelete: SetNull)
|
|
sections Section[]
|
|
|
|
@@index([createdById])
|
|
}
|
|
|
|
model Section {
|
|
id String @id @default(cuid())
|
|
boardId String
|
|
title String
|
|
icon String?
|
|
order Int @default(0)
|
|
isExpandedByDefault Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
board Board @relation(fields: [boardId], references: [id], onDelete: Cascade)
|
|
widgets Widget[]
|
|
|
|
@@index([boardId])
|
|
}
|
|
|
|
model Widget {
|
|
id String @id @default(cuid())
|
|
sectionId String
|
|
type String // app | bookmark | note | embed | status
|
|
order Int @default(0)
|
|
config String @default("{}") // JSON stored as string for SQLite
|
|
appId String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
section Section @relation(fields: [sectionId], references: [id], onDelete: Cascade)
|
|
app App? @relation(fields: [appId], references: [id], onDelete: SetNull)
|
|
|
|
@@index([sectionId])
|
|
@@index([appId])
|
|
}
|
|
|
|
model Permission {
|
|
id String @id @default(cuid())
|
|
entityType String // board | app
|
|
entityId String
|
|
targetType String // user | group
|
|
targetId String
|
|
level String // view | edit | admin
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([entityType, entityId, targetType, targetId])
|
|
@@index([entityType, entityId])
|
|
@@index([targetType, targetId])
|
|
}
|
|
|
|
model SystemSettings {
|
|
id String @id @default("singleton")
|
|
authMode String @default("local") // local | oauth | both
|
|
registrationEnabled Boolean @default(true)
|
|
oauthClientId String?
|
|
oauthClientSecret String?
|
|
oauthDiscoveryUrl String?
|
|
defaultTheme String @default("dark")
|
|
defaultPrimaryColor String @default("#6366f1")
|
|
healthcheckDefaults String @default("{}") // JSON stored as string for SQLite
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
}
|