优化结构

This commit is contained in:
Yvan 2026-08-27 23:15:00 +08:00
parent e407d3ac10
commit 04ff85116c
1 changed files with 244 additions and 232 deletions

View File

@ -1,261 +1,273 @@
# 代码审查问题清单internal + pkg # 代码审查问题清单internal + pkg
- 审查日期2026-08-27三轮。第三轮2026-08-27核查前两轮修复落地情况 + 以"高内聚低耦合 / 简单实现复杂化 / 过分拆分 / 包归属(可抽 pkg/utils"为重点重审全库 - 审查日期2026-08-27共三轮全量审查
- 审查方式:第一轮 codegraph + 5 路并行深读;第二轮 6 路逐文件深读;第三轮 5 路并行(修复核查 + 重审)。所有死代码结论均经全仓库 Grep 反查调用方验证;第三轮附带 `go build ./...` 编译验证通过 - 审查方式codegraph 符号分析 + 多路并行逐文件深读 + 调用链 Grep 反查验证;第三轮附带 `go build ./...` 编译验证通过
- 第三轮修复核查结论:**S0×17、P0×6、P1-1/2/3/4/5/6/7/10、P4-4、S4 两条全部真实落地**(已从本文档删除,留痕见文末"已修复确认清单"**未修复**S1 死代码大部分、P2/P3/P4 结构问题大部分、1-8/1-8b/1-9/2-10/3-8/3-9 - 文档结构:问题按**类型**归类(不按轮次);每条标注发现轮次【一轮/二轮/三轮】;已修复并经复查确认的统一列在文末
- 当前待办集中在T0 修复回归缺陷 → S1/T3 死代码 → T1 过分拆分合并 → T2 归属移动 → S2 重复消除 → P2/P4 结构 - gva/ 目录是遗留参考库(独立 module 不参与 kra 编译),不在审查范围
- 依赖方向合规确认pkg 无 import internalintegration 无 import data/serviceservice→biz→data 无反向;无循环依赖——架构骨架健康,债务集中在粒度与零消费抽象
优先级定义P0 = 零风险可直接删P1 = 低风险去重P2 = 中风险删转发层P3 = 涉及 import 路径批量修改的移位P4 = 大动作结构合并/文档修正。
--- ---
## P1 重复实现 / 双份维护(遗留 ## 一、修复回归与残留缺陷S0 修复后遗留9 条
| # | 问题 | 位置 | 建议 | | # | 问题 | 位置 | 轮次 |
|---|------|------|------| |---|------|------|------|
| 1-8 | DSN 一致性双写:`persistDatabaseConfig`、`refreshDatabaseSource`、`InitializeDatabase` 三处维护"结构化字段→Source"不变式refresh 用"先清空再恢复"绕开 databaseDSN 短路 | internal/data/config_store.go:78-94internal/data/initialization_backend.go:42-59,135-140 | 固化进 databaseDSN 唯一入口 | | R-1 | **vendor 退款静默受理残留(资金安全,高危)**S0-1 修复覆盖"FAIL 状态字段"场景,但 create/refund 响应 HTTP 200 且 body 非 JSON、或无可识别状态字段时仍默认 `created`biz `validatePaymentRefundResult` 接受 created → 真实被拒但响应无状态字段的退款会被永久记为已受理。建议 refund 端点无状态字段时报错或至少 pending | internal/integration/payment/vendor.go:135-163biz/payment/payment.go:1020-1021,837-855 | 三轮 |
| 1-8b | "storage/email 缺省则沿用现值"策略散布 4 处(文件/DB 配置合并规则;原 5 处已收敛为 4 处,但无统一 MergeRuntimeConfig | internal/config/runtime.go:275-286internal/data/config_store.go:173-183internal/data/initialization_backend.go:77-85,171-186 | config 包提供唯一 `MergeRuntimeConfig` | | R-2 | Excel `[]byte` 全转文本副作用MySQL 数值列也变文本单元格,大面积"数字以文本存储"警告(原值保真达成,展示体验回退);可结合模板列类型区分处理 | internal/service/system/export_excel.go:85-86 | 三轮 |
| 1-9 | config.Store 与 runtimeconfig.Store 各写一套同构的 listener 注册/通知/克隆机制(语义确有差异:文件全量 vs DB 集成窄通道,可辩护为有意分离,需明确决策) | internal/config/runtime.go:29,150-196internal/integration/runtimeconfig/store.go:62-167桥接靠 data 层三处 Replacedata.go:417、config_store.go:258、initialization_backend.go:214 | 抽泛型 notifier或写决策注释固化现状 | | R-3 | ErrAuthoritiesRequired 错误透传缺失biz 返回具体错误后 handler 只回"修改失败"data 层 setUserAuthorities 还残留一处重复中文防御错误(双轨) | internal/server/handler/user.go:208-212internal/data/system/user.go:563-565 | 三轮 |
| 1-11 | mq.Registry 接口面积翻倍且恶化legacy APISubscribe/Unsubscribe/Publish内部转译为声明式 Register双面并存且整个 mq 体系业务消费者为零 | pkg/mq/mq.gointernal/integration/mq/emqx.go:539-589 | 见 T3整体裁撤或收缩 | | R-4 | 版本导入非原子残留:落库成功但留痕 CreateVersion 失败时返回错误,用户误判"导入失败"(幂等查重使重试可控) | internal/service/system/version.go:256-270 | 三轮 |
| R-5 | 任务元数据双源漂移已发生:种子描述("**定时**清理…")与注册方法描述("清理…")不一致;建议 worker 注册时复用 catalog TimedTask 元数据 | internal/modules/task/definition.go:14-15 vs internal/worker/task_registry.go:31,45 | 三轮 |
| R-6 | export SQL/ImportSQL 摆设字段dto 保留但 ValidateExportTemplate 拒绝非空,只能提交空值且响应回显空值 | internal/service/dto/export.go:26-27internal/biz/system/export.go:72-74 | 三轮 |
| R-7 | payment 回调读体失败分支未入 Gin 错误链S0-12 修复只覆盖 service 调用错误) | internal/server/handler/payment.go:149-153 | 三轮 |
| R-8 | LoginLogFilter 收敛为仅 Username/Status 两字段:若前端需按 IP/时间筛选登录日志则能力缺失(设计取舍需确认) | internal/biz/system/audit.go:42-45 | 三轮 |
| R-9 | PaymentUsecase 注册面零调用时,生产装配下支付主链路 Create/Refund/Fulfill 必然在 preparePaymentRequest 报"支付业务订单来源未注册"——模板未完成态,建议 Wire/cmd 层提供默认注册或 fail-fast 提示 | internal/biz/payment/payment.go:296-326,407-410 | 三轮 |
## P2 转发 shim / 门面层(过度分层) ## 二、死代码与零消费者机制
### 2.1 biz/data/service 三层死方法(约 15 组,均经全仓 Grep 反查确认零调用)【二轮发现,三轮复核仍在】
| 层 | 死代码 | 位置 |
|----|--------|------|
| biz 接口 | PermissionRepo.Buttons/SetAuthorityButtons/AuthorityButtonIDs3/4 方法死) | biz/system/permission.go:6-8 |
| biz 接口 | APITokenRepo.DisableAPITokenUserRepo.CreateUser/UpdateUserWithAuthorities | biz/system/api_token.go:26user.go:45,49 |
| biz 接口 | MediaMetadataRepo.FindMediaByHashMenuRepo.AuthorityMenuIDs | biz/system/media_metadata.go:44menu.go:61 |
| biz 接口 | EmailUsecase.AlertSecurityUsecase.ActiveTokenMatches | biz/system/email.go:31-48security.go:243-249 |
| biz 注入面 | PaymentUsecase 注册面SetHooks/SetOrderSourceRegistry/SetFulfillmentRegistry/RegisterBusinessModule含两阶段注册+回滚补偿PayInternal/RefundInternal/AuthorizeRefund 无生产实现service 却作为正式 API 暴露Fulfill | biz/payment/payment.go:296-326 |
| data 实现 | 与上述接口配套parseTemplateColumns、userRepo.CreateUser/UpdateUserWithAuthorities、DisableAPIToken、FindMediaByHash、AuthorityButtonIDs、AuthorityMenuIDs | data/system/export.go:430-440、user.go:317-319,474-491、api_token.go:108-114、media.go:67-73、permission.go:113-117、menu.go:283-287 |
| service 包装 | MenuService.List连带 biz MenuUsecase.Listhandler 实际用 TreeRecordLogin/RecordDataAccess后者整链含 biz 接口+data 实现全死IsTokenDisabledsecurity_session.go 14 方法中 8 个死AuditRecorder.CreateErrorRequest+recordedErrorDomain | service/system/menu.go:14-20、audit.go:56-58,91-93、api_token.go:60-62、security_session.go:17-67、audit_error.go:17-31 |
| dto 死类型 | LoginLogRequestDataAccessRecordRequestGetAuthorityButtonsRequest.SelectedMenuResponse.Authorities 恒 nullbiz 无此字段DynamicMenuResponse.MenuButtons 恒 nilSysBaseMenuID 输入被静默丢弃version 导出结构体大量零值噪声字段ID:0/CreatedAt 零时间/authoritys:null | dto/system.go:68-75、audit.go:21-30、menu.go:21,28,132、version.go:23-94 |
误报更正service 层 PersistConfig 实为活代码initialize.go:20 消费)【三轮更正】。
### 2.2 mq / websocket 零消费者基础设施【二轮发现,三轮复核反而扩大】
- mq 全链(声明式订阅+legacy API+簿记/dispatcher/reconcile业务消费者为零emqx.go 约 710 行 + mq.go 106 行 + subscription.go 55 行空转legacy APISubscribe/Unsubscribe/Publishemqx.go:539-589内部又转译为声明式 Register双面并存且加码`internal/modules`、`biz`、`service` 无一处注册订阅或调用 Publish
- websocketHub 接口零消费者单实现pkg/websocket/melody.go:28-40wire 死绑定 provider.go:31integration 层 On* 四注册方法零调用server.go:326-373双层 handler 登记机制两层都永远为空server.go:28-31,169-180 vs melody.go:65-118
- 连带死装配cmd/main.go:65 `_ mq.Client` 幻影参数(为保活 wire 图integration/provider.go:28,29 两条死 wire 绑定
- 建议要么接入首个真实业务消费者要么裁掉保留最小面TestConfig 探测 + Enabled/Path/HandleRequest
### 2.3 零散死代码【二/三轮】
| 死代码 | 位置 |
|--------|------|
| s3 多 provider endpoint 五个不可达分支local.go:39-48 只让 minio 进 newS3Storage | storage/s3_storage.go:29-41 |
| namedClient/Client() 整型死代码 | integration/mq/emqx.go:47-50,632-650 |
| isBootstrapPath 零调用 | middleware/capture.go:72-74 |
| NewGinEngine 生产死代码wire 用 NewGinEngineWithRuntime测试专用 | server/gin.go:23-25 |
| vendorSupperPay 死枚举(定义注册但 switch 无 case | integration/payment/vendor.go:26,38 |
| stringOrnormalizePayPalOrderStatepaypalOrderTradeNonestedString/amountFromDecimalFieldshim 连调用者都没有) | wechat_v2.go:584、paypal.go:651,388-391、result.go:98,148-155 |
| RegisterAll 仅测试调用TaskScheduler.Trigger(task) 可未导出(仅 TriggerID 内部用) | pkg/task/registry.go:39worker/task_scheduler.go:425 |
| 仅测试调用decryptWechatV3、alipaySignContent、validatePaymentConfig、wechatV2Sign可移测试文件 | wechat_v3.go:600-605、alipay.go:572-585、data/payment/payment.go:551-553、wechat_v2.go:47 |
| P1-3 修复残留 micro-shimresult.go:58-64 与 payment_helpers.go:5-11 仍保留同名本地包装转发 paymentutil | integration/payment/result.godata/payment/payment_helpers.go |
## 三、重复实现 / 双份维护
### 3.1 大块可消除(估算合计 1900+ 行)【二轮】
| # | 问题 | 位置 | | # | 问题 | 位置 |
|---|------|------| |---|------|------|
| 2-1 | payment 回调 ack 穿透仍四层(第三轮部分收敛:定义已单源化到 paymentkit、biz 用别名零拷贝;但 biz/service/handler 三层转发仍在,且 dto/payment.go:58-62 重复声明同构 3 字段结构体,加字段需同步三处) | pkg/paymentkit/callback.go:11-83 → biz/payment/payment.go:206-215 → service/payment/payment.go:131-148 → handler/payment.go:173-184 | | D-1 | data/system List 样板 13 处同构(构建 db→逐字段翻译 filter→Count→分页→Find→循环 toBiz可抽泛型 helper 消 200+ 行 | data/system/user.go:281-315、api.go:119-181、data_access_log.go:32-55、operation_log.go:39-68、error_record.go:83-109 等 13 处 |
| 2-2 | integration/payment/result.go 自称 "Compatibility shims"11 个纯转发函数全部仍在normalizePaymentStatus/parseIntegerAmount/jsonObject/nestedString 等) | internal/integration/payment/result.go:68-110 | | D-2 | payment 渠道适配器家族重复约 500 行:下单方式归一化骨架 9 份Replacer 归一化行逐字出现 9 次);退款身份校验 4 份同构;状态归一化 switch 10 份(可收敛为 normalizeState+词表);金额拆分守恒 5 份+biz 层第 6 份SDK 客户端构造 10 份同构firstNonEmpty 三胞胎mustMarshalAlipayPayload≡mustJSON | integration/payment/alipay.go:434-456、douyin.go:108-126、qq.go:124-144、lakala.go:69-75、saobei.go:87-101、wechat_v2.go:184-204、allinpay.go:205-221、gopay_helpers.go:145-225、alipay.go:475/qq.go:146/paypal.go:707、alipay.go:470-473 等 |
| 2-3 | service 根包 25 个 `type X = systemservice.X` 别名门面 + 函数转发(迁移脚手架,注释自辩 "one import instead of four";使 handler 无法感知真实包结构) | internal/service/service.go:18-51 | | D-3 | storage provider 家族重复约 200 行key/unkey/file 三件套 5 份逐行相同DeletePrefix 分页循环 5 份(可提 deletePrefixViaListCompose 一行委托 7 份limit 守卫 7 份;构造尾部样板 5 份 | storage/aliyun_storage.go:35-48、aws_storage.go:63-76、huawei_storage.go:31-44、s3_storage.go:61-74、tencent_storage.go:45-58 等 |
| 2-4 | handler/http.go 纯转发别名层3 常量+2 类型+6 函数一对一转发到 pkg/httpx 与 middleware.Claims仅为省一个 import每个 handler 文件仍要同时认识两个包) | internal/server/handler/http.go:14-29 | | D-4 | handler 四段式样板约 70 处ShouldBindJSON→Fail→service→Write抽 bindJSON+respond 两个 helper 可消一半 | server/handler/*announcement.go:17-28、api.go:43-240、audit.go:27-316 等) |
| 2-5 | service/task 双面 APIDO 签名版与 DTO 版并存DO 版 Create/Update/Tasks 仅被同文件 DTO 版内部调用handler 只用 `*Request` 版 | internal/service/task/task.go:35-46 | | D-5 | middleware请求体读取三处access_log.go:56-74 / audit.go:49-67 fallback / handler/media.go:17-21同一请求体三层 MaxBytesReader脱敏/截断三处且分散capture.go:41-68 / audit.go:118-136 / redact 词表在 redact.go 函数散在 access_log.goaudit.go:47-48,93 对已 mask 已截断的正文再处理一遍 | server/middleware/* |
| 2-6 | TaskUsecase 嵌入透传且加重:仍嵌入 TaskRepo 透传 9 方法给 worker新增 TaskApplicationUsecase 再包一层,其 6 方法纯转发——双 usecase 并存worker 持前者、service 持后者wire_gen.go:115-119 | internal/biz/task/task.go:76-79,159-237 | | D-6 | mq/websocket 两包各写一套 map 解码 helper 且逐字符相同configText≡text、configBool≡boolValueTestConfig 探测骨架三处同构 | emqx.go:226-260 vs websocket/server.go:189-240emqx.go:92-133/server.go:65-126/connectivity.go |
| 2-7 | `openWithDriver` 单调用点便捷转发(第三轮部分修复:已拆出 openWithDriverConfigwrapper 仍有 1 个生产调用 + 约 20 处测试调用) | internal/data/database.go:134-136生产调用 :248 |
| 2-8 | Backend 接口三层缝合biz `InitializationRepo` → initialize.Repo内嵌 6 方法 Backend + seed 回调单传入点)→ data.Datainitialize 包只为"转手 6 个同名方法 + 注入 catalog"存在 | internal/initialize/initialize.go:17-46internal/data/initialization_backend.go:17-217cmd/wire.go:45 |
| 2-9 | data-scope 审计回调 `dataScopeAuditEnqueue` 穿透 6 层签名,生产实现唯一 | internal/data/data.go:238,245,392 → runtime_clients.go:168 → data_scope.go:19-136 |
| 2-10 | `*Data` 方法约 10 处模板式 `if d == nil` 防御(构造归 Wire 管理,不可能为 nil`NewIntegrationRuntime` 的 nil→空 Store 回退掩盖错误状态 | internal/data/data.go:41,72,82,88,97,119,126,373-375initialization_backend.go:18 |
## P3 包归属问题pkg 应为可对外复用、无业务语义) ### 3.2 配置/数据不变式双份维护【一轮,三轮复核仍在】
| # | 包 | 问题 | 建议 | | # | 问题 | 位置 |
|---|----|------|------| |---|------|------|
| 3-1 | pkg/paymentkit | 目录名≠包名(实际 `package paymentutil`17 个支付渠道常量是本项目商户目录(与 biz/integration 中文渠道定义一一对应);回调 ack 硬编码微信/支付宝协议、中文业务文案;调用方 100% 在 internal | 整体并入 internal/integration/payment顺带消灭 17 常量双份导出biz/payment/payment.go:20-43 逐个重命名再导出一遍)、三层金额/回调转发、text/firstAny 双份 | | D-7 | DSN 一致性三处维护"结构化字段→Source"不变式refreshDatabaseSource 用"先清空再恢复"绕开 databaseDSN 短路 | data/config_store.go:78-94initialization_backend.go:42-59,135-140 |
| 3-2 | pkg/logging | source.go:54-61 硬编码 internal 目录布局效果等同反向依赖zap.go:346-383 中文上报文案、:342 特判遗留 gva 项目文件名AGENTS.md 声称的 `internal/logging/` 目录实际不存在 | 内移为 internal/logging同步修 AGENTS.md | | D-8 | "storage/email 缺省则沿用现值"策略散布 4 处(原 5 处收敛为 4无统一 MergeRuntimeConfig | config/runtime.go:275-286config_store.go:173-183initialization_backend.go:77-85,171-186 |
| 3-3 | pkg/httpx | response.go:17 业务状态码 10001PasswordChangeRequired:60-69 硬编码 `x-token` cookie 契约;调用方全部在 internal/server | 移入 internal/server | | D-9 | config.Store 与 runtimeconfig.Store 各写一套同构 listener/通知/克隆机制(语义有差异:文件全量 vs DB 集成窄通道,可辩护为有意分离,需明确决策;桥接靠 data 层三处 Replace | config/runtime.go:29,150-196runtimeconfig/store.go:62-167 |
| 3-4 | internal/initialize/configuration.go | `management*` 家族(:221-318手工构造 camelCase JSON属 service 层 DTO 塑形职责;根因是 biz `InitializationRepo``json.RawMessage` 为出入参,表现形状泄漏进 repo 层 | JSON 形状定义移至 internal/service/dtosnakeCase/normalizeDuration 等纯函数与掩码逻辑分文件(当前 464 行混杂三种职责) | | D-10 | "storage/email 不落盘"不变式三重执行persistConfigValues 置 nil+Delete、persistDatabaseConfig 再 Delete、removeIntegrationConfigFromFile 启动时又删一遍(一次性迁移 shim 常驻持久化路径) | config_store.go:46-52,103-104,108-125data.go:279-283 |
| 3-5 | pkg/database/pagination、gormkit | 调用方 100% 在 internal/data分页纯数学无业务语义轻度 | 可下沉 internal/data低优先级 |
| 3-6 | pkg/mq | rabbitmq.go:127 硬编码项目名前缀 `kra-`subscription.go 的 Contributor 面向本项目 module 概念 | 去项目化(低优先级) |
| 3-7 | pkg/module、pkg/task、pkg/database/migration | 只被本仓库消费但互为依赖构成同层契约组module 依赖 migration/task单独搬会破坏依赖方向一致性 | 维持现状 |
| 3-8 | internal/data/runtime_clients.go | `newReloadableDB` 在通用热切换构造器里调用领域函数 `registerDataScopeCallbacks`,越界 | 该调用移到 data.go 与 replacePrimaryDB 同址 |
| 3-9 | internal/data/data_scope_record.go | 整文件只有一行类型别名 `dataAccessLogPO = datasystem.DataAccessLogPO` | 删除文件并入 data_scope.go |
## P4 结构性设计(双份数据 / 文档漂移,大动作需决策) ### 3.3 中小重复【一/二轮】
| # | 问题 | 位置 | 建议 | | # | 问题 | 位置 |
|---|------|------|
| D-11 | authority 树构建算法两份byID map+Children 重置+父子装配,仅节点类型不同) | biz authority.go:48-78 vs menu.go:80-99 |
| D-12 | CreateAuthority/CopyAuthority 前 8 行校验逐字重复 | data/system/authority.go:133-151,211-245 |
| D-13 | gorm.DeletedAt→*time.Time 转换 4 处逐字重复 | data/system/user.go:99-104、menu.go:17-21,241-245,250-255 |
| D-14 | version 阶段→消息映射两份engine.Routes()→dto 转换两份 | handler version.go:107-121 vs 158-167api.go:161-167 vs public.go:135-139 |
| D-15 | defaults 合并逻辑三层三份 | service/integration:86-98 / biz/integration:215-224 / data/integration/migrations.go:69-75 |
| D-16 | media 分片根目录逻辑两份media_upload 三处复制会话校验样板(顺带吞掉 ErrUploadNotFound 可判定性) | biz media.go:126-132 vs media_upload.go:61-69media_upload.go:120-129,176-184,244-250 |
| D-17 | data/paymentcallbackFields/first 整函数复制且已分叉integration 版 Content-Type 大小写不敏感遍历 vs data 版直接下标行为漂移隐患values() 与 testRow() 近重复;渠道"免 notify_url"同义词表在 data 层重抄一份与各适配器 createMethod 表双份维护 | data/payment/payment.go:507-540,31-50,273-292,394-425 vs integration/payment/result.go:14-56 |
| D-18 | serviceauthorityResponse 与 convertAuthority 逐字重复;"单条 DTO helper + for-append"样板 9 处;"Request 包装+Filter 包装+裸方法"三重入口家族audit/parameter/export/dictionary/mediauser 空对象兜底三连 | service/system/authority.go:30-36 vs user_conversion.go:8-14 等 |
| D-19 | payment 金额守恒校验四处重复biz validatePaymentBreakdown + vendor + wechat_v3 + douyin 各一份) | biz/payment/payment.go:1112-1135vendor.go:235-253wechat_v3.go:555douyin.go |
| D-20 | 状态词汇归一三处维护paymentutil.NormalizeStatus + 各 adapter + data/payment normalizeOrderPaymentStatus | paymentkit/status.go:8-19data/payment/payment_order.go:478 |
## 四、过度分层:转发门面 / 透传壳 / 回调穿透
| # | 问题 | 位置 | 轮次 |
|---|------|------|------| |---|------|------|------|
| 4-1 | router 与 routecatalog 双声明21 个 router 文件纯声明式注册 method+pathroutecatalog 又用一张 map 声明同一批路由的元数据public/audit/group靠契约测试强制对齐——改一条路径要同时改两处 | internal/server/router/*routes.go:22-43 手工 21 连调internal/routecatalog/catalog.go:41- | 表驱动合并为单一声明源method+path+handlerFunc+元数据),可同时消掉对齐测试 | | F-1 | payment 回调 ack 穿透四层(定义已单源化到 paymentkit、biz 用别名——算部分收敛;但 biz/service/handler 三层转发仍在dto/payment.go:58-62 重复声明同构 3 字段结构体,加字段需同步三处) | paymentkit/callback.go:11-83 → biz/payment/payment.go:206-215 → service/payment/payment.go:131-148 → handler/payment.go:173-184 | 一轮(三轮复核部分收敛) |
| 4-2 | 新增一个资源实际要触碰 7 处dto、service/system、handler、router/资源文件、router/routes.go、routecatalog、Set/provider | — | 同 4-1 | | F-2 | integration/payment/result.go 自称 "Compatibility shims"11 个纯转发函数全部仍在 | integration/payment/result.go:68-110 | 一轮 |
| 4-3 | 同一份集成配置三种形状两条通道:`config.Storage` 强类型 ↔ `sys_integration_configs` JSON 行 ↔ 运行时客户端storage/email 走 config.Storeemail 即时读快照、storage 手动 Replacemq/websocket 走 runtimeconfig 订阅——同一"集成"概念两套配置源两种重载模式 | internal/data/integration_config.go:43-104,157-179internal/data/integration/runtime.go:13-29storage/reloadable.go:18-32email/email.go:25-34 | 评估统一为一条解析-分发通道 | | F-3 | service 根包 25 个 `type X = systemservice.X` 别名门面 + 函数转发(迁移脚手架;使 handler 无法感知真实包结构) | service/service.go:18-51 | 一轮 |
| 4-5 | swagger 运行时文档:约 160 行 map 手拼 Swagger 2.0 JSON + 正则加工,全局单例仍在 server 根包 | internal/server/swagger.go:21-159 | 可辩护README 有意为之),但按 server/README 自己的规则更宜独立子包 | | F-4 | handler/http.go 纯转发别名层3 常量+2 类型+6 函数一对一转发,仅为省一个 import每个 handler 文件仍要同时认识两个包) | server/handler/http.go:14-29 | 一轮 |
| 4-6 | 错误日志热路径做磁盘 IO + go/parser AST 解析(为错误上报附上出错方法源码) | pkg/logging/source.go:71-104pkg/logging/zap.go:373-379 | 展示性需求不该在日志关键路径,缓存或降级 | | F-5 | service/task 双面 APIDO 签名版与 DTO 版并存DO 版仅被同文件 DTO 版内部调用handler 只用 `*Request` 版 | service/task/task.go:35-46 | 一轮 |
| 4-7 | dto 包文件组织混乱dto/system.go 混装 Login/User/ServerInfo 三域dto/settings.go 横跨 Dictionary/SystemParameter/APIToken/SecurityConfig 四域(名不副实) | internal/service/dto/system.go:5-105settings.go:5-172 | 按域拆分重命名 | | F-6 | task 双 usecase 并存且加重TaskUsecase 嵌入 TaskRepo 透传 9 方法给 workerTaskApplicationUsecase 再包一层、其 6 方法纯转发worker 持前者、service 持后者wire_gen.go:115-119 | biz/task/task.go:76-79,159-237 | 一/三轮 |
| 4-8 | 校验双轨制handler 手工 if 校验与 dto binding 标签并存menu dto 无 binding 标签全靠 handler 手补 | internal/server/handler/user.go:27-64internal/service/dto/settings.go:46-48 | 统一为 binding 标签 | | F-7 | Backend 三层缝合biz InitializationRepo → initialize.Repo内嵌 6 方法 Backend + seed 回调单传入点)→ data.Datainitialize 包只为"转手 6 个同名方法+注入 catalog"存在 | initialize/initialize.go:17-46data/initialization_backend.go:17-217cmd/wire.go:45 | 一轮 |
| 4-9 | 单方法 handler 各占结构体+构造器+Set 字段Session/Navigation 可并入相邻资源 handlerSet 已膨胀到 23 个字段、provider 23 个构造器) | internal/server/handler/session.go:10-12navigation.go:9-11set.go:3-26 | 合并 | | F-8 | data-scope 审计回调 dataScopeAuditEnqueue 穿透 6 层签名,生产实现唯一 | data/data.go:238,245,392 → runtime_clients.go:168 → data_scope.go:19-136 | 一轮 |
| 4-10 | local 存储两套入口逻辑staticfiles 直读 config 本地盘语义 vs integration/storage 的 Reloadable 体系 | internal/server/staticfiles/staticfiles.go:49-92internal/integration/storage/local.go | 边界收敛(低优先级) | | F-9 | **纯透传壳 usecase 12 个**(整个 struct 无自有逻辑/纯改名转发service 可直依赖 biz repo 接口——repo 接口仍在 biz分层契约不破wire 链物证 wire_gen.go:88-91 permission 全程零逻辑Parameter/Permission/Version/Announcement(7 方法全透传)/Maintenance/AccessControl/Department(2 改名)/Authority(仅 Tree 有逻辑)/Task/Menu(10 处透传)/User(13 处透传)/SystemConfig(7 处透传)。对照组有真实逻辑应保留Authentication/Security/Media/Email/IntegrationConfig/Payment/TaskApplication | biz/system/*、biz/task/task.go | 三轮(二轮发现同型) |
| F-10 | security_session.goSecurityService 14 方法全部一行透传(零 DTO 工作service 层另有近纯透传小文件 email.go(16)/permission.go(24)/access_control.go(28仅 5 行逻辑) | service/system/security_session.go:17-68 等 | 三轮 |
| F-11 | biz 接口嵌入透传 12 处 usecaseAPI/Token/LogViewer/Audit/AuditRecorder/Authority/Dictionary/Export/Media/Parameter/Permission/Position/Version与同包 9 个私有字段风格并存 | biz/system/* | 二轮 |
| F-12 | `openWithDriver` 单调用点便捷转发(已拆出 openWithDriverConfigwrapper 仍有 1 个生产调用 + 约 20 处测试调用) | data/database.go:134-136生产调用 :248 | 一轮(三轮复核部分修复) |
## 五、过分拆分 / 文件组织
**根因模式三条**【三轮】:①零逻辑 usecase 壳wire 强制每域一个构造器放大);②"每资源 N 文件"机械切分dto+biz+service+handler+router 各一个);③为 import 美观引入的中间缝合包/门面。
| # | 问题 | 位置 | 轮次 |
|---|------|------|------|
| S-1 | biz/system 38 文件 3430 行,其中 17 个非测试文件 <60 合计约 575 保守可归并 8-10 个文件errors.go(14)cache.go(15)maintenance.go(19)actor.go(19)access_control.go(20)storage.go(26)data_scope.go(27)upload_session.go(38)parameter.go(33)settings.go(43)department.go(46)position.go(48)token.go(48)media_metadata.go(53)email.go(48)/api_token.go(55)/version.go(57)合并建议actor/data_scopeauthoritycachesecuritystorage/media_metadata/upload_sessionmedia department+positionorganizationtokenauthenticationerrors 集中 | biz/system/* | 三轮 |
| S-2 | SystemConfigService 一型拆四文件system.go(19)+system_config.go(26)+system_init.go(38)+system_info.go(42)=125 行audit.go 与 audit_error.go 同属 AuditService/AuditRecorder 可合并audit_log_file.go 是独立 LogViewerService保留 | service/system/* | 三轮 |
| S-3 | router 22 文件 464 行,平均 21 行/文件(最小 email.go 12 行routes.go:18-43 手工 21 连调——纯注册碎片无内聚(与 X-1 表驱动合并一并解决) | server/router/* | 三轮 |
| S-4 | 单符号包/微文件modules/surface 整包只有 1 个 10 行函数data/provider 整包只有 1 个 7 行 2 方法接口中性缝可辩护provider.go+providers.go 双小文件模式 ×4 子包8 文件可并 4bootstrap.go(27 行仅 seed 用)worker/worker.go(7 行)、initialize/provider.go(5 行)、pkg/task/provider.go(3 行)、biz/payment/provider.go(8 行) 纯 wire-set 微文件data_scope_record.go 整文件 1 行别名 | 各处 | 三轮 |
| S-5 | 巨微两极biz/payment/payment.go 单文件 1150 行usecase+常量再导出+5 validator+指纹工具vs 同域 payment_log.go(32)/provider.go(8)dto authentication.go(8 行)/email.go(7 行) vs settings.go(170 行横跨四域) | biz/payment、service/dto | 三轮 |
| S-6 | dto 包文件组织混乱system.go 混装 Login/User/ServerInfo 三域settings.go 横跨 Dictionary/SystemParameter/APIToken/SecurityConfig 四域(名不副实) | service/dto/system.go:5-133settings.go:5-170 | 一轮 |
| S-7 | data 层组织纪律:转换函数命名四种风格违反 new<X>/toBiz 契约FromPO×16/ToPO×4/ToBiz×2/new×2PO 分布无规则models.go 集中 6 个+散落 30+models.go:98-100 还混 repo 声明audit.go 名不副实(只有构造器,实现在 5 个文件runtime.go 拼盘settings+tokenIssuer 无关联转换函数跨文件错位dictionary.go 的 parameterFromPO 服务 parameter.go | data/system/* | 二轮 |
| S-8 | media 域同域碎片biz/system 的 media.go(158)/media_upload.go(268)/media_metadata.go(53)/upload_session.go(38) 拆四文件 | biz/system/media* | 三轮 |
| S-9 | 单方法 handler 各占结构体+构造器+Set 字段Session/Navigation 可并入相邻资源 handlerSet 已膨胀到 23 字段、provider 23 个构造器) | server/handler/session.go、navigation.go、set.go:3-26 | 一轮 |
## 六、包归属问题(应移 pkg / internal / utils
### 6.1 移动建议清单【三轮汇总】
| # | 从 | 到 | 理由 | 影响 |
|---|---|---|---|---|
| P-1 | pkg/httpx | internal/server/httpx | 消费者 100% 在 internal/server 7 文件;中文文案+x-token cookie 是本项目契约logging/source.go:59 已预留该路径 marker | 7 文件 |
| P-2 | pkg/logging | internal/logging | source.go:47-69 硬编码本仓库 internal 路径zap.go:366-382 中文文案模块路由硬编码服务日志查看器语义AGENTS.md 声称的 internal/logging 不存在 | 约 5 文件 |
| P-3 | pkg/module | internal/modules | Menu/API/Surface/TimedTask 是本项目模块系统契约import gin15 消费者全在本仓库 | 15 文件 |
| P-4 | pkg/paymentkit 渠道常量provider.go | internal/biz/payment 本体 | 常量归位并删 biz/payment/payment.go:20-43 的 17+2 个别名转发层;目录更名 paymentutil 对齐包名当前目录名≠包名通用工具signing/json/amount/xml可留 pkg 或并入 internal/utils | 约 8 文件 |
| P-5 | pkg/mq + pkg/websocket(Hub) | 收缩或合并进 internal/integration/mq | 全链零业务消费者(见 2.2);保留 TestConfig 探测+基础驱动,删 Registry/Client()/namedClient/legacy API/Hub/ApplySubscriptions | 约 7 文件 |
| P-6 | integration/mq 与 integration/websocket 的重复 JSON map helper | internal/utils/jsonvalue | 上收去重(逐字符相同) | 2-3 文件 |
| P-7 | storageaws-sdk-v2 栈与 minio-go 栈双 S3 实现并存 | 统一 S3 兼容单栈(可选) | qiniu/aliyun/huawei/tencent 原生 SDK 均有 S3 兼容端点,可收敛删 4 实现+s3 死分支 | 5-6 文件 |
| P-8 | handler/query.go:13-61Gin 工具、middleware/request.go:67-102纯函数、handler/announcement.go parseTime被 export.go 跨域借用) | pkg 或 internal/utils 候选 | 通用无状态逻辑上收 | 3 文件 |
### 6.2 其他归属/职责越界【一/二轮】
| # | 问题 | 位置 |
|---|------|------|
| P-9 | internal/initialize/configuration.gomanagement* 家族(:221-318手工构造 camelCase JSON属 service 层 DTO 塑形职责;根因是 biz InitializationRepo 以 json.RawMessage 为出入参,表现形状泄漏进 repo 层464 行混杂 DTO 塑形/JSON 规范化/秘密掩码三种职责 | initialize/configuration.go |
| P-10 | pkg/database/pagination、gormkit调用方 100% 在 internal/data无业务语义轻度 | pkg/database/* |
| P-11 | pkg/mqrabbitmq.go:127 硬编码项目名前缀 `kra-`subscription.go 的 Contributor 面向本项目 module 概念 | pkg/mq |
| P-12 | newReloadableDB 在通用热切换构造器里调用领域函数 registerDataScopeCallbacks越界应移到 data.go 与 replacePrimaryDB 同址) | data/runtime_clients.go:168-171 |
| P-13 | pkg/module、pkg/task、pkg/database/migration互为依赖构成同层契约组单独搬会破坏依赖方向一致性——维持现状 | pkg/* |
## 七、分层 / 职责违规
| # | 问题 | 位置 | 轮次 |
|---|------|------|------|
| L-1 | data 直依赖 integrationdata/payment/payment.go:17 import kra/internal/integration/paymentpaymentRepo 实为"配置读取+适配器编排+ack 组装"的编排层Create/Query/Refund/HandleCallback 四方法无一行 DO↔PO 转换,真正仓储职责全在 paymentOrderRepoTestProvider 是 145 行业务编排本地建单、500ms×3 重试轮询、退款闭环)长在 data 层;还自建第二 paymentOrderRepo 实例(:91绕过 wire 单一构造点 | data/payment/payment.go | 二轮 |
| L-2 | service 层混入业务/存储细节system_init.go:13-26 DSN/驱动连接串与回退规则system_info.go:14-41 直连 gopsutil 采集(每请求阻塞 200msexport_excel.go:63-71 SQL 别名/前缀归一api_token.go:28-42 发币编排与到期规则user.go:36-37,85-96 密码策略编排api.go:60-82 Groups 分组推导version.go:184-221 导入导出全编排 | service/system/* | 二轮 |
| L-3 | biz DO 带 json 标签PaymentResult/PaymentTestResult死标签service 逐字段转 dtoPaymentRequest把指纹编码格式锚死在 DObiz/integration 的 Definition/Field/Option 家族直接充当前端契约dto/integration_config.go:21 内嵌 biz 类型biz 事实上兼任 DTO 提供方) | biz/payment/payment.go:59-204biz/integration | 二轮 |
| L-4 | DO 兼过滤器API.OrderKey/Desc/StrictAll、SystemParameter/ExportTemplate.StartCreatedAt/EndCreatedAt 混入实体 | biz/system/api.go:16-18、parameter.go:16-17、export.go:30-31 | 二轮 |
| L-5 | middleware 硬编码业务语义error_audit.go:70-77 靠中文消息黑名单判断是否审计改文案即改审计行为error_audit.go:25,55-67 硬编码业务路径access_log.go:82-203 支付回调专用逻辑内嵌通用中间件rate_limit.go:33-51 限流策略参数内联且挂在全局链却只匹配两个 public 路由 | server/middleware/* | 二轮 |
| L-6 | biz 契约泄漏存储/表现原语QueryExport 返回 []map[string]anyLogViewer 的文件读取器细节export DO 字面携带 SQL/Join/Table 片段Export 域整体是查询引擎不是领域逻辑,应下沉 dataUserOptions {Label,Value} UI 形状进 bizAuthenticationResult 携带含密码哈希的完整 User | biz/system/* | 二轮 |
| L-7 | data 层纪律Table("字符串") 绕过已有 PO 7 处saveRelations 回写入参 DO 约 10 处OriginSetting 裸 string↔map 转换与 gormkit.JSON 封装并存 | data/system/user.go:58,70,88,231,259 等 | 二轮 |
| L-8 | 编排类文件过重seedSystem 单函数 126 行 10 类职责authority.go 834 行四类职责CRUD/严格权限引擎被 4 文件 15+ 处借用/DataScope 域解析/用户-角色关联,权限引擎应独立 accessGuardBuildVersionBundle 105 行五职责migrations.go 两个通信 surface 迁移互为重复子集 | data/system/seed.go:30-156、authority.go、version.go:76-181、migrations.go:36-173 | 二轮 |
| L-9 | dto 契约问题ID 类型三处分叉int/uint/string 混用迫使 handler 转换AuthorityResponse.DeletedAt 泄漏且破坏全库 json:"-" 约定ErrorRecordMutationRequest 一半指针一半值不自洽DTO 反向依赖 biz 类型 | service/dto/* | 二轮 |
| L-10 | 错误体系双体系errors.go 仅 3 个 kratos 类型错误,其余 stdlib errors.New 散落 13+ 文件,无 reason 码token.go:35-42 另有 6 个分散);错误包装 Error+Unwrap 与 Error+Is 两机制混用PasswordPolicyError 类型定义在 service | biz/system/errors.go 等 | 二轮 |
| L-11 | List 契约三种风格并存(过滤结构体内含分页/位置参数+指针 DO/裸标量 5-6 参data 分页三风格pagination.ApplyRequired/Apply/手写 Limit-Offset手写版 page=0 产生负 offsetposition.go:89、export.go:208-210 无防护) | biz+data 多处 | 二轮 |
| L-12 | 校验双轨制handler 手工 if 校验与 dto binding 标签并存user.go:26-64 手工 6 字段 vs dto.UserRequest 无标签);同类资源一半 binding、一半手工、一半裸奔 | server/handler/* + service/dto/* | 一/三轮 |
## 八、简单实现复杂化
| # | 问题 | 位置 | 轮次 |
|---|------|------|------|
| C-1 | payment Create 过度防御:先拷 9+1 字段逐一回比+Extra 双次 JSON 序列化同一不可变保证指纹层RequestFingerprint+落库后二次比对)已做两道 | biz/payment/payment.go:385-402,898-907,588-590 | 二轮 |
| C-2 | loadUser/loadUsers 双实现(单实体 6 次串行查询 vs 批量实现,可复用省约 45 行) | data/system/user.go:53-97,115-218 | 二轮 |
| C-3 | JWT 签名双重检查validateSigningOptions 后 signToken 再查一遍) | data/system/token.go:34-51 | 二轮 |
| C-4 | `*Data` 方法约 10 处模板式 `if d == nil` 防御(构造归 Wire 管理NewIntegrationRuntime 的 nil→空 Store 回退掩盖错误状态;中间件 nil 防御四处gin.go:28-30 已兜底access/access_log/audit/cors 仍各自检查) | data/data.go:41,72,82,88,97,119,126,373-375middleware/* | 一/二轮 |
| C-5 | public.go captchaConfig 恒真分支与无效首调用 | server/handler/public.go:29-43 | 二轮 |
| C-6 | 媒体上传三重大小防御limitMultipartBody+rejectMediaTooLarge+header.Size 检查,三重中两重冗余) | server/handler/media.go:38-50,226-240 | 二轮 |
| C-7 | emqx.go 恒真 ctx 判断(:561-569,592-600websocket 双层 handler 登记(两层各持四份列表互相重放,且都为空) | integration/mq/emqx.gointegration/websocket | 二轮 |
| C-8 | 单实现接口PaymentLogger仅为包装 *slog.LoggerDictionaryRepo/MediaRepo 组合式子接口无独立消费方 | biz/payment/payment_log.go:10-32biz/system | 二轮 |
| C-9 | dictionary.go Tree 解析结果被丢弃byType 分支不用 id/parseErr | server/handler/dictionary.go:211-213 | 二轮 |
| C-10 | mq 体系接口面积翻倍且恶化(见 2.2mq.Registry 双 API 并存 | pkg/mq/mq.go:66-83emqx.go:539-589 | 一轮(三轮复核恶化) |
## 九、结构性设计(大动作需决策)
| # | 问题 | 位置 | 轮次 |
|---|------|------|------|
| X-1 | router 与 routecatalog 双声明21 个 router 文件纯声明式注册 method+pathroutecatalog 又用一张 195 条 map 声明同一批路由的元数据,靠契约测试强制对齐——改一条路径要同时改两处。表驱动合并为单一声明源可同时消掉对齐测试 | server/router/*routecatalog/catalog.go:41-236 | 一轮 |
| X-2 | 新增一个资源实际要触碰 7 处dto、service、handler、router 资源文件、routes.go、routecatalog、Set/provider | — | 一轮 |
| X-3 | 同一份集成配置三种形状两条通道config.Storage 强类型 ↔ sys_integration_configs JSON 行 ↔ 运行时客户端storage/email 走 config.Storeemail 即时读快照、storage 手动 Replacemq/websocket 走 runtimeconfig 订阅——同一"集成"概念两套配置源两种重载模式 | data/integration_config.go:43-104,157-179data/integration/runtime.go:13-29 | 一轮(三轮细化) |
| X-4 | swagger 运行时文档:约 160 行 map 手拼 Swagger 2.0 JSON+正则加工,全局单例仍在 server 根包 | server/swagger.go:21-159 | 一轮 |
| X-5 | 错误日志热路径做磁盘 IO+go/parser AST 解析(每条 Error 日志触发 os.ReadFile+parser.ParseFile无缓存 | pkg/logging/source.go:71-103zap.go:373-379 | 一轮(三轮复核仍在) |
| X-6 | local 存储两套入口staticfiles 直读 config 本地盘语义 vs integration/storage 的 Reloadable 体系 | server/staticfiles/staticfiles.go:20-47integration/storage/local.go | 一轮 |
| X-7 | gopay.go/gopay_helpers.go 名实相反gopay.go 是窄基座4 个函数,:12-13 注释过时gopay_helpers.go 是杂物间7 类职责混装,渠道专属谓词/状态机应下沉各渠道文件,公共函数 mergeMap 反而散在 alipay.go | integration/payment/* | 二轮 |
| X-8 | vendor.go金额拆分 14 键配置 DSL 疑似投机通用性(无内置默认使用);通用渠道定义 18 字段全 Required=true不用退款的商户也被迫配置退款地址 | integration/payment/vendor.go:170-238biz/integration/integration_config_definition.go:58-77 | 二轮 |
| X-9 | 集成配置双轨制(同 X-3config 热重载双通道fsnotify watchLoop 只 Replace 快照不重建 DB/Redis/Mongo 客户端,全量重载只能手动 POST 触发——行为不透明 | config/runtime.go:263-287data/config_store.go:127 | 三轮 |
| X-10 | payment 域新增一个渠道需改 4 处paymentkit 常量+biz 再导出+adapter 工厂+配置定义)散弹式修改 | paymentkit/provider.go:4-30 等 | 三轮 |
| X-11 | TaskScheduler 的 6 把锁与 dispatch async 参数:每处均有并发正确性注释论证,是真实并发需求的代价——不建议改,仅记录 | worker/task_scheduler.go:24-36,260-283 | 二轮 |
## 审查后认为合理、不建议改动的部分 ## 审查后认为合理、不建议改动的部分
- **modules 与 routecatalog 分离**前者是启动期模块装配wire/种子/迁移),后者是请求期热路径策略查询(有 byMethod 桶等性能优化),消费方零重叠,仅存在 modules→routecatalog 的合理单向依赖。 - **modules 与 routecatalog 分离**:启动期模块装配 vs 请求期热路径策略查询,消费方零重叠,仅合理单向依赖
- **Provider 接口缝模式**(子包不反向 import 根 data 避免成环 + 各子包测试假 Data模式本身正当仅 1-1 所述两处重复需合并。 - **Provider 接口缝模式**(子包不反向 import 根 data 避免成环+测试假 Data模式正当provider.Database 中性接口P1-1 修复)设计合理,唯 system 包内 Provider5 方法)与 DatabaseProvider别名两个近义缝命名易混淆建议注释互指
- **config.StoreYAML 文件)与 runtimeconfig.StoreDB 集成表)职责分离**:不重叠,不建议合并包;仅需评估统一 pub-sub 实现1-9 - **config.StoreYAML 文件)与 runtimeconfig.StoreDB 集成表)职责分离**:正确,仅 pub-sub 同构待决策D-9
- **utils/routepath 与 routecatalog**:互补非重复(前者剥离配置前缀供落库/Casbin 用,后者纯策略匹配)。 - **utils/routepath 与 routecatalog**互补非重复utils 整体纪律良好routepath/uploadpolicy 均无状态多域共用)
- **TaskScheduler 多锁**:每处均有并发正确性注释论证,是真实并发需求的代价。 - **worker→biz 正向依赖+biz 经 TaskRuntime/TaskReloader 接口反向倒置**:任务链路最规范的一段
- **worker→biz 正向依赖 + biz 经 TaskRuntime/TaskReloader 接口反向倒置**:整个任务链路最规范的一段。 - **data 根多文件同包共享 Data 状态与重载锁**:符合 data/README 既定约定
- **三个"registry"实为三种角色**pkg/task=实现、biz/task=接口缝、worker=贡献者):不是重复机制,但命名误导(建议重命名 worker/task_registry.go - **apple_jws.go 的 CheckSignatureFrom+OID 检查**:经 gopay 源码核对是补真实漏洞gopay 不验证叶证书由中间证书签发),必要;仅单一根指纹需运维轮换预案注释
- **data 根 11 个文件同包共享 Data 状态与重载锁**:符合 data/README 既定约定,不建议拆包。 - **capture/auth 等中间件质量**capture 作为唯一请求/响应捕获点、auth singleflight 防取消传染,有据可依
## 处置建议(按优先级)
1. **先修一节修复回归缺陷**R-1 资金安全高危优先)
2. **删二节死代码**(纯减法零风险:三层死方法约 15 组+mq/websocket 零消费者机制+零散死码,估算 800+ 行)
3. **做五节过分拆分合并**(透传壳 usecase 12 个、biz/system 小文件归并、SystemConfigService 四合一、provider/providers 双文件 ×4——零行为变更的文件级减法
4. **执行六节归属移动**(按 P-1~P-8 逐项决策)
5. **消除三节大块重复**D-1/2/3 三大块估算 900+ 行)
6. **收敛四/七/八/九节结构与分层**service 根门面、Backend 三层缝合、L 系列归位、X 系列大动作)
--- ---
## 第二轮深审发现S 系列编号) ## 已修复并经复查确认第三轮逐条验证2026-08-27
### S1 死代码补充(第一轮 P0 之外;第三轮核查:约 15 组仍存在,仅 PersistConfig 属误报已更正) > 以下条目经第三轮 5 路代理逐条核查属实(含编译验证通过),从上方问题清单移除,此处留痕。复查中发现的部分修复残留已回升为一节 R 系列条目。
**biz 层死接口方法/死注入面** ### 第一轮问题P 系列)
- PermissionRepo 3/4 方法死Buttons/SetAuthorityButtons/AuthorityButtonIDs— internal/biz/system/permission.go:6-8
- APITokenRepo.DisableAPIToken — api_token.go:26UserRepo.CreateUser/UpdateUserWithAuthorities — user.go:45,49
- MediaMetadataRepo.FindMediaByHash — media_metadata.go:44MenuRepo.AuthorityMenuIDs — menu.go:61
- SecurityUsecase.ActiveTokenMatches — security.go:243-249EmailUsecase.Alert — email.go:31-48
- PaymentUsecase 注册面全死SetHooks/SetOrderSourceRegistry/SetFulfillmentRegistry/RegisterBusinessModule含两阶段注册+回滚补偿)— biz/payment/payment.go:296-326PayInternal/RefundInternal/AuthorizeRefund 无生产实现service 却作为正式 API 暴露Fulfill
**data 层死实现**与上述接口配套data/system/export.go:430-440、user.go:317-319,474-491、api_token.go:108-114、media.go:67-73、permission.go:113-117、menu.go:283-287 - P0-1pkg/protoutil 整包删除
- P0-2paymentkit WechatV2Sign 死实现删除
- P0-3Data 的 MongoClient/NamedDatabases/NamedRedisClients 三死方法删除
- P0-4config Bootstrap 别名删除
- P0-5静态任务方法注册链删除重建为活的 TimedTasks 单源链路,含防回归测试)
- P0-6TaskScheduler.Schedule(task) 删除(生产与测试均改用 ScheduleID
- P1-1中性 internal/data/provider.Database 接口抽取task/security 两处仅剩一行别名)
- P1-2任务种子单源化migrations fallback 删除,只来自 module catalog
- P1-3text/firstAny 收敛到 paymentkit.Text/FirstText残留 micro-shim 见 2.3
- P1-4menu handler 校验提取 validateMenuRequest
- P1-5surface.APIsForPrefix 提取(含契约测试)
- P1-6persistConfig Locked 变体删除,锁逻辑单点化
- P1-7NewData/reloadConfig 均改用 rollback 收集器commit/run 语义核对无误)
- P1-10websocket snapshotHandlers 泛型收敛
- P4-4AGENTS.md 更新为真实栈Gin+手写 DTO+Wire
**service 层死方法**MenuService.Listmenu.go:14-20handler 实际用 Tree连带 biz MenuUsecase.List 也死、RecordLogin/RecordDataAccessaudit.go:56-58,91-93后者整链含 biz 接口+data 实现全死、IsTokenDisabledapi_token.go:60-62、security_session.go 14 方法中 8 个死(:17-67、AuditRecorder.CreateErrorRequest+recordedErrorDomainaudit_error.go:17-31 ### 第二轮 S0 正确性/安全缺陷17 条全部修复,含回归验证
**integration 层零消费者基础设施** - S0-1vendor 通用渠道退款业务状态解析+失败回归测试(残留缺口见 R-1
- mq legacy 发布/订阅 API 全链零生产调用Publish/Subscribe/Unsubscribe 及 To 变体、Register/Unregister、订阅簿记/dispatcher/reconcile 约 350 行空转)— integration/mq/emqx.go:358-630连带 cmd/main.go:69 `_ mq.Client` 幻影参数与 integration/provider.go:28,29 两条死 wire 绑定(外加 :31 的 platformws.Hub 死绑定) - S0-2登录日志独立 LoginLogFilter+*bool 三态筛选status=false 正确过滤)
- websocketHub 接口零消费者pkg/websocket/melody.go:28-40integration 层 On* 四注册方法零调用server.go:326-373双层 handler 登记机制两层都永远为空server.go:28-31,169-180 vs melody.go:65-118 - S0-3公告/媒体导入 UserID 从 claims 注入DTO 移除可伪造字段
- s3 多 provider endpoint 五个死分支(唯一调用点只传 "minio")— storage/s3_storage.go:29-41 - S0-4客户端时间戳改为服务端生成ErrorRecord/Menu/Parameter/Export 均覆盖)
- namedClient/Client() 整型死代码 — emqx.go:632-650 - S0-5审计中间件 x-user-id 头回退删除+CORS 白名单收紧(含防回归测试)
- 零散wechat_v2.go:584 `stringOr`、paypal.go:651 `normalizePayPalOrderState`、paypal.go:388-391 `paypalOrderTradeNo`、result.go:98,148-155 `nestedString`/`amountFromDecimalField`shim 连调用者都没有、middleware/capture.go:72-74 `isBootstrapPath` - S0-6export 统一安全查询构建器(标识符/Join/条件/排序校验+禁任意 SQLbiz/data 双保险BETWEEN 值参数化)
- S0-7ListAuthorities 委托统一权限入口
- S0-8版本导入 JSON/Save 阶段错误返回
- S0-9用户服务失败关闭安全配置读取错误即返回
- S0-10SecurityConfig 未就绪只返回 nil+error
- S0-11限流文案加入预期客户端失败白名单闭环匹配
- S0-12支付回调 service 错误加入 Gin error chain读体分支残留见 R-7
- S0-13Excel 文本保真("007" 保持 string含测试副作用见 R-2
- S0-14Apple JWS 固定 Apple Root CA G3 真实指纹(经官方根证书清单核实)+完整链校验(叶←中←根+CA 约束+OID+ES256+签名时刻验证
- S0-15SetUserAuthorities 空列表改 ErrAuthoritiesRequiredBadRequest
- S0-16OriginSetting JSON 解析错误传播(单条/批量/关联加载)
- S0-17cache.Incr Redis 原子 Lua 补 TTL仅无 TTL 的 key 补,语义正确;内存实现同步修复)
**仅测试调用(生产死代码)**decryptWechatV3wechat_v3.go:600-605、alipaySignContentalipay.go:572-585、validatePaymentConfigdata/payment/payment.go:551-553 ### 第二轮 S4 两条
**dto 死类型/死字段**LoginLogRequestdto/system.go:68-75、DataAccessRecordRequestdto/audit.go:21-30、GetAuthorityButtonsRequest.Selected、MenuResponse.Authorities 恒 nullbiz 无此字段、DynamicMenuResponse.MenuButtons 恒 nil、SysBaseMenuID 输入被静默丢弃dto/menu.go:21,28、version 导出结构体大量零值噪声字段ID:0/CreatedAt 零时间/authoritys:nullversion.go:23-94 - export QueryExport 双重 JSON 解析 → 单次严格列解析
- saveRelations 三布尔参数 → 单 replace 参数
### S2 重复模式补充(大块可消除,估算合计 1000+ 行)
- **data/system List 样板 13 处同构**(构建 db→逐字段翻译 filter→Count→分页→Find→循环 toBiz可抽泛型 helper 消 200+ 行 — user.go:281-315、api.go:119-181、data_access_log.go:32-55、operation_log.go:39-68、error_record.go:83-109 等 13 处
- **payment 渠道适配器家族重复**(合计约 500 行):下单方式归一化骨架 9 份Replacer 归一化行逐字出现 9 次);退款身份校验 4 份同构;状态归一化 switch 10 份(可收敛为 `normalizeState(state, successWords, failedWords)` + 词表);金额拆分守恒 5 份 + biz 层再校验第 6 份SDK 客户端构造 10 份同构firstNonEmpty 三胞胎alipay.go:475/qq.go:146/paypal.go:707mustMarshalAlipayPayload ≡ mustJSON
- **storage provider 家族重复**(约 200 行key/unkey/file 三件套 5 份逐行相同aliyun:35-48/aws:63-76/huawei:31-44/s3:61-74/tencent:45-58DeletePrefix 分页循环 5 份(可提 `deletePrefixViaList`Compose 一行委托 7 份limit 守卫 7 份;构造尾部样板 5 份
- **handler 四段式样板约 70 处**ShouldBindJSON→Fail→service→Write`bindJSON`+`respond` 两个 helper 可消一半
- **biz 接口嵌入透传 12 处 usecase**API/APIRepo/Token/LogViewer/Audit/AuditRecorder/Authority/Dictionary/Export/Media/Parameter/Permission/Position/Version与同包 9 个私有字段风格并存
- **middleware**请求体读取三处access_log.go:56-74 / audit.go:49-67 fallback / handler/media.go:17-21同一请求体三层 MaxBytesReader脱敏/截断三处且分散capture.go:41-68 / audit.go:118-136 / redact 词表在 redact.go 但函数散在 access_log.go双重脱敏双重截断audit.go:47-48,93 对已 mask 已截断的正文再处理一遍)
- mq/websocket 两包各写一套 map 解码 helper 且逐字符相同emqx.go:226-260 vs server.go:189-240TestConfig 探测骨架三处同构emqx.go:92-133/server.go:65-126/connectivity.go
- authority 树构建算法两份biz authority.go:48-78 vs menu.go:80-99CreateAuthority/CopyAuthority 前 8 行校验逐字重复data authority.go:133-151,211-245
- serviceauthorityResponse 与 convertAuthority 逐字重复authority.go:30-36 vs user_conversion.go:8-14"单条 DTO helper + for-append"样板 9 处;"Request 包装 + Filter 包装 + 裸方法"三重入口家族audit/parameter/export/dictionary/mediauser 空对象兜底三连
- data/paymentcallbackFields/first 整函数复制payment.go:507-540 vs result.go:14-56values() 与 testRow() 近重复;渠道"免 notify_url 方法"同义词表在 data 层重抄一份payment.go:390-426与各适配器 createMethod 表双份维护)
- gorm.DeletedAt→*time.Time 转换 4 处逐字重复user.go:99-104、menu.go:17-21,241-245,250-255
- version 阶段→消息映射两份handler version.go:107-121 vs 158-167engine.Routes()→dto 转换两份api.go:161-167 vs public.go:135-139
- defaults 合并逻辑三层三份service/integration:86-98 / biz/integration:215-224 / data/integration/migrations.go:69-75
- media 分片根目录逻辑两份biz media.go:126-132 vs media_upload.go:61-69
- media_upload 三处复制会话校验样板biz media_upload.go:120-129,176-184,244-250顺带吞掉 ErrUploadSessionNotFound 可判定性)
### S3 分层/归属违规补充
- **data 直依赖 integration**data/payment/payment.go:17 import `kra/internal/integration/payment`TestProvider 是 145 行业务编排本地建单、500ms×3 重试轮询、退款闭环)长在 data 层;还自建第二 paymentOrderRepo 实例绕过 wire 单一构造点
- **service 层混入业务/存储细节**system_init.go:13-26 DSN/驱动连接串与回退规则system_info.go:14-41 直连 gopsutil 采集(每请求阻塞 200msexport_excel.go:63-71 SQL 别名/前缀归一api_token.go:28-42 发币编排与到期规则user.go:36-37,85-96 密码策略编排api.go:60-82 Groups 分组推导version.go:184-221 导入导出全编排
- **biz DO 带 json 标签**PaymentResult/PaymentTestResult死标签service 逐字段转 dtoPaymentRequest把指纹编码格式锚死在 DObiz/integration 的 Definition/Field/Option 家族直接充当前端契约dto/integration_config.go:21 内嵌 biz 类型biz 事实上兼任 DTO 提供方)
- **DO 兼过滤器**API.OrderKey/Desc/StrictAll、SystemParameter/ExportTemplate.StartCreatedAt/EndCreatedAt 混入实体LoginLog 已改为独立 Filter
- **middleware 硬编码业务语义**error_audit.go:70-77 靠中文消息黑名单判断是否审计改文案即改审计行为error_audit.go:25,55-67 硬编码业务路径access_log.go:82-203 支付回调专用逻辑内嵌通用中间件rate_limit.go:33-51 限流策略参数内联A8 限流挂在全局链却只匹配两个 public 路由
- **biz 契约泄漏存储/表现原语**QueryExport 返回 `[]map[string]any`LogViewer 的文件读取器细节NextCursor/LimitedByBytesexport DO 字面携带 SQL/Join/Table 片段Export 域整体是查询引擎不是领域逻辑,应下沉 dataUserOptions `{Label,Value}` UI 形状进 bizAuthenticationResult 携带含密码哈希的完整 User
- **data 层纪律**:转换函数命名四种风格违反 new<X>/toBiz 契约FromPO×16/ToPO×4/ToBiz×2/new×2PO 分布无规则models.go 集中 6 个 + 散落 30+models.go:98-100 还混 repo 声明Table("字符串") 绕过已有 PO 7 处user.go:58,70,88,231,259、announcement.go:100、security.go:92saveRelations 回写入参 DO 约 10 处audit.go 名不副实(只有构造器,实现在 5 个文件runtime.go 拼盘settings + tokenIssuer 无关联)
- **编排类文件过重**seedSystem 单函数 126 行 10 类职责seed.go:30-156authority.go 834 行四类职责CRUD/严格权限引擎被 4 个文件 15+ 处借用/DataScope 域解析/用户-角色关联,权限引擎应独立 accessGuardBuildVersionBundle 105 行五职责version.go:76-181migrations.go 两个通信 surface 迁移互为重复子集(:36-130 vs :132-173
- **dto 契约问题**ID 类型三处分叉int/uint/string 混用,迫使 handler 做转换AuthorityResponse.DeletedAt 泄漏且破坏全库 `json:"-"` 约定dto/authority.go:34ErrorRecordMutationRequest 一半指针一半值不自洽DTO 反向依赖 biz 类型dto/integration_config.go:21
- **错误体系**错误定义双体系errors.go 仅 3 个 kratos 类型错误,其余 stdlib errors.New 散落 13+ 文件,无 reason 码);错误包装 Error+Unwrap 与 Error+Is 两机制混用PasswordPolicyError 类型定义在 servicesecurity.go:11-19
- **List 契约三种风格并存**(过滤结构体内含分页 / 位置参数+指针 DO / 裸标量 5-6 参)
- **data 分页三风格**pagination.ApplyRequired/Apply/手写 Limit-Offset手写版 page=0 产生负 offsetposition.go:89、export.go:208-210 无防护media.go:112-115 有)
### S4 简单实现复杂化补充(遗留)
- payment Create 过度防御:先拷 9+1 字段再逐一回比 + Extra 双次 JSON 序列化同一不可变保证指纹层RequestFingerprint + 落库后二次指纹比对)已做两道 — biz/payment/payment.go:385-402,898-907,588-590
- loadUser/loadUsers 双实现(单实体 6 次串行查询 vs 批量实现,可复用)— data/system/user.go:53-97,115-218
- JWT 签名双重检查validateSigningOptions 后 signToken 再查一遍)— data/system/token.go:34-51
- 中间件 nil 防御四处gin.go:28-30 已兜底access.go:33/access_log.go:36/audit.go:27/cors.go:22-25 仍各自检查)
- public.go captchaConfig 恒真分支与无效首调用public.go:29-43
- 媒体上传三重大小防御limitMultipartBody + rejectMediaTooLarge + header.Size 检查)— handler/media.go:38-50,226-240
- emqx.go 恒真 ctx 判断(:561-569,592-600
- PaymentLogger 单实现接口(仅为包装 *slog.Logger— biz/payment/payment_log.go:10-32
- dictionary.go Tree 解析结果被丢弃handler dictionary.go:211-213byType 分支不用 id/parseErr
- DictionaryRepo/MediaRepo 组合式子接口无独立消费方biz dictionary.go:56-59、media.go:19-22
### 第二轮结构性发现(遗留)
- **mq 与 websocket 是"零消费者基础设施"**:大量生命周期/重放/簿记机制空转,要么接入首个真实业务消费者,要么裁掉 legacy 半区保留最小面TestConfig 探测 + Enabled/Path/HandleRequest
- **payment 域 data/integration 边界倒置**paymentRepo 实为"配置读取+适配器编排+ack 组装"的编排层,仅 4 个纯转发方法符合 repo 形态;渠道知识(同义词表)在 data 与 integration 双份维护必然漂移
- **gopay.go/gopay_helpers.go 名实相反**gopay.go 是窄基座4 个函数gopay_helpers.go 是杂物间7 类职责混装,渠道专属谓词/状态机应下沉各渠道文件,公共函数 mergeMap 反而散在 alipay.go
- **vendor.go**vendorSupperPay 是死枚举26,38 定义注册switch 无 case金额拆分 14 键配置 DSL 疑似投机通用性(无内置默认使用);通用渠道定义 18 字段全 Required=true
- **gva/ 目录是遗留参考库**(独立 module 不参与 kra 编译pkg/logging 为其保留文件名特判zap.go:342
---
## 第三轮审查发现T 系列编号2026-08-27
### T0 修复回归缺陷与残留S0 修复核查时发现,优先处理)
| # | 问题 | 位置 |
|---|------|------|
| T0-1 | **vendor 退款静默受理残留(资金安全,高危)**S0-1 修复覆盖了"FAIL 状态字段"场景,但 create/refund 响应 HTTP 200 且 body 非 JSON、或 JSON 无可识别状态字段时仍默认 `created`biz `validatePaymentRefundResult` 接受 created → 真实被渠道拒绝但响应无状态字段的退款会被永久记为已受理。建议refund 端点响应无状态字段时报错或至少 pending | internal/integration/payment/vendor.go:135-163biz/payment/payment.go:1020-1021,837-855 |
| T0-2 | Excel `[]byte` 全转文本副作用MySQL 数值列也会变文本单元格,大面积"数字以文本存储"警告(原值保真达成,展示体验回退);可结合模板列类型区分处理 | internal/service/system/export_excel.go:85-86 |
| T0-3 | ErrAuthoritiesRequired 错误透传缺失biz 返回具体错误后 handler 只回"修改失败",用户看不到"至少一个角色"data 层 setUserAuthorities 还残留一处重复中文防御错误(双轨) | internal/server/handler/user.go:208-212internal/data/system/user.go:563-565 |
| T0-4 | 版本导入非原子残留:落库成功但留痕 CreateVersion 失败时返回错误,用户误判"导入失败"(幂等查重使重试可控) | internal/service/system/version.go:256-270 |
| T0-5 | 任务元数据双源漂移已发生:种子描述("**定时**清理数据库过期日志…")与注册方法描述("清理数据库过期日志…")不一致——两处维护必然继续漂移;建议 worker 注册时复用 catalog TimedTask 元数据 | internal/modules/task/definition.go:14-15 vs internal/worker/task_registry.go:31,45 |
| T0-6 | export SQL/ImportSQL 摆设字段dto 保留但 ValidateExportTemplate 拒绝非空,只能提交空值且响应回显空值 | internal/service/dto/export.go:26-27internal/biz/system/export.go:72-74 |
| T0-7 | payment 回调读体失败分支未入 Gin 错误链S0-12 修复只覆盖 service 调用错误) | internal/server/handler/payment.go:149-153 |
| T0-8 | LoginLogFilter 收敛为仅 Username/Status 两字段:若前端需按 IP/时间筛选登录日志则能力缺失(设计取舍需确认) | internal/biz/system/audit.go:42-45 |
| T0-9 | 任务种子与注册方法的"必经链路"提示PaymentUsecase 注册面SetHooks 等 4 个方法)零调用时,生产装配下支付主链路 Create/Refund/Fulfill 必然在 preparePaymentRequest 报"支付业务订单来源未注册"——模板未完成态,建议 Wire/cmd 层提供默认注册或 fail-fast 提示 | internal/biz/payment/payment.go:296-326,407-410 |
### T1 过分拆分清单(用户重点维度,量化)
**根因模式三条**:①零逻辑 usecase 壳wire 强制每域一个构造器放大);②"每资源 N 文件"机械切分dto+biz+service+handler+router 各一个);③为 import 美观引入的中间缝合包/门面。
**A. biz/system38 文件 3430 行,其中 17 个非测试文件 <60 合计约 575 保守可归并 8-10 个文件**
| 文件 | 行数 | 内容 | 合并目标 |
|---|---|---|---|
| errors.go | 14 | 4 个错误变量token.go:35-42 另有 6 个,同类分散) | 并入 user.go 或统一 errors |
| cache.go | 15 | Cache 接口 4 方法 | 并入 security.go主消费者 |
| maintenance.go | 19 | Repo 接口+纯透传壳 | 并入 user.go 或保留worker 消费) |
| actor.go | 19 | ctx 携带 helper | 并入 authority.go唯一消费者 |
| access_control.go | 20 | 透传壳 2 方法 | 并入 authority.go/api.go |
| storage.go | 26 | FileStorage 接口 | 并入 media.go主消费者 |
| data_scope.go | 27 | DataScope 类型+ctx helper | 并入 authority.go |
| upload_session.go | 38 | DO+Repo 13 方法无 usecase | 并入 media_upload.go同域 |
| parameter.go | 33 | DO+Repo+零方法壳 | 壳删后 28 行 |
| settings.go | 43 | 3 设置类型+接口 | 可保留wire 5 处消费) |
| department.go | 46 | DO+Repo+改名壳 | 壳删后 32 行 |
| position.go | 48 | DO+Repo | 与 department.go 合并为 organization.go |
| token.go | 48 | AuthClaims+TokenIssuer | 并入 authentication.go唯一 biz 消费) |
| media_metadata.go | 53 | DO+Repo | 并入 media.gomedia 域 4 文件最典型同域碎片) |
| email.go / api_token.go / version.go | 48/55/57 | — | 保留(有逻辑)或去壳 |
**B. 纯透传壳 usecase 12 个**(整个 struct 无自有逻辑/纯改名转发service 可直依赖 biz repo 接口——repo 接口仍在 biz分层契约不破wire 链物证 wire_gen.go:88-91 permission 全程零逻辑):
ParameterUsecase(parameter.go:29)、PermissionUsecase(permission.go:14)、VersionUsecase(version.go:55)、AnnouncementUsecase(announcement.go:397 方法全一行透传)、MaintenanceUsecase(maintenance.go:11)、AccessControlUsecase(access_control.go:5)、DepartmentUsecase(department.go:342 改名)、AuthorityUsecase(authority.go:42仅 Tree 有逻辑)、TaskUsecase(task.go:76)、MenuUsecase(menu.go:7210 处透传)、UserUsecase(user.go:5913 处透传)、SystemConfigUsecase(system_init.go:507 处透传)。
对照组有真实逻辑应保留Authentication/Security/Media/Email/IntegrationConfig/Payment/TaskApplication。
**C. service/system 碎片**
- SystemConfigService 一型拆四文件system.go(19)+system_config.go(26)+system_init.go(38)+system_info.go(42)=125 行 4 文件
- security_session.go:17-68SecurityService 14 方法全部一行透传(零 DTO 工作)
- audit.go 与 audit_error.go 同属 AuditService/AuditRecorder 可合并audit_log_file.go 是独立 LogViewerService保留
- email.go(16)/permission.go(24)/access_control.go(28仅 5 行逻辑) 近纯透传小文件
**D. router 碎片**22 文件 464 行,平均 21 行/文件(最小 email.go 12 行routes.go:18-43 手工 21 连调——纯注册碎片无内聚(与 4-1 表驱动合并一并解决)。
**E. 单符号包/微文件**
- internal/modules/surface整包只有一个 10 行函数surface.go:10-192 个调用方
- internal/data/provider整包只有一个 7 行 2 方法接口provider.go:5-8——中性缝可辩护建议与 provider.go 别名使用方注释互指
- provider.go+providers.go 双小文件模式 ×4 子包integration 12+5 行、payment 8+5、task 7+5、system 17+29→ 8 文件并 4
- data/system/bootstrap.go 27 行仅 seed.go 使用可并入worker/worker.go 7 行、initialize/provider.go 5 行、pkg/task/provider.go 3 行、biz/payment/provider.go 8 行均为纯 wire-set 微文件
- data_scope_record.go 整文件 1 行别名(同 3-9
**F. 巨微并存两极**
- biz/payment/payment.go 单文件 1150 行usecase+常量再导出+5 validator+指纹工具vs 同域 payment_log.go 32 行/provider.go 8 行微文件
- dtoauthentication.go 8 行/email.go 7 行超小文件 vs settings.go 170 行横跨四域(同 4-7
### T2 包归属移动建议(从 → 到)
| # | 从 | 到 | 动作 | 影响 |
|---|---|---|---|---|
| 1 | pkg/httpx | internal/server/httpx | 整包内移(消费者 100% 在 internal/server 7 文件;中文文案+x-token 是本项目契约logging/source.go:59 已预留该路径 marker | 7 文件 |
| 2 | pkg/logging | internal/logging | 整包内移source.go:47-69 硬编码本仓库 internal 路径zap.go:366-382 中文文案;模块路由硬编码服务日志查看器语义) | 约 5 文件 |
| 3 | pkg/module | internal/modules | 契约内移Menu/API/Surface/TimedTask 是本项目模块系统契约import gin15 消费者全在本仓库) | 15 文件 |
| 4 | pkg/paymentkit 渠道常量provider.go | internal/biz/payment 本体 | 常量归位并删 biz/payment/payment.go:20-43 的 17+2 个别名转发层;目录更名 paymentutil 对齐包名通用工具signing/json/amount/xml可留 pkg 或并入 internal/utils | 约 8 文件 |
| 5 | pkg/mq + pkg/websocket(Hub) | 收缩或合并进 internal/integration/mq | 全链零业务消费者(详见 T3保留 TestConfig 探测+基础驱动,删 Registry/Client()/namedClient/legacy API/Hub/ApplySubscriptions | 约 7 文件 |
| 6 | integration/mq emqx.go:226-260 与 integration/websocket server.go:189-240 的重复 JSON map helper | internal/utils/jsonvalue | 上收去重configText≡text、configBool≡boolValue 逐字符相同) | 2-3 文件 |
| 7 | storageaws-sdk-v2 栈与 minio-go 栈双 S3 实现并存 | 统一 S3 兼容单栈(可选) | qiniu/aliyun/huawei/tencent 原生 SDK 均有 S3 兼容端点,可收敛删 4 实现+s3 死分支 | 5-6 文件 |
| 8 | handler/query.go:13-61Gin 工具、middleware/request.go:67-102纯函数、handler/announcement.go parseTime被 export.go 跨域借用) | pkg 或 internal/utils 候选 | 通用无状态逻辑上收 | 3 文件 |
依赖方向合规确认第三轮验证pkg 无 import internal仅 zap_test.go:131 字符串字面量integration 无 import data/serviceservice→biz→data 无反向。
### T3 死代码回归与新增S1 现状核查)
- **S1 清单约 15 组死方法仍存在**biz 接口+data 实现+service 包装三层残留已更正误报service 层 PersistConfig 实为活代码
- mq 零消费者机制未清理且**规模扩大**emqx.go 约 710 行 + mq.go 106 行 + subscription.go 55 行声明式订阅全套无注册者legacy API 转译层又加了一层1-11 恶化)
- websocket Hub 死绑定、s3 五个不可达 endpoint 分支local.go:39-48 只让 minio 进 newS3Storage、namedClient/Client()、`_ mq.Client` 幻影参数main.go:65、isBootstrapPath 死函数——全部未清理
- 新增死代码wechat_v2.go:47 私有 wechatV2Sign 变为仅测试调用可移测试文件pkg/task RegisterAll 仅测试调用;**NewGinEngine 生产死代码**gin.go:23-25wire 用 NewGinEngineWithRuntimeTaskScheduler.Trigger(task) 可未导出(仅 TriggerID 内部用)
- P1-3 修复残留result.go:58-64 与 payment_helpers.go:5-11 两包仍保留同名本地包装转发 paymentutilmicro-shim 未拆)
### 已修复确认清单(第三轮验证后从本文档删除,留痕)
- P0 全部 6 条protoutil 整包删除WechatV2Sign 死实现删除Data 三死方法删除Bootstrap 别名删除;静态任务注册链删除(重建为活的 TimedTasks 单源链路Schedule(task) 删除
- P1-1/2/4/5/6/7/10provider.Database 中性接口task/security 两处仅剩一行别名种子单源化含防回归测试validateMenuRequestsurface.APIsForPrefixpersistConfig Locked 变体删除NewData/reloadConfig 均用 rollback 收集器websocket snapshotHandlers 泛型收敛
- P1-3paymentkit.Text/FirstText 落地(残留 micro-shim 见 T3
- P4-4AGENTS.md 已更新为真实栈
- S0 全部 17 条含回归验证登录日志三态过滤、claims 注入、时间戳服务端生成、x-user-id 删除+CORS 收紧含防回归测试、export 安全查询构建器双保险、ListAuthorities 委托统一入口、版本错误返回、失败关闭、SecurityConfig nil+error、限流白名单闭环、回调错误入链、Excel 文本保真、Apple JWS 固定 Root CA G3 真实指纹(经官方根证书清单核实)+完整链校验+签名时刻验证、ErrAuthoritiesRequired、OriginSetting 错误传播、cache Lua 原子补 TTL语义正确
- S4 两条QueryExport 单次严格解析saveRelations 单 replace 参数
## 处置建议总览(三轮合并,按优先级)
1. **先修 T0 修复回归缺陷**T0-1 资金安全高危优先)
2. **删 S1+T3 死代码**纯减法零风险biz/data/service 三层死方法约 15 组 + mq/websocket 零消费者机制 + 微死码,估算 800+ 行)
3. **T1 过分拆分合并**(透传壳 usecase 12 个、biz/system 小文件归并、SystemConfigService 四合一、provider/providers 双文件 ×4——零行为变更的文件级减法
4. **T2 归属移动**httpx/logging/module/paymentkit 内移 + jsonvalue 上收,按表逐项决策)
5. **S2 重复消除三大块**data/system List 泛型、payment 渠道骨架、storage provider 基座,估算 900+ 行)
6. **P2/P4 结构收敛**service 根门面、Backend 三层缝合、router+routecatalog 表驱动合并)