17 KiB
第 12 章状态机与数据模型补强设计
文档版本:V1.0
编制日期:2026-10-08
依据:后台管理系统需求文档第 12 章
关联设计:后台管理系统概要设计
适用项目:olons_admin
1. 文档目标
本文档用于补齐需求文档第 12 章中尚未闭环的状态机、资金冲正、内容归档与历史版本回滚能力,作为数据库迁移、后端接口、前端操作、权限配置和测试验收的实施依据。
本次设计遵循以下原则:
- 复用现有 HotGo 分层、字典、审批、审计、权限和多租户能力。
- 不修改已经投入使用的状态编号,只追加新状态或转换规则。
- 客户端只提交业务意图,最终状态由服务端状态机决定。
- 已生效资金不得修改或删除历史台账,只能生成反向流水冲正。
- 历史内容和配置不得原地覆盖,回滚必须生成新的草稿版本。
- 所有高风险执行都必须重新检查业务状态、审批状态和当前数据版本。
2. 实施范围
2.1 本期范围
- 会员状态合法转换和注销不可逆。
- 充值入账后的审批冲正。
- 任务佣金结算后的审批冲正。
- 文本内容归档和历史版本生成回滚草稿。
- 状态转换、重复执行、并发执行和资金一致性测试。
- 新增操作对应的菜单权限、业务审计和幂等保护。
2.2 不在本期范围
- 管理员 MFA 的真实认证流程。
- 支付渠道退款接口和外部清算实现。
- 新建独立的状态机管理页面。
- 修改 HotGo 原有管理员、角色、字典和个人设置模块。
- 直接修改 GoFrame CLI 生成的
entity、do、dao/internal文件。
MFA 数据字段继续保留,但真实验证码、再认证凭证和会话升级机制后续单独设计开发。
3. 现状评估
| 领域 | 已有能力 | 本次缺口 |
|---|---|---|
| 会员 | 正常、禁用、注销;风险状态;双人审批;状态日志 | 未限制全部非法转换,注销后仍可能被旧审批恢复 |
| 钱包 | 可用余额、冻结余额、乐观锁、不可变台账、幂等键、reversal_of |
充值和任务佣金尚未提供完整冲正入口 |
| 充值 | 待支付、待审核、成功、驳回、过期、取消;审核入账 | 成功后无冲正状态、审批和执行流程 |
| 任务审核 | 待审核、通过、驳回、已结算、已冲正;佣金台账字段 | 已冲正仅有字典和字段,缺少业务实现 |
| 内容 | 草稿、待审、已发布、已下线、已归档;内容版本 | 缺少归档和历史版本生成回滚草稿接口 |
| 配置 | 草稿、审批、发布、版本、回滚草稿 | 已满足本章要求,本期不重做 |
| 审计 | Trace ID、前后摘要、哈希链、审批单号 | 新增流程需要补充结构化差异和冲正关联信息 |
4. 状态机设计
4.1 通用规则
每个状态变更必须依次执行:
- 查询目标记录并加行锁。
- 校验记录存在且属于当前租户。
- 校验当前状态与申请时的
fromStatus一致。 - 校验
fromStatus → toStatus在允许转换表中。 - 校验审批已通过、尚未执行,且申请人与执行人符合职责分离要求。
- 在同一事务内完成业务状态、台账、审批执行时间和审计记录更新。
- 事务提交后再触发缓存清理、通知或 Outbox 事件。
状态转换判断统一放在后端,不接受前端直接指定任意结果状态。
4.2 会员状态
现有会员状态编号保持不变:
| 常量 | 值 | 含义 |
|---|---|---|
AppMemberStatusNormal |
1 | 正常 |
AppMemberStatusDisabled |
2 | 禁用 |
AppMemberStatusCancelled |
3 | 已注销 |
允许转换:
| 当前状态 | 目标状态 | 是否允许 | 说明 |
|---|---|---|---|
| 正常 | 禁用 | 是 | 必须审批 |
| 正常 | 注销 | 是 | 必须审批,执行后不可恢复 |
| 禁用 | 正常 | 是 | 必须审批 |
| 禁用 | 注销 | 是 | 必须审批 |
| 注销 | 任意状态 | 否 | 注销不可逆 |
| 任意状态 | 相同状态 | 否 | 防止无意义重复申请 |
需求中的“受限”继续由现有 risk_status 表达,不新增或重排会员主状态:
AppMemberRiskNormal:正常。AppMemberRiskWatch:观察或限制部分能力。AppMemberRiskBlocked:拦截高风险能力。
发起状态审批时保存 fromStatus;执行时必须重新比对。如果会员状态已变化,则旧审批失效,不得覆盖最新状态。
4.3 充值状态
保留现有 1~6 状态,追加:
| 常量 | 值 | 含义 |
|---|---|---|
RechargeReversed |
7 | 已冲正 |
核心转换:
| 当前状态 | 目标状态 | 触发方式 |
|---|---|---|
| 用户未支付 | 手动审核 | 支付凭证或支付结果进入审核 |
| 用户未支付 | 已过期/已取消 | 超时任务或用户取消 |
| 手动审核 | 已入账 | 审批通过并写入入账台账 |
| 手动审核 | 手动驳回 | 审批驳回 |
| 已入账 | 已冲正 | 冲正审批通过并生成反向台账 |
已入账 → 已冲正 是成功充值唯一允许的后续资金状态转换。已冲正记录不得再次冲正。
4.4 任务审核状态
保留现有状态编号:
| 常量 | 值 | 含义 |
|---|---|---|
TaskSubmissionPending |
1 | 待审核 |
TaskSubmissionApproved |
2 | 已通过 |
TaskSubmissionRejected |
3 | 已驳回 |
TaskSubmissionSettled |
4 | 已结算 |
TaskSubmissionReversed |
5 | 已冲正 |
当前佣金为同步结算时,可在同一事务中完成“待审核 → 已通过 → 已结算”,数据库最终状态为“已结算”;若以后改为异步结算,“已通过”可作为中间状态。
允许转换:
| 当前状态 | 目标状态 | 说明 |
|---|---|---|
| 待审核 | 已驳回 | 保存驳回原因和是否允许重提 |
| 待审核 | 已结算 | 审核通过并成功写入佣金台账 |
| 已结算 | 已冲正 | 冲正审批通过并写入反向台账 |
| 已驳回 | 其他状态 | 禁止;重新提交需生成新提交记录 |
| 已冲正 | 其他状态 | 禁止 |
4.5 内容状态
使用现有 BizPublishStatusOptions:
草稿 → 待审 → 已发布 → 已下线 → 已归档
规则:
- 只有草稿可以提交审核。
- 只有审批通过的版本可以发布。
- 只有已发布内容可以下线。
- 只有已下线内容可以归档。
- 已归档内容不可直接编辑、发布或恢复。
- 历史版本回滚不修改历史版本,而是复制为一个版本号更大的新草稿。
站点配置继续使用现有“历史版本 → 新回滚草稿 → 审批 → 发布”流程,不增加直接覆盖线上配置的接口。
5. 数据库变更
新增迁移文件:
server/storage/data/migrations/20261008_009_state_machine_hardening.sql
5.1 hg_recharge_order
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
reversal_approval_id |
bigint unsigned | 0 | 冲正审批单 ID |
reversal_ledger_id |
bigint unsigned | 0 | 冲正台账 ID |
reversed_at |
datetime(3) | NULL | 冲正执行时间 |
建议增加索引:
KEY `idx_recharge_reversal_approval` (`tenant_id`,`reversal_approval_id`)
5.2 hg_task_submission
保留已有 reversal_approval_id,新增:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
reversal_ledger_id |
bigint unsigned | 0 | 佣金冲正台账 ID |
reversed_at |
datetime(3) | NULL | 冲正执行时间 |
建议增加索引:
KEY `idx_task_submission_reversal` (`tenant_id`,`reversal_approval_id`)
5.3 hg_content_version
为了保留回滚来源,新增:
| 字段 | 类型 | 默认值 | 说明 |
|---|---|---|---|
base_version_id |
bigint unsigned | 0 | 新版本来源的历史版本 ID |
正常新增版本可为 0;通过回滚生成的新草稿必须保存来源版本 ID。
5.4 生成代码
迁移执行后,使用 GoFrame CLI 重新生成下列表对应的代码:
hg_recharge_orderhg_task_submissionhg_content_version
生成范围包括 entity、do、dao/internal 和 dao,禁止手工修改生成文件。
6. 后端接口设计
6.1 会员状态
复用现有接口:
POST /appMember/statusRequestPOST /appMember/statusExecute
补强内容:
StatusRequest校验允许转换并写入申请时状态。StatusExecute锁定会员记录后再次校验允许转换。- 已注销会员禁止发起和执行任何恢复状态请求。
- 业务审计必须记录
before.memberStatus和after.memberStatus。
6.2 充值冲正
新增接口:
| 接口 | Method | 权限 | 说明 |
|---|---|---|---|
/rechargeOrder/reversalRequest |
POST | /rechargeOrder/reversalRequest |
发起充值冲正审批 |
/rechargeOrder/reversalExecute |
POST | /rechargeOrder/reversalExecute |
执行已通过的充值冲正 |
申请参数至少包括:
- 充值单 ID。
- 标准原因编码。
- 补充说明。
- 幂等键。
- 证据附件或证据摘要,按现有 JSON 附件格式保存。
申请前置条件:
- 充值单状态为“已入账”。
- 存在原入账台账。
- 尚未发起或执行冲正。
- 原审批和入账结果有效。
执行必须在同一事务中:
- 锁定审批单、充值单、钱包账户和原台账。
- 校验审批已通过且未执行。
- 校验充值单仍为“已入账”。
- 校验原台账属于该充值单和该钱包。
- 生成金额相同、方向相反的新台账,并设置
reversal_of=原台账ID。 - 更新钱包余额和乐观锁版本,余额不得为负数。
- 更新充值单为“已冲正”,保存冲正审批、台账和时间。
- 标记审批已执行并写入业务审计。
6.3 任务佣金冲正
新增接口:
| 接口 | Method | 权限 | 说明 |
|---|---|---|---|
/taskSubmission/reversalRequest |
POST | /taskSubmission/reversalRequest |
发起佣金冲正审批 |
/taskSubmission/reversalExecute |
POST | /taskSubmission/reversalExecute |
执行已通过的佣金冲正 |
申请前置条件:
- 提交记录状态为“已结算”。
ledger_id有效。- 尚未发起或执行冲正。
- 必须填写标准原因和补充说明。
执行逻辑与充值冲正一致,但业务状态更新为 TaskSubmissionReversed,冲正流水指向佣金原流水。
6.4 内容归档与回滚
新增接口:
| 接口 | Method | 权限 | 说明 |
|---|---|---|---|
/content/archive |
POST | /content/archive |
将已下线内容归档 |
/content/rollback |
POST | /content/rollback |
根据历史版本生成新草稿 |
归档规则:
- 当前内容必须为“已下线”。
- 归档后不可编辑或直接重新发布。
- 保存操作人、原因和审计记录。
回滚规则:
- 指定内容 ID 和历史版本 ID。
- 历史版本必须属于该内容。
- 新版本号为当前最大版本号加 1。
- 复制历史版本正文、摘要、封面和附件信息。
- 新版本状态为“草稿”,
base_version_id指向来源版本。 - 不修改当前线上版本和历史版本。
7. 后端代码影响范围
按 HotGo 分层补充以下内容:
| 层级 | 主要文件 |
|---|---|
| 常量与字典 | server/internal/consts/trade.go、product_task.go、portal.go |
| API 契约 | server/api/admin/rechargeorder/、tasksubmission/、portal/ |
| Controller | server/internal/controller/admin/sys/ 对应薄控制器 |
| Service | 在 server/internal/service/sys.go 的现有接口中追加方法 |
| Input | server/internal/model/input/sysin/ 对应模块文件 |
| Logic | app_member.go、recharge_order.go、task_submission.go、portal.go |
| 路由 | 复用现有模块控制器注册,无需新增一级菜单 |
| 迁移 | 20261008_009_state_machine_hardening.sql |
状态值合法性通过后端字典校验;字段名使用 dao.Xxx.Columns(),禁止在 Logic 中硬编码数据库列名。
8. 前端设计
不增加一级菜单,只在现有页面增加操作入口。
8.1 充值管理
- 状态为“已入账”且拥有申请权限时显示“申请冲正”。
- 已存在冲正审批时显示审批状态,不允许重复申请。
- 审批通过且拥有执行权限时显示“执行冲正”。
- 已冲正记录显示原台账和冲正台账关联信息。
8.2 会员任务审核
- 状态为“已结算”时显示“申请冲正”。
- 申请弹窗包含原因字典、补充说明和证据。
- 审批通过后由有执行权限的管理员执行。
- 状态为“已冲正”后不再显示审核或冲正按钮。
8.3 文本管理
- 已下线内容显示“归档”。
- 历史版本列表显示“生成回滚草稿”。
- 回滚前明确提示“不会覆盖当前线上版本”。
- 已归档内容的编辑和发布按钮禁用。
前端继续使用 Naive UI、BasicTable、BasicForm、BasicModal 和 http.request,状态标签通过后端字典渲染。
9. 权限设计
新增操作权限:
/rechargeOrder/reversalRequest
/rechargeOrder/reversalExecute
/taskSubmission/reversalRequest
/taskSubmission/reversalExecute
/content/archive
/content/rollback
权限规则:
- 申请权限和执行权限分离。
- 申请人不得审批或执行自己的高风险申请。
- 执行接口必须独立校验权限,不能只依赖前端按钮隐藏。
- 新权限通过
hg_admin_menu的按钮类型记录配置,并授权给管理角色和业务角色。
10. 台账、幂等与审计
10.1 台账要求
- 原台账不可更新和删除。
- 冲正台账金额必须等于原台账金额。
- 冲正台账方向必须与原台账相反。
reversal_of必须指向原台账 ID。- 同一原台账只能存在一条有效冲正台账。
- 钱包变更后必须满足
after_amount = before_amount ± amount。 - 可用余额和冻结余额不得小于 0。
10.2 幂等要求
- 申请接口使用调用方传入的幂等键。
- 执行接口以审批单 ID 和业务单 ID 共同保证幂等。
- 重复执行已完成审批时返回清晰业务错误,不重复写钱包和台账。
- 数据库唯一索引冲突必须转换为用户可理解的业务错误。
10.3 审计要求
业务审计至少记录:
- 模块和动作。
- 操作人、目标类型和目标 ID。
- 原状态和目标状态。
- 原台账 ID 和冲正台账 ID。
- 冲正金额、原因和证据摘要。
- 审批单号和 Trace ID。
- 变更前后摘要与结构化差异。
11. 异常与并发处理
| 场景 | 处理要求 |
|---|---|
| 重复点击执行 | 只允许第一次成功,后续返回“审批已执行” |
| 两个管理员同时执行 | 通过事务行锁保证只有一个事务成功 |
| 审批后业务状态变化 | 拒绝执行,要求重新发起审批 |
| 钱包余额不足以冲正 | 整体回滚,不产生台账和状态变化 |
| 原台账不存在或归属不符 | 拒绝执行并记录 Warning 日志 |
| 审批通过但事务失败 | 审批保持未执行,可排查后重试 |
| 审计写入失败 | 核心事务整体回滚 |
| 通知发送失败 | 不回滚核心事务,记录 Warning 并通过队列重试 |
12. 测试方案
12.1 状态机测试
每个状态机都要覆盖:
- 所有允许转换成功。
- 所有禁止转换失败。
- 相同状态重复申请失败。
- 注销会员恢复失败。
- 申请后状态变化导致执行失败。
- 已执行审批重复执行失败。
12.2 资金测试
- 充值入账冲正后余额正确。
- 任务佣金冲正后余额正确。
- 原台账保持不变。
- 冲正台账方向、金额和
reversal_of正确。 - 幂等键重复提交不产生重复台账。
- 两个并发执行请求只生成一条冲正台账。
- 余额不足时业务状态、钱包和台账均不变化。
- 审计日志、审批单和台账可以相互追溯。
12.3 内容测试
- 只有已下线内容可以归档。
- 已归档内容不可编辑和发布。
- 历史版本回滚生成新草稿。
- 回滚不改变当前发布版本。
- 新草稿的
base_version_id、版本号和内容正确。
12.4 回归测试
- 原充值审核、提现审核和任务审核流程不受影响。
- 原会员禁用和恢复流程仍可使用。
- 原站点配置版本与回滚流程不受影响。
- 字典加载、权限菜单和审计列表正常。
13. 验收标准
满足以下条件后视为第 12 章补强完成:
- 注销会员无法通过任何后台状态接口恢复。
- 充值成功后只能通过审批冲正,不允许直接修改余额或原台账。
- 已结算任务佣金可以通过审批冲正,且不可重复冲正。
- 每次冲正都能从业务单追溯到原台账、冲正台账、审批单和审计记录。
- 已下线内容可以归档,历史版本可以生成新草稿且不覆盖线上数据。
- 所有新增接口具有后端权限校验和明确的中文业务错误。
- 非法转换、重复执行、并发执行和余额不足测试全部通过。
- 后端编译、前端类型检查和现有模块回归测试通过。
14. 推荐实施顺序
- 新增数据库迁移并用 GoFrame CLI 重新生成模型和 DAO。
- 补充状态字典和统一转换判断。
- 修复会员状态申请与执行校验。
- 实现充值冲正申请与执行。
- 实现任务佣金冲正申请与执行。
- 实现内容归档和历史版本回滚草稿。
- 增加按钮权限和角色授权。
- 增加前端操作按钮、弹窗和状态展示。
- 完成状态机、资金并发和回归测试。