# TMS Framework Single-process TMS monolith scaffold built with: - JDK 17 - Spring Boot 3.5.x - MyBatis-Plus - TiDB (MySQL driver) - Swagger (springdoc-openapi) ## Quick Start ```bash cd tms-framework mvn spring-boot:run ``` ## Jar 包部署(外置配置) 完整部署手册: - [docs/deployment/tms-deployment.md](/Users/waner/Work/CISD/文档/tms-framework/docs/deployment/tms-deployment.md) 1. 构建 jar 包: ```bash cd tms-framework mvn -q -DskipTests package cp target/tms-framework-*.jar /home/tms/tms-framework.jar ``` 2. 在 CentOS 上准备部署目录: ```bash sudo mkdir -p /home/tms/{bin,config,scripts,logs,run} sudo mkdir -p /home/tms/bin/resource-restore sudo chown -R "$(whoami)":"$(whoami)" /home/tms cp scripts/tms.sh /home/tms/scripts/tms.sh cp scripts/standard-init/*.sh /home/tms/bin/ cp scripts/resource-restore/*.sh /home/tms/bin/resource-restore/ cp config/application.yml.example /home/tms/config/application.yml chmod +x /home/tms/bin/*.sh chmod +x /home/tms/bin/resource-restore/*.sh chmod +x /home/tms/scripts/tms.sh ``` 3. 启动 / 停止 / 状态: ```bash /home/tms/scripts/tms.sh start /home/tms/scripts/tms.sh status /home/tms/scripts/tms.sh stop ``` 说明: - 脚本默认 `APP_HOME=/home/tms`,并通过 `--spring.config.additional-location=optional:file:/config/` 从 `/home/tms/config/` 读取外部配置。 - 默认要求 `/home/tms/config/application.yml` 存在。 - 脚本不再强制指定 profile;默认按 Spring 配置文件自身规则解析,可通过 `SPRING_PROFILES_ACTIVE=dev /home/tms/scripts/tms.sh start` 显式覆盖。 - 可通过 `JAR_PATH=/home/tms/tms-framework.jar` 覆盖 jar 路径。 - 如果部署路径不是 `/home/tms`,使用 `APP_HOME=/your/path /your/path/scripts/tms.sh start`。 - 标准 CISD 初始化辅助脚本位于 `scripts/standard-init/`,部署时需复制到 `/home/tms/bin/`。 - 资源恢复辅助脚本位于 `scripts/resource-restore/`,部署时需复制到 `/home/tms/bin/resource-restore/`。 - `apply_standard_db.sh` 依赖预置环境变量,例如 `DB_USER`、`DB_PASSWORD`,不要直接写入 `application.yml`。 - 运行目录结构、配置项说明、文件上传 `fileId` 流程和故障排查,请查看上面的完整部署手册。 运行时建议: - 本地构建和测试统一使用 JDK 17,与项目和 CI 运行时保持一致。 Open: - Swagger UI: http://localhost:8080/swagger-ui.html - Internal API docs JSON: http://localhost:8080/v3/api-docs/internal-api - Runtime-generated Swagger/OpenAPI docs are the source of truth for `/api/**`. - Internal health API: `GET /api/v1/device/status` - Internal sign preview API: `POST /api/v1/sign/preview` - External sign API: `POST /openapi/v1/sign/signature` - Init template API: `GET /api/v1/init/template` - Init preview API: `POST /api/v1/init/preview` - Current init config API: `GET /api/v1/init/config` - Reset preview API: `POST /api/v1/init/reset/preview` - Reset create task API: `POST /api/v1/init/reset/tasks` - Reset execute API: `POST /api/v1/init/reset/tasks/{taskId}/execute` - Auth login API: `POST /api/v1/auth/login` - Compat password login API: `POST /api/v1/auth/password-login` - Compat UKey login API: `POST /api/v1/auth/ukey-login` - Compat UKey random API: `GET /api/v1/auth/ukey-login/randoms` - UKey binding issue-sign API: `POST /api/v1/auth/roles/{roleCode}/ukeys/issue-sign` - UKey binding API: `POST /api/v1/auth/roles/{roleCode}/ukeys/bind` - Device info API: `GET /api/v1/device/info` - Device profile API: `GET /api/v1/device/profile` - Device runtime status API: `GET /api/v1/device/runtime-status` - Upgrade package upload API: `POST /api/v1/upgrade-packages` - Upgrade preview API: `POST /api/v1/upgrades/previews` - Upgrade create task API: `POST /api/v1/upgrades` - Upgrade execute API: `POST /api/v1/upgrades/{taskId}/execute` - Upgrade list API: `GET /api/v1/upgrades` - PCIe crypto count API: `GET /api/v1/device/crypto/device-count` - PCIe crypto HMAC API: `POST /api/v1/device/crypto/hmac` ## CISD Reset 最小调用顺序: - `POST /api/v1/init/reset/preview` - `POST /api/v1/init/reset/tasks` - `POST /api/v1/init/reset/tasks/{taskId}/execute` - `GET /api/v1/init/reset/tasks/{taskId}` - `GET /api/v1/init/reset/tasks/{taskId}/steps` - `GET /api/v1/init/reset/tasks/{taskId}/steps/{stepNo}/log` 当前支持范围: - 仅支持设备预置产品类型为 `ENTERPRISE` 或 `INDIRECT` - `DIRECT` 当前明确不支持 reset 请求说明: - reset 接口不再要求前端重复提交机构号、MQ 类型和 RabbitMQ 通道用户 - 后端会自动读取“最近一次成功初始化任务”的快照,提取 `orgCode`、`mqType`、`channelUsername` - 如果当前设备没有有效初始化快照,reset 预检和任务创建会直接失败 设备状态接口: - `GET /api/v1/device/status` - 返回字段 `initState` - `UNINITIALIZED`: 当前没有有效初始化快照 - `INITIALIZING`: 初始化任务正在执行 - `INITIALIZED`: 当前设备已初始化 - `RESETTING`: 重置任务正在执行 - 前端仅根据 `initState` 判断展示初始化页、已初始化页或执行中页面 当前初始化配置展示接口: - `GET /api/v1/init/config` - 数据来源固定为最新一次成功初始化任务快照 - 只返回机构信息、部署信息、中间件信息和节点/签名核心字段 - 只用于展示,不用于编辑 当前 reset 实际会做的事情: - 停止 `CMSP/CMTP` - 删除数据库 `CMEP` - 删除数据库 `orgCode` - 删除 RabbitMQ 客户化账号、`/RQ` 权限、客户化队列 - 停止 RabbitMQ 进程 - 删除 TLQ license 文件 - 清理当前 reset 任务的 staging 目录 当前 reset 不做的事情: - 不回滚 `cpconfig.cfg` - 不删除 nginx 配置和已发布前端目录 - 不回滚应用配置文件中的 RabbitMQ 账号密码 - 不删除标准安装介质目录 运维前置条件: - `scripts/standard-init/*.sh` 已部署到 `/home/tms/bin/` - `/home/tms/bin/stop_standard_apps.sh` - `/home/tms/bin/stop_standard_rabbitmq.sh` - `/home/tms/bin/apply_standard_db.sh` - `tms.init.executor.standard-db-username/password` 已正确配置 - `tms.init.executor.rabbitmq-ctl-command` 指向可执行的 `rabbitmqctl` - 运行时 Swagger 文档以 `http://:8080/swagger-ui.html` 和 `http://:8080/v3/api-docs/internal-api` 为准 ## Offline Upgrade 最小调用顺序: - `POST /api/v1/upgrade-packages` - `POST /api/v1/upgrades/previews` - `POST /api/v1/upgrades` - `POST /api/v1/upgrades/{taskId}/execute` - `POST /api/v1/upgrades/{taskId}/rollback` - `GET /api/v1/upgrades` - `GET /api/v1/upgrades/{taskId}` - `GET /api/v1/upgrades/{taskId}/log` 当前支持范围: - 仅支持离线升级 - 当前支持任务类型: - `TMS` - `RECEIVER` - `FIRMWARE` - 当前不支持: - 在线升级 - `CVE` / 操作系统补丁升级 当前流程: - 先上传离线升级包,复用现有文件上传能力,得到 `fileId` - 后端基于 `fileId` 解析升级包并做预检 - 预检结果返回 `taskType`、`productType`、当前版本、目标版本和版本变化提示 - 用户确认后创建升级任务 - 调用执行接口后,任务异步进入后台执行 - 升级失败后,如升级包提供 `rollback` 入口,可手工调用回滚接口 - 前端通过列表、详情和日志接口轮询任务状态 当前升级包要求: - 外层为 zip 包 - 至少包含: - `manifest.json` - `signature.sig` - `payload/` 下按需包含: - `app/` - `web/dist/` - `config/` - `sql/` - `firmware/` - `scripts/` - 外层升级包实际包含的是 `payload.zip`,`payload.zip` 内部再包含上述 `payload/` 目录 - `signature.sig` 需要能被配置的 PEM 公钥使用 `SM3withSM2` 软验签通过 - 服务端需要配置 `tms.upgrade.signature-public-key-pem-path`(公钥 PEM 文件路径) - `manifest.json` 当前要求包含: - `packageId` - `taskType` - `productType` - `version` - `minCompatibleVersion` - `description` - `entrypoints.execute` - `payloadSm3` - 可选 `entrypoints.precheck` - 可选 `entrypoints.verify` - 可选 `entrypoints.rollback` - `payloadSm3` 是整个 `payload.zip` 文件的 `SM3` 摘要;后端验签 `manifest.json` 后,会校验 `payload.zip` 摘要并解压出 `payload/` 供脚本执行 当前执行规则: - 同一时刻只允许一个升级任务处于 `RUNNING` - 不允许目标版本低于当前版本 - 不满足最小兼容版本时拒绝升级 - `execute.sh` 必填,`precheck.sh`、`verify.sh`、`rollback.sh` 可选 - 执行顺序为:`precheck -> execute -> verify` - `TMS` 自升级包内脚本第一版不应直接 `stop/start` 当前 TMS;推荐只完成文件准备,由后端在写入终态和日志后异步触发 `/home/tms/scripts/tms.sh restart` - `FIRMWARE` 不增加额外后端流程,具体固件刷写、重启、恢复提示由包内脚本负责 - 回滚不自动触发,需要调用回滚接口 - `TMS`、`RECEIVER` 升级成功后会更新 `tms_device_software_version`;`FIRMWARE` 暂不维护版本表 ## Resource Backup / Restore 最小调用顺序: - `POST /api/v1/resource-backups` - `GET /api/v1/resource-backups/{taskId}` - `GET /api/v1/resource-backups/{taskId}/download` - `POST /api/v1/resource-restores/precheck` - `POST /api/v1/resource-restores` - `GET /api/v1/resource-restores/{taskId}` - `GET /api/v1/resource-restores/{taskId}/steps` - `GET /api/v1/resource-restores/{taskId}/steps/{stepNo}/log` 前后端字段、状态枚举和联调流程见 `docs/openapi/resource-backup-restore-frontend-integration.md`。 当前实现边界: - 资源备份包输出为 `.tmsbak`,包内包含 `manifest.json`、`envelope.json`、`payload.enc`、`signature.sig` - 当前第一版备份/恢复只覆盖最小资源集: - `TMS_CONFIG` - `TMS_DB` - `CMEP_DB` - `CP_CONFIG` - `RECEIVER_LICENSE` - `MQ_REPLAY` - 预检阶段只做包头解析、指纹匹配和验签,不提前解密完整 payload - 恢复任务创建时 Java 完成验签、PCIe 解密、payload 展开和恢复路径白名单校验 - Java 会生成 shell 友好的 `restore-files.tsv`、`restore-databases.tsv`、`restore-mq.tsv` - 创建恢复任务后启动 `apply-resource-backup.sh --work-dir `,由 shell 执行停服务、文件覆盖、SQL 导入、MQ replay、起服务和健康检查 - shell 侧状态写入 `status.json`,日志写入 `restore.log` - `FILE` 回写 manifest 明确声明的配置/License 文件 - `DATABASE` 恢复: - `db/TMS.sql` - `db/CMEP.sql`(包内存在时) - `MQ_REPLAY` 通过 `replay-mq.sh` 消费 `mq/mq-restore-context.json`,也可用 `MQ_REPLAY_COMMAND` 委派给现场脚本 - Java 启动恢复脚本前会在工作目录生成 `restore-env.sh`,传递数据库连接、恢复脚本路径、MQ replay 脚本路径和健康检查配置 关键配置: - `tms.backup.output-dir` - `tms.backup.precheck-store-dir` - `tms.backup.restore-task-root-dir` - `tms.backup.tms-script-path` - `tms.backup.restore-apply-script-path` - `tms.backup.allowed-restore-roots` - `tms.backup.mysqldump-path` - `tms.backup.mysql-path` - `tms.backup.restore-db-script-path` - `tms.backup.mq-replay-script-path` - `tms.backup.tms-database-name` - `tms.backup.cmep-database-name` - `tms.backup.health-check-url` - `tms.backup.health-check-timeout-seconds` 恢复前置条件: - LMK、IK、数据存储加密密钥对、数据真实性保护密钥对需先通过 UKey 恢复 - `/home/tms/bin/resource-restore/apply-resource-backup.sh`、`restore-db.sh`、`replay-mq.sh` 必须已部署并可执行 - `mysql` / `mysqldump` 客户端必须可用 当前明确不在第一版恢复范围内: - nginx 配置 - `organization.json` - 已发布 web 静态资源 - `/home/tms/uploads` - 机构库 - 在线恢复 / 增量恢复 / 回滚 - 升级执行日志统一写入 `tms.upgrade.log-dir` 联调清单: - [资源备份恢复 V1 联调清单](/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-04-18-resource-backup-restore-v1-checklist.md) 当前配置项: - `tms.upgrade.staging-root-dir` - `tms.upgrade.log-dir` - `tms.upgrade.signature-public-key-pem-path` 升级包规范见: - [2026-03-19-upgrade-package-spec.md](/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-19-upgrade-package-spec.md) - [标准收发器升级包最小样例](/Users/waner/Work/CISD/文档/tms-framework/docs/examples/upgrade-package/standard-app/README.md) - [离线升级包预检联调清单与示例](/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-19-upgrade-preview-integration-guide.md) ## Architecture (Monolith + Modular) - One deployable Spring Boot application. - Module-first packaging under `modules/*`. - Default module layout: `controller + service + repository + entity + dto`. - `sign` module has extra `controller/openapi`, `dto/openapi`, and `support`. - Cross-cutting concerns moved to top-level `security` and `integration`. ## Project Structure ```text src/main/java/com/cisd/tms ├── TmsApplication.java ├── common │ ├── api │ ├── config │ │ └── properties │ ├── constant │ ├── enums │ ├── exception │ └── util ├── infrastructure │ └── persistence │ ├── entity │ ├── mapper │ └── mybatis ├── integration │ ├── cips │ ├── mq │ ├── crypto │ └── file ├── security │ ├── internal │ └── openapi └── modules ├── system │ ├── controller │ ├── service │ └── dto ├── sign │ ├── controller │ ├── controller/openapi │ ├── service │ ├── dto/internal │ ├── dto/openapi │ ├── support │ ├── repository │ └── entity ├── init ├── auth ## Auth Compat 当前仓库只包含后端认证接口,不包含登录页前端工程。 兼容旧管理端的登录调用说明见: - [2026-03-23-auth-compat-integration-guide.md](/Users/waner/Work/CISD/文档/tms-framework/docs/plans/2026-03-23-auth-compat-integration-guide.md) ├── device ├── upgrade ├── cert ├── key ├── audit ├── backup └── activation ``` ```text src/main/resources ├── application.yml ├── application-dev.yml ├── application-prod.yml ├── mapper │ ├── init/InitTaskMapper.xml │ ├── auth/AuthUserMapper.xml │ └── device/DeviceNodeMapper.xml └── db/migration └── V1__init_auth_device_tables.sql ``` ## API Boundary Rules - `/api/**` controllers live under `controller`. - External API controllers only in `*/controller/openapi`, path prefix `/openapi/**`. - Internal and external DTOs are separated. - Cross-module calls must go through `service`, not `repository`. - Internal token interceptor exclusions: `/api/v1/device/status`, `/api/v1/auth/login`. ## Auth Configuration ```yaml tms: security: internal-token: ${TMS_INTERNAL_TOKEN:change-me-internal-token} openapi: timestamp-skew-seconds: 300 clients: demo-app: ${TMS_OPENAPI_DEMO_SECRET:change-me-openapi-secret} ``` ## Crypto Card Configuration ```yaml tms: crypto-card: enabled: ${TMS_CRYPTO_CARD_ENABLED:false} mode: ${TMS_CRYPTO_CARD_MODE:MOCK} # MOCK / JNA vendor-lib-path: ${TMS_CRYPTO_VENDOR_LIB_PATH:/home/tms/libs/libsdf_ukey_syd1408-x64.so.1.0.0} vendor-lib-name: ${TMS_CRYPTO_VENDOR_LIB_NAME:sdf_ukey_syd1408} ``` - Internal PCIe debug APIs (strong-typed service): - `GET /api/v1/device/crypto/device-count` - `GET /api/v1/device/crypto/device-conf` - `GET /api/v1/device/crypto/device-info` - `GET /api/v1/device/crypto/random?length=16` - `POST /api/v1/device/crypto/self-test` - `POST /api/v1/device/crypto/hmac` - `POST /api/v1/device/crypto/digest` - `POST /api/v1/device/crypto/encrypt/plain` - `POST /api/v1/device/crypto/decrypt/plain` - `POST /api/v1/device/crypto/encrypt/kek` - `POST /api/v1/device/crypto/decrypt/kek` - `POST /api/v1/device/crypto/mac/plain` - `POST /api/v1/device/crypto/file/create` - `POST /api/v1/device/crypto/file/write` - `POST /api/v1/device/crypto/file/read` - `POST /api/v1/device/crypto/file/delete` - `POST /api/v1/device/crypto/kek/generate` - `GET /api/v1/device/crypto/kek/status?keyIndex=1` - `GET /api/v1/device/crypto/lmk/seed-mac` - `POST /api/v1/device/crypto/std/keypair/rsa` - `POST /api/v1/device/crypto/std/keypair/ecc` - `POST /api/v1/device/crypto/envelope/exchange/rsa` - `POST /api/v1/device/crypto/envelope/exchange/ecc` - `POST /api/v1/device/crypto/agreement/data-key/ecc` - `POST /api/v1/device/crypto/agreement/session-key/ecc` ## PCIe Crypto Unified Wrapper (JNA) The project keeps JNA native mappings for PCIe card `SDF/SDFE` interfaces from `PCIE密码卡应用接口说明书 V1.02`, and provides strong-typed service APIs via `com.cisd.tms.integration.crypto.pcie.service.PcieCryptoService`. ```yaml tms: crypto-card: enabled: ${TMS_CRYPTO_CARD_ENABLED:false} mode: ${TMS_CRYPTO_CARD_MODE:JNA} # MOCK / JNA vendor-lib-path: ${TMS_CRYPTO_VENDOR_LIB_PATH:/home/tms/libs/libsdf_ukey_syd1408-x64.so.1.0.0} vendor-lib-name: ${TMS_CRYPTO_VENDOR_LIB_NAME:sdf_ukey_syd1408} ``` - JNA native mapping: `com.cisd.tms.integration.crypto.pcie.jna.PcieNativeLibrary` - JNA implementation: `com.cisd.tms.integration.crypto.pcie.service.JnaPcieCryptoService` - Mock fallback: `com.cisd.tms.integration.crypto.pcie.service.MockPcieCryptoService` ### OpenAPI Signature Rules - Headers: `X-App-Id`, `X-Timestamp`, `X-Nonce`, `X-Signature` - Canonical string: `appId + "\\n" + timestamp + "\\n" + nonce` - Signature algorithm: `HMAC-SHA256` with app secret, lowercase hex - Replay protection: nonce one-time in time window ## Build And Test ```bash mvn -q -DskipTests compile mvn -q test ``` ## PCIe Real-Card Smoke - Checklist: `docs/plans/2026-02-28-pcie-realcard-smoke-checklist.md` - Script template: `scripts/pcie_realcard_smoke.sh` Example: ```bash export BASE_URL=http://127.0.0.1:8080 export INTERNAL_TOKEN=change-me-internal-token export ALG_SM3=1 export ALG_SM4_ECB=1025 ./scripts/pcie_realcard_smoke.sh ``` - CI is pinned to JDK 17 via `.github/workflows/ci.yml`. - Maven Surefire preloads Mockito javaagent to avoid dynamic self-attach failures on newer JDKs. ## Current Status - Structure refactored to lightweight monolith modules. - Internal and external API entry points separated. - Basic auth interceptors for internal/openapi are in place. - `init/auth/device/sign/system` modules have runnable skeleton controllers and services. - `init/auth/device` modules include mapper+xml+repository-impl+DDL skeleton for TiDB.