english version update
This commit is contained in:
@@ -13,33 +13,35 @@ datasource db {
|
||||
// VPS/Server models removed - moving to S3 storage
|
||||
|
||||
model User {
|
||||
id Int @id @default(autoincrement())
|
||||
username String
|
||||
email String @unique
|
||||
password String
|
||||
createdAt DateTime @default(now())
|
||||
id Int @id @default(autoincrement())
|
||||
username String
|
||||
email String @unique
|
||||
password String
|
||||
createdAt DateTime @default(now())
|
||||
// plans Plan[] @relation("UserPlans")
|
||||
operator Int @default(0)
|
||||
isAdmin Boolean @default(false)
|
||||
tickets Ticket[] @relation("UserTickets")
|
||||
responses Response[] @relation("OperatorResponses")
|
||||
checks Check[] @relation("UserChecks")
|
||||
balance Float @default(0)
|
||||
notifications Notification[]
|
||||
operator Int @default(0)
|
||||
isAdmin Boolean @default(false)
|
||||
tickets Ticket[] @relation("UserTickets")
|
||||
responses Response[] @relation("OperatorResponses")
|
||||
checks Check[] @relation("UserChecks")
|
||||
balance Float @default(0)
|
||||
notifications Notification[]
|
||||
pushSubscriptions PushSubscription[]
|
||||
transactions Transaction[] // История всех транзакций
|
||||
posts Post[] @relation("PostAuthor") // Статьи блога
|
||||
comments Comment[] @relation("UserComments") // Комментарии
|
||||
buckets StorageBucket[] // S3 хранилища пользователя
|
||||
checkoutSessions StorageCheckoutSession[]
|
||||
|
||||
transactions Transaction[] // История всех транзакций
|
||||
posts Post[] @relation("PostAuthor") // Статьи блога
|
||||
comments Comment[] @relation("UserComments") // Комментарии
|
||||
buckets StorageBucket[] // S3 хранилища пользователя
|
||||
checkoutSessions StorageCheckoutSession[]
|
||||
// Список промокодов, использованных пользователем
|
||||
usedPromoCodes PromoCode[]
|
||||
|
||||
// Новые relations для расширенных настроек
|
||||
sessions Session[]
|
||||
loginHistory LoginHistory[]
|
||||
apiKeys APIKey[]
|
||||
notificationSettings NotificationSettings?
|
||||
profile UserProfile?
|
||||
qrLoginRequests QrLoginRequest[]
|
||||
sessions Session[]
|
||||
loginHistory LoginHistory[]
|
||||
apiKeys APIKey[]
|
||||
notificationSettings NotificationSettings?
|
||||
profile UserProfile?
|
||||
qrLoginRequests QrLoginRequest[]
|
||||
|
||||
@@map("user")
|
||||
}
|
||||
@@ -53,48 +55,47 @@ model Check {
|
||||
createdAt DateTime @default(now())
|
||||
user User @relation("UserChecks", fields: [userId], references: [id])
|
||||
|
||||
@@map("check")
|
||||
@@map("check")
|
||||
}
|
||||
|
||||
|
||||
model Service {
|
||||
id Int @id @default(autoincrement())
|
||||
name String @unique
|
||||
price Float
|
||||
id Int @id @default(autoincrement())
|
||||
name String @unique
|
||||
price Float
|
||||
// planId Int?
|
||||
// plan Plan? @relation("PlanServices", fields: [planId], references: [id])
|
||||
|
||||
@@map("service")
|
||||
@@map("service")
|
||||
}
|
||||
|
||||
model Ticket {
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
message String @db.Text
|
||||
userId Int
|
||||
status String @default("open") // open, in_progress, awaiting_reply, resolved, closed
|
||||
priority String @default("normal") // low, normal, high, urgent
|
||||
category String @default("general") // general, technical, billing, other
|
||||
assignedTo Int? // ID оператора, которому назначен тикет
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
closedAt DateTime?
|
||||
responses Response[] @relation("TicketResponses")
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
message String @db.Text
|
||||
userId Int
|
||||
status String @default("open") // open, in_progress, awaiting_reply, resolved, closed
|
||||
priority String @default("normal") // low, normal, high, urgent
|
||||
category String @default("general") // general, technical, billing, other
|
||||
assignedTo Int? // ID оператора, которому назначен тикет
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
closedAt DateTime?
|
||||
responses Response[] @relation("TicketResponses")
|
||||
attachments TicketAttachment[]
|
||||
user User? @relation("UserTickets", fields: [userId], references: [id])
|
||||
user User? @relation("UserTickets", fields: [userId], references: [id])
|
||||
|
||||
@@map("ticket")
|
||||
}
|
||||
|
||||
model Response {
|
||||
id Int @id @default(autoincrement())
|
||||
ticketId Int
|
||||
operatorId Int
|
||||
message String @db.Text
|
||||
isInternal Boolean @default(false) // Внутренний комментарий (виден только операторам)
|
||||
createdAt DateTime @default(now())
|
||||
ticket Ticket @relation("TicketResponses", fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
operator User @relation("OperatorResponses", fields: [operatorId], references: [id])
|
||||
id Int @id @default(autoincrement())
|
||||
ticketId Int
|
||||
operatorId Int
|
||||
message String @db.Text
|
||||
isInternal Boolean @default(false) // Внутренний комментарий (виден только операторам)
|
||||
createdAt DateTime @default(now())
|
||||
ticket Ticket @relation("TicketResponses", fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
operator User @relation("OperatorResponses", fields: [operatorId], references: [id])
|
||||
attachments ResponseAttachment[]
|
||||
|
||||
@@map("response")
|
||||
@@ -102,17 +103,17 @@ model Response {
|
||||
|
||||
// Прикреплённые файлы к тикетам
|
||||
model TicketAttachment {
|
||||
id Int @id @default(autoincrement())
|
||||
ticketId Int
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
|
||||
filename String
|
||||
fileUrl String
|
||||
fileSize Int // Размер в байтах
|
||||
mimeType String
|
||||
|
||||
id Int @id @default(autoincrement())
|
||||
ticketId Int
|
||||
ticket Ticket @relation(fields: [ticketId], references: [id], onDelete: Cascade)
|
||||
|
||||
filename String
|
||||
fileUrl String
|
||||
fileSize Int // Размер в байтах
|
||||
mimeType String
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
|
||||
@@map("ticket_attachment")
|
||||
}
|
||||
|
||||
@@ -121,32 +122,32 @@ model ResponseAttachment {
|
||||
id Int @id @default(autoincrement())
|
||||
responseId Int
|
||||
response Response @relation(fields: [responseId], references: [id], onDelete: Cascade)
|
||||
|
||||
filename String
|
||||
fileUrl String
|
||||
fileSize Int
|
||||
mimeType String
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
|
||||
filename String
|
||||
fileUrl String
|
||||
fileSize Int
|
||||
mimeType String
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
@@map("response_attachment")
|
||||
}
|
||||
|
||||
// QR-код авторизация (как в Telegram Web)
|
||||
model QrLoginRequest {
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique @db.VarChar(128) // Уникальный код QR
|
||||
userId Int? // После подтверждения - ID пользователя
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
status String @default("pending") // pending, confirmed, expired, rejected
|
||||
ipAddress String?
|
||||
userAgent String? @db.Text
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime // Через 60 секунд
|
||||
confirmedAt DateTime?
|
||||
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique @db.VarChar(128) // Уникальный код QR
|
||||
userId Int? // После подтверждения - ID пользователя
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
status String @default("pending") // pending, confirmed, expired, rejected
|
||||
ipAddress String?
|
||||
userAgent String? @db.Text
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime // Через 60 секунд
|
||||
confirmedAt DateTime?
|
||||
|
||||
@@index([code])
|
||||
@@index([status, expiresAt])
|
||||
@@map("qr_login_request")
|
||||
@@ -154,34 +155,34 @@ model QrLoginRequest {
|
||||
|
||||
// История всех транзакций (пополнения, списания, возвраты)
|
||||
model Transaction {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
amount Float
|
||||
type String // deposit (пополнение), withdrawal (списание), refund (возврат)
|
||||
description String
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
amount Float
|
||||
type String // deposit (пополнение), withdrawal (списание), refund (возврат)
|
||||
description String
|
||||
balanceBefore Float
|
||||
balanceAfter Float
|
||||
adminId Int? // ID админа, если операция выполнена админом
|
||||
createdAt DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
adminId Int? // ID админа, если операция выполнена админом
|
||||
createdAt DateTime @default(now())
|
||||
user User @relation(fields: [userId], references: [id])
|
||||
|
||||
@@map("transaction")
|
||||
}
|
||||
|
||||
// Блог
|
||||
model Post {
|
||||
id Int @id @default(autoincrement())
|
||||
id Int @id @default(autoincrement())
|
||||
title String
|
||||
content String @db.Text // Rich text content (HTML)
|
||||
excerpt String? @db.Text // Краткое описание для ленты
|
||||
coverImage String? // URL обложки
|
||||
url String @unique // Пользовательский URL (blog_name)
|
||||
status String @default("draft") // draft, published, archived
|
||||
content String @db.Text // Rich text content (HTML)
|
||||
excerpt String? @db.Text // Краткое описание для ленты
|
||||
coverImage String? // URL обложки
|
||||
url String @unique // Пользовательский URL (blog_name)
|
||||
status String @default("draft") // draft, published, archived
|
||||
authorId Int
|
||||
author User @relation("PostAuthor", fields: [authorId], references: [id])
|
||||
views Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
author User @relation("PostAuthor", fields: [authorId], references: [id])
|
||||
views Int @default(0)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
publishedAt DateTime?
|
||||
comments Comment[]
|
||||
|
||||
@@ -190,41 +191,41 @@ model Post {
|
||||
|
||||
// Комментарии к статьям блога
|
||||
model Comment {
|
||||
id Int @id @default(autoincrement())
|
||||
postId Int
|
||||
userId Int? // null если комментарий от гостя
|
||||
authorName String? // Имя автора (для гостей)
|
||||
content String @db.Text
|
||||
status String @default("pending") // pending, approved, rejected
|
||||
createdAt DateTime @default(now())
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
user User? @relation("UserComments", fields: [userId], references: [id])
|
||||
id Int @id @default(autoincrement())
|
||||
postId Int
|
||||
userId Int? // null если комментарий от гостя
|
||||
authorName String? // Имя автора (для гостей)
|
||||
content String @db.Text
|
||||
status String @default("pending") // pending, approved, rejected
|
||||
createdAt DateTime @default(now())
|
||||
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
|
||||
user User? @relation("UserComments", fields: [userId], references: [id])
|
||||
|
||||
@@map("comment")
|
||||
}
|
||||
|
||||
// Модель для уведомлений
|
||||
model Notification {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
type String // server_created, payment_charged, tariff_expiring, ticket_reply, payment_received, balance_low
|
||||
title String
|
||||
message String @db.Text
|
||||
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
type String // server_created, payment_charged, tariff_expiring, ticket_reply, payment_received, balance_low
|
||||
title String
|
||||
message String @db.Text
|
||||
|
||||
// Связанные сущности (опционально)
|
||||
ticketId Int?
|
||||
checkId Int?
|
||||
|
||||
ticketId Int?
|
||||
checkId Int?
|
||||
|
||||
// Метаданные
|
||||
actionUrl String? // URL для перехода при клике
|
||||
icon String? // Иконка (emoji или path)
|
||||
color String? // Цвет (green, blue, orange, red, purple)
|
||||
|
||||
actionUrl String? // URL для перехода при клике
|
||||
icon String? // Иконка (emoji или path)
|
||||
color String? // Цвет (green, blue, orange, red, purple)
|
||||
|
||||
isRead Boolean @default(false)
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
|
||||
@@index([userId, isRead])
|
||||
@@index([userId, createdAt])
|
||||
@@map("notification")
|
||||
@@ -232,19 +233,19 @@ model Notification {
|
||||
|
||||
// Модель для Push-подписок (Web Push API)
|
||||
model PushSubscription {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
endpoint String @db.VarChar(512)
|
||||
p256dh String @db.Text // Публичный ключ для шифрования
|
||||
auth String @db.Text // Токен аутентификации
|
||||
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
endpoint String @db.VarChar(512)
|
||||
p256dh String @db.Text // Публичный ключ для шифрования
|
||||
auth String @db.Text // Токен аутентификации
|
||||
|
||||
userAgent String? @db.Text // Браузер/устройство
|
||||
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
lastUsed DateTime @default(now())
|
||||
|
||||
|
||||
@@unique([userId, endpoint])
|
||||
@@index([userId])
|
||||
@@map("push_subscription")
|
||||
@@ -252,40 +253,40 @@ model PushSubscription {
|
||||
|
||||
// Активные сеансы пользователя
|
||||
model Session {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
token String @unique @db.VarChar(500) // JWT refresh token
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
token String @unique @db.VarChar(500) // JWT refresh token
|
||||
ipAddress String?
|
||||
userAgent String? @db.Text
|
||||
device String? // Desktop, Mobile, Tablet
|
||||
browser String? // Chrome, Firefox, Safari, etc.
|
||||
location String? // Город/страна по IP
|
||||
|
||||
userAgent String? @db.Text
|
||||
device String? // Desktop, Mobile, Tablet
|
||||
browser String? // Chrome, Firefox, Safari, etc.
|
||||
location String? // Город/страна по IP
|
||||
|
||||
lastActivity DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime
|
||||
|
||||
|
||||
@@index([userId])
|
||||
@@map("session")
|
||||
}
|
||||
|
||||
// История входов
|
||||
model LoginHistory {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
ipAddress String
|
||||
userAgent String? @db.Text
|
||||
userAgent String? @db.Text
|
||||
device String?
|
||||
browser String?
|
||||
location String?
|
||||
|
||||
|
||||
success Boolean @default(true) // true = успешный вход, false = неудачная попытка
|
||||
createdAt DateTime @default(now())
|
||||
|
||||
|
||||
@@index([userId])
|
||||
@@index([createdAt])
|
||||
@@map("login_history")
|
||||
@@ -293,20 +294,20 @@ model LoginHistory {
|
||||
|
||||
// API ключи для разработчиков
|
||||
model APIKey {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
name String // Название (например, "Production API")
|
||||
key String @unique @db.VarChar(64) // Сам API ключ
|
||||
prefix String @db.VarChar(16) // Префикс для отображения (ospab_xxxx)
|
||||
|
||||
permissions String? @db.Text // JSON массив разрешений ["servers:read", "servers:create", etc.]
|
||||
|
||||
lastUsed DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime?
|
||||
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
name String // Название (например, "Production API")
|
||||
key String @unique @db.VarChar(64) // Сам API ключ
|
||||
prefix String @db.VarChar(16) // Префикс для отображения (ospab_xxxx)
|
||||
|
||||
permissions String? @db.Text // JSON массив разрешений ["servers:read", "servers:create", etc.]
|
||||
|
||||
lastUsed DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime?
|
||||
|
||||
@@index([userId])
|
||||
@@index([key])
|
||||
@@map("api_key")
|
||||
@@ -317,95 +318,95 @@ model NotificationSettings {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @unique
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
|
||||
// Email уведомления
|
||||
emailBalanceLow Boolean @default(true)
|
||||
emailPaymentCharged Boolean @default(true)
|
||||
emailTicketReply Boolean @default(true)
|
||||
emailNewsletter Boolean @default(false)
|
||||
|
||||
emailBalanceLow Boolean @default(true)
|
||||
emailPaymentCharged Boolean @default(true)
|
||||
emailTicketReply Boolean @default(true)
|
||||
emailNewsletter Boolean @default(false)
|
||||
|
||||
// Push уведомления
|
||||
pushBalanceLow Boolean @default(true)
|
||||
pushPaymentCharged Boolean @default(true)
|
||||
pushTicketReply Boolean @default(true)
|
||||
|
||||
pushBalanceLow Boolean @default(true)
|
||||
pushPaymentCharged Boolean @default(true)
|
||||
pushTicketReply Boolean @default(true)
|
||||
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
|
||||
@@map("notification_settings")
|
||||
}
|
||||
|
||||
// Настройки профиля
|
||||
model UserProfile {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @unique
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
avatarUrl String? // Путь к аватару
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int @unique
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
avatarUrl String? // Путь к аватару
|
||||
phoneNumber String?
|
||||
timezone String? @default("Europe/Moscow")
|
||||
language String? @default("ru")
|
||||
|
||||
timezone String? @default("Europe/Moscow")
|
||||
language String? @default("ru")
|
||||
|
||||
// Настройки приватности
|
||||
profilePublic Boolean @default(false)
|
||||
showEmail Boolean @default(false)
|
||||
|
||||
|
||||
// 2FA
|
||||
twoFactorEnabled Boolean @default(false)
|
||||
twoFactorSecret String? @db.Text
|
||||
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
@@map("user_profile")
|
||||
}
|
||||
|
||||
// S3 Bucket модель
|
||||
model StorageBucket {
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
id Int @id @default(autoincrement())
|
||||
userId Int
|
||||
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
||||
|
||||
name String // Уникальное имя бакета в рамках пользователя
|
||||
plan String // Код тарифа из StoragePlan
|
||||
quotaGb Int // Лимит включённого объёма в GB
|
||||
usedBytes BigInt @default(0) // Текущий объём хранения в байтах
|
||||
objectCount Int @default(0)
|
||||
storageClass String @default("standard") // standard, infrequent, archive
|
||||
region String @default("ru-central-1")
|
||||
public Boolean @default(false)
|
||||
versioning Boolean @default(false)
|
||||
status String @default("active") // active, grace, suspended
|
||||
monthlyPrice Float
|
||||
nextBillingDate DateTime?
|
||||
lastBilledAt DateTime?
|
||||
autoRenew Boolean @default(true)
|
||||
usageSyncedAt DateTime?
|
||||
storagePlan StoragePlan? @relation(fields: [plan], references: [code])
|
||||
regionConfig StorageRegion @relation("BucketRegion", fields: [region], references: [code])
|
||||
storageClassConfig StorageClass @relation("BucketClass", fields: [storageClass], references: [code])
|
||||
consoleCredential StorageConsoleCredential?
|
||||
name String // Уникальное имя бакета в рамках пользователя
|
||||
plan String // Код тарифа из StoragePlan
|
||||
quotaGb Int // Лимит включённого объёма в GB
|
||||
usedBytes BigInt @default(0) // Текущий объём хранения в байтах
|
||||
objectCount Int @default(0)
|
||||
storageClass String @default("standard") // standard, infrequent, archive
|
||||
region String @default("ru-central-1")
|
||||
public Boolean @default(false)
|
||||
versioning Boolean @default(false)
|
||||
status String @default("active") // active, grace, suspended
|
||||
monthlyPrice Float
|
||||
nextBillingDate DateTime?
|
||||
lastBilledAt DateTime?
|
||||
autoRenew Boolean @default(true)
|
||||
usageSyncedAt DateTime?
|
||||
storagePlan StoragePlan? @relation(fields: [plan], references: [code])
|
||||
regionConfig StorageRegion @relation("BucketRegion", fields: [region], references: [code])
|
||||
storageClassConfig StorageClass @relation("BucketClass", fields: [storageClass], references: [code])
|
||||
consoleCredential StorageConsoleCredential?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
accessKeys StorageAccessKey[]
|
||||
accessKeys StorageAccessKey[]
|
||||
|
||||
@@unique([userId, name]) // Имя уникально в рамках пользователя
|
||||
@@index([userId])
|
||||
@@index([region])
|
||||
@@index([storageClass])
|
||||
@@unique([userId, name]) // Имя уникально в рамках пользователя
|
||||
@@map("storage_bucket")
|
||||
}
|
||||
|
||||
model StorageAccessKey {
|
||||
id Int @id @default(autoincrement())
|
||||
bucketId Int
|
||||
bucket StorageBucket @relation(fields: [bucketId], references: [id], onDelete: Cascade)
|
||||
id Int @id @default(autoincrement())
|
||||
bucketId Int
|
||||
bucket StorageBucket @relation(fields: [bucketId], references: [id], onDelete: Cascade)
|
||||
|
||||
accessKey String @unique
|
||||
secretKey String // хранится в зашифрованном виде
|
||||
accessKey String @unique
|
||||
secretKey String // хранится в зашифрованном виде
|
||||
label String?
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
lastUsedAt DateTime?
|
||||
|
||||
@@index([bucketId])
|
||||
@@ -413,36 +414,36 @@ model StorageAccessKey {
|
||||
}
|
||||
|
||||
model StorageConsoleCredential {
|
||||
id Int @id @default(autoincrement())
|
||||
bucketId Int @unique
|
||||
bucket StorageBucket @relation(fields: [bucketId], references: [id], onDelete: Cascade)
|
||||
id Int @id @default(autoincrement())
|
||||
bucketId Int @unique
|
||||
bucket StorageBucket @relation(fields: [bucketId], references: [id], onDelete: Cascade)
|
||||
|
||||
login String
|
||||
passwordHash String
|
||||
login String
|
||||
passwordHash String
|
||||
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
lastGeneratedAt DateTime? // Для rate limiting (1 раз в неделю)
|
||||
|
||||
@@map("storage_console_credential")
|
||||
}
|
||||
|
||||
model StoragePlan {
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique
|
||||
name String
|
||||
price Float
|
||||
pricePerGb Decimal? @db.Decimal(10, 4) // Цена за 1 GB для кастомного тарифа
|
||||
bandwidthPerGb Decimal? @db.Decimal(10, 4) // GB трафика на 1 GB хранения
|
||||
requestsPerGb Int? // Количество операций на 1 GB хранения
|
||||
quotaGb Int // Базовая квота для обычных тарифов (0 для custom)
|
||||
bandwidthGb Int // Базовый трафик для обычных тарифов (0 для custom)
|
||||
requestLimit String // Текстовое описание лимита операций
|
||||
order Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
description String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique
|
||||
name String
|
||||
price Float
|
||||
pricePerGb Decimal? @db.Decimal(10, 4) // Цена за 1 GB для кастомного тарифа
|
||||
bandwidthPerGb Decimal? @db.Decimal(10, 4) // GB трафика на 1 GB хранения
|
||||
requestsPerGb Int? // Количество операций на 1 GB хранения
|
||||
quotaGb Int // Базовая квота для обычных тарифов (0 для custom)
|
||||
bandwidthGb Int // Базовый трафик для обычных тарифов (0 для custom)
|
||||
requestLimit String // Текстовое описание лимита операций
|
||||
order Int @default(0)
|
||||
isActive Boolean @default(true)
|
||||
description String?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @default(now()) @updatedAt
|
||||
|
||||
buckets StorageBucket[]
|
||||
checkoutSessions StorageCheckoutSession[]
|
||||
@@ -451,22 +452,22 @@ model StoragePlan {
|
||||
}
|
||||
|
||||
model StorageCheckoutSession {
|
||||
id String @id @default(uuid())
|
||||
id String @id @default(uuid())
|
||||
userId Int?
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
user User? @relation(fields: [userId], references: [id], onDelete: SetNull)
|
||||
planId Int
|
||||
plan StoragePlan @relation(fields: [planId], references: [id])
|
||||
planCode String
|
||||
planName String
|
||||
planDescription String?
|
||||
price Float
|
||||
promoCodeId Int?
|
||||
promoCode PromoCode? @relation(fields: [promoCodeId], references: [id])
|
||||
promoDiscount Float? @default(0)
|
||||
promoCodeId Int?
|
||||
promoCode PromoCode? @relation(fields: [promoCodeId], references: [id])
|
||||
promoDiscount Float? @default(0)
|
||||
quotaGb Int
|
||||
bandwidthGb Int
|
||||
requestLimit String
|
||||
createdAt DateTime @default(now())
|
||||
createdAt DateTime @default(now())
|
||||
expiresAt DateTime
|
||||
consumedAt DateTime?
|
||||
|
||||
@@ -486,40 +487,43 @@ model StorageRegion {
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
buckets StorageBucket[] @relation("BucketRegion")
|
||||
buckets StorageBucket[] @relation("BucketRegion")
|
||||
|
||||
@@map("storage_region")
|
||||
}
|
||||
|
||||
model StorageClass {
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique
|
||||
name String
|
||||
description String?
|
||||
redundancy String?
|
||||
performance String?
|
||||
retrievalFee String?
|
||||
isDefault Boolean @default(false)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique
|
||||
name String
|
||||
description String?
|
||||
redundancy String?
|
||||
performance String?
|
||||
retrievalFee String?
|
||||
isDefault Boolean @default(false)
|
||||
isActive Boolean @default(true)
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
buckets StorageBucket[] @relation("BucketClass")
|
||||
buckets StorageBucket[] @relation("BucketClass")
|
||||
|
||||
@@map("storage_class")
|
||||
}
|
||||
|
||||
model PromoCode {
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique
|
||||
amount Float // discount amount in RUB
|
||||
used Boolean @default(false)
|
||||
usedBy Int?
|
||||
id Int @id @default(autoincrement())
|
||||
code String @unique
|
||||
amount Float // discount amount in RUB
|
||||
used Boolean @default(false)
|
||||
usedBy Int?
|
||||
usedAt DateTime?
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
createdAt DateTime @default(now())
|
||||
updatedAt DateTime @updatedAt
|
||||
|
||||
user User? @relation(fields: [usedBy], references: [id])
|
||||
user User? @relation(fields: [usedBy], references: [id], onDelete: SetNull)
|
||||
|
||||
// Обратная связь для корзин, в которые применяли этот промокод
|
||||
checkoutSessions StorageCheckoutSession[]
|
||||
|
||||
@@map("promo_code")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user