短视频应用开发文档
- 版本:v1.0
- 日期:2026-10-14
- 适用端:Flutter App(iOS / Android)、Python 后端
1. 项目介绍
1.1 项目概述
一款竖屏沉浸式短视频应用(产品形态参考抖音/快手)。核心商业模式为:
免费额度 + 积分付费观看 + 会员订阅
- 所有用户(含游客)每天可免费观看 10 个视频
- 超出免费额度后,注册用户每观看 1 个视频消耗 1 积分,游客需注册/登录
- 积分通过充值获得(支付宝 / 微信 / USDT),1 元 = 10 积分
- 积分可开通会员,会员享有无限观看和优先上传权益
- 用户可通过评论赚取积分(每评论 10 个视频奖励 1 积分),形成内容互动激励闭环
1.2 项目组成
1.3 名词定义
| 名词 |
定义 |
| 游客 |
未注册/未登录用户,以设备 ID(device_id)标识 |
| 注册用户 |
通过手机号或邮箱注册并登录的用户 |
| 会员 |
开通体验/月卡/年卡/终身卡且在有效期内的注册用户 |
| 积分 |
平台虚拟货币,1 元 = 10 积分,用于观看扣费、开通会员 |
| 免费额度 |
每个计费主体(游客=设备,注册用户=账号)每天可免费观看的视频数,默认 10 个 |
| 计费主体 |
观看计费的统计单位:注册用户为 user_id,游客为 device_id |
| 资产 |
创作者激励体系的虚拟货币,10 资产 = 1 元,存放于资产钱包,可提现 |
| 推荐人/被推荐人 |
通过邀请码绑定的邀请关系双方;推荐人须为会员方可获得奖励 |
2. 功能介绍
2.1 用户模块
2.1.1 游客模式
- 无需注册登录,打开 App 即可观看视频
- App 首次启动生成唯一 device_id 并本地持久化,之后所有请求携带
X-Device-ID 头
- 游客每天可免费观看 10 个视频,第 11 个视频弹出登录/注册引导
- 游客不可点赞、收藏、评论、上传
2.1.2 注册
- 优先手机号注册:手机号 + 短信验证码 + 密码
- 备选邮箱注册:邮箱 + 邮箱验证码 + 密码
- 注册即登录,返回 Token
- 约束:手机号/邮箱全局唯一;密码 ≥ 8 位,含字母和数字
2.1.3 登录
- 手机号 + 密码,或 手机号 + 短信验证码
- 邮箱 + 密码
- 登录成功后,游客时期的设备 ID 与账号可关联(观看记录合并,可选)
2.1.4 资料管理
- 昵称(默认"用户+尾号")、头像、性别、个人简介
- 修改手机号/邮箱需验证码验证
2.1.5 找回密码与账号注销
- 找回密码:已验证的手机号/邮箱 + 验证码 + 新密码完成重置(
POST /auth/password/reset),重置后旧 Token 全部失效
- 账号注销:用户主动发起 → 7 天冻结期(期间登录即撤销)→ 到期匿名化:手机号/邮箱置空释放、昵称头像清空、作品全部下架、钱包余额清零作废、Token 立即失效
2.2 观看与计费模块(核心业务)
2.2.1 计费规则
- 会员:观看不限量,不消耗免费额度与积分
- 非会员(含游客):每个计费主体每天前 10 个不同视频免费
- 免费额度用完后:注册用户每看 1 个视频扣 1 积分;游客拦截并引导登录
- 所有"每日"口径均按 Asia/Shanghai(服务器时区)0 点切分
- 积分余额不足:拦截播放,引导充值或开通会员
2.2.2 计费判定流程
2.2.3 补充规则(对需求的完善)
- 同日去重:同一视频当天重复观看,不重复占用免费额度、不重复扣积分
- 自己的视频免费:观看自己上传的视频不计费、不占额度
- 扣费时点:开始播放即扣费(播放页加载完成上报),简单可解释;退款场景(视频违规下架)通过后台人工处理
- 额度重置:每日 00:00(服务器时区)重置,免费额度不可累积
- 观看记录:所有观看(免费/扣费)均记录,用于历史列表与风控分析
2.3 积分模块
2.3.1 积分获取
| 途径 |
规则 |
| 充值 |
支付宝/微信/USDT 支付成功到账,1 元 = 10 积分 |
| 评论奖励 |
每评论满 10 个不同视频,奖励 1 积分(循环累计,进度清零重新计) |
| 推荐奖励 |
会员邀请的新用户激活后,推荐人获 N 积分(默认 10,可配置),见 2.8 |
| 活动赠送 |
后台手动发放(含体验会员赠送活动) |
2.3.2 积分消耗
| 场景 |
规则 |
| 观看视频 |
免费额度用完后,1 积分/个 |
| 开通会员 |
按套餐价扣减(见 2.4) |
2.3.3 评论奖励防刷规则(完善项)
- 评论内容长度 ≥ 5 字才计入进度
- 同一视频仅首次有效评论计入进度
- 评论被删除(自删/违规)时,已计入的进度回退;已发放奖励的扣回(余额可为负,后续充值抵扣)
- 每日评论奖励上限 5 积分(可配置)
- 同一用户短时间高频评论触发限流(如 10 条/分钟)
2.3.4 积分流水
- 所有积分变动必须写入积分流水表(变动值、变动后余额、业务类型、关联单据)
- 流水是积分对账、客服处理、风控审计的唯一依据
2.4 会员模块
2.4.1 会员类型(价格/时长均可在配置文件中修改)
| 类型 |
时长 |
价格(积分) |
获取方式 |
| 体验会员 |
1 天 |
默认 5 积分(可配置) |
活动赠送 / 积分开通 |
| 月卡 |
30 天 |
300 |
积分开通 |
| 年卡 |
365 天 |
3650 |
积分开通 |
| 终身卡 |
永久 |
10000 |
积分开通 |
注:按 1 元 = 10 积分折算,即月卡=30 元、年卡=365 元、终身卡=1000 元。各套餐时长与价格均为默认值,可在配置文件中调整。
2.4.2 会员权益
- 无限观看:不消耗免费额度和积分
- 优先上传:转码队列优先、审核队列优先
2.4.3 会员规则(完善项)
- 必须注册登录才能开通和使用会员
- 有效期内重复开通:有效期叠加(如月卡剩余 10 天再开月卡 → 40 天)
- 已是终身卡:不可再开通其它套餐(前端置灰)
- 体验会员与付费卡互斥逻辑:体验会员期间开通付费卡,按付费卡生效(体验剩余时间不累加,避免活动滥用)
- 到期自动失效,不自动续费(当前无连续包月需求)
- 新注册赠送:新用户注册成功即赠送体验会员(默认 1 天),管理后台可配置开关与天数(system_configs:
register_gift_trial.enabled / register_gift_trial.days),关闭后注册不再赠送,实时生效
2.5 视频模块
2.5.1 视频上传
- 主流程:App 选择本地视频(mp4 等)→ 上传至服务端/对象存储 → 服务端 FFmpeg 转码为 HLS(m3u8 + ts 分片) → 生成封面 → 提交审核 → 发布
- 兼容流程:也支持直接上传已转码好的 m3u8 + ts 文件包(服务端校验分片完整性后直接进入审核)
- 上传限制:单文件 ≤ 500MB、时长 5 秒 ~ 10 分钟(可配置)
- 会员"优先上传":转码任务进入高优先级队列,优先被消费
2.5.2 视频转码
- 统一转 HLS:1080p 源 → 输出 720p(默认),可配置多码率(1080/720/480)自适应
- 从视频第 1 秒截取封面图
- 转码失败自动重试 3 次,仍失败则标记失败并通知作者
2.5.3 视频审核
- 状态机:
转码中 → 待审核 → 已发布 / 审核拒绝 / 已下架
- 一期采用管理后台人工审核:审核员在后台在线预览视频,执行 通过 / 拒绝(填写原因),通过后自动发布上架
- 仅"已发布"状态进入推荐流
2.5.4 视频播放
- m3u8(HLS)流媒体播放,App 竖屏全屏沉浸式播放
- 上滑/下滑切换视频,预加载下一个视频
- 记录播放量(进入播放即 +1,Redis 计数异步落库)
2.5.5 视频标签(Tag)
- 发布视频时可填写 0
5 个标签,每个标签 120 字(字母/数字/中文/下划线)
- 播放页在标题后展示标签(#标签 样式)
- 点击标签进入"标签视频列表页":展示该标签下全部已发布视频(支持 热度/最新 排序)
- 标签是推荐策略中个性化加权的主要特征
2.5.6 视频推荐策略
Feed 支持三种策略,客户端通过接口参数切换:
| 策略 |
说明 |
| recommend(默认) |
个性化推荐 |
| latest |
最新发布倒序 |
| hot |
热度倒序(播放/点赞/评论加权) |
个性化推荐(recommend)规则:
- 候选池:全部"已发布"视频
- 个性化打分:统计用户近 7 天观看/点赞/收藏视频的标签,得出偏好标签及权重,候选视频命中偏好标签加权;游客与无行为新用户退化为热度分
- 每日重排:以"当天日期 + 用户/设备"为随机种子对候选池确定性洗牌,保证同一用户每天的推荐顺序都不一样,且同一天内多次刷新顺序稳定(翻页不混乱)
- 当日去重:当天已观看过的视频尽量不再出现在推荐流中;候选池耗尽时放开过滤兜底,避免 Feed 刷空
2.5.7 作品管理(作者)
- 编辑:作者可修改自己视频的标题/描述/分类/标签,仅元信息变更,不影响已发布状态、不重新触发审核(视频文件不可替换)
- 删除:作者可删除自己视频 → 软删除(status=5 已删除),立即从 Feed/搜索/标签页下架;播放/点赞等历史数据保留用于对账,资产结算即刻停止
- 两个操作仅作者本人可用(非作者返回 2107)
2.5.8 搜索
- 一期:按标题、标签做关键词匹配(MySQL LIKE / FULLTEXT),支持 最新/热度 排序;二期接 Elasticsearch
- 热搜词:近 24h 搜索频次 Top10(Redis ZSet 统计,每小时截断)
- 搜索历史:App 端本地存储最近 10 条,不上报服务端
- 搜索词先过敏感词过滤,命中直接返回空结果
2.6 互动模块
| 功能 |
规则 |
| 点赞 |
仅登录用户;同一视频重复点击为取消;视频表冗余 like_count;唯一约束防重 |
| 收藏 |
仅登录用户;同上;个人中心可查看收藏列表 |
| 评论 |
仅登录用户;支持一级评论和楼中楼回复(二级);作者可删除自己视频下的评论;评论计数入奖励进度 |
2.6.4 消息通知
- 类型:审核结果(视频通过/拒绝)、提现进度(通过打款/拒绝退回)、系统公告、评论回复
- 触发即写 notifications 表,Redis 维护未读数;App 我的页消息入口带红点
- 通知为站内信,一期不做 App 推送(push 二期接厂商通道)
2.6.5 举报
- 举报对象:视频、评论;原因分类:色情低俗/暴力血腥/侵权/广告营销/其他
- 同一用户对同一对象仅可举报一次(唯一约束,重复返回 2106)
- 后台处理动作:下架视频 / 删除评论 / 驳回;处理结果通过消息通知告知举报人
- 举报不自动处置内容,全部人工决策
2.6.6 敏感词过滤
- 评论、昵称、视频标题/描述/标签、搜索词均先过敏感词库(DFA 算法),命中拒绝并返回 2105
- 词库由运营在管理后台维护(sensitive_words 表),服务端 Redis 缓存 60s
2.7 支付模块
2.7.1 充值套餐(管理后台可在线调整)
- 默认档位:10 / 30 / 100 / 200 元,另开放自定义金额(1~10000 元)
- 到账规则:1 元 = 10 积分;档位可单独配置"赠送积分"(如充 100 元赠 50 积分)
- 档位存储于数据库
recharge_packages 表,管理后台实时增删改、上下架、排序,无需改配置、无需重启服务
2.7.2 支付方式
| 方式 |
方案 |
说明 |
| 支付宝 |
支付宝开放平台 App 支付 |
服务端下单生成 orderString → App 调起 SDK → 异步回调到账 |
| 微信支付 |
微信支付 V3 App 支付 |
服务端下单 prepay → App 调起 SDK → 异步回调验签到账 |
| USDT |
TRC20 链上收款 |
配置固定收款地址 + 汇率;订单生成"唯一金额"(如 30 USDT + 0.001~0.999 随机尾差),服务端轮询 TronGrid 匹配金额与时间窗,满 19 个确认后入账 |
2.7.3 支付通用规则(完善项)
- 订单有效期 30 分钟,超时自动关闭
- 到账必须幂等:以第三方流水号/tx_hash 唯一约束防重复入账
- 到账在数据库事务内完成:更新订单状态 + 钱包加积分 + 写积分流水,三步原子
- 回调验签失败、金额不匹配一律拒绝并告警
- 所有支付参数(商户号、密钥、证书、USDT 地址/汇率)走配置文件/环境变量,不入库、不进代码仓库
2.7.4 退款规则
- 发起:仅运营/客服在支付平台商户后台(支付宝/微信)人工发起退款;USDT 订单不支持自动退款(人工链上退回并线下登记)
- 系统处理(退款回调或后台人工登记后):
- 订单状态置为 refunded
- 扣回该订单已发放积分(余额允许为负,后续充值先抵扣负数;负余额用户禁止积分消费)
- 扣回推荐人已获得的该笔充值返利资产(biz_type=6,资产允许为负)
- 退款不改变已发生的观看/会员事实(会员不回收,防止复杂对穿,运营层面约束)
2.8 推荐与创作者激励(资产体系)
平台在积分之外设有资产钱包:资产可提现,与人民币固定换算 10 资产 = 1 元(与积分同量纲,比例可配置)。所有资产变动写资产流水,变更规范与积分一致(行锁 + 流水 + 乐观锁)。
2.8.1 推荐奖励(会员邀请新用户)
- 每位用户注册自动生成邀请码/邀请链接;推荐人须为会员才产生奖励(发放时点校验会员身份)
- 新用户注册时通过邀请码/分享口令/推广链接自动归因完成绑定(归因方案见 2.8.2),注册后 24h 内可补绑,每人仅能绑定 1 个推荐人
- 被推荐人"激活"(注册 72h 内累计观看 ≥3 个视频,且次日有登录)后,推荐人获得 N 积分(默认 10,可配置),不限量
- 充值返利:被推荐人每次充值成功,推荐人获得"充值积分 × 5%"的资产(不限量,比例可配置);订单退款时对应返利扣回(资产余额允许为负,后续收益抵扣)
2.8.2 推广归因(邀请链接 / 分享口令 / 模糊匹配)
用户通过推广链接下载 App,安装注册后自动识别推荐人。采用三段式自建归因方案(不依赖第三方 SDK):
| 优先级 |
路径 |
说明 |
| 1(主路径) |
分享口令 |
推广文案内含 #短视频邀请码XXXXXXXX# 口令,被邀请人复制后首次打开 App,客户端解析剪贴板 → 注册页自动预填邀请码,准确率 100% |
| 2(辅助路径) |
H5 落地页点击埋点 + 模糊匹配 |
推广链接 /r/{code} 打开 H5 落地页时自动上报点击(code+IP+UA 存 Redis 24h);App 首启无口令时上报 device_id,服务端按 IP 就近匹配点击记录,命中结果按 device_id 服务端缓存(7 天),注册时自动带出 |
| 3(兜底) |
注册页手填邀请码 |
注册表单邀请码选填;注册后 24h 内还可在"邀请好友"页补绑(/referral/bind) |
- 归因结果由服务端按 device_id 缓存并一次性消费,不信任客户端回传,防止伪造归因
- 绑定优先级:显式 invite_code(口令/手填)> 模糊归因缓存;绑定沿用 2.8.3 全部风控规则
- 落地页展示邀请人昵称、复制口令按钮与 App 下载入口(下载地址由 system_configs
app.download_url 驱动,后台可配)
2.8.3 推荐防作弊规则
- 不可绑定自己;同 device_id 已存在账号的设备注册 → 绑定直接无效(防开小号)
- 注册 IP 与推荐人常用 IP 一致、或同 IP 24h 内注册 >5 个账号 → 标记风险
- 推荐人 24h 内新增绑定 >10 人 → 超出部分冻结
- 命中风控的绑定状态置为"风控冻结",奖励暂停发放,管理后台人工审核后可解冻或判无效
- 未激活的绑定不发放奖励;激活判定由定时任务执行
2.8.4 会员视频创作收益
仅会员发布的视频参与资产结算(结算时点校验作者会员身份;非会员期间数据持续累计,成为会员后按增量结算):
| 收益项 |
规则 |
说明 |
| 完整观看收益 |
每累计 1000 次完整观看 → 1 资产 |
完整观看=播放进度 ≥95% 或看到结尾;同一用户/设备同视频每日最多计 1 次;作者本人不计 |
| 点赞收益 |
每累计 100 次点赞 → 1 资产 |
以累计新增点赞计数;取消点赞回退计数,但已结算发放的资产不扣回 |
- 结算由定时任务每 5 分钟按增量执行,按视频独立保留余数(如 2500 次完整观看 → 发 2 资产,余 500 继续累计)
2.8.5 资产提现
- 满 100 资产(=10 元)可申请提现(门槛可配置)
- 渠道:支付宝 / 微信 / USDT;管理后台人工审核后打款
- 审核拒绝 → 资产原路退回资产钱包;同一时间仅允许一笔审核中的提现
2.9 管理后台(一期包含,Web 端)
独立 Web 管理后台,管理员账号体系与 App 用户完全隔离,分角色控制权限。
| 模块 |
功能 |
| 仪表盘 |
今日/累计:DAU、新增注册、充值金额、积分发放与消耗、播放量、待审核数 |
| 视频审核(人工) |
待审核列表(在线预览 m3u8)、通过、拒绝(必填原因)、已发布视频下架 |
| 用户管理 |
搜索(ID/手机号/邮箱)、用户详情(钱包/会员/作品/流水)、封禁与解封 |
| 积分管理 |
用户积分流水查询、手动加/减积分(原因必填 + 二次确认,写流水 biz_type=6) |
| 订单管理 |
充值订单查询(状态/渠道/时间筛选)、异常订单人工补单(核实已收款后手动入账) |
| 提现审核 |
提现申请列表、审核通过(线下打款后确认)/ 拒绝(自动退回资产) |
| 推荐风控 |
推荐关系查询(状态/风控标记筛选)、冻结记录解冻或判无效 |
| 平台配置 |
注册赠送体验会员开关与天数等运营参数(system_configs 键值对,实时生效) |
| 充值套餐管理 |
档位与赠送积分增删改、上下架、排序,实时生效 |
| 活动运营 |
赠送体验会员/积分(支持单个或批量用户) |
| 管理员管理 |
管理员账号增删、角色分配(超级管理员/审核员/运营)、操作日志查询 |
角色权限:超级管理员(全部)、审核员(仅视频审核)、运营(套餐/活动/看板)。
2.10 二期规划清单
- 关注/粉丝:预留,二期开放
- App 推送:厂商通道(评论回复、审核结果、提现进度等通知的 push)
- 搜索升级:Elasticsearch、搜索联想词
- 分享:视频分享链接/海报生成
- 趋势看板:管理后台 7/30 天数据曲线、订单导出 CSV
- 黑名单:用户拉黑、内容"不感兴趣"负反馈,深化个性化推荐
- 游客数据合并:注册后游客观看记录正式合并入账号
- 实名认证提示:充值环节按支付合规要求引导实名(依赖支付渠道商户资质)
- 运维:上传临时文件与拒绝视频分片的定时清理、SLO 指标(Feed <300ms、起播 <1.5s)、客户端埋点上报
2.11 合规提示
- 短视频平台运营涉及《网络文化经营许可证》《信息网络传播视听节目许可证》或备案要求,上架应用市场需提供对应资质,需提前规划
- 必须接内容审核,否则存在下架风险
- USDT 收款存在地区合规风险,请评估主体与运营地区法规
- iOS 虚拟支付合规:苹果要求 App 内虚拟商品(积分/会员)走 IAP,使用支付宝/微信支付存在拒审风险。对策:预留"iOS 支付开关"(system_configs:
ios_payment.enabled),审核期/风险期切换为引导用户到 H5 网页端充值;安卓端不受限
- 注册协议:注册页必须勾选《用户协议》与《隐私政策》后方可提交
3. 数据库设计
数据库选型:MySQL 8.0(InnoDB / utf8mb4),缓存与计数:Redis 7。
详细 DDL、索引策略见《02-技术文档》第 3 章,此处给出表结构定义。
3.1 表清单
| 表 |
说明 |
| users |
用户表 |
| user_wallets |
用户钱包(积分余额) |
| user_membership |
用户当前会员状态 |
| membership_orders |
会员开通记录 |
| videos |
视频表 |
| categories |
视频分类表 |
| comments |
评论表 |
| likes |
点赞表 |
| favorites |
收藏表 |
| watch_records |
观看记录表 |
| point_transactions |
积分流水表 |
| recharge_orders |
充值订单表 |
| transcode_tasks |
转码任务表 |
| tags |
标签表 |
| video_tags |
视频-标签关联表 |
| recharge_packages |
充值套餐表(后台可配) |
| admin_users |
管理员表 |
| admin_logs |
后台操作日志表 |
| referrals |
推荐关系表 |
| asset_wallets |
资产钱包表 |
| asset_transactions |
资产流水表 |
| withdrawals |
提现记录表 |
| video_earnings |
视频收益结算表 |
| notifications |
消息通知表 |
| reports |
举报表 |
| sensitive_words |
敏感词表 |
3.2 用户域
users 用户表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK AUTO_INCREMENT |
用户 ID |
| phone |
VARCHAR(20) NULL |
手机号,唯一索引,与 email 至少其一非空 |
| email |
VARCHAR(100) NULL |
邮箱,唯一索引 |
| password_hash |
VARCHAR(255) |
密码哈希(bcrypt) |
| nickname |
VARCHAR(50) |
昵称 |
| avatar_url |
VARCHAR(500) |
头像 URL |
| gender |
TINYINT DEFAULT 0 |
0未知 1男 2女 |
| bio |
VARCHAR(200) |
简介 |
| status |
TINYINT DEFAULT 1 |
1正常 2封禁 |
| register_type |
TINYINT |
1手机 2邮箱 |
| invite_code |
VARCHAR(10) |
我的邀请码,注册时自动生成,唯一索引 |
| register_ip |
VARCHAR(45) |
注册 IP(风控) |
| last_login_at |
DATETIME NULL |
最近登录时间(推荐激活判定用) |
| last_login_ip |
VARCHAR(45) |
最近登录 IP |
| created_at / updated_at |
DATETIME |
创建/更新时间 |
索引:uk_phone(phone)、uk_email(email)、uk_invite_code(invite_code)、idx_status_created(status, created_at)
user_wallets 钱包表
| 字段 |
类型 |
说明 |
| user_id |
BIGINT PK FK→users.id |
用户 ID |
| points |
INT UNSIGNED DEFAULT 0 |
当前积分余额 |
| total_recharge |
INT UNSIGNED DEFAULT 0 |
累计充值积分 |
| total_earned |
INT UNSIGNED DEFAULT 0 |
累计奖励积分 |
| total_consumed |
INT UNSIGNED DEFAULT 0 |
累计消耗积分 |
| version |
INT DEFAULT 0 |
乐观锁版本号 |
| updated_at |
DATETIME |
更新时间 |
余额变更必须走"行锁/乐观锁 + 流水",禁止直接 update 余额。
user_membership 当前会员状态表(冗余加速查询)
| 字段 |
类型 |
说明 |
| user_id |
BIGINT PK FK |
用户 ID |
| is_member |
TINYINT DEFAULT 0 |
是否会员(冗余,以 expire_at 判定为准) |
| current_plan |
VARCHAR(20) |
当前套餐:trial/month/year/lifetime |
| is_lifetime |
TINYINT DEFAULT 0 |
是否终身卡 |
| expire_at |
DATETIME NULL |
到期时间(终身卡为 NULL) |
| updated_at |
DATETIME |
|
membership_orders 会员开通记录表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| order_no |
VARCHAR(32) |
业务单号,唯一索引 |
| user_id |
BIGINT FK |
|
| plan_code |
VARCHAR(20) |
trial/month/year/lifetime |
| points_cost |
INT |
消耗积分(赠送为 0) |
| duration_days |
INT |
时长(0=终身) |
| start_at / end_at |
DATETIME |
生效/到期(终身 end_at 为 NULL) |
| source |
TINYINT |
1积分购买 2活动赠送 |
| created_at |
DATETIME |
|
索引:idx_user(user_id, created_at)
3.3 视频域
videos 视频表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| user_id |
BIGINT FK |
作者 |
| category_id |
INT |
分类 |
| title |
VARCHAR(100) |
标题 |
| description |
VARCHAR(500) |
描述 |
| cover_url |
VARCHAR(500) |
封面 URL |
| video_url |
VARCHAR(500) |
m3u8 播放地址 |
| duration |
INT |
时长(秒) |
| file_size |
BIGINT |
源文件大小 |
| width / height |
INT |
分辨率 |
| status |
TINYINT |
0转码中 1待审核 2已发布 3审核拒绝 4已下架 5转码失败 |
| reject_reason |
VARCHAR(200) |
拒绝/下架原因 |
| reviewer_id |
BIGINT NULL |
审核人(admin_users.id) |
| reviewed_at |
DATETIME NULL |
审核时间 |
| is_priority |
TINYINT DEFAULT 0 |
会员优先标记 |
| view_count |
BIGINT DEFAULT 0 |
播放量 |
| like_count |
INT DEFAULT 0 |
点赞数(冗余) |
| comment_count |
INT DEFAULT 0 |
评论数(冗余) |
| favorite_count |
INT DEFAULT 0 |
收藏数(冗余) |
| published_at |
DATETIME NULL |
发布时间 |
| created_at / updated_at |
DATETIME |
|
索引:idx_user_status(user_id, status)、idx_feed(status, published_at DESC)、idx_category(category_id, status)
categories 分类表
| 字段 |
类型 |
说明 |
| id |
INT PK |
|
| name |
VARCHAR(50) |
分类名 |
| sort |
INT DEFAULT 0 |
排序 |
| status |
TINYINT DEFAULT 1 |
1启用 0停用 |
transcode_tasks 转码任务表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| video_id |
BIGINT FK |
|
| source_url |
VARCHAR(500) |
源文件地址 |
| task_status |
TINYINT |
0排队 1转码中 2成功 3失败 |
| priority |
TINYINT DEFAULT 0 |
0普通 1优先(会员) |
| retry_count |
INT DEFAULT 0 |
重试次数 |
| error_msg |
VARCHAR(500) |
失败原因 |
| created_at / updated_at |
DATETIME |
|
索引:idx_pick(task_status, priority DESC, created_at)(消费者取任务用)
tags 标签表
| 字段 |
类型 |
说明 |
| id |
INT PK AUTO_INCREMENT |
|
| name |
VARCHAR(20) |
标签名,唯一索引(大小写不敏感) |
| video_count |
INT DEFAULT 0 |
关联视频数(冗余) |
| created_at |
DATETIME |
|
video_tags 视频-标签关联表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| video_id |
BIGINT FK |
|
| tag_id |
INT FK |
|
约束:唯一索引 uk_video_tag(video_id, tag_id);索引 idx_tag(tag_id, video_id)(标签视频列表页用)
3.4 互动域
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| video_id |
BIGINT FK |
|
| user_id |
BIGINT FK |
|
| parent_id |
BIGINT DEFAULT 0 |
0=一级评论,否则为父评论 ID |
| reply_to_user_id |
BIGINT NULL |
被回复人 |
| content |
VARCHAR(500) |
内容 |
| like_count |
INT DEFAULT 0 |
|
| status |
TINYINT DEFAULT 1 |
1正常 2已删除 3审核中 |
| reward_counted |
TINYINT DEFAULT 0 |
是否已计入评论奖励进度 |
| created_at |
DATETIME |
|
索引:idx_video(video_id, status, created_at)、idx_user_video(user_id, video_id)(查首评用)
likes 点赞表 / favorites 收藏表(结构相同)
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| user_id |
BIGINT FK |
|
| video_id |
BIGINT FK |
|
| created_at |
DATETIME |
|
约束:唯一索引 uk_user_video(user_id, video_id) 防重复点赞/收藏;另建 idx_video(video_id)。
3.5 计费域
watch_records 观看记录表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| subject_type |
TINYINT |
1注册用户 2游客 |
| subject_id |
VARCHAR(64) |
user_id 或 device_id |
| video_id |
BIGINT |
|
| watch_date |
DATE |
观看日期(用于当日去重) |
| cost_type |
TINYINT |
0免费额度 1积分扣减 2会员免费 3作者本人 |
| cost_points |
INT DEFAULT 0 |
本次消耗积分 |
| watch_duration |
INT DEFAULT 0 |
观看时长(秒) |
| position |
INT DEFAULT 0 |
最新播放进度(秒,用于续播) |
| created_at |
DATETIME |
|
约束:唯一索引 uk_dedup(subject_type, subject_id, video_id, watch_date),是"同日同视频不重复扣费"的底层保证。
point_transactions 积分流水表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| user_id |
BIGINT FK |
|
| change_amount |
INT |
变动值(正=增,负=减) |
| balance_after |
INT |
变动后余额 |
| biz_type |
TINYINT |
1充值 2观看消耗 3评论奖励 4开通会员 5活动赠送 6后台调整 7奖励扣回 8推荐奖励 |
| biz_id |
VARCHAR(64) |
关联单据号(订单号/视频ID等) |
| remark |
VARCHAR(200) |
备注 |
| created_at |
DATETIME |
|
索引:idx_user_created(user_id, created_at)、idx_biz(biz_type, biz_id)
recharge_orders 充值订单表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| order_no |
VARCHAR(32) |
平台订单号,唯一索引 |
| user_id |
BIGINT FK |
|
| amount_fen |
INT |
人民币金额(分) |
| points |
INT |
应到账积分 |
| pay_method |
TINYINT |
1支付宝 2微信 3USDT |
| status |
TINYINT |
0待支付 1已支付 2已关闭 3已退款 |
| third_trade_no |
VARCHAR(64) NULL |
第三方流水号/tx_hash,唯一索引(幂等关键) |
| usdt_amount |
DECIMAL(18,6) NULL |
USDT 金额(含随机尾差) |
| usdt_rate |
DECIMAL(10,4) NULL |
下单时 USDT 汇率 |
| paid_at |
DATETIME NULL |
支付时间 |
| expire_at |
DATETIME |
过期时间 |
| created_at / updated_at |
DATETIME |
|
索引:idx_user_status(user_id, status)
3.6 Redis Key 设计(配合数据库)
| Key |
类型 |
TTL |
用途 |
sms:code:{phone} |
String |
5min |
短信验证码 |
email:code:{email} |
String |
10min |
邮箱验证码 |
free:watch:{subject}:{yyyyMMdd} |
Set(video_id) |
48h |
当日免费观看去重与计数 |
comment:prog:{user_id} |
Hash {count, date, daily} |
7d |
评论奖励进度/日上限 |
comment:counted:{user_id}:{video_id} |
String |
永久(或随评论删除) |
同视频首评去重 |
view:video:{video_id} |
String(计数) |
异步落库 |
播放量缓冲 |
token:blacklist:{jti} |
String |
token剩余有效期 |
登出拉黑 |
watched:{subject}:{yyyyMMdd} |
Set(video_id) |
48h |
当日已看视频集合(推荐去重) |
rec:seed:{yyyyMMdd} |
String |
48h |
当日推荐重排随机种子 |
cview:{subject}:{video_id}:{yyyyMMdd} |
String |
48h |
完整观看当日去重 |
video:cview:{video_id} |
String(计数) |
异步落库 |
完整观看计数缓冲 |
ref:device:{device_id} |
String |
永久 |
设备已注册标记(防小号绑定) |
ref:risk:{inviter_id}:{yyyyMMdd} |
String(计数) |
48h |
邀请人当日新增绑定计数(风控) |
invite:ip:{ip} |
ZSet(code→点击时间戳) |
24h |
推广点击埋点(按 IP 的归因候选) |
invite:clk:{code}:{ip} |
String(JSON) |
24h |
点击详情(UA/时间戳) |
invite:dup:{ip}:{code} |
String |
60s |
同 IP+code 重复埋点去重 |
invite:attr:{device_id} |
String(邀请码) |
7d |
首启归因结果缓存,注册时一次性消费 |
wd:pending:{user_id} |
String |
审核期间 |
提现在途唯一锁 |
search:hot |
ZSet(word→次数) |
25h |
热搜统计(小时截断) |
notif:unread:{user_id} |
String(计数) |
随读清零 |
未读通知数 |
words:sensitive |
String(词库) |
60s |
敏感词缓存 |
config:system |
Hash |
60s |
system_configs 缓存 |
3.7 管理后台域
admin_users 管理员表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| username |
VARCHAR(50) |
登录名,唯一索引 |
| password_hash |
VARCHAR(255) |
bcrypt |
| name |
VARCHAR(50) |
姓名 |
| role |
VARCHAR(20) |
super / reviewer / operator |
| status |
TINYINT DEFAULT 1 |
1正常 0禁用 |
| last_login_at |
DATETIME NULL |
|
| created_at |
DATETIME |
|
admin_logs 操作日志表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| admin_id |
BIGINT FK |
操作人 |
| action |
VARCHAR(50) |
动作(review/adjust_points/ban...) |
| target |
VARCHAR(100) |
操作对象 |
| detail |
VARCHAR(1000) |
参数与原因 |
| ip |
VARCHAR(45) |
操作 IP |
| created_at |
DATETIME |
|
索引:idx_admin_created(admin_id, created_at)
system_configs 平台配置表
| 字段 |
类型 |
说明 |
| config_key |
VARCHAR(50) PK |
配置键 |
| config_value |
VARCHAR(500) |
配置值 |
| description |
VARCHAR(200) |
说明 |
| updated_by |
BIGINT NULL |
最后修改人(admin_users.id) |
| updated_at |
DATETIME |
|
预置键:register_gift_trial.enabled(注册赠送体验会员开关:1/0,默认 1)、register_gift_trial.days(赠送天数,默认 1)
recharge_packages 充值套餐表
| 字段 |
类型 |
说明 |
| id |
INT PK |
|
| amount_yuan |
INT |
充值金额(元) |
| points |
INT |
基础到账积分(= 金额 × 汇率) |
| bonus_points |
INT DEFAULT 0 |
赠送积分 |
| sort |
INT DEFAULT 0 |
排序(越大越靠前) |
| status |
TINYINT DEFAULT 1 |
1上架 0下架 |
| created_at / updated_at |
DATETIME |
|
3.8 激励域
referrals 推荐关系表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| inviter_id |
BIGINT FK |
推荐人 |
| invitee_id |
BIGINT |
被推荐人,唯一索引(一人仅一次绑定) |
| invite_code |
VARCHAR(10) |
使用的邀请码 |
| status |
TINYINT |
0待激活 1有效(已发奖) 2无效 3风控冻结 |
| risk_flag |
VARCHAR(50) |
风控标记:same_device/same_ip/batch/inviter_burst |
| register_ip |
VARCHAR(45) |
被推荐人注册 IP |
| activated_at |
DATETIME NULL |
激活时间 |
| created_at |
DATETIME |
绑定时间 |
索引:idx_inviter(inviter_id, created_at)、idx_status(status, created_at)
asset_wallets 资产钱包表
| 字段 |
类型 |
说明 |
| user_id |
BIGINT PK FK |
|
| assets |
DECIMAL(12,1) DEFAULT 0 |
当前资产(允许为负,返利扣回场景) |
| total_earned |
DECIMAL(14,1) DEFAULT 0 |
累计获得 |
| total_withdrawn |
DECIMAL(14,1) DEFAULT 0 |
累计提现 |
| version |
INT DEFAULT 0 |
乐观锁 |
| updated_at |
DATETIME |
|
asset_transactions 资产流水表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| user_id |
BIGINT FK |
|
| change_amount |
DECIMAL(12,1) |
变动值(正=增,负=减) |
| balance_after |
DECIMAL(12,1) |
变动后余额 |
| biz_type |
TINYINT |
1充值返利 2完整观看收益 3点赞收益 4提现 5提现退回 6返利扣回 7后台调整 |
| biz_id |
VARCHAR(64) |
关联单据(订单号/视频ID/提现单号) |
| remark |
VARCHAR(200) |
|
| created_at |
DATETIME |
|
索引:idx_user_created(user_id, created_at)、idx_biz(biz_type, biz_id)
withdrawals 提现记录表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| withdraw_no |
VARCHAR(32) |
提现单号,唯一索引 |
| user_id |
BIGINT FK |
|
| assets |
DECIMAL(12,1) |
申请资产 |
| amount_fen |
INT |
折合人民币(分) |
| channel |
TINYINT |
1支付宝 2微信 3USDT |
| account |
VARCHAR(200) |
收款账号 |
| status |
TINYINT |
0待审核 1已打款 2已拒绝(已退回) |
| reason |
VARCHAR(200) |
拒绝原因 |
| admin_id |
BIGINT NULL |
审核人 |
| created_at / processed_at |
DATETIME |
申请/处理时间 |
索引:idx_user(user_id, created_at)、idx_status(status, created_at)
video_earnings 视频收益结算表
| 字段 |
类型 |
说明 |
| video_id |
BIGINT PK |
|
| author_id |
BIGINT |
作者(冗余,结算时查会员) |
| complete_views |
INT DEFAULT 0 |
累计完整观看次数 |
| views_settled |
INT DEFAULT 0 |
已结算的完整观看刻度 |
| likes_accrued |
INT DEFAULT 0 |
累计点赞(取消会回退) |
| likes_settled |
INT DEFAULT 0 |
已结算的点赞刻度 |
| updated_at |
DATETIME |
|
索引:idx_author(author_id)
3.9 通用域
notifications 消息通知表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| user_id |
BIGINT FK |
接收人 |
| type |
TINYINT |
1审核结果 2提现进度 3系统公告 4评论回复 |
| title |
VARCHAR(100) |
|
| content |
VARCHAR(500) |
|
| biz_id |
VARCHAR(64) |
关联单据(视频ID/提现单号/评论ID) |
| is_read |
TINYINT DEFAULT 0 |
0未读 1已读 |
| created_at |
DATETIME |
|
索引:idx_user_read(user_id, is_read, id)
reports 举报表
| 字段 |
类型 |
说明 |
| id |
BIGINT PK |
|
| user_id |
BIGINT FK |
举报人 |
| target_type |
TINYINT |
1视频 2评论 |
| target_id |
BIGINT |
对象 ID |
| reason_type |
TINYINT |
1色情低俗 2暴力血腥 3侵权 4广告营销 5其他 |
| remark |
VARCHAR(200) |
补充说明 |
| status |
TINYINT |
0待处理 1已处理 2已驳回 |
| handle_result |
VARCHAR(50) |
处理动作(offline_video/delete_comment) |
| admin_id |
BIGINT NULL |
处理人 |
| created_at / handled_at |
DATETIME |
|
约束:唯一索引 uk_user_target(user_id, target_type, target_id);索引 idx_status(status, created_at)
sensitive_words 敏感词表
| 字段 |
类型 |
说明 |
| id |
INT PK AUTO_INCREMENT |
|
| word |
VARCHAR(50) |
敏感词,唯一索引 |
| created_at |
DATETIME |
|
4. 接口设计(概览)
- 统一前缀:
/api/v1
- 认证:
Authorization: Bearer <access_token>,游客请求携带 X-Device-ID
- 统一响应:
{ "code": 0, "message": "ok", "data": {...} }
- 完整接口定义见《03-接口文档》
| 分组 |
接口数 |
说明 |
| 认证 |
7 |
验证码、注册、登录、找回密码、刷新、登出 |
| 用户 |
8 |
资料、头像、钱包、积分明细、注销、公开主页、他人作品 |
| 视频 |
13 |
Feed、详情、观看/完整观看上报、上传、发布、编辑、删除、我的作品、分类、标签视频、搜索、热搜 |
| 互动 |
7 |
点赞、收藏、评论增删查、收藏/历史列表 |
| 会员 |
3 |
套餐、我的会员、积分开通 |
| 支付 |
4 + 2回调 |
套餐、下单、查单、取消;支付宝/微信回调(USDT 为服务端轮询) |
| 激励 |
6 |
邀请信息、绑定邀请码、资产钱包/流水、提现申请/记录 |
| 推广归因 |
2 + 1 落地页 |
点击埋点、首启归因匹配、H5 推广落地页(/r/{code}) |
| 消息与通用 |
5 |
版本检查、通知列表/未读数/标记已读、举报 |
| 后台管理 |
32 |
审核、视频/评论管理、用户、积分、订单、套餐配置、赠送、提现审核、推荐风控、举报处理、敏感词、平台配置、看板、日志(/admin 前缀) |
5. 前端设计
技术选型:Flutter(一套代码出 iOS/Android)。技术细节见《02-技术文档》第 5 章。
5.1 页面清单与路由
| 路由 |
页面 |
说明 |
| /splash |
启动页 |
初始化 device_id、Token 续期、配置拉取 |
| /home |
首页 |
沉浸式视频 Feed(默认页) |
| /video/:id |
视频播放详情 |
全屏播放 + 互动栏 |
| /login |
登录/注册 |
手机号 Tab(默认)/ 邮箱 Tab |
| /mine |
我的 |
个人中心 |
| /mine/edit |
编辑资料 |
|
| /mine/wallet |
我的钱包 |
积分余额、明细、充值入口 |
| /mine/recharge |
充值页 |
套餐选择 + 支付方式 |
| /mine/recharge/usdt |
USDT 支付页 |
金额/地址/二维码/倒计时 |
| /mine/referral |
邀请好友 |
邀请码/链接、累计奖励、推荐列表 |
| /mine/assets |
资产钱包 |
资产余额、流水、提现入口 |
| /mine/assets/withdraw |
提现页 |
金额/渠道/账号,提交后查进度 |
| /mine/vip |
会员中心 |
套餐卡片、权益、开通 |
| /mine/videos |
我的作品 |
含审核状态 |
| /mine/favorites |
我的收藏 |
|
| /mine/history |
观看历史 |
|
| /upload |
上传视频 |
选片→剪辑信息→发布 |
| /search |
搜索 |
|
| /tags/:name |
标签视频页 |
某标签下的视频列表 |
| /settings |
设置 |
退出登录等 |
5.2 核心页面布局
5.2.1 首页(视频 Feed)
- 全屏竖向 PageView,每个页面一个视频播放器
- 顶部:Feed 策略 Tab(推荐 / 最新 / 热度)+ 搜索图标
- 右侧互动栏(自上而下):作者头像(+关注预留)、点赞(红心+计数)、评论(气泡+计数)、收藏(星标+计数)、分享
- 左下:作者昵称、标题(标题后展示 #标签,点击跳转标签视频页)、描述(展开/收起)
- 底部(游客/非会员场景):今日免费剩余次数提示条(剩余 ≤ 3 次时显示)
5.2.2 评论页(底部弹层)
- BottomSheet,高度 2/3 屏;顶部评论总数;列表(头像/昵称/内容/时间/点赞);底部输入框
- 二级回复:点击评论展开子回复
5.2.3 我的
- 顶部:头像、昵称、ID、会员标识(金色卡片入口)
- 中部数据行:作品 / 收藏 / 历史
- 功能列表:我的钱包(积分余额)、资产钱包(可提现)、邀请好友、会员中心、上传视频、设置
5.2.4 充值页
- 积分余额展示;充值套餐网格(后台配置的档位,角标"赠 x 积分")+ 自定义金额输入框
- 支付方式单选:支付宝 / 微信 / USDT(带图标)
- 底部"立即支付"按钮;支付结果页(成功/失败/查询中轮询)
5.2.5 会员中心
- 当前会员状态卡片(类型、到期时间)
- 四张套餐卡:体验/月卡/年卡/终身卡(价格=积分,终身卡高亮"永久")
- 权益说明列表:无限观看、优先上传
- 开通按钮 → 积分余额确认弹窗(余额不足跳充值)
5.2.6 上传页
- 三步:选择视频(系统相册/拍摄)→ 填写信息(封面选择、标题、描述、分类)→ 发布
- 发布后进入"转码中"状态页/ Toast 提示,可在"我的作品"查看进度
5.3 核心交互设计
| 场景 |
交互 |
| 切换视频 |
垂直滑动,松手吸附;滑出即暂停,滑入自动播放并上报观看计费 |
| 单击屏幕 |
暂停 / 继续播放(暂停时显示播放图标) |
| 双击屏幕 |
点赞动画(大爱心飘出) |
| 游客超限 |
播放第 11 个视频时弹出登录引导弹窗("注册解锁更多视频,今日已看 10/10") |
| 用户积分不足 |
弹窗"积分不足":去充值 / 开通会员 两个按钮 |
| 扣费提示 |
每次扣积分播放时顶部 Toast"本次消耗 1 积分" |
| 会员标识 |
昵称旁金色 VIP 角标;会员 Center 显示到期时间 |
| 上传结果 |
转码/审核状态在我的作品实时刷新(轮询或推送) |
5.4 UI 样式规范
| 项 |
规范 |
| 主题 |
深色为主(#121212 背景),保证视频沉浸感;浅色可选(二期) |
| 主色 |
#FE2C55(红),辅助色 #25F4EE(青) |
| 会员色 |
金色渐变 #F7D794 → #D4A017 |
| 文字 |
主 #FFFFFF,次 #B0B0B0,弱 #6E6E6E |
| 字体 |
系统默认(中文 PingFang/思源),标题 17sp 加粗,正文 15sp,辅助 12sp |
| 间距 |
4 的倍数体系:4/8/12/16/24 |
| 圆角 |
按钮 8dp,卡片 12dp,头像圆形 |
| 组件 |
统一封装:按钮、弹窗、Toast、空态、骨架屏 |
5.5 域名发现(API 入口)
App 不内置固定 API 域名,启动时按以下流程动态获取:
- 优先:DNS TXT 解析。解析
txt.256kb.top 的 TXT 记录,记录内容即真实 API 域名(如 api.xxx.com),拼接 https:// 作为 Base URL
- 兜底:计算域名。TXT 解析失败或内容为空时,取当前"年月"字符串(格式
yyyyMM,如 202610)计算 MD5(32 位小写),拼接为 {md5(yyyyMM)}_jsnbhh.vip(例如 d8578ef...9c_jsnbhh.vip)
- 获取成功后写入本地缓存;后续启动优先使用缓存域名,同时后台异步刷新;缓存域名连续请求失败达到阈值时重新走完整发现流程
- 所有网络请求统一从该入口获取 Base URL,业务代码中禁止硬编码任何 API 域名
- 兜底域名配套:
jsnbhh.vip 需配置 DNS 泛解析 + 通配符证书(*.jsnbhh.vip)并接入 CDN/网关回源,保证任意 md5 前缀域名开箱可用;每月 1 日前运维确认泛解析与证书有效
5.6 设备指纹与公共请求头
- device_id:App 首次启动生成 UUID(v4),Android 存 Keystore 加密的 SharedPreferences,iOS 存 Keychain(卸载重装保留);即游客计费与风控的设备指纹,客户端禁止采集 IMEI/OAID 等系统标识
- 所有请求携带公共 Header:
X-Device-ID(必带)、X-App-Version(如 1.0.0)、X-Platform(android/ios)
5.7 版本检查与强制更新
- App 启动及回到前台时调用
GET /app/version:返回最新版本号、是否强制更新、下载地址、维护公告
- 强制更新:弹窗阻断使用并跳转商店/下载页;非强制:可跳过的提示弹窗;维护公告:全 App 只读提示
6. 后端设计
6.1 框架推荐:FastAPI
| 对比项 |
FastAPI(推荐) |
Django REST Framework |
Flask |
| 异步支持 |
原生 async/await(IO 密集接口吞吐高) |
3.x 起部分支持 |
需额外方案 |
| API 文档 |
自动生成 OpenAPI/Swagger |
需 drf-spectacular |
需 flasgger 等 |
| 数据校验 |
Pydantic 类型声明即校验 |
Serializer 较繁琐 |
无内置 |
| 性能 |
高(Starlette + Uvicorn) |
中 |
中 |
| 学习/维护 |
类型提示友好,适合中小团队快速迭代 |
全家桶偏重 |
灵活但需自行拼装 |
本项目接口以高并发短请求 + 文件流转为主,FastAPI 的异步 IO、自动文档(与《03-接口文档》可互验)和 Pydantic 校验最匹配。
技术栈:Python 3.11 + FastAPI + SQLAlchemy 2.0(异步)+ Alembic + Pydantic v2 + Celery(转码/异步任务)+ MySQL 8 + Redis 7 + FFmpeg + Nginx。
6.2 模块划分
6.3 核心流程设计
6.3.1 观看计费(watch 接口内部逻辑)
- 解析身份:有 Token → 用户;无 Token → device_id 游客
- 会员校验:
user_membership 终身卡或 expire_at > now() → 记录观看(cost_type=2)返回放行
- 同日去重:尝试插入
watch_records(唯一键冲突 = 今日已看过)→ 放行返回
- 免费额度:Redis
SADD free:watch:{subject}:{date} video_id,若返回 1 且 SCARD ≤ 10 → 免费占用,落库返回
- 超额度:游客 → 返回错误码
FREE_LIMIT_EXCEEDED;用户 → 事务内扣积分(锁钱包行 + 写流水 + 落观看记录)→ 返回成功及剩余积分
- 积分不足 → 返回错误码
INSUFFICIENT_POINTS
关键:步骤 3-5 的"去重 + 占额度"用 Redis Lua 脚本保证原子性;扣积分用数据库事务 + 行锁保证原子性。
6.3.2 支付到账(回调逻辑,三渠道统一)
- 验签/验来源(支付宝公钥、微信 V3 平台证书、USDT 链上数据核对)
- 按订单号查订单,校验状态为"待支付"且金额一致
- 幂等校验:
third_trade_no/tx_hash 唯一索引冲突 → 直接返回成功(重复回调)
- 事务:订单置已支付 → 钱包加积分(行锁)→ 写积分流水 → 提交
- 返回支付平台要求的成功响应;失败进入重试/告警
6.3.3 转码流水线
- 上传完成 → 创建 videos(status=0) + transcode_tasks(priority=会员?1:0)
- Celery 两个队列:
transcode.high / transcode.normal,Worker 优先消费 high
- FFmpeg 转 HLS(输出 m3u8 + ts)→ 上传 OSS → 更新 video_url、时长、封面
- 状态流转:转码成功 → 待审核;失败重试 3 次 → 转码失败
6.3.4 评论奖励结算
- 发表评论(≥5 字、视频有效、同视频首评)→ 写评论 +
comment:counted 去重标记
- Redis
HINCRBY comment:prog:{uid} count 1;达 10 → 扣减 10 并事务发放 1 积分(写流水,biz_type=3)
- 日上限校验:
daily 字段达 5 则当日不再发放
- 评论删除:若
reward_counted=1 → 进度 -1;若奖励已发放 → 发放 -1 积分流水(biz_type=7)
6.4 配置文件样例(config.yaml)
6.5 安全设计
- 密码 bcrypt 哈希;登录失败 5 次锁定 15 分钟(Redis 计数)
- JWT 双 Token:access 2 小时 + refresh 30 天;登出/改密加入黑名单
- 支付回调只信验签结果,金额以服务端订单为准
- 接口限流:验证码 1 条/分钟、评论 10 条/分钟、观看上报 60 次/分钟
- 上传文件类型白名单校验(mp4/mov/m3u8/ts),大小校验
- SQL 注入防护:ORM 参数化;XSS:评论内容转义输出