七月迭代短暂完结,还有很多后端的关键东西没有弄,这是一版赶时间做的东西
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 8m26s
This commit is contained in:
@@ -0,0 +1,163 @@
|
||||
## Context
|
||||
|
||||
本 Change 以 `docs/7月迭代/七月迭代需求范围确认表.md` 为业务范围,以 `docs/7月迭代/物联网卡管系统-需求.csv` 为原始来源,以 `docs/7月迭代/企业微信审批官方接口调研.md` 为企微能力依据。旧 Change 已完成部分公共能力,但其剩余任务存在漏项、错误口径和过度 DDD 迁移,不能继续作为实施顺序。
|
||||
|
||||
当前仓库已经具备可复用的通用审批实例、标准决策同步、公共 Outbox/Relay、异步任务、对象存储、站内通知、`system_config`、钱包流水和 Integration Log。本设计只补业务接线和确实缺失的企微 Adapter,不重建这些基础设施。
|
||||
|
||||
涉及方包括后端、前端、测试、部署人员,以及企业微信和 Gateway 配置负责人。当前仓库没有前端源码,因此本 Change 交付后端接口、OpenAPI 契约和联调门禁。
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
|
||||
- 按已确认口径覆盖所有“本期做”需求,并核验所有“已完成,只联调/验收”需求。
|
||||
- 让简单字段、筛选、配置和 Bug 保持简单,能够独立开发、独立验证、独立上线。
|
||||
- 让退款和员工线下代充值真正通过企微模板审批闭环,同时保留金额、幂等和终态处理的现有安全边界。
|
||||
- 冻结前后端需要的字段、接口、状态和错误语义,避免实现阶段再次扩张范围。
|
||||
|
||||
**Non-Goals:**
|
||||
|
||||
- 不继续执行旧 Change 中未被本 Change重新列出的任务。
|
||||
- 不做代理在线扫码充值、原路退款、聚水潭、跨品类换货、分销码/佣金提现、自动限速、通用营销/ERP、本地审批流程设计器、未来钉钉适配或全局 Audit Event 专项。
|
||||
- 不迁移未触碰的旧模块,不因为新增字段或筛选建立聚合、Repository 接口、事件消费者或历史投影。
|
||||
- 不强制吊销已登录 C 端 Token;店铺限制只阻止新的登录流程。
|
||||
- 本次执行不编写或补齐测试代码,不运行测试、构建、LSP、迁移、OpenAPI 生成或真实外部环境验收;实现收口到生产代码可联调状态。
|
||||
|
||||
## Decisions
|
||||
|
||||
### 1. 新 Change 是后续实施的唯一契约
|
||||
|
||||
本 Change 校验通过后,`complete-july-iteration-test-release` 只作为历史完成证据归档,不再从其中领取任务。已完成代码不会回滚或重复实现;本 Change 的 tasks 会先做一次证据核验,再只实现真实缺口。
|
||||
|
||||
**理由**:旧 Change 的 task 勾选、proposal/spec 和仓库状态已经漂移,继续补丁式修订容易再次执行错误任务。
|
||||
|
||||
**否决方案**:在旧 Change 上继续增删 191 个任务。该方案无法可靠区分已完成公共能力、错误口径和本期真实需求。
|
||||
|
||||
### 2. 按纵向切片选择最小架构通道
|
||||
|
||||
| 需求切片 | 主通道 | 完整业务边界 | 明确不迁移范围 |
|
||||
| --- | --- | --- | --- |
|
||||
| #189、#181、#57 | 旧 `Handler → Service → Store → Model` | 对现有换货、退款、订单路径做局部修复和拦截 | 不迁移换货、退款或订单模块 |
|
||||
| #182、#44、#53 | 既有 Query 或旧 Store 查询 | 列表/详情字段、实名筛选、批量账号名称解析 | 不建聚合、历史投影或事件消费者 |
|
||||
| #41、#62、#48 | 简单写 + 既有读取 | 店铺开关、实名策略、系统配置的更新和查询 | 不建领域模型,不重构认证/支付模块 |
|
||||
| #188、#97、#33 | Application/既有通知 Adapter | 产生明确业务事件后向既有站内通知接线 | 不建营销平台或新通知中心 |
|
||||
| #36、#42、#49 | 既有异步导入/导出 Infrastructure + 业务 Service | 文件校验、异步处理、结果文件和业务写入 | 不再建第二套任务、对象存储或进度平台 |
|
||||
| #47 | 旧 IoT 卡 Service + Gateway Adapter | 固定档位校验、卡 ICCID 权限解析、一次 Gateway 调用 | 不提供设备限速,不通过设备绑定关系间接限速,不自动计算运营商策略,不迁移资产模块 |
|
||||
| #34、#35 | 复杂写 Application/Domain | 申请快照、审批终态、充值入账或退款终结 | 不把企微 DTO/状态码写入资金领域 |
|
||||
| #37 | Infrastructure Adapter + Application Port | 通讯录、模板、提交、回调、轮询和状态翻译 | 不建设本地审批流引擎或继续抽象未来渠道 |
|
||||
| #40 | 旧 Service/Query | 下架套餐续费资格与可购列表过滤 | 不迁移套餐或订单全模块 |
|
||||
|
||||
依赖通过构造函数结构体字段注入。旧 Service 保持现有注入方式;企微 Adapter 实现现有 `internal/application/approval` Port,由 bootstrap 同时注入 API、回调和 Worker。新增 Handler 必须同步两个文档生成器。
|
||||
|
||||
### 3. API 只表达当前业务,不暴露通用平台
|
||||
|
||||
所有接口继续使用 Fiber、Validator、`pkg/errors` 和 `{code,msg,data,timestamp}` 统一响应;既有项目字段名为 `msg`,不引入另一套 `message` 字段。列表默认 20、最大 100,平台/代理数据权限沿用现有中间件与 GORM Callback。
|
||||
|
||||
关键契约如下:
|
||||
|
||||
| 场景 | 接口决定 |
|
||||
| --- | --- |
|
||||
| 店铺 C 端登录限制 | 店铺模型和管理接口增加 `client_login_disabled`,默认 `false`;复用店铺更新接口或增加单一语义 PATCH。C 端 `verify-asset` 在签发 asset token 前按资产 `shop_id` 拦截 |
|
||||
| 企微账号绑定 | 账号列表/详情返回 `wecom_corp_id`、`wecom_userid`、`wecom_name`;管理员更新账号时选择通讯录成员,不提供个人扫码接口 |
|
||||
| 企微通讯录 | 提供分页成员选择接口,支持姓名或 userid 搜索;只展示应用可见成员,不依赖手机号/邮箱 |
|
||||
| 企微场景配置 | 管理员配置 `business_type → template_id` 及业务字段到控件 ID/类型/选项 key 的映射;模板必须先在企微后台创建 |
|
||||
| 实名顺序 | 保持已约定的单资产 PATCH、卡批量 POST、设备批量 POST;枚举仅为 `none/before_order/after_order`,批量上限 500、全成全败 |
|
||||
| 列表人员字段 | 退款、充值、换货返回提交人 ID/名称;审批人仅从已同步企微详情中的 userid 批量映射,映射不到返回空,不实时调用企微 |
|
||||
| 批量订购 | CSV 只有资产标识列;请求额外选择一个套餐和一个支付方式,不选择代理;整批使用相同参数 |
|
||||
| 导出 | 复用现有导出任务入口,通过六个 datasource code 区分;每类只输出本业务已有且已确认的字段 |
|
||||
| 支付方式 | `system_config` 分别保存卡和设备允许的支付方式;两类资产默认均启用 `wallet/wechat/alipay`,三项可独立取消但至少保留一项;C 端返回当前购包场景有效集合,创建订单时后端再次校验 |
|
||||
| 设备批量分配 | 复用现有导入任务 API 和状态模型,CSV 单列设备标识;业务参数选择“代理”或“套餐系列”及目标 ID |
|
||||
|
||||
### 4. 店铺登录限制在资产令牌前拦截
|
||||
|
||||
`client_auth.Service.VerifyAsset` 解析出卡或设备后取得资产 `shop_id`,再读取店铺开关。无店铺/平台库存保持当前行为;开关关闭时返回统一禁止错误,不签发短期资产令牌,因此不会进入微信登录、客户创建或资产绑定。
|
||||
|
||||
不在每个 C 端业务接口重复查询店铺开关,也不吊销已有 Token。这严格对应“不能登录”而不是“立即踢下线”,并避免在本期引入 Token 版本和全局会话撤销。
|
||||
|
||||
### 5. 企微只做 Adapter,审批流程仍由企微模板拥有
|
||||
|
||||
系统按应用保存加密 Secret、回调 Token、EncodingAESKey、`corp_id/agent_id` 和一个从当前可见成员中选择的默认审批发起人;`access_token` 按应用缓存并预留提前刷新。管理员从应用可见通讯录选择成员,账号绑定键为 `(corp_id, userid)`,姓名和部门仅为展示快照。内部员工已绑定且仍可见时优先以本人发起,代理等非企微账号始终以应用默认成员发起;本地申请仍保留真实业务提交人,不用默认成员冒充业务操作者。
|
||||
|
||||
场景配置保存已知 `template_id`。保存或发布时调用 `oa/gettemplatedetail` 校验控件 ID、类型、必填项和选择项 key。系统不创建模板、不保存审批节点、不计算部门领导或财务人员;`oa/applyevent` 使用 `use_template_approver=1`,审批人由企微后台模板决定。
|
||||
|
||||
提交过程:
|
||||
|
||||
1. 业务用例校验内部提交人的企微绑定或应用默认发起人仍可见、场景已启用且模板结构有效。
|
||||
2. 退款或线下充值在同一 GORM 事务保存业务申请、通用审批实例和提交 Outbox。
|
||||
3. Adapter 消费提交事件,上传必要附件并调用 `oa/applyevent`,保存返回的 `sp_no` 到通用实例 `external_ref`。
|
||||
4. 外部调用记录 Integration Log;结果未知时不盲目创建第二张审批单,转人工/查询恢复。
|
||||
5. 回调端点在 5 秒内完成验签解密、必要幂等记录和快速响应,再异步调用 `getapprovaldetail`。
|
||||
6. Adapter 将企微状态翻译为现有标准决策;现有决策 Outbox 分别驱动退款终结或线下代充入账。
|
||||
7. 定时任务扫描未终态实例,并用批量拉取审批单号与详情查询补偿回调遗漏。
|
||||
|
||||
企业微信审批详情的审批节点 userid 可以用于页面展示,但只做读取投影;不能映射系统账号时返回空名称,不影响业务终态。
|
||||
|
||||
### 6. 通知只复用现有站内能力
|
||||
|
||||
- 创建物流换货单成功后,向关联个人客户写一次站内通知;C 端按既有未读弹窗机制展示。
|
||||
- 店铺主钱包余额从不低于 100 元变为低于 100 元时,向 `business_owner_account_id` 对应后台账号发送一次通知;余额恢复到阈值以上后允许下一次下降再次提醒。
|
||||
- 每日扫描预计套餐到期日在 15、7、3 天节点的资产,生成后台/代理临期列表所需标识,并向关联个人客户发送节点通知。相同资产、节点、到期日只通知一次。
|
||||
|
||||
通知属于可靠副作用时使用现有 Outbox 和幂等键;不新增短信、企微业务员提醒或自定义营销内容。
|
||||
|
||||
### 7. 批量与导出复用已完成基础设施
|
||||
|
||||
批量订购和设备分配只新增业务解析器/执行器,继续使用现有对象存储、任务五态、Asynq 重试、失败明细和下载能力。文件级校验失败不写业务数据;涉及扣款/订购时按现有订单幂等键和钱包流水保证不重复扣款。
|
||||
|
||||
六类导出分别实现 datasource,查询直接投影 DTO,不串联多个业务迁移。不存在的字段不得临时创造含义;先从既有数据组合,确认确实缺失后再增加最小字段和迁移。
|
||||
|
||||
### 8. 数据、事务、常量与缓存
|
||||
|
||||
- 新表/字段通过 PostgreSQL 增量迁移添加,不建外键,不写 GORM 关联标签。
|
||||
- 简单列表字段使用批量 `WHERE id IN (...)` 或 JOIN 投影,禁止逐行查询账号。
|
||||
- 批量实名策略在单事务内校验全部资产后统一更新;任何冲突则全部回滚。
|
||||
- 退款和充值金额继续使用现有 Domain Ledger/钱包流水与乐观锁;审批 Adapter 不直接修改余额或退款金额。
|
||||
- 所有新枚举、任务类型、场景编码、导出 datasource code 和 Redis key 在 `pkg/constants` 定义并写中文注释。
|
||||
- 企微 token 使用 Redis 缓存和短锁;Redis 不可用时允许受控回源,但不得把 token 返回前端。
|
||||
|
||||
### 9. Audit Event、Domain Ledger、Integration Log 与 Outbox 决策
|
||||
|
||||
| 切片 | Audit Event | Domain Ledger | Integration Log | Outbox |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 字段、筛选、Bug、只读导出 | N/A:无敏感状态变更;实现时登记覆盖基线理由 | N/A 或沿用既有订单/套餐事实 | N/A | N/A |
|
||||
| 店铺登录开关、企微账号绑定、模板场景、支付方式配置 | 使用现有统一审计接缝记录操作者和前后值;不建设新的审计中心 | N/A | 模板校验调用记录 | 缓存失效仅沿用现有配置机制 |
|
||||
| 退款、线下代充 | 审批申请人和配置操作进入既有审计/申请快照;企微自动终态不伪造人工操作者 | 沿用退款、订单、钱包流水 | 所有企微请求、响应摘要、回调和结果未知 | 申请提交、标准终态和资金后续动作使用现有 Outbox |
|
||||
| 通知 | N/A:通知记录本身是投递事实 | N/A | N/A | 必须,按业务键和接收人防重 |
|
||||
| Gateway 限速 | 记录后台操作者、资产和档位 | N/A | 必须记录请求、响应及结果未知 | 无后续可靠副作用时 N/A |
|
||||
| 批量订购/分配 | 沿用任务提交审计;资金动作沿用既有记录 | 订购扣款沿用订单/钱包流水 | 涉及外部支付或 Gateway 时沿用 | 仅业务已有可靠副作用继续使用 |
|
||||
|
||||
实现前必须增量更新 `.scratch/tech-global-audit/审计覆盖基线.md`,不得因本 Change 排除全局 Audit Event 专项而跳过上述已有审计接缝。
|
||||
|
||||
### 10. 续费、待支付订单与强充支付方式边界
|
||||
|
||||
- 历史已支付订单和资产当前套餐只提供稳定的资产、套餐引用。用户点击续费时继续调用现有 C 端创建订单接口并生成一张新订单,不新增续费接口,也不在旧订单上修改支付方式。
|
||||
- 续费新订单创建前按当前 `system_config`、当前套餐价格/流量和当前强充状态重新选择支付方式;订单创建成功后,和普通订单一样固化所选方式。既有待支付订单再次支付时只能执行其已保存方式,不允许切换。
|
||||
- 卡和设备分别维护非空支付方式集合,合法选项均为 `wallet`、`wechat`、`alipay`,三项可独立启停;首次初始化两类资产均全选。配置非法或读取失败时失败关闭,不推断或放开支付渠道。
|
||||
- C 端购包接口返回“配置集合与当前业务场景的交集”。当前资产仍命中既有强充规则时必须剔除 `wallet`;普通钱包充值场景固定剔除 `wallet`。后端在创建订单、创建充值单和支付准备时执行相同校验,不能信任前端展示结果。
|
||||
- 强充继续沿用现有流程:第三方支付充值成功后先入资产钱包,再通过既有异步自动购包任务扣钱包并购买所选套餐。支付方式配置不得把强充改成提示后由用户手工充值。
|
||||
- 强充资格必须复用既有一次性佣金状态语义:`first_recharge` 与 `accumulated_recharge` 是同一强充/自动购包流程的不同触发配置;该系列一次性佣金已经触发后不再强充。不得在 C 端订单服务复制一套遗漏已触发状态的判断。
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- **[企微应用看不到提交人]** → 保存绑定前只允许选择应用可见成员,提交前再次校验;权限变化时明确失败,不创建业务申请和审批实例。
|
||||
- **[管理员修改企微模板导致控件映射失效]** → 保存/发布场景时拉取模板详情并保存指纹,提交前校验关键控件;失效只阻断新提交,存量审批继续同步。
|
||||
- **[回调丢失或重复]** → 回调快速响应、按 `sp_no` 幂等同步,保留未终态轮询和时间窗补偿。
|
||||
- **[企微提交超时但实际成功]** → 标记结果未知并先查详情/批量单号,不直接重试创建,避免重复审批。
|
||||
- **[简单需求再次被扩张]** → tasks 明确每个切片的不迁移范围;实现阶段不得改变架构通道,确需改变必须先更新提案。
|
||||
- **[大批量影响接口响应]** → 实名批量限制 500 且同步事务;CSV 和导出走异步任务,列表/人员映射使用批量查询。
|
||||
- **[店铺开关不能立即踢掉在线用户]** → 这是本期有意取舍;接口和文档明确只阻止新登录。
|
||||
|
||||
## Migration Plan
|
||||
|
||||
1. 先完成仓库证据核验,确认公共 Outbox、审批核心、通知、导入/导出和 `system_config` 可复用,禁止重复建表。
|
||||
2. 按纵向切片先交付无外部依赖的 Bug、字段、筛选、开关、实名、支付配置和本地通知。
|
||||
3. 增量迁移企微应用/场景/账号绑定及确实缺失的业务字段,迁移脚本保持向前兼容,不删除旧字段。
|
||||
4. 部署企微 Adapter、回调和轮询 Worker,配置测试应用、模板和账号绑定,完成真实退款/线下代充闭环后再关闭旧人工审批入口。
|
||||
5. 部署批量订购、导出、限速和设备批量分配,完成前后端联调与任务失败恢复验证。
|
||||
6. 完成生产代码、必要迁移文件、接口契约、配置说明和实施证据,以 `gofmt`、只读检查与 `git diff --check` 做静态收口并交付联调;自动化测试、构建、迁移执行和真实外部环境验收由后续流程承担。
|
||||
|
||||
回滚时,简单字段和兼容接口可回退应用版本;新增列/表暂不删除。产生企微审批、退款、充值、钱包流水、订单、通知、Outbox 或 Integration Log 后不得清表或恢复旧 Writer,只能暂停新入口并前向修复。旧人工审批入口仅在新链路验证完成后停用,因此切换前仍可回退。
|
||||
|
||||
## Open Questions
|
||||
|
||||
无阻塞性业务问题。实施和部署阶段仅需提供测试环境企微应用 Secret、可见范围、模板 ID、可信 IP、回调 Token/EncodingAESKey,以及 Gateway 测试配置;这些是环境输入,不改变需求范围。
|
||||
Reference in New Issue
Block a user