// Mosaic Stack Database Schema // PostgreSQL 17 with pgvector extension generator client { provider = "prisma-client-js" previewFeatures = ["postgresqlExtensions"] } datasource db { provider = "postgresql" url = env("DATABASE_URL") extensions = [pgvector(map: "vector"), uuid_ossp(map: "uuid-ossp")] } // ============================================ // ENUMS // ============================================ enum TaskStatus { NOT_STARTED IN_PROGRESS PAUSED COMPLETED ARCHIVED } enum TaskPriority { LOW MEDIUM HIGH } enum ProjectStatus { PLANNING ACTIVE PAUSED COMPLETED ARCHIVED } enum WorkspaceMemberRole { OWNER ADMIN MEMBER GUEST } enum ActivityAction { CREATED UPDATED DELETED COMPLETED ASSIGNED COMMENTED } enum EntityType { TASK EVENT PROJECT WORKSPACE USER } // ============================================ // MODELS // ============================================ model User { id String @id @default(uuid()) @db.Uuid email String @unique name String emailVerified Boolean @default(false) @map("email_verified") image String? authProviderId String? @unique @map("auth_provider_id") preferences Json @default("{}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz // Relations ownedWorkspaces Workspace[] @relation("WorkspaceOwner") workspaceMemberships WorkspaceMember[] assignedTasks Task[] @relation("TaskAssignee") createdTasks Task[] @relation("TaskCreator") createdEvents Event[] @relation("EventCreator") createdProjects Project[] @relation("ProjectCreator") activityLogs ActivityLog[] sessions Session[] accounts Account[] @@map("users") } model Workspace { id String @id @default(uuid()) @db.Uuid name String ownerId String @map("owner_id") @db.Uuid settings Json @default("{}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz // Relations owner User @relation("WorkspaceOwner", fields: [ownerId], references: [id], onDelete: Cascade) members WorkspaceMember[] tasks Task[] events Event[] projects Project[] activityLogs ActivityLog[] memoryEmbeddings MemoryEmbedding[] @@index([ownerId]) @@map("workspaces") } model WorkspaceMember { workspaceId String @map("workspace_id") @db.Uuid userId String @map("user_id") @db.Uuid role WorkspaceMemberRole @default(MEMBER) joinedAt DateTime @default(now()) @map("joined_at") @db.Timestamptz // Relations workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@id([workspaceId, userId]) @@index([userId]) @@map("workspace_members") } model Task { id String @id @default(uuid()) @db.Uuid workspaceId String @map("workspace_id") @db.Uuid title String description String? @db.Text status TaskStatus @default(NOT_STARTED) priority TaskPriority @default(MEDIUM) dueDate DateTime? @map("due_date") @db.Timestamptz assigneeId String? @map("assignee_id") @db.Uuid creatorId String @map("creator_id") @db.Uuid projectId String? @map("project_id") @db.Uuid parentId String? @map("parent_id") @db.Uuid sortOrder Int @default(0) @map("sort_order") metadata Json @default("{}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz completedAt DateTime? @map("completed_at") @db.Timestamptz // Relations workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) assignee User? @relation("TaskAssignee", fields: [assigneeId], references: [id], onDelete: SetNull) creator User @relation("TaskCreator", fields: [creatorId], references: [id], onDelete: Cascade) project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) parent Task? @relation("TaskSubtasks", fields: [parentId], references: [id], onDelete: Cascade) subtasks Task[] @relation("TaskSubtasks") @@index([workspaceId]) @@index([workspaceId, status]) @@index([workspaceId, dueDate]) @@index([assigneeId]) @@index([projectId]) @@index([parentId]) @@map("tasks") } model Event { id String @id @default(uuid()) @db.Uuid workspaceId String @map("workspace_id") @db.Uuid title String description String? @db.Text startTime DateTime @map("start_time") @db.Timestamptz endTime DateTime? @map("end_time") @db.Timestamptz allDay Boolean @default(false) @map("all_day") location String? recurrence Json? creatorId String @map("creator_id") @db.Uuid projectId String? @map("project_id") @db.Uuid metadata Json @default("{}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz // Relations workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) creator User @relation("EventCreator", fields: [creatorId], references: [id], onDelete: Cascade) project Project? @relation(fields: [projectId], references: [id], onDelete: SetNull) @@index([workspaceId]) @@index([workspaceId, startTime]) @@index([creatorId]) @@index([projectId]) @@map("events") } model Project { id String @id @default(uuid()) @db.Uuid workspaceId String @map("workspace_id") @db.Uuid name String description String? @db.Text status ProjectStatus @default(PLANNING) startDate DateTime? @map("start_date") @db.Date endDate DateTime? @map("end_date") @db.Date creatorId String @map("creator_id") @db.Uuid color String? metadata Json @default("{}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz // Relations workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) creator User @relation("ProjectCreator", fields: [creatorId], references: [id], onDelete: Cascade) tasks Task[] events Event[] @@index([workspaceId]) @@index([workspaceId, status]) @@index([creatorId]) @@map("projects") } model ActivityLog { id String @id @default(uuid()) @db.Uuid workspaceId String @map("workspace_id") @db.Uuid userId String @map("user_id") @db.Uuid action ActivityAction entityType EntityType @map("entity_type") entityId String @map("entity_id") @db.Uuid details Json @default("{}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz // Relations workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([workspaceId]) @@index([workspaceId, createdAt]) @@index([entityType, entityId]) @@index([userId]) @@map("activity_logs") } model MemoryEmbedding { id String @id @default(uuid()) @db.Uuid workspaceId String @map("workspace_id") @db.Uuid content String @db.Text // Note: vector dimension (1536) must match EMBEDDING_DIMENSION constant in @mosaic/shared embedding Unsupported("vector(1536)")? entityType EntityType? @map("entity_type") entityId String? @map("entity_id") @db.Uuid metadata Json @default("{}") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz // Relations workspace Workspace @relation(fields: [workspaceId], references: [id], onDelete: Cascade) @@index([workspaceId]) @@map("memory_embeddings") } // ============================================ // AUTHENTICATION MODELS (BetterAuth) // ============================================ model Session { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid token String @unique expiresAt DateTime @map("expires_at") @db.Timestamptz ipAddress String? @map("ip_address") userAgent String? @map("user_agent") createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([token]) @@map("sessions") } model Account { id String @id @default(uuid()) @db.Uuid userId String @map("user_id") @db.Uuid accountId String @map("account_id") providerId String @map("provider_id") accessToken String? @map("access_token") refreshToken String? @map("refresh_token") idToken String? @map("id_token") accessTokenExpiresAt DateTime? @map("access_token_expires_at") @db.Timestamptz refreshTokenExpiresAt DateTime? @map("refresh_token_expires_at") @db.Timestamptz scope String? password String? createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz // Relations user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([providerId, accountId]) @@index([userId]) @@map("accounts") } model Verification { id String @id @default(uuid()) @db.Uuid identifier String value String expiresAt DateTime @map("expires_at") @db.Timestamptz createdAt DateTime @default(now()) @map("created_at") @db.Timestamptz updatedAt DateTime @updatedAt @map("updated_at") @db.Timestamptz @@index([identifier]) @@map("verifications") }