HotTRDealsBackend/prisma/schema.prisma
2026-01-29 00:45:52 +00:00

331 lines
8.1 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
enum UserRole {
USER
MOD
ADMIN
}
model User {
id Int @id @default(autoincrement())
username String @unique
email String @unique
passwordHash String
avatarUrl String? @db.VarChar(512)
role UserRole @default(USER)
createdAt DateTime @default(now())
updatedAt DateTime @default(now()) @updatedAt
Deal Deal[]
votes DealVote[]
comments Comment[]
companies Seller[]
domains SellerDomain[]
dealVoteHistory DealVoteHistory[]
dealNotices DealNotice[] @relation("UserDealNotices")
refreshTokens RefreshToken[] // <-- bunu ekle
commentLikes CommentLike[]
}
model RefreshToken {
id String @id @default(cuid()) // token kaydı id
userId Int
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
tokenHash String @unique // refresh token hash (örn sha256)
familyId String // rotation zinciri için aynı aile
jti String // token id (JWT jti / random)
expiresAt DateTime
createdAt DateTime @default(now())
revokedAt DateTime?
replacedById String? @unique
replacedBy RefreshToken? @relation("TokenRotation", fields: [replacedById], references: [id])
replaces RefreshToken? @relation("TokenRotation")
createdByIp String?
userAgent String?
@@index([userId])
@@index([familyId])
@@index([expiresAt])
}
enum DealStatus {
PENDING
ACTIVE
EXPIRED
REJECTED
}
enum SaleType {
ONLINE
OFFLINE
CODE
}
enum AffiliateType {
AFFILIATE
NON_AFFILIATE
USER_AFFILIATE
}
model SellerDomain {
id Int @id @default(autoincrement())
domain String @unique
sellerId Int
seller Seller @relation(fields: [sellerId], references: [id])
createdAt DateTime @default(now())
createdById Int
createdBy User @relation(fields: [createdById], references: [id])
}
model Seller {
id Int @id @default(autoincrement())
name String @unique
url String @default("")
sellerLogo String @default("")
isActive Boolean @default(true)
createdAt DateTime @default(now())
createdById Int
deals Deal[]
createdBy User @relation(fields: [createdById], references: [id])
domains SellerDomain[]
}
/**
* NEW: Category (self-parent tree)
* NOTE: You want Deal.categoryId default 0 -> you MUST create a Category row with id=0 ("Undefined")
*/
model Category {
id Int @id @default(autoincrement())
name String
slug String @unique
description String @default("")
parentId Int?
parent Category? @relation("CategoryParent", fields: [parentId], references: [id])
children Category[] @relation("CategoryParent")
deals Deal[]
@@index([parentId])
}
/**
* NEW: Tag (canonical)
*/
model Tag {
id Int @id @default(autoincrement())
slug String @unique
name String
dealTags DealTag[]
}
/**
* NEW: Join table Deal <-> Tag (many-to-many)
*/
model DealTag {
dealId Int
tagId Int
deal Deal @relation(fields: [dealId], references: [id], onDelete: Cascade)
tag Tag @relation(fields: [tagId], references: [id], onDelete: Cascade)
createdAt DateTime @default(now())
@@id([dealId, tagId])
@@index([tagId, dealId]) // tag -> deals hızlı
@@index([dealId]) // deal -> tags hızlı
}
model Deal {
id Int @id @default(autoincrement())
title String
description String?
url String?
price Float?
originalPrice Float?
shippingPrice Float?
percentOff Float?
userId Int
score Int @default(0)
commentCount Int @default(0)
status DealStatus @default(PENDING)
saletype SaleType @default(ONLINE)
affiliateType AffiliateType @default(NON_AFFILIATE)
sellerId Int?
customSeller String?
seller Seller? @relation(fields: [sellerId], references: [id])
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
user User @relation(fields: [userId], references: [id])
votes DealVote[]
voteHistory DealVoteHistory[]
notices DealNotice[] @relation("DealNotices")
comments Comment[]
images DealImage[]
// NEW: category (single)
categoryId Int @default(0)
category Category @relation(fields: [categoryId], references: [id])
// NEW: tags (multiple, optional)
dealTags DealTag[]
aiReview DealAiReview?
@@index([categoryId, createdAt])
@@index([userId, createdAt])
}
enum DealNoticeSeverity {
INFO
WARNING
DANGER
SUCCESS
}
model DealNotice {
id Int @id @default(autoincrement())
dealId Int
title String
body String?
severity DealNoticeSeverity @default(INFO)
isActive Boolean @default(true)
createdBy Int
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deal Deal @relation("DealNotices", fields: [dealId], references: [id], onDelete: Cascade)
creator User @relation("UserDealNotices", fields: [createdBy], references: [id])
@@index([dealId, isActive, createdAt])
@@index([createdBy])
}
model DealImage {
id Int @id @default(autoincrement())
imageUrl String @db.VarChar(512)
order Int @default(0)
createdAt DateTime @default(now())
dealId Int
deal Deal @relation(fields: [dealId], references: [id], onDelete: Cascade)
}
model DealVote {
id Int @id @default(autoincrement())
dealId Int
userId Int
voteType Int @default(0) // -1,0,1
createdAt DateTime @default(now())
lastVotedAt DateTime @default(now()) // her vote değişiminde set edeceğiz
deal Deal @relation(fields: [dealId], references: [id])
user User @relation(fields: [userId], references: [id])
@@unique([dealId, userId])
@@index([dealId])
}
model DealVoteHistory {
id Int @id @default(autoincrement())
dealId Int
userId Int
voteType Int
createdAt DateTime @default(now())
deal Deal @relation(fields: [dealId], references: [id])
user User @relation(fields: [userId], references: [id])
@@index([dealId])
@@index([userId])
@@index([createdAt])
}
model Comment {
id Int @id @default(autoincrement())
text String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
userId Int
dealId Int
parentId Int?
likeCount Int @default(0)
deletedAt DateTime?
user User @relation(fields: [userId], references: [id])
deal Deal @relation(fields: [dealId], references: [id])
parent Comment? @relation("CommentReplies", fields: [parentId], references: [id], onDelete: SetNull)
replies Comment[] @relation("CommentReplies")
likes CommentLike[]
@@index([dealId, createdAt])
@@index([parentId, createdAt])
@@index([dealId, parentId, createdAt])
@@index([deletedAt])
}
model CommentLike {
id Int @id @default(autoincrement())
commentId Int
userId Int
createdAt DateTime @default(now())
comment Comment @relation(fields: [commentId], references: [id], onDelete: Cascade)
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
@@unique([commentId, userId])
@@index([commentId])
@@index([userId])
}
enum DealAiIssueType {
NONE
PROFANITY
PHONE_NUMBER
PERSONAL_DATA
SPAM
OTHER
}
model DealAiReview {
id Int @id @default(autoincrement())
dealId Int @unique
deal Deal @relation(fields: [dealId], references: [id], onDelete: Cascade)
bestCategoryId Int
needsReview Boolean @default(false)
hasIssue Boolean @default(false)
issueType DealAiIssueType @default(NONE)
issueReason String?
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@index([needsReview, hasIssue, updatedAt])
}