205 lines
6.7 KiB
Plaintext
205 lines
6.7 KiB
Plaintext
generator client {
|
|
provider = "prisma-client-js"
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
url = env("DATABASE_URL")
|
|
}
|
|
|
|
// ─── Users ──────────────────────────────────────────────────────────
|
|
|
|
model User {
|
|
id String @id @default(cuid())
|
|
did String @unique // EncryptID DID
|
|
username String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
notebooks NotebookCollaborator[]
|
|
notes Note[]
|
|
files File[]
|
|
sharedByMe SharedAccess[] @relation("SharedBy")
|
|
}
|
|
|
|
// ─── Notebooks ──────────────────────────────────────────────────────
|
|
|
|
model Notebook {
|
|
id String @id @default(cuid())
|
|
title String
|
|
slug String @unique
|
|
description String? @db.Text
|
|
coverColor String @default("#f59e0b")
|
|
canvasSlug String?
|
|
canvasShapeId String?
|
|
isPublic Boolean @default(false)
|
|
sortOrder Int @default(0)
|
|
workspaceSlug String @default("") // subdomain scope: "" = personal/unscoped
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
collaborators NotebookCollaborator[]
|
|
notes Note[]
|
|
sharedAccess SharedAccess[]
|
|
|
|
@@index([slug])
|
|
@@index([workspaceSlug])
|
|
}
|
|
|
|
enum CollaboratorRole {
|
|
OWNER
|
|
EDITOR
|
|
VIEWER
|
|
}
|
|
|
|
model NotebookCollaborator {
|
|
id String @id @default(cuid())
|
|
userId String
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
notebookId String
|
|
notebook Notebook @relation(fields: [notebookId], references: [id], onDelete: Cascade)
|
|
role CollaboratorRole @default(VIEWER)
|
|
joinedAt DateTime @default(now())
|
|
|
|
@@unique([userId, notebookId])
|
|
@@index([notebookId])
|
|
}
|
|
|
|
// ─── Notes ──────────────────────────────────────────────────────────
|
|
|
|
model Note {
|
|
id String @id @default(cuid())
|
|
notebookId String?
|
|
notebook Notebook? @relation(fields: [notebookId], references: [id], onDelete: SetNull)
|
|
authorId String?
|
|
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
|
|
title String
|
|
content String @db.Text
|
|
contentPlain String? @db.Text
|
|
type NoteType @default(NOTE)
|
|
url String?
|
|
archiveUrl String?
|
|
language String?
|
|
mimeType String?
|
|
fileUrl String?
|
|
fileSize Int?
|
|
duration Int?
|
|
isPinned Boolean @default(false)
|
|
canvasShapeId String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
// ─── Memory Card fields ─────────────────────────────────────────
|
|
parentId String?
|
|
parent Note? @relation("NoteTree", fields: [parentId], references: [id], onDelete: SetNull)
|
|
children Note[] @relation("NoteTree")
|
|
bodyJson Json? // TipTap JSON (canonical format)
|
|
bodyMarkdown String? @db.Text // portable markdown for search + Logseq
|
|
bodyFormat String @default("html") // "html" | "markdown" | "blocks"
|
|
cardType String @default("note") // note|link|file|task|person|idea|reference
|
|
summary String? // auto or manual
|
|
visibility String @default("private") // private|space|public
|
|
position Float? // fractional ordering
|
|
properties Json @default("{}") // Logseq-compatible key-value
|
|
archivedAt DateTime? // soft-delete
|
|
|
|
tags NoteTag[]
|
|
attachments CardAttachment[]
|
|
|
|
@@index([notebookId])
|
|
@@index([authorId])
|
|
@@index([type])
|
|
@@index([isPinned])
|
|
@@index([parentId])
|
|
@@index([cardType])
|
|
@@index([archivedAt])
|
|
@@index([position])
|
|
}
|
|
|
|
enum NoteType {
|
|
NOTE
|
|
CLIP
|
|
BOOKMARK
|
|
CODE
|
|
IMAGE
|
|
FILE
|
|
AUDIO
|
|
}
|
|
|
|
// ─── Files & Attachments ────────────────────────────────────────────
|
|
|
|
model File {
|
|
id String @id @default(cuid())
|
|
storageKey String @unique // unique filename on disk
|
|
filename String // original filename
|
|
mimeType String
|
|
sizeBytes Int
|
|
checksum String?
|
|
authorId String?
|
|
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
|
|
createdAt DateTime @default(now())
|
|
|
|
attachments CardAttachment[]
|
|
}
|
|
|
|
model CardAttachment {
|
|
id String @id @default(cuid())
|
|
noteId String
|
|
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
|
fileId String
|
|
file File @relation(fields: [fileId], references: [id], onDelete: Cascade)
|
|
role String @default("supporting") // "primary"|"preview"|"supporting"
|
|
caption String?
|
|
position Float @default(0)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([noteId, fileId])
|
|
@@index([noteId])
|
|
@@index([fileId])
|
|
}
|
|
|
|
// ─── Tags ───────────────────────────────────────────────────────────
|
|
|
|
model Tag {
|
|
id String @id @default(cuid())
|
|
name String
|
|
color String? @default("#6b7280")
|
|
spaceId String @default("") // "" = global, otherwise space-scoped
|
|
schema Json?
|
|
createdAt DateTime @default(now())
|
|
|
|
notes NoteTag[]
|
|
|
|
@@unique([spaceId, name])
|
|
@@index([spaceId])
|
|
}
|
|
|
|
model NoteTag {
|
|
id String @id @default(cuid())
|
|
noteId String
|
|
note Note @relation(fields: [noteId], references: [id], onDelete: Cascade)
|
|
tagId String
|
|
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([noteId, tagId])
|
|
@@index([tagId])
|
|
@@index([noteId])
|
|
}
|
|
|
|
// ─── Shared Access ──────────────────────────────────────────────────
|
|
|
|
model SharedAccess {
|
|
id String @id @default(cuid())
|
|
notebookId String
|
|
notebook Notebook @relation(fields: [notebookId], references: [id], onDelete: Cascade)
|
|
sharedById String
|
|
sharedBy User @relation("SharedBy", fields: [sharedById], references: [id], onDelete: Cascade)
|
|
targetDid String
|
|
role CollaboratorRole @default(VIEWER)
|
|
createdAt DateTime @default(now())
|
|
|
|
@@unique([notebookId, targetDid])
|
|
@@index([targetDid])
|
|
}
|