Files
video/docs/01-开发文档.md
T
2026-10-18 21:08:54 +08:00

58 KiB
Raw Blame History

短视频应用开发文档

  • 版本:v1.0
  • 日期:2026-10-14
  • 适用端:Flutter App(iOS / Android)、Python 后端

1. 项目介绍

1.1 项目概述

一款竖屏沉浸式短视频应用(产品形态参考抖音/快手)。核心商业模式为:

免费额度 + 积分付费观看 + 会员订阅

  • 所有用户(含游客)每天可免费观看 10 个视频
  • 超出免费额度后,注册用户每观看 1 个视频消耗 1 积分,游客需注册/登录
  • 积分通过充值获得(支付宝 / 微信 / USDT),1 元 = 10 积分
  • 积分可开通会员,会员享有无限观看和优先上传权益
  • 用户可通过评论赚取积分(每评论 10 个视频奖励 1 积分),形成内容互动激励闭环

1.2 项目组成

video/                      # 项目根目录(当前目录)
├── app/                    # Flutter 手机端(前端)
├── server/                 # Python 后端服务
├── admin/                  # 管理后台 Web(Vue3,一期包含)
└── docs/                   # 项目文档

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 注册

  • 注册页手机号 / 邮箱 Tab 切换:手机号 + 短信验证码 + 密码,或 邮箱 + 邮箱验证码 + 密码
  • 邮箱验证码由服务端真实 SMTP 发送(POST /auth/email/send),验证码写 Redis(email:code:{email},600s),与短信验证码同一套校验机制
  • 注册即登录,返回 Token
  • 约束:手机号/邮箱全局唯一;密码 ≥ 8 位,含字母和数字

2.1.3 登录

  • 支持手机号或邮箱作为账号:手机号 + 密码 / 手机号 + 短信验证码 / 邮箱 + 密码
  • 登录成功后,游客时期的设备 ID 与账号可关联(观看记录合并,可选)

2.1.4 资料管理

  • 昵称(默认"用户+尾号")、头像、性别、个人简介
  • 修改手机号/邮箱需验证码验证

2.1.5 找回密码与账号注销

  • 找回密码:已验证的手机号/邮箱 + 验证码 + 新密码完成重置(POST /auth/password/reset),重置后旧 Token 全部失效
  • 账号注销:用户主动发起 → 7 天冻结期(期间登录即撤销)→ 到期匿名化:手机号/邮箱置空释放、昵称头像清空、作品全部下架、钱包余额清零作废、Token 立即失效

2.2 观看与计费模块(核心业务)

2.2.1 计费规则

  1. 会员:观看不限量,不消耗免费额度与积分
  2. 非会员(含游客):每个计费主体每天前 10 个不同视频免费
  3. 免费额度用完后:注册用户每看 1 个视频扣 1 积分;游客拦截并引导登录
  4. 所有"每日"口径均按 Asia/Shanghai(服务器时区)0 点切分
  5. 积分余额不足:拦截播放,引导充值或开通会员

2.2.2 计费判定流程

用户开始播放视频
      │
      ▼
App 调用「观看上报」接口
      │
      ▼
是否会员? ──是──► 直接放行
      │否
      ▼
该视频今天看过? ──是──► 直接放行(同日去重,不重复扣费)
      │否
      ▼
今日免费额度未用完? ──是──► 占用 1 次免费额度,放行
      │否
      ▼
是游客? ──是──► 返回"需登录",App 弹登录引导
      │否
      ▼
积分 ≥ 1? ──是──► 扣 1 积分(写积分流水),放行
      │否
      ▼
返回"积分不足",App 引导充值/开会员

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 会员权益

  1. 无限观看:不消耗免费额度和积分
  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 竖屏全屏沉浸式播放
  • 上滑/下滑切换视频;3 槽播放器池预加载:当前页播放 + 下一页预缓冲,划走即 stop(断音 + 中断缓存下载)
  • 切到"我的"等页面时播放器池挂起(suspend)静音断流,回到 Feed 且首页 Tab 可见才恢复(resume),修复"切页仍出声"问题
  • 网络 m3u8 播放地址改写为 App 内嵌本地媒体代理(127.0.0.1 HTTP 服务):m3u8 每次回源保证签名时效,ts 分片落盘缓存(1GB LRU),支持拖动进度条(Range/206);ts 流量直连源站 CDN,不经过业务服务器
  • 进度条拖动时显示时间气泡(x时xx分xx秒),标题后带时长角标
  • 记录播放量(进入播放即 +1,Redis 计数异步落库)

