datasource db { provider = "postgresql" url = env("DATABASE_URL") } generator client { provider = "prisma-client-js" } generator json { provider = "prisma-json-types-generator" } generator zod { provider = "zod-prisma" modelSuffix = "ModelSchema" imports = "./zod/schemas" } model User { id String @id @unique @default(cuid()) @db.VarChar(30) username String @unique @db.VarChar(255) password String @db.VarChar(60) role String @db.VarChar(50) createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) deletedAt DateTime? @db.Timestamptz(6) currentWorkspaceId String @db.VarChar(30) currentWorkspace Workspace @relation(fields: [currentWorkspaceId], references: [id]) workspaces WorkspacesOnUsers[] } model Workspace { id String @id @unique @default(cuid()) @db.VarChar(30) name String @db.VarChar(100) dashboardOrder String[] /// [DashboardLayout] dashboardLayout Json? @db.Json createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) users WorkspacesOnUsers[] websites Website[] notifications Notification[] monitors Monitor[] monitorStatusPages MonitorStatusPage[] // for user currentWorkspace selectedUsers User[] workspaceDailyUsage WorkspaceDailyUsage[] } model WorkspacesOnUsers { userId String @db.VarChar(30) workspaceId String @db.VarChar(30) role String @db.VarChar(100) createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) user User @relation(fields: [userId], references: [id], onUpdate: Cascade, onDelete: Cascade) workspace Workspace @relation(fields: [workspaceId], references: [id], onUpdate: Cascade, onDelete: Cascade) @@id([userId, workspaceId]) @@index([userId]) @@index([workspaceId]) } model Website { id String @id @unique @default(cuid()) @db.VarChar(30) workspaceId String @db.VarChar(30) name String @db.VarChar(100) domain String? @db.VarChar(500) shareId String? @unique @db.VarChar(50) resetAt DateTime? @db.Timestamptz(6) monitorId String? @db.VarChar(30) createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) deletedAt DateTime? @db.Timestamptz(6) workspace Workspace @relation(fields: [workspaceId], references: [id], onUpdate: Cascade, onDelete: Cascade) monitor Monitor? @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade) sessions WebsiteSession[] eventData WebsiteEventData[] sessionData WebsiteSessionData[] @@index([workspaceId]) @@index([createdAt]) @@index([shareId]) } model WebsiteSession { id String @id @unique @db.Uuid websiteId String @db.VarChar(30) hostname String? @db.VarChar(100) browser String? @db.VarChar(20) os String? @db.VarChar(20) device String? @db.VarChar(20) screen String? @db.VarChar(11) language String? @db.VarChar(35) ip String? @db.VarChar(45) // The max length of ipv6 which adapter with ipv4 is 45(for example: [::ffff:192.168.100.228] => 0000:0000:0000:0000:0000:ffff:192.168.100.228) country String? @db.Char(2) subdivision1 String? @db.VarChar(20) subdivision2 String? @db.VarChar(50) city String? @db.VarChar(50) createdAt DateTime @default(now()) @db.Timestamptz(6) website Website @relation(fields: [websiteId], references: [id], onUpdate: Cascade, onDelete: Cascade) websiteEvent WebsiteEvent[] sessionData WebsiteSessionData[] @@index([createdAt]) @@index([websiteId]) @@index([websiteId, createdAt]) @@index([websiteId, createdAt, hostname]) @@index([websiteId, createdAt, browser]) @@index([websiteId, createdAt, os]) @@index([websiteId, createdAt, device]) @@index([websiteId, createdAt, screen]) @@index([websiteId, createdAt, language]) @@index([websiteId, createdAt, country]) @@index([websiteId, createdAt, subdivision1]) @@index([websiteId, createdAt, city]) } model WebsiteEvent { id String @id() @default(cuid()) @db.VarChar(30) websiteId String @db.VarChar(30) sessionId String @db.Uuid urlPath String @db.VarChar(500) urlQuery String? @db.VarChar(500) referrerPath String? @db.VarChar(500) referrerQuery String? @db.VarChar(500) referrerDomain String? @db.VarChar(500) pageTitle String? @db.VarChar(500) eventType Int @default(1) @db.Integer // 1 is view, 2 is click event eventName String? @db.VarChar(50) createdAt DateTime @default(now()) @db.Timestamptz(6) eventData WebsiteEventData[] session WebsiteSession @relation(fields: [sessionId], references: [id], onUpdate: Cascade, onDelete: Cascade) @@index([createdAt]) @@index([sessionId]) @@index([websiteId]) @@index([websiteId, createdAt]) @@index([websiteId, createdAt, urlPath]) @@index([websiteId, createdAt, urlQuery]) @@index([websiteId, createdAt, referrerDomain]) @@index([websiteId, createdAt, pageTitle]) @@index([websiteId, createdAt, eventName]) @@index([websiteId, sessionId, createdAt]) } model WebsiteEventData { id String @id() @default(cuid()) @db.VarChar(30) websiteId String @db.VarChar(30) websiteEventId String @db.VarChar(30) eventKey String @db.VarChar(500) stringValue String? @db.VarChar(500) numberValue Decimal? @db.Decimal(19, 4) dateValue DateTime? @db.Timestamptz(6) dataType Int @db.Integer createdAt DateTime @default(now()) @db.Timestamptz(6) website Website @relation(fields: [websiteId], references: [id], onUpdate: Cascade, onDelete: Cascade) websiteEvent WebsiteEvent @relation(fields: [websiteEventId], references: [id], onUpdate: Cascade, onDelete: Cascade) @@index([createdAt]) @@index([websiteId]) @@index([websiteEventId]) @@index([websiteId, createdAt]) @@index([websiteId, createdAt, eventKey]) } model WebsiteSessionData { id String @id() @default(cuid()) @db.VarChar(30) websiteId String @db.VarChar(30) sessionId String @db.Uuid stringValue String? @db.VarChar(500) numberValue Decimal? @db.Decimal(19, 4) dateValue DateTime? @db.Timestamptz(6) dataType Int @db.Integer createdAt DateTime @default(now()) @db.Timestamptz(6) website Website @relation(fields: [websiteId], references: [id], onUpdate: Cascade, onDelete: Cascade) session WebsiteSession @relation(fields: [sessionId], references: [id], onUpdate: Cascade, onDelete: Cascade) @@index([createdAt]) @@index([websiteId]) @@index([sessionId]) } model TelemetrySession { id String @id @unique @db.Uuid workspaceId String @db.VarChar(30) hostname String? @db.VarChar(100) browser String? @db.VarChar(20) os String? @db.VarChar(20) ip String? @db.VarChar(45) country String? @db.Char(2) subdivision1 String? @db.VarChar(20) subdivision2 String? @db.VarChar(50) city String? @db.VarChar(50) createdAt DateTime @default(now()) @db.Timestamptz(6) telemetryEvent TelemetryEvent[] @@index([createdAt]) @@index([workspaceId, createdAt]) } model TelemetryEvent { id String @id() @default(cuid()) @db.VarChar(30) sessionId String @db.Uuid workspaceId String @db.VarChar(30) eventName String? @db.VarChar(100) urlOrigin String @db.VarChar(500) urlPath String @db.VarChar(500) /// [CommonPayload] payload Json? @db.Json // Other payload info get from query params, should be a object createdAt DateTime @default(now()) @db.Timestamptz(6) session TelemetrySession @relation(fields: [sessionId], references: [id], onUpdate: Cascade, onDelete: Cascade) @@index([createdAt]) @@index([sessionId]) @@index([workspaceId]) @@index([workspaceId, createdAt]) } model Notification { id String @id() @default(cuid()) @db.VarChar(30) workspaceId String @db.VarChar(30) name String @db.VarChar(100) type String @db.VarChar(100) /// [CommonPayload] payload Json @db.Json createdAt DateTime @default(now()) @db.Timestamptz(6) workspace Workspace @relation(fields: [workspaceId], references: [id], onUpdate: Cascade, onDelete: Cascade) monitors Monitor[] @@index([workspaceId]) } model Monitor { id String @id() @default(cuid()) @db.VarChar(30) workspaceId String @db.VarChar(30) name String @db.VarChar(100) type String @db.VarChar(100) active Boolean @default(true) @db.Boolean interval Int @default(20) @db.Integer // TODO // maxRetry Int @default(0) @db.Integer // retryInterval Int @default(0) @db.Integer /// [CommonPayload] payload Json @db.Json createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @default(now()) @updatedAt @db.Timestamptz(6) workspace Workspace @relation(fields: [workspaceId], references: [id]) websites Website[] notifications Notification[] events MonitorEvent[] datas MonitorData[] status MonitorStatus[] @@index([workspaceId]) } model MonitorEvent { id String @id @default(cuid()) @db.VarChar(30) message String @db.VarChar(500) monitorId String @db.VarChar(30) type String @db.VarChar(100) // UP or DOWN createdAt DateTime @default(now()) @db.Timestamptz(6) monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade) } model MonitorData { id String @id @default(cuid()) @db.VarChar(30) monitorId String @db.VarChar(30) value Int @default(0) @db.Integer // -1 means error createdAt DateTime @default(now()) @db.Timestamptz(6) monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade) } // Use for record latest monitor status, for example tls status model MonitorStatus { monitorId String @db.VarChar(30) statusName String @db.VarChar(50) /// [CommonPayload] payload Json @db.Json createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) monitor Monitor @relation(fields: [monitorId], references: [id], onUpdate: Cascade, onDelete: Cascade) @@id([monitorId, statusName]) } model MonitorStatusPage { id String @id @default(cuid()) @db.VarChar(30) workspaceId String @db.VarChar(30) slug String @unique // url slug title String @db.VarChar(100) description String @default("") @db.VarChar(1000) /// [MonitorStatusPageList] /// @zod.custom(imports.MonitorStatusPageListSchema) monitorList Json @default("[]") // monitor list createdAt DateTime @default(now()) @db.Timestamptz(6) updatedAt DateTime @updatedAt @db.Timestamptz(6) workspace Workspace @relation(fields: [workspaceId], references: [id]) @@index([slug]) } model WorkspaceDailyUsage { id String @id @unique @default(cuid()) @db.VarChar(30) workspaceId String @db.VarChar(30) date DateTime @db.Date // calc every day websiteAcceptedCount Int // website accept any request count websiteEventCount Int // website accept event request count monitorExecutionCount Int // monitor exec number count createdAt DateTime @default(now()) @db.Timestamptz(6) workspace Workspace @relation(fields: [workspaceId], references: [id], onUpdate: Cascade, onDelete: Cascade) @@unique([workspaceId, date]) }