// 答题红包APP - Prisma Schema(兼容MySQL) generator client { provider = "prisma-client-js" } datasource db { provider = "mysql" url = env("DATABASE_URL") } // 用户模型 model User { id Int @id @default(autoincrement()) phone String @unique deviceId String? @map("device_id") nickname String? @map("nickname") goldBalance Int @default(0) @map("gold_balance") totalCorrect Int @default(0) @map("total_correct") totalAnswers Int @default(0) @map("total_answers") correctAnswers Int @default(0) @map("correct_answers") alipayAccount String? @map("alipay_account") realName String? @map("real_name") status Int @default(1) @map("status") // 0-禁用, 1-正常, 2-冻结 lastLoginAt DateTime? @map("last_login_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // 关联关系 goldLogs GoldLog[] withdrawRequests WithdrawRequest[] answerRecords AnswerRecord[] sessions UserSession[] signRecords SignRecord[] taskRecords TaskRecord[] adWatchRecords AdWatchRecord[] feedbacks Feedback[] userDevices UserDevice[] @@map("users") } // 金币流水模型 model GoldLog { id Int @id @default(autoincrement()) userId Int @map("user_id") amount Int type Int // 1-答题广告奖励, 2-提现扣除, 3-提现退回, 4-提现取消退回, 5-管理员调整, 6-任务奖励, 7-广告奖励, 8-签到奖励, 9-红包奖励 typeStr String? @map("type_str") // 字符串类型:redpacket, redpacket_reward, etc. referenceId String? @map("reference_id") remark String? @map("remark") createdAt DateTime @default(now()) @map("created_at") // 关联关系 user User @relation(fields: [userId], references: [id]) @@map("gold_logs") @@index([userId]) @@index([createdAt]) } // 提现申请模型 model WithdrawRequest { id Int @id @default(autoincrement()) userId Int @map("user_id") amountCny Float @map("amount_cny") goldCost Int @map("gold_cost") alipayAccount String @map("alipay_account") realName String @map("real_name") status Int @default(0) // 0-待审核, 1-已打款, 2-已拒绝 adminRemark String? @map("admin_remark") createdAt DateTime @default(now()) @map("created_at") processedAt DateTime? @map("processed_at") // 关联关系 user User @relation(fields: [userId], references: [id]) @@map("withdraw_requests") @@index([userId]) @@index([status]) @@index([createdAt]) } // 题目模型 // 题目分类模型 model QuestionCategory { id Int @id @default(autoincrement()) name String @unique icon String? order Int @default(0) createdAt DateTime @default(now()) @map("created_at") // 关联关系 questions Question[] @@map("question_categories") } // 题目模型 model Question { id Int @id @default(autoincrement()) title String content String? image String? difficulty Int @default(1) // 1-简单, 2-中等, 3-困难 goldReward Int @default(10) @map("gold_reward") explanation String? categoryId Int? @map("category_id") timesAnswered Int @default(0) @map("times_answered") timesCorrect Int @default(0) @map("times_correct") createdAt DateTime @default(now()) @map("created_at") // 关联关系 category QuestionCategory? @relation(fields: [categoryId], references: [id]) options QuestionOption[] answerRecords AnswerRecord[] @@map("questions") @@index([categoryId]) @@index([difficulty]) @@index([createdAt]) @@unique([title]) } // 题目选项模型 model QuestionOption { id Int @id @default(autoincrement()) questionId Int @map("question_id") content String isCorrect Boolean @default(false) @map("is_correct") order Int @default(0) createdAt DateTime @default(now()) @map("created_at") // 关联关系 question Question @relation(fields: [questionId], references: [id]) @@map("question_options") @@index([questionId]) @@unique([questionId, order]) } // 答题记录模型 model AnswerRecord { id Int @id @default(autoincrement()) userId Int @map("user_id") questionId Int @map("question_id") isCorrect Boolean @map("is_correct") goldReward Int? @map("gold_reward") adWatched Boolean @default(false) @map("ad_watched") createdAt DateTime @default(now()) @map("created_at") // 关联关系 user User @relation(fields: [userId], references: [id]) question Question @relation(fields: [questionId], references: [id]) @@map("answer_records") @@index([userId]) @@index([createdAt]) @@index([userId, createdAt]) } // 短信验证码模型 model SMSCode { id Int @id @default(autoincrement()) phone String code String type String @default("LOGIN") // LOGIN, REGISTER, RESET_PASSWORD used Boolean @default(false) expiresAt DateTime @map("expires_at") createdAt DateTime @default(now()) @map("created_at") @@map("sms_codes") @@index([phone]) @@index([expiresAt]) } // 用户会话模型 model UserSession { id Int @id @default(autoincrement()) userId Int @map("user_id") token String @unique expiresAt DateTime @map("expires_at") createdAt DateTime @default(now()) @map("created_at") // 关联关系 user User @relation(fields: [userId], references: [id]) @@map("user_sessions") @@index([userId]) @@index([expiresAt]) @@index([token]) } // 签到记录模型 model SignRecord { id Int @id @default(autoincrement()) userId Int @map("user_id") date DateTime @map("date") goldReward Int @default(0) @map("gold_reward") consecutiveDays Int @default(1) @map("consecutive_days") createdAt DateTime @default(now()) @map("created_at") // 关联关系 user User @relation(fields: [userId], references: [id]) @@map("sign_records") @@unique([userId, date]) @@index([userId]) @@index([date]) } // 任务记录模型 model TaskRecord { id Int @id @default(autoincrement()) userId Int @map("user_id") taskId String @map("task_id") date DateTime @map("date") completed Boolean @default(false) claimed Boolean @default(false) createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // 关联关系 user User @relation(fields: [userId], references: [id]) @@map("task_records") @@unique([userId, taskId, date]) @@index([userId]) @@index([taskId]) @@index([date]) } // 广告观看记录模型 model AdWatchRecord { id Int @id @default(autoincrement()) userId Int @map("user_id") adType String @default("video") @map("ad_type") // video, banner, interstitial goldReward Int @default(0) @map("gold_reward") createdAt DateTime @default(now()) @map("created_at") // 关联关系 user User @relation(fields: [userId], references: [id]) @@map("ad_watch_records") @@index([userId]) @@index([createdAt]) @@index([userId, createdAt]) } // 系统配置模型 model SystemConfig { id Int @id @default(autoincrement()) key String @unique value String description String? updatedAt DateTime @updatedAt @map("updated_at") updatedBy Int? @map("updated_by") @@map("system_configs") @@index([key]) } // 公告模型 - 用于APP轮播公告 model Announcement { id Int @id @default(autoincrement()) title String @map("title") // 公告标题 content String @map("content") // 公告内容 type Int @default(1) @map("type") // 1-安全提示, 2-活动公告, 3-系统通知 priority Int @default(0) @map("priority") // 优先级,数字越大越靠前 status String @default("active") @map("status") // active, inactive, deleted enabled Boolean @default(true) @map("enabled") // 是否启用 startTime DateTime? @map("start_time") // 开始时间 endTime DateTime? @map("end_time") // 结束时间 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("announcements") @@index([enabled]) @@index([priority]) @@index([status]) } // 机器人发言模型 - 用于红包群聊天 model RobotMessage { id Int @id @default(autoincrement()) userId Int? @map("user_id") // 关联用户ID(可选) content String @map("content") // 发言内容 type String @default("normal") @map("type") // normal-普通, reminder-提醒, answer-答题提醒 status String @default("active") @map("status") // pending, active, inactive, sent scheduledAt DateTime? @map("scheduled_at") // 定时发送时间 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("robot_messages") @@index([status]) @@index([type]) @@index([scheduledAt]) } // 红包活动配置模型 model RedPacketConfig { id Int @id @default(autoincrement()) name String @map("name") // 配置名称 enabled Boolean @default(true) @map("enabled") // 是否启用 minAmount Float @default(0.1) @map("min_amount") // 最小金额 maxAmount Float @default(1.0) @map("max_amount") // 最大金额 intervalSeconds Int @default(30) @map("interval_seconds") // 发放间隔(秒) startHour Int @default(0) @map("start_hour") // 开始小时(0-23) endHour Int @default(23) @map("end_hour") // 结束小时(0-23) dailyLimit Int @default(100) @map("daily_limit") // 每日发放上限 todayCount Int @default(0) @map("today_count") // 今日已发放 lastSentAt DateTime? @map("last_sent_at") // 上次发放时间 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("red_packet_configs") } // 管理员操作日志 model AdminLog { id Int @id @default(autoincrement()) adminId Int? @map("admin_id") // 管理员ID(如果已登录) adminPhone String @map("admin_phone") // 管理员手机号 action String @map("action") // 操作类型 targetType String @map("target_type") // 操作对象类型(user, question, withdrawal等) targetId String? @map("target_id") // 操作对象ID detail String? @map("detail") // 操作详情 ip String? @map("ip") // IP地址 userAgent String? @map("user_agent") // 浏览器信息 createdAt DateTime @default(now()) @map("created_at") @@map("admin_logs") @@index([adminId]) @@index([action]) @@index([createdAt]) } // 答题日志模型(用于统计) model AnswerLog { id Int @id @default(autoincrement()) userId Int @map("user_id") questionId Int @map("question_id") isCorrect Boolean @map("is_correct") answerTime Int? @map("answer_time") // 答题耗时(毫秒) createdAt DateTime @default(now()) @map("created_at") @@map("answer_logs") @@index([userId]) @@index([questionId]) @@index([createdAt]) } // 系统设置模型 model SystemSetting { id Int @id @default(autoincrement()) key String @unique @map("key") value String @map("value") category String? @map("category") // 设置分类 description String? @map("description") // 设置描述 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("system_settings") @@index([key]) @@index([category]) } // 系统日志模型 model SystemLog { id Int @id @default(autoincrement()) level String @default("info") @map("level") // info, warn, error message String @map("message") context String? @map("context") // JSON格式的上下文 ip String? @map("ip") createdAt DateTime @default(now()) @map("created_at") @@map("system_logs") @@index([level]) @@index([createdAt]) } // 管理员操作日志(扩展) model AdminActionLog { id Int @id @default(autoincrement()) adminId Int? @map("admin_id") adminPhone String? @map("admin_phone") action String @map("action") targetType String? @map("target_type") targetId Int? @map("target_id") detail String? @map("detail") ip String? @map("ip") createdAt DateTime @default(now()) @map("created_at") @@map("admin_action_logs") @@index([adminId]) @@index([action]) @@index([createdAt]) } // 用户意见反馈模型 model Feedback { id Int @id @default(autoincrement()) userId Int @map("user_id") type String @default("suggestion") @map("type") // suggestion-建议, bug-反馈, other-其他 title String? @map("title") // 反馈标题 content String @map("content") // 反馈内容 images String? @map("images") // 图片URL,逗号分隔 contact String? @map("contact") // 联系方式 status String @default("pending") @map("status") // pending-待处理, processing-处理中, resolved-已解决, rejected-已拒绝 adminReply String? @map("admin_reply") // 管理员回复 adminReplyAt DateTime? @map("admin_reply_at") // 回复时间 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // 关联关系 user User? @relation(fields: [userId], references: [id]) replies FeedbackReply[] @@map("feedbacks") @@index([userId]) @@index([status]) @@index([type]) @@index([createdAt]) } // 推送通知模型 model PushNotification { id Int @id @default(autoincrement()) title String @map("title") // 通知标题 content String @map("content") // 通知内容 type String @default("all") @map("type") // all-全部用户, specific-指定用户, tag-标签用户 targetUsers String? @map("target_users") // 指定用户ID,逗号分隔 targetTags String? @map("target_tags") // 指定标签 status String @default("pending") @map("status") // pending-待发送, sending-发送中, sent-已发送, failed-发送失败 scheduledAt DateTime? @map("scheduled_at") // 定时发送时间 sentAt DateTime? @map("sent_at") // 实际发送时间 totalSent Int @default(0) @map("total_sent") // 已发送数量 totalFailed Int @default(0) @map("total_failed") // 发送失败数量 clickCount Int @default(0) @map("click_count") // 点击数量 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("push_notifications") @@index([status]) @@index([type]) @@index([scheduledAt]) @@index([createdAt]) } // 系统协议模型(用户协议、隐私政策等) model SystemAgreement { id Int @id @default(autoincrement()) type String @unique @map("type") // user_agreement-用户协议, privacy_policy-隐私政策 title String @map("title") // 协议标题 content String @map("content") // 协议内容(富文本/HTML) version String @default("1.0.0") @map("version") // 版本号 status String @default("active") @map("status") // active-生效, inactive-未生效, archived-已归档 effectiveAt DateTime? @map("effective_at") // 生效时间 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("system_agreements") @@index([type]) @@index([status]) } // 系统弹窗公告模型 model Popup { id Int @id @default(autoincrement()) title String @map("title") // 弹窗标题 content String @map("content") // 弹窗内容 type String @default("info") @map("type") // info-信息, warning-警告, success-成功, error-错误 buttonText String @default("确定") @map("button_text") // 按钮文字 linkUrl String? @map("link_url") // 点击跳转链接 priority Int @default(0) @map("priority") // 优先级 status String @default("active") @map("status") // active-显示, inactive-隐藏 startTime DateTime? @map("start_time") // 开始时间 endTime DateTime? @map("end_time") // 结束时间 showOnce Boolean @default(false) @map("show_once") // 每个用户只显示一次 createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("popups") @@index([status]) @@index([priority]) @@index([startTime]) } // 意见反馈回复模型 model FeedbackReply { id Int @id @default(autoincrement()) feedbackId Int @map("feedback_id") adminId Int? @map("admin_id") adminPhone String? @map("admin_phone") content String @map("content") createdAt DateTime @default(now()) @map("created_at") // 关联关系 feedback Feedback @relation(fields: [feedbackId], references: [id], onDelete: Cascade) @@map("feedback_replies") } // ========== 风控相关模型 ========== // 设备指纹模型 model DeviceFingerprint { id Int @id @default(autoincrement()) fingerprint String @unique @map("fingerprint") // 设备指纹(唯一标识) androidId String? @map("android_id") // Android ID brand String? @map("brand") // 品牌 model String? @map("model") // 型号 device String? @map("device") // 设备名 manufacturer String? @map("manufacturer") // 制造商 sdkVersion Int? @map("sdk_version") // SDK版本 releaseVersion String? @map("release_version") // 系统版本 isEmulator Boolean @default(false) @map("is_emulator") // 是否模拟器 isRooted Boolean @default(false) @map("is_rooted") // 是否Root isDeveloperMode Boolean @default(false) @map("is_developer_mode") // 是否开发者模式 isMultiApp Boolean @default(false) @map("is_multi_app") // 是否多开 isXposed Boolean @default(false) @map("is_xposed") // 是否Xposed isBlocked Boolean @default(false) @map("is_blocked") // 是否封禁 blockReason String? @map("block_reason") // 封禁原因 riskScore Int @default(0) @map("risk_score") // 风险评分 0-100 firstSeenAt DateTime @default(now()) @map("first_seen_at") lastSeenAt DateTime @default(now()) @map("last_seen_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // 关联关系 userDevices UserDevice[] @@map("device_fingerprints") @@index([fingerprint]) @@index([androidId]) @@index([isBlocked]) @@index([riskScore]) } // 用户设备关联模型 model UserDevice { id Int @id @default(autoincrement()) userId Int @map("user_id") deviceId Int @map("device_id") lastIp String? @map("last_ip") // 最后登录IP loginCount Int @default(0) @map("login_count") // 登录次数 firstLoginAt DateTime @default(now()) @map("first_login_at") lastLoginAt DateTime @default(now()) @map("last_login_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") // 关联关系 user User @relation(fields: [userId], references: [id]) device DeviceFingerprint @relation(fields: [deviceId], references: [id]) @@map("user_devices") @@unique([userId, deviceId]) @@index([userId]) @@index([deviceId]) @@index([lastIp]) } // 答题风控日志模型 model AnswerRiskLog { id Int @id @default(autoincrement()) userId Int @map("user_id") questionId Int @map("question_id") isCorrect Boolean @map("is_correct") answerTime Int @map("answer_time") // 答题时间(毫秒) riskType String? @map("risk_type") // 风险类型:fast_answer, high_accuracy, pattern_match riskScore Int @default(0) @map("risk_score") // 风险分 detail String? @map("detail") // 详情JSON createdAt DateTime @default(now()) @map("created_at") @@map("answer_risk_logs") @@index([userId]) @@index([riskType]) @@index([createdAt]) } // IP风控模型 model IpRiskControl { id Int @id @default(autoincrement()) ip String @unique @map("ip") riskLevel Int @default(0) @map("risk_level") // 0-正常, 1-低风险, 2-中风险, 3-高风险 riskReason String? @map("risk_reason") // 风险原因 isProxy Boolean @default(false) @map("is_proxy") // 是否代理 isDatacenter Boolean @default(false) @map("is_datacenter") // 是否机房IP isVpn Boolean @default(false) @map("is_vpn") // 是否VPN requestCount Int @default(0) @map("request_count") // 请求次数 lastRequestAt DateTime? @map("last_request_at") createdAt DateTime @default(now()) @map("created_at") updatedAt DateTime @updatedAt @map("updated_at") @@map("ip_risk_controls") @@index([ip]) @@index([riskLevel]) } // 滑块验证记录模型 model SliderVerification { id Int @id @default(autoincrement()) userId Int? @map("user_id") deviceId String? @map("device_id") type String @map("type") // login, withdraw, answer success Boolean @map("success") attemptCount Int @default(1) @map("attempt_count") ip String? @map("ip") createdAt DateTime @default(now()) @map("created_at") @@map("slider_verifications") @@index([userId]) @@index([deviceId]) @@index([type]) @@index([createdAt]) } // 短信发送日志模型 model SmsLog { id Int @id @default(autoincrement()) phoneNumber String @map("phone_number") code String @map("code") templateId String @map("template_id") requestId String? @map("request_id") status String @map("status") message String? @map("message") createdAt DateTime @default(now()) @map("created_at") @@map("sms_logs") @@index([phoneNumber]) @@index([createdAt]) }