Files
olons_admin/docs/admin_reference_prd/后台管理系统概要设计.md
T

1245 lines
64 KiB
Markdown
Raw 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.
# 后台管理系统概要设计
> 文档版本:V1.0
> 编制日期:2026-10-08
> 依据:[后台管理系统需求文档](./后台管理系统需求文档.md)
> 技术基线:Go 1.24 + GoFrame v2.10 + Vue 3 + TypeScript + Naive UI + MySQL 8.0 + Redis
## 目录
- [1. 文档目标](#1-文档目标)
- [2. 设计原则](#2-设计原则)
- [3. 技术架构](#3-技术架构)
- [4. 系统模块设计](#4-系统模块设计)
- [5. 核心业务流程](#5-核心业务流程)
- [6. 数据库设计](#6-数据库设计)
- [7. 字典与状态设计](#7-字典与状态设计)
- [8. 接口设计约定](#8-接口设计约定)
- [9. 缓存、队列与定时任务](#9-缓存队列与定时任务)
- [10. 安全设计](#10-安全设计)
- [11. 可观测性与运维](#11-可观测性与运维)
- [12. 性能与容量设计](#12-性能与容量设计)
- [13. 开发与数据库迁移顺序](#13-开发与数据库迁移顺序)
- [14. 测试策略](#14-测试策略)
- [15. 分阶段交付](#15-分阶段交付)
- [16. 需进一步确认的设计决策](#16-需进一步确认的设计决策)
---
## 1. 文档目标
本文档用于将需求基线转换为可实施的系统概要设计,作为后续详细设计、数据库建模、接口定义、代码开发、测试与上线评审的共同输入。
本版设计重点解决:
- C 端与后台在配置、状态、金额和业务单号上的一致性。
- 会员隐私数据、银行卡与钱包账户的加密、脱敏、临时授权和审计。
- 充值、提现、账变、奖励金等资金操作的幂等、台账、冻结、复核与冲正。
- 站点配置、文本、Banner、会员等级等高影响配置的草稿、审批、发布、版本和回滚。
- 管理员 RBAC、数据权限、敏感操作复核与不可篡改审计。
### 1.1 范围边界
本设计覆盖需求文档中的 21 个后台页面和对应 C 端业务闭环。不包含支付机构的具体 SDK 选型、实名认证供应商选型、法律合规结论和生产密钥管理实施细节。这些内容需在接入真实资金前单独评审。
## 2. 设计原则
1. **单一事实源**:字典、状态、金额口径和配置版本由后端统一提供,前端不硬编码枚举。
2. **台账驱动资金**:余额不允许普通 CRUD 直接修改,所有变动必须由不可变台账产生。
3. **敏感数据分离**:会员主表不保存可直接展示的完整敏感值;密文、检索哈希和脱敏值分字段存储。
4. **最小权限**:菜单权限、接口权限、数据权限和敏感值查看权限分层判定。
5. **高风险双人复核**:资金、权限、禁用会员和发布配置采用“申请人 ≠ 复核人”。
6. **服务端状态机**:客户端只发送意图,不直接指定结果状态。
7. **可追溯与可冲正**:已生效的资金与审批记录不原地覆盖,通过反向记录冲正。
8. **兼容 HotGo 规范**:遵循 `api → controller → service → logic → dao` 分层,字典由 `internal/consts` 注册,路由由 `genrouter` 加载。
## 3. 技术架构
```mermaid
flowchart LR
A[后台 Web<br/>Vue 3 + Naive UI] -->|HTTPS /admin| B[GoFrame HTTP API]
C[C 端] -->|HTTPS /api| B
B --> D[认证、RBAC<br/>Casbin + Middleware]
B --> E[业务 Service / Logic]
E --> F[(MySQL 8.0)]
E --> G[(Redis / Cache)]
E --> H[对象存储<br/>附件/凭证/图片]
E --> I[队列 / Outbox]
I --> J[通知、统计、对账消费者]
E --> K[支付/客服/实名等外部服务]
B --> L[日志、Trace、指标、告警]
```
### 3.1 部署单元
| 单元 | 职责 | 状态 |
| --- | --- | --- |
| `web` | 后台 SPA,路由由后端菜单驱动 | 无状态 |
| `server` | 管理 API、C 端 API、业务状态机、审批和台账 | 无状态,可水平扩展 |
| MySQL | 核心业务数据、台账、审批和审计 | 主从/高可用 |
| Redis | 会话、限流、短期缓存、分布式锁 | 不作资金最终事实源 |
| 对象存储 | Banner、商品、任务、凭证和收款码 | 通过 `hg_sys_attachment` 管理元数据 |
| 队列 | 通知、统计、回调重试和对账 | 必须与 Outbox 表组合 |
### 3.2 代码模块划分
本项目属于系统核心业务,采用主模块实现,不作为临时 Addon。
| 业务域 | 后端模块建议 | 前端视图建议 |
| --- | --- | --- |
| 看板 | `dashboard` | `views/dashboard/business` |
| 站点与内容 | `siteConfig`, `content`, `banner`, `customerService` | `views/content/*` |
| 会员 | `appMember`, `memberLevel`, `memberPaymentAccount` | `views/member/*` |
| 商品 | `productCategory`, `product` | `views/product/*` |
| 任务 | `taskHall`, `task`, `taskSubmission` | `views/task/*` |
| 交易 | `tradeOrder`, `recharge`, `withdrawal` | `views/trade/*` |
| 资产 | `wallet`, `walletLedger`, `walletAdjustment` | `views/finance/*` |
| 治理 | `approval`, `sensitiveAccess`, `bizAudit` | `views/governance/*` |
每个模块依次在以下位置实现:
```text
server/api/admin/<module>/
server/internal/controller/admin/sys/<module>.go
server/internal/service/sys.go
server/internal/logic/sys/<module>.go
server/internal/model/input/sysin/<module>.go
server/internal/router/genrouter/<module>.go
web/src/api/<module>/index.ts
web/src/views/<module>/
```
## 4. 系统模块设计
### 4.1 认证与权限
复用现有 `hg_admin_member`、`hg_admin_role`、`hg_admin_menu`、`hg_admin_member_role`、`hg_admin_role_menu` 和 Casbin 能力。
权限判定顺序:
1. 校验管理员会话、账号状态和 MFA 状态。
2. 按路由权限标识判定功能权限。
3. 通过 `handler.FilterAuth` 或 `FilterAuthWithField` 施加数据范围。
4. 对完整手机号、银行卡、收款码等额外校验敏感值查看权限和二次认证。
5. 资金、权限和配置发布类操作进入审批流,申请人不得审批自己的申请。
### 4.2 站点配置与内容发布
- 站点配置按版本存储为 JSON,同时记录 Schema 版本、摘要和生效时间。
- 业务代码不从零散 key-value 直接组装核心规则,而是读取唯一的“已发布版本”。
- 文本内容使用主表 + 版本表;发布仅更新主表的 `published_version_id`。
- Banner 和客服渠道为结构化数据,支持有效期、排序、启停和作用域。
- 发布后删除缓存,通过 Outbox 发送“配置已更新”事件。
### 4.3 会员与隐私数据
- C 端会员使用 `hg_app_member`,不与后台管理员 `hg_admin_member` 混用。
- 登录检索使用 `mobile_hash`,列表展示使用 `mobile_mask`,完整手机号仅存在 `mobile_cipher`。
- 哈希使用带服务端 Pepper 的 HMAC-SHA-256,避免穷举原始手机号。
- 收款账户、地址和身份信息分表存储,列表查询不联表返回完整密文。
- 敏感值查看接口使用一次性授权令牌,返回短时数据,不缓存且写入专用审计表。
### 4.4 商品、任务和交易订单
- 商品、任务和会员等级均可停用;被历史订单引用后不得物理删除。
- 交易订单保存商品、任务、等级和佣金规则快照,后续修改基础配置不影响在途订单。
- 订单状态由 Logic 层状态机转换,更新时携带 `version` 作为乐观锁。
- 任务提交通过独立审核表流转,任务通过后由结算服务写入佣金台账。
### 4.5 钱包与资金安全
资金字段统一使用 `bigint` 存储最小货币单位(CNY 为分),字段名以 `_amount` 或 `_balance` 结尾,不使用 `float64` 参与资金计算。每个资金动作在单个数据库事务内完成:
1. 锁定业务单和钱包行。
2. 校验业务单状态、幂等键、可用/冻结余额和审批结果。
3. 写入不可变台账,台账同时记录变更前后值。
4. 更新钱包汇总值和版本号。
5. 更新业务单状态并写入 Outbox 事件。
6. 事务提交后异步通知 C 端、更新看板和执行对账。
### 4.6 统一审批
`hg_approval_request` 和 `hg_approval_action` 提供通用审批能力,覆盖:
- 提现审核与大额复核。
- 人工充值、账变、奖励金和冲正。
- 会员禁用、解禁和异常解冻。
- 角色权限变更。
- 站点配置、会员等级和重要内容发布。
审批请求保存目标类型、目标 ID、操作类型、变更摘要和完整 payload 快照。业务表只引用审批单号,审批通过后由对应业务 Logic 执行最终变更。
## 5. 核心业务流程
### 5.1 充值入账
```mermaid
sequenceDiagram
participant U as C 端会员
participant API as API
participant P as 支付渠道
participant R as 充值订单
participant W as 钱包/台账
U->>API: 创建充值订单
API->>R: 写入 pending_payment
API->>P: 创建支付
P-->>API: 异步回调
API->>R: 验签、金额、商户、幂等校验
API->>W: 事务内写台账并增加余额
API->>R: 置为 success
API-->>U: 通知到账
```
人工凭证充值不经过自动回调,进入初审和复核。两条路径共用同一个入账方法和幂等约束。
### 5.2 提现与资金冻结
```mermaid
stateDiagram-v2
[*] --> pending_review: 提交申请并冻结金额
pending_review --> reviewing: 初审通过
pending_review --> rejected: 初审驳回
reviewing --> processing: 复核通过
reviewing --> rejected: 复核驳回
processing --> success: 通道付款成功
processing --> failed: 付款失败
pending_review --> cancelled: 会员撤销
rejected --> [*]: 解冻
cancelled --> [*]: 解冻
failed --> pending_review: 审核后重试
success --> [*]: 扣减冻结金额
```
创建提现订单时立即将 `available_balance` 转入 `frozen_balance`;驳回或撤销时解冻;付款成功时扣减冻结余额。每一步均产生台账。
### 5.3 任务审核与佣金
1. 会员领取任务时生成交易订单,固化商品、任务、等级和佣金快照。
2. 会员提交任务证据,产生 `task_submission`。
3. 后台审核通过时更新提交记录,调用结算服务写入佣金台账。
4. 同一提交记录仅允许产生一笔有效佣金台账。
5. 已结算记录如需撤销,必须新建冲正审批并写入反向台账。
### 5.4 配置发布
1. 编辑者基于已发布版本创建草稿。
2. 前端完成基础校验,后端 `Filter()` 完成 Schema 和跨字段校验。
3. 提交审批后草稿锁定,禁止再编辑。
4. 审批人查看前后差异并通过或驳回。
5. 即时或定时发布,原版本置为历史版本。
6. 清理配置缓存,通知 C 端与后台重新拉取版本。
## 6. 数据库设计
### 6.1 数据库基线
- 生产基线为 MySQL 8.0,存储引擎 InnoDB,字符集 `utf8mb4`,排序规则统一为 `utf8mb4_0900_ai_ci`。
- 时间字段使用 `datetime(3)` 保存 UTC,展示时根据用户时区转换。
- 主键使用 `bigint unsigned`;全局业务单号使用时间有序 ID 或雪花 ID,字符串形式最长 32 位。
- 金额使用 `bigint` 最小货币单位;比例使用 `int` 万分比,`10000 = 100%`。
- 新增业务表使用 `hg_` 前缀;不直接修改 CLI 生成的 `entity`、`do` 和 `dao/internal`。
- 为适配 HotGo 代码生成和多库兼容,业务关系使用逻辑外键 + 索引,默认不创建物理外键。
- 可编辑业务表使用软删除;台账、审批动作、回调、幂等、Outbox 和审计表禁止删除。
### 6.2 通用字段
所有新表至少包含 `id`、`tenant_id` 和 `created_at`。可编辑业务表默认使用以下完整模板;台账、审批动作、回调、幂等、Outbox 和审计等不可变表仅保留上述三个基础字段与各自明确定义的业务字段,不设置 `updated_at`、`deleted_at`、`updated_by` 和 `deleted_by`。
| 字段 | 类型 | 约束 | 说明 |
| --- | --- | --- | --- |
| `id` | bigint unsigned | PK, auto_increment | 主键 |
| `tenant_id` | bigint unsigned | NOT NULL DEFAULT 0, INDEX | 租户;单租户部署为 0 |
| `status` | tinyint | NOT NULL DEFAULT 1, INDEX | 仅需通用启停时复用 `sys_normal_disable`:1正常、2停用;已有完整业务状态字段的表可省略此字段 |
| `sort` | int | NOT NULL DEFAULT 0 | 排序值,越小越靠前 |
| `version` | int unsigned | NOT NULL DEFAULT 0 | 乐观锁 |
| `remark` | varchar(500) | NULL | 内部备注 |
| `created_by` | bigint unsigned | NOT NULL DEFAULT 0 | 后台创建人;C 端创建时为 0 |
| `updated_by` | bigint unsigned | NOT NULL DEFAULT 0 | 最后后台更新人 |
| `deleted_by` | bigint unsigned | NOT NULL DEFAULT 0 | 软删除人 |
| `created_at` | datetime(3) | NOT NULL | 创建时间 |
| `updated_at` | datetime(3) | NOT NULL | 更新时间 |
| `deleted_at` | datetime(3) | NULL, INDEX | 软删除时间 |
### 6.3 表关系概览
一期共规划 39 张新业务表,按域划分如下:
| 业务域 | 表数 | 主要表 |
| --- | ---: | --- |
| 配置与内容 | 5 | 配置版本、内容与版本、Banner、客服渠道 |
| 会员 | 8 | 等级与版本、会员、隐私资料、地址、收款账户、会话、状态记录 |
| 商品与任务 | 7 | 分类、商品、任务大厅、任务、等级关系、任务提交 |
| 交易与资金 | 11 | 交易订单、钱包、台账、支付渠道、充值、提现、账变、审核、回调、对账 |
| 治理与可靠性 | 7 | 审批、敏感查看、审计、幂等、Outbox、看板汇总 |
| 通知 | 1 | C 端通知 |
```mermaid
erDiagram
APP_MEMBER_LEVEL ||--o{ APP_MEMBER : owns
APP_MEMBER ||--|| APP_MEMBER_PROFILE : has
APP_MEMBER ||--o{ APP_MEMBER_ADDRESS : has
APP_MEMBER ||--o{ APP_MEMBER_PAYMENT_ACCOUNT : binds
APP_MEMBER ||--o{ APP_MEMBER_SESSION : logs_in
APP_MEMBER ||--|| WALLET_ACCOUNT : owns
WALLET_ACCOUNT ||--o{ WALLET_LEDGER : produces
PRODUCT_CATEGORY ||--o{ PRODUCT : contains
TASK_HALL ||--o{ TASK_HALL_LEVEL : permits
APP_MEMBER_LEVEL ||--o{ TASK_HALL_LEVEL : allowed
TASK_HALL ||--o{ TASK : groups
TASK ||--o{ TASK_LEVEL : permits
APP_MEMBER_LEVEL ||--o{ TASK_LEVEL : allowed
TASK ||--o{ TRADE_ORDER : creates
APP_MEMBER ||--o{ TRADE_ORDER : places
TRADE_ORDER ||--o| TASK_SUBMISSION : submits
APP_MEMBER ||--o{ RECHARGE_ORDER : recharges
APP_MEMBER ||--o{ WITHDRAWAL_ORDER : withdraws
APP_MEMBER_PAYMENT_ACCOUNT ||--o{ WITHDRAWAL_ORDER : receives
APPROVAL_REQUEST ||--o{ APPROVAL_ACTION : contains
APPROVAL_REQUEST ||--o{ FINANCE_REVIEW : drives
CONTENT ||--o{ CONTENT_VERSION : versions
SITE_CONFIG_VERSION ||--o| APPROVAL_REQUEST : publishes
PAYMENT_CHANNEL ||--o{ RECHARGE_ORDER : handles
PAYMENT_CHANNEL ||--o{ WITHDRAWAL_ORDER : handles
```
### 6.4 现有系统表复用
| 表 | 用途 | 设计处理 |
| --- | --- | --- |
| `hg_admin_member` | 后台管理员 | 直接复用,不存 C 端会员 |
| `hg_admin_role` / `hg_admin_menu` | 角色、菜单、接口权限 | 直接复用,增加业务菜单数据 |
| `hg_admin_member_role` / `hg_admin_role_menu` | RBAC 关系 | 直接复用 |
| `hg_sys_attachment` | 文件与对象存储元数据 | 图片、凭证、收款码统一引用附件 ID |
| `hg_sys_dict_type` / `hg_sys_dict_data` | 可维护字典 | 用于非核心动态选项 |
| `hg_sys_config` | HotGo 系统自身配置 | 仅保留框架配置,不承载需审批的业务配置 |
| `hg_sys_log` / `hg_sys_login_log` | 请求与登录日志 | 保留,与业务审计表互补 |
字典功能不新建表、不新建 API、不另做前端 Store。统一复用 `hg_sys_dict_type`、`hg_sys_dict_data`、`server/internal/library/dict`、`/dictData/option`、`/dictData/options` 和 `web/src/store/modules/dict.ts`。详细复用规则见第 7 章。
### 6.5 配置与内容域
#### 6.5.1 `hg_site_config_version` 站点配置版本
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `config_no` | varchar(32) | NOT NULL, UNIQUE(`tenant_id`,`config_no`) | 配置版本号 |
| `config_group` | varchar(64) | NOT NULL, INDEX | `site_basic`/`trade_rule`/`time_window` 等 |
| `schema_version` | varchar(32) | NOT NULL | 校验 Schema 版本 |
| `config_json` | json | NOT NULL | 完整配置快照 |
| `config_digest` | char(64) | NOT NULL | SHA-256,用于差异与一致性校验 |
| `publish_status` | tinyint | NOT NULL, INDEX | 1草稿 2待审 3已发布 4已回滚 5已失效 |
| `effective_at` | datetime(3) | NULL, INDEX | 计划生效时间 |
| `published_at` | datetime(3) | NULL | 实际发布时间 |
| `approval_request_id` | bigint unsigned | NOT NULL DEFAULT 0, INDEX | 关联审批单 |
| `base_version_id` | bigint unsigned | NOT NULL DEFAULT 0 | 基础版本 |
索引:`INDEX idx_config_current (tenant_id, config_group, publish_status, effective_at)`。同一租户和配置组在某一时点只允许一个有效已发布版本,由发布事务保证。
#### 6.5.2 `hg_content` 内容主表
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `content_key` | varchar(64) | UNIQUE(`tenant_id`,`content_key`) | 稳定内容标识,删除后不复用 |
| `content_type` | varchar(32) | NOT NULL, INDEX | notice/about/faq/rule/activity/popup |
| `title` | varchar(200) | NOT NULL | 后台标题 |
| `published_version_id` | bigint unsigned | NOT NULL DEFAULT 0 | 当前发布版本 |
| `publish_status` | tinyint | NOT NULL, INDEX | 内容状态 |
| `published_at` | datetime(3) | NULL | 发布时间 |
#### 6.5.3 `hg_content_version` 内容版本
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `content_id` | bigint unsigned | NOT NULL, INDEX | 内容主表 ID |
| `version_no` | int unsigned | UNIQUE(`content_id`,`version_no`) | 递增版本 |
| `title` | varchar(200) | NOT NULL | 展示标题 |
| `summary` | varchar(500) | NULL | 摘要 |
| `body_html` | longtext | NOT NULL | 服务端清洗后 HTML |
| `body_text` | longtext | NULL | 搜索与降级文本 |
| `asset_ids` | json | NULL | 正文引用附件 ID |
| `publish_status` | tinyint | NOT NULL, INDEX | 1草稿 2待审 3已发布 4已下线 5已归档 |
| `effective_at` | datetime(3) | NULL | 定时发布 |
| `approval_request_id` | bigint unsigned | NOT NULL DEFAULT 0 | 审批单 |
#### 6.5.4 `hg_banner` Banner
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `name` | varchar(100) | NOT NULL | 后台名称 |
| `position` | varchar(32) | NOT NULL, INDEX | home_top/home_popup 等 |
| `image_attachment_id` | bigint unsigned | NOT NULL | 图片附件 |
| `alt_text` | varchar(200) | NOT NULL | 替代文本 |
| `target_type` | tinyint | NOT NULL | 1无跳转 2内部路由 3外部 URL |
| `target_value` | varchar(500) | NULL | 跳转值 |
| `start_at` / `end_at` | datetime(3) | NULL, INDEX | 有效期 |
| `publish_status` | tinyint | NOT NULL, INDEX | 草稿/已发布/已下线 |
#### 6.5.5 `hg_customer_service_channel` 客服渠道
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `name` | varchar(100) | NOT NULL | 渠道名称 |
| `channel_type` | tinyint | NOT NULL | 1内置工单 2外部链接 3客服电话 4即时通讯 |
| `entry_url_cipher` | varchar(1024) | NULL | 加密入口地址 |
| `fallback_text` | varchar(500) | NULL | 降级联系方式 |
| `work_time_json` | json | NOT NULL | 工作时段及时区 |
| `allowed_origins` | json | NULL | iframe 来源白名单 |
### 6.6 会员域
#### 6.6.1 `hg_app_member_level` 会员等级
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `level_code` | varchar(32) | UNIQUE(`tenant_id`,`level_code`) | 稳定等级编码 |
| `name` | varchar(64) | NOT NULL | 等级名称 |
| `current_version_id` | bigint unsigned | NOT NULL DEFAULT 0 | 当前规则版本 |
| `member_count` | bigint unsigned | NOT NULL DEFAULT 0 | 可重建的统计值 |
#### 6.6.2 `hg_app_member_level_version` 等级规则版本
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `level_id` | bigint unsigned | NOT NULL, INDEX | 等级 ID |
| `version_no` | int unsigned | UNIQUE(`level_id`,`version_no`) | 版本号 |
| `upgrade_amount` | bigint | NOT NULL DEFAULT 0 | 升级金额,分 |
| `gift_amount` | bigint | NOT NULL DEFAULT 0 | 赠送金额,分 |
| `daily_order_limit` | int unsigned | NOT NULL DEFAULT 0 | 每日接单次数 |
| `commission_rate` | int unsigned | NOT NULL DEFAULT 0 | 佣金万分比 |
| `daily_withdraw_limit` | int unsigned | NOT NULL DEFAULT 0 | 每日提现次数 |
| `rule_json` | json | NULL | 扩展规则快照 |
| `publish_status` | tinyint | NOT NULL, INDEX | 发布状态 |
| `effective_at` | datetime(3) | NULL | 生效时间 |
#### 6.6.3 `hg_app_member` C 端会员
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `member_no` | varchar(32) | UNIQUE(`tenant_id`,`member_no`) | 对外会员号 |
| `username` | varchar(64) | UNIQUE(`tenant_id`,`username`) | 登录名,注销后不复用 |
| `mobile_cipher` | varchar(512) | NOT NULL | 手机号密文 |
| `mobile_hash` | char(64) | UNIQUE(`tenant_id`,`mobile_hash`) | 带 Pepper 检索哈希,注销后按合规策略做不可逆匿名化 |
| `mobile_mask` | varchar(32) | NOT NULL | 脱敏手机号 |
| `password_hash` | varchar(255) | NOT NULL | Argon2id/bcrypt 结果 |
| `trade_password_hash` | varchar(255) | NULL | 交易密码,不可回显 |
| `level_id` | bigint unsigned | NOT NULL, INDEX | 会员等级 |
| `parent_id` | bigint unsigned | NOT NULL DEFAULT 0, INDEX | 直接上级 |
| `level` | int unsigned | NOT NULL DEFAULT 1 | 关系树级别 |
| `tree` | varchar(1024) | NOT NULL DEFAULT '' | 关系树路径 |
| `invite_code` | varchar(32) | UNIQUE(`tenant_id`,`invite_code`) | 邀请码 |
| `member_status` | tinyint | NOT NULL DEFAULT 1, INDEX | 会员生命周期:正常/受限/禁用/注销 |
| `risk_status` | tinyint | NOT NULL DEFAULT 1, INDEX | 1正常 2观察 3限制 4冻结 |
| `auto_dispatch` | tinyint | NOT NULL DEFAULT 2 | 复用 `sys_switch`:1开启、2关闭 |
| `credit_score` | int | NOT NULL DEFAULT 100 | 信用分 |
| `last_login_at` | datetime(3) | NULL | 最后登录时间 |
| `last_login_ip_cipher` | varchar(512) | NULL | 加密 IP |
| `last_login_region` | varchar(128) | NULL | IP 地区粗粒度结果 |
重要索引:`idx_member_parent (tenant_id,parent_id,status)`、`idx_member_level (tenant_id,level_id,status)`、`idx_member_created (tenant_id,created_at,id)`。
#### 6.6.4 `hg_app_member_profile` 会员隐私资料
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `member_id` | bigint unsigned | UNIQUE | 会员 ID |
| `real_name_cipher` | varchar(512) | NULL | 姓名密文 |
| `real_name_mask` | varchar(64) | NULL | 脱敏姓名 |
| `id_no_cipher` | varchar(1024) | NULL | 证件号密文 |
| `id_no_hash` | char(64) | NULL, INDEX | 证件检索哈希 |
| `id_no_mask` | varchar(64) | NULL | 脱敏证件号 |
| `avatar_attachment_id` | bigint unsigned | NOT NULL DEFAULT 0 | 头像 |
| `kyc_status` | tinyint | NOT NULL DEFAULT 0, INDEX | 0未认证 1审核中 2已认证 3驳回 |
| `kyc_verified_at` | datetime(3) | NULL | 认证时间 |
#### 6.6.5 `hg_app_member_address` 会员地址
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 ID |
| `receiver_name_cipher` / `receiver_name_mask` | varchar(512)/varchar(64) | NOT NULL | 收件人密文/脱敏值 |
| `receiver_mobile_cipher` / `receiver_mobile_mask` | varchar(512)/varchar(32) | NOT NULL | 电话密文/脱敏值 |
| `province_id` / `city_id` / `district_id` | bigint unsigned | NOT NULL DEFAULT 0 | 省市区 |
| `address_cipher` | varchar(1024) | NOT NULL | 详细地址密文 |
| `is_default` | tinyint | NOT NULL DEFAULT 0 | 默认地址 |
#### 6.6.6 `hg_app_member_payment_account` 收款账户
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 ID |
| `account_type` | tinyint | NOT NULL, INDEX | 1银行卡 2数字钱包 3云闪付 4支付宝 5微信 |
| `bank_code` | varchar(32) | NULL | 银行编码 |
| `bank_name` | varchar(100) | NULL | 银行名称快照 |
| `holder_name_cipher` / `holder_name_mask` | varchar(512)/varchar(64) | NOT NULL | 户名 |
| `account_no_cipher` | varchar(1024) | NOT NULL | 账号密文 |
| `account_no_hash` | char(64) | NOT NULL, INDEX | 检索与去重哈希 |
| `account_no_mask` | varchar(64) | NOT NULL | 脱敏账号 |
| `qr_attachment_id` | bigint unsigned | NOT NULL DEFAULT 0 | 收款码附件 |
| `verify_status` | tinyint | NOT NULL DEFAULT 0 | 校验状态 |
| `is_default` | tinyint | NOT NULL DEFAULT 0 | 默认收款账户 |
唯一约束:`UNIQUE (tenant_id,member_id,account_type,account_no_hash)`。已解绑账户可重新启用,不重复插入。MySQL 中 `NULL` 不能可靠表示“仅未删除数据唯一”,因此本设计不将可空 `deleted_at` 加入唯一索引。
#### 6.6.7 `hg_app_member_session` 会员会话
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 ID |
| `session_no` | varchar(64) | UNIQUE | 会话号 |
| `refresh_token_hash` | char(64) | NOT NULL | 刷新令牌哈希 |
| `device_id_hash` | char(64) | NULL, INDEX | 设备标识哈希 |
| `ip_cipher` | varchar(512) | NULL | IP 密文 |
| `user_agent` | varchar(512) | NULL | 客户端信息 |
| `expires_at` | datetime(3) | NOT NULL, INDEX | 过期时间 |
| `revoked_at` | datetime(3) | NULL | 撤销时间 |
#### 6.6.8 `hg_app_member_status_log` 会员状态记录
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 ID |
| `from_status` / `to_status` | tinyint | NOT NULL | 状态变更 |
| `reason_code` | varchar(64) | NOT NULL | 标准原因 |
| `reason_text` | varchar(500) | NULL | 补充说明 |
| `effective_at` / `expire_at` | datetime(3) | NULL | 生效和到期时间 |
| `approval_request_id` | bigint unsigned | NOT NULL DEFAULT 0 | 审批单 |
| `operator_id` | bigint unsigned | NOT NULL | 操作人 |
该表为追加表,不软删除。
### 6.7 商品与任务域
#### 6.7.1 `hg_product_category` 商品分类
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `pid` | bigint unsigned | NOT NULL DEFAULT 0, INDEX | 父级 ID |
| `level` | int unsigned | NOT NULL DEFAULT 1 | 树等级 |
| `tree` | varchar(512) | NOT NULL DEFAULT '' | 关系树 |
| `category_code` | varchar(32) | UNIQUE(`tenant_id`,`category_code`) | 分类编码 |
| `name` | varchar(100) | NOT NULL | 分类名称 |
#### 6.7.2 `hg_product` 商品
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `product_no` | varchar(32) | UNIQUE(`tenant_id`,`product_no`) | 商品编号 |
| `category_id` | bigint unsigned | NOT NULL, INDEX | 分类 |
| `product_type` | tinyint | NOT NULL DEFAULT 1, INDEX | 1标准商品 2手工商城商品 |
| `payment_type` | varchar(32) | NOT NULL DEFAULT 'balance', INDEX | 优先复用并按需扩展现有 `payType` 枚举字典 |
| `name` | varchar(200) | NOT NULL, INDEX | 商品名称 |
| `shop_name` | varchar(100) | NOT NULL | 店铺名称快照 |
| `price_amount` | bigint | NOT NULL | 单价,分 |
| `currency` | char(3) | NOT NULL DEFAULT 'CNY' | 币种 |
| `cover_attachment_id` | bigint unsigned | NOT NULL | 封面 |
| `detail_html` | longtext | NULL | 清洗后富文本 |
| `is_recommended` | tinyint | NOT NULL DEFAULT 2, INDEX | 复用 `sys_switch`:1推荐、2不推荐 |
| `publish_status` | tinyint | NOT NULL, INDEX | 草稿/上架/下架 |
| `start_at` / `end_at` | datetime(3) | NULL | 展示时间 |
#### 6.7.3 `hg_task_hall` 任务大厅
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `hall_code` | varchar(32) | UNIQUE(`tenant_id`,`hall_code`) | 大厅编码 |
| `name` | varchar(100) | NOT NULL | 名称 |
| `icon_attachment_id` | bigint unsigned | NOT NULL | 图标 |
| `summary` | varchar(500) | NULL | 简介 |
| `commission_rate` | int unsigned | NOT NULL DEFAULT 0 | 万分比 |
| `publish_status` | tinyint | NOT NULL, INDEX | 发布状态 |
#### 6.7.4 `hg_task_hall_level` 任务大厅可用等级
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `id` | bigint unsigned | PK, auto_increment | 主键 |
| `tenant_id` | bigint unsigned | NOT NULL DEFAULT 0 | 租户 |
| `hall_id` | bigint unsigned | NOT NULL, INDEX | 任务大厅 |
| `level_id` | bigint unsigned | NOT NULL, INDEX | 会员等级 |
| `created_at` | datetime(3) | NOT NULL | 创建时间 |
唯一约束:`UNIQUE (tenant_id,hall_id,level_id)`。
#### 6.7.5 `hg_task` 任务
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `task_no` | varchar(32) | UNIQUE(`tenant_id`,`task_no`) | 任务编号 |
| `hall_id` | bigint unsigned | NOT NULL, INDEX | 任务大厅 |
| `title` | varchar(200) | NOT NULL | 标题 |
| `description` | varchar(1000) | NULL | 描述 |
| `detail_html` | longtext | NULL | 详情 |
| `cover_attachment_id` | bigint unsigned | NOT NULL | 封面 |
| `commission_amount` | bigint | NOT NULL DEFAULT 0 | 固定佣金,分 |
| `commission_rate` | int unsigned | NOT NULL DEFAULT 0 | 比例佣金,万分比 |
| `daily_limit` | int unsigned | NOT NULL DEFAULT 0 | 每日总量,0 不限 |
| `per_member_limit` | int unsigned | NOT NULL DEFAULT 1 | 单会员限制 |
| `start_at` / `end_at` | datetime(3) | NULL, INDEX | 任务周期 |
| `publish_status` | tinyint | NOT NULL, INDEX | 发布状态 |
#### 6.7.6 `hg_task_level` 任务可用等级
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `id` | bigint unsigned | PK, auto_increment | 主键 |
| `tenant_id` | bigint unsigned | NOT NULL DEFAULT 0 | 租户 |
| `task_id` | bigint unsigned | NOT NULL, INDEX | 任务 |
| `level_id` | bigint unsigned | NOT NULL, INDEX | 会员等级 |
| `created_at` | datetime(3) | NOT NULL | 创建时间 |
唯一约束:`UNIQUE (tenant_id,task_id,level_id)`。
#### 6.7.7 `hg_task_submission` 会员任务提交
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `submission_no` | varchar(32) | UNIQUE | 提交单号 |
| `trade_order_id` | bigint unsigned | UNIQUE | 交易订单 |
| `task_id` | bigint unsigned | NOT NULL, INDEX | 任务 |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 |
| `evidence_text` | varchar(2000) | NULL | 提交说明 |
| `evidence_attachment_ids` | json | NULL | 证据附件 ID |
| `submission_status` | tinyint | NOT NULL, INDEX | 1待审 2通过 3驳回 4已结算 5已冲正 |
| `commission_amount` | bigint | NOT NULL DEFAULT 0 | 审核时的佣金快照 |
| `reviewed_by` | bigint unsigned | NOT NULL DEFAULT 0 | 审核人 |
| `reviewed_at` | datetime(3) | NULL | 审核时间 |
| `review_reason` | varchar(500) | NULL | 审核意见 |
| `settled_at` | datetime(3) | NULL | 结算时间 |
### 6.8 交易与资金域
#### 6.8.1 `hg_trade_order` 交易订单
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `order_no` | varchar(32) | UNIQUE | 订单号 |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 |
| `task_id` / `product_id` | bigint unsigned | NOT NULL DEFAULT 0, INDEX | 任务/商品 |
| `order_type` | tinyint | NOT NULL, INDEX | 1商品 2任务 3手工商城 |
| `quantity` | int unsigned | NOT NULL DEFAULT 1 | 数量 |
| `unit_price_amount` | bigint | NOT NULL | 单价,分 |
| `total_amount` | bigint | NOT NULL | 订单金额,分 |
| `commission_amount` | bigint | NOT NULL DEFAULT 0 | 佣金,分 |
| `currency` | char(3) | NOT NULL DEFAULT 'CNY' | 币种 |
| `member_level_id` | bigint unsigned | NOT NULL | 下单时等级 |
| `rule_snapshot` | json | NOT NULL | 商品、等级、佣金规则快照 |
| `order_status` | tinyint | NOT NULL, INDEX | 匹配中/待处理/处理中/完成/超时/冻结/取消/失败 |
| `freeze_status` | tinyint | NOT NULL DEFAULT 0 | 冻结状态 |
| `matched_at` / `completed_at` / `unfrozen_at` | datetime(3) | NULL | 业务节点 |
索引:`idx_order_member_time (tenant_id,member_id,created_at,id)`、`idx_order_status_time (tenant_id,order_status,created_at,id)`。
#### 6.8.2 `hg_wallet_account` 钱包账户
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `member_id` | bigint unsigned | UNIQUE(`tenant_id`,`member_id`,`currency`) | 会员 |
| `currency` | char(3) | NOT NULL DEFAULT 'CNY' | 币种 |
| `available_balance` | bigint | NOT NULL DEFAULT 0 | 可用余额,分 |
| `frozen_balance` | bigint | NOT NULL DEFAULT 0 | 冻结余额,分 |
| `total_income` | bigint | NOT NULL DEFAULT 0 | 累计收入,可重建 |
| `total_expense` | bigint | NOT NULL DEFAULT 0 | 累计支出,可重建 |
| `account_status` | tinyint | NOT NULL DEFAULT 1 | 1正常 2只收不付 3冻结 4关闭 |
| `version` | int unsigned | NOT NULL DEFAULT 0 | 乐观锁 |
检查约束:`available_balance >= 0`、`frozen_balance >= 0`。
#### 6.8.3 `hg_wallet_ledger` 钱包台账
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `ledger_no` | varchar(32) | UNIQUE | 台账号 |
| `account_id` | bigint unsigned | NOT NULL, INDEX | 钱包账户 |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 |
| `biz_type` | varchar(32) | NOT NULL, INDEX | recharge/withdraw/freeze/unfreeze/commission/adjust/reversal |
| `biz_no` | varchar(32) | NOT NULL | 业务单号 |
| `entry_type` | tinyint | NOT NULL | 1可用余额 2冻结余额 |
| `direction` | tinyint | NOT NULL | 1收入 2支出 |
| `amount` | bigint | NOT NULL | 变动绝对值,分 |
| `before_balance` / `after_balance` | bigint | NOT NULL | 变动前后值 |
| `currency` | char(3) | NOT NULL | 币种 |
| `reversal_of` | bigint unsigned | NOT NULL DEFAULT 0, INDEX | 被冲正台账 ID |
| `idempotency_key` | varchar(128) | NOT NULL | 幂等键 |
| `occurred_at` | datetime(3) | NOT NULL, INDEX | 业务发生时间 |
| `created_at` | datetime(3) | NOT NULL | 入库时间 |
唯一约束:`UNIQUE (account_id,idempotency_key)`。表中不设置 `updated_at`、`deleted_at`,禁止 UPDATE 和 DELETE。
#### 6.8.4 `hg_payment_channel` 支付渠道
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `channel_code` | varchar(32) | UNIQUE(`tenant_id`,`channel_code`) | 渠道编码 |
| `name` | varchar(100) | NOT NULL | 渠道名称 |
| `channel_type` | tinyint | NOT NULL, INDEX | 1微信 2支付宝 3银行卡 4人工 |
| `direction` | tinyint | NOT NULL | 1充值 2提现 3双向 |
| `config_cipher` | longtext | NULL | 渠道密钥加密密文,不返回前端 |
| `min_amount` / `max_amount` | bigint | NOT NULL DEFAULT 0 | 金额限制 |
| `fee_type` | tinyint | NOT NULL DEFAULT 1 | 1固定 2比例 3混合 |
| `fee_fixed_amount` | bigint | NOT NULL DEFAULT 0 | 固定手续费 |
| `fee_rate` | int unsigned | NOT NULL DEFAULT 0 | 费率万分比 |
#### 6.8.5 `hg_recharge_order` 充值订单
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `recharge_no` | varchar(32) | UNIQUE | 充值单号 |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 |
| `channel_id` | bigint unsigned | NOT NULL, INDEX | 支付渠道 |
| `request_amount` / `paid_amount` | bigint | NOT NULL | 申请/实付金额 |
| `currency` | char(3) | NOT NULL DEFAULT 'CNY' | 币种 |
| `external_no` | varchar(128) | NULL, INDEX | 外部支付单号 |
| `voucher_attachment_ids` | json | NULL | 人工凭证 |
| `recharge_status` | tinyint | NOT NULL, INDEX | 待支付/待审/成功/驳回/过期/取消 |
| `paid_at` / `reviewed_at` / `credited_at` | datetime(3) | NULL | 关键时间 |
| `approval_request_id` | bigint unsigned | NOT NULL DEFAULT 0 | 人工审核单 |
| `ledger_id` | bigint unsigned | NOT NULL DEFAULT 0 | 入账台账 |
索引:`idx_recharge_member_time`、`idx_recharge_status_time`;外部单号在非空时必须唯一,由 Logic 与幂等表联合保证。
#### 6.8.6 `hg_withdrawal_order` 提现订单
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `withdrawal_no` | varchar(32) | UNIQUE | 提现单号 |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 会员 |
| `payment_account_id` | bigint unsigned | NOT NULL | 收款账户 |
| `channel_id` | bigint unsigned | NOT NULL DEFAULT 0 | 付款渠道 |
| `request_amount` | bigint | NOT NULL | 申请金额 |
| `fee_amount` | bigint | NOT NULL DEFAULT 0 | 手续费 |
| `actual_amount` | bigint | NOT NULL | 实际到账 |
| `currency` | char(3) | NOT NULL DEFAULT 'CNY' | 币种 |
| `account_snapshot_cipher` | longtext | NOT NULL | 收款账户加密快照 |
| `account_mask` | varchar(128) | NOT NULL | 脱敏快照 |
| `risk_result` | json | NULL | 风控命中摘要 |
| `withdrawal_status` | tinyint | NOT NULL, INDEX | 待审/复核中/处理中/成功/失败/驳回/取消 |
| `approval_request_id` | bigint unsigned | NOT NULL DEFAULT 0 | 审批单 |
| `external_no` | varchar(128) | NULL, INDEX | 外部付款单号 |
| `freeze_ledger_id` / `final_ledger_id` | bigint unsigned | NOT NULL DEFAULT 0 | 冻结/完成台账 |
| `reviewed_at` / `processed_at` / `completed_at` | datetime(3) | NULL | 关键时间 |
#### 6.8.7 `hg_wallet_adjustment_request` 账变申请
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `request_no` | varchar(32) | UNIQUE | 申请单号 |
| `member_id` / `account_id` | bigint unsigned | NOT NULL, INDEX | 会员与钱包 |
| `adjust_type` | tinyint | NOT NULL | 1奖励 2补款 3扣款 4冲正 5其他 |
| `direction` | tinyint | NOT NULL | 收入/支出 |
| `amount` | bigint | NOT NULL | 金额,分 |
| `reason_code` / `reason_text` | varchar(64)/varchar(500) | NOT NULL | 原因 |
| `evidence_attachment_ids` | json | NULL | 凭证 |
| `request_status` | tinyint | NOT NULL, INDEX | 草稿/待审/通过/驳回/已执行/失败 |
| `approval_request_id` | bigint unsigned | NOT NULL DEFAULT 0 | 审批单 |
| `ledger_id` | bigint unsigned | NOT NULL DEFAULT 0 | 执行后台账 |
#### 6.8.8 `hg_finance_review` 财务审核记录
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `approval_request_id` | bigint unsigned | NOT NULL, INDEX | 审批单 |
| `biz_type` / `biz_id` | varchar(32)/bigint unsigned | NOT NULL, INDEX | 充值/提现/账变等 |
| `review_stage` | tinyint | NOT NULL | 1初审 2复核 3放款 |
| `reviewer_id` | bigint unsigned | NOT NULL, INDEX | 审核人 |
| `decision` | tinyint | NOT NULL | 1通过 2驳回 3退回补充 |
| `reason_code` / `reason_text` | varchar(64)/varchar(500) | NOT NULL | 意见 |
| `snapshot_json` | json | NOT NULL | 审核时数据快照 |
| `created_at` | datetime(3) | NOT NULL | 审核时间 |
唯一约束:`UNIQUE (approval_request_id,review_stage,reviewer_id)`。申请人与审核人不同的约束由 Logic 保证。
#### 6.8.9 `hg_payment_callback` 支付回调记录
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `channel_id` | bigint unsigned | NOT NULL, INDEX | 渠道 |
| `callback_no` | varchar(128) | UNIQUE | 渠道回调唯一号 |
| `biz_type` / `biz_no` | varchar(32)/varchar(32) | NOT NULL, INDEX | 业务定位 |
| `headers_digest` | char(64) | NOT NULL | Header 摘要 |
| `payload_cipher` | longtext | NOT NULL | 回调加密原文 |
| `verify_status` | tinyint | NOT NULL | 验签结果 |
| `process_status` | tinyint | NOT NULL, INDEX | 待处理/成功/失败/已忽略 |
| `error_message` | varchar(1000) | NULL | 处理失败摘要 |
| `received_at` / `processed_at` | datetime(3) | NOT NULL/NULL | 回调时间 |
该表不软删除,原文禁止直接记入通用日志。
#### 6.8.10 `hg_reconciliation_batch` 对账批次
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `batch_no` | varchar(32) | UNIQUE | 对账批次号 |
| `channel_id` | bigint unsigned | NOT NULL DEFAULT 0, INDEX | 渠道,0 表示内部台账对账 |
| `reconcile_date` | date | NOT NULL, INDEX | 对账日期 |
| `source_type` | tinyint | NOT NULL | 1渠道账单 2业务单/台账 3钱包/台账 |
| `file_attachment_id` | bigint unsigned | NOT NULL DEFAULT 0 | 原始账单文件 |
| `total_count` / `matched_count` / `difference_count` | bigint unsigned | NOT NULL DEFAULT 0 | 数量汇总 |
| `total_amount` / `difference_amount` | bigint | NOT NULL DEFAULT 0 | 金额汇总 |
| `batch_status` | tinyint | NOT NULL, INDEX | 1待执行 2执行中 3完成 4有差异 5失败 |
| `started_at` / `finished_at` | datetime(3) | NULL | 执行时间 |
唯一约束:`UNIQUE (tenant_id,channel_id,reconcile_date,source_type)`。
#### 6.8.11 `hg_reconciliation_item` 对账差异项
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `batch_id` | bigint unsigned | NOT NULL, INDEX | 对账批次 |
| `biz_type` / `biz_no` | varchar(32)/varchar(32) | NOT NULL, INDEX | 内部业务单 |
| `external_no` | varchar(128) | NULL, INDEX | 渠道单号 |
| `difference_type` | tinyint | NOT NULL, INDEX | 1内部多 2渠道多 3金额差 4状态差 5时间差 |
| `internal_amount` / `external_amount` | bigint | NOT NULL DEFAULT 0 | 内部/外部金额 |
| `internal_status` / `external_status` | varchar(32) | NULL | 状态快照 |
| `item_status` | tinyint | NOT NULL, INDEX | 1待处理 2已确认 3已修复 4已忽略 |
| `handler_id` | bigint unsigned | NOT NULL DEFAULT 0 | 处理人 |
| `handle_reason` | varchar(500) | NULL | 处理说明 |
| `handled_at` | datetime(3) | NULL | 处理时间 |
差异修复如涉及资金,必须发起账变或冲正审批,禁止在对账页面直接修改台账。
### 6.9 审批、审计与可靠性域
#### 6.9.1 `hg_approval_request` 审批请求
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `approval_no` | varchar(32) | UNIQUE | 审批单号 |
| `approval_type` | varchar(32) | NOT NULL, INDEX | withdrawal/config/permission/member_status/adjustment |
| `target_type` / `target_id` | varchar(32)/bigint unsigned | NOT NULL, INDEX | 目标定位 |
| `action` | varchar(64) | NOT NULL | 拟执行动作 |
| `title` | varchar(200) | NOT NULL | 审批摘要 |
| `payload_json` | json | NOT NULL | 待执行数据快照 |
| `diff_json` | json | NULL | 前后差异 |
| `risk_level` | tinyint | NOT NULL DEFAULT 1 | 1低 2中 3高 4极高 |
| `required_approvals` | int unsigned | NOT NULL DEFAULT 1 | 需要的通过数 |
| `approval_status` | tinyint | NOT NULL, INDEX | 草稿/待审/审批中/通过/驳回/取消/已执行/失败 |
| `applicant_id` | bigint unsigned | NOT NULL, INDEX | 申请人 |
| `submitted_at` / `decided_at` / `executed_at` | datetime(3) | NULL | 关键时间 |
| `expire_at` | datetime(3) | NULL | 超时时间 |
#### 6.9.2 `hg_approval_action` 审批动作
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `approval_request_id` | bigint unsigned | NOT NULL, INDEX | 审批请求 |
| `step_no` | int unsigned | NOT NULL | 节点顺序 |
| `actor_id` | bigint unsigned | NOT NULL, INDEX | 操作人 |
| `action` | tinyint | NOT NULL | 1提交 2通过 3驳回 4退回 5取消 6执行 |
| `reason_code` / `comment` | varchar(64)/varchar(1000) | NULL | 原因和意见 |
| `snapshot_json` | json | NOT NULL | 当时快照 |
| `actor_ip_cipher` | varchar(512) | NULL | 操作 IP 密文 |
| `mfa_verified` | tinyint | NOT NULL DEFAULT 0 | 是否二次认证 |
| `created_at` | datetime(3) | NOT NULL | 动作时间 |
追加表,不允许 UPDATE/DELETE。
#### 6.9.3 `hg_sensitive_access_log` 敏感数据查看日志
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `access_no` | varchar(32) | UNIQUE | 查看流水号 |
| `actor_id` | bigint unsigned | NOT NULL, INDEX | 管理员 |
| `target_type` / `target_id` | varchar(32)/bigint unsigned | NOT NULL, INDEX | 被查看对象 |
| `field_set` | json | NOT NULL | 查看的字段集,不保存字段值 |
| `purpose_code` / `purpose_text` | varchar(64)/varchar(500) | NOT NULL | 用途 |
| `authorization_no` | varchar(64) | NULL | 授权号 |
| `mfa_verified` | tinyint | NOT NULL | 二次认证 |
| `result` | tinyint | NOT NULL | 允许/拒绝/失败 |
| `trace_id` | varchar(64) | NOT NULL, INDEX | 链路 ID |
| `created_at` | datetime(3) | NOT NULL, INDEX | 查看时间 |
#### 6.9.4 `hg_biz_audit_log` 业务审计日志
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `audit_no` | varchar(32) | UNIQUE | 审计号 |
| `actor_type` / `actor_id` | tinyint/bigint unsigned | NOT NULL, INDEX | 管理员/会员/系统 |
| `module` / `action` | varchar(64) | NOT NULL, INDEX | 模块与动作 |
| `target_type` / `target_id` | varchar(64)/bigint unsigned | NOT NULL, INDEX | 目标 |
| `before_digest` / `after_digest` | char(64) | NULL | 变更前后摘要 |
| `change_json` | json | NULL | 已脱敏差异 |
| `reason` | varchar(500) | NULL | 操作原因 |
| `approval_no` | varchar(32) | NULL, INDEX | 审批单号 |
| `trace_id` | varchar(64) | NOT NULL, INDEX | 链路 ID |
| `prev_hash` / `row_hash` | char(64) | NULL/NOT NULL | 防篡改哈希链 |
| `created_at` | datetime(3) | NOT NULL, INDEX | 时间 |
不在 `change_json` 中存储密码、令牌、完整手机、卡号、证件号和渠道密钥。
#### 6.9.5 `hg_idempotency_record` 幂等记录
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `scope` | varchar(64) | NOT NULL | 业务作用域 |
| `idempotency_key` | varchar(128) | NOT NULL | 客户端/系统幂等键 |
| `request_digest` | char(64) | NOT NULL | 请求摘要 |
| `resource_type` / `resource_id` | varchar(64)/bigint unsigned | NULL | 产生的资源 |
| `process_status` | tinyint | NOT NULL | 1处理中 2成功 3失败 |
| `response_code` | int | NULL | 结果码 |
| `response_digest` | char(64) | NULL | 响应摘要 |
| `expire_at` | datetime(3) | NOT NULL, INDEX | 保留到期时间 |
| `created_at` / `updated_at` | datetime(3) | NOT NULL | 时间 |
唯一约束:`UNIQUE (tenant_id,scope,idempotency_key)`。
#### 6.9.6 `hg_outbox_event` 事件出站箱
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `event_no` | varchar(32) | UNIQUE | 事件号 |
| `aggregate_type` / `aggregate_id` | varchar(64)/bigint unsigned | NOT NULL, INDEX | 聚合根 |
| `event_type` | varchar(128) | NOT NULL, INDEX | `wallet.credited` 等 |
| `payload_json` | json | NOT NULL | 已脱敏事件数据 |
| `publish_status` | tinyint | NOT NULL DEFAULT 1, INDEX | 1待发送 2已发送 3失败 4死信 |
| `retry_count` | int unsigned | NOT NULL DEFAULT 0 | 重试次数 |
| `next_retry_at` | datetime(3) | NULL, INDEX | 下次重试 |
| `last_error` | varchar(1000) | NULL | 最后错误 |
| `created_at` / `published_at` | datetime(3) | NOT NULL/NULL | 时间 |
#### 6.9.7 `hg_dashboard_daily_stat` 看板日汇总
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `stat_date` | date | NOT NULL | 统计日期 |
| `dimension_type` / `dimension_value` | varchar(32)/varchar(64) | NOT NULL | 全局/渠道/等级等 |
| `metric_code` | varchar(64) | NOT NULL | 指标编码 |
| `metric_count` | bigint | NOT NULL DEFAULT 0 | 数量 |
| `metric_amount` | bigint | NOT NULL DEFAULT 0 | 金额,分 |
| `calculated_at` | datetime(3) | NOT NULL | 计算时间 |
唯一约束:`UNIQUE (tenant_id,stat_date,dimension_type,dimension_value,metric_code)`。看板可展示汇总值,但财务对账必须以业务单和台账为准。
### 6.10 通知表
#### `hg_app_notification` C 端通知
| 字段 | 类型 | 约束/索引 | 说明 |
| --- | --- | --- | --- |
| `notification_no` | varchar(32) | UNIQUE | 通知号 |
| `member_id` | bigint unsigned | NOT NULL, INDEX | 接收会员 |
| `notification_type` | varchar(32) | NOT NULL, INDEX | system/order/finance/task/security |
| `title` | varchar(200) | NOT NULL | 标题 |
| `content` | varchar(2000) | NOT NULL | 纯文本内容 |
| `biz_type` / `biz_id` | varchar(32)/bigint unsigned | NULL, INDEX | 关联业务 |
| `read_at` | datetime(3) | NULL | 已读时间 |
| `expire_at` | datetime(3) | NULL | 过期时间 |
| `created_at` | datetime(3) | NOT NULL, INDEX | 创建时间 |
需求中的“弹幕/模拟会员”不作为真实会员行为实现。如确需运营轮播消息,使用显式标注为“平台消息”的通知类型,不关联伪造会员 ID,不进入真实统计。
### 6.11 核心索引和分区策略
| 场景 | 策略 |
| --- | --- |
| 会员查询 | 手机精确查询走 `mobile_hash`;用户名走唯一索引;列表按 `(tenant_id,created_at,id)` 游标分页 |
| 订单查询 | 业务单号唯一索引;高频列表索引必须以 `tenant_id` 开头,紧跟状态/会员和时间 |
| 台账 | `(account_id,occurred_at,id)` 和 `(biz_type,biz_no)`;按月度作冷热分层,不盲目对在线主表分区 |
| 审计 | `(target_type,target_id,created_at)`、`(actor_id,created_at)`、`trace_id`;超过在线保留期后归档到独立存储 |
| Outbox | `(publish_status,next_retry_at,id)` 供消费者抢占;已发送数据定期归档 |
| 看板 | 当日数据可实时聚合,历史数据读日汇总表 |
## 7. 字典与状态设计
本系统不建设新的字典体系,完整复用 HotGo 已有的三类字典能力。三类字典通过同一组接口和前端 Store 向页面提供选项。
### 7.1 HotGo 现有字典机制
| 类型 | 现有实现 | 适用场景 | 是否可在后台修改 |
| --- | --- | --- | --- |
| 数据库字典 | `hg_sys_dict_type` + `hg_sys_dict_data` | 驳回原因、内容分类等运营可维护选项 | 是 |
| 枚举字典 | `internal/consts` + `dict.RegisterEnums()` | 状态机、资金方向、账户类型等稳定业务枚举 | 否,随代码版本发布 |
| 方法字典 | `dict.RegisterFunc()` | 会员等级、商品分类、任务大厅、支付渠道等数据库动态选项 | 数据由对应业务模块维护 |
后端选项查询继续使用现有 `/dictData/option/{type}` 和 `/dictData/options`。`SysDictData.Select()` 已按“内置枚举/方法字典优先,数据库字典兜底”加载,新业务不重复实现查询逻辑。
### 7.2 直接复用的现有字典
| 现有字典 key | 复用场景 | 处理 |
| --- | --- | --- |
| `sys_normal_disable` | 所有可维护业务表的 `status` | 直接使用 1正常、2停用,不再定义启停枚举 |
| `sys_switch` | 自动派单、是否推荐、默认开关 | 直接使用 1开启、2关闭 |
| `sys_user_sex` | 会员或管理员性别 | 如业务确需则直接使用 |
| `payType` | 支付方式选项 | 优先复用现有微信/支付宝/QQ 值;为原 `PayTypeOptions` 补充 `balance`、`bank_transfer`、`manual` 等本项目确需值,不另建同义字典 |
| `payStatus` | 简单支付结果展示 | 仅在“待支付/已支付”语义完全一致时复用 |
| `creditType` / `creditGroup` | 旧资金日志兼容、余额/积分分类 | 数据迁移时复用映射;新钱包台账扩展原枚举而不建第二套同义字典 |
`orderStatus` 是 HotGo 原商品订单状态(待付款、已发货、退款等),与本项目的任务匹配订单状态语义不同,不强行复用其数值。保留原字典供框架旧模块使用,新增独立的 `tradeOrderStatus` 枚举字典,避免同一值在两种业务中含义不同。
### 7.3 新增枚举字典(依然使用 HotGo 注册机制)
以下仅新增 `internal/consts` 常量和 `dict.RegisterEnums()` 注册,不新增字典表或接口:
| 字典 key | Go 选项变量 | 核心值 |
| --- | --- | --- |
| `appMemberStatus` | `AppMemberStatusOptions` | 1正常 2受限 3禁用 4注销 |
| `appMemberRiskStatus` | `AppMemberRiskStatusOptions` | 1正常 2观察 3限制 4冻结 |
| `bizPublishStatus` | `BizPublishStatusOptions` | 1草稿 2待审 3已发布 4已下线 5已归档 |
| `tradeOrderStatus` | `TradeOrderStatusOptions` | 1匹配中 2待处理 3处理中 4完成 5超时 6冻结 7取消 8失败 |
| `rechargeStatus` | `RechargeStatusOptions` | 1待支付 2待审 3成功 4驳回 5过期 6取消 |
| `withdrawalStatus` | `WithdrawalStatusOptions` | 1待审 2复核中 3处理中 4成功 5失败 6驳回 7取消 |
| `taskSubmissionStatus` | `TaskSubmissionStatusOptions` | 1待审 2通过 3驳回 4已结算 5已冲正 |
| `approvalStatus` | `ApprovalStatusOptions` | 1草稿 2待审 3审批中 4通过 5驳回 6取消 7已执行 8执行失败 |
| `ledgerBizType` | `LedgerBizTypeOptions` | recharge/withdraw/freeze/unfreeze/commission/reward/adjust/reversal |
| `paymentAccountType` | `PaymentAccountTypeOptions` | 1银行卡 2数字钱包 3云闪付 4支付宝 5微信 |
资金、审批和状态机值必须是代码枚举,因为 Logic 会依赖其稳定语义。它们在 HotGo 字典管理页面中仍会以“内置字典 → 枚举字典”展示,但不允许运营人员修改值。
### 7.4 复用数据库字典的运营选项
以下选项在现有“系统设置 → 字典管理”中新增类型和数据,不新建业务字典表:
| 数据库字典 key | 用途 | 修改影响 |
| --- | --- | --- |
| `member_disable_reason` | 会员禁用/限制标准原因 | 只影响后续新申请,历史记录保留 label 快照 |
| `recharge_reject_reason` | 充值驳回原因 | 同上 |
| `withdrawal_reject_reason` | 提现驳回原因 | 同上 |
| `task_reject_reason` | 任务审核驳回原因 | 同上 |
| `wallet_adjust_reason` | 账变/奖励金原因 | 同上,且操作仍需审批 |
| `content_type` | 公告、简介、FAQ、规则、活动等内容分类 | 新类型可由运营增加,但 C 端特殊展示类型需代码支持 |
这些字典的 `value_type`、`list_class`、`sort`、`status` 继续由 `hg_sys_dict_data` 承载。删除前必须检查是否已被业务使用;已使用选项应停用而不是删除。
### 7.5 方法字典
下列选择器来自业务表,使用 `dict.RegisterFunc()` 注册,不将业务数据复制到 `hg_sys_dict_data`:
| 方法字典 key | 数据源 | 缓存策略 |
| --- | --- | --- |
| `memberLevelOption` | `hg_app_member_level` | 可缓存,等级更新后 `dict.ClearFuncCache()` |
| `productCategoryOption` | `hg_product_category` | 可缓存,分类更新后清理 |
| `taskHallOption` | `hg_task_hall` | 可缓存,大厅更新后清理 |
| `paymentChannelOption` | `hg_payment_channel` | 可缓存,渠道更新后清理 |
### 7.6 后端与前端用法
后端在 `Filter(ctx)` 或 Logic 中使用现有方法校验字典值:
```go
if !dict.HasOptionKey(consts.WithdrawalStatusOptions, in.WithdrawalStatus) {
return gerror.New("提现状态不合法")
}
```
前端在每个模块 `model.ts` 中继续使用现有 Pinia 字典 Store:
```ts
const dict = useDictStore();
export function loadOptions() {
dict.loadOptions([
'sys_normal_disable',
'sys_switch',
'withdrawalStatus',
'withdrawal_reject_reason',
'paymentChannelOption',
]);
}
// 表格显示
dict.getLabel('withdrawalStatus', row.withdrawalStatus);
// 下拉选项
computed(() => dict.getOptionUnRef('withdrawal_reject_reason'));
```
不在 Vue 模板、`model.ts` 或 API 文件中重复定义 label/value 数组。
### 7.7 字典与业务配置的边界
- **字典**:为字段提供有限选项、标签、颜色和排序,复用 HotGo 字典系统。
- **业务配置**:交易时段、最低余额、佣金比例、额度和功能开关等会直接影响 C 端和资金,使用 `hg_site_config_version` 的审批、发布和回滚机制,不塞入字典表。
- **业务主数据**:会员等级、商品分类、支付渠道等有独立属性和关系,使用业务表,只通过方法字典提供下拉选项。
## 8. 接口设计约定
### 8.1 路由与方法
- 后台路由使用 HotGo 现有 `/admin` 前缀,不再叠加 `/admin-api/v1`。
- 列表与详情使用 GET;新增、编辑、状态变更和审批使用 POST。
- 标准 CRUD 按 `/module/list`、`/view`、`/edit`、`/delete`、`/status`、`/export` 组织。
- 高风险动作不复用通用 `edit`,使用显式语义接口,如 `/withdrawal/review`、`/walletAdjustment/submit`、`/approval/approve`。
### 8.2 写请求通用要求
- 资金、审核、发布类接口必须携带 `idempotencyKey`。
- 更新可并发编辑的数据必须携带 `version`,冲突返回明确错误。
- 审核、驳回、禁用、删除、导出和敏感查看必须携带原因。
- 资金与权限写接口返回审计号或审批单号。
- Controller 仅做参数透传和结果组装;所有业务校验在 `sysin.Filter()` 或 Logic 中完成。
### 8.3 错误码分类
| 分类 | 示例 | 前端处理 |
| --- | --- | --- |
| 参数错误 | 时间区间反向、金额超限 | 定位到字段 |
| 状态冲突 | 订单已处理、版本过期 | 刷新当前数据 |
| 权限拒绝 | 无敏感值查看权限 | 不展示目标数据 |
| 审批约束 | 申请人尝试审批自己 | 提示职责分离 |
| 余额不足 | 可用余额小于提现金额 | 显示当前可用余额 |
| 外部服务错误 | 支付通道超时 | 显示可重试状态与 `traceId` |
## 9. 缓存、队列与定时任务
### 9.1 缓存
| Key | TTL | 用途 |
| --- | --- | --- |
| `site:config:{tenant}:{group}` | 5 分钟 | 当前已发布站点配置 |
| `content:published:{tenant}:{key}` | 10 分钟 | 已发布内容 |
| `member:level:{tenant}:{id}` | 10 分钟 | 当前等级规则 |
| `dashboard:summary:{tenant}:{date}` | 1 分钟 | 看板汇总 |
| `sensitive:grant:{token}` | 1–5 分钟 | 一次性敏感查看授权 |
| `lock:finance:{bizNo}` | 小于 30 秒 | 防止跨实例重复处理 |
统一通过 `cache.Instance()` 使用,不在业务代码中直接调用 Redis。更新成功后主动删除缓存。
### 9.2 队列主题
| Topic 常量 | 事件 | 消费者 |
| --- | --- | --- |
| `QueueBizNotification` | 订单、充值、提现、任务状态变更 | C 端站内信/短信/推送 |
| `QueueDashboardStat` | 会员、订单、台账事件 | 看板汇总 |
| `QueuePaymentCallback` | 通道回调待处理 | 支付处理器 |
| `QueueReconciliation` | 入账、付款和冲正 | 对账服务 |
| `QueueAuditArchive` | 审计日志归档 | 审计归档服务 |
### 9.3 定时任务
| 任务名 | 频率 | 职责 |
| --- | --- | --- |
| `publishScheduledContent` | 每分钟 | 发布到期内容、Banner 和配置 |
| `expireTradeOrders` | 每分钟 | 处理超时订单 |
| `retryOutboxEvents` | 每 10 秒 | 发送 Outbox 并执行指数退避 |
| `reconcileFinanceDaily` | 每日 | 业务单、台账、钱包和渠道对账 |
| `aggregateDashboardDaily` | 每小时/每日 | 重建看板汇总 |
| `expireSessionsAndGrants` | 每 10 分钟 | 清理会话与临时授权 |
## 10. 安全设计
### 10.1 数据保护
- 密文字段使用 AEAD(AES-256-GCM 或等价算法),每条记录使用唯一 nonce。
- 业务库只保存密文;主密钥位于 KMS/密钥管理系统,不存在代码、数据库和普通配置文件。
- 密钥定期轮换,密文保存密钥版本,支持惰性重加密。
- 通用请求日志对密码、令牌、卡号、证件号、收款码 URL 和渠道密钥执行强制红线过滤。
### 10.2 Web 安全
- 富文本在服务端执行标签、属性和 URL 协议白名单清洗。
- 设置 CSP、`X-Content-Type-Options`、`Referrer-Policy` 和合理的 iframe `sandbox`。
- 文件上传校验 MIME、扩展名、文件头、尺寸和大小,异步病毒扫描,不使用用户原始文件名作为存储键。
- 后台使用 MFA;资金、完整敏感值和权限修改触发再认证。
### 10.3 资金安全不变式
1. 钱包可用余额和冻结余额不得为负数。
2. 每笔台账的 `after_balance = before_balance ± amount`。
3. 同一账户同一幂等键只能有一条台账。
4. 充值成功必须且只能对应一笔入账台账。
5. 提现成功必须存在冻结和扣减冻结两类台账。
6. 资金纠错只能冲正,不得修改或删除历史台账。
7. 申请人、初审人和复核人按风险级别实施职责分离。
## 11. 可观测性与运维
### 11.1 指标
- API 请求数、成功率、P50/P95/P99 延迟和错误码分布。
- 待审充值/提现数、审批时长、通道成功率、回调验签失败数。
- 钱包与台账对账差异数、重复幂等请求数、事务冲突数。
- Outbox 积压、重试数、死信数和消费延迟。
- 敏感数据查看次数、拒绝次数、非工作时段查看和大量导出。
### 11.2 告警
| 级别 | 场景 |
| --- | --- |
| P0 | 钱包与台账不平、重复入账、未经审批的资金变更、密钥泄漏 |
| P1 | 支付通道大面积失败、Outbox 严重积压、异常批量敏感查看 |
| P2 | 单个外部服务降级、定时发布延迟、看板汇总延迟 |
### 11.3 备份与恢复
- MySQL 全量备份 + binlog 时点恢复,目标 RPO ≤ 5 分钟,RTO ≤ 30 分钟。
- 对象存储开启版本和生命周期,资金凭证在留存期内不得物理删除。
- 每季度执行恢复演练,演练必须验证业务单、钱包和台账的一致性。
## 12. 性能与容量设计
| 指标 | 一期目标 |
| --- | --- |
| 会员 | 10 万 |
| 交易订单 | 1,000 万级历史数据 |
| 钱包台账 | 3,000 万级历史数据 |
| 后台并发用户 | 200 |
| 后台列表 | P95 < 1s |
| 普通写操作 | P95 < 1.5s |
| 资金事务 | P95 < 2s,不包外部通道等待 |
列表默认使用索引覆盖的时间倒序与游标分页。需跳页的后台页面可保留普通分页,但必须限制最大页深;大量数据导出使用异步任务,不在 HTTP 请求中生成。
## 13. 开发与数据库迁移顺序
1. **基础治理**:字典常量、审批、审计、幂等、Outbox、敏感字段加密工具。
2. **会员域**:会员等级、会员、隐私资料、收款账户、状态记录和会话。
3. **内容配置域**:站点配置版本、内容版本、Banner、客服渠道。
4. **商品任务域**:分类、商品、任务大厅、任务、交易订单和任务提交。
5. **资金域沙箱**:钱包、台账、充值、提现、账变、财务审核和回调。
6. **外部通道**:支付、实名、短信和客服等外部服务。
7. **历史迁移**:脱敏盘点、数据清洗、密文转换、台账校验和切换。
每批建表 SQL 合入前,使用 GoFrame CLI 重新生成 `entity`、`do`、`dao/internal` 和 `dao`;禁止手动修改生成文件。
## 14. 测试策略
### 14.1 单元测试
- 金额计算、手续费计算、佣金计算和边界值。
- 所有状态机的允许与禁止转换。
- 脱敏、加密、哈希检索和密钥版本轮换。
- 站点配置跨字段校验,特别是时间反向和比例超限。
- 审批人与申请人分离、审批数量与权限校验。
### 14.2 集成测试
- 重复充值回调只入账一次。
- 并发提现不得使钱包余额为负。
- 提现驳回、撤销和付款失败的冻结与解冻一致。
- 任务重复审核不得重复发放佣金。
- 已发布配置回滚后,C 端和后台读取同一版本。
- 敏感查看令牌单次使用、过期失效并产生审计记录。
### 14.3 数据不变式测试
在 CI 和生产对账中定期执行:
```text
钱包可用余额 = 对应可用余额台账累计值
钱包冻结余额 = 对应冻结台账累计值
充值成功单数 = 充值入账唯一业务单数
提现成功单数 = 提现最终扣款唯一业务单数
已结算任务数 = 任务佣金有效台账业务单数
```
## 15. 分阶段交付
| 阶段 | 后端 | 前端 | 数据库 | 退出条件 |
| --- | --- | --- | --- | --- |
| S1 基础 | RBAC、审批、审计、幂等、Outbox | 统一列表/弹窗/审批组件 | 治理域表 | 安全评审通过 |
| S2 配置会员 | 配置、内容、会员、脱敏 | 对应页面 | 配置与会员域表 | C 端版本联调通过 |
| S3 商品任务 | 商品、任务、订单、审核 | 对应页面 | 商品任务域表 | 沙箱任务闭环通过 |
| S4 资金沙箱 | 钱包、台账、充值、提现、对账 | 财务页面 | 资金域表 | 并发、幂等、对账测试通过 |
| S5 生产通道 | 外部支付与风控 | 运营看板与降级 | 回调与统计 | 小流量、限额、人工对账通过 |
## 16. 需进一步确认的设计决策
1. 生产是否需要真实资金、支持币种以及法定小数位。
2. 单租户还是多租户部署;本设计预留 `tenant_id`,单租户使用 0。
3. 提现初审、复核、放款的金额阈值和岗位矩阵。
4. 会员实名认证所需字段、外部供应商与数据留存期。
5. 会员关系树与层级返佣是否保留;若保留,需先完成合规评审和返佣规则详细设计。
6. 客服使用自建工单还是第三方服务;第三方可接收的会员数据范围。
7. 原系统历史数据的字段映射、缺失值处理、重复账号合并和台账校验方案。
上述决策不阻塞 S1–S3 的基础开发,但在真实充值、提现和历史资金数据迁移前必须完成确认。