generator client { provider = "prisma-client" output = "../src/generated/prisma" } datasource db { provider = "postgresql" } model User { id String @id name String email String emailVerified Boolean @default(false) image String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt sessions Session[] accounts Account[] assigneeIssues Issue[] @relation(name: "assigneeIssues") reporterIssues Issue[] @relation(name: "reporterIssues") projects Project[] projectMemberships ProjectMember[] notificationDeviceTokens NotificationDeviceToken[] notificationPreferences NotificationPreference[] notificationMessages NotificationMessage[] @@unique([email]) @@map("user") } model Session { id String @id expiresAt DateTime token String createdAt DateTime @default(now()) updatedAt DateTime @updatedAt ipAddress String? userAgent String? userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([token]) @@index([userId]) @@map("session") } model Account { id String @id accountId String providerId String userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) accessToken String? refreshToken String? idToken String? accessTokenExpiresAt DateTime? refreshTokenExpiresAt DateTime? scope String? password String? createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@unique([providerId, accountId]) @@index([userId]) @@map("account") } model Verification { id String @id identifier String value String expiresAt DateTime createdAt DateTime @default(now()) updatedAt DateTime @updatedAt @@index([identifier]) @@map("verification") } model Issue { id Int @id @default(autoincrement()) key String title String content String? status String priority Int @default(0) assigneeId String? assignee User? @relation(name: "assigneeIssues", fields: [assigneeId], references: [id], onDelete: Cascade) reporterId String reporter User @relation(name: "reporterIssues", fields: [reporterId], references: [id], onDelete: Cascade) projectId String project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) dueDate DateTime? @db.Timestamptz(3) createdAt DateTime @default(now()) @db.Timestamptz(3) updatedAt DateTime @updatedAt @db.Timestamptz(3) @@index([status]) @@index([assigneeId]) @@index([reporterId]) @@index([projectId]) @@index([createdAt]) @@index([projectId, createdAt]) @@index([dueDate]) @@map("issue") } model Project { id String @id @default(uuid(7)) name String key String createdAt DateTime @default(now()) @db.Timestamptz(3) updatedAt DateTime @updatedAt @db.Timestamptz(3) issues Issue[] ownerId String owner User @relation(fields: [ownerId], references: [id], onDelete: Restrict) members ProjectMember[] @@unique([key]) @@index([createdAt]) @@index([ownerId]) @@map("project") } model ProjectMember { id String @id @default(uuid(7)) projectId String userId String createdAt DateTime @default(now()) @db.Timestamptz(3) project Project @relation(fields: [projectId], references: [id], onDelete: Cascade) user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([projectId, userId]) @@index([userId]) @@map("project_member") } /// Push-токены устройств пользователя. Регистрируются напрямую клиентом, /// без участия остального приложения. model NotificationDeviceToken { id String @id @default(uuid(7)) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) token String platform String // ios | android | web createdAt DateTime @default(now()) @db.Timestamptz(3) updatedAt DateTime @updatedAt @db.Timestamptz(3) @@unique([userId, token]) @@index([userId]) @@map("notification_device_token") } /// Включён ли у пользователя конкретный канал доставки уведомлений. /// Категорий нет — настройка одна на канал. /// Допустимые значения channel валидируются в коде (NotificationChannel VO), /// а не типом БД — расширение списка каналов не требует миграции. model NotificationPreference { id String @id @default(uuid(7)) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) channel String enabled Boolean @default(true) updatedAt DateTime @updatedAt @db.Timestamptz(3) @@unique([userId, channel]) @@map("notification_preference") } /// Лог/история отправленных уведомлений — одна запись на попытку доставки /// по одному каналу. channel/status — строки, валидируются в коде /// (NotificationChannel/NotificationStatus VO), см. комментарий выше. model NotificationMessage { id String @id @default(uuid(7)) userId String user User @relation(fields: [userId], references: [id], onDelete: Cascade) channel String status String @default("PENDING") subject String? content String error String? sentAt DateTime? @db.Timestamptz(3) createdAt DateTime @default(now()) @db.Timestamptz(3) @@index([userId]) @@index([status]) @@index([createdAt]) @@map("notification_message") }