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

576 lines
21 KiB
Plaintext
Raw Permalink 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")
}
// ============ 授权角色表 ============
model AuthorizationRole {
id String @id @default(uuid())
userId String @map("user_id")
accountSequence String @map("account_sequence")
roleType RoleType @map("role_type")
regionCode String @map("region_code")
regionName String @map("region_name")
status AuthorizationStatus @default(PENDING)
displayTitle String @map("display_title")
// 授权信息
authorizedAt DateTime? @map("authorized_at")
authorizedBy String? @map("authorized_by")
revokedAt DateTime? @map("revoked_at")
revokedBy String? @map("revoked_by")
revokeReason String? @map("revoke_reason")
// 软删除 (大厂通用做法: deleted_at 为 NULL 表示未删除)
deletedAt DateTime? @map("deleted_at")
// 考核配置
initialTargetTreeCount Int @map("initial_target_tree_count")
monthlyTargetType MonthlyTargetType @map("monthly_target_type")
// 自有团队占比
requireLocalPercentage Decimal @default(5.0) @map("require_local_percentage") @db.Decimal(5, 2)
exemptFromPercentageCheck Boolean @default(false) @map("exempt_from_percentage_check")
// 权益状态
benefitActive Boolean @default(false) @map("benefit_active")
benefitActivatedAt DateTime? @map("benefit_activated_at")
benefitDeactivatedAt DateTime? @map("benefit_deactivated_at")
benefitValidUntil DateTime? @map("benefit_valid_until") // 权益有效期截止日期(当前月+下月末)
// 月度考核追踪
lastAssessmentMonth String? @map("last_assessment_month") // 上次考核月份 YYYY-MM
monthlyTreesAdded Int @default(0) @map("monthly_trees_added") // 当月新增树数
lastMonthTreesAdded Int @default(0) @map("last_month_trees_added") // 上月新增树数(考核用存档)
// 当前考核月份索引
currentMonthIndex Int @default(0) @map("current_month_index")
// 时间戳
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// 关联
assessments MonthlyAssessment[]
bypassRecords MonthlyBypass[]
// 注意: 唯一约束通过数据库层的部分索引实现,只对 deleted_at IS NULL 的记录生效
// 需要手动执行迁移 SQL 创建部分唯一索引
// @@unique([accountSequence, roleType, regionCode]) -- 已移除,改用部分索引
@@index([accountSequence])
@@index([userId])
@@index([roleType, regionCode])
@@index([status])
@@index([roleType, status])
@@index([deletedAt])
@@map("authorization_roles")
}
// ============ 月度考核表 ============
model MonthlyAssessment {
id String @id @default(uuid())
authorizationId String @map("authorization_id")
userId String @map("user_id")
accountSequence String @map("account_sequence")
roleType RoleType @map("role_type")
regionCode String @map("region_code")
// 考核月份
assessmentMonth String @map("assessment_month") // YYYY-MM
monthIndex Int @map("month_index") // 第几个月考核
// 考核目标
monthlyTarget Int @map("monthly_target")
cumulativeTarget Int @map("cumulative_target")
// 完成情况
monthlyCompleted Int @default(0) @map("monthly_completed")
cumulativeCompleted Int @default(0) @map("cumulative_completed")
completedAt DateTime? @map("completed_at") // 达标时间(用于排名)
// 自有团队占比
localTeamCount Int @default(0) @map("local_team_count")
totalTeamCount Int @default(0) @map("total_team_count")
localPercentage Decimal @default(0) @map("local_percentage") @db.Decimal(10, 2)
localPercentagePass Boolean @default(false) @map("local_percentage_pass")
// 超越目标占比
exceedRatio Decimal @default(0) @map("exceed_ratio") @db.Decimal(10, 4)
// 考核结果
result AssessmentResult @default(NOT_ASSESSED)
// 排名
rankingInRegion Int? @map("ranking_in_region")
isFirstPlace Boolean @default(false) @map("is_first_place")
// 豁免
isBypassed Boolean @default(false) @map("is_bypassed")
bypassedBy String? @map("bypassed_by")
bypassedAt DateTime? @map("bypassed_at")
// 时间戳
assessedAt DateTime? @map("assessed_at")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
// 关联
authorization AuthorizationRole @relation(fields: [authorizationId], references: [id])
@@unique([authorizationId, assessmentMonth])
@@index([accountSequence, assessmentMonth])
@@index([userId, assessmentMonth])
@@index([roleType, regionCode, assessmentMonth])
@@index([assessmentMonth, result])
@@index([assessmentMonth, roleType, exceedRatio(sort: Desc)])
@@map("monthly_assessments")
}
// ============ 单月豁免记录表 ============
model MonthlyBypass {
id String @id @default(uuid())
authorizationId String @map("authorization_id")
userId String @map("user_id")
accountSequence String @map("account_sequence")
roleType RoleType @map("role_type")
bypassMonth String @map("bypass_month") // YYYY-MM
// 授权信息
grantedBy String @map("granted_by")
grantedAt DateTime @map("granted_at")
reason String?
// 审批信息(三人授权)
approver1Id String @map("approver1_id")
approver1At DateTime @map("approver1_at")
approver2Id String? @map("approver2_id")
approver2At DateTime? @map("approver2_at")
approver3Id String? @map("approver3_id")
approver3At DateTime? @map("approver3_at")
approvalStatus ApprovalStatus @default(PENDING) @map("approval_status")
createdAt DateTime @default(now()) @map("created_at")
authorization AuthorizationRole @relation(fields: [authorizationId], references: [id])
@@unique([authorizationId, bypassMonth])
@@index([accountSequence, bypassMonth])
@@index([userId, bypassMonth])
@@map("monthly_bypasses")
}
// ============ 阶梯考核目标配置表 ============
model LadderTargetConfig {
id String @id @default(uuid())
roleType RoleType @map("role_type")
monthIndex Int @map("month_index")
monthlyTarget Int @map("monthly_target")
cumulativeTarget Int @map("cumulative_target")
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([roleType, monthIndex])
@@map("ladder_target_configs")
}
// ============ 认种限制配置表 ============
model PlantingRestriction {
id String @id @default(uuid())
restrictionType RestrictionType @map("restriction_type")
// 账户限制配置
accountLimitDays Int? @map("account_limit_days")
accountLimitCount Int? @map("account_limit_count")
// 总量限制配置
totalLimitDays Int? @map("total_limit_days")
totalLimitCount Int? @map("total_limit_count")
currentTotalCount Int @default(0) @map("current_total_count")
// 生效时间
startAt DateTime @map("start_at")
endAt DateTime @map("end_at")
isActive Boolean @default(true) @map("is_active")
createdBy String @map("created_by")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("planting_restrictions")
}
// ============ 管理员授权审批表 ============
model AdminApproval {
id String @id @default(uuid())
operationType OperationType @map("operation_type")
targetId String @map("target_id")
targetType String @map("target_type")
requestData Json @map("request_data")
// 审批状态
status ApprovalStatus @default(PENDING)
// 审批人
requesterId String @map("requester_id")
approver1Id String? @map("approver1_id")
approver1At DateTime? @map("approver1_at")
approver2Id String? @map("approver2_id")
approver2At DateTime? @map("approver2_at")
approver3Id String? @map("approver3_id")
approver3At DateTime? @map("approver3_at")
// 完成信息
completedAt DateTime? @map("completed_at")
rejectedBy String? @map("rejected_by")
rejectedAt DateTime? @map("rejected_at")
rejectReason String? @map("reject_reason")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@index([status])
@@index([targetId, targetType])
@@map("admin_approvals")
}
// ============ 授权操作日志表 ============
model AuthorizationAuditLog {
id String @id @default(uuid())
operationType String @map("operation_type")
targetUserId String @map("target_user_id")
targetRoleType RoleType? @map("target_role_type")
targetRegionCode String? @map("target_region_code")
operatorId String @map("operator_id")
operatorRole String @map("operator_role")
beforeState Json? @map("before_state")
afterState Json? @map("after_state")
ipAddress String? @map("ip_address")
userAgent String? @map("user_agent")
createdAt DateTime @default(now()) @map("created_at")
@@index([targetUserId])
@@index([operatorId])
@@index([createdAt])
@@map("authorization_audit_logs")
}
// ============ 省市热度统计表 ============
model RegionHeatMap {
id String @id @default(uuid())
regionCode String @map("region_code")
regionName String @map("region_name")
regionType RegionType @map("region_type")
totalPlantings Int @default(0) @map("total_plantings")
monthlyPlantings Int @default(0) @map("monthly_plantings")
weeklyPlantings Int @default(0) @map("weekly_plantings")
dailyPlantings Int @default(0) @map("daily_plantings")
activeUsers Int @default(0) @map("active_users")
authCompanyCount Int @default(0) @map("auth_company_count")
heatScore Decimal @default(0) @map("heat_score") @db.Decimal(10, 2)
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([regionCode, regionType])
@@map("region_heat_maps")
}
// ============ 火柴人排名视图数据表 ============
model StickmanRanking {
id String @id @default(uuid())
userId String @map("user_id")
accountSequence String @map("account_sequence")
authorizationId String @map("authorization_id")
roleType RoleType @map("role_type")
regionCode String @map("region_code")
regionName String @map("region_name")
// 用户信息
nickname String
avatarUrl String? @map("avatar_url")
// 进度信息
currentMonth String @map("current_month")
cumulativeCompleted Int @map("cumulative_completed")
cumulativeTarget Int @map("cumulative_target")
progressPercentage Decimal @map("progress_percentage") @db.Decimal(10, 2)
exceedRatio Decimal @map("exceed_ratio") @db.Decimal(10, 4)
// 排名
ranking Int
isFirstPlace Boolean @map("is_first_place")
// 本月收益
monthlyRewardUsdt Decimal @map("monthly_reward_usdt") @db.Decimal(18, 2)
monthlyRewardRwad Decimal @map("monthly_reward_rwad") @db.Decimal(18, 8)
updatedAt DateTime @updatedAt @map("updated_at")
@@unique([authorizationId, currentMonth])
@@index([accountSequence, currentMonth])
@@index([roleType, regionCode, currentMonth])
@@map("stickman_rankings")
}
// ============ 系统配置表 ============
model AuthorizationConfig {
id String @id @default(uuid())
configKey String @unique @map("config_key")
configValue String @map("config_value")
description String?
isActive Boolean @default(true) @map("is_active")
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
@@map("authorization_configs")
}
// ============ 枚举定义 ============
enum RoleType {
COMMUNITY // 社区
AUTH_PROVINCE_COMPANY // 授权省公司团队权益20U
PROVINCE_COMPANY // 正式省公司区域权益15U+1%算力)
AUTH_CITY_COMPANY // 授权市公司团队权益40U
CITY_COMPANY // 正式市公司区域权益35U+2%算力)
}
enum AuthorizationStatus {
PENDING // 待授权/待考核
AUTHORIZED // 已授权
REVOKED // 已撤销
}
enum AssessmentResult {
NOT_ASSESSED // 未考核
PASS // 达标
FAIL // 未达标
BYPASSED // 豁免
}
enum MonthlyTargetType {
NONE // 无月度考核(正式省市公司)
FIXED // 固定目标社区10棵/月)
LADDER // 阶梯目标(授权省市公司)
}
enum RestrictionType {
ACCOUNT_LIMIT // 账户限时限量
TOTAL_LIMIT // 总量限制
}
enum ApprovalStatus {
PENDING // 待审批
APPROVED // 已通过
REJECTED // 已拒绝
}
enum OperationType {
GRANT_AUTHORIZATION // 授予授权
REVOKE_AUTHORIZATION // 撤销授权
GRANT_BYPASS // 授予豁免
EXEMPT_PERCENTAGE // 豁免占比考核
MODIFY_CONFIG // 修改配置
}
enum RegionType {
PROVINCE // 省
CITY // 市
}
// ============ 系统账户类型枚举 ============
enum SystemAccountType {
COST_ACCOUNT // 成本账户
OPERATION_ACCOUNT // 运营账户
HQ_COMMUNITY // 总部社区账户
RWAD_POOL_PENDING // RWAD矿池待注入
SYSTEM_PROVINCE // 系统省账户(无授权时)
SYSTEM_CITY // 系统市账户(无授权时)
}
// ============ 系统账户流水类型枚举 ============
enum SystemLedgerEntryType {
PLANTING_ALLOCATION // 认种分配收入
REWARD_EXPIRED // 过期奖励收入
TRANSFER_OUT // 转出
TRANSFER_IN // 转入
WITHDRAWAL // 提现
ADJUSTMENT // 调整
}
// ============ 系统账户表 ============
// 管理成本、运营、总部社区、矿池等系统级账户
model SystemAccount {
id BigInt @id @default(autoincrement()) @map("account_id")
// 账户类型
accountType SystemAccountType @map("account_type")
// 区域信息(仅 SYSTEM_PROVINCE/SYSTEM_CITY 需要)
regionCode String? @map("region_code") @db.VarChar(10)
regionName String? @map("region_name") @db.VarChar(50)
// MPC 生成的钱包地址(按需生成)
walletAddress String? @map("wallet_address") @db.VarChar(42)
mpcPublicKey String? @map("mpc_public_key") @db.VarChar(130)
// 余额USDT
usdtBalance Decimal @default(0) @map("usdt_balance") @db.Decimal(20, 8)
// 算力(仅用于省市账户的算力分配)
hashpower Decimal @default(0) @map("hashpower") @db.Decimal(20, 8)
// 累计统计
totalReceived Decimal @default(0) @map("total_received") @db.Decimal(20, 8)
totalTransferred Decimal @default(0) @map("total_transferred") @db.Decimal(20, 8)
// 状态
status String @default("ACTIVE") @map("status") @db.VarChar(20)
createdAt DateTime @default(now()) @map("created_at")
updatedAt DateTime @updatedAt @map("updated_at")
ledgerEntries SystemAccountLedger[]
@@unique([accountType, regionCode], name: "uk_account_region")
@@index([accountType], name: "idx_system_account_type")
@@index([walletAddress], name: "idx_system_wallet_address")
@@map("system_accounts")
}
// ============ 系统账户流水表 ============
// 记录系统账户的所有资金变动Append-only
model SystemAccountLedger {
id BigInt @id @default(autoincrement()) @map("ledger_id")
accountId BigInt @map("account_id")
// 流水类型
entryType SystemLedgerEntryType @map("entry_type")
// 金额
amount Decimal @map("amount") @db.Decimal(20, 8)
balanceAfter Decimal @map("balance_after") @db.Decimal(20, 8)
// 关联信息
sourceOrderId BigInt? @map("source_order_id") // 来源认种订单
sourceRewardId BigInt? @map("source_reward_id") // 来源过期奖励
txHash String? @map("tx_hash") @db.VarChar(66) // 链上交易哈希
memo String? @map("memo") @db.VarChar(500)
createdAt DateTime @default(now()) @map("created_at")
account SystemAccount @relation(fields: [accountId], references: [id])
@@index([accountId, createdAt(sort: Desc)], name: "idx_system_ledger_account_created")
@@index([sourceOrderId], name: "idx_system_ledger_source_order")
@@index([txHash], name: "idx_system_ledger_tx_hash")
@@map("system_account_ledgers")
}
// ============ 权益有效性考核记录表 ============
// 专门记录权益激活/续期/失效的考核历史
// 与 MonthlyAssessment (火柴人排名) 分离,避免职责混淆
model BenefitAssessmentRecord {
id String @id @default(uuid())
authorizationId String @map("authorization_id")
userId String @map("user_id")
accountSequence String @map("account_sequence")
roleType RoleType @map("role_type")
regionCode String @map("region_code")
regionName String @map("region_name")
// 考核月份
assessmentMonth String @map("assessment_month") // YYYY-MM
monthIndex Int @map("month_index") // 第几个月考核
// 考核目标
monthlyTarget Int @map("monthly_target") // 当月目标
cumulativeTarget Int @map("cumulative_target") // 累计目标
// 完成情况
treesCompleted Int @map("trees_completed") // 实际完成数
treesRequired Int @map("trees_required") // 需要达到的数量(用于续期判定)
// 权益状态变化
benefitActionTaken BenefitActionType @map("benefit_action_taken") // RENEWED / DEACTIVATED / ACTIVATED
previousBenefitStatus Boolean @map("previous_benefit_status") // 考核前权益状态
newBenefitStatus Boolean @map("new_benefit_status") // 考核后权益状态
newValidUntil DateTime? @map("new_valid_until") // 新的有效期截止日
// 考核结果
result AssessmentResult @default(NOT_ASSESSED)
// 备注
remarks String? @map("remarks") @db.VarChar(500)
// 时间戳
assessedAt DateTime @map("assessed_at")
createdAt DateTime @default(now()) @map("created_at")
@@unique([authorizationId, assessmentMonth])
@@index([accountSequence, assessmentMonth])
@@index([userId, assessmentMonth])
@@index([roleType, regionCode, assessmentMonth])
@@index([assessmentMonth, result])
@@map("benefit_assessment_records")
}
// ============ 权益操作类型枚举 ============
enum BenefitActionType {
ACTIVATED // 首次激活
RENEWED // 续期
DEACTIVATED // 失效
NO_CHANGE // 无变化(未到考核时间)
}
// ============================================
// Outbox 事件表 - 保证事件可靠发送
// 使用 Outbox Pattern 确保领域事件100%送达
// ============================================
model OutboxEvent {
id BigInt @id @default(autoincrement()) @map("outbox_id")
// 事件信息
eventType String @map("event_type") @db.VarChar(100)
topic String @map("topic") @db.VarChar(100)
key String @map("key") @db.VarChar(200)
payload Json @map("payload")
// 聚合根信息 (用于幂等性检查)
aggregateId String @map("aggregate_id") @db.VarChar(100)
aggregateType String @map("aggregate_type") @db.VarChar(50)
// 发布状态: PENDING, SENT, CONFIRMED, FAILED
status String @default("PENDING") @map("status") @db.VarChar(20)
retryCount Int @default(0) @map("retry_count")
maxRetries Int @default(5) @map("max_retries")
lastError String? @map("last_error") @db.Text
// 时间戳
createdAt DateTime @default(now()) @map("created_at")
publishedAt DateTime? @map("published_at")
nextRetryAt DateTime? @map("next_retry_at")
@@index([status, createdAt])
@@index([status, nextRetryAt])
@@index([aggregateType, aggregateId])
@@index([topic])
@@map("outbox_events")
}