feat:CISD初始化
This commit is contained in:
@@ -0,0 +1,907 @@
|
||||
{
|
||||
"openapi": "3.0.3",
|
||||
"info": {
|
||||
"title": "TMS CISD Init Internal API",
|
||||
"version": "1.0.0",
|
||||
"description": "CISD 一体机初始化相关内部接口(含设备状态接口)。\n返回体统一为 ApiResponse 包装结构。\n"
|
||||
},
|
||||
"servers": [
|
||||
{
|
||||
"url": "http://127.0.0.1:8080",
|
||||
"description": "Local"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "Device",
|
||||
"description": "设备信息与状态"
|
||||
},
|
||||
{
|
||||
"name": "Init",
|
||||
"description": "CISD 初始化任务"
|
||||
}
|
||||
],
|
||||
"security": [
|
||||
{
|
||||
"InternalTokenAuth": [
|
||||
|
||||
]
|
||||
}
|
||||
],
|
||||
"paths": {
|
||||
"/api/v1/device/info": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "获取设备信息",
|
||||
"operationId": "getDeviceInfo",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseDeviceInfoResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/device/status": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "获取设备状态(含预制版本信息)",
|
||||
"operationId": "getDeviceStatus",
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseDeviceInfoResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/device/restart": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Device"
|
||||
],
|
||||
"summary": "重启设备",
|
||||
"operationId": "restartDevice",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "X-User",
|
||||
"in": "header",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "操作人"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseDeviceActionResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/init/template": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Init"
|
||||
],
|
||||
"summary": "获取初始化模板元信息",
|
||||
"operationId": "getInitTemplate",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "version",
|
||||
"in": "query",
|
||||
"required": false,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "兼容参数,后端按预置版本返回"
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseInitPlanTemplateResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/init/preview": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Init"
|
||||
],
|
||||
"summary": "初始化预检(不落库)",
|
||||
"operationId": "previewInitPlan",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InitPreviewRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseInitPreviewResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/init/tasks": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Init"
|
||||
],
|
||||
"summary": "创建初始化任务",
|
||||
"operationId": "createInitTask",
|
||||
"requestBody": {
|
||||
"required": true,
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/InitPreviewRequest"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseInitCreateTaskResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/init/tasks/{taskId}": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Init"
|
||||
],
|
||||
"summary": "查询任务详情",
|
||||
"operationId": "getInitTaskDetail",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "taskId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseInitTaskDetailResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/init/tasks/{taskId}/steps": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Init"
|
||||
],
|
||||
"summary": "查询任务步骤",
|
||||
"operationId": "getInitTaskSteps",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "taskId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseInitTaskStepResponseList"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/init/tasks/{taskId}/steps/{stepNo}/log": {
|
||||
"get": {
|
||||
"tags": [
|
||||
"Init"
|
||||
],
|
||||
"summary": "查询步骤日志",
|
||||
"operationId": "getInitTaskStepLog",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "taskId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "stepNo",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseInitTaskStepLogResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/api/v1/init/tasks/{taskId}/execute": {
|
||||
"post": {
|
||||
"tags": [
|
||||
"Init"
|
||||
],
|
||||
"summary": "执行初始化任务",
|
||||
"operationId": "executeInitTask",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "taskId",
|
||||
"in": "path",
|
||||
"required": true,
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "OK",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/ApiResponseInitTaskExecuteResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"components": {
|
||||
"securitySchemes": {
|
||||
"InternalTokenAuth": {
|
||||
"type": "apiKey",
|
||||
"in": "header",
|
||||
"name": "X-Internal-Token"
|
||||
}
|
||||
},
|
||||
"schemas": {
|
||||
"ApiResponseBase": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"success": {
|
||||
"type": "boolean",
|
||||
"example": true
|
||||
},
|
||||
"code": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"example": 200
|
||||
},
|
||||
"msg": {
|
||||
"type": "string",
|
||||
"example": "success"
|
||||
},
|
||||
"timestamp": {
|
||||
"type": "integer",
|
||||
"format": "int64",
|
||||
"example": 1740902400000
|
||||
},
|
||||
"traceId": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
"nullable": true
|
||||
},
|
||||
"details": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"ApiResponseDeviceInfoResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/DeviceInfoResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseDeviceActionResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/DeviceActionResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseInitPlanTemplateResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/InitPlanTemplateResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseInitPreviewResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/InitPreviewResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseInitCreateTaskResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/InitCreateTaskResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseInitTaskDetailResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/InitTaskDetailResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseInitTaskStepResponseList": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/InitTaskStepResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseInitTaskStepLogResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/InitTaskStepLogResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"ApiResponseInitTaskExecuteResponse": {
|
||||
"allOf": [
|
||||
{
|
||||
"$ref": "#/components/schemas/ApiResponseBase"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"data": {
|
||||
"$ref": "#/components/schemas/InitTaskExecuteResponse"
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"DeviceInfoResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"deviceId": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
},
|
||||
"presetProductType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ENTERPRISE",
|
||||
"INDIRECT",
|
||||
"DIRECT"
|
||||
]
|
||||
},
|
||||
"presetVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"presetSource": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"DeviceActionResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"action": {
|
||||
"type": "string"
|
||||
},
|
||||
"accepted": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"operator": {
|
||||
"type": "string"
|
||||
},
|
||||
"acceptedAt": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitPlanTemplateResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"presetProductType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ENTERPRISE",
|
||||
"INDIRECT",
|
||||
"DIRECT"
|
||||
]
|
||||
},
|
||||
"presetVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"supportedVersions": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"templatePath": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitPreviewRequest": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"orgCodeType",
|
||||
"orgCode",
|
||||
"orgNameCn",
|
||||
"deployMode",
|
||||
"nodes",
|
||||
"mq",
|
||||
"licenses"
|
||||
],
|
||||
"properties": {
|
||||
"orgCodeType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"BIC",
|
||||
"CIPSID",
|
||||
"LEI"
|
||||
]
|
||||
},
|
||||
"orgCode": {
|
||||
"type": "string",
|
||||
"maxLength": 32
|
||||
},
|
||||
"orgNameCn": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
},
|
||||
"orgNameEn": {
|
||||
"type": "string",
|
||||
"maxLength": 256
|
||||
},
|
||||
"deployMode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"SINGLE",
|
||||
"DUAL",
|
||||
"QUAD"
|
||||
]
|
||||
},
|
||||
"nodes": {
|
||||
"$ref": "#/components/schemas/InitPreviewRequestNodes"
|
||||
},
|
||||
"mq": {
|
||||
"$ref": "#/components/schemas/InitPreviewRequestMq"
|
||||
},
|
||||
"licenses": {
|
||||
"$ref": "#/components/schemas/InitPreviewRequestLicenses"
|
||||
},
|
||||
"signServer": {
|
||||
"$ref": "#/components/schemas/InitPreviewRequestSignServer"
|
||||
},
|
||||
"directTlq": {
|
||||
"$ref": "#/components/schemas/InitPreviewRequestDirectTlqConfig"
|
||||
}
|
||||
},
|
||||
"description": "初始化请求体。部分字段为条件必填:\n- DIRECT + RABBITMQ_TLQ 需提供 directTlq\n- DIRECT 需提供 signServer 与 licenses.cfgZipFileId\n- TLQ 模式需提供 mq.tlqLicenseFileId\n- RABBITMQ_CFMQ 需提供 mq.cfmqConfigFileId\n"
|
||||
},
|
||||
"InitPreviewRequestNodes": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"node01Ip"
|
||||
],
|
||||
"properties": {
|
||||
"node01Ip": {
|
||||
"type": "string",
|
||||
"pattern": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
},
|
||||
"node02Ip": {
|
||||
"type": "string",
|
||||
"pattern": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
},
|
||||
"node03Ip": {
|
||||
"type": "string",
|
||||
"pattern": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
},
|
||||
"node04Ip": {
|
||||
"type": "string",
|
||||
"pattern": "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitPreviewRequestMq": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"mqType",
|
||||
"channelUsername",
|
||||
"channelPassword"
|
||||
],
|
||||
"properties": {
|
||||
"mqType": {
|
||||
"type": "string",
|
||||
"description": "ENTERPRISE/INDIRECT: RABBITMQ|TLQ; DIRECT: RABBITMQ_TLQ|RABBITMQ_CFMQ"
|
||||
},
|
||||
"channelUsername": {
|
||||
"type": "string",
|
||||
"maxLength": 32
|
||||
},
|
||||
"channelPassword": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
},
|
||||
"tlqLicenseFileId": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
},
|
||||
"cfmqConfigFileId": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitPreviewRequestLicenses": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"receiverLicenseFileId"
|
||||
],
|
||||
"properties": {
|
||||
"receiverLicenseFileId": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
},
|
||||
"cfgZipFileId": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitPreviewRequestSignServer": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"signHost": {
|
||||
"type": "string",
|
||||
"maxLength": 64
|
||||
},
|
||||
"signPort": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"minimum": 1,
|
||||
"maximum": 65535
|
||||
},
|
||||
"signType": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Infosec",
|
||||
"CFCA"
|
||||
]
|
||||
},
|
||||
"signCertDn": {
|
||||
"type": "string",
|
||||
"maxLength": 512
|
||||
},
|
||||
"signCertSn": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
},
|
||||
"signPassword": {
|
||||
"type": "string",
|
||||
"maxLength": 128
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitPreviewRequestDirectTlqConfig": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"localNodeSeq": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"A",
|
||||
"B"
|
||||
]
|
||||
},
|
||||
"upstreamInstitutions": {
|
||||
"type": "string",
|
||||
"maxLength": 256,
|
||||
"description": "上级机构编码,支持分号分隔"
|
||||
},
|
||||
"upstreamCocCount": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"minimum": 1,
|
||||
"maximum": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitPreviewResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"resolvedProductType": {
|
||||
"type": "string"
|
||||
},
|
||||
"presetVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"stepCount": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"summary": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitCreateTaskResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"resolvedProductType": {
|
||||
"type": "string"
|
||||
},
|
||||
"presetVersion": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitTaskDetailResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"resolvedProductType": {
|
||||
"type": "string"
|
||||
},
|
||||
"presetVersion": {
|
||||
"type": "string"
|
||||
},
|
||||
"orgCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"mqType": {
|
||||
"type": "string"
|
||||
},
|
||||
"deployMode": {
|
||||
"type": "string"
|
||||
},
|
||||
"initPlanJson": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitTaskStepResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"stepNo": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"stepCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"message": {
|
||||
"type": "string"
|
||||
},
|
||||
"commandLine": {
|
||||
"type": "string"
|
||||
},
|
||||
"logPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"exitCode": {
|
||||
"type": "integer",
|
||||
"format": "int32",
|
||||
"nullable": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitTaskStepLogResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string"
|
||||
},
|
||||
"stepNo": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"stepCode": {
|
||||
"type": "string"
|
||||
},
|
||||
"logPath": {
|
||||
"type": "string"
|
||||
},
|
||||
"content": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"InitTaskExecuteResponse": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"taskId": {
|
||||
"type": "string"
|
||||
},
|
||||
"status": {
|
||||
"type": "string"
|
||||
},
|
||||
"totalSteps": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
},
|
||||
"successSteps": {
|
||||
"type": "integer",
|
||||
"format": "int32"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,581 @@
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: TMS CISD Init Internal API
|
||||
version: "1.0.0"
|
||||
description: |
|
||||
CISD 一体机初始化相关内部接口(含设备状态接口)。
|
||||
返回体统一为 ApiResponse 包装结构。
|
||||
servers:
|
||||
- url: http://127.0.0.1:8080
|
||||
description: Local
|
||||
tags:
|
||||
- name: Device
|
||||
description: 设备信息与状态
|
||||
- name: Init
|
||||
description: CISD 初始化任务
|
||||
security:
|
||||
- InternalTokenAuth: []
|
||||
paths:
|
||||
/api/v1/device/info:
|
||||
get:
|
||||
tags: [Device]
|
||||
summary: 获取设备信息
|
||||
operationId: getDeviceInfo
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseDeviceInfoResponse"
|
||||
/api/v1/device/status:
|
||||
get:
|
||||
tags: [Device]
|
||||
summary: 获取设备状态(含预制版本信息)
|
||||
operationId: getDeviceStatus
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseDeviceInfoResponse"
|
||||
/api/v1/device/restart:
|
||||
post:
|
||||
tags: [Device]
|
||||
summary: 重启设备
|
||||
operationId: restartDevice
|
||||
parameters:
|
||||
- name: X-User
|
||||
in: header
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: 操作人
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseDeviceActionResponse"
|
||||
|
||||
/api/v1/init/template:
|
||||
get:
|
||||
tags: [Init]
|
||||
summary: 获取初始化模板元信息
|
||||
operationId: getInitTemplate
|
||||
parameters:
|
||||
- name: version
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
description: 兼容参数,后端按预置版本返回
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseInitPlanTemplateResponse"
|
||||
|
||||
/api/v1/init/preview:
|
||||
post:
|
||||
tags: [Init]
|
||||
summary: 初始化预检(不落库)
|
||||
operationId: previewInitPlan
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InitPreviewRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseInitPreviewResponse"
|
||||
|
||||
/api/v1/init/tasks:
|
||||
post:
|
||||
tags: [Init]
|
||||
summary: 创建初始化任务
|
||||
operationId: createInitTask
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/InitPreviewRequest"
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseInitCreateTaskResponse"
|
||||
|
||||
/api/v1/init/tasks/{taskId}:
|
||||
get:
|
||||
tags: [Init]
|
||||
summary: 查询任务详情
|
||||
operationId: getInitTaskDetail
|
||||
parameters:
|
||||
- name: taskId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseInitTaskDetailResponse"
|
||||
|
||||
/api/v1/init/tasks/{taskId}/steps:
|
||||
get:
|
||||
tags: [Init]
|
||||
summary: 查询任务步骤
|
||||
operationId: getInitTaskSteps
|
||||
parameters:
|
||||
- name: taskId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseInitTaskStepResponseList"
|
||||
|
||||
/api/v1/init/tasks/{taskId}/steps/{stepNo}/log:
|
||||
get:
|
||||
tags: [Init]
|
||||
summary: 查询步骤日志
|
||||
operationId: getInitTaskStepLog
|
||||
parameters:
|
||||
- name: taskId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- name: stepNo
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
format: int32
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseInitTaskStepLogResponse"
|
||||
|
||||
/api/v1/init/tasks/{taskId}/execute:
|
||||
post:
|
||||
tags: [Init]
|
||||
summary: 执行初始化任务
|
||||
operationId: executeInitTask
|
||||
parameters:
|
||||
- name: taskId
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/ApiResponseInitTaskExecuteResponse"
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
InternalTokenAuth:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: X-Internal-Token
|
||||
|
||||
schemas:
|
||||
ApiResponseBase:
|
||||
type: object
|
||||
properties:
|
||||
success:
|
||||
type: boolean
|
||||
example: true
|
||||
code:
|
||||
type: integer
|
||||
format: int32
|
||||
example: 200
|
||||
msg:
|
||||
type: string
|
||||
example: success
|
||||
timestamp:
|
||||
type: integer
|
||||
format: int64
|
||||
example: 1740902400000
|
||||
traceId:
|
||||
type: string
|
||||
nullable: true
|
||||
path:
|
||||
type: string
|
||||
nullable: true
|
||||
details:
|
||||
type: object
|
||||
additionalProperties: true
|
||||
nullable: true
|
||||
|
||||
ApiResponseDeviceInfoResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/DeviceInfoResponse"
|
||||
|
||||
ApiResponseDeviceActionResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/DeviceActionResponse"
|
||||
|
||||
ApiResponseInitPlanTemplateResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/InitPlanTemplateResponse"
|
||||
|
||||
ApiResponseInitPreviewResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/InitPreviewResponse"
|
||||
|
||||
ApiResponseInitCreateTaskResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/InitCreateTaskResponse"
|
||||
|
||||
ApiResponseInitTaskDetailResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/InitTaskDetailResponse"
|
||||
|
||||
ApiResponseInitTaskStepResponseList:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/InitTaskStepResponse"
|
||||
|
||||
ApiResponseInitTaskStepLogResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/InitTaskStepLogResponse"
|
||||
|
||||
ApiResponseInitTaskExecuteResponse:
|
||||
allOf:
|
||||
- $ref: "#/components/schemas/ApiResponseBase"
|
||||
- type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: "#/components/schemas/InitTaskExecuteResponse"
|
||||
|
||||
DeviceInfoResponse:
|
||||
type: object
|
||||
properties:
|
||||
deviceId:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
version:
|
||||
type: string
|
||||
presetProductType:
|
||||
type: string
|
||||
enum: [ENTERPRISE, INDIRECT, DIRECT]
|
||||
presetVersion:
|
||||
type: string
|
||||
presetSource:
|
||||
type: string
|
||||
|
||||
DeviceActionResponse:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
accepted:
|
||||
type: boolean
|
||||
operator:
|
||||
type: string
|
||||
acceptedAt:
|
||||
type: string
|
||||
|
||||
InitPlanTemplateResponse:
|
||||
type: object
|
||||
properties:
|
||||
presetProductType:
|
||||
type: string
|
||||
enum: [ENTERPRISE, INDIRECT, DIRECT]
|
||||
presetVersion:
|
||||
type: string
|
||||
supportedVersions:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
templatePath:
|
||||
type: string
|
||||
|
||||
InitPreviewRequest:
|
||||
type: object
|
||||
required:
|
||||
- orgCodeType
|
||||
- orgCode
|
||||
- orgNameCn
|
||||
- deployMode
|
||||
- nodes
|
||||
- mq
|
||||
- licenses
|
||||
properties:
|
||||
orgCodeType:
|
||||
type: string
|
||||
enum: [BIC, CIPSID, LEI]
|
||||
orgCode:
|
||||
type: string
|
||||
maxLength: 32
|
||||
orgNameCn:
|
||||
type: string
|
||||
maxLength: 128
|
||||
orgNameEn:
|
||||
type: string
|
||||
maxLength: 256
|
||||
deployMode:
|
||||
type: string
|
||||
enum: [SINGLE, DUAL, QUAD]
|
||||
nodes:
|
||||
$ref: "#/components/schemas/InitPreviewRequestNodes"
|
||||
mq:
|
||||
$ref: "#/components/schemas/InitPreviewRequestMq"
|
||||
licenses:
|
||||
$ref: "#/components/schemas/InitPreviewRequestLicenses"
|
||||
signServer:
|
||||
$ref: "#/components/schemas/InitPreviewRequestSignServer"
|
||||
directTlq:
|
||||
$ref: "#/components/schemas/InitPreviewRequestDirectTlqConfig"
|
||||
description: |
|
||||
初始化请求体。部分字段为条件必填:
|
||||
- DIRECT + RABBITMQ_TLQ 需提供 directTlq
|
||||
- DIRECT 需提供 signServer 与 licenses.cfgZipFileId
|
||||
- TLQ 模式需提供 mq.tlqLicenseFileId
|
||||
- RABBITMQ_CFMQ 需提供 mq.cfmqConfigFileId
|
||||
|
||||
InitPreviewRequestNodes:
|
||||
type: object
|
||||
required: [node01Ip]
|
||||
properties:
|
||||
node01Ip:
|
||||
type: string
|
||||
pattern: "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
node02Ip:
|
||||
type: string
|
||||
pattern: "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
node03Ip:
|
||||
type: string
|
||||
pattern: "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
node04Ip:
|
||||
type: string
|
||||
pattern: "^(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)(\\.(25[0-5]|2[0-4]\\d|1\\d\\d|[1-9]?\\d)){3}$"
|
||||
|
||||
InitPreviewRequestMq:
|
||||
type: object
|
||||
required: [mqType, channelUsername, channelPassword]
|
||||
properties:
|
||||
mqType:
|
||||
type: string
|
||||
description: "ENTERPRISE/INDIRECT: RABBITMQ|TLQ; DIRECT: RABBITMQ_TLQ|RABBITMQ_CFMQ"
|
||||
channelUsername:
|
||||
type: string
|
||||
maxLength: 32
|
||||
channelPassword:
|
||||
type: string
|
||||
maxLength: 128
|
||||
tlqLicenseFileId:
|
||||
type: string
|
||||
maxLength: 128
|
||||
cfmqConfigFileId:
|
||||
type: string
|
||||
maxLength: 128
|
||||
|
||||
InitPreviewRequestLicenses:
|
||||
type: object
|
||||
required: [receiverLicenseFileId]
|
||||
properties:
|
||||
receiverLicenseFileId:
|
||||
type: string
|
||||
maxLength: 128
|
||||
cfgZipFileId:
|
||||
type: string
|
||||
maxLength: 128
|
||||
|
||||
InitPreviewRequestSignServer:
|
||||
type: object
|
||||
properties:
|
||||
signHost:
|
||||
type: string
|
||||
maxLength: 64
|
||||
signPort:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 1
|
||||
maximum: 65535
|
||||
signType:
|
||||
type: string
|
||||
enum: [Infosec, CFCA]
|
||||
signCertDn:
|
||||
type: string
|
||||
maxLength: 512
|
||||
signCertSn:
|
||||
type: string
|
||||
maxLength: 128
|
||||
signPassword:
|
||||
type: string
|
||||
maxLength: 128
|
||||
|
||||
InitPreviewRequestDirectTlqConfig:
|
||||
type: object
|
||||
properties:
|
||||
localNodeSeq:
|
||||
type: string
|
||||
enum: [A, B]
|
||||
upstreamInstitutions:
|
||||
type: string
|
||||
maxLength: 256
|
||||
description: 上级机构编码,支持分号分隔
|
||||
upstreamCocCount:
|
||||
type: integer
|
||||
format: int32
|
||||
minimum: 1
|
||||
maximum: 2
|
||||
|
||||
InitPreviewResponse:
|
||||
type: object
|
||||
properties:
|
||||
resolvedProductType:
|
||||
type: string
|
||||
presetVersion:
|
||||
type: string
|
||||
stepCount:
|
||||
type: integer
|
||||
format: int32
|
||||
summary:
|
||||
type: string
|
||||
|
||||
InitCreateTaskResponse:
|
||||
type: object
|
||||
properties:
|
||||
taskId:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
resolvedProductType:
|
||||
type: string
|
||||
presetVersion:
|
||||
type: string
|
||||
|
||||
InitTaskDetailResponse:
|
||||
type: object
|
||||
properties:
|
||||
taskId:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
resolvedProductType:
|
||||
type: string
|
||||
presetVersion:
|
||||
type: string
|
||||
orgCode:
|
||||
type: string
|
||||
mqType:
|
||||
type: string
|
||||
deployMode:
|
||||
type: string
|
||||
initPlanJson:
|
||||
type: string
|
||||
|
||||
InitTaskStepResponse:
|
||||
type: object
|
||||
properties:
|
||||
stepNo:
|
||||
type: integer
|
||||
format: int32
|
||||
stepCode:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
message:
|
||||
type: string
|
||||
commandLine:
|
||||
type: string
|
||||
logPath:
|
||||
type: string
|
||||
exitCode:
|
||||
type: integer
|
||||
format: int32
|
||||
nullable: true
|
||||
|
||||
InitTaskStepLogResponse:
|
||||
type: object
|
||||
properties:
|
||||
taskId:
|
||||
type: string
|
||||
stepNo:
|
||||
type: integer
|
||||
format: int32
|
||||
stepCode:
|
||||
type: string
|
||||
logPath:
|
||||
type: string
|
||||
content:
|
||||
type: string
|
||||
|
||||
InitTaskExecuteResponse:
|
||||
type: object
|
||||
properties:
|
||||
taskId:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
totalSteps:
|
||||
type: integer
|
||||
format: int32
|
||||
successSteps:
|
||||
type: integer
|
||||
format: int32
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,75 @@
|
||||
# PCIe 真卡联调与冒烟检查清单
|
||||
|
||||
## 1. 前置条件
|
||||
|
||||
- 部署环境为目标架构(与生产一致的 CPU/OS/libc)。
|
||||
- 已安装厂商 `.so`,并可被进程访问。
|
||||
- 服务配置为 JNA 真卡模式:
|
||||
- `tms.crypto-card.enabled=true`
|
||||
- `tms.crypto-card.mode=JNA`
|
||||
- `tms.crypto-card.vendor-lib-path` 或 `tms.crypto-card.vendor-lib-name` 正确
|
||||
- `tms.crypto-card.strict-alg-id-validation=true`(若厂商扩展算法可临时关闭)
|
||||
- 已知内部接口鉴权令牌 `X-Internal-Token`。
|
||||
|
||||
## 2. 核心检查项(必须通过)
|
||||
|
||||
1. 设备与会话
|
||||
- `GET /api/v1/device/crypto/device-count`
|
||||
- `GET /api/v1/device/crypto/device-info`
|
||||
- `POST /api/v1/device/crypto/self-test`
|
||||
2. 基础密码能力
|
||||
- 随机数:`GET /api/v1/device/crypto/random?length=16`
|
||||
- 摘要:`POST /api/v1/device/crypto/digest`
|
||||
- HMAC:`POST /api/v1/device/crypto/hmac`
|
||||
3. 对称能力
|
||||
- 明文密钥加解密:`/encrypt/plain` + `/decrypt/plain`
|
||||
- KEK 生成与状态:`/kek/generate` + `/kek/status`
|
||||
4. 主密钥状态
|
||||
- `GET /api/v1/device/crypto/lmk/seed-mac`
|
||||
|
||||
验收标准:
|
||||
|
||||
- `ApiResponse.success == true`
|
||||
- `ApiResponse.code == 200`
|
||||
- 返回长度字段与 Base64 解码长度一致
|
||||
- 错误日志中无 native 崩溃/段错误
|
||||
|
||||
## 3. 高风险专项
|
||||
|
||||
### 3.1 `SDFE_ImportEncKeyPair_ECC`(结构体直传)
|
||||
|
||||
- 用最小可用样本执行导入流程。
|
||||
- 成功后立即查询相关密钥状态接口验证导入结果。
|
||||
- 若出现参数错误,优先检查结构体字段对齐与 `unsigned long` 位宽。
|
||||
|
||||
### 3.2 `ECCCipher` 变长字段边界
|
||||
|
||||
- 对不同明文长度执行 ECC 加密路径。
|
||||
- 记录返回 `ECCCipher.l` 的最大值。
|
||||
- 若接近当前上限(`C_MAX_LEN`),必须提升上限并复测。
|
||||
|
||||
### 3.3 算法标识白名单
|
||||
|
||||
- 对业务实际用到的所有 `algId` 跑一遍。
|
||||
- 若被严格校验拦截,补充到 `Gm0018AlgorithmIds` 后再回归。
|
||||
|
||||
## 4. 失败排查顺序
|
||||
|
||||
1. 配置错误:库路径、库名、鉴权 token。
|
||||
2. 运行时依赖:`ldd`/动态库缺失。
|
||||
3. 参数编码:Base64 入参、长度字段、结构体大小。
|
||||
4. 算法标识:`algId` 是否在白名单。
|
||||
5. 厂商错误码:结合 `PcieErrorMapper` 与厂商文档定位。
|
||||
|
||||
## 5. 回归策略
|
||||
|
||||
- 每次升级以下任一项,都执行本清单:
|
||||
- JDK 版本
|
||||
- 厂商 `.so` 版本
|
||||
- JNA 结构体定义
|
||||
- `JnaPcieCryptoService` 参数转换逻辑
|
||||
|
||||
## 6. 自动化模板
|
||||
|
||||
- 使用脚本:`scripts/pcie_realcard_smoke.sh`
|
||||
- 建议在联调机和预生产各执行一次,并保留日志归档。
|
||||
@@ -0,0 +1,214 @@
|
||||
# CISD 初始化 API Curl 样例集
|
||||
|
||||
- 日期:2026-03-02
|
||||
- 适用接口前缀:`/api/v1/device`、`/api/v1/init`
|
||||
- 说明:以下样例用于联调,不包含生产鉴权与审计策略
|
||||
|
||||
## 1. 公共变量
|
||||
|
||||
```bash
|
||||
BASE_URL="${BASE_URL:-http://127.0.0.1:8080}"
|
||||
INTERNAL_TOKEN="${INTERNAL_TOKEN:-change-me-internal-token}"
|
||||
```
|
||||
|
||||
## 2. 查询设备预置版本信息
|
||||
|
||||
```bash
|
||||
curl -sS \
|
||||
-H "X-Internal-Token: ${INTERNAL_TOKEN}" \
|
||||
"${BASE_URL}/api/v1/device/status" | jq
|
||||
```
|
||||
|
||||
预期关键字段:
|
||||
|
||||
1. `data.presetProductType`:`ENTERPRISE|INDIRECT|DIRECT`
|
||||
2. `data.presetVersion`
|
||||
|
||||
## 3. 企业/间参请求体(RabbitMQ)
|
||||
|
||||
```bash
|
||||
cat > /tmp/cisd-init-standard-rabbit.json <<'JSON'
|
||||
{
|
||||
"orgCodeType": "BIC",
|
||||
"orgCode": "AAAABBBBXXX",
|
||||
"orgNameCn": "测试机构",
|
||||
"orgNameEn": "TEST BANK",
|
||||
"deployMode": "SINGLE",
|
||||
"nodes": {
|
||||
"node01Ip": "10.0.0.11"
|
||||
},
|
||||
"mq": {
|
||||
"mqType": "RABBITMQ",
|
||||
"channelUsername": "cisd_channel_user",
|
||||
"channelPassword": "cisd_channel_pass"
|
||||
},
|
||||
"licenses": {
|
||||
"receiverLicenseFileId": "file-receiver-001"
|
||||
}
|
||||
}
|
||||
JSON
|
||||
```
|
||||
|
||||
## 4. 企业/间参请求体(TLQ)
|
||||
|
||||
```bash
|
||||
cat > /tmp/cisd-init-standard-tlq.json <<'JSON'
|
||||
{
|
||||
"orgCodeType": "BIC",
|
||||
"orgCode": "AAAABBBBXXX",
|
||||
"orgNameCn": "测试机构",
|
||||
"orgNameEn": "TEST BANK",
|
||||
"deployMode": "DUAL",
|
||||
"nodes": {
|
||||
"node01Ip": "10.0.0.11",
|
||||
"node02Ip": "10.0.0.12"
|
||||
},
|
||||
"mq": {
|
||||
"mqType": "TLQ",
|
||||
"channelUsername": "cisd_channel_user",
|
||||
"channelPassword": "cisd_channel_pass",
|
||||
"tlqLicenseFileId": "file-tlq-license-001"
|
||||
},
|
||||
"licenses": {
|
||||
"receiverLicenseFileId": "file-receiver-001"
|
||||
}
|
||||
}
|
||||
JSON
|
||||
```
|
||||
|
||||
## 5. 轻量化直参请求体(RABBITMQ_TLQ)
|
||||
|
||||
```bash
|
||||
cat > /tmp/cisd-init-direct-tlq.json <<'JSON'
|
||||
{
|
||||
"orgCodeType": "BIC",
|
||||
"orgCode": "AAAABBBBXXX",
|
||||
"orgNameCn": "测试机构",
|
||||
"orgNameEn": "TEST BANK",
|
||||
"deployMode": "DUAL",
|
||||
"nodes": {
|
||||
"node01Ip": "10.0.1.11",
|
||||
"node02Ip": "10.0.1.12"
|
||||
},
|
||||
"mq": {
|
||||
"mqType": "RABBITMQ_TLQ",
|
||||
"channelUsername": "cisd_channel_user",
|
||||
"channelPassword": "cisd_channel_pass",
|
||||
"tlqLicenseFileId": "file-tlq-license-001"
|
||||
},
|
||||
"licenses": {
|
||||
"receiverLicenseFileId": "file-receiver-001",
|
||||
"cfgZipFileId": "/opt/cpconfig.cfg"
|
||||
},
|
||||
"signServer": {
|
||||
"signHost": "172.30.1.101",
|
||||
"signPort": 50006,
|
||||
"signType": "Infosec",
|
||||
"signCertDn": "CN=051@AAAABBBBXXX@7321@1,OU=Org,OU=CIPS,O=CFCA OCA1,C=CN",
|
||||
"signCertSn": "1154809590",
|
||||
"signPassword": "secret"
|
||||
},
|
||||
"directTlq": {
|
||||
"localNodeSeq": "A",
|
||||
"upstreamInstitutions": "CIPSCNSHXXX;CIPSCNWXXXX",
|
||||
"upstreamCocCount": 2
|
||||
}
|
||||
}
|
||||
JSON
|
||||
```
|
||||
|
||||
## 6. 轻量化直参请求体(RABBITMQ_CFMQ)
|
||||
|
||||
```bash
|
||||
cat > /tmp/cisd-init-direct-cfmq.json <<'JSON'
|
||||
{
|
||||
"orgCodeType": "BIC",
|
||||
"orgCode": "AAAABBBBXXX",
|
||||
"orgNameCn": "测试机构",
|
||||
"orgNameEn": "TEST BANK",
|
||||
"deployMode": "SINGLE",
|
||||
"nodes": {
|
||||
"node01Ip": "10.0.1.11"
|
||||
},
|
||||
"mq": {
|
||||
"mqType": "RABBITMQ_CFMQ",
|
||||
"channelUsername": "cisd_channel_user",
|
||||
"channelPassword": "cisd_channel_pass",
|
||||
"cfmqConfigFileId": "/pmts/cfg/cfmqapi_trans.properties"
|
||||
},
|
||||
"licenses": {
|
||||
"receiverLicenseFileId": "file-receiver-001",
|
||||
"cfgZipFileId": "/opt/cpconfig.cfg"
|
||||
},
|
||||
"signServer": {
|
||||
"signHost": "172.30.1.101",
|
||||
"signPort": 50006,
|
||||
"signType": "Infosec",
|
||||
"signCertDn": "CN=051@AAAABBBBXXX@7321@1,OU=Org,OU=CIPS,O=CFCA OCA1,C=CN",
|
||||
"signCertSn": "1154809590",
|
||||
"signPassword": "secret"
|
||||
}
|
||||
}
|
||||
JSON
|
||||
```
|
||||
|
||||
## 7. 初始化任务执行链路(通用)
|
||||
|
||||
将 `<REQUEST_JSON>` 替换为上面任一 json 文件路径。
|
||||
|
||||
```bash
|
||||
REQUEST_JSON="/tmp/cisd-init-standard-rabbit.json"
|
||||
|
||||
# 1) preview
|
||||
curl -sS -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Internal-Token: ${INTERNAL_TOKEN}" \
|
||||
"${BASE_URL}/api/v1/init/preview" \
|
||||
-d @"${REQUEST_JSON}" | jq
|
||||
|
||||
# 2) create task
|
||||
TASK_ID="$(curl -sS -X POST \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "X-Internal-Token: ${INTERNAL_TOKEN}" \
|
||||
"${BASE_URL}/api/v1/init/tasks" \
|
||||
-d @"${REQUEST_JSON}" | jq -r '.data.taskId')"
|
||||
|
||||
echo "TASK_ID=${TASK_ID}"
|
||||
|
||||
# 3) execute task
|
||||
curl -sS -X POST \
|
||||
-H "X-Internal-Token: ${INTERNAL_TOKEN}" \
|
||||
"${BASE_URL}/api/v1/init/tasks/${TASK_ID}/execute" | jq
|
||||
|
||||
# 4) query steps
|
||||
curl -sS \
|
||||
-H "X-Internal-Token: ${INTERNAL_TOKEN}" \
|
||||
"${BASE_URL}/api/v1/init/tasks/${TASK_ID}/steps" | jq
|
||||
```
|
||||
|
||||
## 8. 单步日志查询(失败定位)
|
||||
|
||||
```bash
|
||||
STEP_NO=3
|
||||
curl -sS \
|
||||
-H "X-Internal-Token: ${INTERNAL_TOKEN}" \
|
||||
"${BASE_URL}/api/v1/init/tasks/${TASK_ID}/steps/${STEP_NO}/log" | jq -r '.data.content'
|
||||
```
|
||||
|
||||
## 9. 常见问题
|
||||
|
||||
1. 直参 TLQ 报 `directTlq is required`:请求体缺 `directTlq` 三字段。
|
||||
2. `APP_MQ_CREDENTIALS_APPLY` 失败:应用配置匹配路径无文件或无写权限。
|
||||
3. MQ 连接失败:确认 `TMS_INIT_EXECUTOR_STANDARD_RABBIT_CREDENTIAL_SECRET_KEY` 与收发器解密密钥一致。
|
||||
|
||||
## 10. 一键执行脚本(推荐)
|
||||
|
||||
```bash
|
||||
chmod +x scripts/cisd_init_flow.sh
|
||||
REQUEST_JSON=/tmp/cisd-init-standard-rabbit.json \
|
||||
BASE_URL=http://127.0.0.1:8080 \
|
||||
INTERNAL_TOKEN=change-me-internal-token \
|
||||
./scripts/cisd_init_flow.sh
|
||||
```
|
||||
|
||||
输出目录默认:`/tmp/cisd-init-run/run-<timestamp>`,包含每一步请求响应与失败日志抓取结果。
|
||||
@@ -0,0 +1,165 @@
|
||||
# CISD 初始化真机联调与回滚手册
|
||||
|
||||
- 日期:2026-03-02
|
||||
- 适用版本:`ENTERPRISE` / `INDIRECT` / `DIRECT`
|
||||
- 适用代码基线:已包含 `APP_MQ_CREDENTIALS_APPLY`、`direct_db_init`、`tlq_init_cfg`
|
||||
|
||||
## 1. 目的
|
||||
|
||||
1. 在目标设备上完成初始化关键路径联调。
|
||||
2. 验证三类版本在“预部署完成后,仅做客户化初始化”的边界下可稳定运行。
|
||||
3. 提供失败后的快速回滚与重试指引。
|
||||
|
||||
## 2. 关键实现映射(联调前必须确认)
|
||||
|
||||
1. 企业/间参步骤链:
|
||||
`RENDER_CONFIG -> SET_(RABBITMQ|TLQ) -> MQ_USER_APPLY -> MQ_QUEUE_APPLY -> DB_INIT -> DEPLOY_RECEIVER -> APP_MQ_CREDENTIALS_APPLY -> VERIFY`
|
||||
2. 轻量化直参(TLQ)步骤链:
|
||||
`RENDER_CONFIG -> MQ_USER_APPLY -> DB_INIT(direct_db_init) -> TLQ_INIT_CFG(tlq_init_cfg) -> VERIFY`
|
||||
3. 轻量化直参(CFMQ)步骤链:
|
||||
`RENDER_CONFIG -> MQ_USER_APPLY -> DB_INIT(direct_db_init) -> CFMQ_APPLY -> VERIFY`
|
||||
4. 通道账号密码写回应用配置时默认加密:
|
||||
`DESede(3DES) + secretKey=ABCDEFGHIJKLMN1234567890 + HEX(upper)`。
|
||||
|
||||
## 3. 联调前置检查
|
||||
|
||||
## 3.1 环境变量基线
|
||||
|
||||
在 TMS 进程环境确认以下参数:
|
||||
|
||||
```bash
|
||||
echo "$TMS_CISD_PRESET_PRODUCT_TYPE"
|
||||
echo "$TMS_INIT_EXECUTOR_MODE"
|
||||
echo "$TMS_INIT_EXECUTOR_STANDARD_CPCONFIG_PATH"
|
||||
echo "$TMS_INIT_EXECUTOR_DIRECT_DB_SCRIPT_DIR"
|
||||
echo "$TMS_INIT_EXECUTOR_DIRECT_TLQ_INIT_CFG_DIR"
|
||||
echo "$TMS_INIT_EXECUTOR_STANDARD_RABBIT_APP_CONFIG_PATTERN_1"
|
||||
echo "$TMS_INIT_EXECUTOR_STANDARD_RABBIT_APP_CONFIG_PATTERN_2"
|
||||
echo "$TMS_INIT_EXECUTOR_STANDARD_RABBIT_CREDENTIAL_ENCRYPT_ENABLED"
|
||||
echo "$TMS_INIT_EXECUTOR_STANDARD_RABBIT_CREDENTIAL_SECRET_KEY"
|
||||
```
|
||||
|
||||
建议值:
|
||||
|
||||
1. `TMS_INIT_EXECUTOR_MODE=LOCAL`
|
||||
2. `TMS_INIT_EXECUTOR_STANDARD_RABBIT_CREDENTIAL_ENCRYPT_ENABLED=true`
|
||||
3. `TMS_INIT_EXECUTOR_STANDARD_RABBIT_CREDENTIAL_SECRET_KEY` 与现场收发器解密密钥一致。
|
||||
|
||||
## 3.2 目录与脚本存在性
|
||||
|
||||
```bash
|
||||
ls -l /home/cmep4i/cpconfig.cfg
|
||||
ls -l /home/cmep4i/cpackage/toolsh/{setfraq.sh,setftq.sh,setsql.sh,setsptp.sh}
|
||||
ls -l /opt/CAE_Install_Base_Resource/DB/setsql.sh
|
||||
ls -l /opt/CAE_Install_App_Resource/CAE/init_cfg.sh
|
||||
```
|
||||
|
||||
## 3.3 MQ 与配置文件可写性
|
||||
|
||||
```bash
|
||||
ls -l /home/cmep4i/cmsp/application-prd*.properties
|
||||
ls -l /home/cmep4i/cmtp/application-prd*.properties
|
||||
which rabbitmqctl
|
||||
which rabbitmqadmin
|
||||
```
|
||||
|
||||
## 4. 联调执行清单(统一流程)
|
||||
|
||||
## 4.1 接口执行顺序
|
||||
|
||||
1. `GET /api/v1/device/status`
|
||||
2. `POST /api/v1/init/preview`
|
||||
3. `POST /api/v1/init/task`
|
||||
4. `POST /api/v1/init/task/{taskId}/execute`
|
||||
5. `GET /api/v1/init/task/{taskId}/steps`
|
||||
6. 失败时逐步查看日志:`GET /api/v1/init/task/{taskId}/steps/{stepNo}/log`
|
||||
|
||||
## 4.2 用例矩阵(最小集合)
|
||||
|
||||
1. 企业版 + RabbitMQ
|
||||
2. 企业版 + TLQ
|
||||
3. 间参版 + RabbitMQ
|
||||
4. 轻量化直参 + RABBITMQ_TLQ(必须带 `directTlq` 三字段)
|
||||
5. 轻量化直参 + RABBITMQ_CFMQ
|
||||
|
||||
## 4.3 直参 TLQ 请求体附加字段
|
||||
|
||||
```json
|
||||
{
|
||||
"directTlq": {
|
||||
"localNodeSeq": "A",
|
||||
"upstreamInstitutions": "CIPSCNSHXXX;CIPSCNWXXXX",
|
||||
"upstreamCocCount": 2
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 5. 关键验收点
|
||||
|
||||
1. `RENDER_CONFIG` 后,`cpconfig.cfg` 中机构号、节点、签名参数、`MQ_TYPE` 已替换。
|
||||
2. `MQ_USER_APPLY` 后,RabbitMQ 中存在通道用户,且具备目标 vhost 权限。
|
||||
3. `MQ_QUEUE_APPLY` 后,业务队列创建成功(企业/间参)。
|
||||
4. `APP_MQ_CREDENTIALS_APPLY` 后,`spring.rabbitmq.username/password` 已更新且为密文(非明文)。
|
||||
5. `DB_INIT` 生成或替换的 SQL 文件可执行,无路径/权限错误。
|
||||
6. `VERIFY` 成功,任务最终状态 `SUCCESS`。
|
||||
|
||||
## 6. 失败定位顺序
|
||||
|
||||
1. 配置错误:版本预置、环境变量、路径。
|
||||
2. 权限错误:TMS 进程用户对脚本和配置文件不可写。
|
||||
3. 脚本依赖缺失:`rabbitmqctl/rabbitmqadmin`、Java、数据库客户端。
|
||||
4. 参数不完整:直参 TLQ 缺 `directTlq` 字段。
|
||||
5. 密钥不一致:写回密文与收发器解密密钥不匹配导致 MQ 连接失败。
|
||||
|
||||
## 7. 回滚策略(按层次)
|
||||
|
||||
## 7.1 执行前备份(强制)
|
||||
|
||||
```bash
|
||||
TS=$(date +%Y%m%d%H%M%S)
|
||||
mkdir -p /tmp/cisd-init-backup-$TS
|
||||
cp -a /home/cmep4i/cpconfig.cfg /tmp/cisd-init-backup-$TS/
|
||||
cp -a /home/cmep4i/cmsp/application-prd*.properties /tmp/cisd-init-backup-$TS/ 2>/dev/null || true
|
||||
cp -a /home/cmep4i/cmtp/application-prd*.properties /tmp/cisd-init-backup-$TS/ 2>/dev/null || true
|
||||
echo "/tmp/cisd-init-backup-$TS"
|
||||
```
|
||||
|
||||
## 7.2 配置回滚
|
||||
|
||||
```bash
|
||||
cp -a /tmp/cisd-init-backup-<TS>/cpconfig.cfg /home/cmep4i/cpconfig.cfg
|
||||
cp -a /tmp/cisd-init-backup-<TS>/application-prd*.properties /home/cmep4i/cmsp/ 2>/dev/null || true
|
||||
cp -a /tmp/cisd-init-backup-<TS>/application-prd*.properties /home/cmep4i/cmtp/ 2>/dev/null || true
|
||||
```
|
||||
|
||||
## 7.3 MQ 回滚(按需)
|
||||
|
||||
```bash
|
||||
# 删除通道用户(示例)
|
||||
rabbitmqctl delete_user <channelUsername>
|
||||
|
||||
# 删除业务队列(示例,按实际创建队列名执行)
|
||||
rabbitmqadmin --username=admin --password=admin --vhost=/ delete queue name=<queueName>
|
||||
rabbitmqadmin --username=admin --password=admin --vhost=/RQ delete queue name=<queueName>
|
||||
```
|
||||
|
||||
## 7.4 数据库回滚(按实际 SQL 执行情况)
|
||||
|
||||
1. 若仅生成 SQL 未执行:删除临时生成物即可。
|
||||
2. 若已执行入库:使用预先准备的回滚 SQL 或从数据库备份恢复。
|
||||
3. 严禁在无备份情况下直接清库重建。
|
||||
|
||||
## 8. 重试策略
|
||||
|
||||
1. 先回滚配置和 MQ 变更,再重建任务重试,不复用失败任务。
|
||||
2. 每次仅变更一个变量(如路径、密钥、账号),避免多变量同时变化。
|
||||
3. 连续两次同一步失败,先停止重试,导出该步骤日志并人工排查根因。
|
||||
|
||||
## 9. 交付物归档
|
||||
|
||||
每次联调需归档:
|
||||
|
||||
1. `taskId`、版本类型、请求参数(脱敏后)。
|
||||
2. 步骤执行日志目录:`/tmp/tms-init-logs/<taskId>/`。
|
||||
3. 回滚操作记录(是否执行、执行人、时间)。
|
||||
4. 最终结论:通过/失败及根因。
|
||||
@@ -0,0 +1,108 @@
|
||||
# CISD Init Request Schema Spec (Preset-Version Driven)
|
||||
|
||||
## 1. Scope
|
||||
This document defines the frontend request schema for CISD initialization in TMS when product version is preset by device metadata.
|
||||
|
||||
- Frontend must call `GET /api/v1/device/status` first.
|
||||
- If `presetProductType` is empty or invalid, initialization is forbidden.
|
||||
- Frontend must render version-specific form fields automatically; user does not manually choose version.
|
||||
|
||||
## 2. Device status fields used by frontend
|
||||
`/api/v1/device/status` response includes:
|
||||
|
||||
- `presetProductType`: `ENTERPRISE | INDIRECT | DIRECT`
|
||||
- `presetVersion`: preset package version
|
||||
- `presetSource`: where preset was loaded from (e.g., `CONFIG`, future `DB`)
|
||||
|
||||
## 3. Init preview request payload
|
||||
Endpoint: `POST /api/v1/init/preview`
|
||||
|
||||
```json
|
||||
{
|
||||
"orgCodeType": "BIC",
|
||||
"orgCode": "AAAABBBBXXX",
|
||||
"orgNameCn": "示例机构",
|
||||
"orgNameEn": "Example Bank",
|
||||
"deployMode": "DUAL",
|
||||
"nodes": {
|
||||
"node01Ip": "10.0.0.1",
|
||||
"node02Ip": "10.0.0.2",
|
||||
"node03Ip": "127.0.0.1",
|
||||
"node04Ip": "127.0.0.1"
|
||||
},
|
||||
"mq": {
|
||||
"mqType": "RABBITMQ",
|
||||
"channelUsername": "channel_user",
|
||||
"channelPassword": "channel_password",
|
||||
"tlqLicenseFileId": "file-tlq-license",
|
||||
"cfmqConfigFileId": "file-cfmq-config"
|
||||
},
|
||||
"licenses": {
|
||||
"receiverLicenseFileId": "file-receiver-license",
|
||||
"cfgZipFileId": "file-cfg-zip"
|
||||
},
|
||||
"signServer": {
|
||||
"signHost": "172.30.1.101",
|
||||
"signPort": 50006,
|
||||
"signType": "Infosec",
|
||||
"signCertDn": "CN=...",
|
||||
"signCertSn": "1154809590",
|
||||
"signPassword": "***"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 4. Mandatory fields by product type
|
||||
|
||||
### 4.1 Common mandatory fields (all versions)
|
||||
- `orgCodeType`, `orgCode`, `orgNameCn`
|
||||
- `deployMode`
|
||||
- `nodes.node01Ip`
|
||||
- `mq.mqType`, `mq.channelUsername`, `mq.channelPassword`
|
||||
- `licenses.receiverLicenseFileId`
|
||||
|
||||
### 4.2 ENTERPRISE / INDIRECT
|
||||
Allowed values:
|
||||
- `deployMode`: `SINGLE | DUAL`
|
||||
- `mq.mqType`: `RABBITMQ | TLQ`
|
||||
|
||||
Conditional required fields:
|
||||
- `deployMode=DUAL` -> `nodes.node02Ip`
|
||||
- `mqType=TLQ` -> `mq.tlqLicenseFileId`
|
||||
|
||||
### 4.3 DIRECT
|
||||
Allowed values:
|
||||
- `deployMode`: `SINGLE | DUAL | QUAD`
|
||||
- `mq.mqType`: `RABBITMQ_TLQ | RABBITMQ_CFMQ`
|
||||
|
||||
Always required:
|
||||
- `licenses.cfgZipFileId`
|
||||
- `signServer.signHost`
|
||||
- `signServer.signPort`
|
||||
- `signServer.signType`
|
||||
- `signServer.signCertDn`
|
||||
- `signServer.signCertSn`
|
||||
- `signServer.signPassword`
|
||||
|
||||
Conditional required fields:
|
||||
- `deployMode=DUAL|QUAD` -> `nodes.node02Ip`
|
||||
- `deployMode=QUAD` -> `nodes.node03Ip`, `nodes.node04Ip`
|
||||
- `mqType=RABBITMQ_TLQ` -> `mq.tlqLicenseFileId`
|
||||
- `mqType=RABBITMQ_CFMQ` -> `mq.cfmqConfigFileId`
|
||||
|
||||
## 5. Prefilled vs user-input fields
|
||||
|
||||
### 5.1 Prefilled and hidden from frontend
|
||||
- Product preset metadata: version type and package version
|
||||
- Database deployment credentials and root/app user passwords
|
||||
- RabbitMQ admin username/password
|
||||
|
||||
### 5.2 User input fields
|
||||
- Institution identity and node addresses
|
||||
- MQ channel username/password
|
||||
- Version-conditional file uploads (receiver license, TLQ license, CFMQ config, direct CFG zip)
|
||||
- Direct sign server information
|
||||
|
||||
## 6. Validation behavior
|
||||
- Validation errors return code `4001` with field message.
|
||||
- Missing/invalid preset product type returns business error and initialization is blocked.
|
||||
@@ -0,0 +1,121 @@
|
||||
# CISD Init Request Schema DTO Implementation Plan
|
||||
|
||||
> **For Claude:** REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
|
||||
|
||||
**Goal:** Replace placeholder init preview request with a production-ready CISD initialization request DTO and server-side rule validation based on preset product type.
|
||||
|
||||
**Architecture:** Keep the current single-module Spring Boot structure. Introduce strong-typed nested DTOs for init request payload, centralize preset version/product-type sourcing in configuration properties (as current phase baseline), and enforce cross-field conditional rules in `InitService` before preview generation. Surface preset product type in `/api/v1/device/info` for frontend auto-rendering.
|
||||
|
||||
**Tech Stack:** JDK 17, Spring Boot 3.5, Jakarta Bean Validation, JUnit 5.
|
||||
|
||||
---
|
||||
|
||||
### Task 1: Add failing tests for init request rule validation
|
||||
|
||||
**Files:**
|
||||
- Create: `src/test/java/com/cisd/tms/modules/init/service/InitServiceTest.java`
|
||||
|
||||
**Step 1: Write failing tests**
|
||||
- Add tests for:
|
||||
- missing preset product type should reject init preview.
|
||||
- enterprise + TLQ should require `tlqLicenseFileId`.
|
||||
- direct + `RABBITMQ_CFMQ` should require `cfmqConfigFileId`, `cfgZipFileId`, and sign server fields.
|
||||
- valid enterprise request should pass and generate summary.
|
||||
|
||||
**Step 2: Run targeted tests to verify red**
|
||||
- Run: `mvn -q -Dtest=InitServiceTest test`
|
||||
- Expected: FAIL because `InitService` still uses old DTO and has no rule engine.
|
||||
|
||||
### Task 2: Implement strong-typed init request DTO model
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/main/java/com/cisd/tms/modules/init/dto/InitPreviewRequest.java`
|
||||
|
||||
**Step 1: Replace old placeholder fields**
|
||||
- Remove `version/nodeCount`.
|
||||
- Add nested models for:
|
||||
- basic institution fields
|
||||
- deploy mode + nodes
|
||||
- mq settings
|
||||
- licenses
|
||||
- sign server
|
||||
|
||||
**Step 2: Add validation annotations**
|
||||
- Add required constraints for common fields (`orgCodeType`, `orgCode`, `orgNameCn`, `deployMode`, `node01Ip`, `mqType`, `channelUsername`, `channelPassword`, `receiverLicenseFileId`).
|
||||
|
||||
**Step 3: Keep model minimal and serializable**
|
||||
- Use static inner classes with getters/setters only.
|
||||
|
||||
### Task 3: Add preset product type source and expose in device info
|
||||
|
||||
**Files:**
|
||||
- Create: `src/main/java/com/cisd/tms/common/config/properties/CisdPresetProperties.java`
|
||||
- Modify: `src/main/java/com/cisd/tms/modules/device/dto/DeviceInfoResponse.java`
|
||||
- Modify: `src/main/java/com/cisd/tms/modules/device/service/DeviceService.java`
|
||||
- Modify: `src/main/resources/application.yml`
|
||||
|
||||
**Step 1: Add configuration properties bean**
|
||||
- Prefix: `tms.cisd.preset`
|
||||
- Fields: `productType`, `version`, `source`.
|
||||
|
||||
**Step 2: Extend device status response**
|
||||
- Add `presetProductType`, `presetVersion`, `presetSource`.
|
||||
|
||||
**Step 3: Populate response from preset config**
|
||||
- Inject `CisdPresetProperties` into `DeviceService` and map values.
|
||||
|
||||
### Task 4: Implement rule validation in InitService
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/main/java/com/cisd/tms/modules/init/service/InitService.java`
|
||||
- Modify: `src/main/java/com/cisd/tms/modules/init/dto/InitPreviewResponse.java`
|
||||
- Modify: `src/main/java/com/cisd/tms/modules/init/dto/InitPlanTemplateResponse.java`
|
||||
|
||||
**Step 1: Add preset guard**
|
||||
- If preset product type missing/invalid, throw `BizException` and block preview/template.
|
||||
|
||||
**Step 2: Add product-type conditional validation**
|
||||
- Enterprise/Indirect:
|
||||
- deploy mode only `SINGLE/DUAL`
|
||||
- mq type only `RABBITMQ/TLQ`
|
||||
- TLQ requires `tlqLicenseFileId`
|
||||
- DUAL requires `node02Ip`
|
||||
- Direct:
|
||||
- deploy mode `SINGLE/DUAL/QUAD`
|
||||
- mq type `RABBITMQ_TLQ/RABBITMQ_CFMQ`
|
||||
- `cfgZipFileId` required
|
||||
- sign server fields required
|
||||
- TLQ requires `tlqLicenseFileId`
|
||||
- CFMQ requires `cfmqConfigFileId`
|
||||
- DUAL/QUAD require `node02Ip`; QUAD require `node03Ip/node04Ip`
|
||||
|
||||
**Step 3: Produce meaningful preview summary**
|
||||
- Set response fields: resolved product type, step count estimate, and concise summary.
|
||||
|
||||
### Task 5: Add developer-facing validation spec doc
|
||||
|
||||
**Files:**
|
||||
- Create: `docs/plans/2026-03-02-cisd-init-request-schema-spec.md`
|
||||
|
||||
**Step 1: Document payload JSON schema shape**
|
||||
- Include common object structure and conditional fields by product type.
|
||||
|
||||
**Step 2: Document prefilled vs user-input fields**
|
||||
- Explicitly list DB creds and RabbitMQ admin creds as prefilled-only.
|
||||
|
||||
### Task 6: Verify and stabilize
|
||||
|
||||
**Files:**
|
||||
- N/A
|
||||
|
||||
**Step 1: Run targeted tests**
|
||||
- `mvn -q -Dtest=InitServiceTest test`
|
||||
|
||||
**Step 2: Run compile check**
|
||||
- `mvn -q -DskipTests compile`
|
||||
|
||||
**Step 3: Run full test suite if stable**
|
||||
- `mvn -q test`
|
||||
|
||||
**Step 4: Record results in response**
|
||||
- Include changed files, command outputs summary, remaining risks.
|
||||
@@ -0,0 +1,70 @@
|
||||
-- -----------------------------------------------------------------------------
|
||||
-- TMS 基础库结构(TiDB/MySQL)
|
||||
-- 适用范围:当前已实现的初始化任务、步骤、设备节点、用户表
|
||||
-- -----------------------------------------------------------------------------
|
||||
|
||||
-- 1) 建库(如已存在则跳过)
|
||||
CREATE DATABASE IF NOT EXISTS tms
|
||||
DEFAULT CHARACTER SET utf8mb4
|
||||
COLLATE utf8mb4_general_ci;
|
||||
|
||||
USE tms;
|
||||
|
||||
-- 2) 初始化任务主表
|
||||
CREATE TABLE IF NOT EXISTS tms_init_task (
|
||||
id BIGINT PRIMARY KEY COMMENT '主键ID',
|
||||
task_id VARCHAR(64) NOT NULL COMMENT '任务业务ID',
|
||||
version VARCHAR(32) NOT NULL COMMENT 'CIPS版本',
|
||||
status VARCHAR(32) NOT NULL COMMENT '任务状态',
|
||||
product_type VARCHAR(16) NULL COMMENT '产品版本: enterprise/interbank/lite_direct',
|
||||
org_code VARCHAR(32) NULL COMMENT '机构号',
|
||||
mq_type VARCHAR(32) NULL COMMENT '消息队列类型',
|
||||
deploy_mode VARCHAR(16) NULL COMMENT '部署模式: single/double/four',
|
||||
init_plan_json LONGTEXT NULL COMMENT '初始化计划快照(JSON)',
|
||||
create_time DATETIME(3) NOT NULL COMMENT '创建时间',
|
||||
update_time DATETIME(3) NOT NULL COMMENT '更新时间',
|
||||
UNIQUE KEY uk_tms_init_task_task_id (task_id)
|
||||
) COMMENT='初始化任务表';
|
||||
|
||||
-- 3) 初始化任务步骤表
|
||||
CREATE TABLE IF NOT EXISTS tms_init_task_step (
|
||||
id BIGINT PRIMARY KEY COMMENT '主键ID',
|
||||
task_id VARCHAR(64) NOT NULL COMMENT '任务业务ID',
|
||||
step_no INT NOT NULL COMMENT '步骤序号',
|
||||
step_code VARCHAR(64) NOT NULL COMMENT '步骤编码',
|
||||
status VARCHAR(32) NOT NULL COMMENT '步骤状态',
|
||||
message VARCHAR(512) NULL COMMENT '步骤信息',
|
||||
command_line VARCHAR(2048) NULL COMMENT '实际执行命令',
|
||||
log_path VARCHAR(512) NULL COMMENT '日志文件路径',
|
||||
exit_code INT NULL COMMENT '命令退出码',
|
||||
create_time DATETIME(3) NOT NULL COMMENT '创建时间',
|
||||
update_time DATETIME(3) NOT NULL COMMENT '更新时间',
|
||||
UNIQUE KEY uk_tms_init_task_step_task_no (task_id, step_no),
|
||||
KEY idx_tms_init_task_step_task_id (task_id)
|
||||
) COMMENT='初始化任务步骤表';
|
||||
|
||||
-- 4) 系统用户表(简化)
|
||||
CREATE TABLE IF NOT EXISTS tms_auth_user (
|
||||
id BIGINT PRIMARY KEY COMMENT '主键ID',
|
||||
username VARCHAR(64) NOT NULL COMMENT '用户名',
|
||||
display_name VARCHAR(128) NOT NULL COMMENT '显示名',
|
||||
role VARCHAR(64) NOT NULL COMMENT '角色',
|
||||
create_time DATETIME(3) NOT NULL COMMENT '创建时间',
|
||||
update_time DATETIME(3) NOT NULL COMMENT '更新时间',
|
||||
UNIQUE KEY uk_tms_auth_user_username (username)
|
||||
) COMMENT='系统用户表';
|
||||
|
||||
-- 5) 设备节点表
|
||||
CREATE TABLE IF NOT EXISTS tms_device_node (
|
||||
id BIGINT PRIMARY KEY COMMENT '主键ID',
|
||||
node_id VARCHAR(64) NOT NULL COMMENT '节点业务ID',
|
||||
host VARCHAR(128) NOT NULL COMMENT '节点主机地址',
|
||||
status VARCHAR(32) NOT NULL COMMENT '节点状态',
|
||||
create_time DATETIME(3) NOT NULL COMMENT '创建时间',
|
||||
update_time DATETIME(3) NOT NULL COMMENT '更新时间',
|
||||
UNIQUE KEY uk_tms_device_node_node_id (node_id)
|
||||
) COMMENT='设备节点表';
|
||||
|
||||
-- 6) 可选初始化数据(按需启用)
|
||||
-- INSERT INTO tms_auth_user (id, username, display_name, role, create_time, update_time)
|
||||
-- VALUES (10001, 'admin', '系统管理员', 'ADMIN', NOW(3), NOW(3));
|
||||
Reference in New Issue
Block a user