25 KiB
后端问题修复方案(2026-07-21)
配套审计报告:docs/backend-audit-2026-07-21.md 本文把审计发现的问题转化为可执行的修复批次,每条含:问题引用 → 根因 → 修复方案 → 涉及文件 → migration/SQL → 验证 → 风险 → 工作量。
一、方案概述(必读)
要解决的问题
安全类
- 生产密钥(OSS/SMS/OpenAI/Dify)已提交进 git,任何人 clone 即可拿到。
- 4/5 服务信任请求体/attachment 里的
user_id/reporter_id,可越权与刷量。 - JWT 全局可变密钥、弱默认值、data race。
财务/数据一致性类
- 展品收益结算非幂等,实测超发 2,525,254 水晶且已被领取(
exhibition_revenue_records无唯一约束 + 多结算入口)。 - 铸造扣费事务内嵌跨服务 gRPC,可扣费成功但无藏品、连接池耗尽。
- 累计时长累加无幂等(
AddExhibitionHours不用 sourceID),时长虚高→提前升级→多发奖励。 exhibition_revenue_records.created_at单位混乱(秒/毫秒混存)。
稳定性类
- bcrypt 在 DB 事务内执行,注册高峰连接池耗尽。
- Redis-Streams 消费者重启即丢消息,无 DLQ/重试。
架构/边界类
- 全部服务共享一个 Postgres + 一套 migration + 一个
pkg/models;服务间直接 import 对方 Go 包;49 条跨域外键。 - 网关直连 DB、import 服务内部包;
UserSocialService契约混合。 - 服务端口默认值四层不一致;
starbookService孤儿但仍在部署链路。
整体实现路径(按风险/收益排序,非架构驱动)
| 批次 | 主题 | 目标 | 工作量估算 |
|---|---|---|---|
| 批次 0 | 安全紧急 | 轮换密钥、清历史、密钥出库 | 0.5–1 天(+ 运维轮换) |
| 批次 1 | 财务正确性 | 结算幂等、mint 事务/随机数、doMint 限流、时长幂等、存量校正 | 4–6 天 |
| 批次 2 | 鉴权边界 | provider 统一从 attachment 取身份、social 隐私/正确性 | 3–4 天 |
| 批次 3 | 稳定性 | bcrypt、Login 限流、MQ DLQ、JWT 密钥、aiChat 健壮性、事件可靠性、网关聚合 | 4–6 天 |
| 批次 4 | 配置/部署 | 端口对齐、starbook 决断、健康探针、.env 对齐、P2 清理 | 2–3 天 |
| 批次 5 | 架构治理(路线图) | 去分布式单体(不在本次落地) | 独立项目,数周 |
关键决策
- 不在本次拆库/拆
pkg/models(MVP 先行原则)。当前业务规模下,拆库是数周级独立项目,收益/风险比不划算。本次只做加固:加 lint 禁止新增跨服务 import、加唯一约束堵幂等漏洞、明确表 owner 注释。架构级拆分列入批次 5 路线图。参见 §批次5。 - 财务批次优先于边界批次:已实证资损(超发水晶已被领取)>理论越权,先止血。
- 存量数据修复走 dry-run + 备份 + 序列同步,遵循
CLAUDE.mdPostgreSQL 序列规范。参见 §存量数据修复。
核心修复优先级图(TL;DR)
先做 ──────────────────────────────────────────────────────→ 后做
批次0 批次1 批次2 批次3 批次4 批次5
安全紧急 财务正确性 鉴权边界 稳定性 配置/部署 架构治理(路线图)
密钥轮换 结算幂等/mint/时长 身份透传 bcrypt/MQ/JWT 端口/starbook 去分布式单体
(P0) /doMint (P0+P1) /social(P0+P1) /aiChat/网关(P1) /探针/.env/P2 (本次不落地)
文档说明
- 适用范围:backend 全部服务 + gateway + pkg + 配置/部署。
- 工作量:批次 0–4 合计约 14–20 人天(不含架构批次 5)。
- 前置:审计报告
docs/backend-audit-2026-07-21.md;基线 commitb7f8f1b724e5。 - 目标读者:后端负责人、运维、DBA。
二、修复批次详解
批次 0:安全紧急(密钥)
对应审计 P0-1。先做,且需运维配合轮换。
根因:backend/deploy/envs/*.env、backend/.env.example、docker/.env.local、docker/.env.prod 含真实密钥且被 git 追踪。
修复步骤:
- 立即轮换(运维):阿里云 OSS AccessKey(
LTAI5t6QcdJHpYbCPxM8SXYE及第二套)、复用的 SMS key、OpenAI(sk-proj-.../微达)、Dify(app-...)。轮换是首要动作——git 历史清理无法撤销已泄露的凭证。 - 密钥出库:
.gitignore增加:backend/deploy/envs/*.env(保留*.env.example占位模板)。- 从 git 索引移除:
git rm --cached backend/deploy/envs/*.env docker/.env.local docker/.env.prod。 .env.example里所有真实密钥替换为<REPLACE_ME>占位符。
- 清理 git 历史:
git filter-repo --path backend/deploy/envs --path docker/.env.prod --invert-paths(需团队协调强推 + 重新 clone)。 - 改由部署时注入:docker-compose 走宿主机环境变量 / k8s 走 Secret(
values-prod.yaml已 gitignore,作为注入源)。
验证:git ls-files | grep -E 'deploy/envs/.*\.env$' 应为空;git log -p -- backend/.env.example | grep -c 'sk-proj' 为 0。
风险:轮换 OSS key 需同步更新所有消费方(asset/user/gateway);历史清理需全员重新 clone。
批次 1:财务正确性
1.1 展品收益结算幂等(最高优先,已实测资损)
对应审计 §七.1。
根因:exhibition_revenue_records 无 (exhibition_id, cycle_start_time) 唯一约束;cleanup_worker.go 的 ZSET 路径(L137)、DB 兜底路径(L239)、MQ 消费路径三者可对同一展品-周期重复调 OnExhibitionCompleted → CreateRevenueRecord(revenue_service.go:476)无条件插入。实测 3850 个展品同周期重复结算。
修复方案:
- 加唯一约束(migration,见下):
UNIQUE(exhibition_id, cycle_start_time)。 - 写入改幂等:
revenue_service.go:476的CreateRevenueRecord用clause.OnConflict{DoNothing: true}。// repository 层 tx.Clauses(clause.OnConflict{ Columns: []clause.Column{{Name: "exhibition_id"}, {Name: "cycle_start_time"}}, DoNothing: true, }).Create(record) - 收敛结算入口:保留 MQ 消费路径(已有
isAlreadyProcessed),删除cleanup_worker.go:137和:239的直连 RPC 调用(OnExhibitionCompleted已标注"本期内废弃");或让三路共用同一isAlreadyProcessed判重。 - 审计列:新增
settled_at bigint,弃用把is_processed当 settled(原 §四 P2)。
涉及文件:
backend/services/taskService/service/revenue_service.go:461-482(写入幂等)backend/services/taskService/repository/(revenueRepo.CreateRevenueRecord)backend/services/galleryService/service/cleanup_worker.go:137,239(删直连入口)- 新 migration
migration(backend/migrations/2026_07_21_001_exhibition_revenue_idempotent.sql):
-- 先去重历史(保留每组最早一条),再加约束
DELETE FROM exhibition_revenue_records a
USING exhibition_revenue_records b
WHERE a.exhibition_id = b.exhibition_id
AND a.cycle_start_time = b.cycle_start_time
AND a.id > b.id;
ALTER TABLE exhibition_revenue_records
ADD CONSTRAINT uk_exhibition_revenue_cycle UNIQUE (exhibition_id, cycle_start_time);
ALTER TABLE exhibitions ADD COLUMN IF NOT EXISTS settled_at bigint;
-- 序列同步(本表 BIGSERIAL)
SELECT setval('exhibition_revenue_records_id_seq', (SELECT COALESCE(MAX(id),1) FROM exhibition_revenue_records));
验证:迁移后 select count(*)-count(distinct (exhibition_id,cycle_start_time)) from exhibition_revenue_records = 0;重放 worker 两次不新增记录。
1.2 累计时长幂等
对应审计 §七.2。
根因:fan_profile_repository.go:535-558 的 AddExhibitionHours 收 sourceID 但不判重;revenue_service.go:513 资产级累加不传 sourceID。
修复方案:
- 新增去重表
exhibition_hours_log(source_id VARCHAR UNIQUE, user_id, star_id, hours, created_at);AddExhibitionHours事务内先INSERT ... ON CONFLICT DO NOTHING,RowsAffected==0则跳过累加。 - 资产级
assetLevelService.AddExhibitionHours补sourceID参数并同样判重。 - 存量:按 distinct exhibition 重算
total_exhibition_hours与season_exhibition_hours,回滚因虚高误发的升级奖励(见 §四)。
涉及文件:
backend/services/userService/repository/fan_profile_repository.go:535-558backend/services/taskService/service/revenue_service.go:487-524backend/services/assetService/...(assetLevelService.AddExhibitionHours 签名)
1.3 created_at 单位统一
对应审计 §七.1 附带发现。
根因:exhibition_revenue_records.created_at 6013 条秒、45836 条毫秒混存。
修复:代码统一 time.Now().UnixMilli();migration 回填:
UPDATE exhibition_revenue_records SET created_at = created_at * 1000
WHERE created_at < 100000000000; -- 10位秒 → 毫秒
排查同类 bigint 时间列(like_bet_revenue_records、crystal_transaction_records)是否同样混用。
1.4 铸造扣费事务重构
对应审计 P0-2。
根因:mint_service.go:309-318 在 db.Transaction 内调 userClient.UpdateCrystalBalance(跨服务 gRPC);且 CreateMintOrder 非幂等。
修复方案:
- RPC 移出事务:先在事务内落"扣费意图/占位订单",提交后再调 userService 扣费,失败走补偿/回滚订单状态。
- 幂等键:
mint_orders已有order_id,CreateMintOrder入口先按order_id查已存在的成功订单直接返回,而非重复扣费。 - 用户侧
UpdateCrystalBalance已带source_id,确认 userService 侧按(source_id, change_type)幂等。
涉及文件:backend/services/assetService/service/mint_service.go:209-516。
1.5 铸造随机性可预测
对应审计 §三 P1(
mint_service.go:323,349)。
- 保底概率:
mint_service.go:323用time.Now().UnixNano()%100,并发同纳秒结果相同、可被脚本卡点操纵。改用crypto/rand。 - mockTxHash:
mint_service.go:349由orderID/userID/starID/时间戳全可观测输入拼 sha256,可被预测伪造"已上链"。改为不可预测来源或明确标注非链上哈希、不作为凭证。
1.6 doMint 限流 TOCTOU
对应审计 §三 P1(
peripheral_service.go:217-319)。
CountRecentMint(L233)检查与 insert(L271)不在同一事务,并发可绕过 10/24h 限制。把 count 检查并入同一事务,或用 Redis Lua 原子自增。
批次 2:鉴权边界
对应审计 P0-3、P1(trust boundary)。
根因:moderation_provider.go:35、asset_provider.go:483、share_service.go 等直接用 req.UserId/ReporterId/SharerUserId;4/5 服务信任 attachment 不再校验。
修复方案:
- 统一身份提取中间件/拦截器:所有 provider 从 Dubbo attachment 提取
user_id/star_id,覆盖req内同名字段,禁止业务读req.UserId。抽到pkg/公共拦截器,避免每服务各写一份。 - 内部 RPC 可信边界:内部服务间 RPC 走内网 + mTLS 或签名;
ValidateToken(router.go:151)移出公开/auth组。 - 逐个 provider review(asset/social/moderation/gallery/task),列出所有读
req.*Id的点改为读 attachment。
涉及文件:各服务 provider/*.go;pkg/ 新增拦截器;gateway/router/router.go:151。
验证:构造伪造 reporter_id/user_id 的 RPC,应被拦截器覆盖为真实身份。
2.1 socialService 隐私/正确性
对应审计 §三 P1(social 三条)。
friend_service.go:685:CheckFriendship硬编码starID=0(TODO 未做)→ 结果错误 + 好友关系隐私预言机。改为从 attachment 取真实 starID。social_repository.go:648,672,903,923:OR 子句括号优先级问题,可能让已删除资产漏进点赞列表。用显式db.Where(...).Or(...)或单条带括号的 SQL 分组。social_repository.go:461:GetRandomUsersByStar用OFFSET rand + LIMIT取连续段,非随机且可预测。改TABLESAMPLE或ORDER BY random()(小表)。
批次 3:稳定性
3.1 bcrypt 移出事务
P1。
auth_service.go:161,566的HashPassword移到db.Transaction之前。仅需调整语句顺序,风险低。
3.2 Login 限流 + 消除用户枚举
P1。
auth_service.go:300 vs 315统一错误码("账号或密码错误");Login 加与 SMS 同款 Redis 限流。
3.3 MQ 可靠性
P1。
pkg/mq/streams/adapter.go:consumer 名改为稳定标识(服务名+实例名,去掉UnixNano)以便重启认领 PEL;加XAUTOCLAIM回收 + DLQ。若短期不投入,则明确停用 streams adapter(当前 EventProducer/Stream* 常量 0 引用),二选一,避免半吊子。
3.4 material_type 收敛
P1。
asset_like_service.go:267的CONCAT改为集合去重写入(或独立标签表),防无限增长。当前实测最多 3 值未爆,属预防。
3.5 JWT 密钥治理
P1 安全。
pkg/jwt/jwt.go:18包级可变全局jwtSecret,弱默认值"your-secret-key-change-in-production",SetSecret/ParseToken无锁 data race。修复:启动时强制从 env 注入,缺失/为默认值即 fail-fast;密钥用sync.Once或初始化时一次性设定,运行期只读,消除 race;gateway 与 userService 用同一密钥源(KMS/Secret),避免漂移导致全量 token 失效。
3.6 aiChatService 健壮性
对应审计 §三 P1(aiChat 三条)。
ai_chat_provider.go:250:保存上下文用请求里的personaID而非解析后的persona.ID→ 用persona.ID。ai_chat_provider.go:138,141:Redis 出错静默吞掉(记忆/历史丢失无日志)→ 记 Error 日志 + 降级提示,不静默。main.go:190-211/provider:188:Dify/LLM 启动时二选一、无 fallback/熔断/重试,Dify 挂即硬故障,且原样回传err.Error()→ 加熔断/超时/降级,错误映射为稳定用户文案,原始 err 仅记服务端。
3.7 事件/统计可靠性
对应审计 §三 P1(statistic、队列名)。
pkg/statistic/client.go:53-70:TrackEventfire-and-forget,失败只 log → 至少加本地重试/落盘补偿,或明确接受丢失并在文档标注。- 队列名(
"gallery"、"default")硬编码在 producer/consumer 两侧 → 抽为共享常量,消除改名漂移。
3.8 网关聚合与双写
对应审计 §三 P1(gateway)。
asset_controller.go:414-436:铸造后本地写激光卡与 assetService 无事务串联 → 实例卡mining。改为由 assetService 统一落状态 + 事件驱动,或加对账补偿任务。auth_controller.go:69-97等 6 处:Register/Login/Me/Profile 链式调GetFanIdentities(每次拉全量明星目录)→ 让 userService 单 RPC 返回带 star 信息的实体,减少往返并加下游失败补偿。user_controller.go:647-748:DeleteAccount用database.GetDB()自开事务直接软删users+fan_profiles,绕过 userService(userService 无从感知、无法执行下游失效)。近期止血:改调 userService 的删除 RPC;彻底修复随批次 5「网关瘦身」移除网关直连 DB。gateway/repository/laser_card_repository.go、app_download_repository.go:网关持有 DB repo(非纯 BFF)→ 归批次 5「网关瘦身」,DB 写回落 owner 服务。
批次 4:配置/部署
4.1 服务端口对齐
P0-6。修
gateway/config/config.go:162-165默认端口(gallery 20001 / activity 20004 / starbook 20005);galleryService/main.go:44taskService 默认改 20006;userService/main.go:283去掉硬编码WithPort(20000)或删死 flag。加配置测试断言"网关默认端口 == 服务绑定端口"。
4.2 starbookService 决断
P0-7。二选一:
- 正式化:补
go.mod、加入go.work、加 systemd/env;或- 删除:移除目录 +
assetService对它的 import(main.go:32)+ compose/helm/dev.sh/gateway config 引用,代码并入 assetService。 推荐后者(生产未部署它)。
4.3 健康探针 & 大二进制
P1。k8s
notificationservice探针/healthz→/health;moderationservice补探针策略。.gitignore补backend/{assetService,gateway-fixed,test,cleanup-orphan-avatars}并git rm --cached。
4.4 序列规范
P1。
backend/scripts/create_gallery_test_users.go生成的 SQL 末尾补setval(...)(见CLAUDE.md强制规则)。
4.5 .env 漂移
P1。
backend/.env有WS_AI_CHAT_PATH但.env.example未文档化;.env.example有一批.env缺失的必需键(DIFY_TIMEOUT_SEC/DIFY_WORKFLOW/LANDING_BASE_URL/PUSH_*/SEGMENT_*等)。对齐两份,.env.example只留占位符 + 完整键清单。
批次 4.9:P2 择机清理(随相关批次一起做)
对应审计 §四。不单独排期,改动到对应文件时顺手清。
| P2 项 | 文件:行 | 动作 |
|---|---|---|
| 错误码字符串解析 | gateway/controller/asset_controller.go:160-194 |
改用 status.FromError |
| 原始 err 泄露给前端 | auth_controller.go:222、user_controller.go:139 等 |
统一错误码 + 友好文案,err 仅记日志 |
| ResetPassword 不失效 JWT | userService/service/user_service.go:681 |
校验 JWT 与 users.access_token,或引入版本号/黑名单 |
| 头像 URL 不校验同源 | user_service.go:1023 |
限本站 OSS bucket 或只接受 asset id |
| PII 打进 INFO 日志 | ai_chat_provider.go:107、mint_service.go/user_service.go 多处 |
手机号/JWT/聊天内容脱敏或降级 |
| pkg/mq 死代码 | EventProducer/Stream*/asynq.GetInfo/Delete |
删除或补真实现(与 3.3 一并决断) |
| 直连 Redis Pub/Sub | activityService/service/activity_service.go:217,1579 |
走 broker 抽象 adapter.EventProducer |
| 周边密钥兜底 | pkg/peripheral/sign.go:33-44 |
去掉 JWT_SECRET/dev 默认兜底,SECRET_KEY 缺失即 fail-fast |
批次 5:架构治理(路线图,仅规划,本次不落地)
⚠️ MVP 先行:以下为长期方向,当前不实施,避免为未来规模写用不上的抽象。
- 去分布式单体:按域拆库或至少拆 schema + 明确表 owner;跨服务读写改 RPC + service-local DTO。
- 拆
pkg/models:改为各服务本地 model + proto DTO,消除 7 服务共享 model 的编译耦合。 - 消除跨服务 Go import:
taskService↔assetService↔starbookService、gateway→asset/moderation改走 RPC;加 lint 规则禁止新增。 - 拆分
UserSocialService:公开 API 与内部 RPC 分为两个契约(参考task.proto的 Mobile/Internal 范式)。 - 网关瘦身:移除
gateway/repository/,DB 写回落到 owner 服务。 - 事件契约:
proto/event.proto加{event_id, schema_version, produced_at}envelope。
加固动作(本次可做,低成本):加 CI lint 禁止 services/*/ 之间、gateway→services/*/{repository,service} 的新增 import,防止耦合继续恶化。
三、问题 → 修复映射表
| 审计条目 | 严重度 | 批次 |
|---|---|---|
| P0-1 密钥泄露 | P0 | 批次 0 |
| §七.1 结算超发(已实测资损) | P0/财务 | 批次 1.1 |
| §七.2 累计时长幂等 | P1/财务 | 批次 1.2 |
| §七.1 created_at 单位 | P1 | 批次 1.3 |
| P0-2 mint 事务嵌 RPC | P0 | 批次 1.4 |
| §三 P1 mint 随机数/txHash | P1 | 批次 1.5 |
| §三 P1 doMint 限流 TOCTOU | P1 | 批次 1.6 |
| P0-3 身份伪造/越权 | P0 | 批次 2 |
| §三 P1 social 隐私/正确性(CheckFriendship/OR/随机) | P1 | 批次 2.1 |
| P1 bcrypt 事务内 | P1 | 批次 3.1 |
| P1 Login 枚举/限流 | P1 | 批次 3.2 |
| P1 MQ 丢消息/无 DLQ | P1 | 批次 3.3 |
| P1 material_type 增长 | P1 | 批次 3.4 |
| P1 JWT 全局密钥/data race | P1 | 批次 3.5 |
| §三 P1 aiChat(personaID/Redis/Dify) | P1 | 批次 3.6 |
| §三 P1 TrackEvent 丢事件/队列名漂移 | P1 | 批次 3.7 |
| §三 P1 网关双写/链式调用/DeleteAccount 直连 DB | P1 | 批次 3.8(止血)/ 批次 5(彻底) |
| P0-6 端口不一致 | P0 | 批次 4.1 |
| P0-7 starbook 孤儿 | P0 | 批次 4.2 |
| P1 健康探针/大二进制/序列 | P1 | 批次 4.3/4.4 |
| P1 .env 漂移 | P1 | 批次 4.5 |
| §四 P2 全部(8 项) | P2 | 批次 4.9 |
| P0-4/5 分布式单体、共享库、跨域 FK | P0/架构 | 批次 5(路线图) |
| P1 UserSocialService / social.proto 契约混合 | P1/架构 | 批次 5 |
| P1 event.proto 无 version envelope | P1/架构 | 批次 5(事件契约) |
| P1 网关持有 DB repo(laser_card/app_download) | P1/架构 | 批次 5(网关瘦身) |
四、存量数据修复脚本规范
遵循
CLAUDE.md:手动 INSERT 指定 id 必须setval;破坏性操作前备份 + dry-run。
统一要求:
- 备份:
pg_dump -t exhibition_revenue_records -t exhibitions -t user_exhibition_hours -t asset_level_records ...先落盘。 - dry-run:所有清理脚本先跑
SELECT版本输出将影响的行数/金额,人工确认后再跑DELETE/UPDATE。 - 事务包裹:
BEGIN; ... ; COMMIT;,异常回滚。 - 序列同步:任何删改后对相关表执行
SELECT setval('<table>_id_seq', (SELECT MAX(id) FROM <table>));。 - 回收超发:批次 1.1 去重后,统计已
claimed的重复水晶(本库 2,525,254),与运营确认回收/核销口径(本库为测试数据,可直接清账;生产需谨慎)。 - 时长重算 + 等级/奖励回滚(批次 1.2 存量):
- 按
distinct exhibition重算每个(user_id,star_id)的total_exhibition_hours与每个资产的season_exhibition_hours(以去重后的结算记录为准)。 - 用重算后的时长经
CalculateLevelFromExhibitionHours复算等级;对因虚高时长误升的等级下修,并冲销对应的升级奖励水晶(crystal_transaction_records中change_type='level_up_bonus'且 source 关联误升的记录)。 - 全程 dry-run 先出"将下修的用户/资产 + 冲销水晶总额"清单,人工确认后执行;执行后同步相关表序列。
- 按
存量清理顺序:created_at 单位回填(1.3)→ 收益记录去重 + 加约束(1.1)→ 回收重复水晶 → 重算时长 + 回滚误发奖励(1.2)。
五、回归验证清单(每批次完成后)
go build ./...(含go.work全部模块)通过。- 改动函数的所有调用方(
query_graph callers_of)不受影响。 - 相关单测通过;财务/鉴权补新用例。
- migration 在本地
top-fans全新库跑通,序列健康检查通过。 - 端口配置测试通过(批次 4)。
- 伪造身份 RPC 被拦截(批次 2)。
- 结算重放不产生重复记录(批次 1)。
git ls-files无密钥/大二进制(批次 0/4)。
六、备注
- 本文按
CLAUDE.md接口开发规范(分层、DTO、错误码、日志、migration、测试)落地各修复。 - 架构级拆分(批次 5)建议单独立项,本次仅做加固与止血。
- 本库多为测试期脏数据,存量脚本以"可清账"为前提;生产执行前需 DBA 复核并按生产数据量重估。
六.1 跨 plan 执行协调(全局自审 2026-07-21 发现)
各批次已拆成独立 plan(docs/superpowers/plans/2026-07-21-*.md)。以下为多 plan 触碰同一资源的协调约定,执行时按序,第二个改的人先 rebase:
| 共享资源 | 涉及 plan | 约定 |
|---|---|---|
| migration 编号 | settlement/mint/hours | 固定顺序 001 收益幂等 → 002 crystal_tx 唯一索引 → 003 时长幂等,按号执行 |
galleryService/mq/consumer.go isSettled/markSettled + settled_at |
settlement(Task3) owns / config(4.9-G 仅校验) | 只由 settlement plan 改;config plan 不重复编辑 |
galleryService/mq/consumer.go 队列名常量(RegisterHandlers) |
stability(3.7) | 与上者不同区域;建议 settlement 先落、stability 后落 |
taskService/service/revenue_service.go |
settlement(只读调用方) / hours(Task4 改 :513) | 无同行冲突;hours 后落即可 |
userService/repository/fan_profile_repository.go |
hours(AddExhibitionHours) / mint(UpdateCrystalBalance) | 不同方法,任意顺序;第二个先 go build 校验 |
crystal_transaction_records 幂等 |
mint(加 uk_crystal_tx_source_change) |
唯一约束只由 mint plan 加;hours 的 level_up_bonus 流水用不同 change_type,不冲突 |
userService/service/user_service.go ResetPassword |
stability(3.1 bcrypt 出事务) / config(4.9 P2 JWT 失效) | 不同关注点同一函数,串行改、后者 rebase |