575 lines
20 KiB
Plaintext
575 lines
20 KiB
Plaintext
// =============================================================================
|
||
// 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")
|
||
}
|