happy-server/prisma/schema.prisma
2025-09-20 14:42:28 -07:00

344 lines
9.3 KiB
Plaintext

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
previewFeatures = ["metrics", "relationJoins"]
}
generator json {
provider = "prisma-json-types-generator"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
//
// Account
//
model Account {
id String @id @default(cuid())
publicKey String @unique
seq Int @default(0)
feedSeq BigInt @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
settings String?
settingsVersion Int @default(0)
githubUserId String? @unique
githubUser GithubUser? @relation(fields: [githubUserId], references: [id])
// Profile
firstName String?
lastName String?
username String? @unique
/// [ImageRef]
avatar Json?
Session Session[]
AccountPushToken AccountPushToken[]
TerminalAuthRequest TerminalAuthRequest[]
AccountAuthRequest AccountAuthRequest[]
UsageReport UsageReport[]
Machine Machine[]
UploadedFile UploadedFile[]
ServiceAccountToken ServiceAccountToken[]
RelationshipsFrom UserRelationship[] @relation("RelationshipsFrom")
RelationshipsTo UserRelationship[] @relation("RelationshipsTo")
Artifact Artifact[]
AccessKey AccessKey[]
UserFeedItem UserFeedItem[]
}
model TerminalAuthRequest {
id String @id @default(cuid())
publicKey String @unique
supportsV2 Boolean @default(false)
response String?
responseAccountId String?
responseAccount Account? @relation(fields: [responseAccountId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model AccountAuthRequest {
id String @id @default(cuid())
publicKey String @unique
response String?
responseAccountId String?
responseAccount Account? @relation(fields: [responseAccountId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model AccountPushToken {
id String @id @default(cuid())
accountId String
account Account @relation(fields: [accountId], references: [id])
token String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([accountId, token])
}
//
// Sessions
//
model Session {
id String @id @default(cuid())
tag String
accountId String
account Account @relation(fields: [accountId], references: [id])
metadata String
metadataVersion Int @default(0)
agentState String?
agentStateVersion Int @default(0)
dataEncryptionKey Bytes?
seq Int @default(0)
active Boolean @default(true)
lastActiveAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
messages SessionMessage[]
usageReports UsageReport[]
accessKeys AccessKey[]
@@unique([accountId, tag])
@@index([accountId, updatedAt(sort: Desc)])
}
model SessionMessage {
id String @id @default(cuid())
sessionId String
session Session @relation(fields: [sessionId], references: [id])
localId String?
seq Int
/// [SessionMessageContent]
content Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([sessionId, localId])
@@index([sessionId, seq])
}
//
// Github
//
model GithubUser {
id String @id
/// [GitHubProfile]
profile Json
token Bytes?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
Account Account[]
}
model GithubOrganization {
id String @id
/// [GitHubOrg]
profile Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
//
// Utility
//
model GlobalLock {
key String @id @default(cuid())
value String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
expiresAt DateTime
}
model RepeatKey {
key String @id
value String
createdAt DateTime @default(now())
expiresAt DateTime
}
model SimpleCache {
key String @id
value String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
//
// Usage Reporting
//
model UsageReport {
id String @id @default(cuid())
key String
accountId String
account Account @relation(fields: [accountId], references: [id])
sessionId String?
session Session? @relation(fields: [sessionId], references: [id])
/// [UsageReportData]
data Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([accountId, sessionId, key])
@@index([accountId])
@@index([sessionId])
}
//
// Machines
//
model Machine {
id String @id
accountId String
account Account @relation(fields: [accountId], references: [id])
metadata String // Encrypted - contains static machine info
metadataVersion Int @default(0)
daemonState String? // Encrypted - contains dynamic daemon state
daemonStateVersion Int @default(0)
dataEncryptionKey Bytes?
seq Int @default(0)
active Boolean @default(true)
lastActiveAt DateTime @default(now())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
accessKeys AccessKey[]
@@unique([accountId, id])
@@index([accountId])
}
model UploadedFile {
id String @id @default(cuid())
accountId String
account Account @relation(fields: [accountId], references: [id])
path String
width Int?
height Int?
thumbhash String?
reuseKey String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([accountId, path])
@@index([accountId])
}
model ServiceAccountToken {
id String @id @default(cuid())
accountId String
account Account @relation(fields: [accountId], references: [id], onDelete: Cascade)
vendor String
token Bytes // Encrypted token
metadata Json? // Optional vendor metadata
lastUsedAt DateTime?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([accountId, vendor])
@@index([accountId])
}
//
// Artifacts
//
model Artifact {
id String @id // UUID provided by client
accountId String
account Account @relation(fields: [accountId], references: [id])
header Bytes // Encrypted header (can contain JSON)
headerVersion Int @default(0)
body Bytes // Encrypted body
bodyVersion Int @default(0)
dataEncryptionKey Bytes // Encryption key for this artifact
seq Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([accountId])
@@index([accountId, updatedAt(sort: Desc)])
}
//
// Access Keys
//
model AccessKey {
id String @id @default(cuid())
accountId String
account Account @relation(fields: [accountId], references: [id])
machineId String
machine Machine @relation(fields: [accountId, machineId], references: [accountId, id])
sessionId String
session Session @relation(fields: [sessionId], references: [id])
data String // Encrypted data
dataVersion Int @default(0)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([accountId, machineId, sessionId])
@@index([accountId])
@@index([sessionId])
@@index([machineId])
}
//
// Social Network - Relationships
//
enum RelationshipStatus {
none
requested
pending
friend
rejected
}
model UserRelationship {
fromUserId String
fromUser Account @relation("RelationshipsFrom", fields: [fromUserId], references: [id], onDelete: Cascade)
toUserId String
toUser Account @relation("RelationshipsTo", fields: [toUserId], references: [id], onDelete: Cascade)
status RelationshipStatus @default(pending)
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
acceptedAt DateTime?
@@id([fromUserId, toUserId])
@@index([toUserId, status])
@@index([fromUserId, status])
}
//
// Feed
//
model UserFeedItem {
id String @id @default(cuid())
userId String
user Account @relation(fields: [userId], references: [id], onDelete: Cascade)
counter BigInt
repeatKey String?
/// [FeedBody]
body Json
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@unique([userId, counter])
@@unique([userId, repeatKey])
@@index([userId, counter(sort: Desc)])
}