// 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") } // ============================================ // 用户表 // ============================================ model User { id String @id @default(uuid()) username String @unique @db.VarChar(50) email String @unique @db.VarChar(100) passwordHash String @map("password_hash") @db.VarChar(255) avatar String? @db.VarChar(255) // VIP 状态 isVip Boolean @default(false) @map("is_vip") vipLevel Int @default(0) @map("vip_level") vipExpireAt DateTime? @map("vip_expire_at") // Token 吊销 (递增版本号使旧 token 失效) tokenVersion Int @default(0) @map("token_version") // 统计 schemesCount Int @default(0) @map("schemes_count") favoritesCount Int @default(0) @map("favorites_count") // 设备绑定 installId String? @map("install_id") @db.VarChar(64) deviceHash String? @map("device_hash") @db.VarChar(64) lastDeviceCheck DateTime? @map("last_device_check") // 元数据 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") lastLoginAt DateTime? @map("last_login_at") deletedAt DateTime? @map("deleted_at") // 关系 schemes Scheme[] schemesAob SchemeAob[] filterShares FilterShare[] favorites Favorite[] likes Like[] logs UserLog[] usedVipCards VipCard[] @relation("UsedCards") deviceBindings DeviceBinding[] @@map("users") } // ============================================ // VIP 卡密表 // ============================================ model VipCard { id String @id @default(uuid()) cardKey String @unique @map("card_key") @db.VarChar(50) cardType String @map("card_type") @db.VarChar(20) days Int status String @default("UNUSED") @db.VarChar(20) usedBy String? @map("used_by") usedAt DateTime? @map("used_at") batchId String? @map("batch_id") generatedAt DateTime @default(now()) @map("generated_at") originalPrice Decimal? @map("original_price") @db.Decimal(10, 2) salePrice Decimal? @map("sale_price") @db.Decimal(10, 2) user User? @relation("UsedCards", fields: [usedBy], references: [id], onDelete: SetNull) @@map("vip_cards") } // ============================================ // 方案表 - 烽火地带 // ============================================ model Scheme { id String @id @default(uuid()) userId String @map("user_id") title String? @db.VarChar(100) description String? @db.Text weaponName String? @map("weapon_name") @db.VarChar(100) category String? @db.VarChar(50) schemeContent String @map("scheme_content") @db.Text contentEncrypted Boolean @default(true) @map("content_encrypted") price Int @default(0) viewsCount Int @default(0) @map("views_count") downloadsCount Int @default(0) @map("downloads_count") likesCount Int @default(0) @map("likes_count") favoritesCount Int @default(0) @map("favorites_count") gpuModel String? @map("gpu_model") @db.VarChar(100) driverVersion String? @map("driver_version") @db.VarChar(50) appVersion String? @map("app_version") @db.VarChar(20) status String @default("DRAFT") @db.VarChar(20) isOfficial Boolean @default(false) @map("is_official") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([weaponName]) @@index([category]) @@index([status]) @@map("schemes") } // ============================================ // 方案表 - 全面战场 (AOB) // ============================================ model SchemeAob { id String @id @default(uuid()) userId String @map("user_id") title String? @db.VarChar(100) description String? @db.Text weaponName String? @map("weapon_name") @db.VarChar(100) category String? @db.VarChar(50) schemeContent String @map("scheme_content") @db.Text contentEncrypted Boolean @default(true) @map("content_encrypted") price Int @default(0) viewsCount Int @default(0) @map("views_count") downloadsCount Int @default(0) @map("downloads_count") likesCount Int @default(0) @map("likes_count") favoritesCount Int @default(0) @map("favorites_count") status String @default("DRAFT") @db.VarChar(20) isOfficial Boolean @default(false) @map("is_official") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@index([weaponName]) @@map("schemes_aob") } // ============================================ // 滤镜分享表 // ============================================ model FilterShare { id String @id @default(uuid()) userId String @map("user_id") title String @db.VarChar(100) description String? @db.Text category String? @db.VarChar(50) filterContent String @map("filter_content") @db.Text contentFormat String @default("MQTS1") @map("content_format") @db.VarChar(20) viewsCount Int @default(0) @map("views_count") likesCount Int @default(0) @map("likes_count") status String @default("DRAFT") @db.VarChar(20) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@index([userId]) @@map("filter_shares") } // ============================================ // 收藏表 // ============================================ model Favorite { id String @id @default(uuid()) userId String @map("user_id") targetType String @map("target_type") @db.VarChar(20) targetId String @map("target_id") createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, targetType, targetId]) @@index([userId]) @@map("favorites") } // ============================================ // 点赞表 // ============================================ model Like { id String @id @default(uuid()) userId String @map("user_id") targetType String @map("target_type") @db.VarChar(20) targetId String @map("target_id") createdAt DateTime @default(now()) @map("created_at") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, targetType, targetId]) @@index([userId]) @@index([targetType, targetId]) @@map("likes") } // ============================================ // 分类表 // ============================================ model Category { id String @id @default(uuid()) name String @db.VarChar(50) type String @db.VarChar(20) sortOrder Int @default(0) @map("sort_order") isActive Boolean @default(true) @map("is_active") createdAt DateTime @default(now()) @map("created_at") @@map("categories") } // ============================================ // 用户日志表 // ============================================ model UserLog { id String @id @default(uuid()) userId String? @map("user_id") action String @db.VarChar(50) targetType String? @map("target_type") @db.VarChar(50) targetId String? @map("target_id") installId String? @map("install_id") @db.VarChar(64) deviceHash String? @map("device_hash") @db.VarChar(64) ipAddress String? @map("ip_address") @db.VarChar(45) createdAt DateTime @default(now()) @map("created_at") user User? @relation(fields: [userId], references: [id], onDelete: SetNull) @@index([userId]) @@index([action]) @@map("user_logs") } // ============================================ // 设备绑定表 // ============================================ model DeviceBinding { id String @id @default(uuid()) userId String @map("user_id") installId String @map("install_id") @db.VarChar(64) deviceHash String @map("device_hash") @db.VarChar(64) boundAt DateTime @default(now()) @map("bound_at") lastActiveAt DateTime? @map("last_active_at") isActive Boolean @default(true) @map("is_active") user User @relation(fields: [userId], references: [id], onDelete: Cascade) @@unique([userId, installId]) @@map("device_bindings") }