feat:CISD配置初始化

This commit is contained in:
waner
2026-03-11 14:23:11 +08:00
parent 1c254aaba9
commit d02c6530e8
58 changed files with 10699 additions and 1281 deletions
@@ -0,0 +1,70 @@
# CISD 标准版初始化支持方式设计
## 背景
当前 TMS 将标准版初始化统一抽象为 `mqType=RABBITMQ|TLQ`。这与实际部署介质不完全一致:
- `ENTERPRISE` 支持 `RABBITMQ` 和 `TLQ` 两种互斥模式。
- `INDIRECT` 支持 `仅 RabbitMQ` 和 `RabbitMQ + TLQ` 两种模式。
- `INDIRECT` 的 `RabbitMQ + TLQ` 并不是纯 `TLQ`,仍需执行 RabbitMQ 用户、队列和应用配置。
## 目标
在不破坏现有接口字段名的前提下,修正标准版初始化参数校验、步骤编排和执行条件,使其与部署介质和脚本行为一致。
## 约束
- 保留前端请求字段 `mq.mqType`,避免接口字段名变更带来的联调成本。
- 仅修改 `modules/init` 范围内代码和 `docs/openapi/cisd-init` 文档。
- 不调整出厂前预装边界;本次仍只覆盖初始化阶段。
## 方案选择
### 方案 A:重命名字段为 `supportMode`
优点:语义最准确。
缺点:破坏现有接口,前后端和历史任务数据都要联动修改。
### 方案 B:保留 `mqType` 字段名,按产品解释枚举值
优点:改动最小,能直接修正行为。
缺点:字段名与实际语义存在轻微偏差,需要通过文档解释。
### 方案 C:继续保留当前模型,仅靠执行器特殊判断
优点:表面改动更少。
缺点:校验、预检、步骤预览、OpenAPI 全部失真,后续维护成本更高。
## 采用方案
采用方案 B。
## 调整后的 `mqType` 语义
- `ENTERPRISE`: `RABBITMQ` | `TLQ`
- `INDIRECT`: `RABBITMQ` | `RABBITMQ_TLQ`
- `DIRECT`: `RABBITMQ_TLQ` | `RABBITMQ_CFMQ`
## 标准版步骤编排
### ENTERPRISE + RABBITMQ
`RENDER_CONFIG -> FILE_PREPARE -> SET_RABBITMQ -> MQ_USER_APPLY -> MQ_QUEUE_APPLY -> DB_INIT -> DEPLOY_RECEIVER -> APP_MQ_CREDENTIALS_APPLY -> VERIFY`
### ENTERPRISE + TLQ
`RENDER_CONFIG -> FILE_PREPARE -> SET_TLQ -> TLQ_CONF_APPLY -> DB_INIT -> DEPLOY_RECEIVER -> VERIFY`
### INDIRECT + RABBITMQ
`RENDER_CONFIG -> FILE_PREPARE -> SET_RABBITMQ -> MQ_USER_APPLY -> MQ_QUEUE_APPLY -> DB_INIT -> DEPLOY_RECEIVER -> APP_MQ_CREDENTIALS_APPLY -> VERIFY`
### INDIRECT + RABBITMQ_TLQ
`RENDER_CONFIG -> FILE_PREPARE -> SET_TLQ -> TLQ_CONF_APPLY -> MQ_USER_APPLY -> MQ_QUEUE_APPLY -> DB_INIT -> DEPLOY_RECEIVER -> APP_MQ_CREDENTIALS_APPLY -> VERIFY`
## 脚本映射
- `SET_RABBITMQ` -> `cpackage/toolsh/setfraq.sh`
- `SET_TLQ` -> `cpackage/toolsh/setftq.sh`
- `TLQ_CONF_APPLY` -> `cpackage/toolsh/settlq.sh`
- `DB_INIT` -> `cpackage/toolsh/setsql.sh`
- `DEPLOY_RECEIVER` -> `cpackage/toolsh/setsptp.sh`
- `MQ_USER_APPLY` -> 标准版 `setuprabq.sh` staging 执行
- `MQ_QUEUE_APPLY` -> 标准版 `addrabq_R_01.sh` / `addrabq_R_02.sh` staging 执行
## 执行条件
- `ENTERPRISE + TLQ` 跳过 RabbitMQ 用户、队列和应用账号写回。
- `INDIRECT + RABBITMQ_TLQ` 保留 RabbitMQ 用户、队列和应用账号写回。
- `FILE_PREPARE` 在 `TLQ` 或 `RABBITMQ_TLQ` 模式下均需准备 TLQ license。
## 测试重点
- `ENTERPRISE + TLQ` 预检通过且步骤中包含 `TLQ_CONF_APPLY`,不包含 RabbitMQ 相关步骤。
- `INDIRECT + RABBITMQ_TLQ` 预检通过且步骤中同时包含 `TLQ_CONF_APPLY` 与 RabbitMQ 相关步骤。
- `INDIRECT + TLQ` 作为非法值被拒绝。
- `ENTERPRISE + RABBITMQ_TLQ` 作为非法值被拒绝。
- `APP_MQ_CREDENTIALS_APPLY` 在 `ENTERPRISE + TLQ` 下跳过,在 `INDIRECT + RABBITMQ_TLQ` 下执行。
@@ -0,0 +1,121 @@
# CISD Standard Init Support Mode Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 修正标准版 CISD 初始化中 `ENTERPRISE` 和 `INDIRECT` 的支持方式建模、步骤编排和执行条件。
**Architecture:** 保留 `mqType` 字段名,但将其解释为按产品区分的支持方式枚举;服务层负责校验和步骤编排,执行器负责按产品与模式判定脚本是否实际执行或跳过。
**Tech Stack:** Java 17, Spring Boot 3, JUnit 5, OpenAPI YAML/JSON
---
### Task 1: 固化设计与枚举语义
**Files:**
- Create: `docs/plans/2026-03-06-cisd-standard-init-support-mode-design.md`
- Create: `docs/plans/2026-03-06-cisd-standard-init-support-mode-plan.md`
**Step 1: 保存设计文档**
保存版本差异、步骤编排和脚本映射。
**Step 2: 保存实施计划**
记录测试先行的修改顺序。
### Task 2: 先补服务层失败测试
**Files:**
- Modify: `src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
**Step 1: 写 ENTERPRISE TLQ 的预检和步骤测试**
断言 `TLQ_CONF_APPLY` 存在,`MQ_USER_APPLY/MQ_QUEUE_APPLY/APP_MQ_CREDENTIALS_APPLY` 不存在。
**Step 2: 写 INDIRECT RABBITMQ_TLQ 的预检和步骤测试**
断言 `TLQ_CONF_APPLY`、`MQ_USER_APPLY`、`MQ_QUEUE_APPLY`、`APP_MQ_CREDENTIALS_APPLY` 同时存在。
**Step 3: 写非法组合测试**
覆盖 `INDIRECT + TLQ`、`ENTERPRISE + RABBITMQ_TLQ` 被拒绝。
**Step 4: 运行定向测试,确认红灯**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: 至少新增用例失败。
### Task 3: 实现服务层校验和编排
**Files:**
- Modify: `src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Modify: `src/main/resources/initplan/step-command-profiles.json`
**Step 1: 调整标准版允许枚举**
按 `productType` 区分 `ENTERPRISE` 与 `INDIRECT`。
**Step 2: 调整标准版 license 校验**
`ENTERPRISE + TLQ` 与 `INDIRECT + RABBITMQ_TLQ` 都要求 `tlqLicenseFileId`。
**Step 3: 新增 `TLQ_CONF_APPLY` 编排**
更新 `defaultSteps` 和命令模板。
**Step 4: 运行服务层测试,确认绿灯**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: PASS
### Task 4: 先补执行器失败测试
**Files:**
- Modify: `src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: 写 ENTERPRISE TLQ 下 RabbitMQ 应用配置应跳过的测试**
**Step 2: 写 INDIRECT RABBITMQ_TLQ 下 RabbitMQ 用户步骤应执行的测试**
**Step 3: 写 `TLQ_CONF_APPLY` 命令解析或任务步骤断言测试**
**Step 4: 运行定向测试,确认红灯**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest test`
Expected: 至少新增用例失败。
### Task 5: 实现执行器条件修正
**Files:**
- Modify: `src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Modify: `src/main/java/com/cisd/tms/modules/init/config/InitCommandProfileService.java`(如需补充注释/兼容逻辑)
**Step 1: 抽取标准版 RabbitMQ 是否启用的判断**
- `ENTERPRISE`: 仅 `RABBITMQ`
- `INDIRECT`: `RABBITMQ` 和 `RABBITMQ_TLQ`
**Step 2: 修正 `MQ_USER_APPLY` / `MQ_QUEUE_APPLY` 条件**
**Step 3: 修正 `APP_MQ_CREDENTIALS_APPLY` 条件**
**Step 4: 运行执行器测试,确认绿灯**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest test`
Expected: PASS
### Task 6: 同步 OpenAPI 文档
**Files:**
- Modify: `docs/openapi/cisd-init.openapi.yaml`
- Modify: `docs/openapi/cisd-init.openapi.json`
**Step 1: 更新 `mqType` 描述**
明确不同产品的合法取值。
**Step 2: 更新请求示例和步骤含义说明**
体现 `TLQ_CONF_APPLY` 与 `INDIRECT` 的双通道模式。
### Task 7: 完整验证
**Files:**
- Verify only
**Step 1: 运行模块定向测试**
Run: `mvn -q -Dtest=InitServiceTest,ConfigurableInitStepExecutorTest test`
Expected: PASS
**Step 2: 运行编译验证**
Run: `mvn -q -DskipTests compile`
Expected: PASS
**Step 3: 人工检查关键路径**
检查 `ENTERPRISE + TLQ`、`INDIRECT + RABBITMQ_TLQ` 的任务步骤和命令模板。
@@ -0,0 +1,289 @@
# CIPS Auto Deployment Refactor Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 在保留“基础环境预置”的前提下,将 CISD/CIPS 初始化从“cpconfig.cfg 驱动 vendor shell”逐步升级为“TMS 后端接管客户化渲染、输出物管理和执行编排”的自动化部署流程。
**Architecture:** 运维继续负责操作系统、目录、基础软件、介质上传解压、数据库和中间件平台级账号密码等与客户无关的预置动作;TMS 负责根据前端参数生成部署上下文,输出渲染后的配置和 SQL,按版本/支持方式编排客户化初始化步骤,并产出可审计的日志、配置快照和结果摘要。vendor 原始脚本默认只读,优先采用 staging 临时渲染执行,而不是直接改写介质本体。
**Tech Stack:** Spring Boot 3, Shell staging execution, 模板渲染, TiDB SQL 初始化, RabbitMQ/TLQ, CMSP/CMTP, Nginx/Web 发布
---
### Task 1: 固化“预置层 / 初始化层”边界
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-09-auto-deploy-refactor.md`
- Reference: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Reference: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/initplan/step-command-profiles.json`
**Step 1: 明确定义预置层**
预置层仅包含与客户参数无关的动作:
- OS 用户、用户组、目录、权限创建
- JDK、RabbitMQ/TLQ/TiDB/Nginx 安装
- 防火墙和服务注册
- 安装介质上传、解压、静态资源预放置
- 数据库账号密码、中间件管理员账号密码等平台级凭据预置
- 许可证预置(如果出厂前已拿到)
**Step 2: 明确定义初始化层**
初始化层仅包含客户化动作:
- 机构号 / BIC / CIPS ID / LEI
- 节点 IP / 数据库地址
- RabbitMQ 通道账号密码
- RabbitMQ 用户 / 队列 / VHost 初始化
- TLQ 配置替换
- SQL 渲染与导库编排
- CMSP / CMTP / filetrans 配置渲染
- Nginx upstream / organization.json / Web 发布
- 服务启动与验收
**Step 3: 删除“初始化阶段执行预置脚本”的需求**
以下脚本只保留为预置脚本,不纳入 TMS 初始化主流程:
- `setpd.sh`
- `opencport.sh`
- `install_newpackage.sh`
- `setrabqstart.sh`
- `setxsd.sh`
- `setngservice.sh`
- `pongx.sh`
### Task 2: 固化部署上下文模型
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-09-auto-deploy-refactor.md`
- Reference: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/dto/InitPreviewRequest.java`
- Reference: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
**Step 1: 区分“前端输入参数”和“后端部署上下文”**
前端输入参数只承载业务输入;后端部署上下文承载可直接渲染文件和执行脚本的派生值。
**Step 2: 部署上下文仅保留初始化阶段所需客户化字段**
部署上下文至少应包含:
- `productType`
- `supportMode`
- `myCipsIdOrBic`
- `mq01Ip`
- `mq02Ip`
- `app01Ip`
- `app02Ip`
- `dbIp`
- `bicCode`
- `cipsId`
- `leiCode`
- `organizationNameCn`
- `organizationNameEn`
- `signVendor`
- `signIp`
- `signPort`
- `signDn`
- `signPasswordEnc`
**Step 3: 平台级凭据不进入初始化上下文**
以下内容由预置层提供,不作为初始化接口输入:
- 数据库用户名 / 密码
- RabbitMQ 管理员账号 / 密码
- TiDB 管理员账号 / 密码
**Step 4: supportMode 显式按产品定义**
- `ENTERPRISE`: `RABBITMQ` / `TLQ`
- `INDIRECT`: `RABBITMQ` / `RABBITMQ_TLQ`
- `DIRECT`: `RABBITMQ_TLQ` / `RABBITMQ_CFMQ`
### Task 3: 优先接管数据库初始化
**Status (2026-03-09):** 标准版已完成第一阶段落地,初始化编排已拆为 `DB_RENDER -> DB_APPLY`,并在 task staging 目录生成渲染后 SQL 包;后续仍需补强真实导库命令与结果校验。
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/initplan/step-command-profiles.json`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/toolsh/setsql.sh`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/sql_script/CMEP-DML.sql`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/sql_script/sql_script_tmp/CMTP-01-raq.sql`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/sql_script/sql_script_tmp/CMTP-01-tlq.sql`
**Step 1: 让后端输出渲染后的 SQL 包**
输出至少包含:
- `CMTP-01.sql`
- `CMEP-DML.sql`
- 其他导库所需脚本快照
**Step 2: 数据库导入凭据继续由预置层提供**
初始化阶段不再输入和修改数据库账号密码;TMS 只负责:
- 渲染 SQL
- 组织导入顺序
- 记录执行结果
**Step 3: DB_INIT 从“纯脚本黑盒”升级为“渲染 + 执行”双阶段**
拆成:
- `DB_RENDER`
- `DB_APPLY`
**Step 4: 保留 vendor 导库脚本作为执行器,而不是模板引擎**
如果短期不能完全替代 `setsql.sh`,则至少做到:
- 模板由后端渲染
- vendor 脚本只负责导入,不再负责替换占位符
### Task 4: 接管应用配置输出物
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/toolsh/setsptp.sh`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/cmsp/01/application-prd-ci01.properties`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/cmtp/01/application-prd-ci01.properties`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/cmsp/01/filetrans.properties`
**Step 1: 后端直接输出以下配置快照**
- `application-prd*.properties`
- `filetrans.properties`
- 标准版 RabbitMQ 通道账号密码回写结果
**Step 2: 数据库连接凭据保持预置,不由初始化阶段改写**
应用配置接管范围仅覆盖客户化字段,不覆盖预置层数据库连接凭据。
**Step 3: 将 setsptp.sh 从“渲染 + 拷贝”降级为“拷贝器”**
短期目标:
- 配置替换由后端完成
- `setsptp.sh` 仅做 JAR / 目录拷贝
**Step 4: 禁止敏感信息输出到步骤日志**
渲染日志中不得出现密码明文或密文。
### Task 5: 接管 Nginx / Web 客户化
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/initplan/step-command-profiles.json`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/software/setngx.sh`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/toolsh/setweb.sh`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/software/nginx.conf`
**Step 1: 新增 Nginx/Web 相关步骤**
至少新增:
- `NGINX_CONFIG_APPLY`
- `WEB_CONFIG_APPLY`
**Step 2: 后端渲染输出物**
- `nginx.conf`
- `organization.json`
- Web 发布目录快照或发布日志
**Step 3: 不再把 setweb.sh 作为首批高收益改造对象本体**
优先由后端接管组织名称和 nginx upstream 渲染,再决定是否保留 `setweb.sh` 作为拷贝器。
### Task 6: 建立显式启动顺序
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/initplan/step-command-profiles.json`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/sh/sh/stcmep_cent.sh`
**Step 1: 将“部署”和“启动”拆开**
当前 `DEPLOY_RECEIVER` 不能同时承载“拷贝应用”和“启动服务”两种职责。
**Step 2: 新增启动步骤**
建议新增:
- `START_CMSP_CMTP`
- `START_NGINX`
- `POST_CHECK`
**Step 3: 定义启动顺序**
推荐顺序:
1. 参数校验
2. 渲染配置和 SQL
3. 准备 license
4. 初始化 RabbitMQ / TLQ
5. 初始化数据库
6. 下发 CMSP / CMTP 配置
7. 下发 Nginx / Web 配置
8. 启动 CMSP / CMTP
9. 启动 Nginx
10. 验收检查
### Task 7: 建立失败边界和输出物
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
**Step 1: 明确失败即停边界**
- MQ 初始化失败后停止后续步骤
- 数据库导入失败后不启动应用
- 应用配置失败后不覆盖旧版本
- Web 发布失败不影响已启动后台服务
**Step 2: 输出四类审计产物**
每次部署任务至少输出:
- 渲染后的配置快照
- 渲染后的 SQL 包
- 步骤执行日志
- 最终部署结果摘要
### Task 8: 第一批高收益实施顺序
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/initplan/step-command-profiles.json`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: 第一优先级**
- 标准版 SQL 渲染输出物
- DB_INIT 拆分为渲染与执行
- 数据库导入结果可审计化
**Step 2: 第二优先级**
- CMSP / CMTP / filetrans 配置输出物
- RabbitMQ / TLQ 初始化后的验收
**Step 3: 第三优先级**
- Nginx / Web 渲染与发布
- 显式启动顺序和启动后检查
### Task 9: 验收标准
**Files:**
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/document/CIPS标准收发器安装部署手册1.0(企业信创版)-V1.3.2.pdf`
**Step 1: 参数层验收**
确认后端输入能完整覆盖初始化阶段真正需要的客户化字段,特别是:
- 支持方式
- 组织名称
- Nginx/Web 所需字段
- RabbitMQ 通道账号密码
**Step 2: 配置层验收**
确认输出物中不再残留以下占位符:
- `AAAABBBBXXX`
- `sptp.01app.ip`
- `sptp.02app.ip`
- `sptp.01db.ip`
- `01tlq.ip`
- `02tlq.ip`
- `mybiccode`
- `mycipsid`
- `myleicode`
**Step 3: 部署层验收**
确认:
- MQ / TLQ 正常可连
- TiDB 库和 schema 正常创建
- CMSP / CMTP 正常启动
- Nginx 正常代理
- Web 首页可访问
- `organization.json` 为客户实际机构名称
### Task 10: 非目标项
**Step 1: 明确本轮不做**
以下内容不作为本轮主线:
- 大规模直接修改 vendor 原始脚本
- 修改介质 readme/document 作为交付主成果
- 将所有 cpconfig 依赖一次性彻底移除
- 将平台级凭据纳入初始化接口输入
**Step 2: 后续演进原则**
优先让 TMS 接管“产物和编排”,再逐步削弱 vendor shell 的模板职责。
@@ -0,0 +1,175 @@
# Standard DB Render Apply Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 将标准版初始化中的数据库步骤从黑盒 `DB_INIT` 拆分为 `DB_RENDER` 和 `DB_APPLY`,生成可审计的 SQL 输出物,并保留数据库凭据在预制层处理。
**Architecture:** 标准版步骤编排改为先在 task staging 目录生成渲染后的 SQL 包,再由单独的 `DB_APPLY` 步骤将 SQL 包落位到标准收发器数据库加载目录,并按预置命令执行导库。渲染逻辑直接基于 `sql_script_tmp` 模板和 `CMEP-DML.sql/CMEP.sql`,不依赖 vendor 脚本副作用,也不修改 vendor 原始介质。
**Tech Stack:** Java 17, Spring Boot 3.5, Jackson, JUnit 5, Maven
---
### Task 1: 固化步骤编排与计划文档
**Files:**
- Create: `/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-09-standard-db-render-apply-plan.md`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/initplan/step-command-profiles.json`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
**Step 1: Write the failing test**
在 `InitServiceTest` 增加标准版断言:
- `ENTERPRISE + RABBITMQ` 不再包含 `DB_INIT`
- 改为包含 `DB_RENDER` 和 `DB_APPLY`
- `ENTERPRISE + TLQ`、`INDIRECT + RABBITMQ`、`INDIRECT + RABBITMQ_TLQ` 同样断言
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: FAIL,提示仍存在 `DB_INIT` 或缺少 `DB_RENDER/DB_APPLY`
**Step 3: Write minimal implementation**
修改 `InitService.defaultSteps()` 与 `step-command-profiles.json`:
- 标准版统一把 `DB_INIT` 替换成 `DB_RENDER`、`DB_APPLY`
- 直参版保持 `DB_INIT`
- 标准版 `DB_RENDER` 使用 `internal::db_render`
- 标准版 `DB_APPLY` 使用 `internal::db_apply`
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: PASS
### Task 2: 先写标准版 SQL 渲染失败用例
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/config/InitExecutorProperties.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/application.yml`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/config/application.yml.example`
**Step 1: Write the failing test**
新增两个执行器测试:
- `shouldRenderStandardDatabaseSqlPackageForEnterpriseRabbitmq`
- 在临时目录准备 `cpconfig.cfg`、`sql_script/CMEP-DML.sql`、`sql_script/CMEP.sql`、`sql_script/SCHEMA-DDL.sql`、`sql_script/UP-ORG-INFO.sql`、`sql_script/sql_script_tmp/CMTP-01-raq.sql`
- 执行 `internal::db_render`
- 断言 staging 下存在 `db/sql/CMTP-01.sql`、`CMEP-DML.sql`、`CMEP.sql` 等文件
- 断言 `AAAABBBBXXX`、`01tlq.ip`、`02tlq.ip`、`sptp.01app.ip` 被替换
- `shouldApplyStandardDatabaseSqlPackageToLoadDir`
- 基于上一步产物执行 `internal::db_apply`
- 断言 SQL 被复制到 configured load dir
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest test`
Expected: FAIL,提示不支持 `db_render/db_apply` 或目标文件不存在
**Step 3: Define minimal config surface**
为标准版数据库处理增加配置项:
- `standard-db-script-base-dir`
- `standard-db-load-dir`
- `standard-db-apply-command`
- `standard-db-entry-sql-file-name`
并在两个 `application.yml` 中补注释和默认值。
**Step 4: Re-run focused test**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest test`
Expected: 仍失败,但失败点只剩未实现逻辑
### Task 3: 实现标准版 DB_RENDER
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Add internal step dispatch**
在 `executeInternal()` 新增:
- `case "db_render" -> executeStandardDbRender(task, step)`
**Step 2: Implement render behavior**
新增最小实现:
- 仅对标准版生效;直参版返回 skipped
- 从 `standard-db-script-base-dir` 读取:
- `sql_script/CMEP-DML.sql`
- `sql_script/CMEP.sql`
- `sql_script/SCHEMA-DDL.sql`
- `sql_script/UP-ORG-INFO.sql`
- `sql_script/sql_script_tmp/CMTP-01-raq.sql` 或 `CMTP-01-tlq.sql`
- 渲染输出到 `staging/<taskId>/db/sql/`
- 输出文件名固定为:
- `CMEP-DML.sql`
- `CMEP.sql`
- `SCHEMA-DDL.sql`
- `UP-ORG-INFO.sql`
- `CMTP-01.sql`
- 渲染规则复用 `buildStandardReplacements()`,并补充 SQL 占位映射:
- `AAAABBBBXXX -> orgCode`
- `01tlq.ip -> mq_01_ip`
- `02tlq.ip -> mq_02_ip`
- `sptp.01app.ip -> sptp_01app_ip`
- `sptp.02app.ip -> sptp_02app_ip`
- `mybiccode/mycipsid/myleicode -> 对应机构号映射`
- `CMEP.sql` 里的 `source /home/cmep4i/mysql/loadfilepath/...` 保持不变,不在渲染阶段改路径
**Step 3: Run render test**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldRenderStandardDatabaseSqlPackageForEnterpriseRabbitmq test`
Expected: PASS
### Task 4: 实现标准版 DB_APPLY
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Add internal step dispatch**
在 `executeInternal()` 新增:
- `case "db_apply" -> executeStandardDbApply(task, step)`
**Step 2: Implement apply behavior**
最小实现:
- 仅对标准版生效;直参版返回 skipped
- 从 `staging/<taskId>/db/sql/` 读取渲染后 SQL 包
- 复制到 `standard-db-load-dir`
- `SIMULATE` 模式只校验 staging 产物存在并返回 success
- `LOCAL` 模式:
- 若 `standard-db-apply-command` 为空,只做落位并返回 success
- 若不为空,则以该命令执行导库,工作目录指向 `standard-db-load-dir`
- 成功日志中明确输出 staging 路径、load dir、是否执行导库命令
**Step 3: Run apply test**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldApplyStandardDatabaseSqlPackageToLoadDir test`
Expected: PASS
### Task 5: 全量回归与最小文档同步
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-09-auto-deploy-refactor.md`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Sync plan wording**
在重构计划中把 Task 3 结果更新为已实现方向:标准版数据库改为 `DB_RENDER / DB_APPLY`。
**Step 2: Run targeted tests**
Run: `mvn -q -Dtest=InitServiceTest,ConfigurableInitStepExecutorTest test`
Expected: PASS
**Step 3: Run compile verification**
Run: `mvn -q -DskipTests compile`
Expected: PASS
@@ -0,0 +1,51 @@
# Deployment Doc Chinese Localization Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Convert the full TMS deployment manual and deployment-related README sections to Chinese while preserving commands, paths, config keys, and interface names.
**Architecture:** Keep the existing document structure and only localize human-readable prose. Do not change command examples, file paths, YAML keys, API paths, or script names. Limit the scope to `docs/deployment/tms-deployment.md` and the deployment-related part of `README.md`.
**Tech Stack:** Markdown documentation
---
### Task 1: Localize the deployment manual
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md`
**Step 1: Translate headings and narrative text**
Convert the deployment manual to Chinese, preserving commands, paths, config keys, API paths, and script names.
**Step 2: Keep structure and examples stable**
Do not reorder sections or alter shell/YAML examples except for surrounding explanatory text.
### Task 2: Localize deployment-related README content
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/README.md`
**Step 1: Translate deployment entry and notes**
Convert the deployment guide link, Jar deployment section title, and deployment-related notes to Chinese.
**Step 2: Avoid unrelated README changes**
Keep non-deployment sections as-is.
### Task 3: Consistency review
**Files:**
- Verify only
**Step 1: Review focused diff**
Run: `git diff -- README.md docs/deployment/tms-deployment.md`
Expected: only prose localization changes.
**Step 2: Spot-check for path/config drift**
Verify commands, paths, config keys, and script names remain unchanged.
@@ -0,0 +1,214 @@
# File Upload FileId Design
**Date:** 2026-03-10
## Goal
为 TMS 提供一个通用文件上传能力,前端在初始化页面选择文件后先上传,后端返回 `fileId`,初始化任务创建和执行阶段继续只引用 `fileId`,不直接传输文件流。
## Scope
本设计只覆盖:
- 通用文件上传接口
- 文件元信息记录
- 与 CISD 初始化的 `fileId` 约定
- 前端调用时序
本设计不覆盖:
- 文件下载
- 文件删除回收
- 秒传/去重
- 文件内容级业务校验
- 初始化主流程改造
## Current State
当前初始化接口:
- `/api/v1/init/preview`
- `/api/v1/init/tasks`
都只接收 JSON `InitPreviewRequest`,不接收 `multipart/form-data`。
当前初始化模块已经完整依赖以下 `fileId` 字段:
- `licenses.receiverLicenseFileId`
- `licenses.cfgZipFileId`
- `mq.tlqLicenseFileId`
- `mq.cfmqConfigFileId`
当前执行器通过 `upload-base-dir/<fileId>` 或 `upload-base-dir/<fileId>/<preferredFileName>` 解析文件。
## Design Choice
采用:`通用上传接口 + 初始化继续引用 fileId`
不采用:`初始化任务接口直接接收 MultipartFile`
原因:
- 初始化主流程已经基于 `fileId`,继续沿用改动最小
- 上传与初始化创建失败语义不同,拆分更清晰
- 通用上传能力后续可被证书、升级、备份等模块复用
## API Design
### 1. Upload API
`POST /api/v1/files/upload`
Content-Type:`multipart/form-data`
表单字段:
- `file`: 必填,文件本体
- `bizType`: 可选,默认 `GENERIC`
返回示例:
```json
{
"success": true,
"code": 200,
"msg": "success",
"data": {
"fileId": "f_20260310_ab12cd34",
"bizType": "INIT",
"originalFilename": "cmep.license",
"contentType": "application/octet-stream",
"size": 2048,
"storagePath": "/home/tms/uploads/f_20260310_ab12cd34/cmep.license"
},
"timestamp": 1741600000000,
"traceId": "xxx"
}
```
### 2. File Detail API
`GET /api/v1/files/{fileId}`
用于页面回显和排障,不参与初始化主链路。
## Storage Design
### Storage root
- `/home/tms/uploads`
### Directory layout
- `/home/tms/uploads/<fileId>/`
- `/home/tms/uploads/<fileId>/<originalFilename>`
这样做的原因:
- 与当前执行器解析逻辑兼容
- 保留原始文件名,便于排查
- 每个 `fileId` 单独目录,避免同名覆盖
## Database Design
新增表:`sys_file_record`
字段建议:
- `id` bigint pk
- `file_id` varchar(128) unique not null
- `biz_type` varchar(32) not null
- `original_filename` varchar(256) not null
- `stored_filename` varchar(256) not null
- `storage_path` varchar(512) not null
- `content_type` varchar(128) null
- `file_size` bigint not null
- `sha256` varchar(64) null
- `status` varchar(16) not null
- `create_time` datetime not null
- `update_time` datetime not null
状态值当前只需要:
- `ACTIVE`
- `DELETED`
## Backend Module Layout
新增模块:
```text
src/main/java/com/cisd/tms/modules/file
├── controller/internal
│ └── FileInternalController.java
├── dto
│ ├── FileUploadResponse.java
│ └── FileDetailResponse.java
├── entity
│ └── FileRecordEntity.java
├── repository
│ └── FileRecordRepository.java
└── service
└── FileService.java
```
资源文件:
```text
src/main/resources/mapper/file/FileRecordMapper.xml
src/main/resources/db/migration/V3__create_sys_file_record.sql
```
## Validation Boundary
### Upload API validates
- 文件非空
- 原始文件名非空
- 文件大小不超过配置上限
- `bizType` 枚举合法
### Init API continues to validate
- `fileId` 格式
- 按版本和 `mqType` 的必填规则
- 执行阶段按 `fileId` 是否能找到对应文件
## Frontend Flow
1. 用户在初始化页面选择文件
2. 前端立即调用上传接口
3. 上传成功后拿到 `fileId`
4. 前端将 `fileId` 保存到表单状态
5. 用户点击“预检”或“创建任务”时,仅提交 JSON
字段映射:
- 收发器 license -> `licenses.receiverLicenseFileId`
- TLQ 配置/许可证 -> `mq.tlqLicenseFileId`
- CFMQ 配置 -> `mq.cfmqConfigFileId`
- 直参 cfg 包 -> `licenses.cfgZipFileId`
## Configuration
建议新增:
```yaml
tms:
file:
upload-base-dir: /home/tms/uploads
max-file-size-mb: 50
```
后续可考虑让初始化执行器复用同一配置根,而不是再单独维护一份路径配置。
## Risks
1. 当前初始化执行器已有 `tms.init.executor.upload-base-dir`,如果新增 `tms.file.upload-base-dir` 而两者不一致,会导致上传成功但执行阶段找不到文件。
2. 如果上传接口只保留原始文件名而不做额外清洗,需要限制危险文件名字符。
3. 目前不做业务文件类型校验,上传成功不代表该文件一定适合初始化使用。
## Recommendation
先实现最小闭环:
- 上传接口
- 查询接口
- 文件元信息表
- 与初始化 `fileId` 流程对齐
不在第一版加入:
- 下载
- 删除
- 清理任务
- 哈希去重
- 扩展名白名单
@@ -0,0 +1,251 @@
# File Upload FileId Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Add a reusable file upload module that stores uploaded files under `/home/tms/uploads`, returns `fileId`, and keeps CISD initialization flowing through existing `fileId` fields.
**Architecture:** Introduce a small `modules/file` module with internal upload and query APIs, one metadata table, and a service that owns fileId generation plus filesystem persistence. Keep the init module unchanged at the API boundary except for sharing the same upload storage root and documenting the front-end workflow.
**Tech Stack:** Spring Boot MVC multipart upload, MyBatis-Plus repository pattern, Flyway SQL migration, JUnit 5
---
### Task 1: Add file upload persistence contract
**Files:**
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/db/migration/V3__create_sys_file_record.sql`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/file/entity/FileRecordEntity.java`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/file/repository/FileRecordRepository.java`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/mapper/file/FileRecordMapper.xml`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileServiceTest.java`
**Step 1: Write the failing test**
Add a test that expects file metadata to be persisted with:
- generated `fileId`
- original file name
- absolute storage path
- `ACTIVE` status
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=FileServiceTest#shouldPersistUploadedFileMetadata test`
Expected: FAIL because file module classes and table mapping do not exist.
**Step 3: Write minimal implementation**
Implement the entity, mapper/repository, and migration with only the fields needed by upload/query.
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=FileServiceTest#shouldPersistUploadedFileMetadata test`
Expected: PASS
**Step 5: Commit**
```bash
git add src/main/resources/db/migration/V3__create_sys_file_record.sql \
src/main/java/com/cisd/tms/modules/file/entity/FileRecordEntity.java \
src/main/java/com/cisd/tms/modules/file/repository/FileRecordRepository.java \
src/main/resources/mapper/file/FileRecordMapper.xml \
src/test/java/com/cisd/tms/modules/file/FileServiceTest.java
git commit -m "feat: add file upload persistence contract"
```
### Task 2: Implement upload service
**Files:**
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/file/service/FileService.java`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/file/dto/FileUploadResponse.java`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/file/dto/FileDetailResponse.java`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/common/config/properties/FileStorageProperties.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/application.yml`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/config/application.yml.example`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileServiceTest.java`
**Step 1: Write the failing test**
Add tests that assert:
- uploaded file is saved under `<upload-base-dir>/<fileId>/<originalFilename>`
- blank file upload is rejected
- oversize upload is rejected
- returned DTO contains `fileId`, size, storagePath
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=FileServiceTest test`
Expected: FAIL because service and properties do not exist.
**Step 3: Write minimal implementation**
Implement:
- `fileId` generation
- file name sanitization
- directory creation
- file save
- metadata insert
- detail query by `fileId`
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=FileServiceTest test`
Expected: PASS
**Step 5: Commit**
```bash
git add src/main/java/com/cisd/tms/modules/file/service/FileService.java \
src/main/java/com/cisd/tms/modules/file/dto/FileUploadResponse.java \
src/main/java/com/cisd/tms/modules/file/dto/FileDetailResponse.java \
src/main/java/com/cisd/tms/common/config/properties/FileStorageProperties.java \
src/main/resources/application.yml config/application.yml.example \
src/test/java/com/cisd/tms/modules/file/FileServiceTest.java
git commit -m "feat: implement file upload service"
```
### Task 3: Expose internal file APIs
**Files:**
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/file/controller/internal/FileInternalController.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileServiceTest.java`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java`
**Step 1: Write the failing test**
Add controller tests for:
- `POST /api/v1/files/upload`
- `GET /api/v1/files/{fileId}`
Verify upload uses multipart, returns `ApiResponse`, and query returns stored metadata.
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=FileInternalControllerTest test`
Expected: FAIL because controller does not exist.
**Step 3: Write minimal implementation**
Expose two endpoints only:
- upload
- detail query
Keep them internal-only under `/api/v1/files`.
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=FileInternalControllerTest test`
Expected: PASS
**Step 5: Commit**
```bash
git add src/main/java/com/cisd/tms/modules/file/controller/internal/FileInternalController.java \
src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java \
src/test/java/com/cisd/tms/modules/file/FileServiceTest.java
git commit -m "feat: expose internal file upload api"
```
### Task 4: Align init module with shared upload root and docs
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/config/InitExecutorProperties.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/application.yml`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/config/application.yml.example`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/openapi/cisd-init.openapi.yaml`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/openapi/cisd-init.openapi.json`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/README.md`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Write the failing test**
Add or update tests to assert:
- init executor upload root matches the shared upload root config
- docs clearly state init APIs accept `fileId`, not multipart files
- README documents front-end flow: upload first, then create init task
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldDocumentInitFileIdFlow test`
Expected: FAIL because docs/config are not aligned yet.
**Step 3: Write minimal implementation**
Align configuration and docs without changing init request DTO semantics.
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldDocumentInitFileIdFlow test`
Expected: PASS
**Step 5: Commit**
```bash
git add src/main/java/com/cisd/tms/modules/init/config/InitExecutorProperties.java \
src/main/resources/application.yml config/application.yml.example \
docs/openapi/cisd-init.openapi.yaml docs/openapi/cisd-init.openapi.json README.md \
src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java
git commit -m "docs: align init fileId flow with upload api"
```
### Task 5: Add upload API OpenAPI spec
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/openapi/cisd-init.openapi.yaml`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/openapi/cisd-init.openapi.json`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java`
**Step 1: Write the failing test**
Add a documentation test or assertion that the upload route and response fields are present in the OpenAPI output.
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=FileInternalControllerTest#shouldDocumentUploadApi test`
Expected: FAIL because the route is not documented yet.
**Step 3: Write minimal implementation**
Document:
- upload API
- query API
- multipart request
- `fileId` response
- init API references to upload-first workflow
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=FileInternalControllerTest#shouldDocumentUploadApi test`
Expected: PASS
**Step 5: Commit**
```bash
git add docs/openapi/cisd-init.openapi.yaml docs/openapi/cisd-init.openapi.json \
src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java
git commit -m "docs: add file upload api spec"
```
### Task 6: Final verification
**Files:**
- Verify only
**Step 1: Run file module tests**
Run: `mvn -q -Dtest=FileServiceTest,FileInternalControllerTest test`
Expected: PASS
**Step 2: Run init-related tests**
Run: `mvn -q -Dtest=InitServiceTest,ConfigurableInitStepExecutorTest test`
Expected: PASS
**Step 3: Run compile**
Run: `mvn -q -DskipTests compile`
Expected: PASS
**Step 4: Review focused diff**
Run: `git diff -- src/main/java/com/cisd/tms/modules/file src/main/resources/db/migration/V3__create_sys_file_record.sql src/main/resources/mapper/file src/main/resources/application.yml config/application.yml.example README.md docs/openapi/cisd-init.openapi.yaml docs/openapi/cisd-init.openapi.json`
Expected: only file upload module, config, README, and OpenAPI/doc alignment changes.
@@ -0,0 +1,211 @@
# Init Execute Async Resume Design
**Date:** 2026-03-10
## Goal
解决初始化执行接口同步阻塞导致的请求超时问题,并支持任务在失败后从第一个未成功步骤继续执行,而不是每次都从头开始。
## Scope
本设计覆盖:
- `/api/v1/init/tasks/{taskId}/execute` 改为异步受理
- 初始化任务后台执行模型
- 步骤级断点续跑规则
- 同一任务的重复触发保护
- 现有查询接口与状态语义调整
本设计不覆盖:
- 分布式任务调度
- 多实例间执行协调
- 服务重启后的自动恢复调度
- 新增前端页面
- 初始化步骤编排本身的变更
## Current State
当前执行入口是同步的:
- 控制器直接调用 `InitService.executeTask(taskId)`
- 服务层在请求线程内串行执行全部步骤
- 任一步骤失败后立刻中断
当前问题有两个:
- 任务执行时间较长时,HTTP 请求容易超时
- 再次执行时没有跳过已成功步骤的逻辑,会从第一步重新开始
当前已有可复用基础:
- 任务主表 `tms_init_task`
- 任务步骤表 `tms_init_task_step`
- 步骤状态字段:`PENDING` / `RUNNING` / `SUCCESS` / `FAILED`
- 现有步骤详情和日志查询接口
## Design Choice
采用:`应用内异步执行 + 基于步骤状态续跑`
不采用:`继续同步执行`
原因:
- 无法避免请求超时
- 与实际长耗时初始化场景不匹配
不采用:`数据库任务队列 + 独立 worker`
原因:
- 当前需求重点是先解决超时和重跑问题
- 现阶段引入完整调度系统成本过高
## API Design
### Execute API
`POST /api/v1/init/tasks/{taskId}/execute`
接口语义调整为:
- 只负责受理执行请求
- 不等待全部步骤完成
- 返回当前任务快照
返回字段继续复用 `InitTaskExecuteResponse`,但语义变为:
- `taskId`: 任务号
- `status`: 受理后的当前状态,通常为 `RUNNING`
- `totalSteps`: 总步骤数
- `successSteps`: 当前已成功步骤数
前端后续继续通过以下接口轮询:
- `GET /api/v1/init/tasks/{taskId}`
- `GET /api/v1/init/tasks/{taskId}/steps`
- `GET /api/v1/init/tasks/{taskId}/steps/{stepNo}/log`
## Execution Model
### 1. Request thread
请求线程只做以下事情:
- 校验任务存在且有步骤
- 检查是否已经在执行中
- 将任务状态置为 `RUNNING`
- 提交后台执行任务
- 立即返回
### 2. Background worker
后台线程负责真正串行执行步骤:
- 重新加载任务与步骤
- 识别续跑起点
- 逐步执行
- 每步结束后立刻落库状态、消息、日志路径、退出码
- 汇总任务最终状态
### 3. Single-task guard
同一 `taskId` 在一个应用实例内只允许一个执行线程:
- 若任务已在本实例执行中,再次调用 `execute` 不再重复启动
- 接口直接返回当前快照
实现上可使用进程内 `ConcurrentHashMap<String, Future<?>>` 或等价结构维护活动任务。
## Resume Rule
再次执行时采用以下规则:
1. 所有 `SUCCESS` 步骤直接跳过,不重跑
2. 从第一个非 `SUCCESS` 步骤开始继续
3. 后续步骤按原顺序执行
4. 若本次再次失败,当前失败步骤状态记为 `FAILED`,任务状态记为 `FAILED`
### RUNNING residue handling
如果上一次执行过程中服务异常退出,可能残留 `RUNNING` 步骤。
本设计约定:
- 新一轮执行开始前,将残留 `RUNNING` 步骤视为未完成
- 统一重置为 `FAILED`
- 续跑时从第一个非 `SUCCESS` 步骤开始
这样可以保留“上次停在这里”的事实,并避免把 `RUNNING` 误判为仍在健康执行。
## Status Semantics
### Task status
- `PENDING`: 任务已创建,尚未开始
- `RUNNING`: 已受理且后台执行中
- `SUCCESS`: 全部步骤成功
- `FAILED`: 某一步失败并已停止
### Step status
- `PENDING`: 从未执行
- `RUNNING`: 当前正在执行
- `SUCCESS`: 已成功,后续重试跳过
- `FAILED`: 最近一次执行失败,后续重试从此处继续
## Concurrency Policy
### Same task
同一任务重复点击执行:
- 若本实例检测到该任务已在执行,直接返回当前状态
- 不再启动第二个后台线程
### Different tasks
不同任务是否允许并发执行,第一版保持当前默认:
- 允许不同 `taskId` 并行受理
- 不额外加全局串行锁
原因:
- 当前需求只明确要求单任务避免重入
- 是否需要全局串行,取决于目标主机资源和脚本互斥关系,后续再单独设计
## Data Changes
本设计优先复用现有表结构,不新增表字段。
依赖现有字段即可表达:
- 任务当前状态
- 步骤当前状态
- 失败消息
- 日志路径
- 退出码
## Testing Strategy
需要补的测试重点:
1. 异步受理
- `execute` 调用应快速返回
- 后台线程继续推进步骤状态
2. 失败后续跑
- 首次执行在某步失败
- 再次执行时跳过已 `SUCCESS` 步骤
- 从失败步骤重新执行并继续后续步骤
3. 残留 `RUNNING`
- 构造上一次异常中断留下的 `RUNNING` 步骤
- 重试时应从该步骤继续
4. 单任务重复触发保护
- 同一个 `taskId` 在执行中再次调用
- 不应重复启动第二个执行线程
## Risks
1. 应用内异步执行依赖当前进程存活,若服务重启,运行中的任务不会自动恢复。
2. 若底层初始化脚本本身不具备完全幂等性,虽然步骤级跳过已成功步骤可以减少重复执行,但失败步骤重试仍可能触发环境冲突。
3. 当前只做单实例内去重;若后续部署多实例,需要补分布式锁或数据库抢占机制。
## Recommendation
先实现最小闭环:
- `execute` 异步受理
- 单任务进程内防重入
- 从第一个非 `SUCCESS` 步骤续跑
- 残留 `RUNNING` 视为失败点恢复
不在第一版加入:
- 分布式调度
- 自动恢复未完成任务
- 新状态枚举或额外任务队列表
@@ -0,0 +1,188 @@
# Init Execute Async Resume Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Make `/api/v1/init/tasks/{taskId}/execute` return immediately after accepting work, then run init steps in the background and resume from the first non-`SUCCESS` step on retry.
**Architecture:** Keep the existing task table and step table as the source of truth. Split `InitService.executeTask` into an accept-and-dispatch path plus a background execution path, and use existing step statuses to determine where to resume. Add a lightweight in-process guard so one `taskId` cannot be started twice concurrently in the same application instance.
**Tech Stack:** Spring Boot service/controller layer, Java concurrency utilities, MyBatis-style repositories already present in the module, JUnit 5
---
### Task 1: Lock down current behavior with service tests
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
**Step 1: Write the failing tests**
Add tests that assert:
- `executeTask(taskId)` returns before a deliberately blocking executor finishes all steps
- retry skips steps already marked `SUCCESS` and resumes from the first `FAILED` step
- residual `RUNNING` steps are treated as the resume point on retry
- duplicate execute calls for the same running task do not launch a second execution
**Step 2: Run tests to verify they fail**
Run: `mvn -q -Dtest=InitServiceTest#shouldAcceptTaskExecutionAsynchronously,InitServiceTest#shouldResumeFromFirstFailedStepOnRetry,InitServiceTest#shouldResumeFromResidualRunningStep,InitServiceTest#shouldNotDispatchDuplicateBackgroundExecutionForSameTask test`
Expected: FAIL because execution is still synchronous and always starts from step 1.
**Step 3: Write minimal test scaffolding**
Extend the in-memory executor/repository helpers in the test file so they can:
- block on a latch or sleep
- count executed step codes
- fail a chosen step once and succeed on retry
Do not change production code in this step.
**Step 4: Run tests to verify RED is stable**
Run: `mvn -q -Dtest=InitServiceTest#shouldAcceptTaskExecutionAsynchronously,InitServiceTest#shouldResumeFromFirstFailedStepOnRetry,InitServiceTest#shouldResumeFromResidualRunningStep,InitServiceTest#shouldNotDispatchDuplicateBackgroundExecutionForSameTask test`
Expected: FAIL with assertion mismatches that prove the new behavior is not implemented yet.
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 2: Introduce async dispatch in `InitService`
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
**Step 1: Implement minimal async acceptance path**
Refactor `InitService` so `executeTask(taskId)`:
- loads task and steps
- returns a snapshot response quickly
- submits real work to a background executor
Use a small in-process dispatcher owned by `InitService`:
- `ExecutorService` or equivalent
- active-task map keyed by `taskId`
**Step 2: Keep the real execution logic in a dedicated method**
Create a private method such as `executeTaskInBackground(taskId)` that:
- reloads task and steps from repository
- updates statuses
- runs steps serially
- persists each step result immediately
- updates final task status
**Step 3: Run focused tests**
Run: `mvn -q -Dtest=InitServiceTest#shouldAcceptTaskExecutionAsynchronously,InitServiceTest#shouldNotDispatchDuplicateBackgroundExecutionForSameTask test`
Expected: PASS
**Step 4: Refactor for readability**
Extract helpers only if needed:
- build response snapshot
- mark task running
- remove active-task entry in `finally`
Do not add extra features.
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 3: Implement resume-from-first-non-success semantics
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
**Step 1: Implement step selection logic**
Before running steps in the background:
- convert residual `RUNNING` steps to `FAILED`
- skip every step already marked `SUCCESS`
- start execution at the first non-`SUCCESS` step
Preserve current semantics after the resume point:
- mark current step `RUNNING`
- on success mark `SUCCESS`
- on failure mark `FAILED` and stop
**Step 2: Preserve response counters**
Ensure `successSteps` in `InitTaskExecuteResponse` reflects the current number of successful steps, including successes from earlier runs.
**Step 3: Run focused tests**
Run: `mvn -q -Dtest=InitServiceTest#shouldResumeFromFirstFailedStepOnRetry,InitServiceTest#shouldResumeFromResidualRunningStep test`
Expected: PASS
**Step 4: Run the earlier async tests again**
Run: `mvn -q -Dtest=InitServiceTest#shouldAcceptTaskExecutionAsynchronously,InitServiceTest#shouldNotDispatchDuplicateBackgroundExecutionForSameTask,InitServiceTest#shouldResumeFromFirstFailedStepOnRetry,InitServiceTest#shouldResumeFromResidualRunningStep test`
Expected: PASS
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 4: Align controller and API-facing semantics
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/controller/InitInternalController.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/dto/InitTaskExecuteResponse.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
**Step 1: Make the API comments and DTO semantics match async behavior**
Update JavaDoc/comments so they describe:
- execute endpoint only accepts and starts background work
- polling should use existing detail/step/log APIs
If needed, add a field only if tests prove it is necessary. Prefer reusing the current DTO unchanged.
**Step 2: Run focused verification**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: PASS for all service tests, including the pre-existing create/query/execute cases.
**Step 3: Review the controller surface**
Check that:
- route path stays unchanged
- response wrapper stays unchanged
- no new endpoint is introduced unnecessarily
**Step 4: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 5: Final verification
**Files:**
- Verify only
**Step 1: Run init service tests**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: PASS
**Step 2: Run init executor regression tests touched by earlier behavior changes**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldInjectDatabaseCredentialsWhenExecutingStandardDbApplyCommand,ConfigurableInitStepExecutorTest#shouldExposeStandardInitScriptTemplates,ConfigurableInitStepExecutorTest#shouldStartStandardCmspCmtpWithConfiguredCommand test`
Expected: PASS
**Step 3: Run compile**
Run: `mvn -q -DskipTests compile`
Expected: PASS
**Step 4: Review focused diff**
Run: `git diff -- src/main/java/com/cisd/tms/modules/init/service/InitService.java src/main/java/com/cisd/tms/modules/init/controller/InitInternalController.java src/main/java/com/cisd/tms/modules/init/dto/InitTaskExecuteResponse.java src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java docs/plans/2026-03-10-init-execute-async-resume-design.md docs/plans/2026-03-10-init-execute-async-resume-plan.md`
Expected: only async-dispatch, resume logic, and related documentation changes.
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
@@ -0,0 +1,115 @@
# Standard Init Script Templates Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Add standard CISD post-init script templates to the repository and document how TMS should reference them after deployment to `/home/tms/bin`.
**Architecture:** Keep the runtime command model unchanged in TMS. Add script templates under the repository so deployment has a clear source of truth, then point `application.yml.example` and `README.md` to the deployed absolute paths. Tests only verify the repository artifacts and expected command content, not real database or nginx execution.
**Tech Stack:** Shell scripts, Spring Boot config examples, JUnit 5 filesystem assertions
---
### Task 1: Add repository script templates
**Files:**
- Create: `/Users/waner/Work/CISD/文档/tms-framework/scripts/standard-init/apply_standard_db.sh`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/scripts/standard-init/start_standard_apps.sh`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/scripts/standard-init/start_standard_nginx.sh`
- Create: `/Users/waner/Work/CISD/文档/tms-framework/scripts/standard-init/check_standard_runtime.sh`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Write the failing test**
Add tests that assert the four script files exist in `scripts/standard-init/` and contain the expected key commands:
- DB script references `SCHEMA-DDL.sql`, `CMEP.sql`, `UP-ORG-INFO.sql`
- App start script references `start_cmsp.sh` and `start_cmtp.sh`
- Nginx start script references `/usr/local/nginx/sbin/nginx`
- Post-check script references CMSP/CMTP/nginx process checks and `organization.json`
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldExposeStandardInitScriptTemplates test`
Expected: FAIL because the scripts do not exist yet.
**Step 3: Write minimal implementation**
Create the four scripts with:
- `#!/bin/bash`
- `set -euo pipefail`
- environment variable placeholders for preset credentials where needed
- comments limited to critical operational assumptions
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldExposeStandardInitScriptTemplates test`
Expected: PASS
**Step 5: Commit**
```bash
git add scripts/standard-init src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java
git commit -m "feat: add standard init script templates"
```
### Task 2: Wire deployment-facing config examples
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/config/application.yml.example`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/README.md`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Write the failing test**
Add a test that asserts:
- `application.yml.example` points the four command properties to `/home/tms/bin/*.sh`
- `README.md` documents the repository source path `scripts/standard-init/` and the target deploy path `/home/tms/bin`
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldDocumentStandardInitScriptTemplateDeployment test`
Expected: FAIL because the docs/config are not updated yet.
**Step 3: Write minimal implementation**
Update example config and README with:
- exact deployed command values
- copy/deploy note from `scripts/standard-init/` to `/home/tms/bin`
- required environment variables for DB script
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldDocumentStandardInitScriptTemplateDeployment test`
Expected: PASS
**Step 5: Commit**
```bash
git add config/application.yml.example README.md src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java
git commit -m "docs: wire standard init script template deployment"
```
### Task 3: Final verification
**Files:**
- Verify only
**Step 1: Run focused tests**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest test`
Expected: PASS
**Step 2: Run init test suite**
Run: `mvn -q -Dtest=InitServiceTest,ConfigurableInitStepExecutorTest test`
Expected: PASS
**Step 3: Run compile**
Run: `mvn -q -DskipTests compile`
Expected: PASS
**Step 4: Review git diff**
Run: `git diff -- scripts/standard-init config/application.yml.example README.md src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
Expected: only script templates, config example, README, and tests changed.
@@ -0,0 +1,249 @@
# Standard Post Deploy Completion Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** 补齐标准版初始化在部署文档后半段缺失的动作,包括真实导库、CMSP/CMTP 启动与检查、nginx 配置与启动、WEB 发布。
**Architecture:** 保持“预置层负责基础安装与平台凭据,初始化层负责客户化和运行配置”边界不变。TMS 继续负责生成配置和 SQL 输出物,并在标准版流程中新增后半段步骤:真实导库、应用启动、nginx 配置与启动、WEB 发布、启动后检查。vendor 原始脚本继续只读,优先通过 staging 配置和显式命令编排补齐流程,而不扩散成新的黑盒主导链路。
**Tech Stack:** Java 17, Spring Boot 3.5, Jackson, JUnit 5, Maven, Shell command orchestration
---
### Task 1: 固化标准版后半段步骤编排
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/service/InitService.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/initplan/step-command-profiles.json`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/document/CIPS标准收发器安装部署手册1.0(企业信创版)-V1.3.2.doc`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(间参版)-V1.3.2/document/CIPS标准收发器安装部署手册1.0(金融机构信创版)-V1.3.2.doc`
**Step 1: Write the failing test**
在 `InitServiceTest` 新增标准版步骤断言:
- `ENTERPRISE + RABBITMQ` 包含:`DB_RENDER`、`DB_APPLY`、`DEPLOY_RECEIVER`、`NGINX_CONFIG_APPLY`、`WEB_CONFIG_APPLY`、`START_CMSP_CMTP`、`START_NGINX`、`POST_CHECK`
- `ENTERPRISE + TLQ` 同样包含上述后半段步骤
- `INDIRECT + RABBITMQ`、`INDIRECT + RABBITMQ_TLQ` 同样断言
- 直参版仍不包含这些标准版步骤
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: FAIL,提示步骤未生成
**Step 3: Write minimal implementation**
修改 `InitService.defaultSteps()` 和 `step-command-profiles.json`:
- 在标准版 `DEPLOY_RECEIVER` 后追加:
- `NGINX_CONFIG_APPLY`
- `WEB_CONFIG_APPLY`
- `START_CMSP_CMTP`
- `START_NGINX`
- `POST_CHECK`
- 命令模板统一先挂到 internal step:
- `internal::nginx_config_apply`
- `internal::web_config_apply`
- `internal::start_cmsp_cmtp`
- `internal::start_nginx`
- `internal::post_check`
**Step 4: Run test to verify it passes**
Run: `mvn -q -Dtest=InitServiceTest test`
Expected: PASS
### Task 2: 增加配置面与失败测试
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/config/InitExecutorProperties.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/application.yml`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/config/application.yml.example`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Write the failing tests**
新增执行器测试:
- `shouldApplyStandardNginxConfigFromTemplate`
- `shouldPublishStandardWebAssetsAndOrganizationJson`
- `shouldStartStandardCmspCmtpWithConfiguredCommand`
- `shouldStartStandardNginxWithConfiguredCommand`
- `shouldRunStandardPostCheck`
测试目标:
- `NGINX_CONFIG_APPLY` 会输出替换后的 `nginx.conf`
- `WEB_CONFIG_APPLY` 会生成 `organization.json` 并发布 `front.zip` 内容
- `START_CMSP_CMTP` 会调用预置启动命令或脚本
- `START_NGINX` 会调用 nginx 启动命令
- `POST_CHECK` 会执行配置的检查命令并记录日志
**Step 2: Run test to verify it fails**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest test`
Expected: FAIL,提示 internal step 未实现或配置缺失
**Step 3: Define minimal config surface**
为标准版后半段补齐配置项:
- `standard-nginx-template-path`
- `standard-nginx-target-path`
- `standard-web-front-zip-path`
- `standard-web-work-dir`
- `standard-web-target-dir`
- `standard-web-organization-json-path`
- `standard-app-start-command`
- `standard-nginx-start-command`
- `standard-post-check-command`
说明:
- 真实命令由环境配置注入,TMS 只编排,不硬编码具体 systemd/脚本形态
- 默认值可沿用文档建议路径
**Step 4: Re-run focused test**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest test`
Expected: 仍失败,但仅剩实现缺失
### Task 3: 实现标准版 Nginx 配置落地
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/software/setngx.sh`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/software/nginx.conf`
**Step 1: Add internal step dispatch**
在 `executeInternal()` 新增:
- `case "nginx_config_apply" -> executeStandardNginxConfigApply(task, step)`
**Step 2: Implement minimal behavior**
实现逻辑:
- 仅对标准版生效
- 读取 `standard-nginx-template-path`
- 复用 `buildStandardReplacements()` 替换 `sptp.01app.ip`、`sptp.02app.ip`
- 将渲染结果先输出到 `staging/<taskId>/nginx/nginx.conf`
- LOCAL 模式复制到 `standard-nginx-target-path`
- SIMULATE 模式仅产出 staging 文件
**Step 3: Run focused test**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldApplyStandardNginxConfigFromTemplate test`
Expected: PASS
### Task 4: 实现标准版 WEB 发布
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/toolsh/setweb.sh`
**Step 1: Add internal step dispatch**
在 `executeInternal()` 新增:
- `case "web_config_apply" -> executeStandardWebConfigApply(task, step)`
**Step 2: Implement minimal behavior**
实现逻辑:
- 仅对标准版生效
- 从 `standard-web-front-zip-path` 读取 `front.zip`
- 解压到 `staging/<taskId>/web/`
- 生成 `organization.json`,内容来自 `request.orgNameCn`
- LOCAL 模式将解压产物发布到 `standard-web-target-dir`
- 同步 `organization.json` 到 `standard-web-organization-json-path`
- SIMULATE 模式仅生成 staging 产物
**Step 3: Run focused test**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldPublishStandardWebAssetsAndOrganizationJson test`
Expected: PASS
### Task 5: 实现标准版启动与检查
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/sh/sh/stcmep_cent.sh`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/cmsp/01/start_cmsp.sh`
- Reference: `/Users/waner/Work/CISD/文档/CIPS部署文档/标准收发器安装介质及部署手册(企业信创版)-V1.3.2/cpackage/cmtp/01/start_cmtp.sh`
**Step 1: Add internal step dispatch**
在 `executeInternal()` 新增:
- `case "start_cmsp_cmtp" -> executeStandardStartApp(task, step)`
- `case "start_nginx" -> executeStandardStartNginx(task, step)`
- `case "post_check" -> executeStandardPostCheck(task, step)`
**Step 2: Implement minimal behavior**
实现逻辑:
- `START_CMSP_CMTP`
- 仅对标准版生效
- 执行 `standard-app-start-command`
- `START_NGINX`
- 执行 `standard-nginx-start-command`
- `POST_CHECK`
- 执行 `standard-post-check-command`
- 三者都要求:
- SIMULATE 模式返回模拟成功
- LOCAL 模式走统一 `runCommand` 逻辑
- 日志记录命令、cwd、exit code
**Step 3: Run focused tests**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldStartStandardCmspCmtpWithConfiguredCommand,ConfigurableInitStepExecutorTest#shouldStartStandardNginxWithConfiguredCommand,ConfigurableInitStepExecutorTest#shouldRunStandardPostCheck test`
Expected: PASS
### Task 6: 将 DB_APPLY 收敛为“真实导库”入口
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutor.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/application.yml`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/config/application.yml.example`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Tighten DB_APPLY contract**
修改 `DB_APPLY` 行为:
- 标准版 LOCAL 模式下,如果 `standard-db-apply-command` 为空,直接失败而不是跳过
- 错误信息明确提示“导库命令未配置”
**Step 2: Add test**
新增测试:
- `shouldFailDbApplyWhenStandardDbApplyCommandMissingInLocalMode`
- `shouldExecuteStandardDbApplyCommandWhenConfigured`
**Step 3: Run focused test**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldFailDbApplyWhenStandardDbApplyCommandMissingInLocalMode,ConfigurableInitStepExecutorTest#shouldExecuteStandardDbApplyCommandWhenConfigured test`
Expected: PASS
### Task 7: 文档同步与回归验证
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-09-auto-deploy-refactor.md`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/openapi/cisd-init.openapi.yaml`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Sync plan wording**
将标准版初始化主链路更新为:
- `... -> DB_APPLY -> DEPLOY_RECEIVER -> NGINX_CONFIG_APPLY -> WEB_CONFIG_APPLY -> START_CMSP_CMTP -> START_NGINX -> POST_CHECK -> VERIFY`
**Step 2: Refresh API/Doc examples if needed**
如果接口示例中已有步骤说明,补充新增标准版后半段步骤说明。
**Step 3: Run targeted tests**
Run: `mvn -q -Dtest=InitServiceTest,ConfigurableInitStepExecutorTest test`
Expected: PASS
**Step 4: Run compile verification**
Run: `mvn -q -DskipTests compile`
Expected: PASS
@@ -0,0 +1,114 @@
# TMS Deployment Document Design
**Date:** 2026-03-10
## Goal
维护一份面向现场部署和运维的 TMS 部署手册,覆盖 `/home/tms` 目录结构、jar 与脚本部署、配置文件、初始化依赖、文件上传目录、启动检查与常见故障定位。
## Audience
- 现场运维
- 集成交付人员
- 后端开发/联调人员
## Document Style
文档应以“可执行手册”为目标,而不是概念说明。要求:
- 直接给目录和命令
- 标明哪些内容必须预置,哪些由 TMS 初始化处理
- 区分标准版和直参版相关依赖,但不重复解释业务背景
- 每节都有输入、操作、结果或检查点
## Scope
纳入部署文档:
- TMS 运行环境要求
- `/home/tms` 目录结构
- jar、配置、脚本、上传目录部署
- `application.yml` 关键配置说明
- 标准版初始化脚本 `/home/tms/bin/*.sh` 的作用和依赖
- 文件上传与 `fileId` 模型说明
- TMS 启动、停止、状态检查
- 初始化联调前检查
- 常见故障与排查
不纳入:
- CIPS 标准收发器基础安装手册全文复述
- 密码卡详细使用文档
- OpenAPI 业务接口全集说明
## Proposed Document Location
建议新增正式手册:
- `/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md`
README 保留简版入口,完整运维说明进入该文档。
## Proposed Structure
1. 文档目的与适用范围
2. 环境要求
3. 部署目录结构
4. 部署物清单
5. `/home/tms/config/application.yml` 关键配置
6. `/home/tms/bin` 初始化脚本说明
7. 文件上传与 `fileId` 约定
8. 启动/停止/状态命令
9. 初始化前置检查
10. 常见故障排查
11. 附录:推荐命令与检查项
## Key Content Decisions
### 1. 明确边界
部署文档必须明确:
- TMS 只负责自身部署和 CISD 初始化编排
- 标准收发器、RabbitMQ、TLQ、TiDB、nginx 的基础安装属于预置层
- 初始化阶段负责客户化配置、落位、导库、发布和启动命令调用
### 2. 目录结构固定化
文档采用 `/home/tms` 作为标准路径:
- `/home/tms/tms-framework.jar`
- `/home/tms/config/application.yml`
- `/home/tms/scripts/tms.sh`
- `/home/tms/bin/*.sh`
- `/home/tms/uploads/`
- `/home/tms/logs/`
- `/home/tms/run/`
- `/home/tms/tmp/`
### 3. 配置说明强调初始化相关参数
重点说明:
- `tms.file.storage.upload-base-dir`
- `tms.init.executor.*`
- 标准版脚本命令路径
- RabbitMQ 预置管理员账号
- 日志目录、staging 目录
### 4. 文件上传模型单独成节
必须明确:
- 初始化接口不接收 multipart 文件
- 前端先上传文件,再使用 `fileId`
- 上传目录与初始化执行器解析规则保持一致
### 5. 故障排查按常见现场问题组织
优先纳入:
- jar 无法启动
- `DB_APPLY` 命令为空
- `cpconfig` 找不到
- `fileId` 文件找不到
- RabbitMQ 队列创建失败
- nginx 未启动
- WEB 未发布
## Output Expectation
产出两类文档:
- `README.md` 中保留精简入口
- `docs/deployment/tms-deployment.md` 作为完整部署手册
@@ -0,0 +1,156 @@
# TMS Deployment Document Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Create a production-oriented TMS deployment manual that documents runtime files, directories, scripts, config, upload/fileId flow, and on-host verification for `/home/tms` deployments.
**Architecture:** Keep `README.md` as the short entry point and move the full operational content into a dedicated deployment manual under `docs/deployment/`. Reuse existing runtime scripts and config examples instead of duplicating logic, and align every section with the current init/fileId implementation.
**Tech Stack:** Markdown documentation, existing shell scripts, Spring Boot config examples
---
### Task 1: Create deployment manual skeleton
**Files:**
- Create: `/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/README.md`
**Step 1: Draft the document outline**
Add section headers for:
- environment
- directory layout
- deployment artifacts
- config
- scripts
- file upload/fileId flow
- startup operations
- precheck
- troubleshooting
**Step 2: Review against current repo assets**
Verify each section maps to existing files:
- `scripts/tms.sh`
- `scripts/standard-init/*.sh`
- `config/application.yml.example`
- init/file upload config
**Step 3: Write the initial manual content**
Populate the outline with precise paths and commands using `/home/tms`.
**Step 4: Link README to the new manual**
Keep README concise and add a “see full deployment guide” link.
### Task 2: Document deployment artifacts and directories
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md`
**Step 1: Add directory tree**
Document:
- `/home/tms/tms-framework.jar`
- `/home/tms/config/application.yml`
- `/home/tms/scripts/tms.sh`
- `/home/tms/bin/*.sh`
- `/home/tms/uploads`
- `/home/tms/logs`
- `/home/tms/run`
- `/home/tms/tmp`
**Step 2: Add artifact source mapping**
State where each deployed file comes from in the repo.
**Step 3: Add deployment commands**
Include copy/chmod commands required on CentOS.
### Task 3: Document config and init dependencies
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md`
- Reference: `/Users/waner/Work/CISD/文档/tms-framework/config/application.yml.example`
- Reference: `/Users/waner/Work/CISD/文档/tms-framework/src/main/resources/application.yml`
**Step 1: Document mandatory config items**
Explain required runtime settings:
- security token
- upload directory
- init executor mode
- standard script commands
- staging/log directories
**Step 2: Document standard-init scripts**
Describe purpose and prerequisites of:
- `apply_standard_db.sh`
- `start_standard_apps.sh`
- `start_standard_nginx.sh`
- `check_standard_runtime.sh`
**Step 3: Document credential handling**
Clarify which credentials stay in pre-provisioned env vars instead of `application.yml`.
### Task 4: Document file upload and fileId flow
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md`
**Step 1: Describe upload-first workflow**
State that init APIs do not accept multipart files and only accept `fileId`.
**Step 2: Map init fields to uploaded files**
Document:
- `receiverLicenseFileId`
- `tlqLicenseFileId`
- `cfmqConfigFileId`
- `cfgZipFileId`
**Step 3: Explain storage layout**
Describe `/home/tms/uploads/<fileId>/<originalFilename>` and how the init executor resolves files.
### Task 5: Add operations and troubleshooting sections
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md`
**Step 1: Add start/stop/status commands**
Document `tms.sh` usage and log locations.
**Step 2: Add precheck guidance**
Reference `scripts/cisd_init_precheck.sh` and describe expected pass/fail output.
**Step 3: Add troubleshooting cases**
Document diagnosis steps for:
- `standardDbApplyCommand is blank`
- `cpconfig not found`
- uploaded file not found by `fileId`
- RabbitMQ command/path errors
- WEB/NGINX publish/start issues
### Task 6: Final review
**Files:**
- Verify only
**Step 1: Read the final manual top to bottom**
Check for mismatches against current code/scripts/config.
**Step 2: Review focused diff**
Run: `git diff -- README.md docs/deployment/tms-deployment.md`
Expected: only deployment documentation changes.
@@ -0,0 +1,135 @@
# Controller Internal Convention Removal Design
**Date:** 2026-03-11
## Goal
去掉“非 openapi 接口必须使用 `controller/internal` 包和 `*InternalController` 命名”的项目约定,将内部业务接口控制器统一收敛到中性 `controller` 包和 `*Controller` 类名,同时保持现有 URL、鉴权和 Swagger 暴露行为完全不变。
## Scope
本设计覆盖:
- `controller/internal` -> `controller` 的包路径调整
- `*InternalController` -> `*Controller` 的类名调整
- 测试引用、README、结构说明、命名约定同步更新
本设计不覆盖:
- `/api/**` 与 `/openapi/**` 路径变更
- DTO 包结构调整
- 鉴权规则变更
- `openapi` 控制器命名风格调整
- service/repository 结构重构
## Current State
当前仓库对内部接口有一套强命名约定:
- 内部业务接口通常命名为 `*InternalController`
- 其中部分模块控制器位于 `controller/internal`
- README 明确规定:`Internal API controllers only in */controller/internal`
实际代码状态并不统一:
- `auth`、`device`、`init`、`system` 使用 `controller` 包,但类名仍为 `*InternalController`
- `file` 使用 `controller/internal` 包,类名为 `FileInternalController`
- `sign` 模块同时存在 `controller/internal` 和 `controller/openapi`
这意味着“internal controller”已经被项目文档和部分代码固化,但在包结构上并未完全一致。
## Design Choice
采用:`统一改为 controller + *Controller`
不采用:`只改文档,不改代码`
原因:
- 用户目标是去掉该设定本身,而不是仅仅弱化描述
- 如果只改文档,现有类名和包名仍然持续强化旧约定
不采用:`只改类名,不改包路径`
原因:
- `controller/internal` 目录仍会继续表达旧分层含义
- 无法真正完成约定清理
不采用:`新增一套中性 Controller,保留旧类做代理`
原因:
- 没有兼容性收益
- 会引入重复 Bean 或重复请求映射风险
## Naming Rule After Change
调整后的规则:
- `/api/**` 控制器放在 `modules/*/controller`
- `/openapi/**` 控制器继续放在 `modules/*/controller/openapi`
- 内部控制器类名使用中性 `*Controller`
- 对外接口控制器命名不强制带 `Open` 前缀,但当前已有 `OpenSignController` 可暂时保留
## Class Rename Plan
建议重命名如下:
- `AuthInternalController` -> `AuthController`
- `DeviceInternalController` -> `DeviceController`
- `CryptoCardInternalController` -> `CryptoCardController`
- `InitInternalController` -> `InitController`
- `HealthInternalController` -> `HealthController`
- `InternalSignController` -> `SignController`
- `FileInternalController` -> `FileController`
对应包路径调整:
- `modules/file/controller/internal` -> `modules/file/controller`
- `modules/sign/controller/internal` -> `modules/sign/controller`
其余当前已在 `controller` 包下的类,仅改类名即可。
## Compatibility Boundary
以下内容必须保持不变:
- `@RequestMapping` 路径
- 所有 `/api/v1/**` 路径
- 所有 `/openapi/**` 路径
- `WebMvcConfig` 的拦截规则
- Swagger/OpenAPI 文档访问路径
- 前端、脚本、curl 示例调用路径
也就是说,这次是纯 Java 命名与项目约定调整,不是 API 行为调整。
## Security Impact
鉴权策略不变:
- `/api/**` 继续走内部 token 拦截器
- `/openapi/**` 继续走 openapi 签名拦截器
因为拦截器是基于 URL 前缀,而不是控制器类名或包名,所以控制器重命名不会影响运行时鉴权行为。
## Testing Strategy
需要验证三类内容:
1. 编译与导入
- 测试类中的 import、`standaloneSetup(...)`、构造器引用都更新完成
2. 运行时边界不变
- 控制器路径不变
- 鉴权拦截配置不变
3. 文档约定更新
- README 中模块结构和 API Boundary Rules 不再要求 `controller/internal`
- 示例结构改为 `controller + controller/openapi`
## Risks
1. 类名和文件路径同时重命名,容易遗漏测试 import 或文档引用。
2. 如果存在基于类名扫描或人工 grep 的脚本,需要同步更新引用。
3. `sign` 与 `file` 模块同时涉及包移动,若未同步修改 package 声明会导致编译失败。
## Recommendation
先做最小一致性改造:
- 统一内部控制器类名为 `*Controller`
- 去掉 `controller/internal` 包
- 更新 README、测试和约定文档
不在这一轮处理:
- `openapi` 控制器风格统一
- DTO 包命名统一
- 额外的模块结构重构
@@ -0,0 +1,193 @@
# Controller Internal Convention Removal Implementation Plan
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
**Goal:** Remove the project-wide `controller/internal` and `*InternalController` convention for non-openapi APIs while keeping all request paths, authentication behavior, and Swagger exposure unchanged.
**Architecture:** Rename internal API controllers to neutral `*Controller` names and place them under `modules/*/controller`, but leave all `@RequestMapping` values and `WebMvcConfig` interceptor rules untouched. Update tests and README so the repository no longer encodes the old naming convention as a rule.
**Tech Stack:** Spring Boot MVC, springdoc-openapi, JUnit 5, MockMvc
---
### Task 1: Lock down URL and documentation invariants with tests
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java`
- Test: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java`
**Step 1: Write the failing tests**
Adjust or add tests that assert:
- file upload/query endpoints remain `/api/v1/files/**`
- Swagger/OpenAPI docs still mention the same URLs
- README no longer contains the hard rule `Internal API controllers only in */controller/internal`
Do not rename production classes yet.
**Step 2: Run tests to verify they fail**
Run: `mvn -q -Dtest=FileInternalControllerTest,ConfigurableInitStepExecutorTest#shouldDocumentStandardInitScriptTemplateDeployment test`
Expected: FAIL because tests will still reference old controller names and README still encodes the old convention.
**Step 3: Keep the tests minimal**
Limit assertions to:
- unchanged routes
- removed convention wording
- continued `/home/tms/bin` deployment doc assertions already covered in existing tests
**Step 4: Run tests again to confirm stable RED**
Run: `mvn -q -Dtest=FileInternalControllerTest,ConfigurableInitStepExecutorTest#shouldDocumentStandardInitScriptTemplateDeployment test`
Expected: FAIL for the intended naming/documentation reasons only.
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 2: Rename file and sign internal controllers first
**Files:**
- Move/Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/file/controller/internal/FileInternalController.java`
- Move/Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/sign/controller/internal/InternalSignController.java`
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java`
**Step 1: Write the minimal rename**
Rename and relocate:
- `FileInternalController` -> `FileController`
- `InternalSignController` -> `SignController`
Move them into `modules/*/controller`.
Keep:
- package-level Spring scanning working
- all request mappings unchanged
**Step 2: Update tests/imports**
Update MockMvc standalone setup and imports to use new class names.
**Step 3: Run focused tests**
Run: `mvn -q -Dtest=FileInternalControllerTest test`
Expected: PASS
**Step 4: Review for accidental URL changes**
Check that no `@RequestMapping` strings changed.
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 3: Rename the remaining internal controllers
**Files:**
- Move/Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/auth/controller/AuthInternalController.java`
- Move/Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/device/controller/DeviceInternalController.java`
- Move/Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/device/controller/CryptoCardInternalController.java`
- Move/Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/init/controller/InitInternalController.java`
- Move/Modify: `/Users/waner/Work/CISD/文档/tms-framework/src/main/java/com/cisd/tms/modules/system/controller/HealthInternalController.java`
- Modify: imports/usages that reference those class names
**Step 1: Apply the rename set**
Rename:
- `AuthInternalController` -> `AuthController`
- `DeviceInternalController` -> `DeviceController`
- `CryptoCardInternalController` -> `CryptoCardController`
- `InitInternalController` -> `InitController`
- `HealthInternalController` -> `HealthController`
Keep each class in `modules/*/controller`.
**Step 2: Update all direct references**
Use `rg` to find and fix:
- imports
- JavaDoc mentions
- comments that name concrete classes
**Step 3: Run focused compile/test checks**
Run: `mvn -q -Dtest=InitServiceTest,TmsApplicationTests test`
Expected: PASS
**Step 4: Run compile if needed**
Run: `mvn -q -DskipTests compile`
Expected: PASS
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 4: Remove the repository-wide convention from README and docs
**Files:**
- Modify: `/Users/waner/Work/CISD/文档/tms-framework/README.md`
- Modify: any design/plan/doc files that are actively used and explicitly enforce `controller/internal`
**Step 1: Rewrite the structure guidance**
Update README so it says:
- default module layout is `controller + service + repository + entity + dto`
- external APIs may additionally use `controller/openapi`
Remove the hard rule:
- `Internal API controllers only in */controller/internal`
Replace it with a neutral rule:
- `/api/**` controllers live under `controller`
- `/openapi/**` controllers live under `controller/openapi`
**Step 2: Update structure tree examples**
Replace `controller/internal` entries in the README tree with `controller`.
**Step 3: Run focused documentation regression**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldDocumentStandardInitScriptTemplateDeployment test`
Expected: PASS
**Step 4: Manual diff review**
Run: `git diff -- README.md`
Expected: naming and structure guidance changes only, no API path changes.
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.
### Task 5: Final verification
**Files:**
- Verify only
**Step 1: Run controller-related tests**
Run: `mvn -q -Dtest=FileInternalControllerTest,InitServiceTest,TmsApplicationTests test`
Expected: PASS
**Step 2: Run documentation regression tests**
Run: `mvn -q -Dtest=ConfigurableInitStepExecutorTest#shouldDocumentStandardInitScriptTemplateDeployment test`
Expected: PASS
**Step 3: Run compile**
Run: `mvn -q -DskipTests compile`
Expected: PASS
**Step 4: Review focused diff**
Run: `git diff -- src/main/java/com/cisd/tms/modules README.md src/test/java/com/cisd/tms/modules/file/FileInternalControllerTest.java src/test/java/com/cisd/tms/modules/init/executor/ConfigurableInitStepExecutorTest.java docs/plans/2026-03-11-controller-internal-convention-removal-design.md docs/plans/2026-03-11-controller-internal-convention-removal-plan.md`
Expected: only controller renames, import updates, and documentation rule changes.
**Step 5: Commit**
Skip commit in the current dirty workspace per user instruction.