2.5.5 视频标签(Tag)

  • 发布视频时可填写 05 个标签,每个标签 120 字(字母/数字/中文/下划线)
  • 播放页在标题后展示标签(#标签 样式)
  • 点击标签进入"标签视频列表页":展示该标签下全部已发布视频(支持 热度/最新 排序)
  • 标签是推荐策略中个性化加权的主要特征
  • 存量视频标签由离线脚本批量生成(server/scripts/build_tags_from_titles.py:jieba TF-IDF topK=6 + 番号/书名号提取 + 噪音过滤,幂等可重跑;已生成 2.2 万+ 标签、9.9 万+ 关联),后台提供"标签管理"页维护

2.5.6 视频推荐策略

Feed 支持五种策略,客户端通过接口参数切换(App 顶部 Tab:推荐 / 最新 / 热度 / 口碑 / 热播,各策略独立保活分页状态):

策略 说明
recommend(默认) 个性化推荐
latest 最新发布倒序
hot 热度倒序:热度分 = (播放×1 + 点赞×5 + 评论×10) / (1 + 发布天数)
liked(口碑) 按点赞量倒序
viewed(热播) 按播放量倒序

liked / viewed 为纯数值排序,游标采用(值, id)双键避免同值翻页丢失。

个性化推荐(recommend)规则:

  1. 候选池:全部"已发布"视频
  2. 个性化打分:统计用户近 7 天观看/点赞/收藏视频的标签,得出偏好标签及权重,候选视频命中偏好标签加权;游客与无行为新用户退化为热度分
  3. 每日重排:以"当天日期 + 用户/设备"为随机种子对候选池确定性洗牌,保证同一用户每天的推荐顺序都不一样,且同一天内多次刷新顺序稳定(翻页不混乱)
  4. 当日去重:当天已观看过的视频尽量不再出现在推荐流中;候选池耗尽时放开过滤兜底,避免 Feed 刷空

2.5.7 作品管理(作者)

  • 编辑:作者可修改自己视频的标题/描述/分类/标签,仅元信息变更,不影响已发布状态、不重新触发审核(视频文件不可替换)
  • 删除:作者可删除自己视频 → 软删除(status=5 已删除),立即从 Feed/搜索/标签页下架;播放/点赞等历史数据保留用于对账,资产结算即刻停止
  • 两个操作仅作者本人可用(非作者返回 2107)

2.5.8 搜索

  • 一期:按标题、标签做关键词匹配(MySQL LIKE / FULLTEXT),支持 最新/热度 排序;二期接 Elasticsearch
  • 热搜词:近 24h 搜索频次 Top10(Redis ZSet 统计,每小时截断)
  • 搜索历史:App 端本地存储最近 10 条,不上报服务端
  • 搜索词先过敏感词过滤,命中直接返回空结果

2.5.9 视频下载(离线缓存)

  • 入口:Feed 页 / 播放页长按弹出菜单 →「下载」(已下载/下载中置灰)
  • HLS 视频:4 并发下载 ts 分片与 AES-128 密钥,改写为本地 index.m3u8;mp4 整文件直接下载
  • 下载过程展示进度,支持取消;失败自动清理半成品文件
  • 下载列表在「我的 → 已下载」;离线播放走本地媒体代理,支持拖动进度条
  • 已下载视频离线观看不重复扣积分(线上播放时已按正常规则计费)

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 订单不支持自动退款(人工链上退回并线下登记)
  • 系统处理(退款回调或后台人工登记后):
    1. 订单状态置为 refunded
    2. 扣回该订单已发放积分(余额允许为负,后续充值先抵扣负数;负余额用户禁止积分消费)
    3. 扣回推荐人已获得的该笔充值返利资产(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/手机号/邮箱)、用户详情(钱包/会员/作品/流水)、封禁与解封、修改密码(重置后 auth:epoch 递增,该用户全端 Token 立即失效)
积分管理 用户积分流水查询、手动加/减积分(原因必填 + 二次确认,写流水 biz_type=6)
订单管理 充值订单查询(状态/渠道/时间筛选)、异常订单人工补单(核实已收款后手动入账)
提现审核 提现申请列表、审核通过(线下打款后确认)/ 拒绝(自动退回资产)
推荐风控 推荐关系查询(状态/风控标记筛选)、冻结记录解冻或判无效
平台配置 注册赠送体验会员开关与天数等运营参数(system_configs 键值对,实时生效)
充值套餐管理 档位与赠送积分增删改、上下架、排序,实时生效
活动运营 赠送体验会员/积分(支持单个或批量用户)
标签管理 标签列表查询(关联视频数)、重命名、删除(联动清理 video_tags)
采集源管理 采集源 CRUD(分类名 + 列表 URL 模板)、批量添加、单源/全部同步(后台异步采集外部单视频入库)
管理员管理 管理员账号增删、角色分配(超级管理员/审核员/运营)、操作日志查询

角色权限:超级管理员(全部)、审核员(仅视频审核)、运营(套餐/活动/看板)。

2.10 二期规划清单

  1. 关注/粉丝:预留,二期开放
  2. App 推送:厂商通道(评论回复、审核结果、提现进度等通知的 push)
  3. 搜索升级:Elasticsearch、搜索联想词
  4. 分享:视频分享链接/海报生成
  5. 趋势看板:管理后台 7/30 天数据曲线、订单导出 CSV
  6. 黑名单:用户拉黑、内容"不感兴趣"负反馈,深化个性化推荐
  7. 游客数据合并:注册后游客观看记录正式合并入账号
  8. 实名认证提示:充值环节按支付合规要求引导实名(依赖支付渠道商户资质)
  9. 运维:上传临时文件与拒绝视频分片的定时清理、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 表清单

现共 30 张业务表。Alembic 迁移链:init_27_tables → add_collection_records → add_collection_sources;线上数据量约 1.8 万视频。

表 说明
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 敏感词表
series 系列(合集)表:多条视频组织成集数列表
collection_sources 采集源配置表(分类名 + 列表 URL 模板)
collection_records 采集记录表(外部内容源 → 本站系列/视频映射,幂等导入)

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 互动域

comments 评论表

字段 类型 说明
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

3.10 采集域

series 系列(合集)表

字段 类型 说明
id BIGINT PK AUTO_INCREMENT
title VARCHAR(100) 系列标题
cover_url VARCHAR(500) 封面
description VARCHAR(500) 简介
author_id BIGINT NULL 作者
category_id INT 分类
total_episodes INT DEFAULT 0 总集数
view_count BIGINT DEFAULT 0 播放量
status SMALLINT DEFAULT 1 1正常 0隐藏
created_at / updated_at DATETIME

索引:idx_series_cat_status(category_id, status)、idx_series_status_created(status, created_at);videos 表以 series_id 关联所属系列

collection_sources 采集源配置表

字段 类型 说明
id BIGINT PK AUTO_INCREMENT
name VARCHAR(50) 分类名(添加时自动建/找本站分类)
list_url VARCHAR(500) 列表 URL 模板,{{page}} 为页码占位
category_id INT UNSIGNED 本站分类 id
status SMALLINT DEFAULT 1 1启用 0停用
last_sync_at DATETIME NULL 最近同步时间
created_at / updated_at DATETIME

collection_records 采集记录表

字段 类型 说明
id BIGINT PK AUTO_INCREMENT
source_key VARCHAR(50) 内容源标识
source_id BIGINT 源站内容 id
series_id BIGINT NULL 本站系列 id
video_id BIGINT NULL 本站视频 id(单视频类)
created_at DATETIME

约束:唯一索引 uk_source(source_key, source_id) 保证幂等导入(重复同步不产生重复视频);索引 idx_record_series(series_id)、idx_record_video(video_id)


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 搜索
/category 分类页 按分类浏览视频
/tags/:name 标签视频页 某标签下的视频列表
/mine/downloads 已下载 离线视频列表(进度/删除/播放)
/notifications 消息通知 通知列表、未读标记
/settings 设置 退出登录等

5.2 核心页面布局

5.2.1 首页(视频 Feed)

  • 全屏竖向 PageView,每个页面一个视频播放器(3 槽播放器池:当前页播放 + 下一页预缓冲,划走即停)
  • 顶部:Feed 策略 Tab(推荐 / 最新 / 热度 / 口碑 / 热播)+ 搜索图标;各策略分页状态独立保活,切 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 核心交互设计

场景 交互
切换视频 垂直滑动,松手吸附;滑出即暂停,滑入自动播放并上报观看计费
单击屏幕 暂停 / 继续播放(暂停时显示播放图标)
双击屏幕 点赞动画(大爱心飘出)
长按屏幕 弹出操作菜单:下载视频 / 倍速 / 分享(已下载或下载中置灰)
拖动进度条 跟随 thumb 显示时间气泡(x时xx分xx秒,两端自动夹在屏内)
游客超限 播放第 11 个视频时弹出登录引导弹窗("注册解锁更多视频,今日已看 10/10")
用户积分不足 弹窗"积分不足":去充值 / 开通会员 两个按钮
扣费提示 每次扣积分播放时顶部 Toast"本次消耗 1 积分"
会员标识 昵称旁金色 VIP 角标;会员 Center 显示到期时间
上传结果 转码/审核状态在我的作品实时刷新(轮询或推送)

5.4 UI 样式规范

项 规范
主题 深色为主(#121212 背景),保证视频沉浸感;浅色可选(二期);弹窗/底部菜单统一白底亮色(局部包 ThemeData.light(),避免深色背景下文字看不清)
主色 #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 域名,启动时按以下流程动态获取:

  1. 优先:DNS TXT 解析。解析 txt.256kb.top 的 TXT 记录,记录内容即真实 API 域名(如 api.xxx.com),拼接 https:// 作为 Base URL
  2. 兜底:计算域名。TXT 解析失败或内容为空时,取当前"年月"字符串(格式 yyyyMM,如 202610)计算 MD5(32 位小写),拼接为 {md5(yyyyMM)}_jsnbhh.vip(例如 d8578ef...9c_jsnbhh.vip)
  3. 获取成功后写入本地缓存;后续启动优先使用缓存域名,同时后台异步刷新;缓存域名连续请求失败达到阈值时重新走完整发现流程
  4. 所有网络请求统一从该入口获取 Base URL,业务代码中禁止硬编码任何 API 域名
  5. 兜底域名配套: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 只读提示

5.8 工程结构(与当前代码对齐)

app/lib/
├── screens/     # 页面:splash / home(HomeShell+IndexedStack) / feed / search / category
│               #      / player / membership / payment / wallet / assets / upload
│               #      / profile / auth / settings / notification / downloads
├── providers/  # Riverpod 状态(12 个):auth / feed / comment / wallet / member
│               #      / payment / profile / search / upload / asset / notification
│               #      / tag_videos
└── core/       # 子系统:config(环境配置)/ media(local_media_server 本地代理、
                #   download_manager 下载)/ network(api_client、域名发现)/
                #   player(feed_player_pool 播放器池)/ storage(token、本地存储)/
                #   theme / utils
  • Feed 策略状态按策略保活:feedProviderFamily(strategy) 每个策略一个独立 FeedNotifier;activeFeedStrategyProvider + feedTabVisibleProvider 配合 HomeShell(IndexedStack)在切页/回前台时挂起与恢复正确的播放器池
  • 401 兜底:无 refresh token 或刷新被拒时清登录态并跳登录页,防止"僵尸登录态"

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 模块划分

server/
├── app/
│   ├── main.py                # 应用入口、中间件、路由注册、lifespan(settle 周期任务启动)
│   ├── core/                  # 配置、日志、异常、安全(JWT/密码)
│   ├── api/v1/                # 路由层(11 个文件):admin / auth / common / incentives
│   │                          #   / interactions / invite / media / membership / payments
│   │                          #   / users / videos(管理后台同文件 /admin 前缀、独立管理员鉴权)
│   ├── schemas/               # Pydantic 请求/响应模型
│   ├── models/                # SQLAlchemy ORM 模型(30 张表)
│   ├── services/              # 业务逻辑(17 个):user/auth/wallet/video/interaction/membership
│   │                          #   /payment/incentive/invite/admin/common/config/sensitive
│   │                          #   /storage/transcode/settle/collection
│   ├── payment/               # 支付适配层:alipay / wechat / usdt
│   ├── tasks/                 # Celery 任务:转码、播放量落库、订单关单
│   └── utils/                 # 短信、邮件、OSS、设备指纹
├── scripts/                   # 离线脚本:build_tags_from_titles.py(标签生成)、采集脚本
├── alembic/                   # 数据库迁移(init_27_tables → collection_records → collection_sources)
├── config.yaml                # 业务参数配置(积分/会员/支付/上传限制)
├── .env                       # 密钥类配置(不入库)
└── docker-compose.yml

6.3 核心流程设计

6.3.1 观看计费(watch 接口内部逻辑)

  1. 解析身份:有 Token → 用户;无 Token → device_id 游客
  2. 会员校验:user_membership 终身卡或 expire_at > now() → 记录观看(cost_type=2)返回放行
  3. 同日去重:尝试插入 watch_records(唯一键冲突 = 今日已看过)→ 放行返回
  4. 免费额度:Redis SADD free:watch:{subject}:{date} video_id,若返回 1 且 SCARD ≤ 10 → 免费占用,落库返回
  5. 超额度:游客 → 返回错误码 FREE_LIMIT_EXCEEDED;用户 → 事务内扣积分(锁钱包行 + 写流水 + 落观看记录)→ 返回成功及剩余积分
  6. 积分不足 → 返回错误码 INSUFFICIENT_POINTS

关键:步骤 3-5 的"去重 + 占额度"用 Redis Lua 脚本保证原子性;扣积分用数据库事务 + 行锁保证原子性。

6.3.2 支付到账(回调逻辑,三渠道统一)

  1. 验签/验来源(支付宝公钥、微信 V3 平台证书、USDT 链上数据核对)
  2. 按订单号查订单,校验状态为"待支付"且金额一致
  3. 幂等校验:third_trade_no/tx_hash 唯一索引冲突 → 直接返回成功(重复回调)
  4. 事务:订单置已支付 → 钱包加积分(行锁)→ 写积分流水 → 提交
  5. 返回支付平台要求的成功响应;失败进入重试/告警

6.3.3 转码流水线

  1. 上传完成 → 创建 videos(status=0) + transcode_tasks(priority=会员?1:0)
  2. Celery 两个队列:transcode.high / transcode.normal,Worker 优先消费 high
  3. FFmpeg 转 HLS(输出 m3u8 + ts)→ 上传 OSS → 更新 video_url、时长、封面
  4. 状态流转:转码成功 → 待审核;失败重试 3 次 → 转码失败

6.3.4 评论奖励结算

  1. 发表评论(≥5 字、视频有效、同视频首评)→ 写评论 + comment:counted 去重标记
  2. Redis HINCRBY comment:prog:{uid} count 1;达 10 → 扣减 10 并事务发放 1 积分(写流水,biz_type=3)
  3. 日上限校验:daily 字段达 5 则当日不再发放
  4. 评论删除:若 reward_counted=1 → 进度 -1;若奖励已发放 → 发放 -1 积分流水(biz_type=7)

6.4 配置文件样例(config.yaml)

points:
  points_per_yuan: 10        # 1元=10积分
  watch_cost: 1              # 每视频消耗积分
  daily_free_count: 10       # 每日免费观看数
  comment_reward:
    per_count: 10            # 每评论10个视频
    reward: 1                # 奖励1积分
    min_length: 5
    daily_limit: 5
membership:
  trial:    { days: 1,   points: 5,     enabled: true }
  monthly:  { days: 30,  points: 300,   enabled: true }
  yearly:   { days: 365, points: 3650,  enabled: true }
  lifetime: { days: 0,   points: 10000, enabled: true }   # days=0 表示永久
recharge:
  # 充值档位在管理后台维护(recharge_packages 表),实时生效,此处不配置
  usdt: { rate: 7.2, network: TRC20, address: "T...", confirmations: 19, order_expire_min: 30 }
referral:
  register_reward_points: 10   # 邀请有效新用户奖励积分(N),不限量
  rebate_percent: 5            # 被推荐人充值积分返利比例→资产
  activate_watch_count: 3      # 激活条件:72h内观看≥3个视频
  activate_hours: 72
  risk_max_bind_per_day: 10    # 邀请人单日新增绑定上限(超限冻结审核)
  risk_max_register_per_ip: 5  # 同IP单日注册上限(超限标记风险)
asset:
  assets_per_yuan: 10          # 10资产=1元
  complete_views_per_asset: 1000   # 每1000次完整观看=1资产
  likes_per_asset: 100             # 每100次点赞=1资产
  complete_progress: 0.95          # 完整观看判定进度
withdraw:
  min_assets: 100              # 最低提现资产(=10元)
  fee_percent: 0               # 提现手续费比例
  channels: [alipay, wechat, usdt]
upload:
  max_size_mb: 500
  min_duration_s: 5
  max_duration_s: 600
  hls_profiles: ["720p"]     # 可配 ["1080p","720p","480p"]

6.5 安全设计

  • 密码 bcrypt 哈希;登录失败 5 次锁定 15 分钟(Redis 计数)
  • JWT 双 Token:access 2 小时 + refresh 30 天;登出/改密加入黑名单
  • 支付回调只信验签结果,金额以服务端订单为准
  • 接口限流:验证码 1 条/分钟、评论 10 条/分钟、观看上报 60 次/分钟
  • 上传文件类型白名单校验(mp4/mov/m3u8/ts),大小校验
  • SQL 注入防护:ORM 参数化;XSS:评论内容转义输出