rwadurian/backend/services/admin-service/prisma/schema.prisma

575 lines
20 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.

// =============================================================================
// Admin Service - Prisma Schema
// =============================================================================
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
// =============================================================================
// App Version Management
// =============================================================================
model AppVersion {
id String @id @default(uuid())
platform Platform
versionCode Int // Android: versionCode, iOS: CFBundleVersion
versionName String // 用户可见版本号,如 "1.2.3"
buildNumber String // 构建号
downloadUrl String // APK/IPA 下载地址
fileSize BigInt // 文件大小(字节)
fileSha256 String // 文件 SHA-256 校验和
minOsVersion String? // 最低操作系统版本要求
changelog String // 更新日志
isForceUpdate Boolean @default(false) // 是否强制更新
isEnabled Boolean @default(true) // 是否启用
releaseDate DateTime? // 发布日期
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy String // 创建人ID
updatedBy String? // 更新人ID
@@index([platform, isEnabled])
@@index([platform, versionCode])
@@map("app_versions")
}
enum Platform {
ANDROID
IOS
}
// =============================================================================
// Notification System (通知系统)
// =============================================================================
/// 系统通知 - 管理员发布的公告/通知
model Notification {
id String @id @default(uuid())
title String // 通知标题
content String // 通知内容
type NotificationType // 通知类型
priority NotificationPriority @default(NORMAL) // 优先级
targetType TargetType @default(ALL) // 目标用户类型
targetLogic TargetLogic @default(ANY) @map("target_logic") // 多标签匹配逻辑
imageUrl String? // 可选的图片URL
linkUrl String? // 可选的跳转链接
isEnabled Boolean @default(true) // 是否启用
publishedAt DateTime? // 发布时间null表示草稿
expiresAt DateTime? // 过期时间null表示永不过期
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
createdBy String // 创建人ID
// 关联
readRecords NotificationRead[]
targetTags NotificationTagTarget[] // BY_TAG 时使用
targetUsers NotificationUserTarget[] // SPECIFIC 时使用
@@index([isEnabled, publishedAt])
@@index([type])
@@index([targetType])
@@map("notifications")
}
/// 用户已读记录
model NotificationRead {
id String @id @default(uuid())
notificationId String
userSerialNum String // 用户序列号
readAt DateTime @default(now())
notification Notification @relation(fields: [notificationId], references: [id], onDelete: Cascade)
@@unique([notificationId, userSerialNum])
@@index([userSerialNum])
@@map("notification_reads")
}
/// 通知类型
enum NotificationType {
SYSTEM // 系统通知
ACTIVITY // 活动通知
REWARD // 收益通知
UPGRADE // 升级通知
ANNOUNCEMENT // 公告
}
/// 通知优先级
enum NotificationPriority {
LOW
NORMAL
HIGH
URGENT
}
/// 目标用户类型
enum TargetType {
ALL // 所有用户
BY_TAG // 按标签匹配
SPECIFIC // 指定用户列表
}
/// 多标签匹配逻辑
enum TargetLogic {
ANY // 匹配任一标签
ALL // 匹配所有标签
}
/// 通知-标签关联
model NotificationTagTarget {
id String @id @default(uuid())
notificationId String @map("notification_id")
tagId String @map("tag_id")
notification Notification @relation(fields: [notificationId], references: [id], onDelete: Cascade)
tag UserTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@unique([notificationId, tagId])
@@index([tagId])
@@map("notification_tag_targets")
}
/// 通知-用户关联 (指定用户)
model NotificationUserTarget {
id String @id @default(uuid())
notificationId String @map("notification_id")
accountSequence String @map("account_sequence") @db.VarChar(12)
notification Notification @relation(fields: [notificationId], references: [id], onDelete: Cascade)
@@unique([notificationId, accountSequence])
@@index([accountSequence])
@@map("notification_user_targets")
}
// =============================================================================
// User Profile System (用户画像系统) - 面向通知 + 广告
// =============================================================================
// -----------------------------------------------------------------------------
// 标签分类 (Tag Category) - 标签的分组管理
// -----------------------------------------------------------------------------
/// 标签分类
model TagCategory {
id String @id @default(uuid())
code String @unique @db.VarChar(50) // "lifecycle", "value", "behavior"
name String @db.VarChar(100) // "生命周期", "价值分层", "行为特征"
description String? @db.Text
sortOrder Int @default(0) @map("sort_order")
isEnabled Boolean @default(true) @map("is_enabled")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
tags UserTag[]
@@index([code])
@@index([isEnabled])
@@map("tag_categories")
}
// -----------------------------------------------------------------------------
// 用户标签 (User Tag) - 增强版
// -----------------------------------------------------------------------------
/// 标签类型
enum TagType {
MANUAL // 手动打标 (管理员操作)
AUTO // 自动打标 (规则驱动)
COMPUTED // 计算型 (实时计算,不存储关联)
SYSTEM // 系统内置 (不可删除)
}
/// 标签值类型
enum TagValueType {
BOOLEAN // 布尔型: 有/无
ENUM // 枚举型: 高/中/低
NUMBER // 数值型: 0-100分
STRING // 字符串型
}
/// 用户标签定义
model UserTag {
id String @id @default(uuid())
categoryId String? @map("category_id")
code String @unique @db.VarChar(50) // "vip", "new_user", "whale"
name String @db.VarChar(100) // "VIP用户", "新用户", "大客户"
description String? @db.Text
color String? @db.VarChar(20) // "#FF5722"
type TagType @default(MANUAL) // 标签类型
valueType TagValueType @default(BOOLEAN) @map("value_type") // 标签值类型
// 枚举型标签的可选值
// 例如: ["高", "中", "低"] 或 ["活跃", "沉默", "流失"]
enumValues Json? @map("enum_values")
// 关联的自动规则 (type=AUTO 时使用)
ruleId String? @unique @map("rule_id")
rule UserClassificationRule? @relation(fields: [ruleId], references: [id], onDelete: SetNull)
// 广告相关
isAdvertisable Boolean @default(true) @map("is_advertisable") // 是否可用于广告定向
estimatedUsers Int? @map("estimated_users") // 预估覆盖用户数
isEnabled Boolean @default(true) @map("is_enabled")
sortOrder Int @default(0) @map("sort_order")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// 关联
category TagCategory? @relation(fields: [categoryId], references: [id], onDelete: SetNull)
assignments UserTagAssignment[]
notifications NotificationTagTarget[]
@@index([categoryId])
@@index([code])
@@index([type])
@@index([isEnabled])
@@index([isAdvertisable])
@@map("user_tags")
}
// -----------------------------------------------------------------------------
// 用户-标签关联 - 支持标签值
// -----------------------------------------------------------------------------
/// 用户-标签关联
model UserTagAssignment {
id String @id @default(uuid())
accountSequence String @map("account_sequence") @db.VarChar(12)
tagId String @map("tag_id")
// 标签值 (根据 valueType)
// BOOLEAN: null (存在即为true)
// ENUM: "高" / "中" / "低"
// NUMBER: "85" (字符串存储)
// STRING: 任意字符串
value String? @db.VarChar(100)
assignedAt DateTime @default(now()) @map("assigned_at")
assignedBy String? @map("assigned_by") // null=系统自动, 否则为管理员ID
expiresAt DateTime? @map("expires_at") // 可选过期时间
source String? @db.VarChar(50) // 来源: "rule:xxx", "import", "manual", "kafka"
tag UserTag @relation(fields: [tagId], references: [id], onDelete: Cascade)
@@unique([accountSequence, tagId])
@@index([accountSequence])
@@index([tagId])
@@index([value])
@@index([expiresAt])
@@map("user_tag_assignments")
}
// -----------------------------------------------------------------------------
// 用户分类规则 (Classification Rule)
// -----------------------------------------------------------------------------
/// 用户分类规则
model UserClassificationRule {
id String @id @default(uuid())
name String @db.VarChar(100) // "30天内新用户"
description String? @db.Text
// 规则条件 (JSON)
// 示例:
// {
// "type": "AND",
// "rules": [
// { "field": "registeredAt", "operator": "within_days", "value": 30 },
// { "field": "kycStatus", "operator": "eq", "value": "VERIFIED" }
// ]
// }
conditions Json
isEnabled Boolean @default(true) @map("is_enabled")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// 关联的自动标签
tag UserTag?
@@map("user_classification_rules")
}
// -----------------------------------------------------------------------------
// 用户特征 (User Features) - 数值型指标
// -----------------------------------------------------------------------------
/// 用户特征 - 计算后的用户画像指标
model UserFeature {
id String @id @default(uuid())
accountSequence String @unique @map("account_sequence") @db.VarChar(12)
// RFM 模型
rfmRecency Int? @map("rfm_recency") // 最近一次活跃距今天数
rfmFrequency Int? @map("rfm_frequency") // 过去30天活跃天数
rfmMonetary Decimal? @map("rfm_monetary") @db.Decimal(18, 2) // 累计消费金额
rfmScore Int? @map("rfm_score") // RFM综合分 (0-100)
// 活跃度
activeLevel String? @map("active_level") @db.VarChar(20) // "高活跃", "中活跃", "低活跃", "沉默"
lastActiveAt DateTime? @map("last_active_at")
// 价值分层
valueLevel String? @map("value_level") @db.VarChar(20) // "高价值", "中价值", "低价值", "潜力"
lifetimeValue Decimal? @map("lifetime_value") @db.Decimal(18, 2) // 用户生命周期价值 LTV
// 生命周期
lifecycleStage String? @map("lifecycle_stage") @db.VarChar(20) // "新用户", "成长期", "成熟期", "衰退期", "流失"
// 自定义特征 (JSON扩展)
customFeatures Json? @map("custom_features")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([rfmScore])
@@index([activeLevel])
@@index([valueLevel])
@@index([lifecycleStage])
@@map("user_features")
}
// -----------------------------------------------------------------------------
// 人群包 (Audience Segment) - 复杂定向
// -----------------------------------------------------------------------------
/// 人群包用途
enum SegmentUsageType {
GENERAL // 通用
NOTIFICATION // 通知定向
ADVERTISING // 广告定向
ANALYTICS // 数据分析
}
/// 人群包 - 多条件组合的用户群
model AudienceSegment {
id String @id @default(uuid())
name String @db.VarChar(100) // "高价值活跃用户"
description String? @db.Text
// 定向条件 (JSON)
// {
// "type": "AND",
// "conditions": [
// { "type": "tag", "tagCode": "vip", "operator": "eq", "value": true },
// { "type": "feature", "field": "rfmScore", "operator": "gte", "value": 80 },
// { "type": "profile", "field": "province", "operator": "in", "value": ["广东", "浙江"] }
// ]
// }
conditions Json
// 预估数据
estimatedUsers Int? @map("estimated_users")
lastCalculated DateTime? @map("last_calculated")
// 用途
usageType SegmentUsageType @default(GENERAL) @map("usage_type")
isEnabled Boolean @default(true) @map("is_enabled")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
createdBy String @map("created_by")
@@index([usageType])
@@index([isEnabled])
@@map("audience_segments")
}
// -----------------------------------------------------------------------------
// 标签变更日志 (审计追踪)
// -----------------------------------------------------------------------------
/// 标签变更操作
enum TagAction {
ASSIGN // 打标签
UPDATE // 更新标签值
REMOVE // 移除标签
EXPIRE // 过期移除
}
/// 标签变更日志
model UserTagLog {
id String @id @default(uuid())
accountSequence String @map("account_sequence") @db.VarChar(12)
tagCode String @map("tag_code") @db.VarChar(50)
action TagAction
oldValue String? @map("old_value") @db.VarChar(100)
newValue String? @map("new_value") @db.VarChar(100)
reason String? @db.VarChar(200) // "规则触发", "管理员操作", "导入", "过期清理"
operatorId String? @map("operator_id")
createdAt DateTime @default(now()) @map("created_at")
@@index([accountSequence, createdAt])
@@index([tagCode])
@@index([action])
@@index([createdAt])
@@map("user_tag_logs")
}
// =============================================================================
// User Query View (用户查询视图 - 通过 Kafka 事件同步)
// =============================================================================
/// 用户查询视图 - 本地物化视图,通过消费 Kafka 事件同步维护
/// 用于 admin-web 用户管理页面的查询,避免跨服务 HTTP 调用
model UserQueryView {
userId BigInt @id @map("user_id")
accountSequence String @unique @map("account_sequence") @db.VarChar(12)
// 基本信息 (来自 identity-service 事件)
nickname String? @db.VarChar(100)
avatarUrl String? @map("avatar_url") @db.Text
phoneNumberMasked String? @map("phone_number_masked") @db.VarChar(20) // 脱敏: 138****8888
// 推荐关系
inviterSequence String? @map("inviter_sequence") @db.VarChar(12)
// KYC 状态
kycStatus String @default("NOT_VERIFIED") @map("kyc_status") @db.VarChar(20)
// 认种统计 (来自 planting-service 事件)
personalAdoptionCount Int @default(0) @map("personal_adoption_count")
teamAddressCount Int @default(0) @map("team_address_count")
teamAdoptionCount Int @default(0) @map("team_adoption_count")
// 授权统计 (来自 authorization-service 事件)
provinceAdoptionCount Int @default(0) @map("province_adoption_count")
cityAdoptionCount Int @default(0) @map("city_adoption_count")
// 排名
leaderboardRank Int? @map("leaderboard_rank")
// 状态
status String @default("ACTIVE") @db.VarChar(20)
isOnline Boolean @default(false) @map("is_online")
// 时间戳
registeredAt DateTime @map("registered_at")
lastActiveAt DateTime? @map("last_active_at")
syncedAt DateTime @default(now()) @map("synced_at")
@@index([accountSequence])
@@index([nickname])
@@index([status])
@@index([registeredAt])
@@index([personalAdoptionCount])
@@index([inviterSequence])
@@map("user_query_view")
}
// =============================================================================
// Kafka Event Tracking (事件消费追踪)
// =============================================================================
/// 事件消费位置追踪 - 用于幂等性和断点续传
model EventConsumerOffset {
id BigInt @id @default(autoincrement())
consumerGroup String @map("consumer_group") @db.VarChar(100)
topic String @db.VarChar(100)
partition Int
offset BigInt
updatedAt DateTime @default(now()) @map("updated_at")
@@unique([consumerGroup, topic, partition])
@@map("event_consumer_offsets")
}
/// 已处理事件记录 - 用于幂等性检查
model ProcessedEvent {
id BigInt @id @default(autoincrement())
eventId String @unique @map("event_id") @db.VarChar(100)
eventType String @map("event_type") @db.VarChar(50)
processedAt DateTime @default(now()) @map("processed_at")
@@index([eventType])
@@index([processedAt])
@@map("processed_events")
}
// =============================================================================
// System Config (系统配置)
// =============================================================================
/// 系统配置 - 键值对存储,用于存储各种系统设置
model SystemConfig {
id String @id @default(uuid())
key String @unique @db.VarChar(100) // 配置键
value String @db.Text // 配置值 (JSON 格式)
description String? @db.VarChar(255) // 配置描述
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
updatedBy String? @map("updated_by") // 更新人ID
@@index([key])
@@map("system_configs")
}
// =============================================================================
// Co-Managed Wallet System (共管钱包系统)
// =============================================================================
/// 共管钱包会话状态
enum WalletSessionStatus {
WAITING // 等待参与方加入
READY // 所有参与方已就绪
PROCESSING // 密钥生成中
COMPLETED // 创建完成
FAILED // 创建失败
CANCELLED // 已取消
}
/// 共管钱包会话 - 钱包创建过程的会话记录
model CoManagedWalletSession {
id String @id @default(uuid())
walletName String @map("wallet_name") @db.VarChar(100) // 钱包名称
thresholdT Int @map("threshold_t") // 签名阈值 T
thresholdN Int @map("threshold_n") // 参与方总数 N
inviteCode String @unique @map("invite_code") @db.VarChar(20) // 邀请码
status WalletSessionStatus @default(WAITING) // 会话状态
participants String @db.Text // 参与方列表 (JSON)
currentRound Int @default(0) @map("current_round") // 当前密钥生成轮次
totalRounds Int @default(3) @map("total_rounds") // 总轮次
publicKey String? @map("public_key") @db.VarChar(200) // 生成的公钥
error String? @db.Text // 错误信息
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
createdBy String @map("created_by") @db.VarChar(100) // 创建者
@@index([inviteCode])
@@index([status])
@@index([createdBy])
@@index([createdAt])
@@map("co_managed_wallet_sessions")
}
/// 共管钱包 - 创建成功后的钱包记录
model CoManagedWallet {
id String @id @default(uuid())
sessionId String @unique @map("session_id") // 关联的会话 ID
name String @db.VarChar(100) // 钱包名称
publicKey String @map("public_key") @db.VarChar(200) // 钱包公钥
thresholdT Int @map("threshold_t") // 签名阈值 T
thresholdN Int @map("threshold_n") // 参与方总数 N
participants String @db.Text // 参与方列表 (JSON)
createdAt DateTime @default(now()) @map("created_at")
createdBy String @map("created_by") @db.VarChar(100) // 创建者
@@index([sessionId])
@@index([publicKey])
@@index([createdBy])
@@index([createdAt])
@@map("co_managed_wallets")
}