Files
OpenFrame/prisma/schema.prisma
T
Yusuf İpek 264392c2ec chore(init): scaffold OpenFrame — Next.js + Bun + shadcn
Initialize OpenFrame project with core scaffold and UI foundation.

- Project scaffold: Next.js 16.1 (App Router) + Bun runtime
- UI: shadcn/ui + TailwindCSS; landing, dashboard, project, and auth UIs
- Video support: provider abstraction (YouTube first), video player page with timestamped comments and custom timeline
- Auth & DB: NextAuth skeleton and Prisma schema (Postgres) included
- UX: dark-mode toggle, full-width layouts, comments sidebar, video route moved to /watch/[videoId]
- Dev: added YouTube iframe integration, custom controls, and TypeScript types
- Next steps: DB migrations, API routes (CRUD), real data wiring, voice-recording & sharing
2026-02-05 22:11:20 +03:00

268 lines
6.8 KiB
Plaintext

// Prisma Schema for OpenFrame - Video Feedback Platform
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
}
// ============================================
// AUTH MODELS (NextAuth.js compatible)
// ============================================
model User {
id String @id @default(cuid())
name String?
email String? @unique
emailVerified DateTime?
image String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
accounts Account[]
sessions Session[]
projects Project[]
comments Comment[]
memberships ProjectMember[]
@@map("users")
}
model Account {
id String @id @default(cuid())
userId String
type String
provider String
providerAccountId String
refresh_token String? @db.Text
access_token String? @db.Text
expires_at Int?
token_type String?
scope String?
id_token String? @db.Text
session_state String?
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([provider, providerAccountId])
@@map("accounts")
}
model Session {
id String @id @default(cuid())
sessionToken String @unique
userId String
expires DateTime
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@map("sessions")
}
model VerificationToken {
identifier String
token String @unique
expires DateTime
@@unique([identifier, token])
@@map("verification_tokens")
}
// ============================================
// APPLICATION MODELS
// ============================================
model Project {
id String @id @default(cuid())
name String
description String? @db.Text
slug String @unique // URL-friendly identifier
// Visibility
visibility ProjectVisibility @default(PRIVATE)
// Ownership
ownerId String
owner User @relation(fields: [ownerId], references: [id], onDelete: Cascade)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
videos Video[]
members ProjectMember[]
shareLinks ShareLink[]
@@index([ownerId])
@@index([slug])
@@map("projects")
}
enum ProjectVisibility {
PRIVATE // Only owner and members can access
LINK_ONLY // Anyone with link can view
PUBLIC // Listed publicly
}
model ProjectMember {
id String @id @default(cuid())
role ProjectMemberRole @default(VIEWER)
projectId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
userId String
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@unique([projectId, userId])
@@index([userId])
@@map("project_members")
}
enum ProjectMemberRole {
VIEWER // Can view and comment
EDITOR // Can add/edit videos
ADMIN // Can manage members and settings
}
model Video {
id String @id @default(cuid())
title String
description String? @db.Text
// Ordering within project
position Int @default(0)
// Project relation
projectId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// Relations
versions VideoVersion[]
@@index([projectId])
@@map("videos")
}
model VideoVersion {
id String @id @default(cuid())
versionNumber Int // 1, 2, 3...
versionLabel String? // Optional label like "Final Cut", "Review Draft"
// Video source (future-proof for multiple providers)
providerId String // 'youtube', 'vimeo', 'direct'
videoId String // Provider-specific video ID
originalUrl String // Original URL submitted by user
// Cached metadata
title String?
thumbnailUrl String?
duration Int? // Duration in seconds
// Status
isActive Boolean @default(true) // Currently displayed version
// Parent video
videoParentId String
video Video @relation(fields: [videoParentId], references: [id], onDelete: Cascade)
// Timestamps
createdAt DateTime @default(now())
// Relations
comments Comment[]
@@unique([videoParentId, versionNumber])
@@index([videoParentId])
@@map("video_versions")
}
model Comment {
id String @id @default(cuid())
// Comment content
content String? @db.Text // Text content (null if voice-only)
// Timestamp in video (in seconds, with decimal for precision)
timestamp Float // e.g., 65.5 = 1:05.5
timestampEnd Float? // Optional end timestamp for range comments
// Voice recording (optional)
voiceUrl String? // URL to voice recording file
voiceDuration Float? // Duration of voice recording in seconds
// Threading
parentId String?
parent Comment? @relation("CommentReplies", fields: [parentId], references: [id], onDelete: Cascade)
replies Comment[] @relation("CommentReplies")
// Status
isResolved Boolean @default(false)
resolvedAt DateTime?
// Author (optional for guest comments)
authorId String?
author User? @relation(fields: [authorId], references: [id], onDelete: SetNull)
// Guest author info (when authorId is null)
guestName String?
guestEmail String?
// Video version relation
versionId String
version VideoVersion @relation(fields: [versionId], references: [id], onDelete: Cascade)
// Timestamps
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([versionId])
@@index([parentId])
@@index([authorId])
@@index([timestamp])
@@map("comments")
}
model ShareLink {
id String @id @default(cuid())
token String @unique // Random token for URL
// What is being shared
projectId String
project Project @relation(fields: [projectId], references: [id], onDelete: Cascade)
// Permissions
permission SharePermission @default(VIEW)
// Optional restrictions
expiresAt DateTime? // Link expiration
maxUses Int? // Maximum number of uses
useCount Int @default(0)
password String? // Optional password protection
// Settings
allowGuests Boolean @default(true) // Allow comments without account
// Timestamps
createdAt DateTime @default(now())
@@index([projectId])
@@index([token])
@@map("share_links")
}
enum SharePermission {
VIEW // Can only view
COMMENT // Can view and comment
}