RMDC系统设计文档 整体转换为SKILL

This commit is contained in:
zeaslity
2026-01-21 16:15:49 +08:00
parent fc72a7312e
commit 631cce9e1e
163 changed files with 37099 additions and 114 deletions

View File

@@ -0,0 +1,224 @@
# RMDC 产品需求文档 (PRD)
**产品名称**: RMDC (Runtime Management & DevOps Center)
**版本**: v1.0
**编制日期**: 2026-01-06
---
## 1. 产品背景
### 1.1 业务背景
在复杂的混合云/边缘计算环境中,运维团队面临以下挑战:
- **网络隔离**: 多个项目部署在不同网络环境(内网、边缘、公网)
- **权限分散**: Jenkins、K8S、主机等资源权限管理分散
- **状态不可见**: 无法统一查看各项目的运行状态
- **操作复杂**: 跨网络的操作需要繁琐的VPN/跳板机流程
### 1.2 痛点总结
| 痛点 | 当前方案 | 问题 |
|------|----------|------|
| 跨网络访问 | VPN + 跳板机 | 效率低,依赖人工 |
| 分支权限管理 | Jenkins原生 | 粒度粗,无法精细控制 |
| 项目状态监控 | 分散的监控系统 | 无统一视图 |
| 自动化部署 | 手动脚本 | 可靠性差,无审计 |
---
## 2. 产品定位
RMDC是**以项目(K8s Namespace)为核心维度**的统一运维与交付平台,通过"边缘代理 + 消息总线"架构打通网络边界,提供:
- **统一入口**: 一个平台管理所有项目
- **精细权限**: 分支级别的构建权限控制
- **实时可见**: 项目状态、构建进度、监控数据统一展示
- **全程审计**: 所有操作可追溯
---
## 3. 目标用户
| 用户角色 | 关键诉求 |
|----------|----------|
| **超级管理员(SuperAdmin)** | 管理所有项目、用户、权限 |
| **管理员(Admin)** | 管理负责的项目,分配权限给普通用户 |
| **普通人员(Normal)** | 查看项目信息,触发被授权的构建 |
| **第三方人员(Third)** | 有限度地查看被授权的内容 |
---
## 4. 功能范围
### 4.1 核心功能模块
```mermaid
mindmap
root((RMDC))
Jenkins模块
组织/仓库/分支管理
分支级权限控制(DAC)
构建触发与追踪
镜像打包(DCU)
项目管理模块
项目信息CRUD
部署信息管理
授权管理(一级)
消息网关模块
MQTT消息中继
指令生命周期
同步/异步指令
边缘代理模块
K8S操作代理
主机操作代理
二级授权管理
监控日志模块
实时日志查看
监控数据采集
告警通知
用户权限模块
用户管理
角色管理
权限分配
审计模块
操作审计
日志查询
导出功能
```
### 4.2 第一期功能(MVP)
| 模块 | 功能 | 优先级 |
|------|------|--------|
| Jenkins | 组织/仓库/分支查询 | P0 |
| Jenkins | 构建触发与状态追踪 | P0 |
| Jenkins | 分支级权限控制 | P0 |
| 项目管理 | 项目信息CRUD | P0 |
| 项目管理 | 授权密钥生成 | P0 |
| 用户权限 | RBAC权限管理 | P0 |
| 审计 | 基础操作审计 | P1 |
| DCU | 镜像下载压缩上传 | P1 |
### 4.3 第二期功能
| 模块 | 功能 | 优先级 |
|------|------|--------|
| 消息网关 | MQTT消息中继 | P0 |
| 消息网关 | 指令生命周期管理 | P0 |
| 边缘代理 | K8S操作代理 | P0 |
| 边缘代理 | 主机操作代理 | P1 |
| 监控日志 | 实时日志查看 | P1 |
| 监控日志 | 监控数据展示 | P2 |
---
## 5. 用户故事
### 5.1 Jenkins构建
**作为** 开发人员
**我需要** 在RMDC平台触发指定分支的构建
**以便于** 快速验证代码变更无需登录Jenkins
**验收标准**:
- [ ] 能够查看被授权的分支列表
- [ ] 能够触发分支构建
- [ ] 能够查看构建进度和结果
- [ ] 能够查看构建日志
### 5.2 权限管理
**作为** 管理员
**我需要** 为团队成员分配分支级构建权限
**以便于** 确保只有授权人员能够构建特定分支
**验收标准**:
- [ ] 能够按组织/仓库/分支粒度分配权限
- [ ] 权限支持继承(组织→仓库→分支)
- [ ] 能够一键复制其他用户的权限
### 5.3 项目管理
**作为** 超级管理员
**我需要** 创建和管理项目信息
**以便于** 统一维护各项目的基本信息和授权配置
**验收标准**:
- [ ] 能够创建项目并录入基本信息
- [ ] 能够管理项目的部署信息和中间件配置
- [ ] 能够生成项目授权密钥
- [ ] 能够导出项目信息
---
## 6. 非功能性需求
### 6.1 性能要求
| 指标 | 要求 |
|------|------|
| API响应时间 | P90 < 300ms |
| 构建状态同步延迟 | < 15s |
| MQTT消息传输延迟 | < 5s |
| 系统可用性 | 99.9% |
### 6.2 安全要求
| 类别 | 要求 |
|------|------|
| 认证 | JWT Token有效期可配置 |
| 授权 | RBAC + 资源级ACL |
| 传输 | HTTPS/TLS加密 |
| 存储 | 敏感字段AES-256加密 |
| 审计 | 所有写操作记录审计日志 |
### 6.3 兼容性
- **前端**: Chrome 80+, Edge 80+, Firefox 75+
- **后端**: Go 1.21+
- **数据库**: PostgreSQL 13+
---
## 7. 系统边界
### 7.1 与外部系统的关系
| 外部系统 | 交互方式 | 说明 |
|----------|----------|------|
| Jenkins | REST API | 构建管理状态同步 |
| MinIO | S3 API | 镜像包存储 |
| MQTT Broker | MQTT协议 | 消息中继 |
| K8S | K8S API | 容器编排 |
### 7.2 不在范围内
- 源代码管理由GitLab/GitHub负责
- CI/CD编排逻辑由Jenkins Pipeline负责
- 容器镜像仓库由Harbor负责
- 基础设施管理由IaaS平台负责
---
## 8. 约束和假设
### 8.1 约束
1. 必须兼容现有Jenkins配置不修改Jenkinsfile
2. 边缘项目通过公网MQTT通信需考虑弱网环境
3. 授权密钥离线部署不通过网络传输
### 8.2 假设
1. 所有边缘项目均部署在K8S环境
2. 各项目有独立的K8S Namespace
3. MQTT Broker可从公网访问
---
## 9. 版本历史
| 版本 | 日期 | 修改内容 |
|------|------|----------|
| v1.0 | 2026-01-06 | 初始版本 |

View File

@@ -0,0 +1,170 @@
# RMDC系统架构提示词
> 本文档为大模型(AI助手)提供RMDC系统的全面上下文帮助AI理解系统架构并协助开发工作。
---
## 系统定位
**RMDC (Runtime Management & DevOps Center)** 是一个以项目(K8s Namespace)为核心维度的统一运维与交付平台。通过"边缘代理(Watchdog) + 消息总线(Exchange-Hub)"架构打通内外网,提供从代码构建、分支权限控制、自动化部署到实时监控日志的全生命周期管理。
---
## 核心模块清单
| 模块 | 职责 | 关键技术 |
|------|------|----------|
| **rmdc-core** | API Gateway、鉴权、路由 | Go + Gin |
| **rmdc-jenkins-branch-dac** | Jenkins分支权限(DAC)、构建管理 | Jenkins API, MinIO |
| **rmdc-exchange-hub** | MQTT消息网关、指令生命周期 | MQTT, PostgreSQL |
| **rmdc-watchdog** | 边缘代理、K8S操作、二级授权 | K8S API, TOTP |
| **rmdc-project-management** | 项目管理、一级授权中心 | PostgreSQL |
| **rmdc-audit-log** | 审计日志 | PostgreSQL |
| **rmdc-user-auth** | 用户认证、权限管理 | JWT, RBAC |
---
## 系统架构图
```mermaid
graph TB
subgraph "RMDC平台 (内网)"
Portal[前端门户<br/>Vue3+Vuetify3]
Core[rmdc-core<br/>API Gateway]
subgraph "业务模块"
Jenkins[jenkins-branch-dac]
Project[project-management]
Audit[audit-log]
UserAuth[user-auth]
end
ExHub[exchange-hub<br/>消息网关]
MQTT[(MQTT Broker)]
end
subgraph "外部项目环境"
WD[rmdc-watchdog<br/>边缘代理]
Node[watchdog-node]
Agent[watchdog-agent]
end
Portal --> Core --> Jenkins & Project & Audit & UserAuth
Project --> ExHub <--> MQTT <-.公网.-> WD <--> Node & Agent
```
---
## 通信架构
### MQTT Topic设计
| 方向 | Topic | 用途 |
|------|-------|------|
| **上行** | `wdd/RDMC/command/up` | Watchdog发送指令 |
| **上行** | `wdd/RDMC/message/up` | Watchdog发送数据 |
| **下行** | `wdd/RDMC/command/down/{project_id}` | 下发指令 |
| **下行** | `wdd/RDMC/message/down/{project_id}` | 下发数据 |
### 安全机制
```
一级授权: rmdc-project-management ↔ rmdc-watchdog (8位码, 30分钟有效)
二级授权: rmdc-watchdog ↔ watchdog-agent/node (6位码, 30秒有效)
```
---
## API设计规范
> **重要**: RMDC API遵循以下规范
1. **RESTful风格**使用标准HTTP方法语义
2. **优先POST+RequestBody**复杂查询和所有写操作使用POST
3. **避免PathVariables**资源标识放入RequestBody
4. **避免RequestParams**查询参数放入RequestBody
5. **统一响应格式**
```json
{
"code": 0,
"message": "success",
"data": {...}
}
```
---
## 开发规范
### 后端规范(Go)
```
项目结构:
├── cmd/ # 入口
├── configs/ # 配置
├── internal/
│ ├── config/ # 配置结构
│ ├── dao/ # 数据访问层
│ ├── handler/ # HTTP处理器
│ ├── model/
│ │ ├── dto/ # 请求/响应DTO
│ │ └── entity/ # 数据库实体
│ └── service/ # 业务逻辑层
└── pkg/ # 公共包
```
**关键约束**:
- 禁止在Handler层写业务逻辑
- 所有SQL在DAO层
- 使用GORM进行ORM操作
### 前端规范(Vue3)
- 技术栈: Vue3 + TypeScript + Vuetify3
- 使用Composition API
- 组件销毁时断开WebSocket连接
---
## 核心业务流程
### 项目注册流程
```
1. project-management创建项目 → 生成密钥
2. 部署watchdog(携带配置文件)
3. watchdog连接MQTT → 发送注册请求(含TOTP)
4. exchange-hub验证 → 发送挑战码
5. watchdog回复挑战码 → 注册成功
```
### 构建触发流程
```
1. 用户调用 POST /builds/trigger
2. jenkins-branch-dac 调用 Jenkins API
3. BuildTracker开始追踪构建状态
4. 前端轮询构建详情
5. 构建完成 → 可触发DCU打包镜像
```
---
## 文档索引
| 文档路径 | 内容 |
|----------|------|
| `1-基本框架/2-rmdc-DDS.md` | 系统PRD/DDS |
| `2-Jenkins模块/1-jenkins-branch-dac-DDS.md` | Jenkins模块DDS |
| `3-rmdc-exchange-hub/1-rmdc-exchange-hub-DDS.md` | Exchange-Hub DDS |
| `4-rmdc-project-management/1-rmdc-project-management-DDS.md` | 项目管理DDS |
| `6-rmdc-watchdog/1-rmdc-watchdog-DDS.md` | Watchdog DDS |
---
## 如何使用本提示词
1. **理解系统**: 阅读架构说明和业务流程
2. **定位模块**: 确定涉及的模块
3. **查阅详细文档**: 参考模块DDS
4. **遵循规范**: 按照API和开发规范编码

View File

@@ -0,0 +1,150 @@
# 模块交互流程提示词
> 本文档描述RMDC系统各模块之间的交互流程帮助大模型理解数据流和调用关系。
---
## 模块调用关系
```mermaid
graph LR
FE[Vue3 Frontend] --> Core[rmdc-core]
Core --> Jenkins[jenkins-branch-dac]
Core --> Project[project-management]
Core --> Audit[audit-log]
Core --> UserAuth[user-auth]
Core --> ExHub[exchange-hub]
ExHub <--> MQTT[(MQTT)]
MQTT <--> WD[watchdog]
WD <--> Node[watchdog-node]
WD <--> Agent[watchdog-agent]
```
---
## 核心交互流程
### 1. 用户请求处理
```mermaid
sequenceDiagram
participant FE as 前端
participant Core as rmdc-core
participant Auth as AuthMiddleware
participant Perm as PermMiddleware
participant Biz as 业务模块
FE->>Core: HTTP Request (JWT)
Core->>Auth: 验证Token
Auth->>Perm: 权限校验
Perm->>Biz: 处理业务
Biz-->>FE: HTTP Response
```
### 2. Jenkins构建触发
```mermaid
sequenceDiagram
participant User as 用户
participant Handler as BuildHandler
participant Service as BuildService
participant Jenkins as Jenkins API
participant Tracker as BuildTracker
User->>Handler: POST /builds/trigger
Handler->>Service: TriggerBuild()
Service->>Jenkins: 触发构建
Service->>Tracker: TrackBuild()
Service-->>User: 返回构建号
```
### 3. 项目注册授权
```mermaid
sequenceDiagram
participant PM as project-management
participant ExHub as exchange-hub
participant MQTT as MQTT Broker
participant WD as watchdog
Note over PM: 创建项目,生成密钥
WD->>MQTT: 发送注册请求(TOTP)
MQTT->>ExHub: 转发
ExHub->>PM: 验证项目
PM-->>ExHub: 返回结果
ExHub->>MQTT: 发送挑战码
MQTT->>WD: 推送
WD->>MQTT: 回复挑战
ExHub->>ExHub: 验证成功,项目上线
```
### 4. K8S指令执行
```mermaid
sequenceDiagram
participant User as 用户
participant API as rmdc-core
participant ExHub as exchange-hub
participant MQTT as MQTT
participant WD as watchdog
participant K8S as K8S API
User->>API: 发起K8S操作
API->>ExHub: 发送指令
ExHub->>MQTT: 发布command
MQTT->>WD: 推送指令
WD->>K8S: 执行操作
K8S-->>WD: 返回结果
WD->>MQTT: 发布result
MQTT->>ExHub: 接收结果
ExHub->>API: 返回结果
API->>User: 展示结果
```
---
## 数据流向
### 下行数据流
```
用户操作 → rmdc-core → 业务模块 → exchange-hub → MQTT → watchdog → 执行目标
```
### 上行数据流
```
执行目标 → watchdog → MQTT → exchange-hub → 业务模块 → 持久化/展示
```
---
## 接口契约
### MQTT消息格式
```json
{
"message_id": "uuid",
"type": "command|message",
"project_id": "namespace_xxx",
"command_type": "k8s_exec|host_exec|...",
"timestamp": 1704501234567,
"payload": {...},
"signature": "hmac-sha256"
}
```
### 执行结果格式
```json
{
"command_id": "原指令ID",
"status": "success|failure|timeout",
"exit_code": 0,
"output": "执行输出",
"error": "",
"duration": 1111
}
```

View File

@@ -0,0 +1,244 @@
# RMDC 详细设计说明书 (DDS)
**产品名称**: RMDC (Runtime Management & DevOps Center)
**版本**: v1.0
**编制日期**: 2026-01-06
---
## 1. 系统架构
### 1.1 整体架构图
```mermaid
graph TB
subgraph "前端层"
Portal[RMDC Portal<br/>Vue3 + Vuetify3]
end
subgraph "网关层"
Core[rmdc-core<br/>API Gateway + 鉴权]
end
subgraph "业务层"
Jenkins[rmdc-jenkins-branch-dac<br/>构建管理]
Project[rmdc-project-management<br/>项目管理]
Audit[rmdc-audit-log<br/>审计日志]
UserAuth[rmdc-user-auth<br/>用户权限]
ExHub[rmdc-exchange-hub<br/>消息网关]
end
subgraph "通信层"
MQTT[(MQTT Broker)]
end
subgraph "边缘层"
WD[rmdc-watchdog<br/>边缘代理]
Node[watchdog-node<br/>主机代理]
Agent[watchdog-agent<br/>业务启动器]
end
subgraph "外部服务"
JenkinsS[(Jenkins)]
MinIO[(MinIO)]
PG[(PostgreSQL)]
end
Portal --> Core
Core --> Jenkins & Project & Audit & UserAuth & ExHub
Jenkins --> JenkinsS & MinIO
Project & Jenkins & Audit --> PG
ExHub <--> MQTT
MQTT <-.公网.-> WD
WD <--> Node & Agent
```
### 1.2 技术栈
| 层级 | 技术 |
|------|------|
| 前端 | Vue3, TypeScript, Vuetify3 |
| 后端 | Go 1.21+, Gin, GORM |
| 数据库 | PostgreSQL 13+ |
| 消息 | MQTT (Eclipse Mosquitto) |
| 存储 | MinIO |
| 容器 | Docker, Kubernetes |
---
## 2. 模块职责
### 2.1 模块清单
| 模块 | 职责 | 关键能力 |
|------|------|----------|
| **rmdc-core** | API网关 | 路由、鉴权、限流 |
| **rmdc-jenkins-branch-dac** | Jenkins管理 | 分支权限、构建触发、DCU |
| **rmdc-project-management** | 项目管理 | CRUD、一级授权 |
| **rmdc-exchange-hub** | 消息网关 | MQTT中继、指令管理 |
| **rmdc-watchdog** | 边缘代理 | K8S操作、二级授权 |
| **rmdc-audit-log** | 审计日志 | 日志记录、查询导出 |
| **rmdc-user-auth** | 用户权限 | RBAC、权限分配 |
### 2.2 模块依赖关系
```mermaid
graph LR
Core[rmdc-core] --> Jenkins & Project & Audit & UserAuth & ExHub
Jenkins --> Common
Project --> Common
ExHub --> Common
UserAuth --> Common
Common[rmdc-common<br/>公共接口]
```
---
## 3. 通信架构
### 3.1 MQTT Topic设计
| Topic | 方向 | 用途 |
|-------|------|------|
| `wdd/RDMC/command/up` | 上行 | Watchdog发送指令 |
| `wdd/RDMC/message/up` | 上行 | Watchdog发送数据 |
| `wdd/RDMC/command/down/{project_id}` | 下行 | 下发指令 |
| `wdd/RDMC/message/down/{project_id}` | 下行 | 下发数据 |
### 3.2 消息格式
```json
{
"message_id": "uuid",
"type": "command|message",
"project_id": "namespace_xxx",
"command_type": "k8s_exec|host_exec|register|...",
"timestamp": 1704501234567,
"version": "1.0",
"signature": "hmac-sha256",
"payload": {...}
}
```
---
## 4. 安全架构
### 4.1 认证授权
| 层级 | 机制 |
|------|------|
| 用户认证 | JWT Token |
| API授权 | RBAC + 资源ACL |
| MQTT认证 | 用户名密码 + TLS |
| 数据加密 | AES-256-GCM |
### 4.2 TOTP双层授权
```
一级授权: project-management ↔ watchdog
- 8位验证码
- 30分钟有效期
- SHA256算法
二级授权: watchdog ↔ agent/node
- 6位验证码
- 30秒有效期
- SHA1算法
```
---
## 5. 数据模型
### 5.1 核心实体
```mermaid
erDiagram
users ||--o{ user_permissions : has
projects ||--o{ auth_info : has
jenkins_organizations ||--o{ jenkins_repositories : contains
jenkins_repositories ||--o{ jenkins_branches : contains
jenkins_branches ||--o{ jenkins_builds : contains
users {
int64 id PK
string username UK
string password
string role
}
projects {
int64 id PK
string project_id UK
string name
string namespace UK
string status
}
jenkins_organizations {
int64 id PK
string name UK
}
```
---
## 6. API设计规范
### 6.1 设计原则
1. **使用POST + RequestBody**: 所有API优先使用POST
2. **避免PathVariables**: 资源标识放入RequestBody
3. **避免RequestParams**: 查询参数放入RequestBody
4. **统一响应格式**: `{code, message, data}`
### 6.2 接口命名规范
| 操作 | 后缀 | 示例 |
|------|------|------|
| 列表 | `/list` | `/api/projects/list` |
| 详情 | `/detail` | `/api/projects/detail` |
| 创建 | `/create` | `/api/projects/create` |
| 更新 | `/update` | `/api/projects/update` |
| 删除 | `/delete` | `/api/projects/delete` |
---
## 7. 部署架构
### 7.1 K8S部署
```yaml
# 核心服务
rmdc-core: Deployment (replicas: 2)
rmdc-jenkins-branch-dac: 集成在rmdc-core
rmdc-project-management: 集成在rmdc-core
rmdc-exchange-hub: Deployment (replicas: 1)
rmdc-frontend: Deployment (replicas: 2)
# 边缘服务
rmdc-watchdog: Deployment (replicas: 1, 每项目独立)
rmdc-watchdog-node: DaemonSet (每节点一个)
```
### 7.2 网络架构
```
内网 ←→ MQTT Broker (公网暴露) ←→ 边缘网络
```
---
## 8. 相关文档
| 文档 | 内容 |
|------|------|
| [1-rmdc-PRD.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/1-rmdc-system/1-rmdc-PRD.md) | 产品需求文档 |
| [1-jenkins-branch-dac-DDS.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/1-jenkins-branch-dac-DDS.md) | Jenkins模块DDS |
| [prompts/1-system-overview-prompt.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/1-rmdc-system/prompts/1-system-overview-prompt.md) | 系统架构提示词 |
| [prompts/3-api-development-prompt.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/1-rmdc-system/prompts/3-api-development-prompt.md) | API开发规范 |
| [prompts/4-postman-testing-prompt.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/1-rmdc-system/prompts/4-postman-testing-prompt.md) | Postman测试用例 |

View File

@@ -0,0 +1,294 @@
# RDMC 系统架构设计图
## 1. RDMC 整体系统架构图
```mermaid
graph TB
subgraph "RDMC 平台核心 (内网环境)"
Portal["前端门户<br/>Vue3+Vuetify3+TypeScript"]
subgraph "核心业务模块"
JenkinsDAC["jenkins-branch-dac<br/>Jenkins分支管理"]
LogCenter["log-center<br/>日志中心"]
MonitorCenter["monitor-center<br/>监控中心"]
DeliveryUpdate["delivery-update<br/>业务更新"]
Notice["notice-center<br/>消息通知中心"]
Operator["octopus-operator<br/>执行中心"]
ProjectMgmt["project-management<br/>项目管理"]
Audit["audit-log<br/>审计模块"]
end
subgraph "基础设施层"
WatchdogCenter["watchdog-center<br/>一级授权中心"]
ExchangeHub["exchange-hub<br/>消息网关"]
UserAuth["user-auth<br/>用户认证"]
Core["rmdc-core<br/>API Gateway<br/>Go+Gin+GORM"]
DB[(PostgreSQL<br/>业务数据库)]
end
MQTT[(MQTT Broker<br/>EMQX/Mosquitto)]
end
subgraph "外部系统"
Jenkins[Jenkins CI/CD]
DingTalk[钉钉告警]
MinIO[MinIO 对象存储]
end
subgraph "项目环境 A (外网/隔离网络)"
K8sA[Kubernetes Cluster A]
subgraph "Namespace: project-a"
WatchdogA["rmdc-watchdog<br/>二级授权中心<br/>K8s Operator"]
subgraph "微服务Pod"
ServiceA1["业务A1<br/>watchdog-agent"]
ServiceA2["业务A2<br/>watchdog-agent"]
end
end
subgraph "主机层"
HostA1["主机A1<br/>watchdog-node<br/>DaemonSet"]
HostA2["主机A2<br/>watchdog-node<br/>DaemonSet"]
end
end
subgraph "项目环境 B (外网/隔离网络)"
K8sB[Kubernetes Cluster B]
subgraph "Namespace: project-b"
WatchdogB["rmdc-watchdog<br/>二级授权中心"]
ServiceB1["业务B1<br/>watchdog-agent"]
end
HostB1["主机B1<br/>watchdog-node"]
end
%% 前端到后端连接
Portal --> Core
%% 核心模块连接
Core --> JenkinsDAC
Core --> LogCenter
Core --> MonitorCenter
Core --> DeliveryUpdate
Core --> Notice
Core --> Operator
Core --> ProjectMgmt
Core --> Audit
Core --> UserAuth
%% 项目管理与授权中心
ProjectMgmt -.项目创建/授权.-> WatchdogCenter
WatchdogCenter -.授权信息.-> ExchangeHub
%% Exchange-Hub与MQTT
ExchangeHub <==订阅/发布==> MQTT
%% 业务模块到Exchange-Hub
LogCenter -.指令下发.-> ExchangeHub
MonitorCenter -.指令下发.-> ExchangeHub
DeliveryUpdate -.指令下发.-> ExchangeHub
Operator -.指令下发.-> ExchangeHub
%% MQTT到外部项目 (跨公网)
MQTT <=="Command/Message<br/>公网"==> WatchdogA
MQTT <=="Command/Message<br/>公网"==> WatchdogB
%% 项目内部通信
WatchdogA <--"授权心跳<br/>TOTP验证"--> ServiceA1
WatchdogA <--"授权心跳<br/>TOTP验证"--> ServiceA2
WatchdogA <--"主机信息<br/>指令执行"--> HostA1
WatchdogA <--"主机信息<br/>指令执行"--> HostA2
WatchdogB <--授权心跳--> ServiceB1
WatchdogB <--主机信息--> HostB1
%% 数据持久化
Core --> DB
ExchangeHub --> DB
%% 外部系统集成
JenkinsDAC --> Jenkins
Notice --> DingTalk
DeliveryUpdate --> MinIO
style ExchangeHub fill:#ff6b6b,stroke:#c92a2a,stroke-width:3px
style MQTT fill:#ffd43b,stroke:#f08c00,stroke-width:2px
style WatchdogA fill:#4ecdc4,stroke:#087f5b,stroke-width:2px
style WatchdogB fill:#4ecdc4,stroke:#087f5b,stroke-width:2px
style WatchdogCenter fill:#ff8787,stroke:#c92a2a,stroke-width:2px
style Portal fill:#845ef7,stroke:#5f3dc4
style ProjectMgmt fill:#a9e34b,stroke:#5c940d,stroke-width:2px
```
---
## 2. 模块层级架构图
```mermaid
graph TB
subgraph "用户层"
User["用户/管理员"]
end
subgraph "表现层 (Presentation)"
Frontend["Vue3 + Vuetify3<br/>SPA应用"]
end
subgraph "网关层 (Gateway)"
APIGateway["rmdc-core<br/>API Gateway<br/>路由 | 鉴权 | 限流"]
end
subgraph "业务层 (Business)"
subgraph "业务模块"
M1["jenkins-branch-dac"]
M2["log-center"]
M3["monitor-center"]
M4["delivery-update"]
M5["notice-center"]
M6["octopus-operator"]
M7["project-management"]
end
subgraph "基础模块"
Auth["user-auth<br/>用户认证授权"]
AuditLog["audit-log<br/>审计日志"]
end
end
subgraph "通信层 (Communication)"
ExHub["exchange-hub<br/>消息网关"]
end
subgraph "消息中间件层"
MQTT["MQTT Broker"]
end
subgraph "边缘层 (Edge)"
direction LR
WD["rmdc-watchdog<br/>二级授权中心"]
WDNode["watchdog-node<br/>主机守护"]
WDAgent["watchdog-agent<br/>业务代理"]
end
subgraph "数据层 (Data)"
PG[(PostgreSQL)]
end
User --> Frontend
Frontend --> APIGateway
APIGateway --> M1
APIGateway --> M2
APIGateway --> M3
APIGateway --> M4
APIGateway --> M5
APIGateway --> M6
APIGateway --> M7
APIGateway --> Auth
APIGateway --> AuditLog
M2 --> ExHub
M3 --> ExHub
M4 --> ExHub
M6 --> ExHub
M7 --> ExHub
ExHub <--> MQTT
MQTT <--> WD
WD --> WDNode
WD --> WDAgent
M1 --> PG
Auth --> PG
AuditLog --> PG
ExHub --> PG
M3 --> PG
M7 --> PG
style ExHub fill:#ff6b6b,stroke:#c92a2a
style MQTT fill:#ffd43b,stroke:#f08c00
style WD fill:#4ecdc4,stroke:#087f5b
```
---
## 3. 通信架构图
```mermaid
graph LR
subgraph "RMDC平台"
Portal["前端门户"]
API["API Gateway"]
ExHub["Exchange-Hub"]
Modules["业务模块"]
end
subgraph "消息通道"
MQTT["MQTT Broker"]
end
subgraph "外部项目"
WD["Watchdog"]
Node["Node"]
Agent["Agent"]
end
Portal ==HTTP/REST==> API
API ==内部调用==> Modules
Modules ==指令请求==> ExHub
ExHub ==MQTT Publish==> MQTT
MQTT ==MQTT Subscribe==> WD
WD ==执行结果==> MQTT
MQTT ==结果推送==> ExHub
ExHub ==结果返回==> Modules
WD <==内网通信==> Node
WD <==内网通信==> Agent
style MQTT fill:#ffd43b,stroke:#f08c00,stroke-width:2px
style ExHub fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px
```
---
## 4. 数据流向图
```mermaid
flowchart TD
subgraph "指令下行流程"
direction TB
U1[用户操作] --> F1[前端请求]
F1 --> A1[API Gateway]
A1 --> M1[业务模块]
M1 --> E1[Exchange-Hub]
E1 --> Q1[MQTT Broker]
Q1 --> W1[Watchdog]
W1 --> T1{目标类型}
T1 -->|K8S| K1[K8S API]
T1 -->|主机| N1[watchdog-node]
T1 -->|业务| G1[watchdog-agent]
end
subgraph "数据上行流程"
direction BT
K2[K8S执行结果] --> W2[Watchdog]
N2[主机执行结果] --> W2
G2[业务状态] --> W2
W2 --> Q2[MQTT Broker]
Q2 --> E2[Exchange-Hub]
E2 --> D1{数据类型}
D1 -->|执行结果| M2[Operator]
D1 -->|监控数据| M3[Monitor]
D1 -->|日志数据| M4[LogCenter]
D1 -->|告警数据| M5[Notice]
end
style E1 fill:#ff6b6b,stroke:#c92a2a
style E2 fill:#ff6b6b,stroke:#c92a2a
style Q1 fill:#ffd43b,stroke:#f08c00
style Q2 fill:#ffd43b,stroke:#f08c00
```

View File

@@ -0,0 +1,693 @@
# RMDC 审计日志架构设计
## 1. 审计日志模块整体架构
```mermaid
graph TB
subgraph "前端 Frontend"
Vue[Vue3 前端应用]
end
subgraph "rmdc-core 核心模块"
Router[Gin Router]
CORS[CORS 中间件]
Audit[审计中间件<br/>AuditMiddleware]
Auth[认证中间件<br/>AuthMiddleware]
end
subgraph "业务模块层"
Jenkins[rmdc-jenkins-branch-dac<br/>Jenkins模块]
UserAuth[rmdc-user-auth<br/>用户认证模块]
Watchdog[rmdc-watchdog-center<br/>Watchdog模块]
end
subgraph "rmdc-audit-log 审计模块"
AuditWriter[AuditWriter 接口]
AuditService[AuditService<br/>审计服务]
DAOManager[AuditLogDAOManager<br/>DAO管理器]
CoreDAO[AuditLogDao<br/>核心模块DAO]
JenkinsDAO[JenkinsAuditLogDao<br/>Jenkins模块DAO]
end
subgraph "数据持久层 - rmdc_audit 数据库"
DB[(PostgreSQL)]
CoreTable[core_audit_logs]
JenkinsTable[jenkins_audit_logs]
WatchdogTable[watchdog_audit_logs]
UserAuthTable[user_auth_audit_logs]
end
Vue -->|HTTP Request| Router
Router --> CORS
CORS --> Audit
Audit -->|记录审计日志| AuditWriter
AuditWriter --> AuditService
Audit --> Auth
Auth --> Jenkins
Auth --> UserAuth
Auth --> Watchdog
Jenkins -.->|WriteJenkinsLog| AuditWriter
AuditService --> DAOManager
DAOManager --> CoreDAO
DAOManager --> JenkinsDAO
CoreDAO --> DB
JenkinsDAO --> DB
DB --> CoreTable
DB --> JenkinsTable
DB --> WatchdogTable
DB --> UserAuthTable
style Audit fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px
style AuditService fill:#4ecdc4,stroke:#087f5b,stroke-width:2px
style DAOManager fill:#74c0fc,stroke:#1864ab,stroke-width:2px
style DB fill:#ffd43b,stroke:#f08c00,stroke-width:2px
```
---
## 2. Jenkins 模块审计日志写入流程
以触发 Jenkins 构建为例,展示一条请求如何被正确写入 `jenkins_audit_logs` 表:
```mermaid
sequenceDiagram
participant U as 用户浏览器
participant F as Vue3 前端
participant R as Gin Router
participant AM as AuditMiddleware
participant Auth as AuthMiddleware
participant JH as Jenkins Handler
participant JS as Jenkins Service
participant AS as AuditService
participant JenkinsDAO as JenkinsAuditLogDao
participant DB as PostgreSQL
rect rgb(220, 240, 255)
Note over U,DB: 阶段1: 请求发起与审计捕获
end
U->>F: 点击"触发构建"按钮
F->>R: POST /api/builds/trigger<br/>{organization, repository, branch}
R->>AM: 请求进入中间件链
activate AM
AM->>AM: 记录开始时间 startTime
AM->>AM: 读取并缓存 RequestBody
AM->>AM: 提取 QueryParams
rect rgb(255, 240, 220)
Note over AM,Auth: 阶段2: 认证与业务处理
end
AM->>Auth: c.Next() 继续处理
Auth->>Auth: 验证JWT Token
Auth->>Auth: 提取 user_id, username
Auth->>JH: 路由到 Jenkins Handler
JH->>JS: TriggerBuild(org, repo, branch)
JS->>JS: 调用 Jenkins API
JS-->>JH: 返回构建结果
JH-->>Auth: 响应 200 OK
Auth-->>AM: 返回控制权
rect rgb(220, 255, 220)
Note over AM,DB: 阶段3: 审计日志异步写入
end
AM->>AM: 计算 duration = time.Since(startTime)
AM->>AM: 从 context 提取 user_id, username
AM->>AM: 提取 resourceType=jenkins_project
AM->>AM: determineAction() → "TRIGGER_BUILD"
AM->>AM: sanitizeSensitiveData(requestBody)
AM->>AS: WriteLog(auditLog) 写入Jenkins缓冲区
deactivate AM
activate AS
AS->>AS: 判断 Module="jenkins"
AS->>AS: 放入 jenkinsLogBuffer
AS->>AS: jenkinsBatchWriter 批量处理
AS->>JenkinsDAO: BatchCreate(ctx, logs)
JenkinsDAO->>DB: INSERT INTO jenkins_audit_logs
DB-->>JenkinsDAO: 写入成功
deactivate AS
Note over DB: jenkins_audit_logs 表中新增一条记录:<br/>action=TRIGGER_BUILD<br/>organization=Backend<br/>repository=cmii-fly-center<br/>branch=feature-xxx
```
### 关键代码路径
| 步骤 | 文件 | 函数/方法 | 说明 |
|------|------|-----------|------|
| 1 | `pkg/middleware/audit_middleware.go` | `AuditMiddleware()` | 中间件入口,捕获请求信息 |
| 2 | `pkg/middleware/audit_middleware.go` | `determineAction()` | 根据 HTTP 方法和路径确定操作类型 |
| 3 | `pkg/middleware/audit_middleware.go` | `extractResourceInfo()` | 提取资源类型和资源ID |
| 4 | `pkg/middleware/audit_middleware.go` | `sanitizeSensitiveData()` | 脱敏处理敏感数据 |
| 5 | `internal/service/audit_service.go` | `WriteLog()` | 实现 AuditWriter 接口,按模块路由到不同缓冲区 |
| 6 | `internal/service/audit_service.go` | `jenkinsBatchWriter()` | Jenkins专用批量写入协程 |
| 7 | `internal/dao/jenkins_audit_log_dao.go` | `BatchCreate()` | Jenkins审计日志批量插入 |
---
## 3. 多模块审计日志记录方式
### 3.1 审计日志表结构
RMDC 采用**分表存储**策略,每个业务模块有独立的审计日志表,继承公共基础字段并扩展模块特定字段:
```mermaid
erDiagram
AuditLog {
int64 id PK
string module
int64 user_id FK
string username
string action
string resource_type
string resource_id
text details
string ip_address
string status
text error_message
datetime created_at
}
JenkinsAuditLog {
int64 id PK
string organization
string repository
string branch
int build_number
string artifact_name
int64 artifact_size
string artifact_type
}
WatchdogAuditLog {
int64 id PK
string project_id
string project_name
text host_info
}
UserAuthAuditLog {
int64 id PK
string login_type
string device_info
}
AuditLog ||--|| JenkinsAuditLog : "继承"
AuditLog ||--|| WatchdogAuditLog : "继承"
AuditLog ||--|| UserAuthAuditLog : "继承"
```
### 3.2 模块与表的对应关系
| 模块 | 表名 | 扩展字段 | 典型操作 |
|------|------|----------|----------|
| Core | `core_audit_logs` | 无 | 系统配置修改、审计日志清理 |
| Jenkins | `jenkins_audit_logs` | organization, repository, branch, build_number, artifact_name, artifact_size, artifact_type | 触发构建、同步Jenkins、DCU任务、交付物构建 |
| Watchdog | `watchdog_audit_logs` | project_id, project_name, host_info | 主机授权、项目注册 |
| UserAuth | `user_auth_audit_logs` | login_type, device_info | 用户创建、角色修改 |
### 3.3 DAO 管理器架构
```mermaid
classDiagram
class AuditLogDAOManager {
+Core *AuditLogDao
+Jenkins *JenkinsAuditLogDao
+GetDAO(module string) interface{}
}
class AuditLogDao {
-db *gorm.DB
+Create(ctx, log) error
+BatchCreate(ctx, logs) error
+List(ctx, module, page, pageSize) ([]*AuditLog, int64, error)
}
class JenkinsAuditLogDao {
-db *gorm.DB
+Create(ctx, log) error
+BatchCreate(ctx, logs) error
+List(ctx, page, pageSize) ([]*JenkinsAuditLog, int64, error)
+ListByOrganization(ctx, org, page, pageSize) ([]*JenkinsAuditLog, int64, error)
}
AuditLogDAOManager --> AuditLogDao
AuditLogDAOManager --> JenkinsAuditLogDao
```
### 3.4 Jenkins 审计日志写入流程
```mermaid
flowchart TD
A[HTTP 请求到达] --> B{路径包含 /jenkins/ 或 /builds/ 或 /dcu/?}
B -->|是| C[AuditMiddleware 捕获请求]
B -->|否| D[其他模块处理]
C --> E[提取 JWT 中的 user_id, username]
E --> F[解析路径参数: org, repo, branch]
F --> G[determineAction: TRIGGER_BUILD / SYNC_JENKINS / DCU_START]
G --> H[构建 audit.AuditLog 对象]
H --> I[调用 AuditWriter.WriteLog]
I --> J[AuditService.WriteLog]
J --> K{判断模块类型 + DAOManager存在?}
K -->|jenkins + 有DAOManager| L[构建 JenkinsAuditLog]
K -->|其他| M[构建 AuditLog]
L --> N[放入 jenkinsLogBuffer]
N --> O[jenkinsBatchWriter 批量处理]
O --> P[JenkinsAuditLogDao.BatchCreate]
P --> Q[(写入 jenkins_audit_logs 表)]
M --> R[放入 logBuffer]
R --> S[batchWriter 批量处理]
S --> T[AuditLogDao.BatchCreate]
T --> U[(写入 core_audit_logs 表)]
style C fill:#ff6b6b,stroke:#c92a2a
style I fill:#4ecdc4,stroke:#087f5b
style Q fill:#ffd43b,stroke:#f08c00
style U fill:#ffd43b,stroke:#f08c00
```
---
## 4. AuditWriter 接口实现
### 4.1 接口定义
位置: `rmdc-audit-log/pkg/audit/interface.go`
```go
// AuditLog 审计日志结构(公共接口)
type AuditLog struct {
UserID int64 `json:"user_id"`
Username string `json:"username"`
Action string `json:"action"`
ResourceType string `json:"resource_type"`
ResourceID string `json:"resource_id"`
IPAddress string `json:"ip_address"`
Method string `json:"method"`
Path string `json:"path"`
QueryParams string `json:"query_params"`
RequestBody string `json:"request_body"`
Duration int64 `json:"duration"`
Module string `json:"module,omitempty"` // 显式指定模块(可选)
}
// AuditWriter 审计日志写入接口
type AuditWriter interface {
// WriteLog 写入审计日志通用方法根据Path自动判断模块
WriteLog(log *AuditLog)
// WriteJenkinsLog 写入Jenkins模块审计日志
// 用于需要记录Jenkins专属字段的场景
WriteJenkinsLog(log *JenkinsAuditLogInput)
}
// JenkinsAuditLogInput Jenkins审计日志输入结构
type JenkinsAuditLogInput struct {
// 通用字段
UserID int64 `json:"user_id"`
Username string `json:"username"`
Action string `json:"action"`
ResourceType string `json:"resource_type"`
ResourceID string `json:"resource_id"`
IPAddress string `json:"ip_address"`
Details string `json:"details"`
// Jenkins专属字段
Organization string `json:"organization"`
Repository string `json:"repository"`
Branch string `json:"branch"`
BuildNumber int `json:"build_number"`
// 交付物相关字段
ArtifactName string `json:"artifact_name"`
ArtifactSize int64 `json:"artifact_size"`
ArtifactType string `json:"artifact_type"` // docker_image, gzip, jar等
}
```
### 4.2 模块判断逻辑
```go
func (s *AuditService) determineModule(path string) string {
switch {
case strings.Contains(path, "/jenkins/") ||
strings.Contains(path, "/builds/") ||
strings.Contains(path, "/projects/") ||
strings.Contains(path, "/dcu/"):
return "jenkins"
case strings.Contains(path, "/users/") ||
strings.Contains(path, "/auth/") ||
strings.Contains(path, "/permissions/"):
return "user_auth"
case strings.Contains(path, "/watchdog/"):
return "watchdog"
default:
return "core"
}
}
```
---
## 5. 新模块审计日志表添加指南
如需为新模块添加审计日志表,请按以下步骤操作:
### 5.1 步骤概览
```mermaid
flowchart LR
A[1. 定义Entity] --> B[2. 创建DAO]
B --> C[3. 更新DAOManager]
C --> D[4. 扩展Service]
D --> E[5. 更新模块判断]
E --> F[6. 数据库迁移]
```
### 5.2 详细步骤
#### 步骤1: 定义实体 (Entity)
位置: `rmdc-audit-log/internal/model/entity/audit_log.go`
```go
// NewModuleAuditLog 新模块审计日志
type NewModuleAuditLog struct {
AuditLog // 嵌入基础审计日志
// 添加模块专属字段
CustomField1 string `gorm:"size:255" json:"custom_field_1"`
CustomField2 int64 `json:"custom_field_2"`
}
// TableName 指定表名
func (NewModuleAuditLog) TableName() string {
return "new_module_audit_logs"
}
```
#### 步骤2: 创建DAO
位置: `rmdc-audit-log/internal/dao/new_module_audit_log_dao.go`
```go
type NewModuleAuditLogDao struct {
db *gorm.DB
}
func NewNewModuleAuditLogDao(db *gorm.DB) *NewModuleAuditLogDao {
return &NewModuleAuditLogDao{db: db}
}
func (d *NewModuleAuditLogDao) Create(ctx context.Context, log *entity.NewModuleAuditLog) error {
log.Module = "new_module"
return d.db.WithContext(ctx).Create(log).Error
}
func (d *NewModuleAuditLogDao) BatchCreate(ctx context.Context, logs []*entity.NewModuleAuditLog) error {
if len(logs) == 0 {
return nil
}
for i := range logs {
logs[i].Module = "new_module"
}
return d.db.WithContext(ctx).CreateInBatches(logs, len(logs)).Error
}
```
#### 步骤3: 更新DAOManager
位置: `rmdc-audit-log/internal/dao/audit_log_dao_manager.go`
```go
type AuditLogDAOManager struct {
Core *AuditLogDao
Jenkins *JenkinsAuditLogDao
NewModule *NewModuleAuditLogDao // 新增
}
func InitAuditLogDAOManager(db *gorm.DB) (*AuditLogDAOManager, error) {
// ...
daoManagerInstance = &AuditLogDAOManager{
Core: NewAuditLogDao(db),
Jenkins: NewJenkinsAuditLogDao(db),
NewModule: NewNewModuleAuditLogDao(db), // 新增
}
// ...
}
```
#### 步骤4: 扩展Service
位置: `rmdc-audit-log/internal/service/audit_service.go`
1. 添加新模块的日志缓冲区
2. 添加新模块的批量写入协程
3.`WriteLog` 中添加新模块的路由逻辑
#### 步骤5: 更新模块判断逻辑
```go
func (s *AuditService) determineModule(path string) string {
switch {
// ... 现有逻辑 ...
case strings.Contains(path, "/new-module/"):
return "new_module"
default:
return "core"
}
}
```
#### 步骤6: 数据库迁移
位置: `rmdc-core/scripts/init_postgresql.sql`
```sql
-- 新模块审计日志表
CREATE TABLE IF NOT EXISTS new_module_audit_logs (
id BIGSERIAL PRIMARY KEY,
module VARCHAR(50) DEFAULT 'new_module',
user_id INTEGER,
username VARCHAR(64),
action VARCHAR(64) NOT NULL,
resource_type VARCHAR(50),
resource_id VARCHAR(255),
details JSONB,
ip_address INET,
status VARCHAR(20),
error_message TEXT,
created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
-- 模块专属字段
custom_field_1 VARCHAR(255),
custom_field_2 BIGINT
);
CREATE INDEX idx_new_module_audit_created ON new_module_audit_logs (created_at DESC);
```
---
## 6. Jenkins 交付物构建审计日志使用示例
### 6.1 触发构建时记录审计日志
位置: `rmdc-jenkins-branch-dac/internal/service/build_service.go`
```go
func (s *BuildService) TriggerBuild(ctx context.Context, req *dto.TriggerBuildRequest) (*dto.TriggerBuildResponse, error) {
// ... 构建触发逻辑 ...
// 记录Jenkins审计日志
if s.auditWriter != nil {
s.auditWriter.WriteJenkinsLog(&audit.JenkinsAuditLogInput{
UserID: getUserIDFromContext(ctx),
Username: getUsernameFromContext(ctx),
Action: "TRIGGER_BUILD",
ResourceType: "jenkins_build",
ResourceID: fmt.Sprintf("%s/%s/%s", req.OrganizationFolder, req.RepositoryName, req.BranchName),
Organization: req.OrganizationFolder,
Repository: req.RepositoryName,
Branch: req.BranchName,
BuildNumber: latestBuild.Number,
})
}
return response, nil
}
```
### 6.2 DCU任务完成时记录交付物审计日志
```go
func (s *DCUService) OnDCUTaskComplete(ctx context.Context, task *DCUTask) {
// 记录交付物构建完成审计日志
if s.auditWriter != nil {
s.auditWriter.WriteJenkinsLog(&audit.JenkinsAuditLogInput{
UserID: task.UserID,
Username: task.Username,
Action: "DCU_COMPLETE",
ResourceType: "dcu_artifact",
ResourceID: task.TaskID,
Organization: task.Organization,
Repository: task.Repository,
Branch: task.Branch,
BuildNumber: task.BuildNumber,
// 交付物信息
ArtifactName: task.ArtifactGzipName,
ArtifactSize: task.ArtifactSize,
ArtifactType: "gzip",
})
}
}
```
### 6.3 获取AuditWriter实例
在模块初始化时获取 AuditWriter
```go
import (
auditHandler "wdd.io/RMDC/rmdc-audit-log/pkg/handler"
"wdd.io/RMDC/rmdc-audit-log/pkg/audit"
)
// 初始化时获取AuditWriter
func InitBuildService(auditDB *gorm.DB, ...) *BuildService {
auditWriter, err := auditHandler.InitAuditWriter(auditDB)
if err != nil {
wdd_log.Debug("[WARN] Failed to init audit writer: %v", err)
}
return &BuildService{
auditWriter: auditWriter,
// ...
}
}
```
---
## 7. 设计决策与优化
### 7.1 异步批量写入
审计日志采用**缓冲区 + 批量写入**策略,不阻塞业务请求:
```
请求处理时间 = 业务逻辑时间
审计日志写入 = 后台协程异步批量处理
```
- `logBuffer`: 核心模块日志缓冲区 (容量: 100)
- `jenkinsLogBuffer`: Jenkins模块日志缓冲区 (容量: 50)
- `userAuthLogBuffer`: 用户认证模块日志缓冲区 (容量: 50)
- 批量写入阈值: 10条
- 定时刷新间隔: 2秒
### 7.2 敏感数据脱敏
`sanitizeSensitiveData()` 函数自动脱敏以下字段:
- `password`
- `token`
- `secret`
- `api_key`
### 7.3 日志清理策略
通过 `/api/audit/cleanup` 接口支持按保留天数清理旧日志,防止磁盘空间占用过大。
### 7.4 回退机制
如果 DAOManager 初始化失败,系统会自动回退到单一 DAO 模式,所有日志写入 `core_audit_logs` 表,保证审计功能可用性。
---
## 8. 前端审计日志查询界面
### 8.1 模块Tab切换
前端页面通过模块 Tab 切换查询不同表的审计日志:
```mermaid
flowchart LR
A[All Modules] -->|GET /api/audit/logs| B[(core_audit_logs)]
C[Core] -->|GET /api/audit/logs?module=core| B
D[Jenkins] -->|GET /api/audit/logs/jenkins| E[(jenkins_audit_logs)]
F[User Auth] -->|GET /api/audit/logs/user-auth| G[(user_auth_audit_logs)]
```
### 8.2 API 端点列表
| 端点 | 方法 | 描述 | 查询表 |
|------|------|------|--------|
| `/api/audit/logs` | GET | 通用审计日志查询 | core_audit_logs |
| `/api/audit/logs/jenkins` | GET | Jenkins专属日志含专属字段 | jenkins_audit_logs |
| `/api/audit/logs/user-auth` | GET | 用户认证专属日志(含专属字段) | user_auth_audit_logs |
| `/api/audit/modules/stats` | GET | 各模块日志数量统计 | 所有表 |
| `/api/audit/logs/stats` | GET | 审计日志统计(大小、最旧记录) | core_audit_logs |
| `/api/audit/cleanup` | DELETE | 清理旧日志 | 所有表 |
### 8.3 模块专属响应字段
#### Jenkins 模块
```json
{
"id": 1,
"module": "jenkins",
"username": "admin",
"action": "TRIGGER_BUILD",
"organization": "Backend",
"repository": "cmii-fly-center",
"branch": "master",
"build_number": 123,
"artifact_name": "cmii-fly-center-1.0.0.tar.gz",
"artifact_size": 52428800,
"artifact_type": "gzip"
}
```
#### UserAuth 模块
```json
{
"id": 1,
"module": "user_auth",
"username": "admin",
"action": "LOGIN",
"login_type": "password",
"device_info": "Chrome/Windows"
}
```
### 8.4 前端页面功能
1. **模块Tab切换** - 点击 Tab 动态切换查询不同模块的日志
2. **动态表头** - 根据选中模块显示不同列Jenkins: Organization/Repository/Branch; UserAuth: LoginType
3. **模块筛选** - 当选择特定模块时,显示该模块专属的筛选条件
4. **详情弹窗** - 点击日志条目显示完整详情,包含模块专属字段
---
**文档版本**: v2.1
**编制日期**: 2025-12-12
**编制人**: System Architect
**更新内容**:
- 新增 UserAuth 模块审计日志支持
- 新增模块专属审计日志表分表写入架构
- 新增 AuditLogDAOManager DAO管理器
- 新增 WriteJenkinsLog/WriteUserAuthLog 接口
- 新增模块审计日志表添加指南
- 新增 Jenkins 交付物构建审计日志使用示例
- 新增前端审计日志查询界面设计

View File

@@ -0,0 +1,292 @@
# 登录接口统一定义文档
## 版本信息
- **版本**: v1.0
- **创建日期**: 2026-01-15
- **最后更新**: 2026-01-15
## 概述
本文档定义了 RMDC 系统登录接口的统一结构体规范,确保前端和后端之间的数据交互一致性。
## 后端定义 (Go)
### 文件位置
`rmdc-user-auth/internal/model/dto/auth_dto.go`
### 结构体定义
#### LoginRequest - 登录请求
```go
type LoginRequest struct {
Username string `json:"username" binding:"required"` // 用户名(中文真实姓名)
Password string `json:"password"` // 明文密码(已废弃,保持兼容)
EncryptedPassword string `json:"encrypted_password" binding:"required"` // RSA加密后的密码
}
```
#### LoginResponse - 登录响应
```go
type LoginResponse struct {
Token string `json:"token"` // JWT令牌
User *UserDTO `json:"user"` // 用户信息
MustChangePassword bool `json:"must_change_password"` // 是否必须修改密码
PasswordExpireDays int `json:"password_expire_days"` // 密码剩余天数7天内提醒
}
```
#### UserDTO - 用户信息传输对象
```go
type UserDTO struct {
ID int64 `json:"id"` // 用户ID
Username string `json:"username"` // 中文真实姓名
EnglishUsername string `json:"english_username"` // 英文用户名
AvatarID string `json:"avatar_id"` // 头像ID
AvatarFrameID string `json:"avatar_frame_id"` // 头像框ID
Gender string `json:"gender"` // 性别: male/female
Email string `json:"email"` // 邮箱
Phone string `json:"phone"` // 手机号
ShortNumber string `json:"short_number,omitempty"` // 短号
WorkID string `json:"work_id,omitempty"` // 工号
GroupName string `json:"group_name,omitempty"` // 所属小组
Company string `json:"company"` // 公司名称
DevRole string `json:"dev_role"` // 开发角色: backend/frontend/testing/devops
Role string `json:"role"` // RMDC系统角色: superadmin/admin/normal/third
Status string `json:"status"` // 状态: active/locked/disabled
RegisteredByID int64 `json:"registered_by_id"` // 注册人ID
CreatedAt time.Time `json:"created_at"` // 注册时间
UpdatedAt time.Time `json:"updated_at"` // 更新时间
DeletedAt *time.Time `json:"deleted_at,omitempty"` // 删除时间
LastLoginAt *time.Time `json:"last_login_at,omitempty"` // 最后登录时间
PasswordExpires *time.Time `json:"password_expires,omitempty"` // 密码过期时间
}
```
## 前端定义 (TypeScript)
### 文件位置
`frontend/src/types/api.ts`
### 接口定义
#### LoginResponse - 登录响应
```typescript
export interface LoginResponse {
token: string // JWT令牌
user: User // 用户信息
must_change_password: boolean // 是否必须修改密码
password_expire_days: number // 密码剩余天数7天内提醒
}
```
#### User - 用户信息
```typescript
export interface User {
id: number
username: string // 中文真实姓名
english_username: string // 英文用户名
avatar_id: string // 头像ID
avatar_frame_id: string // 头像框ID
gender: string // 性别: male/female
email: string // 邮箱
phone: string // 手机号
short_number?: string // 短号
work_id?: string // 工号
group_name?: string // 所属小组
company: string // 公司名称
dev_role: string // 开发角色: backend/frontend/testing/devops
role: string // 用户角色: superadmin/admin/normal/third
status: string // 用户状态: active/locked/disabled
registered_by_id: number // 注册人ID
created_at: string // 注册时间
updated_at: string // 更新时间
deleted_at?: string // 删除时间
last_login_at?: string // 最后登录时间
password_expires?: string // 密码过期时间
}
```
## API 接口规范
### 请求端点
```
POST /api/auth/login
```
### 请求体示例
```json
{
"username": "张三",
"encrypted_password": "RSA加密后的密码字符串"
}
```
### 响应示例
#### 成功响应 (HTTP 200)
```json
{
"code": 0,
"status": 200,
"timestamp": "2026-01-15T17:40:00Z",
"message": "success",
"data": {
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"user": {
"id": 1,
"username": "张三",
"english_username": "zhangsan",
"avatar_id": "default_1",
"avatar_frame_id": "default",
"gender": "male",
"email": "zhangsan@example.com",
"phone": "13800138000",
"company": "示例公司",
"dev_role": "backend",
"role": "admin",
"status": "active",
"registered_by_id": 1,
"created_at": "2026-01-01T00:00:00Z",
"updated_at": "2026-01-15T17:40:00Z"
},
"must_change_password": false,
"password_expire_days": 30
}
}
```
#### 失败响应 (HTTP 401)
```json
{
"code": 10003,
"status": 401,
"timestamp": "2026-01-15T17:40:00Z",
"message": "用户名或密码错误",
"data": null,
"error": "invalid credentials"
}
```
## 字段映射对照表
| 后端字段 (Go) | 前端字段 (TypeScript) | 字段说明 | 必填 |
|--------------|---------------------|----------|------|
| ID | id | 用户ID | ✓ |
| Username | username | 中文真实姓名 | ✓ |
| EnglishUsername | english_username | 英文用户名 | ✓ |
| AvatarID | avatar_id | 头像ID | ✓ |
| AvatarFrameID | avatar_frame_id | 头像框ID | ✓ |
| Gender | gender | 性别 | ✓ |
| Email | email | 邮箱 | ✓ |
| Phone | phone | 手机号 | ✓ |
| ShortNumber | short_number | 短号 | × |
| WorkID | work_id | 工号 | × |
| GroupName | group_name | 所属小组 | × |
| Company | company | 公司名称 | ✓ |
| DevRole | dev_role | 开发角色 | ✓ |
| Role | role | 用户角色 | ✓ |
| Status | status | 用户状态 | ✓ |
| RegisteredByID | registered_by_id | 注册人ID | ✓ |
| CreatedAt | created_at | 注册时间 | ✓ |
| UpdatedAt | updated_at | 更新时间 | ✓ |
| DeletedAt | deleted_at | 删除时间 | × |
| LastLoginAt | last_login_at | 最后登录时间 | × |
| PasswordExpires | password_expires | 密码过期时间 | × |
## 关键改进点
### 1. 统一命名规范
- **前后端一致性**: 所有字段名统一使用 snake_case (下划线命名)
- **修正**: `avatar_frame``avatar_frame_id`(与后端保持一致)
### 2. 新增字段
- `short_number`: 短号(可选)
- `work_id`: 工号(可选)
- `password_expires`: 密码过期时间(可选)
### 3. 标准化响应结构
- **后端**: 使用 `dto.LoginResponse` 替代 `gin.H` 直接返回
- **前端**: 从 `ApiResponse<LoginResponse>` 中提取 `data` 字段
### 4. 类型安全
- 后端使用强类型 DTO 结构体
- 前端使用 TypeScript 接口定义
- 消除了隐式类型转换的风险
### 5. 密码安全
- 统一使用 RSA 加密传输密码
- 移除明文密码支持(保持向后兼容)
## 使用示例
### 后端 Handler 实现
```go
func (h *AuthHandler) Login(c *gin.Context) {
var req dto.LoginRequest
if err := c.ShouldBindJSON(&req); err != nil {
wdd_res.ResponseErrorWithDetail(c, wdd_res.CodeValidationFail, "请求参数错误", err)
return
}
// ... 业务逻辑 ...
resp := dto.LoginResponse{
Token: token,
User: userDTO,
MustChangePassword: mustChangePassword,
PasswordExpireDays: passwordExpireDays,
}
wdd_res.ResponseSuccess(c, resp)
}
```
### 前端 Store 实现
```typescript
async login(username: string, password: string): Promise<boolean> {
const requestBody = {
username,
encrypted_password: await encryptPasswordWithPublicKey(password)
}
const apiResponse = await api.post<LoginResponse>('/auth/login', requestBody)
if (apiResponse.code !== 0) {
console.error('Login failed:', apiResponse.message)
return false
}
const response = apiResponse.data
this.token = response.token
this.user = response.user
this.mustChangePassword = response.must_change_password
this.passwordExpireDays = response.password_expire_days
localStorage.setItem('token', this.token)
localStorage.setItem('user', JSON.stringify(this.user))
return true
}
```
## 相关文件清单
### 后端文件
- `rmdc-user-auth/internal/model/dto/auth_dto.go` - 登录相关 DTO 定义
- `rmdc-user-auth/internal/handler/auth_handler.go` - 登录处理器
- `rmdc-user-auth/internal/model/entity/user.go` - 用户实体
### 前端文件
- `frontend/src/types/api.ts` - API 类型定义
- `frontend/src/store/auth.ts` - 认证状态管理
- `frontend/src/api/index.ts` - API 请求封装
## 遵循的规范文档
- `3-api-development-prompt.md` - API 开发规范
- `go-gin-gorm-style.md` - Go/Gin/GORM 编码规范
- `vue3-typescript-stye.md` - Vue3/TypeScript 编码规范
## 版本历史
| 版本 | 日期 | 变更说明 |
|------|------|----------|
| v1.0 | 2026-01-15 | 初始版本,统一前后端登录接口定义 |

View File

@@ -0,0 +1,114 @@
## RMDC-K8S 部署方案
### 构建
1. 前提条件
1. 已经存在k8s集群
2. 已经存在harbor仓库 harbor.wdd.io:8033
3. 构建主机 192.168.35.80 已经存在go环境 node环境 docker环境
2. 需要实现的内容,在windwos实现powershell脚本,实现如下的功能
1. 将本地的代码通过rsync推送至192.168.35.80的工作目录
2. 在192.168.35.80实现代码的编译工作
1. 前端使用node构建
2. 后端使用go构建
3. 构建产物放置于项目目录 rmdc-k8s-deploy/build目录下
3. 在192.168.35.80实现dockerfile构建以下为不同的模块
1. 构建的dockerfile放置于项目目录 rmdc-k8s-deploy/dockerfile目录下
2. 构建RMDC-Frontend前端代码
1. 基础镜像为 harbor.wdd.io:8033/rmdc/nginx:1.27.0
2. 镜像命名为 harbor.wdd.io:8033/rmdc/rmdc-frontend:${日期}
3. 前端代码构建需要有生产环境构建的配置
4. 前端代码的API调用的HOST 需要根据实际访问的域名进行配置
3. 基础后端镜像构建
1. 基础镜像为 harbor.wdd.io:8033/rmdc/alpine:3.23.0
2. 指定docker的环境变量,时区等信息
3. 安装常用的基础工具 ping curl telnet netcat nmap mtr traceroute
4. 镜像命名为 harbor.wdd.io:8033/rmdc/rmdc-backend-base:1.0
4. 构建RMDC-Backend后端代码
1. 基础镜像为 harbor.wdd.io:8033/rmdc/rmdc-backend-base:1.0
2. 镜像命名为 harbor.wdd.io:8033/rmdc/rmdc-backend:${日期}
5. 构建RMDC-watchdog镜像
1. 基础镜像使用 harbor.wdd.io:8033/rmdc/rmdc-watchdog-base:1.0
1. 参考[Dockerfile.backend-base](rmdc-k8s-deploy/dockerfile/Dockerfile.backend-base), 安装必要的工具
2. 镜像命名为 harbor.wdd.io:8033/rmdc/rmdc-watchdog:${日期}
6. 构建RMDC-watchdog-node镜像
1. 基础镜像使用 harbor.wdd.io:8033/rmdc/rmdc-watchdog-base:1.0
2. 镜像命名为 harbor.wdd.io:8033/rmdc/rmdc-watchdog-node:${日期}
4. 在192.168.35.80实现harbor推送,将构建好的镜像推送至harbor仓库
5. 此脚本能够通过参数,指定需要构建的模块
1. 前端
2. 后端
3. RMDC-watchdog
4. RMDC-watchdog-node
5. RMDC-watchdog-agent
### K8S-YAML文件
1. RMDC组件需要实现的内容
1. 部署文件需要放置于项目目录 rmdc-k8s-deploy/rmdc-app目录下
2. 命名空间为 cmii-rmdc
3. 为RMDC-frontend实现Deployment和Service如果此模块构建,则需要更新该yaml中的Tag如果此模块构建,则需要更新该yaml
2. 镜像为 harbor.wdd.io:8033/rmdc/rmdc-frontend:${日期}
3. 副本数量为1
4. 端口暴露及Service端口
3. 为RMDC-backend实现Deployment和Service
1. 如果此模块构建,则需要更新该yaml中的Tag
2. 镜像为 harbor.wdd.io:8033/rmdc/rmdc-backend:${日期}
3. 副本数量为1
4. 端口暴露及Service端口
5. 如果此模块构建,则需要更新该yaml
4. 实现Ingress部分
1. Ingress的域名均采用 rmdc.titanium-bullhorses.io
2. 最好在一个Ingress文件中实现
3. 前端Ingress
4. API接口的Ingress
2. RMDC-watchdog组件需要实现的内容
1. 部署文件需要放置于项目目录 rmdc-k8s-deploy/rmdc-watchdog目录下
2. 命名空间为 cmii-rmdc
3. 为RMDC-watchdog实现Deployment和Service
1. 如果此模块构建,则需要更新该yaml中的Tag
2. 镜像为 harbor.wdd.io:8033/rmdc/rmdc-watchdog:${日期}
3. 副本数量为1
4. 端口暴露及Service端口
4. RMDC-watchdog-node组件需要实现的内容
1. 如果此模块构建,则需要更新该yaml中的Tag
2. 镜像为 harbor.wdd.io:8033/rmdc/rmdc-watchdog-node:${日期}
3. 副本数量为1
4. 端口暴露及Service端口
## RMDC-watchdog-agent部分
部署文件需要放置于项目目录 rmdc-k8s-deploy/rmdc-uav目录下
### uav后端JAVA的基础镜像
1. 提供基于openjdk11 17 21的版本
2. 需要能够正确的显示中文日志及字符
3. 安装尽可能丰富的基础工具类
4. 需要指定JVM的时区为Asia/Shanghai
5. 需要设置java的PATH环境变量
6. 需要设置JAVA_HOME环境变量
7. 端口暴露为 EXPOSE 8080
8. 参考为 [Dockerfile-base-java17](rmdc-k8s-deploy/rmdc-uav/base-image/Dockerfile-base-java17)
9. 基础镜像需要尽可能的小
10. 需要修改使用国内的镜像源
11. 最好基于 harbor.wdd.io:8033/rmdc/alpine:3.23.0
#### 不嵌入RMDC-watchdog-agent的时候,
1. 使用传统的start_up.sh 即为ENTRYPOINT ["./start_up.sh"]
2. 需要构建 镜像名为 harbor.wdd.io:8033/rmdc/openjdk17-base-tools:1.0
3. 需要同时 进行Tag为harbor.cdcyy.com.cn/cmii/openjdk17-base-tools:3.0 并且推送该镜像
#### 当嵌入RMDC-watchdog-agent时候
1. 需要go进行build 得到RMDC-watchdog-agent的压缩包
1. 需要记录构建出来二级制文件,命名规则为 rmdc-watchdog-agent-${日期}
2. 构建RMDC-watchdog-agent镜像
1. 需要内嵌rmdc-watchdog-agent版本信息的环境变量 RMDC_WATCHDOG_AGENT_VERSION=${日期}
2. OpenJDK-17版本
1. 基础镜像使用 harbor.wdd.io:8033/rmdc/openjdk17-base-tools:1.0
2. 镜像命名为 harbor.wdd.io:8033/rmdc/rmdc-watchdog-agent-jdk17:1.0
3. OpenJDK-11版本
1. 基础镜像使用 harbor.wdd.io:8033/rmdc/openjdk11-base-tools:1.0
2. 镜像命名为 harbor.wdd.io:8033/rmdc/rmdc-watchdog-agent-jdk11:1.0
3. 内嵌RMDC-watchdog-agent的时候, uav后端程序需要使用ENTRYPOINT ["/cmii/cmii-watchdog-agent", "-business-program-type", "java", "-business-program-path", "/cmii/jarfile.jar"]进行启动

View File

@@ -0,0 +1,479 @@
{
"info": {
"_postman_id": "rmdc-api-collection-2026",
"name": "RMDC API Collection",
"description": "RMDC系统API测试集合\n\n## 使用说明\n\n1. 导入此Collection后首先运行 `Auth > 1. 获取RSA公钥` 请求\n2. 然后运行 `Auth > 2. RSA加密登录` 请求\n3. 登录成功后Token会自动保存其他请求无需手动配置认证\n\n## 环境变量\n- `baseUrl`: API基础地址默认 http://localhost:8080\n- `username`: 登录用户名\n- `password`: 登录密码",
"schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json"
},
"auth": {
"type": "bearer",
"bearer": [
{
"key": "token",
"value": "{{token}}",
"type": "string"
}
]
},
"event": [
{
"listen": "prerequest",
"script": {
"type": "text/javascript",
"exec": [
"// Collection级别的预处理脚本",
"// 自动检查token是否存在"
]
}
},
{
"listen": "test",
"script": {
"type": "text/javascript",
"exec": [
"// Collection级别的测试脚本"
]
}
}
],
"variable": [
{
"key": "baseUrl",
"value": "http://localhost:8080",
"type": "string"
},
{
"key": "username",
"value": "admin",
"type": "string"
},
{
"key": "password",
"value": "supercyy.1",
"type": "string"
},
{
"key": "token",
"value": "",
"type": "string"
},
{
"key": "rsaPublicKey",
"value": "",
"type": "string"
}
],
"item": [
{
"name": "Auth",
"description": "认证相关接口",
"item": [
{
"name": "1. 获取RSA公钥",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('获取公钥成功', function () {",
" pm.response.to.have.status(200);",
"});",
"",
"var jsonData = pm.response.json();",
"if (jsonData.public_key) {",
" pm.collectionVariables.set('rsaPublicKey', jsonData.public_key);",
" console.log('RSA公钥已保存');",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/auth/rsa/public-key",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"auth",
"rsa",
"public-key"
]
}
}
},
{
"name": "2. RSA加密登录",
"event": [
{
"listen": "prerequest",
"script": {
"exec": [
"// RSA加密函数 (使用PKCS1v15填充)",
"const forge = require('node-forge');",
"",
"const publicKeyPem = pm.collectionVariables.get('rsaPublicKey');",
"const password = pm.collectionVariables.get('password');",
"",
"if (!publicKeyPem) {",
" console.error('请先运行\"获取RSA公钥\"请求');",
" throw new Error('RSA公钥未获取');",
"}",
"",
"try {",
" // 解析PEM格式的公钥",
" const publicKey = forge.pki.publicKeyFromPem(publicKeyPem);",
" ",
" // 使用RSA-OAEP加密 (SHA-256)",
" const encrypted = publicKey.encrypt(password, 'RSA-OAEP', {",
" md: forge.md.sha256.create()",
" });",
" ",
" // 转换为Base64",
" const encryptedBase64 = forge.util.encode64(encrypted);",
" ",
" pm.collectionVariables.set('encryptedPassword', encryptedBase64);",
" console.log('密码加密成功');",
"} catch (e) {",
" console.error('RSA加密失败:', e);",
" throw e;",
"}"
],
"type": "text/javascript"
}
},
{
"listen": "test",
"script": {
"exec": [
"pm.test('登录成功', function () {",
" pm.response.to.have.status(200);",
"});",
"",
"var jsonData = pm.response.json();",
"",
"if (jsonData.token) {",
" pm.collectionVariables.set('token', jsonData.token);",
" console.log('Token已保存到Collection变量');",
" console.log('用户:', jsonData.user?.username);",
"}",
"",
"if (jsonData.must_change_password) {",
" console.warn('警告: 密码已过期,需要修改');",
"}",
"",
"if (jsonData.password_expire_days > 0) {",
" console.warn('提示: 密码将在 ' + jsonData.password_expire_days + ' 天后过期');",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"auth": {
"type": "noauth"
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"{{username}}\",\n \"encrypted_password\": \"{{encryptedPassword}}\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/auth/login",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"auth",
"login"
]
}
}
},
{
"name": "3. 明文密码登录(备用)",
"event": [
{
"listen": "test",
"script": {
"exec": [
"pm.test('登录成功', function () {",
" pm.response.to.have.status(200);",
"});",
"",
"var jsonData = pm.response.json();",
"",
"if (jsonData.token) {",
" pm.collectionVariables.set('token', jsonData.token);",
" console.log('Token已保存');",
"}"
],
"type": "text/javascript"
}
}
],
"request": {
"auth": {
"type": "noauth"
},
"method": "POST",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"username\": \"{{username}}\",\n \"password\": \"{{password}}\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/auth/login",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"auth",
"login"
]
}
}
}
]
},
{
"name": "Contacts",
"description": "通信录接口",
"item": [
{
"name": "获取通信录列表",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/contacts?page=1&size=20",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"contacts"
],
"query": [
{
"key": "page",
"value": "1"
},
{
"key": "size",
"value": "20"
},
{
"key": "search",
"value": "",
"disabled": true
}
]
}
}
},
{
"name": "获取联系人详情",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/contacts/1",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"contacts",
"1"
]
}
}
}
]
},
{
"name": "Users",
"description": "用户管理接口 (需要Admin权限)",
"item": [
{
"name": "获取用户列表",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/users?page=1&size=20",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"users"
],
"query": [
{
"key": "page",
"value": "1"
},
{
"key": "size",
"value": "20"
},
{
"key": "status",
"value": "active",
"disabled": true
},
{
"key": "search",
"value": "",
"disabled": true
}
]
}
}
},
{
"name": "获取用户详情",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/users/1",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"users",
"1"
]
}
}
}
]
},
{
"name": "User Profile",
"description": "用户个人接口",
"item": [
{
"name": "修改密码",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"current_password\": \"{{password}}\",\n \"new_password\": \"NewPassword123\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/user/password",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"user",
"password"
]
}
}
},
{
"name": "更新个人资料",
"request": {
"method": "PUT",
"header": [
{
"key": "Content-Type",
"value": "application/json"
}
],
"body": {
"mode": "raw",
"raw": "{\n \"avatar_id\": \"default_1\",\n \"avatar_frame_id\": \"default\"\n}"
},
"url": {
"raw": "{{baseUrl}}/api/user/profile",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"user",
"profile"
]
}
}
}
]
},
{
"name": "Permissions",
"description": "权限管理接口",
"item": [
{
"name": "获取我的权限树",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/permissions/my-tree/full",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"permissions",
"my-tree",
"full"
]
}
}
},
{
"name": "获取我的组织列表",
"request": {
"method": "GET",
"header": [],
"url": {
"raw": "{{baseUrl}}/api/permissions/my-tree/organizations",
"host": [
"{{baseUrl}}"
],
"path": [
"api",
"permissions",
"my-tree",
"organizations"
]
}
}
}
]
}
]
}

View File

@@ -0,0 +1,308 @@
# rmdc-jenkins-branch-dac 详细设计说明书DDS
**模块名称**: rmdc-jenkins-branch-dac
**版本**: v1.0
**编制日期**: 2026-01-06
---
## 1. 模块概述
### 1.1 模块定位
rmdc-jenkins-branch-dac 是 RMDC 平台的**Jenkins分支级权限控制与构建管理模块**,负责:
1. **分支级权限控制(DAC)**基于自主访问控制模型实现Organization→Repository→Branch三级资源权限管理
2. **Jenkins集成**封装Jenkins REST API提供统一的构建触发、状态查询、日志获取等能力
3. **构建产物管理**管理Docker镜像的下载、压缩、上传(DCU)流程集成MinIO对象存储
4. **构建状态追踪**:实时追踪构建进度,提供状态同步和超时检测机制
### 1.2 核心用户角色
| 角色 | 权限说明 |
|------|----------|
| **SuperAdmin** | 全量访问可管理所有Organization/Repository/Branch |
| **Admin** | 拥有分配的权限可将自有权限分配给Normal/Third用户 |
| **Normal** | 拥有分配的权限,只能查看和触发被授权的分支构建 |
| **Third** | 第三方人员,权限最受限,仅能查看被授权内容 |
### 1.3 技术栈
- **后端**: Go + Gin + GORM
- **数据库**: PostgreSQL (主库) + SQLite (DCU模块独立库)
- **外部服务**: Jenkins REST API, MinIO对象存储
---
## 2. 系统架构
### 2.1 模块架构图
```mermaid
graph TB
subgraph "rmdc-core 网关层"
Router[Gin Router]
AuthMW[AuthMiddleware]
PermMW[PermissionMiddleware]
end
subgraph "rmdc-jenkins-branch-dac 模块"
subgraph "Handler层"
OrgH[OrgHandler]
RepoH[RepoHandler]
BranchH[BranchHandler]
BuildH[BuildHandler]
DCUH[DCUHandler]
end
subgraph "Service层"
JenkinsS[JenkinsService]
BuildS[BuildService]
SyncS[SyncService]
DCUS[DCUService]
TrackerS[BuildTracker]
end
subgraph "DAO层"
OrgDAO[OrganizationDAO]
RepoDAO[RepositoryDAO]
BranchDAO[BranchDAO]
BuildDAO[BuildDAO]
end
JenkinsC[JenkinsClient]
MinioC[MinioClient]
end
subgraph "外部服务"
Jenkins[(Jenkins Server)]
MinIO[(MinIO Storage)]
end
Router --> AuthMW --> PermMW
PermMW --> OrgH & RepoH & BranchH & BuildH & DCUH
BuildH --> BuildS --> JenkinsS --> JenkinsC --> Jenkins
DCUH --> DCUS --> MinioC --> MinIO
JenkinsS --> OrgDAO & RepoDAO & BranchDAO & BuildDAO
```
### 2.2 Jenkins层级结构
```
Organization Folder组织
└── Repository/Project仓库
└── Branch分支
└── Build构建
```
**URL路径模式**
```
/job/{ORG} # 组织
/job/{ORG}/job/{REPO} # 仓库
/job/{ORG}/job/{REPO}/job/{BRANCH} # 分支
/job/{ORG}/job/{REPO}/job/{BRANCH}/{NUM} # 构建
```
---
## 3. 数据模型设计
### 3.1 核心实体
```mermaid
erDiagram
jenkins_organizations ||--o{ jenkins_repositories : contains
jenkins_repositories ||--o{ jenkins_branches : contains
jenkins_branches ||--o{ jenkins_builds : contains
jenkins_organizations {
int64 id PK
string name UK
string display_name
string url
datetime last_sync_at
}
jenkins_repositories {
int64 id PK
int64 organization_id FK
string name
string url
}
jenkins_branches {
int64 id PK
int64 repository_id FK
string name
int last_build_number
string last_build_result
}
jenkins_builds {
int64 id PK
int64 branch_id FK
int build_number
string result
int64 timestamp
int64 duration
int64 estimated_duration
bool is_building
string artifact_docker_image
}
```
---
## 4. API接口规范
> **设计原则**: 使用RESTful风格优先使用POST + RequestBody避免PathVariables和RequestParams
### 4.1 组织管理接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/jenkins/organizations/list` | POST | 获取组织列表 |
| `/api/jenkins/organizations/detail` | POST | 获取组织详情 |
| `/api/jenkins/organizations/sync` | POST | 同步Jenkins组织数据 |
### 4.2 仓库管理接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/jenkins/repositories/list` | POST | 获取仓库列表 |
| `/api/jenkins/repositories/detail` | POST | 获取仓库详情 |
| `/api/jenkins/repositories/sync` | POST | 同步仓库数据 |
| `/api/jenkins/repositories/scan` | POST | 触发仓库扫描 |
### 4.3 分支管理接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/jenkins/branches/list` | POST | 获取分支列表 |
| `/api/jenkins/branches/detail` | POST | 获取分支详情 |
| `/api/jenkins/branches/sync` | POST | 同步分支数据 |
### 4.4 构建管理接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/jenkins/builds/list` | POST | 获取构建列表 |
| `/api/jenkins/builds/detail` | POST | 获取构建详情 |
| `/api/jenkins/builds/trigger` | POST | 触发构建 |
| `/api/jenkins/builds/console` | POST | 获取构建日志 |
| `/api/jenkins/builds/sync` | POST | 同步构建数据 |
### 4.5 DCU接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/dcu/start` | POST | 启动DCU任务 |
| `/api/dcu/status` | POST | 查询任务状态 |
| `/api/dcu/list` | POST | 查询任务列表 |
---
## 5. 分支权限(DAC)设计
### 5.1 权限模型
DAC采用**资源-用户-权限**三元组模型,支持三级权限继承:
| 授权层级 | 继承规则 |
|----------|----------|
| Organization级 | 自动继承到该组织下所有Repository和Branch |
| Repository级 | 自动继承到该仓库下所有Branch |
| Branch级 | 最细粒度,不继承 |
### 5.2 权限类型
| 权限 | 说明 |
|------|------|
| `can_view` | 查看权限 |
| `can_build` | 构建权限 |
---
## 6. 构建状态追踪
### 6.1 BuildTracker设计
BuildTracker负责追踪正在进行中的构建提供超时检测和状态同步
```mermaid
sequenceDiagram
participant User as 用户
participant Handler as BuildHandler
participant Service as BuildService
participant Tracker as BuildTracker
participant Jenkins as Jenkins API
User->>Handler: POST /builds/trigger
Handler->>Service: TriggerBuild()
Service->>Jenkins: 触发构建
Service->>Tracker: TrackBuild(buildId, timeout)
Service-->>User: 返回构建号
loop 后台超时检测(每10秒)
Tracker->>Tracker: checkTimeouts()
alt 超时
Tracker->>Jenkins: 查询最新状态
Tracker->>Tracker: 更新数据库
end
end
```
---
## 7. DCU(Download-Compress-Upload)流程
### 7.1 状态机
```mermaid
stateDiagram-v2
[*] --> idle: 创建任务
idle --> downloading: StartTask()
downloading --> compressing: Pull成功
compressing --> uploading: 压缩成功
uploading --> completed: 上传成功
downloading --> failed: Pull失败
compressing --> failed: 压缩失败
uploading --> failed: 上传失败
```
### 7.2 流程说明
1. **Download**: 从Docker Registry拉取镜像
2. **Compress**: 使用gzip压缩镜像tar包
3. **Upload**: 上传到MinIO对象存储
---
## 8. 错误码定义
| 错误码 | 说明 |
|--------|------|
| `JENKINS-001` | Jenkins服务不可用 |
| `JENKINS-002` | Jenkins认证失败 |
| `JENKINS-003` | Jenkins资源不存在 |
| `JENKINS-004` | 构建触发失败 |
| `JENKINS-005` | 构建超时 |
| `DCU-001` | Docker Pull失败 |
| `DCU-002` | 压缩失败 |
| `DCU-003` | MinIO上传失败 |
| `PERM-001` | 无权限访问该资源 |
| `PERM-002` | 无权限执行该操作 |
---
## 9. 相关文档
| 文档 | 内容 |
|------|------|
| [5-RMDC项目权限设计方案.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/5-RMDC项目权限设计方案.md) | 权限设计 |
| [8-jenkins项目层级.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/8-jenkins项目层级.md) | Jenkins层级结构 |
| [9-JenkinsBuild-流程图.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/9-JenkinsBuild-流程图.md) | 构建流程图 |
| [9-rmdc-dcu模块设计方案.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/9-rmdc-dcu模块设计方案.md) | DCU模块设计 |

View File

@@ -0,0 +1,336 @@
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)
请严格遵循系统的详细设计说明书[3-详细设计说明书.md](0-设计方案/3-详细设计说明书.md)
实现完成前端部分的管理页面-权限管理页面,能够为角色为user的用户设置可以访问,构建的分支
1 后端实现接口,查询角色为user的所有用户
2 后端需要定期维护一份,最小颗粒度到Organization Folder-Repository-Branch的权限结构,供前端直接调用
3 前端设计经典的权限分配页面,可以为角色分配权限
4 需要查询展示用户已具备的权限
4 需要将用户权限保存至数据库中
前端-用户页面
1 属于该用户权限的Organization Folder-Repository-Branch
2 具有查看 构建的权限
3 可以针对特定Branch触发构建任务
上述说明只是基础要求,请丰富功能,增强设计
jenkins的项目层级及调用说明如[5-jenkins项目层级.md](0-设计方案/5-jenkins项目层级.md)所以其中python的调用代码是正常运行符合要求的。
请完全重构项目中Jenkins部分的代码请完全重构项目中Jenkins部分的代码
在本项目中类似CMII-UAV-Cloud-Backend-GITLAB这类从Gitlab同步过来的Organization Folder是主要来源获取项目详情需要仿照python代码进行改造。
## 修改Jenkins存储的数据结构
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)
Jenkins官方的项目层级及调用说明见[5-jenkins项目层级.md](0-设计方案/5-jenkins项目层级.md)采用Organization Folder-Repository-Branch的权限结构请进行如下的项目修改
1 修改数据库jenkins_projects表为 jenkins_organization_folders
2 将目前jenkins_repositories表中的repository_name转换存储转换规则为 cmlc%2FCMII-UAV-Cloud-Web%2Fcloud-platform-armypeople 去除掉 %2F之前的内容转换为cloud-platform-armypeople
3 修改jenkins_branches表中的repository_name字段转换规则同上
4 修改jenkins_builds表中的repository_name字段转换规则同上
5 从JenkinsAPI新获取的数据均需要进行如上的转换修改
6 需要修改现有数据库中的数据
## Jenkins权限
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)
目前Jenkins的权限绑定不够精细需要进行重构修改
1. 前提条件新增或者修改查询接口能够分层快速获取到特定项目的branch避免数据爆炸
1. 查询所有的Organization Folder
2. 查询特定Organization Folder下的所有Repository
3. 查询特定Repository下的所有Branch
2. 角色具备的最小权限层级 应该到branch级别
3. 优化现有的角色权限存储数据库结构
1. 能够快速查询出角色拥有的全部权限树结构
2. 能够快速判定角色是否拥有特定Organization Folder-Repository-Branch的权限
4. 前端获取全量的权限树应该是分层获取的,禁止一次性获取
1. 接口见前文所述的查询接口
2. 默认获取全部的Organization Folder
3. 展开特定Organization Folder权限分支之后,获取特定Organization Folder下的所有Repository
4. 展开特定Repository权限分支之后,获取特定Repository下的所有Branch
5. 前端权限支持层级权限赋予
1. 如可以直接赋予特定Organization Folder的全部权限,前端无需加载之下的Repository和Branch,直接传递给后端,后端检测到该Organization Folder权限时,自动加载之下的Repository和Branch,然后存储至数据库中
2. 同理,如可以直接赋予特定Repository的全部权限,前端无需加载之下的Branch,直接传递给后端,后端检测到该Repository权限时,自动加载之下的Branch,然后存储至数据库中
6. 权限模板
1. 支持将另一个用户的权限一键复制到当前用户
2. 后端提供权限复制接口
3. 前端页面需要有相应的设计
7. 前端页面-管理-用户权限页面
1. 双向选择布局
1. 左侧面板 - 所有可用权限
1. 完整的Jenkins三层树结构Org→Repo→Branch
2. 可多选分支进行批量添加
3. 独立搜索框快速定位
2. 中间操作区
1. ➡️ 添加权限选中左侧分支设置View/Build权限级别后添加
2. ⬅️ 移除权限:从右侧移除选中的权限
3. 💾 保存:一键保存所有权限变更
3. 右侧面板 - 用户已有权限
1. 仅显示用户当前拥有的权限
2. 显示每个分支的View/Build权限状态
3. 支持多选批量移除
#### 前端编程规范
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)
针对@PermissionManager.vue 在此页面中Existing Permissions中,现有的逻辑需要进行修改
1. 后端权限部分的路由,需要新增接口
1. 前端-用户部分-分支项目页面
2. 前端-管理部分-用户权限页面
3. 需要根据用户拥有的权限,查询出属于自己的Organization Folder-Repository-Branch层级结构
2. 此部分权限-分支部分的接口
1. 需要认证
2. 需要分层获取
## 用户页面
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)
针对前端页面的用户页面部分,进行如下的修改
1. 路径为 localhost:5173/user/builds
2. 使用如下的API接口,后端的接口已经实现了一部分
1. permissions.GET("/my-tree/organizations", permissionHandler.GetMyOrganizations)
2. permissions.GET("/my-tree/organizations/:org/repositories", permissionHandler.GetMyRepositories)
3. permissions.GET("/my-tree/organizations/:org/repositories/:repo/branches", permissionHandler.GetMyBranches)
4. permissions.GET("/my-tree/organizations/:org/repositories/:repo/branches/:branch/builds", permissionHandler.GetMyBranchBuilds)
3. 能够仿照Jenkins的客户端,按照层级展示,一层一层知道查看分支的所有构建,单次构建的详情
4. 页面设计要美观
### Jenkins构建及日志API
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)
Jenkins的构建及日志API的调用说明见[6-jenkins-api-2.md](0-设计方案/6-jenkins-api-2.md),请参考该文档实现如下的内容
1. 构建API
1. 后端需要实现从Jenkins获取构建信息
2. 需要实现触发构建(参数化构建)
3. 在本项目中, 后端和前端支持的构建参数均有限
2. 日志API
1. 后端需要实现从Jenkins获取历史构建日志(全部日志)
2. 后端需要实现从Jenkins获取实时构建日志(流式日志)
3. 构建状态API
1. 后端需要实现从Jenkins获取构建状态,触发构建后,需要实时获取构建状态,直到构建完成或者异常
4. 前端 用户页面@UserDashboard.vue
1. 实时构建状态
1. 构建层级
1. Organization Folder
2. Repository
3. Branch --此级别若展开, 可以实时查看最新Build的构建状态是构建中还是构建完成。需要标识构建成功还是构建失败
4. Build --此级别若展开, 可以实时查看最新Build的构建状态 可以查看构建的完整日志
2. Build 构建详情页面
1. 可以实时查看最新Build的构建状态,是构建中,还是构建完成。
2. 需要标识构建成功还是构建失败
3. 如果是在构建中,需要能够可以查看实时的构建日志
4. 如果是构建完成,需要能够查看构建的完整日志
5. 日志显示模块
1. 需要能够快速清晰的显示日志内容
2. 通常情况一个build的完整日志内容大小为100KB需要能够快速的显示
3. 日志内容需要能够快速的滚动
4. 日志的字体大小支持调节
5. 日志内容支持下载
6. 日志显示支持彩色字体显示
7. 日志显示支持搜索
8. 日志显示支持复制
4. Branch页面展开 可以触发构建
1. 在特定的分支页面,点击进入构建触发页面
2. 构建触发页面,可以查看当前分支的构建参数
3. 构建触发页面,可以触发构建
4. 触发构建之后自动调转到Build详情页面
### Jenkins参数化构建
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)
为了实现Jenkins的参数化构建,需要实现如下的功能
1. 根据Organization Folder名称中包含的关键字区分加载的参数化构建参数
1. Backend
2. Web
3. Algorithm
2. Backend的参数化构建参数
"parameters": {
"DEPLOY_MODE_STD": "deploy",
"DEPLOY_NAME": "cmii-fly-center",
"DEPLOY_VERSION": "5.7.0-snapshot",
"DEPLOY_BUILD_TARGET": "x86",
"DEPLOY_BUILD_LICENCE": "no",
"SYS_K8S_NAMESPACE": "dev-flight",
"TARGET_JAVA_BASE_IMAGE": "jdk11-base-simple:2.0",
"TARGET_JAVA_OPTS": "-Xms256m-Xmx512m-Dlog4j2.formatMsgNoLookups=true"
}
3. Web的参数化构建参数
"parameters": {
"DEPLOY_MODE_STD": "deploy",
"DEPLOY_NAME": "cmii-uav-platform-lite",
"DEPLOY_VERSION": "5.7.0-snapshot",
"DEPLOY_BUILD_TARGET": "x86",
"DEPLOY_BUILD_LICENCE": "no",
"SYS_K8S_NAMESPACE": "dev-flight",
"TARGET_JS_THEME": "default",
"TARGET_JS_ENV": "dev"
}
4. 针对上述的构建参数说明如下
1. DEPLOY_MODE_STD是固定的几个可选选项前端需要做成下拉选择框唯一选择
1. 可选项如下默认为deploy用户只能选择一个
2. [build image]: 仅执行镜像构建
3. [deploy]: = [build image] + [reinstall]
4. [reinstall]: 重新安装应用(不会执行镜像的构建)
5. [upgrade]: 更新应用(不会执行镜像的构建,仅更新有变化的部分)
6. [uninstall]: 卸载应用
7. [only dry run]: 测试部署配置,而不真正执行
2. DEPLOY_NAME是只读选项只做显示
1. 数据库维护一张表每一个org repository 对应一个 deploy_name
2. 实现后端的查询,参数化构建,自动获取该参数
3. 需要实现这个表
3. DEPLOY_VERSION是输入框用户输入
4. DEPLOY_BUILD_TARGET是固定的几个可选选项前端需要做成下拉选择框唯一选择
1. 可选项如下默认为x86用户只能选择一个
2. [x86]: x86 架构
3. [arm]: arm 架构
5. DEPLOY_BUILD_LICENCE是固定的几个可选选项前端需要做成下拉选择框唯一选择
1. 可选项如下默认为no用户只能选择一个
2. [no]: 不需要许可证
3. [yes]: 需要许可证
6. SYS_K8S_NAMESPACE是固定的几个可选选项前端需要做成下拉选择框唯一选择
1. 可选项如下默认为dev-flight用户只能选择一个
2. [dev-flight]: 开发环境
3. [dev]: 开发环境-2
4. [dev-operation]: 开发环境-3
5. [test]: 测试环境
6. [validation]: 测试环境-2
7. [feature]: 测试环境-3
7. TARGET_JAVA_BASE_IMAGE是固定的几个可选选项前端需要做成下拉选择框唯一选择
1. 可选项如下默认为jdk11-base-simple:2.0,用户只能选择一个
2. [jdk11-base-simple:2.0]: jdk11-base-simple:2.0
3. [jdk17-base-simple:2.0]: jdk17-base-simple:2.0
8. TARGET_JAVA_OPTS是输入框但是有默认值
9. TARGET_JS_THEME是固定的几个可选选项前端需要做成下拉选择框唯一选择
1. 可选项如下默认为default用户只能选择一个
2. [default]: default
3. [dark]: dark
10. TARGET_JS_ENV是固定的几个可选选项前端需要做成下拉选择框唯一选择
1. 可选项如下默认为dev用户只能选择一个
2. [dev]: dev
3. [test]: test
4. [validation]: validation
5. [feature]: feature
6. [prod]: prod
### 用户页面 分支搜索
### 分支同步 高可用
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md),针对 @[jenkins_servers.go](../backend/internal/service/jenkins_service.go)
目前syncRepository()方法 采用的是单线程的同步方式,导致一次分支同步的时间非常长,进行如下修改
1. 修改为并发的形式请求,限制并发的请求速率
2. 存储数据库,请进行采用单例或者减少数据库操作的次数
1. 实际情况,有大量的用户使用会操作数据库,可能导致数据库locked
2. 尽量减少数据库的插入次数
## 审计日志
编程规范请遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md),针对 @[jenkins_servers.go](../backend/internal/service/jenkins_service.go)
请针对系统的审计日志部分,进行如下的修改
1. 精简原则
1. 只记录操作类日志,修改,新增,删除
1. 后期业务会进行拓展如Jenkins构建微服务更新
2. 请求参数quryParm requestbody等均需要被记录
2. 不记录登录,查看等普通操作日志
3. 不记录user_agent
4. 修改detail为path只记录访问路径
2. 性能原则
1. 考虑到sqlite3的并发性能
2. 考虑到多用户实际使用导致的并发问题
3. 审计日志的写入需要考虑不要影响到其他的正常业务
3. 功能设计
1. 管理页面能够筛选查询特定用户特定操作如Jenkins构建的详细操作信息
2. 能够查看审计日志占用的数据库空间
3. 能够删除如3个月、1个月之前的所有审计日志
#### 页面美化
请参考[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)的编程规范使用vutify的样式对 @PermissionManager.vue 页面进行美化
1. 页面功能重构
1. 支持筛选框,快速筛选用户
1. 获取全部用户的列表
2. 分支搜索定位
1. @jenkins_service.go 执行全量项目同步时应该维护一张完整的Organization Folder-Repository-Branch树状结构
2. 前端搜索框能够从树接口,快速查找到 Organization Folder-Repository-Branch的定位
3. 通用模块,前端有多个地方需要用到此搜索
4. @PermissionManager.vue 页面搜索定位到分支之后权限框应该能依次查询Org-Repo-Branch然后定位
显示到此处
5. @UserDashboard.vue 页面应该页 新增搜索框
1. 用户登录页面,会加载一次自身拥有权限的 树状结构
2. 此页面搜索框,从部分树状结构能够快速定位查找
3. 此页面能够根据查找到的定位 快速展示响应的层级
6. @ProjectsManagement.vue 页面 也应该新增此搜索方法
1. 此页面搜索框,从部分树状结构能够快速定位查找
2. 此页面能够根据查找到的定位 快速展示响应的层级
7. 考虑复用 /permissions/my-tree/* 接口
1. 若可以复用, 请修改为requestBody的形式不要用路径变量
2. 美化页面布局
1. 美化Organization Folder-Repository-Branch项目的图标
2. 美化此页面的布局使用vuetify的元素
请参考[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md)的编程规范使用vutify的样式对 @ProjectsManagement.vue 页面进行修改
1. 可以直接使用 @UserDashboard 那一套项目查看体系,可以直接搬过来
2. 项目结构优化,可以将通用的模块放置于一起
3. 管理员和普通用户只是可以操作的org-repo-branch的数量不同而已
### 角色信息及注册页面
请严格遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md),对用户部分进行如下的修改
1. 用户表结构字段
1. 用户名 -中文真实姓名
2. 英文用户名 - 前端自动通过中文真实姓名转换而来
3. 头像ID - 注册页面需要选择头像
4. 角色 - 见下文 用户体系
4. 性别 - 男/女
5. 邮箱 - 和公司VPN注册邮箱相同
6. 手机号 - 必填
7. 密码 - 自己设定
7. 状态 - active locked disabled
8. 注册时间 - 自动生成,前端不展示
8. 删除时间
9. 注册人ID - 由谁注册
8. 公司名称
9. 开发角色-前端工程师/后端工程师/测试工程师/运维工程师
2. 注册页面
1. 注册页面注册之后用户状态默认是locked状态提示需要管理员审批才能使用
2. 注册页面,需要选择头像
1. 提供默认的头像svg
2. 头像svg保存在前端底层
3. 不同角色层级,能够使用的头像不同,高等级的头像更加炫酷
3. 不要使用在线头像
4. 选择头像之后前端需要将头像svg对应的ID保存到数据库
3. 性别为 下拉选择框
4. 邮箱需要检测邮箱格式
5. 公司名称
6. 开发角色
3. 用户体系修改-修改为如下的四个等级
1. SuperAdmin 超级管理员
1. 程序初始化创建的唯一超级管理员
2. 超级管理员头像带有太阳头像框
2. Admin 管理员
1. 管理员头像带有星星头像框
3. Normal 普通用户
4. Third 三方人员
1. 权限最低
4. 管理-用户管理页面 @UserManagement.vue页面
1. 需要展示用户完整的信息
2. SuperAdmin Admin可以修改角色的信息
3. SuperAdmin Admin可以修改用户的状态
4. SuperAdmin 可以修改用户的角色
## 消息中心
请严格遵守[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md)和[vue3-typescript-stye.md](0-设计方案/vue3-typescript-stye.md),按照下文的要求设计详细中心模块
# 项目迁移
完整的系统设计方案见[2-rmdc-DDS.md](0-设计方案\1-基本框架\2-rmdc-DDS.md) 项目系统架构图见[3-系统设计图-sonnet4.5.md](0-设计方案/3-系统设计图-sonnet4.5.md) 当前项目的结构已经降级为RMDC-jenkins-branch-dac子模块
后端代码的编程规范说明见[go-gin-gorm-style.md](0-设计方案/go-gin-gorm-style.md),请严格遵守
请按照项目设计,重构当前的代码结构,要求如下
1. 后端项目模块采用的模块名称示例
1. wdd.io/RMDC/jenkins-branch-dac
2. wdd.io/RMDC/exchange-hub
3. wdd.io/RMDC/watchdog-center
2. 后端项目模块之间采用replace的方式互引用
2. 我已经将之前实现的cmii-uav-watchdog模块复制过来,请按照项目设计说明,进行重构
1. C:\Users\wddsh\Documents\IdeaProjects\RMDC\cmii-uav-watchdog 相对独立
2. C:\Users\wddsh\Documents\IdeaProjects\RMDC\cmii-uav-watchdog-center 请融合进入RMDC
3. 所有的代码我已经重构保存,请放心操作
4. 请勿操作.gitignore覆盖的文件

View File

@@ -0,0 +1,330 @@
# RMDC 项目权限设计方案
## 1. 概述
本文档描述RMDC平台统一权限系统的设计方案涵盖
- 权限系统架构设计
- 模块依赖关系
- 接口抽象层设计
- 权限校验流程
---
## 2. 模块依赖关系
### 2.1 设计原则
- **单向依赖**:业务模块不依赖权限模块,权限模块通过接口访问业务数据
- **接口抽象**:公共接口定义在 `rmdc-common`,各模块实现具体接口
- **依赖注入**`rmdc-core` 负责注入所有依赖
### 2.2 依赖关系图
```mermaid
graph TB
subgraph "公共层"
Common[rmdc-common<br/>公共接口定义]
end
subgraph "权限层"
UserAuth[rmdc-user-auth<br/>权限中心<br/>实现PermissionChecker]
end
subgraph "业务层"
Jenkins[rmdc-jenkins-branch-dac<br/>实现ResourceProvider]
Watchdog[rmdc-watchdog-center<br/>实现ResourceProvider]
Monitor[rmdc-monitor-center<br/>实现ResourceProvider]
Delivery[rmdc-delivery-update<br/>实现ResourceProvider]
end
subgraph "核心层"
Core[rmdc-core<br/>网关 + 依赖注入]
end
UserAuth --> Common
Jenkins --> Common
Watchdog --> Common
Monitor --> Common
Delivery --> Common
Core --> UserAuth
Core --> Jenkins
Core --> Watchdog
Core --> Monitor
Core --> Delivery
style Common fill:#4ecdc4,stroke:#087f5b
style Core fill:#ffd43b,stroke:#f08c00
style UserAuth fill:#ff6b6b,stroke:#c92a2a
```
### 2.3 依赖关系表
| 模块 | 依赖 | 实现接口 |
|------|------|----------|
| `rmdc-common` | 无 | 定义接口 |
| `rmdc-user-auth` | `rmdc-common` | `PermissionChecker` |
| `rmdc-jenkins-branch-dac` | `rmdc-common` | `ResourceProvider` |
| `rmdc-watchdog-center` | `rmdc-common` | `ResourceProvider` |
| `rmdc-core` | 所有上述模块 | - |
---
## 3. 权限接口抽象层
### 3.1 PermissionChecker 接口
```go
// 位置: rmdc-common/pkg/permission/interface.go
package permission
import "context"
// PermissionChecker 统一权限检查接口
type PermissionChecker interface {
// CheckPermission 检查用户对资源的权限
// @param userID 用户ID
// @param resourceType 资源类型: "jenkins_branch", "watchdog_project", "watchdog_host"
// @param resource 资源路径: "org/repo/branch" 或 "project_id"
// @param action 操作类型: "view", "build", "exec", "manage"
CheckPermission(ctx context.Context, userID int64, resourceType, resource, action string) (bool, error)
// IsSuperAdmin 检查是否为超级管理员
IsSuperAdmin(ctx context.Context, userID int64) (bool, error)
// GetUserRole 获取用户角色
GetUserRole(ctx context.Context, userID int64) (string, error)
}
```
### 3.2 ResourceProvider 接口
```go
// 位置: rmdc-common/pkg/resource/interface.go
package resource
import "context"
// ResourceProvider 资源提供者接口(各业务模块实现)
type ResourceProvider interface {
// GetResourceType 返回资源类型标识
GetResourceType() string
// ListResources 列出所有资源用于权限分配UI
ListResources(ctx context.Context) ([]Resource, error)
// ListResourcesForUser 列出用户有权限的资源
ListResourcesForUser(ctx context.Context, userID int64) ([]Resource, error)
// ValidateResource 验证资源是否存在
ValidateResource(ctx context.Context, resourcePath string) (bool, error)
}
// Resource 资源结构
type Resource struct {
Type string `json:"type"` // 资源类型
Name string `json:"name"` // 资源名称
Path string `json:"path"` // 完整路径
Children []Resource `json:"children,omitempty"`
}
```
---
## 4. 统一权限校验流程
### 4.1 校验流程图
```mermaid
flowchart TB
subgraph "请求入口"
Request[API请求<br/>携带JWT Token]
end
subgraph "rmdc-core 网关层"
Router[Gin Router]
AuthMW[AuthMiddleware<br/>1. JWT解析<br/>2. 提取user_id/role]
PermMW[PermissionMiddleware<br/>1. SuperAdmin跳过<br/>2. 权限检查]
end
subgraph "rmdc-user-auth 权限中心"
PermService[PermissionService]
subgraph "模块权限检查器"
JenkinsChecker[JenkinsPermissionChecker<br/>Jenkins分支权限]
WatchdogChecker[WatchdogPermissionChecker<br/>项目/主机权限]
end
subgraph "缓存层"
L1[L1: 内存缓存<br/>sync.Map]
L2[L2: 数据库缓存<br/>user_permission_trees]
end
end
subgraph "业务模块"
JenkinsHandler[JenkinsHandler<br/>无权限检查逻辑]
WatchdogHandler[WatchdogHandler<br/>无权限检查逻辑]
end
subgraph "数据库"
PermDB[(user_permissions)]
end
Request --> Router --> AuthMW --> PermMW
PermMW -->|SuperAdmin| JenkinsHandler
PermMW -->|SuperAdmin| WatchdogHandler
PermMW -->|其他角色| PermService
PermService --> L1
L1 -->|未命中| L2
L2 -->|未命中| PermDB
PermService -->|有权限| JenkinsHandler
PermService -->|有权限| WatchdogHandler
PermService -->|无权限| Request
style PermMW fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px
style PermService fill:#ffd43b,stroke:#f08c00,stroke-width:2px
```
### 4.2 权限检查算法
```mermaid
flowchart TD
Start[开始权限检查] --> GetRole[获取用户角色]
GetRole --> IsSuperAdmin{superadmin?}
IsSuperAdmin -->|是| Allow[✅ 允许访问]
IsSuperAdmin -->|否| CheckL1[检查L1内存缓存]
CheckL1 --> L1Hit{缓存命中?}
L1Hit -->|是| CheckPerm[检查权限树]
L1Hit -->|否| CheckL2[检查L2数据库缓存]
CheckL2 --> L2Hit{缓存命中?}
L2Hit -->|是| UpdateL1[更新L1缓存]
L2Hit -->|否| BuildTree[从权限表构建权限树]
UpdateL1 --> CheckPerm
BuildTree --> SaveL2[保存到L2缓存]
SaveL2 --> UpdateL1
CheckPerm --> HasPerm{有权限?}
HasPerm -->|是| Allow
HasPerm -->|否| Deny[❌ 拒绝访问]
```
---
## 5. 角色权限模型
### 5.1 角色定义
| 角色 | 常量 | 说明 |
|------|------|------|
| **超级管理员** | `superadmin` | 拥有全部权限,可管理所有用户和资源 |
| **管理员** | `admin` | 拥有分配的权限可将自有权限分配给normal/third |
| **普通人员** | `normal` | 拥有分配的权限,无分配能力 |
| **三方人员** | `third` | 拥有分配的权限,无分配能力,权限受限最严格 |
### 5.2 模块级权限
#### Jenkins分支权限
| 资源类型 | 权限类型 | 说明 |
|----------|----------|------|
| Organization | can_view, can_build | 组织级权限,自动继承到子仓库/分支 |
| Repository | can_view, can_build | 仓库级权限,自动继承到子分支 |
| Branch | can_view, can_build | 分支级权限,最细粒度 |
#### Watchdog项目权限
| 资源类型 | 权限类型 | 说明 |
|----------|----------|------|
| Project | can_view, can_manage | 项目级权限 |
| Host | can_view, can_exec | 主机操作权限 |
| Namespace | can_view, can_deploy | K8s命名空间权限 |
### 5.3 权限分配规则
```mermaid
flowchart LR
SuperAdmin[SuperAdmin] -->|可分配| Admin
SuperAdmin -->|可分配| Normal
SuperAdmin -->|可分配| Third
Admin -->|可分配自有权限| Normal
Admin -->|可分配自有权限| Third
style SuperAdmin fill:#ff6b6b
style Admin fill:#ffd43b
style Normal fill:#4ecdc4
style Third fill:#a9e34b
```
---
## 6. 数据库设计
### 6.1 统一权限表
```sql
CREATE TABLE user_permissions (
id BIGSERIAL PRIMARY KEY,
user_id BIGINT NOT NULL,
resource_type VARCHAR(50) NOT NULL, -- 'jenkins_branch', 'watchdog_project'
resource_path VARCHAR(255) NOT NULL, -- 'org/repo/branch' or 'project_id'
permission_level VARCHAR(20), -- 'org', 'repo', 'branch', 'project'
can_view BOOLEAN DEFAULT FALSE,
can_build BOOLEAN DEFAULT FALSE, -- Jenkins特有
can_exec BOOLEAN DEFAULT FALSE, -- Watchdog特有
can_manage BOOLEAN DEFAULT FALSE,
granted_by BIGINT,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW(),
UNIQUE(user_id, resource_type, resource_path),
INDEX idx_user_resource (user_id, resource_type)
);
```
### 6.2 权限树缓存表
```sql
CREATE TABLE user_permission_trees (
user_id BIGINT PRIMARY KEY,
tree JSON NOT NULL, -- 完整权限树JSON
version BIGINT DEFAULT 0, -- 版本号
updated_at TIMESTAMP DEFAULT NOW()
);
```
---
## 7. API设计
### 7.1 用户权限查询API
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/permissions/my-tree/organizations` | GET | 获取当前用户的组织列表 |
| `/api/permissions/my-tree/repositories` | POST | 获取当前用户的仓库列表 |
| `/api/permissions/my-tree/branches` | POST | 获取当前用户的分支列表 |
| `/api/permissions/my-tree/full` | GET | 获取完整权限树 |
### 7.2 权限管理API (Admin)
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/permissions/tree` | GET | 获取系统权限树 |
| `/api/permissions/:userId` | GET | 获取用户权限详情 |
| `/api/permissions/assign` | POST | 分配权限 |
| `/api/permissions/copy` | POST | 复制权限 |
---
## 8. 文档版本
| 版本 | 日期 | 修改内容 |
|------|------|----------|
| v1.0 | 2025-12-10 | 初始版本 |

View File

@@ -0,0 +1,165 @@
# Jenkins Organization Folder REST API 接口文档
Organization Folder 是 Jenkins 中用于自动扫描整个组织(如 GitHub Organization、GitLab Group、Bitbucket Team并为每个仓库自动创建 Multibranch Pipeline 的项目类型 。[1]
***
## URL 层级结构
Organization Folder 比普通 Multibranch Pipeline 多一层嵌套,其层级结构为 [2][3]
```
{JENKINS_URL}
└── /job/{ORG_FOLDER_NAME} ← Organization Folder 层
└── /job/{REPO_NAME} ← Multibranch Pipeline 层(仓库)
└── /job/{BRANCH_NAME} ← 分支层
└── /{BUILD_NUMBER} ← 构建层
```
***
## 一、获取组织与仓库信息
### 1.1 获取 Organization Folder 下所有仓库
| 项目 | 说明 |
|-----|------|
| **请求地址** | `GET {JENKINS_URL}/job/{ORG_FOLDER_NAME}/api/json` |
| **返回内容** | 该组织下所有已扫描的仓库列表(即 Multibranch Pipeline 列表)|
**常用参数**
```
?tree=jobs[name,url,_class]&depth=1
```
### 1.2 获取某仓库下所有分支
| 项目 | 说明 |
|-----|------|
| **请求地址** | `GET {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/api/json` |
| **返回内容** | 该仓库下所有分支及其 Job 信息 |
**示例请求**
```
GET {JENKINS_URL}/job/my-github-org/job/my-repo/api/json?tree=jobs[name,url,lastBuild[number,result]]
```
### 1.3 获取某分支的所有构建信息
| 项目 | 说明 |
|-----|------|
| **请求地址** | `GET {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/job/{BRANCH_NAME}/api/json` |
| **常用参数** | `?tree=builds[number,result,timestamp,duration]&depth=1` |
> **注意**:分支名中的 `/` 需要编码为 `%2F`,例如 `feature/login` → `feature%2Flogin`
***
## 二、触发分支构建
### 2.1 无参数构建
| 项目 | 说明 |
|-----|------|
| **请求地址** | `POST {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/job/{BRANCH_NAME}/build` |
| **认证** | 需要 Basic Auth用户名 + API Token|
### 2.2 带参数构建
| 项目 | 说明 |
|-----|------|
| **请求地址** | `POST {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/job/{BRANCH_NAME}/buildWithParameters` |
| **参数传递** | Query String 或 Form Data |
**示例**
```
POST {JENKINS_URL}/job/my-github-org/job/my-repo/job/main/buildWithParameters?ENV=production&VERSION=1.0.0
```
### 2.3 获取构建号
构建触发后,从 `Location` Header 获取队列 ID再查询实际构建号
| 步骤 | 请求地址 |
|-----|---------|
| 获取队列项 | 响应 Header `Location``{JENKINS_URL}/queue/item/{QUEUE_ID}/` |
| 查询构建号 | `GET {JENKINS_URL}/queue/item/{QUEUE_ID}/api/json` |
| 返回字段 | `executable.number` 即为构建号 |
***
## 三、实时查看 Console 输出
### 3.1 获取完整日志
| 项目 | 说明 |
|-----|------|
| **请求地址** | `GET {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/job/{BRANCH_NAME}/{BUILD_NUMBER}/consoleText` |
| **返回格式** | 纯文本 |
### 3.2 增量实时获取
| 项目 | 说明 |
|-----|------|
| **请求地址** | `GET {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/job/{BRANCH_NAME}/{BUILD_NUMBER}/logText/progressiveText?start={OFFSET}` |
| **响应 Header** | `X-Text-Size`(下次偏移量)、`X-More-Data`(是否继续)|
***
## 四、组织扫描操作
### 4.1 触发组织扫描(发现新仓库/分支)
| 项目 | 说明 |
|-----|------|
| **扫描整个组织** | `POST {JENKINS_URL}/job/{ORG_FOLDER_NAME}/build` |
| **扫描单个仓库** | `POST {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/build` |
扫描操作会检测新增/删除的仓库和分支,并自动更新 Jenkins Job 结构 。[1]
### 4.2 查看扫描日志
| 项目 | 说明 |
|-----|------|
| **组织扫描日志** | `GET {JENKINS_URL}/job/{ORG_FOLDER_NAME}/computation/consoleText` |
| **仓库扫描日志** | `GET {JENKINS_URL}/job/{ORG_FOLDER_NAME}/job/{REPO_NAME}/indexing/consoleText` |
***
## 五、完整 URL 路径汇总
| 功能 | 请求方法 | URL 模板 |
|-----|---------|---------|
| 组织下所有仓库 | GET | `/job/{ORG}/api/json` |
| 仓库下所有分支 | GET | `/job/{ORG}/job/{REPO}/api/json` |
| 分支构建列表 | GET | `/job/{ORG}/job/{REPO}/job/{BRANCH}/api/json` |
| 单次构建详情 | GET | `/job/{ORG}/job/{REPO}/job/{BRANCH}/{NUM}/api/json` |
| 触发分支构建 | POST | `/job/{ORG}/job/{REPO}/job/{BRANCH}/build` |
| 带参数构建 | POST | `/job/{ORG}/job/{REPO}/job/{BRANCH}/buildWithParameters` |
| 完整日志 | GET | `/job/{ORG}/job/{REPO}/job/{BRANCH}/{NUM}/consoleText` |
| 增量日志 | GET | `/job/{ORG}/job/{REPO}/job/{BRANCH}/{NUM}/logText/progressiveText?start={OFFSET}` |
| 扫描组织 | POST | `/job/{ORG}/build` |
| 扫描仓库 | POST | `/job/{ORG}/job/{REPO}/build` |
> **特殊字符处理**:分支名中的 `/` 编码为 `%2F``#` 编码为 `%23`
[1](https://www.jenkins.io/doc/book/pipeline/pipeline-as-code/)
[2](https://plugins.jenkins.io/branch-api/)
[3](https://github.com/jenkinsci/branch-api-plugin)
[4](https://www.jenkins.io/doc/book/using/remote-access-api/)
[5](https://note.com/wa_k77/n/nad2af1ac6d95)
[6](https://stackoverflow.com/questions/55260693/jenkins-create-folder-with-rest-api-in-groovy-script)
[7](https://www.postman.com/api-evangelist/jenkins/folder/cu1b5xc/organization)
[8](https://www.kaizenprogrammer.com/entry/2017/03/20/130721)
[9](https://stackoverflow.com/questions/51428735/list-all-folders-under-jenkins-with-their-path)
[10](https://jenkins-job-builder.readthedocs.io/en/latest/project_githuborg.html)
[11](https://stackoverflow.com/questions/44054789/in-jenkins-how-to-build-job-which-is-inside-folder-using-rest-api)
[12](https://www.youtube.com/watch?v=BcUSfG4A9AI)
[13](https://stackoverflow.com/questions/38507358/how-to-use-jenkins-github-organization-folder-with-github-protected-branches)
[14](https://github.com/jenkinsci/folder-auth-plugin/blob/master/docs/rest-api.adoc)
[15](https://plugins.jenkins.io/cloudbees-folder/)
[16](https://community.jenkins.io/t/failing-to-build-in-an-github-organization-folder-repo/31760)
[17](https://qiita.com/Sho2010@github/items/2a9c13d2f67e754cfb4f)
[18](https://stackoverflow.com/questions/37615638/specify-the-git-url-location-of-jenkinsfile-in-a-github-organization-job)
[19](https://github.com/jenkinsci/branch-api-plugin/blob/master/src/main/java/jenkins/branch/OrganizationFolder.java)
[20](https://jenkinsci.github.io/job-dsl-plugin/)

View File

@@ -0,0 +1,208 @@
根据Jenkins官方文档Jenkins的实际层级组织结构如下
## Jenkins的实际层级结构
Jenkins在使用**Organization Folder**(组织文件夹)功能时,采用的层级结构为:
```
Organization Folder组织
└── Repository/Project仓库/项目)
└── Branch分支
└── Build构建
```
官方文档中明确展示的层级示例:
```
+--- GitHub Organization
+--- Project 1
+--- master
+--- feature-branch-a
+--- feature-branch-b
+--- Project 2
+--- master
+--- pull-request-1
```
## 关键区别
"Projects → Repository"实际上在Jenkins中是同一层级的概念。 Jenkins使用以下术语
- **Organization Folder**对应GitHub Organization、Bitbucket Team、GitLab Organization等组织级别
- **Multibranch Pipeline Project**对应单个代码仓库会自动为该仓库的所有包含Jenkinsfile的分支创建构建任务
- **Branch**具体的分支或Pull Request
- **Build**:针对某个分支的具体构建执行
## 实现逻辑
Jenkins通过以下机制实现这种层级
1. **Multibranch Pipeline**自动扫描单个仓库为每个包含Jenkinsfile的分支创建Pipeline任务
2. **Organization Folder**自动扫描整个组织为每个符合条件的仓库创建Multibranch Pipeline项目
3. 当分支或仓库被创建/删除时可以通过webhook或定期扫描自动更新Jenkins中的任务结构
因此,准确的表述应该是:**Organization → Repository(Project) → Branch → Build**其中Repository和Project是等价的概念。
根据Jenkins官方文档和API最佳实践您可以通过以下方式获取GitLab Organization Folder的所有分支和构建信息
## 推荐方案使用Tree参数的单次API调用
最高效的方式是使用`tree`参数通过一次API调用获取所有数据
```bash
https://<JENKINS_HOST>/job/<ORGANIZATION_FOLDER_NAME>/api/json?tree=jobs[name,url,jobs[name,url,builds[number,result,timestamp,duration,url]]]
```
### 参数说明
- **第一层`jobs`**Organization Folder下的所有RepositoryMultibranch Pipeline项目
- **第二层`jobs`**每个Repository下的所有Branch分支作为子job存在
- **`builds`**每个Branch的构建历史
### 限制返回的构建数量
如果构建历史过多可以限制返回数量例如最近50次
```bash
https://<JENKINS_HOST>/job/<ORGANIZATION_FOLDER_NAME>/api/json?tree=jobs[name,url,jobs[name,url,builds[number,result,timestamp,duration,url]{0,50}]]
```
`{0,50}`表示只返回最近50次构建。
## API调用结构层次
基于Organization Folder的结构API调用路径遵循以下层级
1. **Organization Folder**`/job/<FOLDER_NAME>`
2. **Repository (Multibranch Pipeline)**`/job/<FOLDER_NAME>/job/<REPO_NAME>`
3. **Branch**`/job/<FOLDER_NAME>/job/<REPO_NAME>/job/<BRANCH_NAME>`
4. **Build**`/job/<FOLDER_NAME>/job/<REPO_NAME>/job/<BRANCH_NAME>/<BUILD_NUMBER>`
## 完整示例
假设您的Organization Folder名为`CMII-UAV-Cloud-Backend-GITLAB`
```bash
# 获取所有仓库、分支和最近50次构建
curl -u username:api_token \
"https://<JENKINS_HOST>/job/CMII-UAV-Cloud-Backend-GITLAB/api/json?tree=jobs[name,url,jobs[name,url,builds[number,result,timestamp,duration,url]{0,50}]]"
```
## 性能优化建议
1. **避免使用`depth`参数**`depth`会返回大量不必要的数据,建议使用`tree`参数精确指定所需字段
2. **限制构建数量**:使用`{0,N}`语法限制每个分支返回的构建数量
3. **按需获取字段**:只请求必要的字段,减少数据传输量
分析您的API调用性能问题主要原因是**Jenkins需要遍历整个Organization Folder的所有仓库、分支和构建数据**即使您只请求了前3条记录。 以下是性能瓶颈和优化方案:
## 性能瓶颈分析
### 主要问题
1. **一次性加载所有数据**Jenkins API的`tree`参数在返回前必须先遍历整个数据树结构,即使使用`{0,3}`限制构建数量
2. **Organization Folder扫描开销**每个多分支项目的分支发现和元数据加载都会产生大量I/O操作
3. **深层嵌套查询**三层嵌套Organization → Repository → Branch → Builds导致指数级的数据查询
### 为什么`{0,3}`不起作用
`{0,3}`只限制**每个分支**返回的构建数量但Jenkins仍需要
- 遍历所有Repository
- 扫描每个Repository的所有分支
- 为每个分支加载元数据
## 高效解决方案
### 方案1分层逐级获取推荐
不要一次性获取所有层级,而是分步骤获取:
#### 步骤1获取所有Repository
```bash
curl -g -u username:token \
"http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/api/json?tree=jobs[name,url]"
```
返回速度快只获取Repository列表。
#### 步骤2并行获取每个Repository的分支
```bash
# 对每个Repository
curl -g -u username:token \
"http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/job/<REPO_NAME>/api/json?tree=jobs[name,url,lastBuild[number,result,timestamp,duration]]"
```
使用`lastBuild`只获取最新构建,而非所有构建历史。
#### 步骤3按需获取具体分支的构建历史
```bash
curl -g -u username:token \
"http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/job/<REPO_NAME>/job/<BRANCH_NAME>/api/json?tree=builds[number,result,timestamp,duration]{0,10}"
```
### 方案2只获取关键信息
如果只需要统计数据,使用最小化字段:
```bash
curl -g -u username:token \
"http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB/api/json?tree=jobs[name,jobs[name,lastBuild[number,result,timestamp]]]"
```
关键优化点:
- 移除`url`字段(可自行构造)
- 只用`lastBuild`替代`builds[]`
- 减少返回字段数量
### 方案3使用Python脚本异步并发获取
```python
import asyncio
import aiohttp
from aiohttp import BasicAuth
async def fetch_repos(session, base_url, auth):
url = f"{base_url}/api/json?tree=jobs[name]"
async with session.get(url, auth=auth) as resp:
data = await resp.json()
return [job['name'] for job in data.get('jobs', [])]
async def fetch_repo_branches(session, base_url, repo_name, auth):
url = f"{base_url}/job/{repo_name}/api/json?tree=jobs[name,lastBuild[number,result,timestamp]]"
async with session.get(url, auth=auth) as resp:
data = await resp.json()
return {
'repo': repo_name,
'branches': data.get('jobs', [])
}
async def main():
base_url = "http://192.168.34.41:27081/job/CMII-UAV-Cloud-Backend-GITLAB"
auth = BasicAuth('zeaslity', '114f14f0c48fd9dfb4d3092426b0f72913')
async with aiohttp.ClientSession() as session:
# 1. 获取所有仓库
repos = await fetch_repos(session, base_url, auth)
print(f"找到 {len(repos)} 个仓库")
# 2. 并发获取所有仓库的分支信息
tasks = [fetch_repo_branches(session, base_url, repo, auth) for repo in repos]
results = await asyncio.gather(*tasks)
# 3. 输出结果
for result in results:
print(f"\n仓库: {result['repo']}")
for branch in result['branches']:
build = branch.get('lastBuild', {})
if build != None:
print(f" 分支: {branch['name']}, 最新构建: #{build.get('number', 'N/A')}")
asyncio.run(main())
```
这个脚本将3分钟的串行请求压缩到数秒内。

View File

@@ -0,0 +1,192 @@
# Jenkins Build Flow - 构建流程图
此文档描述了完整的Jenkins构建触发、状态轮询、数据库持久化以及前端状态展示流程。
## 构建任务完整流程
```mermaid
sequenceDiagram
participant FE as Frontend
participant BE as Backend (Handler)
participant SVC as Service
participant DB as Database
participant JK as Jenkins
participant BT as BuildTracker
Note over FE,BT: 1. 触发构建
FE->>BE: POST /build/trigger
BE->>SVC: TriggerBuild()
SVC->>JK: TriggerBuildInOrg()
JK-->>SVC: Success
SVC->>JK: GetBranchBuildsInOrg() (get build number)
SVC->>DB: SaveBuild (is_building=true)
SVC->>BT: TrackBuild(estimatedDuration + 20s)
SVC-->>FE: Build Number
Note over FE,BT: 2. 跳转构建详情页
FE->>FE: 显示JenkinsBuildStatusCard
FE->>BE: GET /builds/details
BE->>SVC: GetBuildDetails()
SVC->>DB: GetBuildByNumber()
SVC->>JK: GetBuildDetailsInOrg()
SVC->>BT: UpdateQueryTime()
alt 构建已完成/失败
SVC->>JK: GetBuildArtifactDockerImage() (仅SUCCESS)
BT->>DB: UpdateBuild (async)
BT->>BT: RemoveTask
end
SVC-->>FE: Build Details
Note over FE,BT: 3. 前端等待轮询
FE->>FE: 计算 waitTime = estimatedDuration - elapsed - 20s
FE->>FE: JenkinsBuildStatusCard显示倒计时
Note over FE,BT: 4. 开始轮询
loop 每3秒 (直到超时或完成)
FE->>FE: 检查超时 (elapsed > estimated + 30s?)
alt 超时
FE->>FE: 停止轮询
else 未超时
FE->>BE: GET /builds/details
BE->>SVC: GetBuildDetails()
alt 构建完成/失败
SVC->>DB: Update (async)
SVC->>BT: Remove from tracker
SVC-->>FE: result != ""
FE->>FE: 停止轮询更新UI
else 仍在构建
SVC-->>FE: is_building=true
FE->>FE: 更新燃尽进度条
end
end
end
Note over FE,BT: 5. 后台超时检查
BT->>BT: checkBuildTimeouts() (每10秒)
alt 超时 (estimatedDuration + 20s)
BT->>JK: GetBuildDetailsInOrg()
BT->>DB: UpdateBuild
BT->>BT: RemoveTask
end
```
## 关键流程说明
### 1. 触发构建 (TriggerBuild)
1. 前端调用 `POST /build/trigger` 触发构建
2. 后端调用 Jenkins API 触发构建
3. 等待1秒后查询最新构建号
4. 将构建初始信息保存到 `jenkins_builds` 表 (is_building=true)
5. 启动 BuildTracker 追踪此构建任务
### 2. 构建详情查询 (GetBuildDetails)
1. 前端调用 `GET /builds/details` 获取构建详情
2. 后端优先从数据库获取已有信息(DCU相关)
3. 调用 Jenkins API 获取最新状态
4. **仅当构建成功时**才查询 ArtifactDockerImage避免不必要的日志解析
5. 通知 BuildTracker 更新查询时间
6. 如果构建已完成异步更新数据库并从Tracker移除
### 3. 前端轮询策略
**等待时间算法**:
```
waitTime = max(0, estimatedDuration - (currentTime - buildStartTime) - 20000ms)
```
- 考虑用户刷新页面的情况,使用已经过的时间计算剩余等待时间
- 提前20秒开始轮询确保及时获取最终状态
**超时停止**:
```
if (currentTime - buildStartTime > estimatedDuration + 30000ms) {
停止轮询
}
```
### 4. 后端超时保障
- BuildTracker 每10秒检查一次超时任务
- 超时时间 = estimatedDuration + 20秒
- 超时后主动查询Jenkins并更新数据库
- 确保即使前端未轮询,构建状态也能被正确记录
---
## JenkinsBuildStatusCard 组件
### 功能说明
位于 `BuildDetails.vue`产物信息卡片和DCU状态卡片之间用于展示Jenkins构建进度。
### 显示状态
| 状态 | 说明 |
|------|------|
| 等待查询 | 构建刚启动,显示轮询倒计时 |
| 构建中 | 显示燃尽进度条和实时duration |
| 超时运行中 | 构建时间已超过预估 |
| 成功/失败 | 构建完成,显示最终状态 |
### 燃尽进度条算法
```mermaid
flowchart TD
A[开始] --> B{duration >= estimatedDuration?}
B -->|No| C{duration >= estimatedDuration - 20s?}
B -->|Yes| D{duration >= estimatedDuration + 20s?}
C -->|No| E[绿色进度条 = 0%<br/>显示'等待中...']
C -->|Yes| F[绿色燃尽<br/>显示'预计完成 Xs']
D -->|No| G[红色增长<br/>显示'已超时 Xs']
D -->|Yes| H[红色 100%<br/>停止增长]
```
**进度条计算公式:**
1. **等待阶段** (`duration < estimated - 20s`):
- 颜色: 绿色
- 进度: 0%
- 文本: "等待中..."
2. **燃尽阶段** (`estimated - 20s <= duration < estimated`):
- 颜色: 绿色
- 进度: `100 - (estimated - duration) / 20s * 100`
- 文本: "预计完成 Xs"
3. **超时阶段** (`estimated <= duration < estimated + 20s`):
- 颜色: 红色
- 进度: `(duration - estimated) / 20s * 100`
- 文本: "已超时 Xs"
4. **停止阶段** (`duration >= estimated + 20s`):
- 颜色: 红色
- 进度: 100%
- 持续更新duration显示
### Duration 实时计算
> **注意**: Jenkins在构建进行中时返回 `duration: 0`只有构建完成后才返回真实duration。
**解决方案**: 在组件中实时计算:
```typescript
realTimeDuration = Date.now() - new Date(build.timestamp).getTime()
```
使用 `setInterval` 每秒更新 `now` 值,驱动 `realTimeDuration` 计算属性更新。
---
## 相关文件
| 文件 | 作用 |
|------|------|
| `build_tracker.go` | 后端构建状态追踪,超时检测 |
| `jenkins_service.go` | GetBuildDetails异步DB更新 |
| `UserDashboard.vue` | 用户端轮询逻辑 |
| `ProjectsManagement.vue` | 管理端轮询逻辑 |
| `BuildDetails.vue` | 构建详情页,集成状态卡片 |
| `JenkinsBuildStatusCard.vue` | 构建状态展示组件 |

View File

@@ -0,0 +1,433 @@
# DCU 模块设计文档
> Docker镜像打包压缩服务模块负责执行 Download-Compress-Upload (DCU) 工作流。
## 1. 模块概述
DCU模块是一个独立运行的服务专门处理Docker镜像的下载、压缩和上传任务。该模块采用Gin+GORM+SQLite3技术栈通过状态机管理任务流程支持异步执行和定时清理。
### 1.1 核心特性
| 特性 | 说明 |
|------|------|
| 独立部署 | 完全独立运行通过HTTP API接收请求 |
| 状态管理 | 基于状态机的任务状态管理,支持持久化 |
| 异步执行 | DCU流程异步执行不阻塞API响应 |
| 定时清理 | 支持定时清理本地gzip文件和MinIO对象 |
| 错误追踪 | 完整的错误信息记录和查询功能 |
---
## 2. 架构设计
### 2.1 系统架构图
```mermaid
graph TB
subgraph "外部系统"
JB[rmdc-jenkins-branch-dac] -->|HTTP Request| API
DR[Docker Registry]
MIO[(MinIO对象存储)]
end
subgraph "rmdc-dcu 模块"
API[REST API Handler]
subgraph "Service Layer"
DCU[DCU Service]
DS[Docker Service]
CS[Compress Service]
MS[MinIO Service]
SCH[Scheduler]
end
subgraph "Core"
SM[State Machine]
DAO[DCU Task DAO]
end
DB[(SQLite3)]
end
API --> DCU
DCU --> SM
DCU --> DS
DCU --> CS
DCU --> MS
SM --> DAO
DAO --> DB
DS -->|docker pull/save| DR
MS -->|upload/delete| MIO
SCH --> CS
SCH --> MS
```
### 2.2 分层架构
```
┌─────────────────────────────────────────────────────┐
│ Handler Layer │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ StartTask │ │ GetStatus │ │ QueryTasks │ │
│ └─────────────┘ └──────────────┘ └────────────┘ │
├─────────────────────────────────────────────────────┤
│ Service Layer │
│ ┌─────────────┐ ┌──────────────┐ ┌────────────┐ │
│ │ DCUService │ │ DockerSvc │ │ CompressSvc│ │
│ ├─────────────┤ ├──────────────┤ ├────────────┤ │
│ │ MinIOSvc │ │ Scheduler │ │ │ │
│ └─────────────┘ └──────────────┘ └────────────┘ │
├─────────────────────────────────────────────────────┤
│ State Machine Layer │
│ ┌─────────────────────────────────────────────────┐│
│ │ StateMachine (状态转换 + 持久化回调) ││
│ └─────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────┤
│ DAO Layer │
│ ┌─────────────────────────────────────────────────┐│
│ │ DCUTaskDAO (CRUD + 分页查询 + 清理) ││
│ └─────────────────────────────────────────────────┘│
├─────────────────────────────────────────────────────┤
│ Entity Layer │
│ ┌─────────────────────────────────────────────────┐│
│ │ DCUTask (任务实体 + GORM映射) ││
│ └─────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────┘
```
---
## 3. 状态机设计
### 3.1 状态定义
| 状态 | 常量值 | 说明 | 进度 |
|------|--------|------|------|
| 等待中 | `idle` | 任务已创建,等待开始 | 0% |
| 下载中 | `downloading` | 正在执行docker pull | 25% |
| 压缩中 | `compressing` | 正在gzip压缩镜像 | 50% |
| 上传中 | `uploading` | 正在上传到MinIO | 75% |
| 已完成 | `completed` | 任务成功完成 | 100% |
| 失败 | `failed` | 任务执行失败 | -1 |
### 3.2 状态转换图
```mermaid
stateDiagram-v2
[*] --> idle: 创建任务
idle --> downloading: StartTask()
idle --> failed: 初始化失败
downloading --> compressing: Pull成功
downloading --> failed: Pull失败
compressing --> uploading: 压缩成功
compressing --> failed: 压缩失败
uploading --> completed: 上传成功
uploading --> failed: 上传失败
completed --> [*]
failed --> [*]
```
### 3.3 状态持久化
状态机通过回调函数实现状态持久化:
```go
// 状态转换时自动调用
func (s *DCUService) onStateTransition(taskID, fromState, toState, errMsg string) error {
return s.taskDAO.UpdateState(ctx, taskID, toState, errMsg)
}
```
---
## 4. DCU 工作流程
### 4.1 完整流程图
```mermaid
sequenceDiagram
participant Client as 调用方
participant API as REST API
participant DCU as DCU Service
participant SM as State Machine
participant Docker as Docker CLI
participant Compress as Compress Service
participant MinIO as MinIO Service
participant DB as SQLite
Client->>API: POST /api/dcu/start
API->>DCU: StartTask(username, imageName)
DCU->>DB: Create task record
DCU->>SM: RegisterTask(taskID)
DCU-->>API: Return taskID
API-->>Client: Response {task_id, state: "idle"}
Note over DCU: 异步执行DCU流程
DCU->>SM: Transition(downloading)
SM->>DB: Update state
DCU->>Docker: docker pull image
Docker-->>DCU: Pull完成
DCU->>Docker: docker save -o image.tar
Docker-->>DCU: Save完成
DCU->>SM: Transition(compressing)
SM->>DB: Update state
DCU->>Compress: CompressFile(tar → gzip)
Compress-->>DCU: 压缩完成
DCU->>DB: Update gzip_file_name
DCU->>SM: Transition(uploading)
SM->>DB: Update state
DCU->>MinIO: Upload(objectName, gzipPath)
MinIO-->>DCU: 上传完成
DCU->>DB: Update minio_object_name
DCU->>SM: Transition(completed)
SM->>DB: Update state + end_time
Client->>API: GET /api/dcu/status/{task_id}
API->>DCU: GetTaskStatus(taskID)
DCU->>DB: Query task
DB-->>DCU: Task entity
DCU-->>API: TaskStatusResponse
API-->>Client: Response with progress
```
### 4.2 错误处理流程
```mermaid
flowchart TD
A[开始DCU] --> B{Docker Pull}
B -->|成功| C{Docker Save}
B -->|失败| F[记录错误信息]
C -->|成功| D{Gzip压缩}
C -->|失败| F
D -->|成功| E{MinIO上传}
D -->|失败| F
E -->|成功| G[状态: completed]
E -->|失败| F
F --> H[状态: failed]
G --> I[结束]
H --> I
```
---
## 5. API 接口说明
### 5.1 启动DCU任务
```
POST /api/dcu/start
```
**请求体:**
```json
{
"username": "test_user",
"docker_image_name": "nginx:latest"
}
```
**响应:**
```json
{
"code": 0,
"status": 200,
"message": "任务已启动",
"data": {
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"state": "idle"
}
}
```
---
### 5.2 查询任务状态
```
GET /api/dcu/status/{task_id}
```
**响应:**
```json
{
"code": 0,
"status": 200,
"message": "success",
"data": {
"task_id": "550e8400-e29b-41d4-a716-446655440000",
"state": "compressing",
"state_display": "压缩镜像中",
"docker_image_name": "nginx:latest",
"gzip_file_name": "./data/gzip/nginx_latest.tar.gz",
"progress": 50,
"duration": 12345,
"username": "test_user",
"start_time": "2025-12-10 20:25:00"
}
}
```
---
### 5.3 查询任务列表
```
GET /api/dcu/query?docker_image_name=nginx&page=1&page_size=10
```
**查询参数:**
| 参数 | 类型 | 说明 |
|------|------|------|
| docker_image_name | string | 镜像名称(模糊匹配) |
| username | string | 用户名 |
| state | string | 状态筛选 |
| page | int | 页码 |
| page_size | int | 每页数量 |
**响应:**
```json
{
"code": 0,
"status": 200,
"message": "success",
"data": {
"total": 42,
"items": [...]
}
}
```
---
### 5.4 健康检查
```
GET /api/dcu/health
```
---
## 6. 数据库设计
### 6.1 DCU任务表 (dcu_tasks)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER | 主键,自增 |
| task_id | VARCHAR(100) | 任务UUID唯一索引 |
| username | VARCHAR(100) | 用户名,索引 |
| docker_image_name | VARCHAR(500) | Docker镜像名索引 |
| gzip_file_name | VARCHAR(500) | Gzip文件路径 |
| minio_object_name | VARCHAR(500) | MinIO对象名 |
| state | VARCHAR(50) | 状态,索引 |
| error_message | VARCHAR(2000) | 错误信息 |
| start_time | DATETIME | 开始时间,索引 |
| end_time | DATETIME | 结束时间 |
| duration | INTEGER | 持续时间(毫秒) |
| created_at | DATETIME | 创建时间 |
| updated_at | DATETIME | 更新时间 |
---
## 7. 定时任务
| 任务 | 默认Cron | 说明 |
|------|----------|------|
| Gzip清理 | `0 0 * * *` | 每天凌晨清理过期gzip文件 |
| MinIO清理 | `0 0 * * 0` | 每周日凌晨清理过期MinIO对象 |
---
## 8. 配置说明
配置文件位置:`configs/config.yaml`
```yaml
server:
host: 0.0.0.0
port: 8090
mode: debug
database:
path: ./data/dcu.db
storage:
gzip_path: ./data/gzip
cleanup_gzip_cron: "0 0 * * *"
cleanup_minio_cron: "0 0 * * 0"
gzip_retention_days: 1
minio_retention_days: 7
minio:
endpoint: 192.168.40.50:9000
access_key: your_access_key
secret_key: your_secret_key
bucket: dcu-artifacts
use_ssl: false
```
---
## 9. 目录结构
```
rmdc-dcu/
├── cmd/
│ └── main.go # 应用入口
├── configs/
│ └── config.yaml # 配置文件
├── internal/
│ ├── config/
│ │ └── config.go # 配置结构
│ ├── dao/
│ │ ├── database.go # 数据库初始化
│ │ └── dcu_task_dao.go # 任务DAO
│ ├── handler/
│ │ ├── dcu_handler.go # API处理器
│ │ └── router.go # 路由注册
│ ├── model/
│ │ ├── dto/
│ │ │ └── dcu_dto.go # 请求/响应DTO
│ │ └── entity/
│ │ └── dcu_task.go # 任务实体
│ ├── service/
│ │ ├── compress_service.go # 压缩服务
│ │ ├── dcu_service.go # DCU编排服务
│ │ ├── docker_service.go # Docker服务
│ │ ├── minio_service.go # MinIO服务
│ │ └── scheduler.go # 定时调度器
│ └── statemachine/
│ ├── machine.go # 状态机实现
│ └── state.go # 状态定义
├── go.mod
└── go.sum
```
---
## 10. 运行要求
- **Go**: 1.24+
- **Docker**: 已安装并配置Docker CLI
- **MinIO**: 可访问的MinIO服务器
- **SQLite3**: 自动创建通过GORM
---
## 11. 启动命令
```bash
cd rmdc-dcu
go run ./cmd/main.go
```
服务将在 `http://0.0.0.0:8090` 启动。

View File

@@ -0,0 +1,837 @@
# JenBranchRBAC 系统详细设计说明书
**Jenkins 分支级权限管理系统架构设计文档**
***
## 1. 系统架构设计
### 1.1 总体架构
JenBranchRBAC 采用前后端分离的三层架构设计,通过 RESTful API 与 WebSocket 实现前后端通信,后端通过 Jenkins REST API 实现与 Jenkins 系统的集成。
```mermaid
graph TB
subgraph "展现层 Presentation Layer"
A[Vue3 + TypeScript]
B[Vuetify 3 UI]
C[Pinia State Management]
end
subgraph "网络通信层 Network Layer"
D[RESTful API]
E[WebSocket]
F[Nginx Reverse Proxy]
end
subgraph "业务逻辑层 Business Layer"
G[Gin Web Framework]
H[JWT Authentication]
I[RBAC Middleware]
J[Jenkins API Client]
K[Cron Job Scheduler]
end
subgraph "数据持久层 Data Layer"
L[GORM ORM]
M[SQLite3 WAL Mode]
N[Backup Service]
end
subgraph "外部系统 External Systems"
O[Jenkins Server]
P[SMTP Server]
Q[Webhook Endpoints]
end
A --> D
A --> E
B --> A
C --> A
D --> F
E --> F
F --> G
G --> H
G --> I
G --> J
G --> K
G --> L
L --> M
M --> N
J --> O
G --> P
G --> Q
```
### 1.2 系统分层职责
| 层次 | 组件 | 职责边界 |
|------|------|----------|
| 展现层 | Vue3 + Vuetify | 用户界面渲染、表单验证、状态管理、路由控制 |
| 网络层 | Nginx + API Gateway | 静态资源托管、请求路由、负载均衡、SSL终止 |
| 业务层 | Gin + 业务逻辑模块 | 认证授权、权限校验、业务流程编排、Jenkins API封装 |
| 数据层 | GORM + SQLite | 数据持久化、事务管理、查询优化、备份恢复 |
***
## 2. 核心模块设计
### 2.1 认证授权模块
#### 2.1.1 认证流程设计
```mermaid
sequenceDiagram
participant U as 用户浏览器
participant F as Vue Frontend
participant N as Nginx
participant B as Gin Backend
participant D as Database
participant J as Jenkins API
U->>F: 输入用户名/密码
F->>F: RSA公钥加密密码
F->>N: POST /api/auth/login
N->>B: 转发请求
B->>B: RSA私钥解密密码
B->>D: 查询用户记录
D-->>B: 返回用户信息
B->>B: bcrypt验证密码
B->>B: 检查账户状态
alt 验证成功
B->>B: 生成JWT Token
B->>D: 记录登录日志
B-->>F: 返回Token + 用户信息
F->>F: 存储Token到LocalStorage
F-->>U: 跳转到项目列表页
else 验证失败
B->>D: 累计失败次数
alt 失败次数>=5
B->>D: 锁定账户30分钟
end
B-->>F: 返回错误信息
F-->>U: 显示错误提示
end
```
#### 2.1.2 权限校验中间件设计
**RBAC 中间件实现逻辑**:
```mermaid
flowchart TD
A[HTTP请求到达] --> B{提取JWT Token}
B -->|Token不存在| C[返回401 Unauthorized]
B -->|Token存在| D[验证Token签名]
D -->|签名无效| C
D -->|签名有效| E{检查Token过期时间}
E -->|已过期| F{在刷新窗口内?}
F -->|是| G[生成新Token并返回]
F -->|否| C
E -->|未过期| H[解析用户ID和角色]
H --> I{检查接口权限}
I -->|超级管理员| J[放行请求]
I -->|项目管理员| K{验证项目权限}
K -->|有权限| J
K -->|无权限| L[返回403 Forbidden]
I -->|普通用户| M{验证分支权限}
M -->|有权限| J
M -->|无权限| L
J --> N[继续处理业务逻辑]
```
***
### 2.2 Jenkins 数据同步模块
#### 2.2.1 定时同步机制
```mermaid
sequenceDiagram
participant C as Cron Scheduler
participant S as Sync Service
participant J as Jenkins API
participant Cache as Local Cache
participant DB as Database
participant WS as WebSocket Server
C->>S: 触发定时任务(每5分钟)
S->>J: GET /api/json?tree=jobs[name,url]
J-->>S: 返回项目列表
loop 遍历多分支项目
S->>J: GET /job/{name}/api/json
J-->>S: 返回分支列表
end
S->>S: 差异检测(对比Cache)
S->>DB: 更新项目/分支元数据
S->>Cache: 更新本地缓存
alt 发现新增/删除
S->>WS: 推送通知给在线管理员
end
S->>DB: 记录同步日志
```
#### 2.2.2 手动同步机制
管理员触发立即同步时,后端启动异步 Goroutine 执行同步任务,前端通过 WebSocket 订阅同步进度:
```mermaid
stateDiagram-v2
[*] --> Idle: 系统空闲
Idle --> Syncing: 点击"立即同步"
Syncing --> FetchingProjects: 获取项目列表
FetchingProjects --> FetchingBranches: 项目获取完成
FetchingBranches --> DiffDetecting: 分支获取完成
DiffDetecting --> Updating: 差异检测完成
Updating --> Success: 更新完成
Updating --> Failed: 更新失败
Success --> Idle: 返回空闲
Failed --> Idle: 返回空闲
note right of Syncing
WebSocket推送: progress=0%
end note
note right of FetchingBranches
WebSocket推送: progress=50%
end note
note right of Success
WebSocket推送: progress=100%
end note
```
***
### 2.3 权限管理模块
#### 2.3.1 权限分配流程
```mermaid
sequenceDiagram
participant A as 管理员
participant F as 前端界面
participant B as 后端API
participant D as 数据库
participant C as 缓存层
A->>F: 选择用户
F->>B: GET /api/users/{id}/permissions
B->>D: 查询现有权限
D-->>B: 返回权限列表
B-->>F: 返回权限数据
F->>F: 渲染左右穿梭框
A->>F: 选择项目/分支并提交
F->>B: POST /api/permissions/assign
B->>B: 验证管理员权限范围
B->>D: 批量插入/更新权限记录
B->>D: 记录审计日志
B->>C: 清除用户权限缓存
B-->>F: 返回操作结果
F-->>A: 显示成功提示
```
#### 2.3.2 权限模板应用
权限模板设计用于快速批量授权相同角色的用户:
```mermaid
flowchart LR
A[创建权限模板] --> B[选择项目-分支组合]
B --> C[保存为JSON格式]
C --> D[存储到permission_templates表]
D --> E[应用模板到用户]
E --> F[解析JSON权限定义]
F --> G[批量插入permissions表]
G --> H[记录审计日志]
```
***
### 2.4 构建管理模块
#### 2.4.1 构建触发流程
```mermaid
sequenceDiagram
participant U as 用户
participant F as 前端
participant B as 后端
participant D as 数据库
participant J as Jenkins
U->>F: 点击"构建"按钮
F->>B: POST /api/build/trigger
B->>D: 查询用户权限
D-->>B: 返回权限信息
B->>B: 二次校验构建权限
alt 有构建权限
B->>J: 获取Jenkins Crumb
J-->>B: 返回Crumb Token
B->>J: POST /job/{job}/job/{branch}/build
J-->>B: 返回Queue ID
B->>D: 记录构建审计日志
B-->>F: 返回Queue ID
F->>F: 建立WebSocket连接
F->>B: 订阅构建日志
else 无权限
B-->>F: 返回403错误
F-->>U: 显示权限不足提示
end
```
#### 2.4.2 实时日志推送
```mermaid
sequenceDiagram
participant F as 前端WebSocket客户端
participant W as 后端WebSocket服务
participant J as Jenkins API
participant L as 日志缓冲区
F->>W: 连接WS /ws/build-log/{buildId}
W->>W: 验证JWT Token
W->>J: GET logText/progressiveText?start=0
J-->>W: 返回日志片段 + nextOffset
W->>L: 写入缓冲区
W->>F: 推送日志数据(JSON格式)
loop 每2秒轮询
W->>J: GET logText/progressiveText?start={nextOffset}
J-->>W: 返回增量日志
W->>F: 推送增量数据
end
alt 构建完成
W->>F: 推送完成标识
W->>W: 关闭连接
end
```
***
## 3. 数据库设计
### 3.1 E-R 关系图
```mermaid
erDiagram
USERS ||--o{ PERMISSIONS : has
USERS ||--o{ AUDIT_LOGS : generates
USERS ||--o{ PERMISSION_TEMPLATES : creates
USERS ||--o{ PERMISSIONS_GRANTED : grants
USERS {
int id PK
string username UK
string password_hash
string role
string status
datetime password_expires_at
int failed_login_attempts
datetime locked_until
string mfa_secret
datetime created_at
datetime updated_at
datetime last_login_at
}
PERMISSIONS {
int id PK
int user_id FK
string project_name
string branch_name
bool can_view
bool can_build
int granted_by FK
datetime granted_at
}
AUDIT_LOGS {
int id PK
int user_id FK
string action
string resource_type
string resource_id
text details
string ip_address
text user_agent
datetime created_at
}
PERMISSION_TEMPLATES {
int id PK
string name UK
text description
text permissions_json
int created_by FK
datetime created_at
}
```
### 3.2 索引优化策略
| 表名 | 索引字段 | 索引类型 | 优化目标 |
|------|----------|----------|----------|
| users | username | UNIQUE | 登录查询加速 |
| permissions | (user_id, project_name, branch_name) | UNIQUE | 防止重复授权 |
| permissions | user_id | BTREE | 用户权限列表查询 |
| audit_logs | (user_id, created_at) | COMPOSITE | 用户操作历史查询 |
| audit_logs | action | BTREE | 操作类型统计分析 |
| audit_logs | created_at | BTREE | 日志归档清理 |
***
## 4. 接口设计规范
### 4.1 RESTful API 设计
#### 4.1.1 认证授权接口
| 接口路径 | 方法 | 功能 | 请求体 | 响应体 |
|---------|------|------|--------|--------|
| /api/auth/login | POST | 用户登录 | `{username, encrypted_password}` | `{token, refresh_token, user_info}` |
| /api/auth/logout | POST | 用户登出 | - | `{message}` |
| /api/auth/refresh | POST | 刷新Token | `{refresh_token}` | `{token}` |
| /api/auth/reset-password | POST | 重置密码 | `{user_id, new_password}` | `{message}` |
#### 4.1.2 用户管理接口
| 接口路径 | 方法 | 功能 | 权限要求 | 请求参数 |
|---------|------|------|----------|----------|
| /api/users | GET | 用户列表 | 管理员 | `page, size, role, status` |
| /api/users | POST | 创建用户 | 管理员 | `{username, password, role}` |
| /api/users/{id} | GET | 用户详情 | 管理员 | - |
| /api/users/{id} | PUT | 更新用户 | 管理员 | `{role, status}` |
| /api/users/{id} | DELETE | 删除用户 | 超级管理员 | - |
| /api/users/batch | POST | 批量导入 | 管理员 | `CSV文件` |
| /api/users/export | GET | 导出用户 | 管理员 | `format=csv/excel` |
#### 4.1.3 权限管理接口
| 接口路径 | 方法 | 功能 | 请求体 |
|---------|------|------|--------|
| /api/permissions/assign | POST | 分配权限 | `{user_id, permissions:[{project, branch, can_view, can_build}]}` |
| /api/permissions/{user_id} | GET | 查询用户权限 | - |
| /api/permissions/templates | GET | 权限模板列表 | - |
| /api/permissions/templates | POST | 创建权限模板 | `{name, description, permissions_json}` |
#### 4.1.4 Jenkins 同步接口
| 接口路径 | 方法 | 功能 | 响应体 |
|---------|------|------|--------|
| /api/jenkins/sync | POST | 手动同步 | `{task_id, status}` |
| /api/jenkins/projects | GET | 项目列表 | `{projects:[{name, branches:[]}]}` |
| /api/jenkins/sync/status | GET | 同步状态 | `{status, progress, message}` |
#### 4.1.5 构建管理接口
| 接口路径 | 方法 | 功能 | 请求体 |
|---------|------|------|--------|
| /api/build/trigger | POST | 触发构建 | `{project, branch, parameters}` |
| /api/build/{build_id}/log | GET | 获取构建日志 | - |
| /api/build/{build_id}/artifacts | GET | 获取构建产物 | - |
| /api/build/history | GET | 历史构建记录 | `project, branch, page, size` |
***
### 4.2 WebSocket 接口设计
| 连接路径 | 事件类型 | 数据格式 | 用途 |
|---------|---------|---------|------|
| /ws/build-log/{build_id} | log_chunk | `{offset, content, is_complete}` | 实时日志推送 |
| /ws/sync-progress | sync_status | `{progress, current_project, message}` | 同步进度通知 |
| /ws/notifications | notification | `{type, title, message, timestamp}` | 系统通知推送 |
***
## 5. 安全设计方案
### 5.1 密码安全策略
```mermaid
flowchart TD
A[用户创建密码] --> B{密码强度校验}
B -->|不符合| C[返回错误提示]
B -->|符合| D[bcrypt哈希 cost=12]
D --> E[存储密码哈希]
E --> F[设置过期时间180天]
F --> G[定时检查过期状态]
G -->|距过期7天| H[发送邮件提醒]
G -->|已过期| I[强制修改密码]
```
**密码策略配置**:
- 最小长度: 8 位
- 必须包含: 大写字母、小写字母、数字、特殊字符
- 历史密码限制: 不能与最近 3 次密码相同
- 加密算法: bcrypt (cost factor = 12)
- 有效期: 180 天
### 5.2 防暴力破解机制
```mermaid
stateDiagram-v2
[*] --> Normal: 正常状态
Normal --> Failed1: 登录失败1次
Failed1 --> Failed2: 登录失败2次
Failed2 --> Failed3: 登录失败3次
Failed3 --> Failed4: 登录失败4次
Failed4 --> Locked: 登录失败5次
Locked --> Normal: 30分钟后自动解锁
Failed1 --> Normal: 登录成功
Failed2 --> Normal: 登录成功
Failed3 --> Normal: 登录成功
Failed4 --> Normal: 登录成功
note right of Locked
账户锁定30分钟
记录审计日志
发送告警邮件
end note
```
### 5.3 API 安全防护
| 安全措施 | 实现方案 | 防护对象 |
|---------|---------|---------|
| SQL 注入防护 | GORM 参数化查询 | 所有数据库操作 |
| XSS 防护 | Vue 自动转义 + Gin SecureJSON | 前后端输出 |
| CSRF 防护 | Jenkins Crumb Token | Jenkins API 调用 |
| 请求限流 | Gin 限流中间件 | 所有 API 端点 |
| 数据加密传输 | RSA 加密密码 + HTTPS | 敏感数据传输 |
| JWT Token 安全 | 8 小时过期 + 刷新机制 | 用户会话管理 |
***
## 6. 性能优化方案
### 6.1 后端性能优化
```mermaid
flowchart LR
A[性能优化策略] --> B[并发优化]
A --> C[缓存优化]
A --> D[数据库优化]
A --> E[网络优化]
B --> B1[Goroutine处理异步任务]
B --> B2[连接池复用]
B --> B3[请求限流防止雪崩]
C --> C1[本地缓存Jenkins数据]
C --> C2[用户权限缓存]
C --> C3[Redis缓存热点数据可选]
D --> D1[SQLite WAL模式]
D --> D2[复合索引优化]
D --> D3[定期清理审计日志]
E --> E1[HTTP/2启用]
E --> E2[Jenkins API tree参数]
E --> E3[WebSocket长连接复用]
```
### 6.2 前端性能优化
| 优化项 | 实现方案 | 性能收益 |
|--------|---------|---------|
| 路由懒加载 | Vue Router 动态 import | 减少首屏加载时间 |
| 组件按需加载 | Vuetify Treeshaking | 减小打包体积 30% |
| 虚拟滚动 | DataGrid 虚拟列表 | 大数据量渲染优化 |
| 请求防抖 | Lodash debounce 搜索 | 减少 API 调用次数 |
| 日志分页加载 | 滚动加载历史日志 | 避免内存溢出 |
***
## 7. 部署架构设计
### 7.1 单机部署方案
```mermaid
graph TB
subgraph "Docker Container"
A[Nginx:alpine] -->|静态资源| B[Vue3 Dist]
A -->|反向代理 :8080| C[Gin Backend]
C --> D[SQLite3 WAL DB]
C --> E[(/data Volume Mount)]
D --> E
end
F[External Client] -->|HTTPS :443| A
C -->|Jenkins API| G[Jenkins Server]
C -->|SMTP :587| H[Mail Server]
```
**Dockerfile 示例**:
```dockerfile
# Stage 1: 前端构建
FROM node:20-alpine AS frontend-builder
WORKDIR /app/frontend
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# Stage 2: 后端构建
FROM golang:1.24-alpine AS backend-builder
WORKDIR /app/backend
COPY backend/go.* ./
RUN go mod download
COPY backend/ ./
RUN CGO_ENABLED=1 GOOS=linux go build -a -installsuffix cgo -o jenbranchrbac .
# Stage 3: 运行时镜像
FROM alpine:latest
RUN apk --no-cache add ca-certificates nginx
WORKDIR /app
COPY --from=backend-builder /app/backend/jenbranchrbac .
COPY --from=frontend-builder /app/frontend/dist /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80 8080
CMD nginx && ./jenbranchrbac
```
### 7.2 高可用部署方案
```mermaid
graph TB
subgraph "负载均衡层"
A[Nginx/HAProxy]
end
subgraph "应用层"
B1[JenBranchRBAC Instance 1]
B2[JenBranchRBAC Instance 2]
B3[JenBranchRBAC Instance N]
end
subgraph "数据层"
C[PostgreSQL Primary]
D[PostgreSQL Standby]
E[Redis Cluster]
end
A -->|Round Robin| B1
A --> B2
A --> B3
B1 --> C
B2 --> C
B3 --> C
C -->|主从复制| D
B1 --> E
B2 --> E
B3 --> E
```
**扩展建议**:
- 当并发用户超过 500 人时,建议从 SQLite 迁移到 PostgreSQL
- 引入 Redis 作为分布式缓存层,存储用户会话和权限信息
- 使用 Kubernetes 部署多实例,实现水平扩展
***
## 8. 监控与运维设计
### 8.1 日志分级策略
| 日志级别 | 记录场景 | 示例 |
|---------|---------|------|
| DEBUG | 详细调试信息 | Jenkins API 请求参数、SQL 查询语句 |
| INFO | 正常业务流程 | 用户登录成功、构建触发成功 |
| WARN | 潜在问题告警 | API 调用超时重试、缓存未命中 |
| ERROR | 错误但可恢复 | Jenkins 连接失败、数据库锁超时 |
| FATAL | 系统致命错误 | 数据库文件损坏、配置文件缺失 |
### 8.2 监控指标设计
```mermaid
graph LR
A[监控指标体系] --> B[系统指标]
A --> C[业务指标]
A --> D[安全指标]
B --> B1[CPU使用率]
B --> B2[内存占用]
B --> B3[磁盘IO]
B --> B4[Goroutine数量]
C --> C1[API响应时间]
C --> C2[Jenkins同步耗时]
C --> C3[构建触发成功率]
C --> C4[WebSocket连接数]
D --> D1[登录失败次数]
D --> D2[异常IP访问]
D --> D3[权限拒绝次数]
D --> D4[Token刷新频率]
```
**Prometheus 集成方案**:
- 使用 `gin-prometheus` 中间件暴露 `/metrics` 端点
- 监控指标包括:HTTP 请求计数、延迟分布、数据库连接池状态、Goroutine 泄漏检测
***
## 9. 备选技术方案
### 9.1 数据库迁移路径
| 数据库类型 | 适用场景 | 迁移工具 |
|-----------|---------|---------|
| SQLite3 | 单机部署 < 500 用户 | 内置方案 |
| PostgreSQL | 生产环境 > 500 用户 | GORM AutoMigrate |
| MySQL 8.0 | 已有 MySQL 基础设施 | GORM AutoMigrate |
**迁移步骤**:
1. 使用 GORM `AutoMigrate` 在目标数据库创建表结构
2. 通过 SQL 脚本导出 SQLite 数据并转换为目标数据库格式
3. 修改配置文件中的 `database.type` 参数
4. 重启服务并验证数据一致性
### 9.2 认证方案扩展
```mermaid
flowchart TD
A[认证方式扩展] --> B[本地认证]
A --> C[LDAP/AD集成]
A --> D[OAuth2.0]
A --> E[SAML SSO]
B --> B1[当前实现方案]
C --> C1[企业内部用户统一认证]
D --> D1[GitHub/GitLab账户登录]
E --> E1[企业级SSO集成]
```
**实现优先级**:
1. **Phase 1**: 本地认证 + MFA (已设计)
2. **Phase 2**: LDAP 集成 (企业高需求)
3. **Phase 3**: OAuth2.0 (开源社区版)
***
## 10. 技术风险与缓解措施
| 风险项 | 影响等级 | 缓解措施 |
|--------|---------|---------|
| Jenkins API 结构变更 | 中 | 使用松散类型解析 + 版本兼容性测试 |
| SQLite 并发写入冲突 | 中 | WAL 模式 + 写操作重试机制 + 升级 PostgreSQL |
| Go 类型系统学习曲线 | 低 | 代码规范文档 + Code Review |
| TypeScript 类型定义复杂 | 低 | 提供 `*.d.ts` 类型文件 + ESLint 规则 |
| WebSocket 连接稳定性 | 中 | 心跳检测 + 自动重连机制 |
| 密钥文件泄露 | 高 | 密钥文件权限控制 (chmod 600) + 密钥轮换机制 |
***
## 11. 实施时间表
```mermaid
gantt
title JenBranchRBAC 实施路线图
dateFormat YYYY-MM-DD
section Phase 1 - MVP
Go项目脚手架与GORM模型 :a1, 2025-11-22, 7d
JWT认证与RBAC中间件 :a2, after a1, 7d
Jenkins API封装与同步 :a3, after a2, 7d
Vue3前端框架与登录页 :a4, after a1, 14d
section Phase 2 - 增强功能
WebSocket实时日志推送 :b1, after a3, 7d
前端日志组件与ANSI渲染 :b2, after a4, 7d
构建产物解析与下载 :b3, after b1, 7d
审计日志中间件完善 :b4, after b1, 7d
section Phase 3 - 企业特性
TOTP MFA认证集成 :c1, after b3, 7d
Webhook通知模块 :c2, after b4, 7d
压力测试与性能优化 :c3, after c2, 7d
Docker镜像与CI/CD流水线 :c4, after c3, 7d
```
***
## 12. 附录
### 12.1 关键技术栈版本
| 组件 | 版本 | 说明 |
|------|------|------|
| Go | 1.24+ | 后端开发语言 |
| Gin | v1.10+ | Web 框架 |
| GORM | v2.0+ | ORM 框架 |
| Vue | 3.4+ | 前端框架 |
| TypeScript | 5.0+ | 类型系统 |
| Vuetify | 3.5+ | UI 组件库 |
| SQLite | 3.45+ | 嵌入式数据库 |
| Nginx | 1.26+ | 反向代理服务器 |
### 12.2 配置文件示例
**c.yaml**:
```yaml
server:
host: 0.0.0.0
port: 8080
mode: release # debug/release
database:
type: sqlite3
path: ./data/jenbranchrbac.db
max_idle_conns: 10
max_open_conns: 100
conn_max_lifetime: 3600
security:
jwt_secret: CHANGE_THIS_SECRET_IN_PRODUCTION
jwt_expiry: 8h
rsa_private_key: ./keys/private.pem
rsa_public_key: ./keys/public.pem
bcrypt_cost: 12
jenkins:
url: https://jenkins.example.com
username: api_user
token: YOUR_JENKINS_API_TOKEN
sync_interval: 300 # seconds
timeout: 30
logging:
level: info # debug/info/warn/error
format: json
output: ./logs/app.log
max_size: 100 # MB
max_backups: 10
max_age: 30 # days
```
### 12.3 参考文档
- Jenkins REST API 官方文档: https://www.jenkins.io/doc/book/using/remote-access-api/
- Gin Web Framework 文档: https://gin-gonic.com/docs/
- GORM ORM 文档: https://gorm.io/docs/
- Vue 3 官方文档: https://vuejs.org/guide/
- Vuetify 3 组件库: https://vuetifyjs.com/en/components/all/
- JWT 认证最佳实践: https://datatracker.ietf.org/doc/html/rfc7519
***
**文档版本**: v1.0
**编制日期**: 2025-11-21
**编制人**: 系统架构师
**审核状态**: 待评审

View File

@@ -0,0 +1,165 @@
# Jenkins模块开发提示词
> 本文档为大模型提供rmdc-jenkins-branch-dac模块的开发上下文。
---
## 模块概述
**rmdc-jenkins-branch-dac** 是RMDC平台的Jenkins分支级权限控制与构建管理模块。
### 核心能力
1. **分支级权限控制(DAC)**: Organization → Repository → Branch 三级权限管理
2. **Jenkins API封装**: 组织/仓库/分支/构建的CRUD操作
3. **构建状态追踪**: 实时追踪构建进度,超时检测
4. **DCU流程**: Docker镜像的下载、压缩、上传到MinIO
---
## 项目结构
```
rmdc-jenkins-branch-dac/
├── internal/
│ ├── config/ # 配置
│ ├── dao/ # 数据访问
│ ├── handler/ # HTTP处理器
│ ├── model/
│ │ ├── dto/ # 请求/响应
│ │ └── entity/ # 数据库实体
│ └── service/ # 业务逻辑
└── pkg/
└── jenkins/
└── client.go # Jenkins HTTP Client
```
---
## API设计规范
> **重要**: 使用POST + RequestBody避免PathVariables
### 请求示例
```go
// ✅ 正确方式
type GetBuildRequest struct {
OrganizationFolder string `json:"organization_folder"`
RepositoryName string `json:"repository_name"`
BranchName string `json:"branch_name"`
BuildNumber int `json:"build_number"`
}
// ❌ 避免使用
// GET /api/jenkins/organizations/{org}/repositories/{repo}/branches/{branch}/builds/{number}
```
### 接口清单
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/jenkins/organizations/list` | POST | 获取组织列表 |
| `/api/jenkins/repositories/list` | POST | 获取仓库列表 |
| `/api/jenkins/branches/list` | POST | 获取分支列表 |
| `/api/jenkins/builds/list` | POST | 获取构建列表 |
| `/api/jenkins/builds/trigger` | POST | 触发构建 |
| `/api/jenkins/builds/detail` | POST | 获取构建详情 |
| `/api/dcu/start` | POST | 启动DCU任务 |
| `/api/dcu/status` | POST | 查询DCU状态 |
---
## 核心数据结构
```go
// Organization Jenkins组织
type Organization struct {
ID int64 `gorm:"primaryKey"`
Name string `gorm:"uniqueIndex"`
DisplayName string
URL string
LastSyncAt time.Time
}
// Repository Jenkins仓库
type Repository struct {
ID int64 `gorm:"primaryKey"`
OrganizationID int64 `gorm:"index"`
Name string
URL string
}
// Branch Jenkins分支
type Branch struct {
ID int64 `gorm:"primaryKey"`
RepositoryID int64 `gorm:"index"`
Name string
LastBuildNumber int
LastBuildResult string
}
// Build Jenkins构建
type Build struct {
ID int64 `gorm:"primaryKey"`
BranchID int64 `gorm:"index"`
BuildNumber int
Result string
Timestamp int64
Duration int64
EstimatedDuration int64
IsBuilding bool
ArtifactDockerImage string
}
```
---
## Jenkins API调用
### URL路径规则
```
{JENKINS_URL}/job/{ORG}/api/json # 获取组织信息
{JENKINS_URL}/job/{ORG}/job/{REPO}/api/json # 获取仓库信息
{JENKINS_URL}/job/{ORG}/job/{REPO}/job/{BRANCH}/api/json # 获取分支信息
{JENKINS_URL}/job/{ORG}/job/{REPO}/job/{BRANCH}/build # 触发构建
```
### 分支名编码
- `/``%2F` (例: `feature/login``feature%2Flogin`)
---
## 权限校验
权限通过中间件校验Handler无需处理
```go
func (h *BuildHandler) TriggerBuild(c *gin.Context) {
// 此时已通过权限校验
var req dto.TriggerBuildRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, err)
return
}
resp, err := h.buildService.TriggerBuild(c.Request.Context(), &req)
if err != nil {
response.Error(c, err)
return
}
response.Success(c, resp)
}
```
---
## 相关文档
| 文档 | 内容 |
|------|------|
| [1-jenkins-branch-dac-DDS.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/1-jenkins-branch-dac-DDS.md) | 完整详细设计 |
| [5-RMDC项目权限设计方案.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/5-RMDC项目权限设计方案.md) | 权限设计 |
| [9-rmdc-dcu模块设计方案.md](file:///c:/Users/wddsh/Documents/IdeaProjects/ProjectAGiPrompt/8-CMII-RMDC/2-Jenkins模块/9-rmdc-dcu模块设计方案.md) | DCU模块设计 |

View File

@@ -0,0 +1,230 @@
# RMDC-exchange-hub Detailed Design Specification
### 项目划分说明
1. RMDC-exchange-hub(MQTTX) 是Server端
2. RMDC-watchdog是Client
1. RMDC-watchdog RMDC-watchdog-agent RMDC-watchdog-node三者运行在外部环境,作为单个项目
2. 下文简称RMDC-watchdog代表的是一个项目单个项目与 RMDC-exchange-hubMQTTX不在同一个网络中需要跨越公网交互
3. 考虑到兼容性假设所有的项目均只能单方面跨公网访问RMDC-exchange-hubMQTTX
4. 有部分项目无法访问RMDC-exchange-hubMQTTX,是纯内网的环境
3. MQTTX是消息中间件
1. 借用现有的消息中间件,处理单向网络环境下的指令 信息处理问题
2. 解决队列消息持久化问题
3. 整体信息流程为 RMDC-exchange-hub <-- MQTTX <-- RMDC-watchdog
4. MQTTX <-- RMDC-watchdog是弱网络环境保证信息传递的准确性
5. RMDC-exchange-hub <-- MQTTX是网络质量很好
## 指令数据处理流程
### 指令数据流向说明
1. RMDC-watchdog向RMDC-exchange-hubMQTTX发送信息成为 上行
2. RMDC-exchange-hubMQTTX向RMDC-watchdog发送信息成为 下行
### 指令数据消息说明
1. RMDC-watchdog需要接收上传多种不同模块的信息并作出相应的解析
1. 接收下行的command指令
1. 授权信息
2. 日志指令
3. 主机执行
4. k8s执行指令
5. 业务更新指令
2. 发送上行的消息message类别
1. 监控信息
2. 日志内容
3. 主机执行结果
4. k8s执行结果
5. 业务更新结果
2. mqtt是明文传输的敏感信息需要进行加密处理
3. RMDC-exchange-hub 维护项目在线状态超时未心跳自动标记离线并告警
### 项目启动注册流程
#### 项目信息注册流程
1. 需要从 rmdc-project-management 创建项目的信息
1. 项目的名称
2. 项目的命名空间
3. 项目ID Project_ID
1. 生成规则为 命名空间_<8位小写字符数字随机数>
4. 项目的一级授权密钥 tier_one_secret
5. 项目的一级授权密钥时间偏移值 time_offset_allowed 单位秒
6. 项目的授权有效期 authorization_duration 单位天
7. 项目的授权类型 authorization_type 永久授权或者时效授权
8. 项目的二级授权密钥 tier_two_secret
#### 正常的rmdc-watchdog启动流程
1. 需要根据 rmdc-project-management 创建的信息启动程序
1. 见上文
2. 项目ID使用项目信息中的不在rmdc-watchdog中生成
2. 采用“挑战-应答”机制,确保边缘节点合法性 正常的流程如下
1. 尝试连接MQTTX创建如下的Topic
1. 发送Topic
1. wdd/RDMC/command/up
2. wdd/RDMC/message/up
2. 接收Topic
1. wdd/RDMC/command/down/<project_id>
2. wdd/RDMC/message/down/<project_id>
2. 发送上行注册command信息, 到wdd/RDMC/command/up包含项目的所有信息
1. 信息需要加密
3. RMDC-exchange-hubMQTTX解析注册command
1. 需要调用 rmdc-project-management 的接口
1. 验证项目信息的合法性
2. 验证项目的一级TOTP密码是否正确 (开关功能,可以不强制)
2. 发送下行 注册成功message到 wdd/RDMC/message/down/<project_id>
1. 附加 随机信息, 32位随机小写字母+数字
3. 发送下行 注册command到 wdd/RDMC/command/down/<project_id>
1. 验证项目的一级TOTP密码是否正确 (开关功能,可以不强制)
4. RMDC-watchdog获取下行的注册 command和message
1. 成功接收到message,解析其中的随机信息
2. 接收到command之后
1. 组装message中的随机信息为新的上行Message
2. 发送上行Message到 wdd/RDMC/message/up
5. RMDC-exchange-hubMQTTX解析到该项目的注册成功Message
1. 验证随机信息的正确性
2. 代表该项目初始化连接成功
#### rmdc-watchdog无法连接到MQTTX的流程
1. 仍然保持项目信息注册流程
### Command Message 生命周期与持久化流程
#### Command生命周期
1. 指令的生命周期流程指的是
1. 指令从从业务模块来,包含模块名称,包含指令类型,包含业务下发人
2. 指令包装成command消息生成指令唯一ID
3. 指令发送至MQTTX记录指令下发时间戳
4. 指令从MQTTX下发到RMDC-watchdog记录指令接收时间戳
5. 指令从RMDC-watchdog下发到执行体
6. 指令从执行体返回到RMDC-watchdog
7. RMDC-watchdog将指令转换为Message消息
8. 消息从RMDC-watchdog返回到MQTTX 记录消息上行时间戳
9. 消息从MQTTX返回到RMDC-exchange-hub记录消息返回时间戳
10. 追踪计算每一阶段的耗时
1. 指令下发耗时 = 指令接收时间戳 - 指令下发时间戳
2. 指令执行耗时 = 消息上行时间戳 - 指令接收时间戳
3. 指令上行耗时 = 消息返回时间戳 - 消息上行时间戳
11. 消息从RMDC-exchange-hub返回到业务模块
2. 利用类似状态机的形式追踪指令的生命周期
3. 指令消息生命周期生命体
1. 业务模块名称
2. 指令类型
3. 项目ID
4. 指令下发人
5. 指令下发时间
6. 指令唯一ID构建方式为 <指令类型>-<项目ID>-<时间格式 yyMMddHHmmss>
7. 异步或者同步指令
4. 异步和同步指令,如果实现困难,与现有架构冲突,暂时不用实现
1. 异步指令
1. 指令下发之后,不等待回复
2. 指令消息返回之后
1. 直接入库
2. 可以通过 rmdc-notice-center 进行消息通知
2. 同步指令
1. 指令下发之后,等待回复
2. 指令消息返回之后
1. 直接返回给调用的业务模块
2. 入库
3. 也可以进行消息通知
#### Command 生命周期持久化
1. 指令的生命周期持久化
1. 负责指令生命周期的持久化
1. 指令的完整信息保存
2. 指令对应回复Message信息保存
2. 优化数据库存储结构
1. 能够快速查询到指令的完整信息 以及 指令对应的Message回复信息
2. 能够快速查询到指令的回复信息
3. 指令回复消息需要持久化
2. 下行指令 Command 持久化
1. 每条下发的指令Command 都应该持久化保存
3. 接收上行 Message 持久化
1. 每条接收的上行Message 都应该持久化保存
2. 优化Message的存储
1. 日志类型信息上行,不保存日志的详细内容
2. 监控类型信息上行不保存监控的详细内容由rmdc-monitor-center进行持久化
### 指令下行 处理流程
1. 参考Command生命周期
### 消息上行 处理流程
1. 消息上行存在两种情况
1. 指令回复消息
2. 心跳及监视消息上行
2. 指令回复消息
1. 指令回复消息需要持久化
2. 此类消息需要与指令生命周期进行关联
3. 此类消息处理之后,需要返回至原业务调用模块
3. 项目心跳消息上行
1. 项目心跳消息需要持久化,参考 MQTTX状态及项目在线状态
4. 监视消息上行
1. 监视消息上行需要发送给 rmdc-monitor-center
### 模块前端展示
1. 指令查询展示,支持筛选,查询,导出
1. 指令的生命周期展示
2. 指令的执行结果展示
3. 指令的执行日志展示
## MQTTX状态及项目在线状态
1. 需要提供项目在线状态查询接口,特定时间段的在线状态
2. 需要提供MQTTX在线状态查询接口特定时间段的在线状态
### 存活连接状态持久化
1. 采用时序数据存储类型
2. MQTTX状态持久化展示
1. rmdc-exchange-hub项目启动时候创建MQTTX在线状态表
2. rmdc-exchange-hub需要每5分钟检查MQTTX的状态
3. 检测到MQTTX在线则更新MQTTX在线状态表
4. MQTTX离线不需要更新状态表应该默认该时间点不在线
3. 项目在线状态持久化展示
1. rmdc-watchdog项目注册时候为该项目创建项目在线状态表
2. rmdc-watchdog需要定期发送心跳存活信息
3. 检测到心跳信息,则更新项目在线状态表
4. 项目离线,不需要更新,状态表应该默认该时间点不在线
### 模块前端展示
1. 所有项目的连接状态查看
1. 能够查看单个项目的具体连接内容
2. 展示能够查看所有项目的连接状态
3. 能够统计单个项目的离线次数
4. 可以利用时序数据存储,然后做成uptime的前端监视页面
1. 展示一段历史时间内的在线状态,在线就是绿色,离线就是红色
2. 展示在线时间段支持调节
2. 查看MQTTX的状态
1. 查看MQTTX的历史存活状态
2. 查看MQTTX的历史消息数量
3. 查看MQTTX的实时消息数量
4. 查看MQTTX的队列数量等
5.
## 消息报文与安全要求
1. **统一报文包装**`message_id`(UUID)、`type`(command/data)、`project_id``timestamp`(ms)、`version``payload`(JSON)、`signature`(HMAC-SHA256)、`encrypted`(bool)、`retry_no`(int)。
2. **敏感字段加密**:授权文件/TOTP/主机账号/业务密钥使用 AES-256-GCM加密后仍需签名。
3. **幂等与去重**:按 `message_id + project_id` 去重,重复上行直接 ACK不重复写库。
4. **访问控制**所有下行指令需验证调用方权限业务模块→exchange-hub所有上行需验证签名+TOTP开关
## 可靠性与重试策略
1. **QoS**上下行默认至少一次At-Least-Once前端/业务模块需幂等。
2. **ACK/超时**:指令下发等待 watchdog ACK默认超时 30 秒、重试 3 次,超时进入告警并记录审计。
3. **指令追踪**`command_tracker` 记录 sent_at/acked_at/started_at/completed_at`command_result` 记录 start_time/end_time/duration/received_at缺失字段展示为 NA。
4. **断线补传**watchdog 缓存最近 N 条结果重连后批量上报exchange-hub 支持批量 up 消息,需按 message_id 去重。
## 异常与降级
1. **错误码**`EXH-4xx`(参数/鉴权),`EXH-5xx`(内部错误),`EXH-MQTT-xxx`MQTT 通道异常),`EXH-AUTH-xxx`(授权/签名/TOTP 异常)。
2. **降级通道**MQTT 不可用时开启 HTTP 临时通道(同样签名+TOTP仅允许 register/auth/exec_result其他指令暂停。
3. **安全告警**:签名/TOTP 失败触发 notice-center 告警并写审计。

View File

@@ -0,0 +1,475 @@
# RDMC Exchange Hub 架构流程图
## 1. Exchange Hub 模块架构总览
```mermaid
graph TB
subgraph "RDMC平台 (内网)"
subgraph "rmdc-exchange-hub 模块"
MQTTSvc["MQTTService<br/>消息服务层<br/>(Paho MQTT Client)"]
MsgRouter["MessageRouter<br/>消息路由器"]
subgraph "消息处理器 Handlers"
RegHandler["RegisterHandler<br/>注册处理"]
AuthHandler["AuthHandler<br/>授权处理"]
ExecHandler["ExecHandler<br/>执行处理"]
LogHandler["LogHandler<br/>日志处理"]
MonitorHandler["MonitorHandler<br/>监控处理"]
AlertHandler["AlertHandler<br/>告警处理"]
end
subgraph "状态管理"
ConnMgr["ConnectionManager<br/>连接管理"]
StateMgr["StateManager<br/>状态机管理"]
CmdTracker["CommandTracker<br/>指令追踪"]
end
subgraph "同步指令支持"
SyncMgr["SyncCommandManager<br/>同步指令管理"]
ResultCache["ResultCache<br/>结果缓存"]
end
end
subgraph "业务模块集成"
ProjectMgmt["project-management<br/>项目管理"]
WDCenter["watchdog-center<br/>一级授权中心"]
LogCenter["日志中心"]
MonitorCenter["监控中心"]
Operator["执行中心"]
Notice["通知中心"]
Audit["审计模块"]
end
DB[(PostgreSQL<br/>数据持久化)]
end
MQTT[(MQTT Broker<br/>消息中间件)]
subgraph "外部项目环境"
Watchdog["rmdc-watchdog<br/>边缘代理"]
WDNode["watchdog-node<br/>主机守护"]
WDAgent["watchdog-agent<br/>业务代理"]
end
%% MQTT 连接
MQTTSvc <=="订阅/发布"==> MQTT
MQTT <=="跨公网"==> Watchdog
%% 内部路由
MQTTSvc --> MsgRouter
MsgRouter --> RegHandler
MsgRouter --> AuthHandler
MsgRouter --> ExecHandler
MsgRouter --> LogHandler
MsgRouter --> MonitorHandler
MsgRouter --> AlertHandler
%% 注册与授权流程
RegHandler --> ProjectMgmt
AuthHandler --> WDCenter
ProjectMgmt -.项目信息.-> RegHandler
WDCenter -.授权信息.-> AuthHandler
%% 处理器到业务模块
ExecHandler --> Operator
LogHandler --> LogCenter
MonitorHandler --> MonitorCenter
AlertHandler --> Notice
%% 状态管理
RegHandler --> ConnMgr
MsgRouter --> StateMgr
ExecHandler --> CmdTracker
%% 同步指令支持
ExecHandler --> SyncMgr
LogHandler --> SyncMgr
SyncMgr --> ResultCache
%% 数据持久化
ConnMgr --> DB
StateMgr --> DB
CmdTracker --> DB
Audit --> DB
%% Watchdog 内部
Watchdog <--> WDNode
Watchdog <--> WDAgent
style MQTTSvc fill:#ff6b6b,stroke:#c92a2a,stroke-width:3px
style MQTT fill:#ffd43b,stroke:#f08c00,stroke-width:2px
style Watchdog fill:#4ecdc4,stroke:#087f5b,stroke-width:2px
style SyncMgr fill:#a9e34b,stroke:#5c940d,stroke-width:2px
```
---
## 2. 消息分类与 Topic 设计
```mermaid
graph LR
subgraph "上行通道 (Watchdog → Exchange Hub)"
direction TB
WD1[Watchdog Client]
CmdUp["📤 wdd/RDMC/command/up<br/>指令上行"]
MsgUp["📤 wdd/RDMC/message/up<br/>数据上行"]
WD1 -->|Publish| CmdUp
WD1 -->|Publish| MsgUp
subgraph "上行指令类型"
UCR[register - 项目注册]
UCA[auth_request - 授权请求]
end
subgraph "上行数据类型"
UDM[monitor - 监控数据]
UDL[log_result - 日志结果]
UDE[exec_result - 执行结果]
UDA[alert - 告警信息]
UDH[heartbeat - 心跳数据]
UDC[register_complete - 注册完成]
end
CmdUp -.- UCR
CmdUp -.- UCA
MsgUp -.- UDM
MsgUp -.- UDL
MsgUp -.- UDE
MsgUp -.- UDA
MsgUp -.- UDH
MsgUp -.- UDC
end
subgraph "下行通道 (Exchange Hub → Watchdog)"
direction TB
EH1[Exchange Hub]
CmdDown["📥 wdd/RDMC/command/down/{project_id}<br/>指令下行"]
MsgDown["📥 wdd/RDMC/message/down/{project_id}<br/>数据下行"]
EH1 -->|Publish| CmdDown
EH1 -->|Publish| MsgDown
subgraph "下行指令类型"
DCA[auth_response - 授权响应]
DCL[log_query - 日志查询]
DCE[host_exec - 主机执行]
DCK[k8s_exec - K8s执行]
DCU[update - 业务更新]
DCR[auth_revoke - 授权撤销]
end
subgraph "下行数据类型"
DDR[register_ack - 注册确认]
DDA[auth_info - 授权信息]
end
CmdDown -.- DCA
CmdDown -.- DCL
CmdDown -.- DCE
CmdDown -.- DCK
CmdDown -.- DCU
CmdDown -.- DCR
MsgDown -.- DDR
MsgDown -.- DDA
end
style CmdUp fill:#ffd43b,stroke:#f08c00
style MsgUp fill:#74c0fc,stroke:#1c7ed6
style CmdDown fill:#ff8787,stroke:#c92a2a
style MsgDown fill:#a9e34b,stroke:#5c940d
```
---
## 3. 消息结构设计
### 3.1 基础消息结构
```mermaid
classDiagram
class BaseMessage {
+string MessageID
+string Type
+string ProjectID
+int64 Timestamp
+string Version
}
class CommandMessage {
+CommandType CommandType
+any Payload
+string Signature
}
class DataMessage {
+DataType DataType
+any Payload
+bool Encrypted
}
BaseMessage <|-- CommandMessage
BaseMessage <|-- DataMessage
```
### 3.2 执行模块消息结构
```mermaid
classDiagram
class K8sExecCommand {
+string CommandID
+string Namespace
+string Resource
+string Name
+string Action
+string Container
+[]string Command
+int Timeout
+int TailLines
+bool FollowLogs
}
class HostExecCommand {
+string CommandID
+string HostID
+string Action
+string Script
+[]string Args
+int Timeout
}
class ExecResult {
+string CommandID
+string Status
+int ExitCode
+string Output
+string Error
+int64 StartTime
+int64 EndTime
+int64 Duration
}
class CommandMessage {
+CommandType CommandType
+any Payload
}
CommandMessage --> K8sExecCommand : Payload (k8s_exec)
CommandMessage --> HostExecCommand : Payload (host_exec)
class DataMessage {
+DataType DataType
+any Payload
}
DataMessage --> ExecResult : Payload (exec_result)
```
---
## 4. 指令生命周期状态机
```mermaid
stateDiagram-v2
[*] --> Pending: 创建指令
Pending --> Sent: 发送到MQTT
Sent --> Delivered: Watchdog确认接收
Delivered --> Running: 开始执行
Running --> Success: 执行成功
Running --> Failed: 执行失败
Running --> Timeout: 执行超时
Sent --> Timeout: 未送达超时
Delivered --> Timeout: 未执行超时
Success --> [*]
Failed --> [*]
Timeout --> [*]
note right of Pending: 状态持久化到数据库<br/>记录指令下发时间戳
note right of Running: 可查询实时输出<br/>支持同步等待
note right of Timeout: 触发告警通知<br/>记录超时原因
```
---
## 5. 项目连接状态管理
```mermaid
stateDiagram-v2
[*] --> Offline: 初始状态
Offline --> Connecting: 收到注册请求
Connecting --> Verifying: 发送挑战随机数
Verifying --> Online: 完成挑战-应答验证
Online --> Online: 心跳刷新
Online --> Offline: 心跳超时<br/>(默认30秒)
Online --> Disconnecting: 主动下线
Disconnecting --> Offline: 确认下线
note right of Connecting: 解析项目信息<br/>验证TOTP
note right of Verifying: 挑战-应答机制<br/>32位随机数验证
note right of Online: 定期心跳(5秒)<br/>监控数据上报
note right of Offline: 触发离线告警<br/>通知相关用户
```
---
## 6. MQTT Client 架构对比
### 6.1 Exchange Hub (Server 端)
```mermaid
graph TB
subgraph "Exchange Hub MQTT 架构"
Config[MQTTConfig<br/>连接配置]
Client[MQTT Client<br/>Paho v3]
subgraph "订阅 (Subscribe)"
SubCmd[wdd/RDMC/command/up]
SubMsg[wdd/RDMC/message/up]
end
subgraph "发布 (Publish)"
PubCmd["wdd/RDMC/command/down/{project_id}"]
PubMsg["wdd/RDMC/message/down/{project_id}"]
end
Router[消息路由器<br/>MessageRouter]
HandlerPool[Handler Pool<br/>处理器池]
Config --> Client
Client --> SubCmd
Client --> SubMsg
SubCmd --> Router
SubMsg --> Router
Router --> HandlerPool
HandlerPool --> Client
Client --> PubCmd
Client --> PubMsg
end
style Client fill:#ff6b6b,stroke:#c92a2a,stroke-width:2px
```
### 6.2 Watchdog (Client 端)
```mermaid
graph TB
subgraph "Watchdog MQTT 架构"
Config[MQTTConfig<br/>连接配置]
Client[MQTT Client<br/>Paho v3]
ProjectID[ProjectID]
subgraph "订阅 (Subscribe)"
SubCmd["wdd/RDMC/command/down/{project_id}"]
SubMsg["wdd/RDMC/message/down/{project_id}"]
end
subgraph "发布 (Publish)"
PubCmd[wdd/RDMC/command/up]
PubMsg[wdd/RDMC/message/up]
end
CmdExecutor[CommandExecutor<br/>指令执行器]
DataCollector[DataCollector<br/>数据采集器]
Config --> Client
ProjectID --> Client
Client --> SubCmd
Client --> SubMsg
SubCmd --> CmdExecutor
SubMsg --> CmdExecutor
DataCollector --> Client
Client --> PubCmd
Client --> PubMsg
end
style Client fill:#4ecdc4,stroke:#087f5b,stroke-width:2px
```
---
## 7. 安全设计
```mermaid
graph LR
subgraph "安全机制"
TLS["TLS/SSL加密<br/>传输层安全"]
Auth["MQTT认证<br/>用户名/密码"]
Sign["消息签名<br/>HMAC-SHA256"]
Encrypt["敏感数据加密<br/>AES-256-GCM"]
TOTP["TOTP验证<br/>时间戳校验"]
end
subgraph "应用场景"
Conn[连接建立] --> TLS
Conn --> Auth
Cmd[指令传输] --> Sign
Cmd --> Encrypt
Reg[项目注册] --> TOTP
Reg --> Sign
end
style TLS fill:#a5d8ff,stroke:#1c7ed6
style Auth fill:#a5d8ff,stroke:#1c7ed6
style Sign fill:#ffd8a8,stroke:#f08c00
style Encrypt fill:#ffd8a8,stroke:#f08c00
style TOTP fill:#d3f9d8,stroke:#087f5b
```
---
## 8. 与业务模块集成架构
```mermaid
graph TB
subgraph "业务模块层"
PM["project-management<br/>项目管理"]
WC["watchdog-center<br/>一级授权中心"]
LC["log-center<br/>日志中心"]
MC["monitor-center<br/>监控中心"]
OP["octopus-operator<br/>执行中心"]
NC["notice-center<br/>通知中心"]
end
subgraph "Exchange-Hub 接口层"
RegAPI["RegisterAPI<br/>注册接口"]
AuthAPI["AuthAPI<br/>授权接口"]
CmdAPI["CommandAPI<br/>指令接口"]
QueryAPI["QueryAPI<br/>查询接口"]
end
subgraph "Exchange-Hub 核心"
MQTTSvc["MQTTService"]
Handlers["Handlers"]
StateDB["StateDB"]
end
PM --> RegAPI
WC --> AuthAPI
LC --> CmdAPI
MC --> CmdAPI
OP --> CmdAPI
NC <-- QueryAPI
RegAPI --> MQTTSvc
AuthAPI --> MQTTSvc
CmdAPI --> MQTTSvc
QueryAPI --> StateDB
MQTTSvc --> Handlers
Handlers --> StateDB
style MQTTSvc fill:#ff6b6b,stroke:#c92a2a
```

View File

@@ -0,0 +1,232 @@
# RMDC-Exchange-Hub 指令执行时间计算规范
## 1. 概述
本文档定义了 RMDC-Exchange-Hub 模块中指令执行全生命周期的时间追踪与计算规范。
---
## 2. 时间点定义
### 2.1 指令生命周期时间点
```mermaid
sequenceDiagram
participant BM as 业务模块
participant EH as Exchange Hub
participant MQTT as MQTT Broker
participant WD as Watchdog
participant EX as 执行体
Note over EH: ① created_at<br/>指令创建时间
BM->>EH: 发起指令请求
Note over EH: ② sent_at<br/>发送到MQTT时间
EH->>MQTT: Publish指令
Note over WD: ③ acked_at<br/>Watchdog确认接收
MQTT->>WD: 推送指令
WD-->>EH: (可选) ACK确认
Note over WD: ④ started_at<br/>开始执行时间
WD->>EX: 调用执行体
Note over EX: ⑤ start_time (ms)<br/>执行体内部开始
EX->>EX: 执行指令...
Note over EX: ⑥ end_time (ms)<br/>执行体内部结束
EX->>WD: 返回结果
Note over WD: ⑦ 消息上行
WD->>MQTT: ExecResult上行
Note over EH: ⑧ received_at<br/>Exchange Hub接收
MQTT->>EH: 推送结果
Note over EH: ⑨ completed_at<br/>指令完成时间
```
### 2.2 时间点存储位置
| 时间点 | 字段名 | 存储表 | 类型 | 说明 |
|-------|-------|-------|------|------|
| 指令创建 | `created_at` | command_trackers | TIMESTAMP | 自动记录 |
| 发送到MQTT | `sent_at` | command_trackers | TIMESTAMP | 调用MQTT Publish时记录 |
| Watchdog确认 | `acked_at` | command_trackers | TIMESTAMP | 收到ACK消息时记录 |
| 开始执行 | `started_at` | command_trackers | TIMESTAMP | 收到running状态时记录 |
| 执行开始(内部) | `start_time` | command_results | INT64 (ms) | Watchdog侧记录 |
| 执行结束(内部) | `end_time` | command_results | INT64 (ms) | Watchdog侧记录 |
| 结果接收 | `received_at` | command_results | TIMESTAMP | Exchange Hub接收结果时记录 |
| 指令完成 | `completed_at` | command_trackers | TIMESTAMP | 更新为终态时记录 |
---
## 3. 时间耗时计算公式
### 3.1 核心耗时指标
| 指标名称 | 计算公式 | 单位 | 含义 |
|---------|---------|------|------|
| **指令下发耗时** | `acked_at - sent_at` | ms | 指令从Exchange Hub到达Watchdog的网络耗时 |
| **指令执行耗时** | `end_time - start_time` (或 `duration`) | ms | 指令在执行体内的实际执行时间 |
| **指令上行耗时** | `received_at - end_time` | ms | 执行结果从Watchdog返回Exchange Hub的耗时 |
| **总体耗时** | `completed_at - sent_at` | ms | 从发送到完成的总时间 |
### 3.2 扩展耗时指标
| 指标名称 | 计算公式 | 单位 | 含义 |
|---------|---------|------|------|
| 排队耗时 | `sent_at - created_at` | ms | 指令在Exchange Hub等待发送的时间 |
| 处理准备耗时 | `started_at - acked_at` | ms | Watchdog接收到开始执行的准备时间 |
---
## 4. 数据结构定义
### 4.1 CommandTracker 时间字段
```go
type CommandTracker struct {
// ... 其他字段 ...
// 时间追踪字段
SentAt *time.Time // 发送到MQTT时间戳
AckedAt *time.Time // Watchdog确认接收时间戳
StartedAt *time.Time // 开始执行时间戳
CompletedAt *time.Time // 完成时间戳
CreatedAt time.Time // 创建时间
TimeoutAt *time.Time // 超时时间
}
```
### 4.2 CommandResult 时间字段
```go
type CommandResult struct {
// ... 其他字段 ...
// 执行时间字段 (来自Watchdog)
StartTime int64 // 执行开始时间戳(ms)
EndTime int64 // 执行结束时间戳(ms)
Duration int64 // 执行时长(ms)
// 上行时间字段 (Exchange Hub记录)
ReceivedAt time.Time // 结果接收时间
UploadDuration int64 // 上行耗时(ms) = ReceivedAt - EndTime
}
```
### 4.3 时间详情DTO
```go
// CommandTimeDurations 指令时间耗时详情
type CommandTimeDurations struct {
DeliveryDuration int64 `json:"delivery_duration"` // 下发耗时(ms)
ExecDuration int64 `json:"exec_duration"` // 执行耗时(ms)
UploadDuration int64 `json:"upload_duration"` // 上行耗时(ms)
TotalDuration int64 `json:"total_duration"` // 总体耗时(ms)
QueueDuration int64 `json:"queue_duration,omitempty"` // 排队耗时(ms)
}
```
---
## 5. API响应格式
### 5.1 查询指令响应增强
```json
{
"code": 0,
"message": "success",
"data": {
"command_id": "k8s_exec-proj_001-241222114530",
"project_id": "proj_001",
"status": "success",
"created_at": "2024-12-22 11:45:30",
"completed_at": "2024-12-22 11:45:35",
"time_durations": {
"delivery_duration": 150,
"exec_duration": 4500,
"upload_duration": 120,
"total_duration": 4850
},
"result": { ... }
}
}
```
### 5.2 同步指令响应
```json
{
"code": 0,
"message": "success",
"data": {
"command_id": "k8s_exec-proj_001-241222114530",
"status": "success",
"exit_code": 0,
"output": "...",
"duration": 4500,
"time_durations": {
"delivery_duration": 150,
"exec_duration": 4500,
"upload_duration": 120,
"total_duration": 4850
}
}
}
```
---
## 6. 计算实现伪代码
```go
// CalculateCommandDurations 计算指令时间耗时
func CalculateCommandDurations(
tracker *entity.CommandTracker,
result *entity.CommandResult,
) *dto.CommandTimeDurations {
durations := &dto.CommandTimeDurations{}
// 1. 下发耗时
if tracker.SentAt != nil && tracker.AckedAt != nil {
durations.DeliveryDuration = tracker.AckedAt.Sub(*tracker.SentAt).Milliseconds()
}
// 2. 执行耗时 (优先使用Watchdog计算值)
if result != nil && result.Duration > 0 {
durations.ExecDuration = result.Duration
} else if result != nil && result.StartTime > 0 && result.EndTime > 0 {
durations.ExecDuration = result.EndTime - result.StartTime
}
// 3. 上行耗时
if result != nil && result.EndTime > 0 {
receivedAtMs := result.ReceivedAt.UnixMilli()
durations.UploadDuration = receivedAtMs - result.EndTime
}
// 4. 总体耗时
if tracker.SentAt != nil && tracker.CompletedAt != nil {
durations.TotalDuration = tracker.CompletedAt.Sub(*tracker.SentAt).Milliseconds()
}
// 5. 排队耗时 (可选)
if tracker.SentAt != nil {
durations.QueueDuration = tracker.SentAt.Sub(tracker.CreatedAt).Milliseconds()
}
return durations
}
```
---
## 7. 注意事项
1. **时区统一**: 所有时间必须使用统一时区 (Asia/Shanghai, UTC+8)
2. **精度要求**: 毫秒级精度int64存储
3. **空值处理**: 计算时需检查时间字段是否为nil
4. **Watchdog时间**: `start_time`/`end_time` 由Watchdog本地时间生成可能存在时钟偏差

View File

@@ -0,0 +1,354 @@
# Exchange-Hub模块开发提示词
> 本文档为大模型提供rmdc-exchange-hub模块的开发上下文。
---
## 模块概述
**rmdc-exchange-hub** 是RMDC平台的消息网关模块负责
1. **MQTT消息中继**: 连接内网业务模块与外网Watchdog
2. **指令生命周期管理**: 追踪指令从下发到执行完成的全过程
3. **项目在线状态管理**: 维护各项目的连接状态
4. **同步/异步指令支持**: 支持两种指令执行模式
---
## 核心概念
### 消息方向
| 方向 | 描述 | Topic |
|------|------|-------|
| **上行** | Watchdog → Exchange-Hub | `wdd/RDMC/command/up`, `wdd/RDMC/message/up` |
| **下行** | Exchange-Hub → Watchdog | `wdd/RDMC/command/down/{project_id}`, `wdd/RDMC/message/down/{project_id}` |
### 消息类型
| 类型 | 描述 |
|------|------|
| **Command** | 指令消息,需要执行的操作 |
| **Message** | 数据消息,执行结果/心跳/监控等 |
---
## 技术栈
| 组件 | 技术 |
|------|------|
| MQTT客户端 | Eclipse Paho |
| Web框架 | Gin |
| ORM | GORM |
| 数据库 | PostgreSQL |
---
## 项目结构
```
rmdc-exchange-hub/
├── internal/
│ ├── config/
│ │ └── config.go
│ ├── dao/
│ │ ├── command_tracker_dao.go # 指令追踪
│ │ ├── command_result_dao.go # 执行结果
│ │ └── project_status_dao.go # 项目状态
│ ├── handler/
│ │ ├── router.go
│ │ ├── command_handler.go
│ │ └── status_handler.go
│ ├── model/
│ │ ├── dto/
│ │ │ └── exchange_dto.go
│ │ └── entity/
│ │ ├── command_tracker.go
│ │ ├── command_result.go
│ │ └── project_status.go
│ └── service/
│ ├── mqtt_service.go # MQTT客户端
│ ├── message_router.go # 消息路由
│ ├── command_service.go # 指令管理
│ ├── sync_command_manager.go # 同步指令
│ └── state_manager.go # 状态管理
└── pkg/
└── mqtt/
└── client.go
```
---
## 核心数据结构
### 统一消息格式
```go
// BaseMessage 基础消息结构
type BaseMessage struct {
MessageID string `json:"message_id"` // UUID
Type string `json:"type"` // "command" or "message"
ProjectID string `json:"project_id"`
Timestamp int64 `json:"timestamp"` // 毫秒时间戳
Version string `json:"version"`
}
// CommandMessage 指令消息
type CommandMessage struct {
BaseMessage
CommandType string `json:"command_type"` // register, k8s_exec, host_exec...
Payload interface{} `json:"payload"`
Signature string `json:"signature"` // HMAC-SHA256签名
}
// DataMessage 数据消息
type DataMessage struct {
BaseMessage
DataType string `json:"data_type"` // exec_result, heartbeat, monitor...
Payload interface{} `json:"payload"`
Encrypted bool `json:"encrypted"`
}
```
### 指令追踪实体
```go
// CommandTracker 指令追踪器
type CommandTracker struct {
ID int64 `gorm:"primaryKey"`
CommandID string `gorm:"uniqueIndex;size:100"`
ProjectID string `gorm:"index;size:100"`
CommandType string `gorm:"size:50"`
Module string `gorm:"size:50"` // 来源模块
OperatorID int64 // 操作人
Status string `gorm:"size:20"` // pending, sent, acked, completed, failed, timeout
SentAt time.Time // 发送时间
AckedAt *time.Time // 确认时间
StartedAt *time.Time // 开始执行
CompletedAt *time.Time // 完成时间
TimeoutAt time.Time // 超时时间
IsSync bool // 是否同步指令
CreatedAt time.Time
UpdatedAt time.Time
}
// CommandResult 指令执行结果
type CommandResult struct {
ID int64 `gorm:"primaryKey"`
CommandID string `gorm:"index;size:100"`
Status string `gorm:"size:20"` // success, failure, timeout
ExitCode int
Output string `gorm:"type:text"`
Error string `gorm:"type:text"`
StartTime int64
EndTime int64
Duration int64
ReceivedAt time.Time
CreatedAt time.Time
}
```
---
## MQTT Topic设计
### 上行TopicWatchdog → Exchange-Hub
```
wdd/RDMC/command/up # 指令上行(注册、授权请求)
wdd/RDMC/message/up # 数据上行(心跳、执行结果、监控)
```
### 下行TopicExchange-Hub → Watchdog
```
wdd/RDMC/command/down/{project_id} # 指令下行
wdd/RDMC/message/down/{project_id} # 数据下行
```
---
## 关键业务流程
### 指令下发流程
```go
func (s *CommandService) SendCommand(ctx context.Context, projectID string, cmdType string, payload interface{}) (*CommandTracker, error) {
// 1. 构造消息
msg := &common.CommandMessage{
BaseMessage: common.BaseMessage{
MessageID: uuid.New().String(),
Type: "command",
ProjectID: projectID,
Timestamp: time.Now().UnixMilli(),
Version: "1.0",
},
CommandType: cmdType,
Payload: payload,
}
// 2. 签名
msg.Signature = s.sign(msg)
// 3. 记录追踪
tracker := &entity.CommandTracker{
CommandID: msg.MessageID,
ProjectID: projectID,
CommandType: cmdType,
Status: "pending",
SentAt: time.Now(),
TimeoutAt: time.Now().Add(30 * time.Second),
}
s.trackerDAO.Create(ctx, tracker)
// 4. 发布到MQTT
topic := fmt.Sprintf("wdd/RDMC/command/down/%s", projectID)
s.mqttService.Publish(topic, msg)
// 5. 更新状态
tracker.Status = "sent"
s.trackerDAO.Update(ctx, tracker)
return tracker, nil
}
```
### 同步指令实现
```go
// SyncCommandManager 同步指令管理器
type SyncCommandManager struct {
waitChannels sync.Map // map[commandID]chan *ExecResult
}
func (m *SyncCommandManager) SendAndWait(ctx context.Context, projectID string, cmd *CommandMessage, timeout time.Duration) (*ExecResult, error) {
// 1. 创建等待通道
waitChan := make(chan *ExecResult, 1)
m.waitChannels.Store(cmd.MessageID, waitChan)
defer m.waitChannels.Delete(cmd.MessageID)
// 2. 发送指令
if err := m.mqttService.PublishCommand(projectID, cmd); err != nil {
return nil, err
}
// 3. 等待结果或超时
select {
case result := <-waitChan:
return result, nil
case <-time.After(timeout):
return nil, errors.New("command execution timeout")
case <-ctx.Done():
return nil, ctx.Err()
}
}
// OnResult 接收结果回调
func (m *SyncCommandManager) OnResult(result *ExecResult) {
if ch, ok := m.waitChannels.Load(result.CommandID); ok {
ch.(chan *ExecResult) <- result
}
}
```
### 消息路由处理
```go
func (r *MessageRouter) handleUpMessage(msg *common.DataMessage) {
switch msg.DataType {
case "exec_result":
r.handleExecResult(msg)
case "heartbeat":
r.handleHeartbeat(msg)
case "monitor":
r.handleMonitor(msg)
case "log_result":
r.handleLogResult(msg)
case "alert":
r.handleAlert(msg)
case "register_complete":
r.handleRegisterComplete(msg)
}
}
func (r *MessageRouter) handleExecResult(msg *common.DataMessage) {
result := msg.Payload.(*ExecResult)
// 1. 更新指令追踪状态
r.trackerService.Complete(result.CommandID, result.Status)
// 2. 保存执行结果
r.resultDAO.Create(result)
// 3. 通知同步等待者
r.syncManager.OnResult(result)
// 4. 推送给业务模块(如需要)
// ...
}
```
---
## 项目状态管理
### 状态机
```
offline → connecting → verifying → online → disconnecting → offline
└── heartbeat刷新
```
### 心跳策略
| 参数 | 默认值 | 说明 |
|------|--------|------|
| 心跳间隔 | 5秒 | Watchdog发送心跳的频率 |
| 超时时间 | 30秒 | 无心跳多久判定为离线 |
---
## API接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/exchange-hub/command/send` | POST | 发送异步指令 |
| `/api/exchange-hub/command/sync` | POST | 发送同步指令(等待结果) |
| `/api/exchange-hub/command/:id` | GET | 查询指令状态 |
| `/api/exchange-hub/project/:id/status` | GET | 查询项目在线状态 |
| `/api/exchange-hub/projects/online` | GET | 获取所有在线项目 |
---
## 常见开发任务
### 1. 添加新的指令类型
1.`common`包定义Payload结构
2. 在Watchdog端添加Handler处理
3. 在业务模块调用`CommandService.SendCommand`
### 2. 添加新的数据类型
1.`MessageRouter.handleUpMessage`添加case分支
2. 实现对应的处理函数
3. 如需持久化添加Entity和DAO
### 3. 修改消息格式
1. 修改`common`包的消息结构
2. 同步修改Watchdog端的解析逻辑
3. 考虑版本兼容性
---
## 相关文档
| 文档 | 内容 |
|------|------|
| `1-rmdc-exchange-hub-DDS.md` | 详细设计 |
| `4-rmdc-exchange-hub-architecture.md` | 架构图 |
| `5-rmdc-exchange-hub-command-time.md` | 指令耗时计算 |

View File

@@ -0,0 +1,296 @@
# 项目管理模块 - RMDC-project-management
1. 单个k8s-namespace作为一个项目
2. 本模块是rmdc项目的核心模块
## 项目权限
1. 项目的权限颗粒度
1. 查看权限
1. 用户可以查看自己拥有权限的所有项目的列表
2. 超级管理员能够查看全部内容
3. 数据权限,分配权限需要精细到项目详情的特定模块
2. 新建(创建)权限
1. 只有超级管理员可以创建项目信息填写工单
3. 修改(编辑)权限
1. 项目详情填写人,自动具备修改权限
2. 由于有工单系统
1. 用户不能直接修改项目信息,只能发起修改工单
2. 具备查看权限的用户具备修改权限
3. 超级管理员可以查看全部项目信息,具备修改权限
4. 删除权限
1. 非超级管理员用户不具备删除权限
5. 导出权限
1. 具有查看权限的用户可以导出项目信息
2. 项目创建权限
1. 项目创建只能由超级管理员进行
2. 项目有唯一字段(项目名称 namespace命名空间需要判定数据库是否存在该项目
3. 用户/管理
1. 用户端能够查看部分内容
2. 超级管理员能够查看全部内容
3. 管理员能够查看部分内容
1. 管理员可以授权自己拥有权限的内容给普通用户
4. 访问控制列表ACL由管理员授权遵循项目的颗粒度进行授权
### 项目权限管理分配页面
1. 只有超级管理员可以访问
2. 后端接口只有超级管理员具备权限
1. 权限检验
2. 审计日志记录
3. 超级管理员可以为特定用户分配项目权限
1. 分配权限只有查看权限,编辑权限(通过工单系统审批)
2. 分配权限可以按照项目颗粒度进行分配
3. 分配权限可以按照用户颗粒度进行分配
4. 分配权限需要精细到 项目详情的特定模块(数据权限)
1. 项目基本信息模块
2. 部署业务模块
3. 部署环境模块
4. 部署中间件模块
5. 项目授权模块(只有超级管理员具备权限)
4. 用户系统使用 rmdc-user-auth 的用户系统
5. 权限分配管理 使用 rmdc-user-auth 模块
6. 权限分配需要记录审计日志
7. 审计日志使用 rmdc-audit-log 模块
## 项目管理的生命周期
1. 项目创建
1. 超级管理员填写项目基本信息,分派给项目填写人
1. 项目处于 未发布状态(草稿状态)
2. 项目填写人填写项目信息
3. 项目填写人提交项目信息给超级管理员审核
4. 超级管理员审核项目信息
5. 超级管理员审批通过之后
1. 项目信息作为master主分支
2. 项目处于已发布状态
2. 项目编辑
1. 非超级管理员用户可以编辑项目信息
2. 非超级管理员用户可以发起修改工单
1. 项目对于 非超级管理员用户 处于编辑状态
3. 非超级管理员用户可以在超级管理员审批之前 撤销修改工单
1. 项目对于 非超级管理员用户 处于已发布状态
4. 超级管理员审批通过之后
1. 项目对于 非超级管理员用户 处于已发布状态
5. 超级管理员审批拒绝之后
1. 项目对于 非超级管理员用户 处于编辑状态
3. 项目删除
1. 只有超级管理员 可以修改项目状态为删除状态
2. 项目采用软删除的策略
### 项目详情页面与项目详情工单之间的关系
1. 项目详情工单分为如下的两种
1. 项目创建时候,项目详情的填写工单
2. 项目正常过程中,项目详情的编辑工单
2. 项目详情工单和项目详情页面之间需要互相能够跳转
1. 项目详情填写工单是唯一的,只能同时存在一个项目详情填写工单
2. 超级管理员的项目详情编辑工单不是唯一的,可以同时存在多个项目详情编辑工单
3. 对于非超级管理员,项目详情编辑工单是唯一的,只能同时存在一个项目详情编辑工单
3. 超级管理员的非正式发布状态的项目详情页面,只能跳转至一个项目详情填写工单
4. 超级管理员的正式发布状态的项目详情页面,可以跳转至多个项目详情编辑工单
## 项目查看
1. 所有项目页面
1. 用户可以查看自己拥有权限的所有项目的列表
2. 支持列表显示,卡片显示
3. 点击项目之后,进入项目详情页面
2. 项目详情页面
1. 展示项目概览信息
2. 具备查看权限,可以进行页面信息修改提交,发起修改工单,修改工单需要超级管理员审核
3. 项目信息导出
1. 支持按照YAML格式模板 导出项目信息
3. 项目模块详情页面
1. 部署业务信息、部署环境信息、部署中间件信息属于特定模块
2. 作为TAB页签显示各个模块
3. 授权信息页面
1. 只有超级管理员可以访问
2. 后端接口只有超级管理员具备权限
1. 权限检验
2. 审计日志记录
3. 具体功能详见 项目授权管理
### 项目详情页面
1. 查看状态
1. 默认状态
2. 项目详情页面有导出按钮,点击之后可以导出项目的详情
3. 项目详情页面的字段具备快捷粘贴的功能
2. 编辑状态
1. 项目详情页面显示编辑按钮,点击之后进入编辑状态
2. 编辑状态没有导出按钮
3. 编辑状态具备 保存草稿 提交审核 放弃编辑的按钮
4. 保存草稿按钮,触发项目详情的草稿保存功能,保存至数据库中
5. 项目详情的编辑草稿 应该与非超级管理员用户产生关联
6. 编辑状态应该能够类似GIT DIFF显示草稿与正式版本的差异
1. 在编辑页面,需要定期获取最新的版本
7. 放弃编辑按钮,触发项目详情的草稿删除功能,删除数据库中的草稿,退出编辑状态
8. 提交审核按钮触发项目详情的草稿提交审核功能可以复用项目详情填写工单流程TODO 考虑与rmdc-work-procedure模块进行整合
9. 字段校验
1. IP地址字段
1. 公网IP地址 内网IP地址 如果不为空值需要进行IP校验
2. IP的空值处理前端显示默认空值填充为 无
2. 命名空间字段
1. 前端创建项目时候命名空间名称必须符合RFC 1123 DNS标签规范具体要求包括
1. 不能超过253个字符
2. 只能包含小写字母、数字以及'-'和'.'字符
3. 必须以字母开头
4. 必须以字母数字结尾
2. 前端显示默认空值填充为 无
10. 密码字段
1. 项目填写人 需要填写密码字段
2. 数据库加密存储应该使用项目的TierOneScret进行加密
11. 部署人姓名
1. 非超级管理员也可以通过用户接口查找到系统中的用户 /api/user
2. 部署人姓名字段,用于显示部署人姓名
3. 超级管理员页面的项目详情页面
1. 超级管理员的项目详情页面,默认显示主线版本分支的内容
2. 超级管理员可以直接修改项目的master主分支直接修改入库不需要工单审批
3. 超级管理员的项目详情页面,具备查看所有版本的功能
1. 超级管理员可以查看所有版本的项目详情
2. 可以查看页面的修订历史类似GIT的历史提交记录
3. 每一个版本可以查看到 修改的内容
4. 超级管理员的项目详情页面,可以跳转至工单详情页面
1. 超级管理员可以跳转至工单详情页面,查看与此项目关联的工单内容
5. 超级管理员的项目详情页面,可以查看到授权信息模块的内容
4. 非超级管理员左侧导航栏 显示 项目管理
1. 默认展示其具备的全部访问权限的项目列表
1. 支持列表、卡片显示
2. 点击项目可以进入项目详情页面
## 项目创建
### 项目创建的流程说明
1. 项目详情展示与填写类似于GIT的分支
2. 项目查看是由超级管理员审核维护的master主分支
4. 项目创建流程,超级管理员分配一个用户进行项目信息登记
5. 当项目初始信息被登记完成超级管理员审批通过之后项目信息作为初始的master主分支
6. 项目编辑是每个用户都具备的临时分支每个用户都具备草稿然后提交审核合并入master主分支需要被超级管理员审核
### 项目信息登记页面
1. 项目创建只能由超级管理员进行
1. 填写必要的信息,不需要考虑空值
2. 考虑到数据库字段限制, 数据库不为空字段,填充默认值
2. 项目创建中,需要按照管理权限,分配给特定的用户进行信息登记
1. 特定用户填写时候, 前端自动过滤掉默认值
3. 支持草稿功能,项目信息填写比较耗时,需要支持草稿功能
4. 必填字段
1. 填满才可以提交项目信
2. 不填满只能保存草稿
5. 信息审核
1. 普通用户填写项目信息之后,需要超级管理员审核修改项目信息认证
### 项目详情填写审批工单
1. 详情见 rmdc-work-procedure
2. 当前阶段已经实现
### 项目详情填写页面
1. 复用 项目详情页面 的编辑状态
#### 特殊字段说明
1. 前端创建项目时候命名空间名称必须符合RFC 1123 DNS标签规范具体要求包括
1. 不能超过253个字符
2. 只能包含小写字母、数字以及'-'和'.'字符
3. 必须以字母开头
4. 必须以字母数字结尾
2. 省份和城市字段 请参照[3-china-province-city.md](3-china-province-city.md)解析
1. 后端和前端都应该维护一份枚举表
2. 前端项目创建时,后端应该校验相应的省份和城市
3. 前端应该实现级联选择
#### 项目基本信息结构体
1. 项目名称
2. 命名空间(唯一)
3. 项目ID project_id (唯一)
4. 省份 (枚举 中国的省份是固定的)
5. 城市(枚举 中国的城市是固定的)
6. 行业组人员
7. 行业组人员电话
8. 项目性质 (科研、测试、试用、市场化、二级平台)
9. 项目信息认证 (草稿,正式)
1. 由超级管理员修改
10. 部署业务结构体
11. 部署环境结构体
12. 部署中间件结构体
#### 项目部署业务结构体
1. 部署人姓名
2. 部署人电话
3. 部署开始时间
4. 部署完成时间
5. 部署系统的版本
6. 部署系统business老行业平台 fly-control新飞控平台 supervisor监管平台
7. 业务主要入口
8. 系统超级管理员用户
9. 系统超级管理员密码(需要加密存储)
#### 项目部署环境结构体
1. 主机信息结构体 与rmdc-watchdog-common中保持一致
1. 此部分信息理论来自 rmdc-watchdog -> rmdc-exchange-hub 上报
2. 新增字段
1. 公网IP
2. 能够访问公网
3. SSH端口
4. SSH用户名
5. SSH密码 (需要加密存储)
6. 主机角色master worker storage
2. 网络环境 (完全内网、单主机公网、全访问公网)
3. 主要公网IP地址
4. 域名URL
5. 是否开启SSL
6. 主机管理方式(堡垒机、白名单、)
7. 管理后台URL
8. 管理后台用户名
9. 管理后台密码(需要加密存储)
10. 主机台数
11. 主机CPU总数
12. 主机CPU型号
13. 主机内存总大小
14. 主机存储总大小
#### 项目部署中间件结构体
1. MySQL结构体
2. Redis结构体
3. EMQX结构体
4. MINIO结构体
5. InfluxDB结构体
6. Nacos结构体
7. K8S Dashboard结构体
8. 上述结构体的字段均有如下字段
1. 公网IP
2. 公网端口
3. 内网IP
4. 内网端口
5. k8s访问地址
6. k8s访问端口
7. 超级管理员用户名
8. 超级管理员密码 (需要加密存储)
#### 项目授权信息结构体
1. 项目一级TOTP授权密钥
2. 一级授权允许时间偏移
3. 开启TOTP验证
4. 项目二级TOTP授权密钥
5. 是否开启授权
6. 授权类型: permanent/time
7. 授权有效期(天)
8. 授权时间
9. 撤销授权时间
## 项目授权功能
1. 集成之前 rmdc-wathchdog-center部分的功能
2. 需要与 rmdc-exchange-hub rmdc-watchdog 交互
1. 只有SuperAdmin具备此权限
2. 接收来自 rmdc-exchange-hub 关于项目注册的信息
1. 项目注册实际来自rmdc-watchdog
2. 项目信息应该持久化保存
3. 能够对全部项目进行授权
1. 正常情况是从rmdc-exchange-hub接收的注册项目
2. 处理来自 rmdc-exchange-hub 的授权信息
3. 调用RMDC-watchdog-center的授权接口
4. 存储项目的授权文件信息
5. 授权时间也可以进行管理
4. 有特殊的项目,无法访问公网
1. 可以手动添加离线项目的相关信息
2. 可以离线进行项目授权
5. 能够取消对一个项目的授权
1. 同样是通过rmdc-exchange-hub的在线方式
2. 可以离线取消项目授权

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,361 @@
## 省份及地级市列表
**河北省**
河北省-石家庄市
河北省-唐山市
河北省-秦皇岛市
河北省-邯郸市
河北省-邢台市
河北省-保定市
河北省-张家口市
河北省-承德市
河北省-沧州市
河北省-廊坊市
河北省-衡水市
**山西省**
山西省-太原市
山西省-大同市
山西省-阳泉市
山西省-长治市
山西省-晋城市
山西省-朔州市
山西省-晋中市
山西省-运城市
山西省-忻州市
山西省-临汾市
山西省-吕梁市
**内蒙古自治区**
内蒙古自治区-呼和浩特市
内蒙古自治区-包头市
内蒙古自治区-乌海市
内蒙古自治区-赤峰市
内蒙古自治区-通辽市
内蒙古自治区-鄂尔多斯市
内蒙古自治区-呼伦贝尔市
内蒙古自治区-巴彦淖尔市
内蒙古自治区-乌兰察布市
**辽宁省**
辽宁省-沈阳市
辽宁省-大连市
辽宁省-鞍山市
辽宁省-抚顺市
辽宁省-本溪市
辽宁省-丹东市
辽宁省-锦州市
辽宁省-营口市
辽宁省-阜新市
辽宁省-辽阳市
辽宁省-盘锦市
辽宁省-铁岭市
辽宁省-朝阳市
辽宁省-葫芦岛市
**吉林省**
吉林省-长春市
吉林省-吉林市
吉林省-四平市
吉林省-辽源市
吉林省-通化市
吉林省-白山市
吉林省-松原市
吉林省-白城市
**黑龙江省**
黑龙江省-哈尔滨市
黑龙江省-齐齐哈尔市
黑龙江省-鸡西市
黑龙江省-鹤岗市
黑龙江省-双鸭山市
黑龙江省-大庆市
黑龙江省-伊春市
黑龙江省-佳木斯市
黑龙江省-七台河市
黑龙江省-牡丹江市
黑龙江省-黑河市
黑龙江省-绥化市
**江苏省**
江苏省-南京市
江苏省-无锡市
江苏省-徐州市
江苏省-常州市
江苏省-苏州市
江苏省-南通市
江苏省-连云港市
江苏省-淮安市
江苏省-盐城市
江苏省-扬州市
江苏省-镇江市
江苏省-泰州市
江苏省-宿迁市
**浙江省**
浙江省-杭州市
浙江省-宁波市
浙江省-温州市
浙江省-嘉兴市
浙江省-湖州市
浙江省-绍兴市
浙江省-金华市
浙江省-衢州市
浙江省-舟山市
浙江省-台州市
浙江省-丽水市
**安徽省**
安徽省-合肥市
安徽省-芜湖市
安徽省-蚌埠市
安徽省-淮南市
安徽省-马鞍山市
安徽省-淮北市
安徽省-铜陵市
安徽省-安庆市
安徽省-黄山市
安徽省-滁州市
安徽省-阜阳市
安徽省-宿州市
安徽省-六安市
安徽省-亳州市
安徽省-池州市
安徽省-宣城市
**福建省**
福建省-福州市
福建省-厦门市
福建省-三明市
福建省-莆田市
福建省-泉州市
福建省-漳州市
福建省-南平市
福建省-龙岩市
福建省-宁德市
**江西省**
江西省-南昌市
江西省-景德镇市
江西省-萍乡市
江西省-九江市
江西省-新余市
江西省-鹰潭市
江西省-赣州市
江西省-吉安市
江西省-宜春市
江西省-抚州市
江西省-上饶市
**山东省**
山东省-济南市
山东省-青岛市
山东省-淄博市
山东省-枣庄市
山东省-东营市
山东省-烟台市
山东省-潍坊市
山东省-济宁市
山东省-泰安市
山东省-威海市
山东省-日照市
山东省-临沂市
山东省-德州市
山东省-聊城市
山东省-滨州市
山东省-菏泽市
**河南省**
河南省-郑州市
河南省-开封市
河南省-洛阳市
河南省-平顶山市
河南省-安阳市
河南省-鹤壁市
河南省-新乡市
河南省-焦作市
河南省-濮阳市
河南省-许昌市
河南省-漯河市
河南省-三门峡市
河南省-南阳市
河南省-商丘市
河南省-信阳市
河南省-周口市
河南省-驻马店市
**湖北省**
湖北省-武汉市
湖北省-黄石市
湖北省-十堰市
湖北省-宜昌市
湖北省-襄阳市
湖北省-鄂州市
湖北省-荆门市
湖北省-孝感市
湖北省-荆州市
湖北省-黄冈市
湖北省-咸宁市
湖北省-随州市
**湖南省**
湖南省-长沙市
湖南省-株洲市
湖南省-湘潭市
湖南省-衡阳市
湖南省-邵阳市
湖南省-岳阳市
湖南省-常德市
湖南省-张家界市
湖南省-益阳市
湖南省-郴州市
湖南省-永州市
湖南省-怀化市
湖南省-娄底市
**广东省**
广东省-广州市
广东省-韶关市
广东省-深圳市
广东省-珠海市
广东省-汕头市
广东省-佛山市
广东省-江门市
广东省-湛江市
广东省-茂名市
广东省-肇庆市
广东省-惠州市
广东省-梅州市
广东省-汕尾市
广东省-河源市
广东省-阳江市
广东省-清远市
广东省-东莞市
广东省-中山市
广东省-潮州市
广东省-揭阳市
广东省-云浮市
**广西壮族自治区**
广西壮族自治区-南宁市
广西壮族自治区-柳州市
广西壮族自治区-桂林市
广西壮族自治区-梧州市
广西壮族自治区-北海市
广西壮族自治区-防城港市
广西壮族自治区-钦州市
广西壮族自治区-贵港市
广西壮族自治区-玉林市
广西壮族自治区-百色市
广西壮族自治区-贺州市
广西壮族自治区-河池市
广西壮族自治区-来宾市
广西壮族自治区-崇左市
**海南省**
海南省-海口市
海南省-三亚市
海南省-三沙市
海南省-儋州市
**四川省**
四川省-成都市
四川省-自贡市
四川省-攀枝花市
四川省-泸州市
四川省-德阳市
四川省-绵阳市
四川省-广元市
四川省-遂宁市
四川省-内江市
四川省-乐山市
四川省-南充市
四川省-眉山市
四川省-宜宾市
四川省-广安市
四川省-达州市
四川省-雅安市
四川省-巴中市
四川省-资阳市
**贵州省**
贵州省-贵阳市
贵州省-六盘水市
贵州省-遵义市
贵州省-安顺市
贵州省-毕节市
贵州省-铜仁市
**云南省**
云南省-昆明市
云南省-曲靖市
云南省-玉溪市
云南省-保山市
云南省-昭通市
云南省-丽江市
云南省-普洱市
云南省-临沧市
**西藏自治区**
西藏自治区-拉萨市
西藏自治区-日喀则市
西藏自治区-昌都市
西藏自治区-林芝市
西藏自治区-山南市
西藏自治区-那曲市
**陕西省**
陕西省-西安市
陕西省-铜川市
陕西省-宝鸡市
陕西省-咸阳市
陕西省-渭南市
陕西省-汉中市
陕西省-延安市
陕西省-榆林市
陕西省-安康市
陕西省-商洛市
**甘肃省**
甘肃省-兰州市
甘肃省-嘉峪关市
甘肃省-金昌市
甘肃省-白银市
甘肃省-天水市
甘肃省-武威市
甘肃省-张掖市
甘肃省-平凉市
甘肃省-酒泉市
甘肃省-庆阳市
甘肃省-定西市
甘肃省-陇南市
**青海省**
青海省-西宁市
青海省-海东市
**宁夏回族自治区**
宁夏回族自治区-银川市
宁夏回族自治区-石嘴山市
宁夏回族自治区-吴忠市
宁夏回族自治区-固原市
宁夏回族自治区-中卫市
**新疆维吾尔自治区**
新疆维吾尔自治区-乌鲁木齐市
新疆维吾尔自治区-克拉玛依市
新疆维吾尔自治区-吐鲁番市
新疆维吾尔自治区-哈密市
**直辖市(与省平级)**
北京市
天津市
上海市
重庆市
**特别行政区**
香港特别行政区
澳门特别行政区
**台湾省**
台湾省

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,251 @@
# 项目管理模块 - HTTP回调设计方案备选方案
> **文档状态**: 备选方案存档
> **当前实现**: 接口注入方式(参见 `2-rmdc-project-management-DDS.md` 第3.4节)
> **适用场景**: 未来微服务化部署时可考虑迁移到此方案
---
## 1. 概述
本文档描述项目与工单模块之间基于 **HTTP 回调** 的状态同步机制。当系统需要分布式部署时,可考虑从当前的"接口注入"方式迁移到此方案。
### 1.1 设计原则
项目模块(`rmdc-project-management`)调用工单模块(`rmdc-work-procedure`)创建和管理工单,工单状态变更需要同步更新项目的生命周期状态。采用 **HTTP 回调机制 + 领域事件** 的设计模式实现状态同步。
> **核心思想**:工单状态变更时,由工单模块主动 HTTP 回调项目模块,项目模块根据事件类型更新自身的生命周期状态。
---
## 2. 架构设计
### 2.1 时序图
```mermaid
sequenceDiagram
participant PM as rmdc-project-management
participant WP as rmdc-work-procedure
participant DB as Database
Note over PM,WP: 回调机制:工单状态变更 → 回调业务模块 → 更新项目状态
PM->>WP: 1. 创建工单 (携带回调配置)
WP->>DB: 2. 存储工单 + 回调配置
WP-->>PM: 3. 返回 workflow_id
Note over WP: 工单状态变更事件发生...
WP->>WP: 4. 状态机转换 (pending_review → approved)
WP->>PM: 5. HTTP回调 /api/project/workflow-callback
PM->>PM: 6. 解析事件,更新项目 lifecycle_status
PM-->>WP: 7. 确认回调成功
WP->>DB: 8. 标记回调已完成
```
### 2.2 为什么不算循环依赖
虽然调用关系形成了"环",但这是 **松耦合的事件通知模式**,不是真正的循环依赖:
| 依赖类型 | 说明 | 是否存在 | 问题程度 |
|:---|:---|:---|:---|
| **编译依赖** | 模块A的代码import模块B | ❌ 不存在 | - |
| **启动依赖** | 模块A启动必须依赖模块B先启动 | ⚠️ 单向 | 低 |
| **运行时调用** | 模块A在运行时调用模块B的API | ✅ 双向 | 需设计 |
| **逻辑依赖** | 模块A的业务逻辑依赖模块B的存在 | ⚠️ 单向 | 低 |
**关键点**工单模块不import项目模块任何代码只知道一个回调URL字符串两个模块在代码层面完全解耦。
---
## 3. 回调配置设计
### 3.1 创建工单时注册回调
```go
// 项目模块创建工单时,注册回调配置
type CreateWorkflowRequest struct {
ModuleCode string `json:"module_code"` // "project_management"
WorkflowType string `json:"workflow_type"` // "project_detail" / "project_modify"
// ... 其他字段 ...
// 回调配置
CallbackConfig *CallbackConfig `json:"callback_config"`
}
type CallbackConfig struct {
// 回调URL工单状态变更时调用
CallbackURL string `json:"callback_url"` // "/api/project/workflow-callback"
// 关注的事件列表(只回调这些事件)
SubscribedEvents []string `json:"subscribed_events"` // ["submit", "approve", "return", "revoke"]
// 业务上下文(回调时原样返回)
BusinessContext map[string]interface{} `json:"business_context"` // {"project_id": "xxx"}
}
```
### 3.2 回调请求结构
```go
// 工单模块发起的回调请求
type WorkflowCallbackRequest struct {
WorkflowID string `json:"workflow_id"`
WorkflowType string `json:"workflow_type"`
Event string `json:"event"` // "approve", "return", "submit" 等
FromStatus string `json:"from_status"`
ToStatus string `json:"to_status"`
OperatorID int64 `json:"operator_id"`
OperatorName string `json:"operator_name"`
BusinessContext map[string]interface{} `json:"business_context"`
Timestamp time.Time `json:"timestamp"`
}
```
---
## 4. 回调处理实现
### 4.1 项目模块接收回调
```go
// 项目模块 - 接收工单回调并更新项目状态
func (h *ProjectHandler) WorkflowCallback(c *gin.Context) {
var req WorkflowCallbackRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.Error(c, errcode.InvalidParams)
return
}
// 幂等性检查
idempotencyKey := fmt.Sprintf("%s:%s:%d", req.WorkflowID, req.Event, req.Timestamp.Unix())
if h.cache.Exists(idempotencyKey) {
response.Success(c, nil) // 幂等返回成功
return
}
projectID := req.BusinessContext["project_id"].(string)
// 根据工单事件映射项目生命周期状态
newLifecycleStatus := h.mapWorkflowEventToLifecycle(req.Event, req.ToStatus, req.WorkflowType)
if newLifecycleStatus != "" {
err := h.projectService.UpdateLifecycleStatus(c, projectID, newLifecycleStatus)
if err != nil {
response.Error(c, errcode.InternalError)
return
}
}
// 标记已处理设置24小时过期
h.cache.Set(idempotencyKey, "1", 24*time.Hour)
response.Success(c, nil)
}
```
### 4.2 事件到生命周期状态的映射
```go
// 事件到生命周期状态的映射
func (h *ProjectHandler) mapWorkflowEventToLifecycle(event, toStatus, workflowType string) string {
// 填写工单
if workflowType == "project_detail" {
switch event {
case "create": // 创建工单
return "DRAFTING"
case "submit": // 提交审核
return "REVIEWING"
case "return": // 审核打回
return "DRAFTING"
case "approve": // 审核通过
return "RELEASED"
case "revoke": // 撤销工单
return "INIT"
}
}
// 修改工单
if workflowType == "project_modify" {
switch event {
case "create": // 发起修改
return "MODIFYING"
case "submit": // 提交审核
return "REVIEWING"
case "return": // 审核打回
return "MODIFYING"
case "approve": // 审核通过
return "RELEASED"
case "revoke": // 撤销工单
return "RELEASED" // 撤销后恢复为 RELEASED
}
}
return ""
}
```
---
## 5. 风险处理
| 风险 | 解决方案 |
|:---|:---|
| **回调再次调用工单API导致死循环** | 回调处理中只更新项目状态不调用工单API |
| **回调失败导致状态不一致** | 工单模块实现重试机制3次重试 + 指数退避) |
| **回调请求超时阻塞工单流程** | 设置短超时5秒或完全异步化 |
| **重复回调导致重复处理** | 使用 `workflow_id + event + timestamp` 作为幂等键 |
---
## 6. 回调失败重试表
```go
// 工单模块 - 回调失败时存储待重试
type CallbackRetry struct {
ID int64 `gorm:"primaryKey;autoIncrement" json:"id"`
WorkflowID string `gorm:"type:varchar(64);index" json:"workflow_id"`
CallbackURL string `gorm:"type:varchar(256)" json:"callback_url"`
Payload string `gorm:"type:text" json:"payload"` // JSON
RetryCount int `gorm:"default:0" json:"retry_count"` // 已重试次数
MaxRetries int `gorm:"default:3" json:"max_retries"` // 最大重试次数
NextRetryAt time.Time `json:"next_retry_at"` // 下次重试时间
Status string `gorm:"type:varchar(16);default:'pending'" json:"status"` // pending/success/failed
LastError string `gorm:"type:text" json:"last_error"` // 最后一次错误信息
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```
---
## 7. 与接口注入方式的对比
| 特性 | HTTP回调本方案 | 接口注入(当前实现) |
|:---|:---|:---|
| **模块解耦** | ✅ 完全解耦仅URL字符串 | ⚠️ 接口级解耦 |
| **分布式支持** | ✅ 支持 | ❌ 不支持 |
| **性能** | ⚠️ 网络开销 | ✅ 进程内调用 |
| **复杂度** | ⚠️ 需要重试/幂等处理 | ✅ 简单直接 |
| **事务一致性** | ⚠️ 最终一致性 | ✅ 强一致性 |
| **适用场景** | 微服务架构 | 模块化单体架构 |
---
## 8. 迁移指南
如果未来需要从"接口注入"迁移到"HTTP回调",需要:
1. **工单模块**
- 实现 HTTP 客户端发起回调
- 添加回调配置存储
- 实现重试机制和 `callback_retries`
2. **项目模块**
- 实现 `/api/project/workflow-callback` 接口
- 添加幂等性检查Redis/缓存)
- 删除 `ProjectLifecycleUpdater` 接口注入逻辑
3. **rmdc-core**
- 删除 `ProjectWorkflowCallback` 适配器
- 删除 `workflowSvc.SetProjectLifecycleUpdater()` 调用

View File

@@ -0,0 +1,229 @@
# RMDC-watchdog详细设计说明书
### 项目归属模块
1. 包含的模块及对应的目录
1. wdd.io/RMDC/rmdc-project-management
2. wdd.io/RMDC/rmdc-watchdog
3. wdd.io/RMDC/rmdc-watchdog-agent
4. wdd.io/RMDC/rmdc-watchdog-node
## 授权系统说明
```概述```
1. rmdc-project-management是一级授权中心
1. 授权所有二级授权中心
2. 维护二级授权中心的授权信息
3. 该模块之前为 rmdc-watchdog-center
1. 但是由于功能单一并且与rmdc-project-management功能冲突
2. 该模块已被移除并且功能完全移动至rmdc-project-management中实现
2. RMDC-watchdog作为项目授权中心(二级授权中心)
1. 接受来自RMDC-watchdog-node的主机信息,唯一主机信息加密
2. 将授权文件上传至rmdc-project-management
3. 接受来自rmdc-project-management的授权文件,并解析授权信息
4. 接受来自RMDC-watchdog-agent的心跳查询是否授权信息
5. 向RMDC-watchdog-agent发送已授权信息,避免agent自毁
3. RMDC-watchdog-agent是嵌入到业务运行的启动器
1. 监控业务运行的一切
2. 向RMDC-watchdog发送心跳查询是否授权信息
3. 若长时间未被授权,则自毁
4. 解析RMDC-watchdog的心跳回复,确保不会自毁
5. 设计方案类似于 死手系统
4. RMDC-watchdog-node是以daemonset运行
1. 只暴露有限的、经过审计的操作接口(重启服务、收集日志、健康检查等),通过严格认证与授权调用,只能接受来自RMDC-watchdog的调用
2. 可以收集每台主机的运行状态信息
1. CPU
2. 内存
3. 磁盘
4. 网络
5. 授权系统防篡改核心
1. TOTP算法防止信息篡改
2. 每个项目的二级授权中心密钥均不同
3. 每个项目的一级授权中心密钥均不同
4. rmdc-project-management和RMDC-watchdog之间交互信息需要加密
5. RMDC-watchdog和RMDC-watchdog-agent之间交互信息不需要加密但是首先需要验证TOTP码
6. 取消授权
1. rmdc-project-management应该可以取消对一个项目的授权
2. RMDC-watchdog应该有相应的接口,能够接收取消授权
1. 取消特定主机的授权
7. 授权时间
1. rmdc-project-management应该能够设置授权时间
2. RMDC-watchdog应该新增授权时间管理功能,
1. 在解析授权文件中,应该解析授权时间,并设置授权时间
## Octopus Operator说明
### 运行环境说明
1. 有网络情况,通过RMDC-Exchange-Hub进行信息交互
1. 正常情况需要通过MQTT接收指令上传指令
2. 正常情况需要通过此种方式交互,无需认证
2. 无网络情况
1. 不正常情况无法接收MQTT指令无法上传指令
2. 预留HTTP端口暴露用于特殊情况访问
3. 通过此种方式调用复用二级授权中心的TOTP密钥,进行认证
### K8S Operator
``` 功能模块归属 rmdc-watchdog ```
#### 业务信息管理
1. 能够获取命名空间内的所有如下信息
1. StatefulSet
2. Deployment
3. DaemonSet
4. Pod
5. ReplicaSet
6. Service
7. ConfigMap
8. Secret
2. 上述的内容均支持筛选查询
3. 上述内容均支持yaml文件编辑
4. 上述内容均支持删除
5. 上述内容均支持创建
6. 上述内容均支持复制
#### K8S信息管理
1. 能够获取k8s的所有如下信息
1. 主机节点信息
2. Ingress信息
#### 业务详情
1. 业务的部署模式为Deployment,能够获取到业务的详情
2. 针对下面的内容均有 查看和编辑能力
1. 副本数量
2. 镜像版本
3. 环境变量
4. JVM参数
3. 该业务的历史版本信息
1. 通过同名的ReplicaSets获取
2. 历史版本创建时间
4. 业务镜像的运行环境变量
1. 在镜像构建的时候, GIT_BRANCH GIT_COMMIT信息保存在docker image中
2. 业务镜像的运行环境变量包含GIT_BRANCH GIT_COMMIT信息此部分需要能够一键获取到
#### 中间件详情
1. 中间件的部署模式为StatefulSet
2. 针对特定的中间件,需要有监视、信息查看、编辑、删除、重启等能力
1. MySQL
2. Redis
3. MQTTX
4. InfluxDB
### 向上-信息交互 wdd.io/RMDC/rmdc-exchange-hub
请参照 [1-rmdc-exchange-hub-DDS.md](0-设计方案\3-信息交换ExchangeHub\1-rmdc-exchange-hub-DDS.md)
中项目启动注册流程-正常的rmdc-watchdog启动流程的详细流程
### 向下-信息交互 rmdc-watchdog-agent rmdc-watchdog-node
#### 集群信息收集
1. 收集主机运行状态信息
1. from rmdc-watchdog-node
2. 收集简单信息
1. 主机名称
2. 主机IP
3. 主机CPU使用率
4. 主机内存使用率
5. 主机磁盘使用率
6. 主机网络使用率
3. 收集详细信息
1. 主机磁盘的详细使用情况,包含每个目录,排除linux系统的特殊目录
2. 主机内存的详细使用情况
3. 主机CPU的详细使用情况
4. 主机网络的详细使用情况
2. 收集k8s集群运行状态信息
1. from 自身
2. 收集简单信息
1. k8s集群名称
2. k8s集群版本
3. k8s集群节点数量
4. k8s集群CPU使用率
5. k8s集群内存使用率
6. k8s节点状态
7. k8s存活状态
8. k8s存活时间
2. 收集业务运行状态信息
1. from rmdc-watchdog-agent
2. 业务如果重启, agent需要向watchdog发送故障信息
1. 故障信息包括 业务名称, 运行主机信息,重启次数, 重启时间, 重启日志结存300行
2. 需要持久化
3. 收集简单信息
1. 业务名称
2. 业务存活状态
3. 业务存活时间
4. 业务CPU使用率
5. 业务内存使用率
4. 业务详细运行信息
1. JAVA 内存分析
2. JAVA 线程分析
3. JAVA GC分析
4. JAVA 类加载分析
5. JAVA 类卸载分析
#### 主机指令下发
1. 下发主机指令
1. to rmdc-watchdog-node
2. 下发业务指令
1. to rmdc-watchdog-agent
3. 下发K8S指令
1. to 自身
### 信息持久化
1. 上文中存在的说明的信息,需要持久化保存
2. 支持时间段所有信息导出
1. 提供HTTP端口,能够导出指定时间段的所有信息
3. 业务系统存在如下的中间件,可以考虑使用
1. MySQL数据库
2. Redis数据库
3. InfluxDB数据库
## Node Operator说明
```功能模块归属 rmdc-watchdog-node```
### DLTU - Download Load Tag Upload
1. 功能模块归属 rmdc-watchdog-node
2. 接收来自wdd.io/RMDC/rmdc-watchdog的指令
3. Download 下载镜像 从指定的url下载镜像压缩包至特定的目录保存
1. 需要考虑无公网的异常情况
2. 人工将压缩包防止在规定的目录中
3. 应该检测本地的镜像压缩包,判定是否存在
4. Load 加载镜像 从指定的目录加载镜像压缩包
5. Tag 标签镜像 为镜像打标签
6. Upload 上传镜像 将镜像推送到指定的Harbor仓库
## 运行状态与心跳策略
1. **状态机**`offline -> connecting -> verifying -> online -> disconnecting -> offline`,对应 exchange-hub 的在线状态表;心跳超时默认 30 秒转 offline。
2. **心跳频率**watchdog→exchange-hub 默认 5 秒agent/node→watchdog 默认 10 秒;支持配置,超时触发 notice-center 告警。
3. **缓存与补传**:指令结果、监控、日志上报在弱网下先写本地队列(容量 N按时间/大小回收),重连后批量补传。
## 安全与授权细化
1. **授权校验**watchdog 启动需验证一级 TOTPagent/node 请求需验证二级 TOTP授权文件到期需自动降级并通知项目管理。
2. **接口暴露**仅开放受审计的操作接口重启、日志收集、健康检查、DLTU默认拒绝除名单外的命令类型。
3. **防篡改**:所有下行指令校验签名 + TOTPagent 自毁前需等待 N 次连续授权失败确认。
## 监控与告警
1. **采集项**:主机 CPU/内存/磁盘/网络、Pod 状态、业务 JVM 指标、重启次数、上报延迟。
2. **指标维度**:按项目/主机/Pod 维度聚合,暴露给 monitor-center上报失败/延迟写入本地并告警。
3. **日志截断**:业务故障日志仅回传最近 300 行;超长日志切片上传,避免 MQTT/HTTP 负载过大。
## 数据留存与导出
1. **持久化**:主机/业务指标可选本地 InfluxDB 或 SQLite弱网时周期性清理过期数据默认 30 天)。
2. **导出**:提供 HTTP 端口导出指定时间段信息,需签名 + TOTP 校验;导出操作写审计。

View File

@@ -0,0 +1,699 @@
# RMDC-Watchdog 业务流程图
## 一、项目注册流程
### 1.1 完整的注册时序流程图
```mermaid
sequenceDiagram
autonumber
participant Admin as 管理员<br/>(RMDC Portal)
participant PM as rmdc-project-management<br/>(项目管理)
participant ExHub as rmdc-exchange-hub<br/>(消息网关)
participant MQTT as MQTT Broker
participant WD as rmdc-watchdog<br/>(二级授权中心)
participant Node as watchdog-node<br/>(主机守护)
participant Agent as watchdog-agent<br/>(业务代理)
rect rgb(200, 220, 255)
Note over Admin,Agent: ===== 阶段1: 项目创建 (RMDC平台侧) =====
end
Admin->>PM: 1. 创建新项目
PM->>PM: 2. 生成项目信息<br/>project_id = namespace_<8位随机数>
PM->>PM: 3. 生成一级授权密钥<br/>tier_one_secret = generateSecret()
PM->>PM: 4. 生成二级授权密钥<br/>tier_two_secret = generateSecret()
PM->>PM: 5. 生成时间偏移值<br/>time_offset_allowed
PM->>PM: 6. 持久化项目信息<br/>{project_id, namespace,<br/>tier_one_secret, tier_two_secret,<br/>auth_duration, time_offset_allowed}
PM-->>Admin: 7. 返回项目配置文件<br/>(包含tier_one_secret和tier_two_secret<br/>用于部署Watchdog)
rect rgb(220, 255, 220)
Note over Admin,Agent: ===== 阶段2: Watchdog启动与MQTT连接 =====
end
Note over WD: 使用项目配置文件部署<br/>本地已有tier_one_secret和tier_two_secret<br/>(密钥不通过公网传输)
WD->>MQTT: 8. 连接MQTT Broker
WD->>WD: 9. 创建MQTT订阅<br/>订阅: wdd/RDMC/command/down/<project_id><br/>订阅: wdd/RDMC/message/down/<project_id>
rect rgb(255, 240, 220)
Note over Admin,Agent: ===== 阶段3: 项目注册 - 挑战应答机制 =====
end
WD->>WD: 10. 生成Tier-One TOTP验证码<br/>(8位, 30分钟有效)<br/>使用本地tier_one_secret
WD->>MQTT: 11. 发布注册Command到<br/>wdd/RDMC/command/up<br/>{type:"register", project_id,<br/>namespace, totp_code, env_info}
MQTT->>ExHub: 12. 转发注册Command
ExHub->>PM: 13. 验证项目信息合法性<br/>GetProjectInfo(project_id)
PM-->>ExHub: 14. 返回项目密钥等信息<br/>{tier_one_secret, tier_two_secret}
ExHub->>ExHub: 15. 验证TOTP验证码 (可配置开关)<br/>VerifyTierOneTOTP(totp_code, tier_one_secret)
alt TOTP验证成功 或 验证已关闭
ExHub->>ExHub: 16. 生成32位随机挑战码<br/>challenge = randomString(32)
ExHub->>ExHub: 17. 生成服务端TOTP响应码<br/>server_totp = GenerateTierOneTOTP(tier_one_secret)
ExHub->>ExHub: 18. 记录挑战码到缓存<br/>cache[project_id] = challenge
ExHub->>MQTT: 19. 发布注册确认Message到<br/>wdd/RDMC/message/down/<project_id><br/>{type:"register_ack", challenge, server_totp}
ExHub->>MQTT: 20. 发布授权Command到<br/>wdd/RDMC/command/down/<project_id><br/>{type:"auth_response", success:true}<br/>(不传输密钥,密钥已在本地)
else TOTP验证失败
ExHub->>MQTT: 发布注册拒绝<br/>{type:"register_reject", reason}
end
MQTT->>WD: 21. 推送注册确认Message
MQTT->>WD: 22. 推送授权Command
WD->>WD: 23. 验证服务端TOTP (可配置开关)<br/>VerifyTierOneTOTP(server_totp, tier_one_secret)
alt 服务端TOTP验证成功 或 验证已关闭
WD->>WD: 24. 确认tier_two_secret有效<br/>(使用本地已有的密钥)
WD->>WD: 25. 解析challenge挑战码
WD->>MQTT: 26. 发布注册完成Message到<br/>wdd/RDMC/message/up<br/>{type:"register_complete",<br/>project_id, challenge}
else 服务端TOTP验证失败
Note over WD: 注册失败,服务端验证不通过<br/>可能是中间人攻击
end
MQTT->>ExHub: 27. 转发注册完成Message
ExHub->>ExHub: 28. 验证challenge匹配<br/>cache[project_id] == received_challenge
alt 挑战验证成功
ExHub->>ExHub: 29. 更新项目状态为Online<br/>UpdateProjectState(project_id, "online")
ExHub->>PM: 30. 通知项目上线
PM->>PM: 31. 更新项目在线状态
Note over WD: 注册成功,开始正常工作
else 挑战验证失败
ExHub->>MQTT: 发布验证失败消息
Note over WD: 注册失败,等待重试
end
rect rgb(220, 240, 255)
Note over Admin,Agent: ===== 阶段4: 心跳维持 =====
end
loop 每5秒
WD->>MQTT: 发布心跳Message到<br/>wdd/RDMC/message/up<br/>{type:"heartbeat", metrics}
MQTT->>ExHub: 转发心跳
ExHub->>ExHub: 刷新项目在线状态
end
```
### 1.2 注册流程关键设计说明
| 设计要点 | 说明 |
|----------|------|
| **密钥生成时机** | tier_one_secret 和 tier_two_secret 均在 rmdc-project-management 创建项目时生成 |
| **密钥传输方式** | 密钥通过项目配置文件离线部署到 Watchdog**不通过公网MQTT传输** |
| **双向TOTP验证** | Watchdog 发送 TOTP 给 ExHub 验证ExHub 返回 TOTP 给 Watchdog 验证 (可配置开关) |
| **挑战应答机制** | 32位随机挑战码确保通信双方身份真实性 |
| **安全增强** | 即使 MQTT 被监听,攻击者也无法伪造有效的 TOTP 验证码 |
---
## 二、授权系统完整流程
### 2.1 授权系统总览架构
```mermaid
graph TB
subgraph "RMDC平台 (内网)"
PM["rmdc-project-management<br/>项目管理"]
CENTER["rmdc-watchdog-center<br/>一级授权中心"]
EXHUB["rmdc-exchange-hub<br/>消息网关"]
DB[(授权数据库)]
end
subgraph "项目环境 (外网/隔离网络)"
WATCHDOG["rmdc-watchdog<br/>二级授权中心"]
AGENT1["watchdog-agent<br/>业务A"]
AGENT2["watchdog-agent<br/>业务B"]
NODE1["watchdog-node<br/>主机1"]
NODE2["watchdog-node<br/>主机2"]
end
PM --"1.项目创建"--> CENTER
CENTER --"2.授权配置"--> PM
CENTER <--"3.授权申请/下发<br/>Tier-One TOTP"--> EXHUB
EXHUB <==" 4.MQTT公网"==> WATCHDOG
NODE1 --"5.主机信息上报"--> WATCHDOG
NODE2 --"5.主机信息上报"--> WATCHDOG
AGENT1 <--"6.心跳/授权<br/>Tier-Two TOTP"--> WATCHDOG
AGENT2 <--"6.心跳/授权<br/>Tier-Two TOTP"--> WATCHDOG
CENTER --> DB
PM --> DB
style CENTER fill:#ff6b6b
style WATCHDOG fill:#4ecdc4
style EXHUB fill:#ffd43b
style PM fill:#a9e34b
```
### 2.2 授权申请与下发流程
```mermaid
sequenceDiagram
autonumber
participant Node as rmdc-watchdog-node<br/>(主机)
participant Watchdog as rmdc-watchdog<br/>(二级授权中心)
participant MQTT as Exchange-Hub<br/>(MQTT)
participant Center as rmdc-watchdog-center<br/>(一级授权中心)
participant DB as 授权数据库
rect rgb(200, 220, 255)
Note over Node,DB: ===== 阶段1: 主机信息收集 =====
end
Note over Node: 项目启动,以DaemonSet运行
Node->>Watchdog: 1. 上报主机硬件信息<br/>{MachineID, CPU, Memory, Serial, IP}
Watchdog->>Watchdog: 2. 加密主机信息<br/>EncryptHostInfo(hostInfo, tierOneSecret)
Watchdog->>Watchdog: 3. 生成授权申请文件<br/>GenerateAuthorizationFile()
Note over Watchdog: 授权文件包含:<br/>- EncryptedHostMap<br/>- TOTPCode (8位,30分钟有效)<br/>- EncryptedNamespace
rect rgb(220, 255, 220)
Note over Node,DB: ===== 阶段2: 授权申请 =====
end
Watchdog->>MQTT: 4. 发布授权申请Command到<br/>wdd/RDMC/command/up<br/>{type:"auth_request", AuthorizationFile}
MQTT->>Center: 5. 转发授权申请
Center->>Center: 6. 解密项目命名空间<br/>Decrypt(EncryptedNamespace)
Center->>DB: 7. 获取项目信息<br/>GetProjectInfo(namespace)
DB-->>Center: 返回项目密钥等信息
Center->>Center: 8. 验证TOTP验证码<br/>VerifyTierOneTOTPCode()
Center->>Center: 9. 验证主机信息完整性<br/>DecryptHostInfo() 逐个验证
rect rgb(255, 240, 220)
Note over Node,DB: ===== 阶段3: 授权下发 =====
end
alt 验证成功
Center->>Center: 10. 生成新TOTP验证码
Center->>Center: 11. 构造授权码<br/>{authorized_hosts, expire_time, tier_two_secret}
Center->>DB: 12. 持久化授权记录
Center->>MQTT: 13. 发布授权码到<br/>wdd/RDMC/command/down/{project_id}<br/>{type:"auth_response", AuthorizationCode}
else 验证失败
Center->>MQTT: 发布授权拒绝消息<br/>{type:"auth_reject", reason}
end
MQTT->>Watchdog: 14. 推送授权码
Watchdog->>Watchdog: 15. 验证返回的TOTP
Watchdog->>Watchdog: 16. 解密并验证命名空间
Watchdog->>Watchdog: 17. 解密每个主机信息
Watchdog->>Watchdog: 18. 计算时间偏移<br/>timeOffset = now - firstAuthTime
Watchdog->>Watchdog: 19. 持久化保存授权信息<br/>saveAuthorizationInfo()
Note over Watchdog: 授权存储包含:<br/>- EncryptedAuthorizationCode<br/>- FirstAuthTime<br/>- TimeOffset<br/>- AuthorizedHostMap<br/>- TierTwoTOTPSecret
```
### 2.3 Agent授权心跳流程
```mermaid
sequenceDiagram
autonumber
participant Agent as rmdc-watchdog-agent<br/>(业务启动器)
participant Watchdog as rmdc-watchdog<br/>(二级授权中心)
participant Business as 业务进程<br/>(Java/Python)
rect rgb(200, 255, 200)
Note over Agent,Business: ===== 首次连接 - 获取密钥 =====
end
Agent->>Agent: 1. 收集主机信息<br/>GetAllInfo()
Agent->>Watchdog: 2. 发送心跳请求<br/>{HostInfo, EnvInfo, Timestamp, TOTPCode=""}
Watchdog->>Watchdog: 3. 验证时间戳有效性<br/>|now - timestamp| < 5分钟
Watchdog->>Watchdog: 4. 添加主机到集合<br/>AddHostInfo()
Watchdog-->>Agent: 5. 返回响应<br/>{Authorized:false, TierTwoSecret:secret}
Agent->>Agent: 6. 保存TOTP密钥<br/>tierTwoTotpSecret = secret
rect rgb(220, 255, 220)
Note over Agent,Business: ===== 后续心跳 - 授权验证 =====
end
loop 心跳循环 (成功后2小时,失败后1小时)
Agent->>Agent: 7. 生成TOTP验证码<br/>GenerateTierTwoTOTPCode(secret)<br/>6位,30秒有效
Agent->>Watchdog: 8. 发送心跳请求<br/>{HostInfo, Timestamp, TOTPCode}
Watchdog->>Watchdog: 9. 验证TOTP验证码<br/>VerifyTierTwoTOTPCode()
alt TOTP验证成功
Watchdog->>Watchdog: 10. 检查主机授权状态<br/>IsHostAuthorized(hostInfo)
Watchdog->>Watchdog: 11. 生成响应TOTP
Watchdog-->>Agent: 12. 返回{Authorized:true/false, TOTPCode}
Agent->>Agent: 13. 验证服务端TOTP<br/>双向验证
alt 授权成功
Agent->>Agent: 14. failCount = 1<br/>等待2小时
else 授权失败
Agent->>Agent: 15. failCount++<br/>等待1小时
end
else TOTP验证失败
Watchdog-->>Agent: 返回错误:无效的TOTP验证码
Agent->>Agent: failCount++
end
alt failCount >= 12
Agent->>Business: 16. 发送SIGTERM信号
Note over Business: 业务进程终止<br/>(死手系统触发)
end
end
```
### 2.4 授权撤销流程
```mermaid
sequenceDiagram
autonumber
participant Admin as 管理员<br/>(RMDC Portal)
participant PM as project-management
participant Center as rmdc-watchdog-center<br/>(一级授权中心)
participant MQTT as Exchange-Hub<br/>(MQTT)
participant Watchdog as rmdc-watchdog<br/>(二级授权中心)
participant Agent as rmdc-watchdog-agent
participant Business as 业务进程
rect rgb(255, 220, 220)
Note over Admin,Business: ===== 授权撤销流程 =====
end
Admin->>PM: 1. 发起撤销授权请求<br/>{project_id, reason}
PM->>Center: 2. 请求撤销项目授权
Center->>Center: 3. 更新项目授权状态<br/>status = revoked
Center->>Center: 4. 生成撤销Command<br/>{type:"auth_revoke", project_id, totp}
Center->>MQTT: 5. 发布撤销Command到<br/>wdd/RDMC/command/down/{project_id}
MQTT->>Watchdog: 6. 推送撤销指令
Watchdog->>Watchdog: 7. 验证撤销指令TOTP
Watchdog->>Watchdog: 8. 清除本地授权存储<br/>deleteAuthorizationInfo()
Watchdog->>Watchdog: 9. 设置授权状态为未授权<br/>initialized = false
Note over Agent: 下次心跳时...
Agent->>Watchdog: 10. 发送心跳请求
Watchdog-->>Agent: 11. 返回{Authorized:false}
Agent->>Agent: 12. failCount++
Note over Agent: 连续失败12次后...
Agent->>Business: 13. 发送SIGTERM信号<br/>触发业务进程终止
Note over Business: 业务自毁<br/>死手系统生效
Watchdog->>MQTT: 14. 上报撤销完成消息<br/>{type:"auth_revoke_ack"}
MQTT->>Center: 15. 转发撤销确认
Center->>PM: 16. 更新项目状态
PM->>Admin: 17. 通知撤销成功
```
---
## 三、K8S指令执行流程
### 3.1 K8S指令业务流程图
```mermaid
sequenceDiagram
autonumber
participant User as 用户<br/>(RMDC Portal)
participant Api as rmdc-core<br/>(API Gateway)
participant Operator as octopus-operator<br/>(执行中心)
participant ExHub as rmdc-exchange-hub<br/>(消息网关)
participant MQTT as MQTT Broker
participant WD as rmdc-watchdog<br/>(K8s Operator)
participant K8s as Kubernetes API
rect rgb(200, 220, 255)
Note over User,K8s: ===== 阶段1: 指令发起 =====
end
User->>Api: 1. 发起K8S操作请求<br/>{project_id, action, resource, name}
Api->>Api: 2. 验证用户权限<br/>CheckPermission(user, project, action)
Api->>Operator: 3. 调用执行中心API
Operator->>Operator: 4. 构造K8S执行指令<br/>K8sExecCommand{<br/> command_id, namespace,<br/> resource, name, action,<br/> command, timeout<br/>}
Operator->>ExHub: 5. 调用指令下发API<br/>POST /api/command/send
ExHub->>ExHub: 6. 生成唯一CommandID<br/>记录指令到数据库<br/>状态: Pending
ExHub->>MQTT: 7. 发布K8S执行Command到<br/>wdd/RDMC/command/down/{project_id}<br/>{type:"k8s_exec", payload}
rect rgb(220, 255, 220)
Note over User,K8s: ===== 阶段2: 指令执行 =====
end
MQTT->>WD: 8. 推送K8S执行指令
WD->>WD: 9. 解析指令<br/>路由到K8sHandler
WD->>WD: 10. 记录开始时间<br/>status = running
alt action == "logs"
WD->>K8s: 11a. 调用K8S API<br/>GetPodLogs(namespace, name, container)
else action == "exec"
WD->>K8s: 11b. 调用K8S API<br/>ExecCommand(pod, container, command)
else action == "scale"
WD->>K8s: 11c. 调用K8S API<br/>ScaleDeployment(name, replicas)
else action == "restart"
WD->>K8s: 11d. 调用K8S API<br/>RolloutRestart(deployment)
else action == "delete"
WD->>K8s: 11e. 调用K8S API<br/>DeleteResource(resource, name)
end
K8s-->>WD: 12. 返回执行结果
rect rgb(255, 240, 220)
Note over User,K8s: ===== 阶段3: 结果返回 =====
end
WD->>WD: 13. 构造执行结果<br/>ExecResult{command_id, status,<br/>exit_code, output, error, duration}
WD->>MQTT: 14. 发布结果Message到<br/>wdd/RDMC/message/up<br/>{type:"exec_result", payload}
MQTT->>ExHub: 15. 转发执行结果
ExHub->>ExHub: 16. 更新指令状态<br/>记录执行时长
ExHub->>Operator: 17. 推送结果给执行中心
Operator->>Api: 18. 返回执行结果
Api->>User: 19. 展示执行结果
```
### 3.2 K8S支持的操作类型
| Action | 说明 | 目标资源 | 参数 |
|--------|------|----------|------|
| `logs` | 获取日志 | Pod | container, tail_lines, follow |
| `exec` | 执行命令 | Pod | container, command[], timeout |
| `scale` | 扩缩容 | Deployment/StatefulSet | scale_count |
| `restart` | 滚动重启 | Deployment/StatefulSet | - |
| `delete` | 删除资源 | Pod/Deployment/Service等 | - |
| `get` | 获取信息 | 任意资源 | output_format |
| `apply` | 应用配置 | 任意资源 | yaml_content |
---
## 四、主机指令执行流程
### 4.1 主机指令业务流程图
```mermaid
sequenceDiagram
autonumber
participant User as 用户<br/>(RMDC Portal)
participant Api as rmdc-core<br/>(API Gateway)
participant Operator as octopus-operator<br/>(执行中心)
participant ExHub as rmdc-exchange-hub<br/>(消息网关)
participant MQTT as MQTT Broker
participant WD as rmdc-watchdog<br/>(二级授权中心)
participant Node as watchdog-node<br/>(主机守护)
rect rgb(200, 220, 255)
Note over User,Node: ===== 阶段1: 指令发起 =====
end
User->>Api: 1. 发起主机操作请求<br/>{project_id, host_id, action, script}
Api->>Api: 2. 验证用户权限<br/>CheckPermission(user, project, "host_exec")
Api->>Operator: 3. 调用执行中心API
Operator->>Operator: 4. 构造主机执行指令<br/>HostExecCommand{<br/> command_id, host_id,<br/> action, script, args, timeout<br/>}
Operator->>ExHub: 5. 调用指令下发API<br/>POST /api/command/send
ExHub->>ExHub: 6. 生成唯一CommandID<br/>记录指令到数据库<br/>状态: Pending
ExHub->>MQTT: 7. 发布主机执行Command到<br/>wdd/RDMC/command/down/{project_id}<br/>{type:"host_exec", payload}
rect rgb(220, 255, 220)
Note over User,Node: ===== 阶段2: 指令转发与执行 =====
end
MQTT->>WD: 8. 推送主机执行指令
WD->>WD: 9. 解析指令<br/>路由到HostHandler
WD->>WD: 10. 验证目标主机在线<br/>CheckHostOnline(host_id)
alt 主机在线
WD->>Node: 11. 转发执行指令到目标Node<br/>HTTP POST /api/exec<br/>(内网通信,TOTP验证)
Node->>Node: 12. 验证请求合法性<br/>VerifyTOTP()
Node->>Node: 13. 执行命令/脚本<br/>ExecuteScript(script, args)
Node-->>WD: 14. 返回执行结果<br/>{exit_code, stdout, stderr}
else 主机离线
WD->>WD: 构造错误结果<br/>error = "目标主机离线"
end
rect rgb(255, 240, 220)
Note over User,Node: ===== 阶段3: 结果返回 =====
end
WD->>WD: 15. 构造执行结果<br/>ExecResult{command_id, status,<br/>exit_code, output, error, duration}
WD->>MQTT: 16. 发布结果Message到<br/>wdd/RDMC/message/up<br/>{type:"exec_result", payload}
MQTT->>ExHub: 17. 转发执行结果
ExHub->>ExHub: 18. 更新指令状态<br/>记录执行时长
ExHub->>Operator: 19. 推送结果给执行中心
Operator->>Api: 20. 返回执行结果
Api->>User: 21. 展示执行结果
```
### 4.2 Watchdog到Node的通信架构
```mermaid
graph TB
subgraph "rmdc-watchdog"
WD_Router[消息路由器]
WD_HostH[HostHandler]
WD_NodeClient[NodeClient<br/>HTTP Client]
end
subgraph "watchdog-node (DaemonSet)"
Node_Server[HTTP Server<br/>:8081]
Node_Auth[TOTP验证中间件]
Node_Exec[命令执行器]
Node_Info[信息收集器]
end
WD_Router --> WD_HostH
WD_HostH --> WD_NodeClient
WD_NodeClient ==HTTP/TOTP==> Node_Server
Node_Server --> Node_Auth
Node_Auth --> Node_Exec
Node_Auth --> Node_Info
style WD_NodeClient fill:#4ecdc4,stroke:#087f5b
style Node_Server fill:#a9e34b,stroke:#5c940d
```
### 4.3 主机支持的操作类型
| Action | 说明 | 参数 |
|--------|------|------|
| `exec` | 执行Shell命令 | script, args[], timeout |
| `info` | 获取主机信息 | info_type (cpu/memory/disk/network) |
| `service` | 服务管理 | service_name, operation (start/stop/restart) |
| `file` | 文件操作 | path, operation (read/write/delete) |
| `dltu` | 镜像操作 | operation (download/load/tag/upload), params |
---
## 五、同步指令设计方案
### 5.1 同步指令可行性分析
#### 适用场景分析
| 场景 | 当前模式 | 同步需求 | 实现建议 |
|------|----------|----------|----------|
| **日志查看** | 异步 | 高 - 需要实时看到日志输出 | 长轮询或推送 |
| **主机命令执行** | 异步 | 中 - 交互式命令需要实时 | 超时等待机制 |
| **K8S资源查询** | 异步 | 中 - 查询操作期望快速返回 | 超时等待机制 |
| **业务更新** | 异步 | 低 - 长时间操作适合异步 | 保持异步 + 通知 |
| **监控数据** | 异步 | 低 - 定期上报即可 | 保持异步 |
#### 技术挑战
1. **网络延迟**: 跨公网MQTT通信存在不确定延迟
2. **超时处理**: 需要合理设置超时时间避免长时间阻塞
3. **连接保持**: 长时间等待需要保持连接不断开
4. **资源占用**: 同步等待会占用服务器连接资源
### 5.2 基于现有架构的同步指令实现方案
#### 方案设计 (基于Go Channel + HTTP长轮询)
根据项目现有的Go技术栈,建议采用**HTTP长轮询 + 结果缓存**方案:
```mermaid
sequenceDiagram
autonumber
participant User as 用户
participant Api as API Gateway
participant ExHub as Exchange-Hub
participant Cache as ResultCache<br/>(sync.Map)
participant MQTT as MQTT Broker
participant WD as Watchdog
rect rgb(200, 220, 255)
Note over User,WD: ===== 同步指令发送 =====
end
User->>Api: 1. POST /api/command/sync<br/>{project_id, type, payload, timeout:30s}
Api->>ExHub: 2. 调用同步指令API
ExHub->>ExHub: 3. 生成CommandID
ExHub->>Cache: 4. 创建等待通道<br/>waitChan[cmdId] = make(chan Result)
ExHub->>MQTT: 5. 发布指令
MQTT->>WD: 6. 推送到Watchdog
rect rgb(220, 255, 220)
Note over User,WD: ===== 执行与等待 =====
end
WD->>WD: 7. 执行指令
WD->>MQTT: 8. 返回结果
MQTT->>ExHub: 9. 接收结果
ExHub->>Cache: 10. 发送结果到通道<br/>waitChan[cmdId] <- result
rect rgb(255, 240, 220)
Note over User,WD: ===== 结果返回 =====
end
ExHub->>ExHub: 11. select等待结果或超时
ExHub->>Api: 12. 返回执行结果
Api->>User: 13. 返回结果给用户
```
#### Exchange-Hub同步指令管理器设计
```go
// SyncCommandManager 同步指令管理器
type SyncCommandManager struct {
waitChannels sync.Map // map[commandID]chan *ExecResult
timeout time.Duration
}
// SendAndWait 发送指令并等待结果
func (m *SyncCommandManager) SendAndWait(projectID string, cmd *CommandMessage, timeout time.Duration) (*ExecResult, error) {
// 1. 创建等待通道
waitChan := make(chan *ExecResult, 1)
m.waitChannels.Store(cmd.MessageID, waitChan)
defer m.waitChannels.Delete(cmd.MessageID)
// 2. 发送指令
mqttService := GetMQTTService()
if err := mqttService.PublishCommand(projectID, cmd); err != nil {
return nil, err
}
// 3. 等待结果或超时
select {
case result := <-waitChan:
return result, nil
case <-time.After(timeout):
return nil, errors.New("command execution timeout")
}
}
// OnResult 接收结果回调
func (m *SyncCommandManager) OnResult(result *ExecResult) {
if ch, ok := m.waitChannels.Load(result.CommandID); ok {
ch.(chan *ExecResult) <- result
}
}
```
### 5.3 日志实时查看方案
对于日志实时查看场景,建议采用**流式日志推送**方案:
```mermaid
sequenceDiagram
autonumber
participant User as 用户
participant Frontend as 前端
participant Api as API Gateway
participant ExHub as Exchange-Hub
participant MQTT as MQTT Broker
participant WD as Watchdog
participant K8s as K8S API
User->>Frontend: 1. 点击查看实时日志
Frontend->>Api: 2. POST /api/logs/stream<br/>{project_id, pod, container, follow:true}
Api->>ExHub: 3. 创建日志流会话<br/>sessionId = uuid()
ExHub->>MQTT: 4. 发布日志查询指令<br/>{type:"log_query", follow:true, session_id}
MQTT->>WD: 5. 推送指令
WD->>K8s: 6. 调用K8S Logs API (follow=true)
loop 日志流
K8s-->>WD: 7. 返回日志行
WD->>MQTT: 8. 发布日志Message<br/>{type:"log_result", session_id, lines, is_complete:false}
MQTT->>ExHub: 9. 转发日志
ExHub->>ExHub: 10. 根据session_id路由
ExHub->>Api: 11. 推送到API会话
Api->>Frontend: 12. SSE/轮询返回日志
Frontend->>User: 13. 实时显示日志
end
User->>Frontend: 14. 停止查看
Frontend->>Api: 15. DELETE /api/logs/stream/{session_id}
Api->>ExHub: 16. 关闭日志流会话
ExHub->>MQTT: 17. 发布停止指令
```
#### 前端实现建议
```typescript
// 使用Server-Sent Events (SSE) 接收实时日志
async function streamLogs(projectId: string, pod: string, container: string) {
const response = await fetch(`/api/logs/stream`, {
method: 'POST',
body: JSON.stringify({ project_id: projectId, pod, container, follow: true })
});
const sessionId = (await response.json()).session_id;
// 使用SSE或长轮询接收日志
const eventSource = new EventSource(`/api/logs/stream/${sessionId}`);
eventSource.onmessage = (event) => {
const logData = JSON.parse(event.data);
appendLogToUI(logData.lines);
};
return {
stop: () => {
eventSource.close();
fetch(`/api/logs/stream/${sessionId}`, { method: 'DELETE' });
}
};
}
```
---
## 六、数据结构与安全机制汇总
### 6.1 MQTT Topic与消息类型对照表
| 方向 | Topic | 消息类型 | 说明 |
|------|-------|----------|------|
| **上行** | `wdd/RDMC/command/up` | `register` | 项目注册 |
| **上行** | `wdd/RDMC/command/up` | `auth_request` | 授权申请 |
| **上行** | `wdd/RDMC/message/up` | `register_complete` | 注册完成确认 |
| **上行** | `wdd/RDMC/message/up` | `heartbeat` | 心跳数据 |
| **上行** | `wdd/RDMC/message/up` | `monitor` | 监控数据上报 |
| **上行** | `wdd/RDMC/message/up` | `exec_result` | 指令执行结果 |
| **上行** | `wdd/RDMC/message/up` | `log_result` | 日志查询结果 |
| **上行** | `wdd/RDMC/message/up` | `alert` | 告警信息 |
| **下行** | `wdd/RDMC/command/down/{id}` | `auth_response` | 授权响应 |
| **下行** | `wdd/RDMC/command/down/{id}` | `auth_revoke` | 授权撤销 |
| **下行** | `wdd/RDMC/command/down/{id}` | `log_query` | 日志查询指令 |
| **下行** | `wdd/RDMC/command/down/{id}` | `host_exec` | 主机执行指令 |
| **下行** | `wdd/RDMC/command/down/{id}` | `k8s_exec` | K8S执行指令 |
| **下行** | `wdd/RDMC/command/down/{id}` | `update` | 业务更新指令 |
| **下行** | `wdd/RDMC/message/down/{id}` | `register_ack` | 注册确认消息 |
### 6.2 安全机制汇总
| 场景 | 安全机制 | 参数 |
|------|----------|------|
| Center ↔ Watchdog | Tier-One TOTP + AES-GCM | 8位码, 30分钟有效期, SHA256 |
| Watchdog ↔ Agent | Tier-Two TOTP | 6位码, 30秒有效期, SHA1 |
| Watchdog ↔ Node | Tier-Two TOTP复用 | 内网HTTP + TOTP认证 |
| HTTP备用接口 | 复用Tier-Two TOTP密钥 | 需要TOTP认证 |
| 主机信息 | 硬件指纹绑定 | MachineID+CPU+Memory+Serial |
| 死手系统 | 心跳失败自毁 | 连续12次失败触发 |
| 消息传输 | TLS加密 | MQTT over TLS |
| 敏感数据 | AES-256-GCM加密 | 授权码、密钥等 |

View File

@@ -0,0 +1,336 @@
# RMDC-Watchdog 内部交互流程
## 一、交互流程总览
本文档详细描述了RMDC-Watchdog系统内部各组件之间的交互流程包括Agent心跳上报、Node信息上报以及项目级别二级授权中心的完整业务流程。
### 1.1 组件关系图
```mermaid
graph TB
subgraph "项目环境 (K8S集群)"
WATCHDOG["rmdc-watchdog<br/>(二级授权中心)<br/>Port: 8990"]
AGENT1["rmdc-watchdog-agent<br/>业务Pod A"]
AGENT2["rmdc-watchdog-agent<br/>业务Pod B"]
NODE1["rmdc-watchdog-node<br/>节点1 (DaemonSet)"]
NODE2["rmdc-watchdog-node<br/>节点2 (DaemonSet)"]
end
NODE1 --"POST /api/node/info<br/>主机信息+运行指标"--> WATCHDOG
NODE2 --"POST /api/node/info<br/>主机信息+运行指标"--> WATCHDOG
AGENT1 <--"POST /api/heartbeat<br/>心跳+TOTP验证"--> WATCHDOG
AGENT2 <--"POST /api/heartbeat<br/>心跳+TOTP验证"--> WATCHDOG
style WATCHDOG fill:#4ecdc4
style AGENT1 fill:#ff8787
style AGENT2 fill:#ff8787
style NODE1 fill:#a9e34b
style NODE2 fill:#a9e34b
```
---
## 二、Agent心跳上报流程
Agent是嵌入到业务Pod中的启动器负责向Watchdog发送心跳请求进行授权验证。
### 2.1 首次连接流程
```mermaid
sequenceDiagram
autonumber
participant Agent as rmdc-watchdog-agent<br/>(业务启动器)
participant Watchdog as rmdc-watchdog<br/>(二级授权中心)
rect rgb(200, 255, 200)
Note over Agent,Watchdog: ===== 首次连接 - 获取TOTP密钥 =====
end
Agent->>Agent: 1. 收集环境信息<br/>GetEnvInfo()
Agent->>Agent: 2. 收集主机信息<br/>host_info.GetAllInfo()
Agent->>Watchdog: 3. POST /api/heartbeat<br/>{HostInfo, EnvInfo, Timestamp, TOTPCode=""}
Watchdog->>Watchdog: 4. 验证时间戳有效性<br/>|now - timestamp| < 5分钟
Watchdog->>Watchdog: 5. 添加主机信息到集合<br/>AddHostInfo()
Watchdog->>Watchdog: 6. 检测TOTPCode为空<br/>返回TOTP密钥
Watchdog-->>Agent: 7. 返回响应<br/>{Authorized:false, SecondTOTPSecret:secret}
Agent->>Agent: 8. 保存TOTP密钥<br/>tierTwoTotpSecret = secret
Note over Agent: 密钥保存在内存中<br/>后续心跳使用此密钥
```
### 2.2 后续心跳流程
```mermaid
sequenceDiagram
autonumber
participant Agent as rmdc-watchdog-agent<br/>(业务启动器)
participant Watchdog as rmdc-watchdog<br/>(二级授权中心)
participant Business as 业务进程<br/>(Java/Python)
rect rgb(220, 255, 220)
Note over Agent,Business: ===== 心跳循环 - 授权验证 =====
end
loop 心跳循环 (成功后2小时, 失败后1小时)
Agent->>Agent: 1. 生成TOTP验证码<br/>GenerateTierTwoTOTPCode(secret)<br/>6位, 30秒有效
Agent->>Watchdog: 2. POST /api/heartbeat<br/>{HostInfo, EnvInfo, Timestamp, TOTPCode}
Watchdog->>Watchdog: 3. 验证时间戳有效性
Watchdog->>Watchdog: 4. 验证TOTP验证码<br/>VerifyTierTwoTOTPCode()
alt TOTP验证成功
Watchdog->>Watchdog: 5. 检查主机授权状态<br/>IsHostAuthorized(hostInfo)
Watchdog->>Watchdog: 6. 生成响应TOTP验证码<br/>(双向验证)
Watchdog-->>Agent: 7. 返回{Authorized:true/false, TOTPCode}
Agent->>Agent: 8. 验证服务端TOTP<br/>双向验证确保安全
alt 授权成功
Agent->>Agent: 9. failCount = 1<br/>等待2小时
else 授权失败
Agent->>Agent: 9. failCount++<br/>等待1小时
end
else TOTP验证失败
Watchdog-->>Agent: 返回错误:无效的TOTP验证码
Agent->>Agent: failCount++
end
alt failCount >= 12
Note over Agent,Business: 死手系统触发
Agent->>Business: 10. 发送SIGTERM信号
Note over Business: 业务进程终止
end
end
```
### 2.3 心跳请求/响应数据结构
| 字段 | 类型 | 说明 |
|------|------|------|
| **HeartbeatRequest** | | |
| host_info | HostInfo | 主机硬件信息 |
| env_info | EnvInfo | 环境信息(K8S_NAMESPACE, APPLICATION_NAME等) |
| timestamp | int64 | 请求时间戳 |
| totp_code | string | TOTP验证码(首次为空) |
| **HeartbeatResponse** | | |
| authorized | bool | 是否已授权 |
| totp_code | string | 响应TOTP验证码(双向验证) |
| timestamp | int64 | 响应时间戳 |
| second_totp_secret | string | 二级TOTP密钥(首次连接时返回) |
---
## 三、Node主机信息上报流程
Node以DaemonSet方式运行在每个K8S节点上负责收集主机硬件信息和运行指标。
### 3.1 Node上报流程
```mermaid
sequenceDiagram
autonumber
participant Node as rmdc-watchdog-node<br/>(DaemonSet)
participant Watchdog as rmdc-watchdog<br/>(二级授权中心)
rect rgb(200, 220, 255)
Note over Node,Watchdog: ===== 首次上报 - 获取TOTP密钥 =====
end
Node->>Node: 1. 收集主机硬件信息<br/>CollectHostInfo()
Node->>Node: 2. 收集运行指标<br/>CollectMetrics()
Node->>Watchdog: 3. POST /api/node/info<br/>{NodeID, HostInfo, Metrics, Timestamp, TOTPCode=""}
Watchdog->>Watchdog: 4. 验证时间戳
Watchdog->>Watchdog: 5. 存储Node信息
Watchdog->>Watchdog: 6. 同步更新AuthService<br/>AddHostInfo()
Watchdog-->>Node: 7. 返回{Success:true, SecondTOTPSecret:secret}
Node->>Node: 8. 保存TOTP密钥
rect rgb(220, 255, 220)
Note over Node,Watchdog: ===== 定时上报 (默认60秒) =====
end
loop 定时上报
Node->>Node: 9. 生成TOTP验证码
Node->>Node: 10. 收集最新指标
Node->>Watchdog: 11. POST /api/node/info<br/>{NodeID, HostInfo, Metrics, Timestamp, TOTPCode}
Watchdog->>Watchdog: 12. 验证TOTP
Watchdog->>Watchdog: 13. 更新Node信息
Watchdog->>Watchdog: 14. 生成响应TOTP
Watchdog-->>Node: 15. 返回{Success:true, TOTPCode}
Node->>Node: 16. 验证响应TOTP(双向)
end
```
### 3.2 Node信息数据结构
| 字段 | 类型 | 说明 |
|------|------|------|
| **NodeInfoRequest** | | |
| node_id | string | 节点唯一标识(MachineID) |
| host_info | HostInfo | 主机硬件信息 |
| metrics | NodeRuntimeMetrics | 运行指标 |
| timestamp | int64 | 请求时间戳 |
| totp_code | string | TOTP验证码 |
| **NodeRuntimeMetrics** | | |
| cpu_usage | float64 | CPU使用率(%) |
| memory_usage | float64 | 内存使用率(%) |
| disk_usage | float64 | 磁盘使用率(%) |
| network_rx_kb | uint64 | 网络接收KB |
| network_tx_kb | uint64 | 网络发送KB |
| collect_time | int64 | 采集时间戳 |
---
## 四、项目级别(二级授权中心)完整业务流程
### 4.1 完整授权流程
```mermaid
sequenceDiagram
autonumber
participant Node as rmdc-watchdog-node<br/>(DaemonSet)
participant Agent as rmdc-watchdog-agent<br/>(业务启动器)
participant Watchdog as rmdc-watchdog<br/>(二级授权中心)
participant MQTT as Exchange-Hub<br/>(MQTT Server)
participant Center as rmdc-watchdog-center<br/>(一级授权中心)
rect rgb(200, 220, 255)
Note over Node,Center: ===== 阶段1: 信息收集与初始化 =====
end
Note over Node: 项目部署后<br/>DaemonSet启动
Node->>Watchdog: 1. 上报主机信息<br/>POST /api/node/info
Watchdog-->>Node: 2. 返回TOTP密钥
Note over Agent: 业务Pod启动
Agent->>Watchdog: 3. 发送首次心跳<br/>POST /api/heartbeat
Watchdog-->>Agent: 4. 返回TOTP密钥
rect rgb(220, 255, 220)
Note over Node,Center: ===== 阶段2: 授权申请 =====
end
Watchdog->>Watchdog: 5. 生成授权文件<br/>GenerateAuthorizationFile()
Note over Watchdog: 授权文件包含:<br/>- EncryptedHostMap<br/>- TOTPCode (8位,30分钟)<br/>- EncryptedNamespace
Watchdog->>MQTT: 6. 发布授权申请Command<br/>wdd/RDMC/command/up
MQTT->>Center: 7. 转发授权申请
rect rgb(255, 240, 220)
Note over Node,Center: ===== 阶段3: 授权验证与下发 =====
end
Center->>Center: 8. 解密项目命名空间
Center->>Center: 9. 验证Tier-One TOTP验证码
Center->>Center: 10. 验证主机信息完整性
alt 验证成功
Center->>Center: 11. 生成新TOTP验证码
Center->>Center: 12. 构造授权码
Center->>MQTT: 13. 发布授权码<br/>wdd/RDMC/command/down/{project_id}
else 验证失败
Center->>MQTT: 发布授权拒绝消息
end
MQTT->>Watchdog: 14. 推送授权码
rect rgb(230, 230, 255)
Note over Node,Center: ===== 阶段4: 授权存储与生效 =====
end
Watchdog->>Watchdog: 15. 验证返回的TOTP
Watchdog->>Watchdog: 16. 解密并验证命名空间
Watchdog->>Watchdog: 17. 解密每个主机信息
Watchdog->>Watchdog: 18. 计算时间偏移<br/>timeOffset = now - firstAuthTime
Watchdog->>Watchdog: 19. 加密并持久化保存
rect rgb(200, 255, 200)
Note over Node,Center: ===== 阶段5: 授权使用 =====
end
loop Agent心跳循环
Agent->>Watchdog: 20. 发送心跳请求
Watchdog->>Watchdog: 21. 检查主机授权状态
Watchdog-->>Agent: 22. 返回{Authorized:true}
end
Note over Agent: 授权成功<br/>业务正常运行
```
### 4.2 授权状态机
```mermaid
stateDiagram-v2
[*] --> 未初始化: 项目部署
未初始化 --> 收集主机信息: Node/Agent连接
收集主机信息 --> 等待授权: 生成授权文件
等待授权 --> 已授权: 收到有效授权码
等待授权 --> 未授权: 授权被拒绝
已授权 --> 已授权: 心跳成功
已授权 --> 授权过期: 时间篡改检测
已授权 --> 未授权: 授权撤销
未授权 --> 等待授权: 重新申请
授权过期 --> 未授权: 需重新授权
```
---
## 五、API接口清单
### 5.1 Watchdog API (Port: 8990)
| 路径 | 方法 | 说明 |
|------|------|------|
| `/api/heartbeat` | POST | Agent心跳接口 |
| `/api/heartbeat/hosts` | GET | 获取所有心跳主机 |
| `/api/node/info` | POST | Node信息上报接口 |
| `/api/node/list` | GET | 获取所有Node列表 |
| `/api/node/metrics/:node_id` | GET | 获取指定Node的运行指标 |
| `/api/authorization/generate` | GET | 生成授权文件 |
| `/api/authorization/auth` | POST | 接收授权码 |
| `/api/authorization/hosts` | GET | 获取所有已授权主机 |
---
## 六、安全机制
### 6.1 TOTP验证机制
| 场景 | 验证方式 | 参数 |
|------|----------|------|
| Agent ↔ Watchdog | Tier-Two TOTP | 6位码, 30秒有效, SHA1 |
| Node ↔ Watchdog | Tier-Two TOTP | 6位码, 30秒有效, SHA1 |
| Watchdog ↔ Center | Tier-One TOTP | 8位码, 30分钟有效, SHA256 |
### 6.2 双向验证流程
1. **客户端(Agent/Node)** 生成TOTP验证码并发送请求
2. **服务端(Watchdog)** 验证客户端TOTP后生成新的TOTP验证码返回
3. **客户端** 验证服务端返回的TOTP验证码
4. 双向验证确保通信双方身份合法
### 6.3 死手系统
Agent内置死手系统当连续12次心跳失败后将发送SIGTERM信号终止业务进程。
| 参数 | 值 | 说明 |
|------|------|------|
| maxRetryCount | 12 | 最大重试次数 |
| defaultHeartbeatInterval | 2小时 | 成功后心跳间隔 |
| failWaitInterval | 1小时 | 失败后等待间隔 |

View File

@@ -0,0 +1,468 @@
# Watchdog模块开发提示词
> 本文档为大模型提供rmdc-watchdog模块的开发上下文。
---
## 模块概述
**rmdc-watchdog** 是部署在外部项目环境的边缘代理模块,负责:
1. **二级授权中心**: 管理项目内业务和主机的授权
2. **K8S操作代理**: 执行K8S API操作CRUD资源、日志获取等
3. **指令接收与执行**: 接收Exchange-Hub下发的指令并执行
4. **监控数据上报**: 收集并上报主机/业务运行状态
---
## 组件架构
```mermaid
graph TB
subgraph "rmdc-watchdog 组件"
MQTT[MQTT Client]
Router[消息路由器]
subgraph "Handler"
AuthH[授权Handler]
K8sH[K8S Handler]
HostH[主机Handler]
LogH[日志Handler]
end
subgraph "Service"
AuthS[授权服务]
K8sS[K8S服务]
NodeS[Node通信服务]
end
K8sClient[K8S Client]
NodeClient[Node HTTP Client]
end
subgraph "watchdog-node (DaemonSet)"
NodeServer[HTTP Server :8081]
NodeInfo[信息采集]
NodeExec[命令执行]
end
subgraph "watchdog-agent (业务启动器)"
AgentHB[心跳模块]
AgentBiz[业务进程管理]
end
MQTT --> Router
Router --> AuthH & K8sH & HostH & LogH
AuthH --> AuthS
K8sH --> K8sS --> K8sClient
HostH --> NodeS --> NodeClient --> NodeServer
NodeServer --> NodeInfo & NodeExec
AgentHB <--> AuthS
```
---
## 关联组件说明
| 组件 | 运行位置 | 职责 |
|------|----------|------|
| **rmdc-watchdog** | K8S Deployment | 二级授权中心、K8S操作、指令调度 |
| **rmdc-watchdog-node** | K8S DaemonSet | 主机信息采集、主机命令执行 |
| **rmdc-watchdog-agent** | 业务Pod Sidecar | 业务进程管理、授权心跳、死手系统 |
---
## 项目结构
```
rmdc-watchdog/
├── cmd/
│ └── main.go
├── configs/
│ └── config.yaml
├── internal/
│ ├── config/
│ │ └── config.go
│ ├── dao/
│ │ ├── auth_dao.go
│ │ └── host_dao.go
│ ├── handler/
│ │ ├── router.go
│ │ ├── auth_handler.go
│ │ ├── heartbeat_handler.go
│ │ ├── k8s_handler.go
│ │ └── node_handler.go
│ ├── model/
│ │ ├── dto/
│ │ │ └── watchdog_dto.go
│ │ └── entity/
│ │ └── auth_info.go
│ └── service/
│ ├── mqtt_service.go
│ ├── auth_service.go
│ ├── k8s_service.go
│ ├── node_service.go
│ └── message_router.go
└── pkg/
├── k8s/
│ └── client.go # K8S API封装
└── totp/
└── totp.go # TOTP工具
```
---
## 核心数据结构
### 心跳请求/响应
```go
// HeartbeatRequest Agent心跳请求
type HeartbeatRequest struct {
HostInfo common.HostInfo `json:"host_info"`
EnvInfo common.EnvInfo `json:"env_info"`
Timestamp int64 `json:"timestamp"`
TOTPCode string `json:"totp_code"`
}
// HeartbeatResponse 心跳响应
type HeartbeatResponse struct {
Authorized bool `json:"authorized"`
TOTPCode string `json:"totp_code"` // 服务端TOTP(双向验证)
Timestamp int64 `json:"timestamp"`
SecondTOTPSecret string `json:"second_totp_secret,omitempty"` // 首次连接返回
}
```
### K8S执行指令
```go
// K8sExecCommand K8S执行指令
type K8sExecCommand struct {
CommandID string `json:"command_id"`
Namespace string `json:"namespace"`
Resource string `json:"resource"` // deployment, pod, statefulset...
Name string `json:"name"`
Action string `json:"action"` // logs, exec, scale, restart, delete, get, apply
Container string `json:"container,omitempty"`
Command []string `json:"command,omitempty"`
Timeout int `json:"timeout"`
TailLines int `json:"tail_lines,omitempty"`
FollowLogs bool `json:"follow_logs,omitempty"`
}
// ExecResult 执行结果
type ExecResult struct {
CommandID string `json:"command_id"`
Status string `json:"status"` // success, failure, timeout
ExitCode int `json:"exit_code"`
Output string `json:"output"`
Error string `json:"error"`
StartTime int64 `json:"start_time"`
EndTime int64 `json:"end_time"`
Duration int64 `json:"duration"`
}
```
---
## TOTP双层授权机制
### 层级说明
```
一级授权(Tier-One): project-management ↔ watchdog
- 8位验证码
- 30分钟有效期
- SHA256算法
二级授权(Tier-Two): watchdog ↔ agent/node
- 6位验证码
- 30秒有效期
- SHA1算法
```
### 授权流程
```go
// 验证Agent心跳
func (s *AuthService) VerifyHeartbeat(req *HeartbeatRequest) (*HeartbeatResponse, error) {
// 1. 验证时间戳
if abs(time.Now().Unix() - req.Timestamp/1000) > 300 {
return nil, errors.New("timestamp expired")
}
// 2. 首次连接(无TOTP码)
if req.TOTPCode == "" {
s.addHost(req.HostInfo)
return &HeartbeatResponse{
Authorized: false,
SecondTOTPSecret: s.tierTwoSecret,
Timestamp: time.Now().UnixMilli(),
}, nil
}
// 3. 验证TOTP
if !s.verifyTierTwoTOTP(req.TOTPCode) {
return nil, errors.New("invalid totp code")
}
// 4. 检查主机授权状态
authorized := s.isHostAuthorized(req.HostInfo)
// 5. 生成响应TOTP(双向验证)
responseTOTP := s.generateTierTwoTOTP()
return &HeartbeatResponse{
Authorized: authorized,
TOTPCode: responseTOTP,
Timestamp: time.Now().UnixMilli(),
}, nil
}
```
---
## K8S操作封装
### 支持的操作
| Action | 说明 | 目标资源 |
|--------|------|----------|
| `logs` | 获取日志 | Pod |
| `exec` | 执行命令 | Pod |
| `scale` | 扩缩容 | Deployment/StatefulSet |
| `restart` | 滚动重启 | Deployment/StatefulSet |
| `delete` | 删除资源 | 任意资源 |
| `get` | 获取信息 | 任意资源 |
| `apply` | 应用YAML | 任意资源 |
### K8S客户端使用
```go
func (s *K8sService) ExecuteCommand(cmd *K8sExecCommand) (*ExecResult, error) {
startTime := time.Now()
result := &ExecResult{
CommandID: cmd.CommandID,
StartTime: startTime.UnixMilli(),
}
var output string
var err error
switch cmd.Action {
case "logs":
output, err = s.k8sClient.GetPodLogs(cmd.Namespace, cmd.Name, cmd.Container, cmd.TailLines)
case "exec":
output, err = s.k8sClient.ExecCommand(cmd.Namespace, cmd.Name, cmd.Container, cmd.Command)
case "scale":
output, err = s.k8sClient.Scale(cmd.Namespace, cmd.Resource, cmd.Name, cmd.Scale)
case "restart":
output, err = s.k8sClient.RolloutRestart(cmd.Namespace, cmd.Resource, cmd.Name)
case "delete":
output, err = s.k8sClient.Delete(cmd.Namespace, cmd.Resource, cmd.Name)
}
result.EndTime = time.Now().UnixMilli()
result.Duration = result.EndTime - result.StartTime
if err != nil {
result.Status = "failure"
result.Error = err.Error()
} else {
result.Status = "success"
result.Output = output
}
return result, nil
}
```
---
## Node通信
### Node HTTP接口
| 接口 | 方法 | 说明 |
|------|------|------|
| `/api/exec` | POST | 执行命令 |
| `/api/info` | GET | 获取主机信息 |
| `/api/metrics` | GET | 获取运行指标 |
| `/api/dltu` | POST | 镜像操作(Download-Load-Tag-Upload) |
### 与Node通信
```go
func (s *NodeService) ExecuteOnNode(nodeID string, script string, args []string) (*ExecResult, error) {
// 1. 获取Node地址
node := s.getNode(nodeID)
if node == nil {
return nil, errors.New("node not found")
}
// 2. 生成TOTP
totp := s.generateTierTwoTOTP()
// 3. 发送请求
req := &NodeExecRequest{
Script: script,
Args: args,
Timestamp: time.Now().UnixMilli(),
TOTPCode: totp,
}
resp, err := s.httpClient.Post(fmt.Sprintf("http://%s:8081/api/exec", node.IP), req)
if err != nil {
return nil, err
}
// 4. 验证响应TOTP
if !s.verifyTierTwoTOTP(resp.TOTPCode) {
return nil, errors.New("invalid response totp")
}
return resp.Result, nil
}
```
---
## 死手系统
Agent内置死手系统保护业务授权安全
| 参数 | 值 | 说明 |
|------|------|------|
| `maxRetryCount` | 12 | 最大失败次数 |
| `successInterval` | 2小时 | 成功后心跳间隔 |
| `failInterval` | 1小时 | 失败后心跳间隔 |
```go
// Agent心跳循环
func (a *Agent) heartbeatLoop() {
failCount := 0
for {
resp, err := a.sendHeartbeat()
if err != nil || !resp.Authorized {
failCount++
if failCount >= 12 {
// 触发死手系统
a.killBusiness()
return
}
time.Sleep(1 * time.Hour)
} else {
failCount = 1
time.Sleep(2 * time.Hour)
}
}
}
func (a *Agent) killBusiness() {
// 发送SIGTERM信号终止业务进程
a.businessProcess.Signal(syscall.SIGTERM)
}
```
---
## MQTT订阅与发布
### 启动时订阅
```go
func (s *MQTTService) Start() {
// 订阅下行Topic
s.client.Subscribe(fmt.Sprintf("wdd/RDMC/command/down/%s", s.projectID), s.onCommand)
s.client.Subscribe(fmt.Sprintf("wdd/RDMC/message/down/%s", s.projectID), s.onMessage)
}
```
### 发布上行消息
```go
func (s *MQTTService) PublishResult(result *ExecResult) error {
msg := &common.DataMessage{
BaseMessage: common.BaseMessage{
MessageID: uuid.New().String(),
Type: "message",
ProjectID: s.projectID,
Timestamp: time.Now().UnixMilli(),
},
DataType: "exec_result",
Payload: result,
}
return s.client.Publish("wdd/RDMC/message/up", msg)
}
```
---
## 配置项
```yaml
# configs/config.yaml
server:
host: 0.0.0.0
port: 8990
mqtt:
broker: tcp://mqtt-broker:1883
client_id: watchdog-${PROJECT_ID}
username: ${MQTT_USERNAME}
password: ${MQTT_PASSWORD}
project:
id: ${PROJECT_ID}
namespace: ${NAMESPACE}
auth:
tier_one_secret: ${TIER_ONE_SECRET}
tier_two_secret: ${TIER_TWO_SECRET}
time_offset_allowed: 300
totp_verification_enabled: true
k8s:
kubeconfig_path: "" # 空则使用InCluster配置
```
---
## 常见开发任务
### 1. 添加新的K8S操作
1.`pkg/k8s/client.go`添加K8S API调用方法
2.`internal/service/k8s_service.go`的switch中添加case
3. 更新`K8sExecCommand`结构(如需新参数)
### 2. 添加新的指令类型
1.`message_router.go`添加路由分支
2. 创建对应的Handler和Service
3. 同步更新Exchange-Hub端的指令下发
### 3. 修改心跳逻辑
1. 修改`auth_service.go``VerifyHeartbeat`方法
2. 同步修改Agent端的心跳发送逻辑
3. 如需新增字段更新DTO结构
---
## 相关文档
| 文档 | 内容 |
|------|------|
| `1-rmdc-watchdog-DDS.md` | 详细设计 |
| `2-rmdc-watchdog-业务流程图.md` | 业务流程图 |
| `3-rmdc-watchdog-内部交互流程.md` | 内部交互流程 |

View File

@@ -0,0 +1,771 @@
# 工单流程模块 DDS (详细设计说明书)
**产品名称**: RMDC 工单流程模块 (rmdc-work-procedure)
**版本**: v2.0
**编制日期**: 2026-01-08
---
## 1. 概述
### 1.1 模块定位
工单流程模块是RMDC系统的核心基础设施模块为其他业务模块提供统一的工单创建、流转、追踪能力。
```mermaid
graph TB
subgraph "业务模块"
UA[rmdc-user-auth<br/>用户认证模块]
PM[rmdc-project-management<br/>项目管理模块]
DU[deliver-update<br/>微服务更新模块]
end
subgraph "工单模块"
WP[rmdc-work-procedure<br/>工单流程模块]
end
subgraph "基础设施"
NC[rmdc-notice-center<br/>通知中心模块]
end
UA --> WP
PM --> WP
DU --> WP
WP --> NC
```
### 1.2 工单类型
| 工单类型代码 | 类型名称 | 来源模块 | 流程详情 |
|-------------|---------|---------|---------|
| `user_registration` | 用户注册工单 | rmdc-user-auth | [用户注册工单流程](diagrams/user-registration-workflow.md) |
| `user_management` | 用户管理工单 | rmdc-user-auth | [用户管理工单流程](diagrams/user-management-workflow.md) |
| `project_detail` | 项目信息填写工单 | rmdc-project-management | [项目信息填写工单流程](diagrams/project-detail-workflow.md) |
| `microservice_update` | 微服务更新工单 | deliver-update | [微服务更新工单流程](diagrams/microservice-update-workflow.md) |
---
## 2. 状态机设计
### 2.1 设计原则
采用 **"通用状态机 + 类型特化配置"** 的混合方案:
- **基础状态层**所有工单类型共享的10个核心状态
- **扩展状态层**:按工单类型配置的特殊状态
### 2.2 基础状态定义
| 状态代码 | 状态名称 | 说明 | 是否终态 |
|---------|---------|------|---------|
| `created` | 已创建 | 工单刚创建,等待分配或自动分配 | 否 |
| `pending` | 待分配 | 等待管理员手动分配处理人 | 否 |
| `assigned` | 已分配 | 已分配处理人,等待接单 | 否 |
| `in_progress` | 处理中 | 处理人正在业务模块中处理 | 否 |
| `pending_review` | 待审核 | 处理完成,等待审核 | 否 |
| `returned` | 已打回 | 审核未通过,需重新处理 | 否 |
| `approved` | 已通过 | 审核通过 | 是 |
| `rejected` | 已拒绝 | 审核拒绝,流程终止 | 是 |
| `revoked` | 已撤销 | 发起人撤销 | 是 |
| `closed` | 已关闭 | 流程完结 | 是 |
### 2.3 扩展状态定义
| 工单类型 | 扩展状态 | 说明 |
|---------|---------|------|
| `microservice_update` | `executing` | 微服务更新执行中 |
| `microservice_update` | `monitoring` | 微服务运行状态监控中 |
| `microservice_update` | `rollbacked` | 更新失败已回滚 |
| `project_detail` | `draft_saved` | 草稿已保存 |
### 2.4 通用状态转换图
```mermaid
stateDiagram-v2
[*] --> created: 工单创建
created --> pending: submit
created --> assigned: auto_assign
pending --> assigned: assign
assigned --> in_progress: accept
assigned --> assigned: reassign
in_progress --> pending_review: complete
in_progress --> returned: return
in_progress --> assigned: reassign
pending_review --> approved: approve
pending_review --> rejected: reject
pending_review --> returned: return
returned --> in_progress: resubmit
approved --> closed: close
rejected --> closed: close
created --> revoked: revoke
pending --> revoked: revoke
assigned --> revoked: revoke
in_progress --> revoked: revoke(需确认)
pending_review --> revoked: revoke(需确认)
returned --> revoked: revoke
revoked --> closed: close
closed --> [*]
```
### 2.5 状态转换权限矩阵
| 转换事件 | 触发角色 | 前置条件 |
|---------|---------|---------|
| `submit` | 创建人 | 状态为 `created` |
| `auto_assign` | 系统 | 配置了自动分配规则 |
| `assign` | SuperAdmin | 状态为 `pending` |
| `accept` | 处理人 | 状态为 `assigned` |
| `reassign` | SuperAdmin | 状态为 `assigned`/`in_progress` |
| `complete` | 处理人 | 状态为 `in_progress` |
| `approve` | SuperAdmin | 状态为 `pending_review` |
| `reject` | SuperAdmin | 状态为 `pending_review` |
| `return` | SuperAdmin | 状态为 `pending_review`/`in_progress` |
| `resubmit` | 创建人/处理人 | 状态为 `returned` |
| `revoke` | 创建人 | 状态非终态 |
| `close` | 系统/SuperAdmin | 状态为终态或 `revoked` |
---
## 3. 数据模型设计
### 3.1 设计原则
采用 **"主表统一 + 业务扩展表分离"** 的设计:
- **主表**:存储所有工单类型的通用字段
- **扩展表**:按工单类型存储特定业务数据
### 3.2 ER图
```mermaid
erDiagram
workflows ||--o{ workflow_steps : contains
workflows ||--o{ workflow_track_history : has
workflows ||--o| user_registration_ext : extends
workflows ||--o| user_management_ext : extends
workflows ||--o| project_detail_ext : extends
workflows ||--o| microservice_update_ext : extends
workflows {
varchar(64) id PK "工单唯一ID"
int version "乐观锁版本号"
varchar(32) module_code "来源模块"
varchar(32) workflow_type "工单类型"
int priority "优先级1-5"
varchar(32) status "当前状态"
int current_step "当前步骤序号"
int total_steps "总步骤数"
bigint creator_id FK "发起人ID"
varchar(64) creator_name "发起人姓名"
bigint assignee_id FK "当前处理人ID"
varchar(64) assignee_name "处理人姓名"
bigint delegated_by "委派来源"
datetime deadline "超时时间"
datetime started_at "开始处理时间"
datetime completed_at "完成时间"
varchar(256) title "工单标题"
text description "工单描述"
json business_payload "业务模块通用数据"
json result_payload "处理结果数据"
datetime created_at
datetime updated_at
}
workflow_steps {
bigint id PK
varchar(64) workflow_id FK
int step_order "步骤顺序"
varchar(64) step_name "步骤名称"
varchar(32) step_type "步骤类型"
bigint assignee_id FK
varchar(64) assignee_name
varchar(32) status "步骤状态"
varchar(32) result "步骤结果"
text remark "处理备注"
json input_data "步骤输入"
json output_data "步骤输出"
datetime started_at
datetime completed_at
datetime created_at
}
workflow_track_history {
bigint id PK
varchar(64) workflow_id FK
varchar(32) from_status
varchar(32) to_status
varchar(32) event "触发事件"
bigint operator_id
varchar(16) operator_type "user/system/timer"
varchar(45) operator_ip
json change_details "变更详情"
text remark
datetime created_at
}
```
### 3.3 主表DDL (workflows)
```sql
CREATE TABLE workflows (
id VARCHAR(64) PRIMARY KEY,
version INT NOT NULL DEFAULT 1,
-- 工单类型与来源
module_code VARCHAR(32) NOT NULL,
workflow_type VARCHAR(32) NOT NULL,
priority INT DEFAULT 3,
-- 状态与流程
status VARCHAR(32) NOT NULL,
current_step INT DEFAULT 1,
total_steps INT DEFAULT 1,
-- 人员关联
creator_id BIGINT NOT NULL,
creator_name VARCHAR(64),
assignee_id BIGINT,
assignee_name VARCHAR(64),
delegated_by BIGINT,
-- 时间管理
deadline DATETIME,
started_at DATETIME,
completed_at DATETIME,
-- 业务数据
title VARCHAR(256),
description TEXT,
business_payload JSON,
result_payload JSON,
-- 审计
created_at DATETIME NOT NULL,
updated_at DATETIME NOT NULL,
INDEX idx_module_code (module_code),
INDEX idx_workflow_type (workflow_type),
INDEX idx_status (status),
INDEX idx_creator (creator_id),
INDEX idx_assignee (assignee_id)
);
```
### 3.4 步骤表DDL (workflow_steps)
```sql
CREATE TABLE workflow_steps (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
workflow_id VARCHAR(64) NOT NULL,
step_order INT NOT NULL,
step_name VARCHAR(64),
step_type VARCHAR(32),
-- 处理信息
assignee_id BIGINT,
assignee_name VARCHAR(64),
status VARCHAR(32),
result VARCHAR(32),
remark TEXT,
input_data JSON,
output_data JSON,
-- 时间
started_at DATETIME,
completed_at DATETIME,
created_at DATETIME NOT NULL,
INDEX idx_workflow (workflow_id),
FOREIGN KEY (workflow_id) REFERENCES workflows(id)
);
```
### 3.5 追踪历史表DDL (workflow_track_history)
```sql
CREATE TABLE workflow_track_history (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
workflow_id VARCHAR(64) NOT NULL,
-- 状态变更
from_status VARCHAR(32),
to_status VARCHAR(32),
event VARCHAR(32),
-- 操作信息
operator_id BIGINT,
operator_type VARCHAR(16),
operator_ip VARCHAR(45),
-- 变更详情
change_details JSON,
remark TEXT,
created_at DATETIME NOT NULL,
INDEX idx_workflow (workflow_id),
INDEX idx_operator (operator_id)
);
```
### 3.6 业务扩展表DDL
#### 用户注册扩展表
```sql
CREATE TABLE user_registration_ext (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
workflow_id VARCHAR(64) NOT NULL UNIQUE,
target_user_id BIGINT NOT NULL,
original_status VARCHAR(32),
FOREIGN KEY (workflow_id) REFERENCES workflows(id)
);
```
#### 用户管理扩展表
```sql
CREATE TABLE user_management_ext (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
workflow_id VARCHAR(64) NOT NULL UNIQUE,
target_user_id BIGINT NOT NULL,
action_type VARCHAR(32) NOT NULL,
original_data JSON,
modified_data JSON,
FOREIGN KEY (workflow_id) REFERENCES workflows(id)
);
```
#### 项目详情扩展表
```sql
CREATE TABLE project_detail_ext (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
workflow_id VARCHAR(64) NOT NULL UNIQUE,
project_id VARCHAR(64) NOT NULL,
detail_filler_id BIGINT,
detail_filler_name VARCHAR(64),
draft_data JSON,
FOREIGN KEY (workflow_id) REFERENCES workflows(id)
);
```
#### 微服务更新扩展表
```sql
CREATE TABLE microservice_update_ext (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
workflow_id VARCHAR(64) NOT NULL UNIQUE,
project_id VARCHAR(64) NOT NULL,
namespace VARCHAR(64) NOT NULL,
service_name VARCHAR(128) NOT NULL,
build_id VARCHAR(128),
current_version VARCHAR(64),
target_version VARCHAR(64),
scheduled_at DATETIME,
execute_result VARCHAR(32),
rollback_info JSON,
FOREIGN KEY (workflow_id) REFERENCES workflows(id)
);
```
---
## 4. API接口设计
### 4.1 工单核心接口
| 方法 | 路径 | 说明 |
|-----|------|------|
| POST | `/api/workflow/create` | 创建工单 |
| POST | `/api/workflow/detail` | 获取工单详情 |
| POST | `/api/workflow/status` | 获取工单状态(轻量) |
| POST | `/api/workflow/update` | 更新工单(需版本号) |
| POST | `/api/workflow/transition` | 状态转换 |
| POST | `/api/workflow/assign` | 分配处理人 |
| POST | `/api/workflow/delegate` | 委派给他人 |
| POST | `/api/workflow/revoke` | 撤销工单 |
| POST | `/api/workflow/callback` | 业务模块回调 |
### 4.2 工单列表与查询
| 方法 | 路径 | 说明 |
|-----|------|------|
| POST | `/api/workflow/list` | 工单列表(分页) |
| POST | `/api/workflow/my/created` | 我发起的工单 |
| POST | `/api/workflow/my/assigned` | 分配给我的工单 |
| POST | `/api/workflow/my/pending` | 待我处理的工单 |
| POST | `/api/workflow/history` | 工单历史记录 |
| POST | `/api/workflow/diagram` | 工单流程图(mermaid格式) |
### 4.3 权限管理接口 (仅SuperAdmin)
| 方法 | 路径 | 说明 |
|-----|------|------|
| POST | `/api/workflow/permission/grant` | 授予权限 |
| POST | `/api/workflow/permission/revoke` | 撤销权限 |
| POST | `/api/workflow/permission/list` | 权限列表 |
---
## 5. 并发处理机制
### 5.1 乐观锁实现
```go
// 更新工单时必须校验版本号
func (s *WorkflowService) UpdateWorkflow(ctx context.Context, req *UpdateRequest) error {
result := s.db.Model(&Workflow{}).
Where("id = ? AND version = ?", req.ID, req.Version).
Updates(map[string]interface{}{
"status": req.Status,
"version": gorm.Expr("version + 1"),
})
if result.RowsAffected == 0 {
return ErrVersionConflict // 409 Conflict
}
return nil
}
```
### 5.2 并发事件处理
| 场景 | 处理策略 |
|-----|---------|
| 工单被委派 | 推送 `WORKFLOW_REASSIGNED` 事件,原处理人页面切换只读模式 |
| 工单被撤销 | 推送 `WORKFLOW_REVOKED` 事件,处理人页面自动关闭 |
| 工单被修改 | 推送 `WORKFLOW_MODIFIED` 事件,前端提示刷新或自动刷新 |
---
## 6. WebSocket事件
| 事件类型 | 触发时机 | 接收方 |
|---------|---------|-------|
| `WORKFLOW_CREATED` | 工单创建 | 处理人 |
| `WORKFLOW_ASSIGNED` | 工单分配 | 处理人 |
| `WORKFLOW_REASSIGNED` | 工单重新委派 | 原处理人、新处理人 |
| `WORKFLOW_STATUS_CHANGED` | 状态变更 | 发起人、处理人 |
| `WORKFLOW_REVOKED` | 工单撤销 | 处理人 |
| `WORKFLOW_MODIFIED` | 工单内容修改 | 处理人 |
| `WORKFLOW_TIMEOUT` | 工单超时 | 发起人、处理人 |
| `WORKFLOW_COMPLETED` | 工单完成 | 发起人 |
---
## 7. 流程图动态生成模块
### 7.1 模块概述
流程图动态生成模块负责根据工单状态动态生成Mermaid源码由后端返回给前端前端使用Mermaid库完成渲染。
### 7.2 架构设计
```mermaid
graph TB
subgraph 后端 rmdc_work_procedure
WS[WorkflowService] --> MG[MermaidGenerator]
MG --> MT[Templates]
MT --> T1[UserRegistrationTemplate]
MT --> T2[UserManagementTemplate]
MT --> T3[ProjectDetailTemplate]
MT --> T4[DefaultTemplate]
end
subgraph API层
H[WorkflowHandler] --> WS
end
subgraph 前端
FE[WorkflowDetail.vue] -->|POST /workflow/diagram| H
FE --> DM[动态 import mermaid]
FE --> VM[VueMermaid<br/>@mermaid-js/mermaid-tiny]
DM -. 初始化 .-> VM
end
classDef async stroke:#ff9800,stroke-width:2px,stroke-dasharray: 4 2
class DM async
```
### 7.3 文件结构
```
rmdc-work-procedure/
├── pkg/
│ └── mermaid/
│ ├── types.go # 数据类型定义
│ ├── generator.go # 核心生成器逻辑仅生成Mermaid源码
│ └── templates.go # 工单类型模板
└── internal/
└── service/
└── mermaid_generator.go # Service层封装
```
### 7.4 核心数据结构
```go
// DiagramResponse 流程图响应
type DiagramResponse struct {
MermaidCode string `json:"mermaid_code"` // Mermaid源代码
CurrentNode string `json:"current_node"` // 当前高亮节点ID
Nodes []DiagramNode `json:"nodes"` // 节点详细信息
}
// DiagramNode 节点信息
type DiagramNode struct {
ID string `json:"id"` // 节点ID
Label string `json:"label"` // 显示文本
Status string `json:"status"` // completed/current/pending/error
Assignee string `json:"assignee"` // 处理人
CompletedAt string `json:"completed_at"` // 完成时间
}
```
### 7.5 支持的工单模板
| 工单类型 | 模板类 | 说明 |
|---------|--------|------|
| `user_registration` | UserRegistrationTemplate | 用户注册流程图 |
| `user_management` | UserManagementTemplate | 用户管理流程图 |
| `project_detail` | ProjectDetailTemplate | 项目详情填写流程图 |
| 其他 | DefaultTemplate | 通用默认流程图 |
### 7.6 API接口详细
**请求**: `POST /api/workflow/diagram`
```json
{
"workflow_id": "project-20260108100000-admin"
}
```
**响应**:
```json
{
"code": 0,
"message": "success",
"data": {
"mermaid_code": "stateDiagram-v2\n direction LR\n ...",
"current_node": "pending_review",
"nodes": [
{
"id": "created",
"label": "创建项目",
"status": "completed",
"assignee": "超级管理员"
},
{
"id": "in_progress",
"label": "填写信息",
"status": "current",
"assignee": "张三"
}
]
}
}
```
### 7.7 项目详情工单流程图示例
```mermaid
stateDiagram-v2
direction LR
[*] --> created: 创建项目
created --> assigned: 分配填写人
assigned --> in_progress: 开始填写
in_progress --> draft_saved: 保存草稿
draft_saved --> in_progress: 继续填写
in_progress --> pending_review: 提交审核
pending_review --> approved: 审批通过
pending_review --> returned: 审批打回
returned --> in_progress: 重新填写
approved --> closed: 项目认证完成
closed --> [*]
classDef completed fill:#4caf50,color:#fff
classDef current fill:#ff9800,color:#fff,stroke-width:3px
classDef pending fill:#e0e0e0,color:#666
```
### 7.8 前端渲染方案Vue
- **开源库**:采用 Vue-Mermaid 组件库 `@mermaid-js/mermaid-tiny`,保持与官方 Mermaid 渲染一致。
- **渲染流程**:调用 `/api/workflow/diagram` 获取 `mermaid_code``current_node``nodes` → 前端异步加载 `mermaid` → 将 `mermaid_code` 传入 VueMermaid 组件渲染 → 根据 `current_node`/`nodes` 动态追加 `classDef``class` 语句实现高亮。
- **兼容性**:使用 SVG 与 ES2020 基础能力,在 Chrome、Firefox 通过官方库验证;初始化时开启 `securityLevel: 'strict'`,避免依赖私有 API。
- **后端约束**:后端不做 SVG/PNG 渲染,无需配置 Node.js 或 Chrome 运行时,仅生成 Mermaid 源码。
### 7.9 动态加载与性能优化
- 通过 `import('mermaid')` 异步加载,避免进入主 bundle可在组件 `mounted`/`onMounted` 时按需初始化。
- 初始化示例:
```js
const { default: mermaid } = await import('mermaid');
mermaid.initialize({
startOnLoad: false,
securityLevel: 'strict',
theme: 'default',
});
```
- Vue 示例(伪代码):
```vue
<template>
<VueMermaid v-if="mermaidReady" :id="`workflow-${id}`" :value="patchedMermaidCode" />
<div v-else>流程图加载中</div>
<button @click="prefetch()">预加载Mermaid</button>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import VueMermaid from '@mermaid-js/mermaid-tiny';
const props = defineProps({ code: String, currentNode: String, nodes: Array });
const mermaidReady = ref(false);
const patchedMermaidCode = computed(() => injectClasses(props.code, props.currentNode, props.nodes));
async function bootstrap() {
if (mermaidReady.value) return;
await import('mermaid'); // 不进入主 bundle
mermaidReady.value = true;
}
function prefetch() {
// 悬停/首屏可调用,进一步降低首次渲染等待
bootstrap();
}
onMounted(bootstrap);
</script>
```
### 7.10 测试方法(项目详情工单)
目标:渲染项目详情工单在每个状态下的 Mermaid 源码,输出为一个 SVG 文件,人工核验是否与 [project-detail-workflow.md](diagrams/project-detail-workflow.md) 一致。
1. **准备状态集合**`['created','assigned','in_progress','draft_saved','pending_review','approved','returned','closed']`
2. **基准 Mermaid 模板**(包含扩展状态 `draft_saved` 与高亮占位符 `__CURRENT__`
```mermaid
stateDiagram-v2
direction LR
[*] --> created: 创建项目
created --> assigned: 分配填写人
assigned --> in_progress: 用户开始填写
in_progress --> draft_saved: 保存草稿
draft_saved --> in_progress: 继续填写
in_progress --> pending_review: 提交审核
in_progress --> assigned: 重新分配
pending_review --> approved: 审批通过
pending_review --> returned: 审批打回
returned --> in_progress: 用户重新填写
returned --> pending_review: 重新提交
approved --> closed: 项目认证完成
closed --> [*]
classDef completed fill:#4caf50,color:#fff
classDef current fill:#ff9800,color:#fff,stroke-width:3px
classDef pending fill:#e0e0e0,color:#666
class __CURRENT__ current
```
3. **浏览器端生成单一 SVG 文件**(在 Chrome/Firefox 打开任意页面按 F12 粘贴执行,需联网获取 `mermaid` 包,满足跨浏览器验证):
```js
const states = ['created','assigned','in_progress','draft_saved','pending_review','approved','returned','closed'];
const template = `stateDiagram-v2
direction LR
[*] --> created: 创建项目
created --> assigned: 分配填写人
assigned --> in_progress: 用户开始填写
in_progress --> draft_saved: 保存草稿
draft_saved --> in_progress: 继续填写
in_progress --> pending_review: 提交审核
in_progress --> assigned: 重新分配
pending_review --> approved: 审批通过
pending_review --> returned: 审批打回
returned --> in_progress: 用户重新填写
returned --> pending_review: 重新提交
approved --> closed: 项目认证完成
closed --> [*]
classDef completed fill:#4caf50,color:#fff
classDef current fill:#ff9800,color:#fff,stroke-width:3px
classDef pending fill:#e0e0e0,color:#666
class __CURRENT__ current`;
const { default: mermaid } = await import('mermaid');
mermaid.initialize({ startOnLoad: false, securityLevel: 'strict' });
const fragments = [];
for (const [index, state] of states.entries()) {
const code = template.replace('__CURRENT__', state);
const { svg } = await mermaid.render(`project-detail-${state}`, code);
const inner = svg.replace(/^<svg[^>]*>|<\/svg>$/g, '');
fragments.push(`<g transform="translate(0, ${index * 360})">${inner}</g>`);
}
const height = states.length * 360 + 40;
const combined = `<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="${height}">${fragments.join('\n')}</svg>`;
const blob = new Blob([combined], { type: 'image/svg+xml' });
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'project-detail-states.svg';
a.click();
```
4. **人工核验**:打开 `project-detail-states.svg`,逐段确认节点、连线、文案及高亮与流程设计一致;如有差异,调整模板并重新生成。
---
## 8. 相关文档
| 文档 | 内容 |
|------|------|
| [用户注册工单流程](diagrams/user-registration-workflow.md) | 用户注册工单的状态机、流程图、时序图 |
| [用户管理工单流程](diagrams/user-management-workflow.md) | 用户管理工单的状态机、流程图、时序图 |
| [项目信息填写工单流程](diagrams/project-detail-workflow.md) | 项目详情工单的状态机、流程图、时序图 |
| [微服务更新工单流程](diagrams/microservice-update-workflow.md) | 微服务更新工单的状态机、流程图、时序图 |
| [工单流程PRD](2-rmdc-work-procedure-PRD.md) | 产品需求文档 |
---
## 9. 参考设计
设计参考了以下开源项目的最佳实践:
1. **Ferry** - Go语言工单系统支持工作流引擎、权限管理、灵活配置
2. **Flowable** - Java工作流引擎乐观锁并发控制机制
3. **Camunda** - BPMN工作流引擎微服务编排
4. **NocoBase** - 低代码平台,灵活的数据建模与工作流设计

View File

@@ -0,0 +1,271 @@
# 工单流程模块(工单系统)
** 工单流程在下文中等同于工单 **
## 工单流程模块与其他模块的关系
1. rmdc-project-management依赖本模块
2. rmdc-user-auth模块依赖本模块
3. deliver-update模块依赖本模块
## 工单流程说明
### 工单流程发起与处理
1. 工单流程发起
1. 工单流程从特定的模块中发起
1. 用户模块 rmdc-user-auth
2. 项目管理模块 rmdc-project-management
2. 不涉及手动创建工单,本项目均通过业务模块直接创建工单
2. 工单流程处理
1. 所有用户具备工单流程的页面
1. 可以查看到自己的发起的工单流程
2. 可以查看到自己的被委派(需要处理)的工单流程
3. 展示完整的工单流程列表,点击可以查看到工单流程的详情
2. 工单流程的详情页面
1. 具体的详情页面需要根据各个模块的工单流程逻辑进行定制
2. 工单详情页面的模板相同
3. 工单详情页面绑定覆盖业务模块的必要信息,可以直接调转到业务模块的详情页面
3. **工单流程状态追踪机制**
1. **业务回调机制**: 业务模块处理完成后,必须调用工单系统的回调接口 `POST /api/workflow/callback` 更新工单状态
2. **状态变更历史表**: 所有状态变更均写入 `workflow_track_history` 表,支持全生命周期审计
3. **实时通知推送**: 状态变更时通过通知中心模块向发起人和处理人推送实时通知(WebSocket/App推送)
4. **轮询兜底**: 前端可选配置定时轮询接口 `GET /api/workflow/{id}/status` 获取最新状态
4. 工单流程通知
1. 通过[通知中心模块](0-设计方案/6-rmdc-notice-center)进行消息通知的
### 工单流程执行策略
1. 从非超级管理员用户到超级管理员的工单流程,有如下的策略
1. 超级管理员可以自行执行
2. 超级管理员可以委派工单执行人,即执行人可以变更
3. 超级管理员可以设置自动审批,工单可以自动审批处理
4. 超级管理员可以设置定时执行,代表工单审批通过,在未来的特定时间点执行
2. 超级管理员到非超级管理员用户的工单流程
1. 非超级管理员用户无法委派,即执行人无法变更
2. 只能由非超级管理员用户自行操作执行
### 工单流程的生命周期
1. 工单流程的生命周期
1. 工单流程的创建
2. 工单流程的处理
3. 工单流程的完成
4. 工单流程的撤销
5. 工单流程的拒绝
6. 工单流程的超时
7. 工单流程的结束
2. **并发处理场景** - 当用户正在处理工单流程时的竞态条件处理
1. **工单流程被委派给其他用户**
- 采用 **乐观锁机制**: 工单表增加 `version` 字段,每次更新必须校验版本号
- 委派操作成功后,通过通知中心向原处理人推送 `WORKFLOW_REASSIGNED` 事件
- 前端收到事件后显示提示弹窗: "此工单已被重新委派给XXX,您的处理权限已转移"
- 原处理人页面切换为只读模式或引导返回列表
- 若原处理人仍尝试提交,后端校验版本号不匹配,返回 `409 Conflict`
2. **工单流程被撤销**
- 撤销操作前校验工单状态: 仅 `pending/assigned` 状态可直接撤销
- `in_progress` 状态撤销需要二次确认,并通知处理人
- 撤销成功后推送 `WORKFLOW_REVOKED` 事件
- 前端收到事件后自动关闭处理页面,引导至工单列表
- 已执行的步骤数据保留,状态标记为 `revoked`
3. **工单流程被修改**
- 修改操作前校验乐观锁版本号
- 仅特定状态允许修改: `pending/assigned/returned`
- 修改成功后推送 `WORKFLOW_MODIFIED` 事件,携带变更字段摘要
- 前端收到事件后提示刷新,或自动刷新表单数据
- 如用户本地有未保存的修改,提示冲突并允许手动合并
3. 每一个工单流程具备唯一的ID进行全生命周期的追踪处理
1. 唯一ID的生成方式, 模块简称+时间戳+发起人英文名称
2. 例子 项目管理模块发起的工单流程ID为 project-20260106110303-zeaslity
## 工单流程持久化说明
1. 每一个工单流程需要进行持久化保存
2. 每一种类型的工单流程的状态机是否应该不同
3. 工单流程必须的字段
1. 工单流程ID
2. 工单流程发起人
3. 工单流程发起时间
4. 工单流程超时时间 需要在多长时间内完成
5. 工单流程处理人
6. 工单流程被委派人 工单流程的实际处理人
7. 工单流程处理时间
8. 工单流程处理状态
9. 工单流程处理结果
10. 工单流程处理备注
11. 工单流程每一步骤的处理时间
12. 工单流程每一步骤的处理人
13. 工单流程每一步骤的处理状态
14. 工单流程每一步骤的处理结果
15. 工单流程每一步骤的处理备注 为下一步提供信息
16. 工单流程可能需要传递参数给下一步
## 工单流程权限
### 项目信息填写工单流程权限
1. 非超级管理员用户
1. 只能查看,处理分配给自己的或者自己创建的项目信息填写工单
2. 超级管理员
1. 可以查看,处理全部项目信息填写工单
### 微服务更新流程权限
1. 非超级管理员用户
1. 只能查看,处理自己创建的微服务更新工单流程
2. 超级管理员
1. 可以查看,处理全部微服务更新工单流程
### 用户注册工单流程权限
1. 非超级管理员用户
1. 只能查看,处理自己创建的用户注册工单流程
2. 超级管理员
1. 可以查看,处理全部的用户注册工单流程
### 用户信息管理工单流程权限
1. 非超级管理员用户
1. 只能查看,处理自己创建的户信息管理工单流程
2. 超级管理员
1. 可以查看,处理全部的户信息管理工单流程
## 工单流程详情
1. 工单流程的每一步均可以附带信息给下一步
2. 工单流程可能需要传递参数给下一步
### 项目信息填写工单流程
1. 超级管理员初步创建项目的Metadata数据
2. 发起工单分派给普通用户进行项目详情的填写
3. 普通用户可以保存草稿,直到可以提交项目审批
4. 普通用户提交项目审批
5. 自动分配给超级管理员审批
6. 超级管理员进行项目的审批
1. 审批通过
1. 工单结束
2. 项目详情表正式上线
2. 审批拒绝
1. 重新回到普通用户补充项目信息的阶段(项目详情处于草稿状态)
2. 用户重新修改项目的详情信息之后
3. 用户可以基于此工单重新提交审批
3. 超级管理员可以进行项目管理详情的修改,修改完成之后,工单结束
7. 当用户的项目信息没有被审批通过
1. 草稿状态的项目信息应该绑定唯一工单
2. 草稿状态的项目详情应该显示工单号
3. 草稿状态的项目信息,提交审批之后可以跳转到 项目详情工单详情页面
4. 除非工单的状态进入到closed状态项目信息才可以重新关联新的工单
8. 用户无法取消项目详情工单的流程
1. 只有超级管理员可以取消项目详情工单
### 用户注册工单流程
1. 非超级管理员用户的在用户注册之后
1. 用户状态默认为 disabled
2. 启动用户注册工单流程
1. 自动创建用户注册工单
2. 自动提交给超级管理员
3. 超级管理员审核
1. 审核通过
1. 自动修改用户状态为 active, 用户启用
2. 审核不通过
1. 回退到用户注册阶段
2. 用户可以重新修改用户注册信息
3. 可以在此工单详情中重新发起审批
4. 处于注册草稿状态disable的用户详情页面
1. 草稿状态的用户详情页面,需要关联唯一用户注册工单流程工单
2. 草稿状态的用户详情页面,可以发起用户注册审批
3. 草稿状态的用户详情页面,提交用户注册审批之后,可以跳转用户注册工单详情页面
5. 用户可以撤回用户注册工单申请
1. 撤回之后,工单重新进入用户信息注册阶段 created状态
2. 撤回之后,用户详情页面仍然处于草稿状态,可以进行草稿状态的操作
6. 用户可以取消注册工单流程
1. 用户取消用户注册工单之后工单进入closed状态
2. 用户取消用户注册工单之后,无法基于此工单提交审批工作
3. 取消之后,从用户数据库中硬删除创建的用户
7. 用户可以基于取消的注册工单一键重新创建新的注册工单流程
1. 密码等信息不能再前端保存
2. 密码需要重新创建
### 用户管理(修改、删除、 状态(启用、禁用))工单流程
1. 用户侧-用户管理页面,用户可以通过编辑按钮、删除按钮进行用户管理
2. 启动用户管理工单流程
1. 自动创建用户管理工单
2. 自动提交给超级管理员进行审批
3. 超级管理员审核
1. 审核通过
1. 根据管理的内容,修改用户相应的信息,更新数据库
2. 用户管理工单结束
2. 审核不通过
1. 回退到用户管理阶段
2. 用户可以继续修改相关信息,继续提交审核
4. 处于编辑状态的用户详情
1. 编辑状态的用户详情页面,需要关联唯一用户管理工单流程工单
2. 编辑状态的用户详情页面,可以发起用户管理审批
3. 编辑状态的用户详情页面,提交用户管理审批之后,可以跳转用户管理工单详情页面
5. 用户可以撤回用户管理工单流程
1. 撤回之后的管理工单处于created状态
2. 撤回之后,用户详情页面仍然处于编辑状态
3. 撤回之后,仍然可以基于此工单重新发起审批
6. 用户可以关闭用户管理工单流程
1. 关闭之后的用户管理工单处于状态机中的closed状态
2. 工单的生命周期结束,无法操作该工单的状态(即无法提交审批 审批 拒绝等)
3. 关闭之后,相应的用户详情应该退出编辑状态,用户详情页面不显示用户管理工单和相关操作
### 微服务更新工单流程
1. 普通用户在构建详情页面点击微服务更新
2. 携带构建物信息跳转至微服务更新详情页面
1. 微服务更新页面使用3大竖列的形式,发起微服务升级工单
2. 如果正确的跳转,构建物信息应该出现在最左侧一栏
3. 中间一栏是微服务更新的表单, 用户可以选择需要更新的项目及微服务, 预期的更新时间
4. 最右侧一栏是微服务更新的发起按钮
3. 普通用户提交微服务更新工单,进行工单的下一步
4. 超级管理员可以自己执行,也可以委派更新任务
5. 超级管理员进行微服务更新的审批
1. 微服务更新如果满足更新条件,则同意更新,进入工单的下一步
2. 微服务更新如果不满足更新条件,则拒绝更新,返回到普通用户修改更新信息的阶段,进行循环直到审批通过
3. 针对定期的更新,超级管理员同意更新,进入工单的下一步
6. 超级管理员进行微服务更新的执行操作
1. 微服务的更新操作,更新状态需要通过 rmdc-exchange-hub rmdc-watchdog模块进行
2. 微服务的更新状态可以在工单中展示
7. 微服务更新状态
1. 微服务更新成功,进入工单的下一步
2. 微服务更新失败,回到超级管理员进行微服务更新的执行操作,进行循环直到更新成功
8. 微服务运行状态
1. 微服务更新后运行状态正常,工单结束
2. 微服务更新后运行状态异常, rmdc-watchdog应该自动回滚微服务至更新前的版本, 工单需要记录微服务更新失败的信息, 工单结束
## 工单详情页面
### 工单处理流程图
1. 工单详情页面应该展示工单处理流程图
2. 工单处理流程图应该展示工单的当前状态
3. 工单处理流程图应该展示每一步分处理人
4. 工单处理流程图应该展示每一步的处理时间
5. 工单处理流程图应该展示每一步的处理结果
6. 工单处理流程图由后端生成mermaid格式的内容,由前端负责渲染
7. 后端需要根据工单的当前状态,生成对应的mermaid格式的内容
8. 开源的库实现为Vue-Mermaid @mermaid-js/mermaid-tiny
9. 动态加载与性能:为了减小对前端性能的影响,通过异步 import('mermaid') 来加载库,避免它进入主 bundle
### 工单处理历史
1. 工单详情页面应该展示工单处理历史
2. 工单处理历史应该展示每一步的处理人
3. 工单处理历史应该展示每一步的处理时间
4. 工单处理历史应该展示每一步的处理结果
5. 工单处理历史应该展示每一步的处理备注
### 跳转策略
1. 工单详情页面 应该可以跳转至业务详情页面
2. 工单详情页面 可以返回至工单列表页面
## 用户注册工单流程详情页面
1. 可以跳转至用户注册详情页面
2. 用户注册详情页面可以跳转至工单详情页面
3. 用户侧 和 管理测的界面有些许不同,但是大部分都可以复用
## 项目信息填写工单流程详情页面
1. 可以跳转至项目详情页面
2. 项目详情页面可以跳转至工单详情页面
3. 用户侧 和 管理测的界面有些许不同,但是大部分都可以复用
## 参考的开源工单系统
设计参考了以下开源项目的最佳实践:
1. **Ferry** - Go语言工单系统,支持工单流程引擎、权限管理、灵活配置
2. **Flowable** - Java工单流程引擎,乐观锁并发控制机制
3. **Camunda** - BPMN工单流程引擎,微服务编排
4. **NocoBase** - 低代码平台,灵活的数据建模与工单流程设计

View File

@@ -0,0 +1,313 @@
# 微服务更新工单流程
**工单类型代码**: `microservice_update`
**来源模块**: deliver-update
**编制日期**: 2026-01-08
---
## 1. 业务场景
普通用户在构建详情页面发起微服务更新请求,经过超级管理员审批后执行更新操作,并监控微服务运行状态。
### 1.1 业务规则
| 规则项 | 说明 |
|-------|------|
| 发起人 | 普通用户 |
| 审批人 | 超级管理员 |
| 执行人 | 超级管理员或委派人 |
| 支持定时执行 | 是 |
| 支持委派 | 是(超管可委派给其他人执行) |
| 自动回滚 | 是(更新失败时自动回滚) |
### 1.2 相关模块
| 模块 | 职责 |
|-----|------|
| rmdc-jenkins-branch-dac | 提供构建物信息 |
| rmdc-exchange-hub | MQTT消息中继 |
| rmdc-watchdog | K8S操作执行、状态监控 |
---
## 2. 状态机
### 2.1 状态定义
| 状态代码 | 状态名称 | 说明 | 是否扩展状态 |
|---------|---------|------|------------|
| `created` | 已创建 | 用户发起更新请求 | 否 |
| `pending_review` | 待审核 | 等待超级管理员审核 | 否 |
| `approved` | 已批准 | 审核通过,等待执行 | 否 |
| `returned` | 已打回 | 审核打回,需修改 | 否 |
| `rejected` | 已拒绝 | 审核拒绝,流程终止 | 否 |
| `executing` | 执行中 | 微服务更新正在执行 | 是 |
| `monitoring` | 监控中 | 更新完成,监控运行状态 | 是 |
| `rollbacked` | 已回滚 | 更新失败,已自动回滚 | 是 |
| `closed` | 已关闭 | 工单生命周期结束 | 否 |
| `revoked` | 已撤销 | 用户撤销更新请求 | 否 |
### 2.2 状态机图
```mermaid
stateDiagram-v2
[*] --> created: 发起更新请求
created --> pending_review: 提交审核
created --> revoked: 用户撤销
pending_review --> approved: 审批通过
pending_review --> returned: 审批打回
pending_review --> rejected: 审批拒绝
pending_review --> revoked: 用户撤销
returned --> pending_review: 修改后重新提交
returned --> revoked: 用户撤销
approved --> executing: 开始执行
approved --> approved: 等待定时执行
executing --> monitoring: 更新成功
executing --> executing: 执行重试
executing --> rollbacked: 更新失败回滚
monitoring --> closed: 运行正常
monitoring --> rollbacked: 运行异常回滚
rollbacked --> closed: 记录失败信息
rejected --> closed: 关闭工单
revoked --> closed: 关闭工单
closed --> [*]
note right of executing: 通过rmdc-watchdog执行
note right of monitoring: 监控微服务健康状态
note right of rollbacked: 自动回滚到更新前版本
```
---
## 3. 流程图
```mermaid
flowchart TD
Start([开始]) --> SelectBuild[用户选择构建物]
SelectBuild --> JumpToUpdate[跳转微服务更新页面]
JumpToUpdate --> ThreeColumns[三栏布局页面]
ThreeColumns --> LeftColumn[左栏:构建物信息]
ThreeColumns --> MiddleColumn[中栏:更新表单]
ThreeColumns --> RightColumn[右栏:发起按钮]
MiddleColumn --> FillForm[填写更新信息]
FillForm --> SelectProject[选择目标项目]
SelectProject --> SelectService[选择目标微服务]
SelectService --> SetSchedule[设置更新时间]
SetSchedule --> SubmitRequest[提交更新请求]
SubmitRequest --> CreateWorkflow[创建更新工单]
CreateWorkflow --> PendingReview{待审核}
PendingReview -->|审批通过| CheckSchedule{是否定时执行?}
PendingReview -->|审批打回| Return[打回修改]
PendingReview -->|审批拒绝| Reject[拒绝请求]
PendingReview -->|用户撤销| Revoke[撤销请求]
Return --> ModifyRequest[修改更新信息]
ModifyRequest --> SubmitRequest
CheckSchedule -->|立即执行| StartExecute[开始执行更新]
CheckSchedule -->|定时执行| WaitSchedule[等待定时触发]
WaitSchedule --> StartExecute
StartExecute --> Executing{执行更新}
Executing -->|成功| Monitoring[监控运行状态]
Executing -->|失败| RetryCheck{重试?}
RetryCheck -->|是| StartExecute
RetryCheck -->|否| Rollback[自动回滚]
Monitoring --> HealthCheck{健康检查}
HealthCheck -->|正常| CloseSuccess[工单关闭-成功]
HealthCheck -->|异常| Rollback
Rollback --> RecordFailure[记录失败信息]
RecordFailure --> CloseFailure[工单关闭-回滚]
Reject --> CloseRejected[工单关闭]
Revoke --> CloseRevoked[工单关闭]
CloseSuccess --> End([结束])
CloseFailure --> End
CloseRejected --> End
CloseRevoked --> End
```
---
## 4. 时序图
```mermaid
sequenceDiagram
autonumber
participant User as 普通用户
participant Frontend as 前端
participant Jenkins as rmdc-jenkins
participant Workflow as rmdc-work-procedure
participant SuperAdmin as 超级管理员
participant ExHub as rmdc-exchange-hub
participant Watchdog as rmdc-watchdog
participant Notice as 通知中心
%% 发起更新请求
User->>Frontend: 查看构建详情
Frontend->>Jenkins: POST /api/jenkins/build/detail
Jenkins-->>Frontend: 返回构建物信息
User->>Frontend: 点击微服务更新
Frontend->>Frontend: 跳转更新页面(携带构建信息)
User->>Frontend: 填写更新表单
Note over Frontend: 选择项目、微服务、更新时间
User->>Frontend: 点击发起更新
Frontend->>Workflow: POST /api/workflow/create
Note over Workflow: 创建microservice_update工单<br/>保存build_id, target_version
Workflow->>Workflow: 设置status=pending_review
Workflow->>Notice: 推送通知
Notice-->>SuperAdmin: 微服务更新审批通知
%% 审批阶段
alt 审批通过
SuperAdmin->>Frontend: 审批通过
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=approve
Workflow->>Workflow: 设置status=approved
alt 立即执行
Workflow->>Workflow: 设置status=executing
Workflow->>ExHub: 发送更新指令
ExHub->>Watchdog: MQTT下发更新命令
%% 执行更新
Watchdog->>Watchdog: 执行K8S滚动更新
alt 更新成功
Watchdog-->>ExHub: 上报更新成功
ExHub->>Workflow: POST /api/workflow/callback
Workflow->>Workflow: 设置status=monitoring
%% 健康监控
loop 健康检查(5分钟)
Watchdog->>Watchdog: 检查Pod状态
end
alt 运行正常
Watchdog-->>ExHub: 上报运行正常
ExHub->>Workflow: POST /api/workflow/callback
Workflow->>Workflow: 设置status=closed
Workflow->>Notice: 推送通知
Notice-->>User: 微服务更新成功
else 运行异常
Watchdog->>Watchdog: 自动回滚
Watchdog-->>ExHub: 上报回滚结果
ExHub->>Workflow: POST /api/workflow/callback
Note over Workflow: 记录rollback_info
Workflow->>Workflow: 设置status=rollbacked
Workflow->>Notice: 推送通知
Notice-->>User: 微服务更新回滚
end
else 更新失败
Watchdog->>Watchdog: 自动回滚
Watchdog-->>ExHub: 上报失败+回滚
ExHub->>Workflow: POST /api/workflow/callback
Workflow->>Workflow: 设置status=rollbacked
end
else 定时执行
Note over Workflow: 等待scheduled_at时间
Workflow->>Workflow: 定时触发执行
end
else 审批打回
SuperAdmin->>Frontend: 打回修改
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=return
Workflow->>Workflow: 设置status=returned
Workflow->>Notice: 推送通知
Notice-->>User: 更新请求被打回
else 审批拒绝
SuperAdmin->>Frontend: 拒绝请求
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=reject
Workflow->>Workflow: 设置status=rejected
end
```
---
## 5. 工单步骤定义
| 步骤序号 | 步骤名称 | 步骤类型 | 处理人 | 操作说明 |
|---------|---------|---------|-------|---------|
| 1 | 提交更新请求 | `submit` | 普通用户 | 填写更新信息并提交 |
| 2 | 审核更新请求 | `approve` | 超级管理员 | 审批通过/打回/拒绝 |
| 3 | 执行更新 | `execute` | 超级管理员/委派人 | 执行微服务滚动更新 |
| 4 | 监控运行状态 | `monitor` | 系统自动 | 监控微服务健康状态 |
---
## 6. 业务扩展字段
存储于 `microservice_update_ext` 表:
| 字段 | 类型 | 说明 |
|-----|------|------|
| `project_id` | VARCHAR(64) | 目标项目ID |
| `namespace` | VARCHAR(64) | K8S命名空间 |
| `service_name` | VARCHAR(128) | 微服务名称 |
| `build_id` | VARCHAR(128) | 构建物ID |
| `current_version` | VARCHAR(64) | 当前版本 |
| `target_version` | VARCHAR(64) | 目标版本 |
| `scheduled_at` | DATETIME | 计划执行时间 |
| `execute_result` | VARCHAR(32) | 执行结果success/failed/rollbacked |
| `rollback_info` | JSON | 回滚信息 |
### 6.1 rollback_info 示例
```json
{
"rollback_reason": "Pod健康检查失败",
"rollback_time": "2026-01-08T15:30:00Z",
"rollback_version": "v3.1.5",
"error_details": {
"pod_name": "service-abc-7d8f9c6b5d-xyz",
"error_message": "Readiness probe failed: connection refused",
"failed_checks": 3
}
}
```
---
## 7. 更新页面布局
```
┌─────────────────────────────────────────────────────────────────┐
│ 微服务更新 │
├─────────────────┬─────────────────────────┬────────────────────┤
│ 构建物信息 │ 更新表单 │ 操作区 │
│ │ │ │
│ 组织: acme │ 目标项目: [下拉选择] │ │
│ 仓库: service │ 目标微服务: [下拉选择] │ [发起更新] │
│ 分支: main │ 更新时间: [日期选择] │ │
│ 构建号: #123 │ ○ 立即执行 │ [取消] │
│ 版本: v3.2.0 │ ○ 定时执行 │ │
│ │ 备注: [文本框] │ │
│ │ │ │
└─────────────────┴─────────────────────────┴────────────────────┘
```

View File

@@ -0,0 +1,258 @@
# 项目信息填写工单流程
**工单类型代码**: `project_detail`
**来源模块**: rmdc-project-management
**编制日期**: 2026-01-08
---
## 1. 业务场景
超级管理员创建项目元数据后,分配给普通用户填写项目详情信息,填写完成后提交审核。
### 1.1 业务规则
| 规则项 | 说明 |
|-------|------|
| 发起人 | 超级管理员 |
| 填写人 | 被分配的普通用户 |
| 审批人 | 超级管理员 |
| 支持草稿 | 是(可多次保存草稿) |
| 可撤销 | 否(仅超级管理员可取消) |
| 项目状态关联 | 草稿状态绑定唯一工单 |
### 1.2 项目状态对应关系
| 工单状态 | 项目认证状态 |
|---------|------------|
| `assigned` / `in_progress` | `draft` (草稿) |
| `pending_review` | `pending` (待审核) |
| `approved` / `closed` | `official` (正式) |
| `returned` | `draft` (草稿) |
---
## 2. 状态机
### 2.1 状态定义
| 状态代码 | 状态名称 | 说明 |
|---------|---------|------|
| `created` | 已创建 | 项目创建,工单生成 |
| `assigned` | 已分配 | 已分配填写人 |
| `in_progress` | 填写中 | 用户正在填写项目信息 |
| `draft_saved` | 草稿已保存 | 扩展状态:草稿保存成功 |
| `pending_review` | 待审核 | 填写完成,等待审核 |
| `approved` | 已通过 | 审核通过,项目正式上线 |
| `returned` | 已打回 | 审核打回,需重新填写 |
| `closed` | 已关闭 | 工单生命周期结束 |
### 2.2 状态机图
```mermaid
stateDiagram-v2
[*] --> created: 创建项目
created --> assigned: 分配填写人
assigned --> in_progress: 用户开始填写
assigned --> assigned: 重新分配
in_progress --> in_progress: 保存草稿
in_progress --> pending_review: 提交审核
in_progress --> assigned: 重新分配
pending_review --> approved: 审批通过
pending_review --> returned: 审批打回
returned --> in_progress: 用户重新填写
returned --> pending_review: 重新提交
approved --> closed: 关闭工单
closed --> [*]
note right of approved: 项目状态变为official
note right of in_progress: 支持多次保存草稿
```
---
## 3. 流程图
```mermaid
flowchart TD
Start([开始]) --> CreateProject[超管创建项目元数据]
CreateProject --> CreateWorkflow[自动创建项目详情工单]
CreateWorkflow --> SelectFiller[选择项目信息填写人]
SelectFiller --> AssignWorkflow[工单分配给填写人]
AssignWorkflow --> NotifyFiller[通知填写人]
NotifyFiller --> UserAccept[填写人接受任务]
UserAccept --> FillDetail[填写项目详情信息]
FillDetail --> SaveDraft{保存操作}
SaveDraft -->|保存草稿| DraftSaved[草稿保存成功]
DraftSaved --> FillDetail
SaveDraft -->|提交审核| ValidateRequired{必填项校验}
ValidateRequired -->|校验失败| FillDetail
ValidateRequired -->|校验通过| SubmitReview[提交审核]
SubmitReview --> PendingReview{待审核}
PendingReview -->|审批通过| Approve[审批通过]
PendingReview -->|审批打回| Return[打回修改]
PendingReview -->|超管直接修改| AdminModify[超管修改信息]
Approve --> SetOfficial[项目状态设为official]
SetOfficial --> CloseWorkflow[关闭工单]
CloseWorkflow --> End([结束])
Return --> BackToFill[回到填写阶段]
BackToFill --> FillDetail
AdminModify --> SetOfficial
%% 重新分配分支
AssignWorkflow --> ReassignCheck{需要重新分配?}
ReassignCheck -->|是| SelectFiller
ReassignCheck -->|否| NotifyFiller
```
---
## 4. 时序图
```mermaid
sequenceDiagram
autonumber
participant Admin as 超级管理员
participant Frontend as 前端
participant Project as rmdc-project-management
participant Workflow as rmdc-work-procedure
participant User as 填写人
participant Notice as 通知中心
%% 项目创建阶段
Admin->>Frontend: 创建项目
Frontend->>Project: POST /api/project/create
Note over Project: 创建项目元数据<br/>status=draft
Project->>Workflow: POST /api/workflow/create
Note over Workflow: 创建project_detail工单<br/>保存detail_filler_id
Workflow-->>Project: 返回工单ID
Project->>Project: 关联工单ID
Project-->>Frontend: 项目创建成功
%% 分配填写人
Admin->>Frontend: 选择填写人
Frontend->>Workflow: POST /api/workflow/assign
Workflow->>Workflow: 设置status=assigned
Workflow->>Notice: 推送通知
Notice-->>User: 项目信息填写通知
%% 用户填写阶段
User->>Frontend: 进入项目详情页
Frontend->>Project: POST /api/project/detail
Project-->>Frontend: 返回项目信息+草稿数据
loop 填写并保存草稿
User->>Frontend: 填写项目信息
Frontend->>Project: POST /api/project/draft/save
Project->>Workflow: 更新draft_data
Project-->>Frontend: 草稿保存成功
end
%% 提交审核
User->>Frontend: 点击提交审核
Frontend->>Project: POST /api/project/submit
Note over Project: 校验必填项
Project->>Workflow: POST /api/workflow/transition
Note over Workflow: event=complete
Workflow->>Workflow: 设置status=pending_review
Workflow->>Notice: 推送通知
Notice-->>Admin: 项目详情审核通知
%% 审批场景
alt 审批通过
Admin->>Frontend: 点击通过
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=approve
Workflow->>Project: 回调更新项目状态
Project->>Project: 设置status=official
Workflow->>Workflow: 设置status=approved
Workflow->>Notice: 推送通知
Notice-->>User: 项目审核通过
else 审批打回
Admin->>Frontend: 点击打回
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=return<br/>附带修改意见
Workflow->>Workflow: 设置status=returned
Workflow->>Notice: 推送通知
Notice-->>User: 项目被打回
User->>Frontend: 根据意见修改
Frontend->>Project: POST /api/project/draft/save
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=resubmit
Workflow->>Workflow: 设置status=pending_review
else 超管直接修改
Admin->>Frontend: 直接修改项目信息
Frontend->>Project: POST /api/project/update
Project->>Workflow: POST /api/workflow/transition
Note over Workflow: event=approve<br/>超管直接完成
Workflow->>Workflow: 设置status=approved
end
```
---
## 5. 工单步骤定义
| 步骤序号 | 步骤名称 | 步骤类型 | 处理人 | 操作说明 |
|---------|---------|---------|-------|---------|
| 1 | 分配填写人 | `assign` | 超级管理员 | 选择项目信息填写人 |
| 2 | 填写项目信息 | `execute` | 被分配用户 | 填写项目详情,可保存草稿 |
| 3 | 审核项目信息 | `approve` | 超级管理员 | 审批通过/打回 |
---
## 6. 业务扩展字段
存储于 `project_detail_ext` 表:
| 字段 | 类型 | 说明 |
|-----|------|------|
| `project_id` | VARCHAR(64) | 关联项目ID |
| `detail_filler_id` | BIGINT | 填写人ID |
| `detail_filler_name` | VARCHAR(64) | 填写人姓名 |
| `draft_data` | JSON | 草稿数据 |
### 6.1 draft_data 示例
```json
{
"deploy_business": {
"deployer_name": "张三",
"deployer_phone": "13800138000",
"deploy_start_time": "2026-01-01",
"system_version": "v3.2.0"
},
"deploy_env": {
"network_type": "internal",
"main_public_ip": "10.0.0.1",
"host_count": 3
},
"deploy_middleware": {
"mysql": {
"internal_ip": "10.0.0.10",
"internal_port": 3306
}
},
"last_saved_at": "2026-01-08T10:30:00Z"
}
```

View File

@@ -0,0 +1,234 @@
# 用户管理工单流程
**工单类型代码**: `user_management`
**来源模块**: rmdc-user-auth
**编制日期**: 2026-01-08
---
## 1. 业务场景
非超级管理员用户对已注册用户进行管理操作(修改、删除、启用、禁用)时,需要经过超级管理员审批。
### 1.1 业务规则
| 规则项 | 说明 |
|-------|------|
| 发起人 | 管理员、普通用户(只能管理自己注册的用户) |
| 默认处理人 | 超级管理员 |
| 操作类型 | `modify`(修改)、`delete`(删除)、`enable`(启用)、`disable`(禁用) |
| 可撤销 | 是(创建人可撤销) |
| 可关闭 | 是(创建人可主动关闭) |
### 1.2 权限矩阵
| 操作人角色 | 可管理用户范围 |
|-----------|--------------|
| 超级管理员 | 所有用户(无需工单) |
| 管理员 | 普通用户、三方用户(自己注册的) |
| 普通用户 | 三方用户(自己注册的) |
| 三方用户 | 无 |
---
## 2. 状态机
### 2.1 状态定义
| 状态代码 | 状态名称 | 说明 |
|---------|---------|------|
| `created` | 已创建 | 发起用户管理操作,工单创建 |
| `pending_review` | 待审核 | 等待超级管理员审核 |
| `approved` | 已通过 | 审核通过,管理操作已执行 |
| `rejected` | 已拒绝 | 审核拒绝 |
| `returned` | 已打回 | 打回修改 |
| `revoked` | 已撤销 | 用户撤销管理操作 |
| `closed` | 已关闭 | 工单生命周期结束 |
### 2.2 状态机图
```mermaid
stateDiagram-v2
[*] --> created: 发起管理操作
created --> pending_review: 提交审核
created --> revoked: 用户撤销
created --> closed: 用户关闭
pending_review --> approved: 超管审批通过
pending_review --> rejected: 超管审批拒绝
pending_review --> returned: 超管打回
pending_review --> revoked: 用户撤销(需确认)
returned --> pending_review: 重新提交
returned --> revoked: 用户撤销
returned --> closed: 用户关闭
rejected --> closed: 关闭工单
approved --> closed: 关闭工单
revoked --> closed: 关闭工单
closed --> [*]
note right of approved: 执行管理操作
note right of closed: 退出用户编辑状态
```
---
## 3. 流程图
```mermaid
flowchart TD
Start([开始]) --> InitiateManage[发起用户管理操作]
InitiateManage --> SelectAction{选择操作类型}
SelectAction -->|修改| ModifyAction[修改用户信息]
SelectAction -->|删除| DeleteAction[删除用户]
SelectAction -->|启用| EnableAction[启用用户]
SelectAction -->|禁用| DisableAction[禁用用户]
ModifyAction --> CreateWorkflow[创建管理工单]
DeleteAction --> CreateWorkflow
EnableAction --> CreateWorkflow
DisableAction --> CreateWorkflow
CreateWorkflow --> EnterEditMode[用户进入编辑状态]
EnterEditMode --> SubmitReview[提交审核]
SubmitReview --> PendingReview{待审核}
PendingReview -->|审批通过| Approve[审批通过]
PendingReview -->|审批拒绝| Reject[直接拒绝]
PendingReview -->|打回| Return[打回修改]
PendingReview -->|用户撤销| Revoke[撤销工单]
Approve --> ExecuteAction[执行管理操作]
ExecuteAction --> UpdateDB[更新数据库]
UpdateDB --> ExitEditMode1[退出编辑状态]
ExitEditMode1 --> CloseApproved[关闭工单]
CloseApproved --> End([结束])
Return --> UserModify{用户修改操作}
UserModify -->|重新提交| SubmitReview
UserModify -->|放弃操作| CloseFromReturn[关闭工单]
Reject --> ExitEditMode2[退出编辑状态]
ExitEditMode2 --> ClosedRejected[关闭工单]
ClosedRejected --> End
Revoke --> ExitEditMode3[退出编辑状态]
ExitEditMode3 --> ClosedRevoked[关闭工单]
ClosedRevoked --> End
CloseFromReturn --> ExitEditMode4[退出编辑状态]
ExitEditMode4 --> End
```
---
## 4. 时序图
```mermaid
sequenceDiagram
autonumber
participant User as 管理人
participant Frontend as 前端
participant UserAuth as rmdc-user-auth
participant Workflow as rmdc-work-procedure
participant SuperAdmin as 超级管理员
participant Notice as 通知中心
%% 发起管理操作
User->>Frontend: 点击编辑/删除/启用/禁用
Frontend->>UserAuth: 校验管理权限
UserAuth-->>Frontend: 权限校验通过
Frontend->>Workflow: POST /api/workflow/create
Note over Workflow: 创建user_management工单<br/>保存original_data快照
Workflow->>UserAuth: 标记用户进入编辑状态
Workflow-->>Frontend: 工单创建成功
Frontend-->>User: 进入编辑模式
%% 用户修改并提交
User->>Frontend: 修改信息/确认操作
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=submit<br/>保存modified_data
Workflow->>Workflow: 设置status=pending_review
Workflow->>Notice: 推送通知
Notice-->>SuperAdmin: 用户管理审批通知
%% 审批通过场景
alt 审批通过
SuperAdmin->>Frontend: 查看工单详情
Frontend->>Workflow: POST /api/workflow/detail
Workflow-->>Frontend: 返回工单信息+变更对比
SuperAdmin->>Frontend: 点击通过
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=approve
Workflow->>UserAuth: 回调执行管理操作
UserAuth->>UserAuth: 根据action_type执行操作
Workflow->>UserAuth: 清除用户编辑状态
Workflow->>Workflow: 设置status=approved
Workflow->>Notice: 推送通知
Notice-->>User: 管理操作已通过
%% 打回场景
else 打回修改
SuperAdmin->>Frontend: 点击打回
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=return<br/>附带修改意见
Workflow->>Workflow: 设置status=returned
Workflow->>Notice: 推送通知
Notice-->>User: 管理操作被打回
User->>Frontend: 根据意见修改
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=resubmit
Workflow->>Workflow: 设置status=pending_review
%% 用户关闭场景
else 用户主动关闭
User->>Frontend: 点击关闭工单
Frontend->>Workflow: POST /api/workflow/close
Workflow->>UserAuth: 清除用户编辑状态
Workflow->>Workflow: 设置status=closed
Note over Workflow: 放弃所有修改
end
```
---
## 5. 工单步骤定义
| 步骤序号 | 步骤名称 | 步骤类型 | 处理人 | 操作说明 |
|---------|---------|---------|-------|---------|
| 1 | 提交管理操作 | `submit` | 创建人 | 提交管理操作审核 |
| 2 | 审核管理操作 | `approve` | 超级管理员 | 审批通过/拒绝/打回 |
---
## 6. 业务扩展字段
存储于 `user_management_ext` 表:
| 字段 | 类型 | 说明 |
|-----|------|------|
| `target_user_id` | BIGINT | 被管理用户ID |
| `action_type` | VARCHAR(32) | 操作类型modify/delete/enable/disable |
| `original_data` | JSON | 变更前数据快照 |
| `modified_data` | JSON | 期望变更数据 |
### 6.1 original_data / modified_data 示例
```json
{
"username": "zhangsan",
"chinese_name": "张三",
"email": "zhangsan@example.com",
"phone": "13800138000",
"group_name": "产品与解决方案组",
"dev_role": "backend",
"rmdc_role": "normal"
}
```

View File

@@ -0,0 +1,190 @@
# 用户注册工单流程
**工单类型代码**: `user_registration`
**来源模块**: rmdc-user-auth
**编制日期**: 2026-01-08
---
## 1. 业务场景
非超级管理员用户注册新用户后,需要经过超级管理员审批才能激活用户账号。
### 1.1 业务规则
| 规则项 | 说明 |
|-------|------|
| 发起人 | 管理员、普通用户(根据权限可注册不同角色账号) |
| 默认处理人 | 超级管理员 |
| 被注册用户初始状态 | `disabled` |
| 审批通过后用户状态 | `active` |
| 可撤销 | 是(创建人可撤销) |
| 撤销后处理 | 硬删除被注册用户 |
---
## 2. 状态机
### 2.1 状态定义
| 状态代码 | 状态名称 | 说明 |
|---------|---------|------|
| `created` | 已创建 | 用户注册完成,工单自动创建 |
| `pending_review` | 待审核 | 等待超级管理员审核 |
| `approved` | 已通过 | 审核通过,用户已激活 |
| `rejected` | 已拒绝 | 审核拒绝,需重新修改 |
| `revoked` | 已撤销 | 用户取消注册 |
| `closed` | 已关闭 | 工单生命周期结束 |
### 2.2 状态机图
```mermaid
stateDiagram-v2
[*] --> created: 用户注册
created --> pending_review: 自动提交审核
created --> revoked: 用户撤销
pending_review --> approved: 超管审批通过
pending_review --> rejected: 超管审批拒绝
pending_review --> revoked: 用户撤销(需确认)
rejected --> pending_review: 用户修改后重新提交
rejected --> revoked: 用户撤销
approved --> closed: 关闭工单
rejected --> closed: 关闭工单
revoked --> closed: 关闭工单
closed --> [*]
note right of approved: 自动激活用户
note right of revoked: 硬删除用户
```
---
## 3. 流程图
```mermaid
flowchart TD
Start([开始]) --> Register[用户注册新账号]
Register --> CreateWorkflow[自动创建注册工单]
CreateWorkflow --> SetDisabled[设置用户状态为disabled]
SetDisabled --> AutoSubmit[自动提交给超级管理员]
AutoSubmit --> PendingReview{待审核}
PendingReview -->|审批通过| Approve[审批通过]
PendingReview -->|审批拒绝| Reject[打回修改]
PendingReview -->|用户撤销| RevokeConfirm{确认撤销?}
Approve --> ActivateUser[激活用户账号]
ActivateUser --> CloseApproved[关闭工单]
CloseApproved --> End([结束])
Reject --> UserModify{用户修改信息}
UserModify -->|重新提交| AutoSubmit
UserModify -->|放弃注册| RevokeFromReject[撤销工单]
RevokeConfirm -->|确认| Revoke[撤销工单]
RevokeConfirm -->|取消| PendingReview
Revoke --> DeleteUser[硬删除用户]
RevokeFromReject --> DeleteUser
DeleteUser --> ClosedRevoked[关闭工单]
ClosedRevoked --> RestartOption{一键重新创建?}
RestartOption -->|是| Register
RestartOption -->|否| End
```
---
## 4. 时序图
```mermaid
sequenceDiagram
autonumber
participant User as 注册人
participant Frontend as 前端
participant UserAuth as rmdc-user-auth
participant Workflow as rmdc-work-procedure
participant SuperAdmin as 超级管理员
participant Notice as 通知中心
%% 用户注册阶段
User->>Frontend: 填写注册表单
Frontend->>UserAuth: POST /api/user/register
UserAuth->>UserAuth: 创建用户(status=disabled)
UserAuth->>Workflow: POST /api/workflow/create
Note over Workflow: 创建user_registration工单
Workflow->>Workflow: 设置status=pending_review
Workflow->>Notice: 推送通知
Notice-->>SuperAdmin: 新用户注册审批通知
UserAuth-->>Frontend: 注册成功,待审批
Frontend-->>User: 显示等待审批状态
%% 审批通过场景
alt 审批通过
SuperAdmin->>Frontend: 查看工单详情
Frontend->>Workflow: POST /api/workflow/detail
Workflow-->>Frontend: 返回工单信息
SuperAdmin->>Frontend: 点击通过
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=approve
Workflow->>UserAuth: 回调更新用户状态
UserAuth->>UserAuth: 更新status=active
Workflow->>Workflow: 设置status=approved
Workflow->>Notice: 推送通知
Notice-->>User: 注册已通过通知
%% 审批拒绝场景
else 审批拒绝
SuperAdmin->>Frontend: 点击拒绝
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=reject
Workflow->>Workflow: 设置status=rejected
Workflow->>Notice: 推送通知
Notice-->>User: 注册被拒绝通知
%% 用户重新提交
User->>Frontend: 修改注册信息
Frontend->>UserAuth: POST /api/user/update
Frontend->>Workflow: POST /api/workflow/transition
Note over Workflow: event=resubmit
Workflow->>Workflow: 设置status=pending_review
Workflow->>Notice: 推送通知
Notice-->>SuperAdmin: 重新提交审批通知
%% 用户撤销场景
else 用户撤销
User->>Frontend: 点击撤销注册
Frontend->>Workflow: POST /api/workflow/revoke
Workflow->>Workflow: 设置status=revoked
Workflow->>UserAuth: 回调删除用户
UserAuth->>UserAuth: 硬删除用户记录
Workflow->>Workflow: 设置status=closed
end
```
---
## 5. 工单步骤定义
| 步骤序号 | 步骤名称 | 步骤类型 | 处理人 | 操作说明 |
|---------|---------|---------|-------|---------|
| 1 | 提交注册 | `submit` | 系统自动 | 用户注册后自动提交审核 |
| 2 | 审核注册 | `approve` | 超级管理员 | 审批通过/拒绝/打回 |
---
## 6. 业务扩展字段
存储于 `user_registration_ext` 表:
| 字段 | 类型 | 说明 |
|-----|------|------|
| `target_user_id` | BIGINT | 被注册用户ID |
| `original_status` | VARCHAR(32) | 原用户状态(备份) |

View File

@@ -0,0 +1,121 @@
| 序号 | 姓名 | 工号 | 手机 | 短号 | 邮箱 | 所属小组 |
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
| 1 | 周剑 | E0003260015 | 13980000043 | 63802 | zhoujian@cmii.chinamobile.com | 低空经济技术研发运营中心 |
| 2 | 李天扬 | E1000119593 | 18200367441 | | litianyang@cmii.chinamobile.com | 低空经济技术研发运营中心 |
| 3 | 陈灵美 | E1000119592 | 18884838475 | | chenlingmei@cmii.chinamobile.com | 低空经济技术研发运营中心 |
| 4 | 杨子仪 | E1000119468 | 17336343307 | | yangziyi@cmii.chinamobile.com | 低空经济技术研发运营中心 |
| 5 | 马建均 | E0003260135 | 18802881983 | 65125 | majianjun@cmii.chinamobile.com | 低空经济技术研发运营中心 |
| 6 | 彭国宇 | E1000120189 | 13648063032 | | pengguoyu@cmii.chinamobile.com | 低空经济技术研发运营中心 |
| 7 | 韩雨亭 | E1000039626 | 18802880189 | 63810 | hanyuting@cmii.chinamobile.com | 产品与解决方案组 |
| 8 | 张震 | E0003260280 | 18802880227 | 63811 | zhangzhen@cmii.chinamobile.com | 产品与解决方案组 |
| 9 | 黄佳伟 | E1000039533 | 18802880662 | 63824 | huangjiawei@cmii.chinamobile.com | 产品与解决方案组 |
| 10 | 杨瑶 | E1000047533 | 18428381971 | 63822 | yangyao01@cmii.chinamobile.com | 产品与解决方案组 |
| 11 | 刘子扬 | E0003260069 | 18802880817 | 63887 | liuziyang@cmii.chinamobile.com | 产品与解决方案组 |
| 12 | 张淼 | E1000000251 | 18782209849 | 63860 | zhangmiao@cmii.chinamobile.com | 产品与解决方案组 |
| 13 | 徐源林 | E1000041972 | 18382354080 | 63888 | xuyuanlin@cmii.chinamobile.com | 产品与解决方案组 |
| 14 | 何博 | E1000094217 | 13550064201 | 63955 | hebo@cmii.chinamoble.com | 产品与解决方案组 |
| 15 | 严朝阳 | E1000041760 | 18802881969 | 65691 | yanchaoyang@cmii.chinamobile.com | 产品与解决方案组 |
| 16 | 童钰辉 | E1000088894 | 18802880389 | 63914 | tongyuhui@cmii.chinamobile.com | 产品与解决方案组 |
| 17 | 刘庭璇 | E1000039627 | 18428359971 | 63932 | liutingxuan@cmii.chinamobile.com | 产品与解决方案组 |
| 18 | 郭忠勇 | E1000042092 | 18224071422 | 63895 | guozhongyong@cmii.chinamobile.com | 产品与解决方案组 |
| 19 | 黄知齐 | E1000111665 | 18380104927 | 63929 | huangzhiqi@cmii.chinamobile.com | 产品与解决方案组 |
| 20 | 傅军 | E1000029753 | 15208325190 | 63842 | fujun@cmii.chinamobile.com | 产品与解决方案组 |
| 21 | 牛锐 | E0003811308 | 13910388292 | | niurui@cmii.chinamobile.com | 战略组 |
| 22 | 程倩倩 | E1000047233 | 18802880930 | 63865 | chengqianqian@cmii.chinamobile.com | 战略组 |
| 23 | 林汲 | E1000094622 | 18884817362 | 63920 | linji@cmii.chinamobile.com | 战略组 |
| 24 | 兰盾 | E0003260413 | 13808205185 | 63805 | landun@cmii.chinamobile.com | 监管军团 |
| 25 | 唐兵 | E0003260554 | 18202806037 | 63876 | tangbing@cmii.chinamobile.com | 监管军团 |
| 26 | 邓玖根 | E1000047135 | 15208489298 | 63877 | dengjiugen@cmii.chinamobile.com | 监管军团 |
| 27 | 刘家琛 | E1000093002 | 18215599792 | 63917 | liujiachen@cmii.chinamobile.com | 监管军团 |
| 28 | 陈宽 | E1000112978 | 19982088679 | 63931 | chenkuan@cmii.chinamobile.com | 监管军团 |
| 29 | 徐晓东 | E0038015091 | 13708024468 | 63892 | xuxiaodong@cmii.chinamobile.com | 监管军团 |
| 30 | 李航宇 | E0038009499 | 15881102865 | 63834 | lihangyu@cmii.chinamobile.com | 监管军团 |
| 31 | 黄益 | E0003260227 | 18244215251 | 63894 | huangyi01@cmii.chinamobile.com | 监管军团 |
| 32 | 张愉菲 | E1000092739 | 18280136310 | 63915 | zhangyufei@cmii.chinamobile.com | 监管军团 |
| 33 | 郑文龙 | E1000047230 | 13890436063 | 63878 | zhengwenlong@cmii.chinamobile.com | 监管军团 |
| 34 | 何孝游 | E1000041675 | 18380417399 | 63836 | hexiaoyou@cmii.chinamobile.com | 监管军团 |
| 35 | 王历 | E1000050130 | 18802881952 | 63875 | wangli02@cmii.chinamobile.com | 监管军团 |
| 36 | 彭璐 | E1000030112 | 13688161465 | 63806 | penglu@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 37 | 成均保 | E0003260372 | 18802881118 | 63815 | chengjunbao@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 38 | 管泽鑫 | E1000048417 | 18802881168 | 63882 | guanzexin@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 39 | 左莹莹 | E0003260324 | 18802881112 | 63812 | zuoyingying@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 40 | 王艺霖 | E1000047239 | 18408218668 | 63813 | wangyilin@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 41 | 孔祥 | E1000046205 | 18628265601 | 63884 | kongxiang@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 42 | 李垚 | E1000044408 | 18200532206 | 63883 | liyao@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 43 | 向昱佼 | E0003260048 | 18802880204 | 63885 | xiangyujiao@cmii.chinamobile.com | 创新研究与应用组(PMO) |
| 44 | 邱裕鹤 | E0003260241 | 18802880201 | 63803 | qiuyuhe@cmii.chinamobile.com | 云平台系统组 |
| 45 | 任一珂 | E1000000224 | 13558770317 | 63833 | renyike@cmii.chinamobile.com | 监视控制组 |
| 46 | 吴云江 | E1000029758 | 13679007674 | 63880 | wuyunjiang@cmii.chinamobile.com | 监视控制组 |
| 47 | 李煜寒 | E1000041015 | 18802880525 | 63839 | liyuhan@cmii.chinamobile.com | 监视控制组 |
| 48 | 王少飞 | E1000042202 | 13438837100 | 63840 | wangshaofei@cmii.chinamobile.com | 监视控制组 |
| 49 | 王义元 | E1000042204 | 18802881214 | 63879 | wangyiyuan@cmii.chinamobile.com | 监视控制组 |
| 50 | 袁雪波 | E1000030093 | 15281059786 | 63862 | yuanxuebo@cmii.chinamobile.com | 监视控制组 |
| 51 | 张聪 | E0003260142 | 18802881839 | 63818 | zhangcong@cmii.chinamobile.com | 监视控制组 |
| 52 | 王子文 | E1000047232 | 18802881074 | 63864 | wangziwen@cmii.chinamobile.com | 监视控制组 |
| 53 | 罗瑞 | E0003260343 | 18802881217 | 63816 | luorui@cmii.chinamobile.com | 监视控制组 |
| 54 | 李松 | E1000000485 | 15882223415 | 63912 | lisong@cmii.chinamobile.com | 监视控制组 |
| 55 | 王清 | E1000000225 | 18215575866 | 63858 | wangqing@cmii.chinamobile.com | 智能云网组 |
| 56 | 刘喜 | E0003260164 | 15828477091 | 63866 | liuxi@cmii.chinamobile.com | 智能云网组 |
| 57 | 何虎 | E1000049890 | 13308059662 | 63841 | hehu@cmii.chinamobile.com | 智能云网组 |
| 58 | 罗文 | E1000039988 | 18780009301 | 63846 | luowen@cmii.chinamobile.com | 智能云网组 |
| 59 | 唐志梁 | E1000049663 | 18802880517 | 63847 | tangzhiliang@cmii.chinamobile.com | 智能云网组 |
| 60 | 钟林林 | E1000029771 | 15208192232 | 63844 | zhonglinlin@cmii.chinamobile.com | 智能云网组 |
| 61 | 胡宝顺 | E1000040553 | 15928589640 | 63835 | hubaoshun@cmii.chinamobile.com | 智能云网组 |
| 62 | 郝昊 | E1000109766 | 14708066381 | 63927 | haohao@cmii.chinamobile.com | 智能云网组 |
| 63 | 张雅洁 | E0003260313 | 18802880806 | 63820 | zhangyajie@cmii.chinamobile.com | 智能云网组 |
| 64 | 龙卫 | E1000036080 | 18280096573 | 63838 | longwei@cmii.chinamobile.com | 智能云网组 |
| 65 | 冉靖 | E1000103347 | 13540664346 | 63924 | ranjing@cmii.chinamobile.com | 智能云网组 |
| 66 | 张睿婧 | E1000103348 | 13689066043 | 63923 | zhangruijing@cmii.chinamobile.com | 智能云网组 |
| 67 | 郑岩 | E1000108860 | 18328603976 | 63928 | zhengyan@cmii.chinamobile.com | 智能云网组 |
| 68 | 刘芸志 | E1000030098 | 18802881811 | 63825 | liuyunzhi@cmii.chinamobile.com | 视觉交互组 |
| 69 | 谭雪敏 | E1000050960 | 13488938986 | 63826 | tanxuemin@cmii.chinamobile.com | 视觉交互组 |
| 70 | 王雄飞 | E1000036084 | 15108281409 | 63827 | wangxiongfei@cmii.chinamobile.com | 视觉交互组 |
| 71 | 罗婷婷 | E1000030087 | 18802880413 | 63828 | luotingting@cmii.chinamobile.com | 视觉交互组 |
| 72 | 李佩哲 | E1000036085 | 18328088043 | 63829 | lipeizhe@cmii.chinamobile.com | 视觉交互组 |
| 73 | 杨淳婷 | E0003260183 | 18802880215 | 63830 | yangchunting@cmii.chinamobile.com | 视觉交互组 |
| 74 | 李贞 | E0003260187 | 18384166196 | 63831 | lizhen@cmii.chinamobile.com | 视觉交互组 |
| 75 | 朱君妍 | E1000049635 | 13980501129 | 63821 | zhujunyan@cmii.chinamobile.com | 视觉交互组 |
| 76 | 梁运珠 | E1000049209 | 18200259225 | 63859 | liangyunzhu@cmii.chinamobile.com | 视觉交互组 |
| 77 | 汪珂丽 | E1000088899 | 18810909875 | | wangkeli@cmii.chinamobile.com | 空域计算组 |
| 78 | 秦正 | E1000029111 | 18802880226 | 63849 | qinzheng@cmii.chinamobile.com | 空域计算组 |
| 79 | 周金福 | E0003260323 | 18224495673 | 63855 | zhoujinfu@cmii.chinamobile.com | 空域计算组 |
| 80 | 张艾 | E1000029770 | 15208206929 | 63843 | zhangai@cmii.chinamobile.com | 空域计算组 |
| 81 | 李志杨 | E1000036309 | 18628380221 | 63845 | lizhiyang@cmii.chinamobile.com | 空域计算组 |
| 82 | 杨云猇 | E1000041171 | 13550397849 | 63848 | yangyunxiao@cmii.chinamobile.com | 空域计算组 |
| 83 | 赵子瑶 | E0003260332 | 18802880615 | 63817 | zhaoziyao@cmii.chinamobile.com | 空域计算组 |
| 84 | 刘晨虹 | E1000103357 | 19827801957 | 63922 | liuchenhong@cmii.chinamobile.com | 空域计算组 |
| 85 | 黄滟茹 | E1000103362 | 13693498572 | 63925 | huangyanru@cmii.chinamobile.com | 空域计算组 |
| 86 | 杨文彬 | E1000084157 | 15216616583 | 63916 | yangwenbin@cmii.chinamobile.com | 空域计算组 |
| 87 | 吴庆洲 | E1000048906 | 13880168124 | 63850 | wuqingzhou@cmii.chinamobile.com | Al+能力组 |
| 88 | 崔诚煜 | E1000047244 | 17358568202 | 63851 | cuichengyu@cmii.chinamobile.com | Al+能力组 |
| 89 | 段亚康 | E1000041886 | 18802881205 | 63853 | duanyakang@cmii.chinamobile.com | Al+能力组 |
| 90 | 米俊桦 | E1000047236 | 18780275860 | 63856 | mijunhua@cmii.chinamobile.com | Al+能力组 |
| 91 | 王玲玉 | E1000048430 | 18802880318 | 63857 | wanglingyu@cmii.chinamobile.com | Al+能力组 |
| 92 | 王水介 | E1000041170 | 18215623760 | 63837 | wangshuijie@cmii.chinamobile.com | Al+能力组 |
| 93 | 陈盛伟 | E0003260259 | 13730884296 | 63804 | chenshengwei@cmii.chinamobile.com | 应急军团 |
| 94 | 张雷 | E1000045186 | 13568880613 | 63867 | zhanglei@cmii.chinamobile.com | 应急军团 |
| 95 | 阳煦平 | E1000026734 | 18802880109 | 63869 | yangxuping@cmii.chinamobile.com | 应急军团 |
| 96 | 谭倩 | E1000040200 | 15198157192 | 63873 | tanqian@cmii.chinamobile.com | 应急军团 |
| 97 | 王文靖 | E0003260163 | 18802881201 | 63870 | wangwenjing@cmii.chinamobile.com | 应急军团 |
| 98 | 李帆 | E1000047536 | 15008406387 | 63872 | lifan01@cmii.chinamobile.com | 应急军团 |
| 99 | 曾辉 | E1000049874 | 18382023722 | 63871 | zenghui@cmii.chinamobile.com | 应急军团 |
| 100 | 刘东 | E0003260050 | 13981766521 | 63808 | liudong@cmii.chinamobile.com | 应急军团 |
| 101 | 李爽 | E1000029110 | 18683782070 | 63874 | lishuang@cmii.chinamobile.com | 应急军团 |
| 102 | 杨光平 | E1000000252 | 13881748089 | 63868 | yangguangping@cmii.chinamobile.com | 应急军团 |
| 103 | 袁嵩 | E1000093977 | 18802880885 | 63919 | yuansong@cmii.chinamobile.com | 应急军团 |
| 104 | 蔡为 | E1000026733 | 18802881450 | 63898 | caiwei@cmii.chinamobile.com | 应急军团 |
| 105 | 陶科翔 | E0038037028 | 13909008628 | 63890 | taokexiang@cmii.chinamobile.com | 行业组南区 |
| 106 | 刘桓良 | E0038016245 | 13540246242 | 63893 | liuhuanliang@cmii.chinamobile.com | 行业组南区 |
| 107 | 刘绍坤 | E0003901279 | 15828665201 | 63823 | liushaokun@cmii.chinamobile.com | 行业组南区 |
| 108 | 张杨 | E0003260053 | 13880606478 | 63809 | zhangyang@cmii.chinamobile.com | 行业组南区 |
| 109 | 卢禹杉 | E0003260398 | 18802881163 | 63889 | luyushan@cmii.chinamobile.com | 行业组南区 |
| 110 | 邹安洋 | E0003260149 | 15802893337 | 63891 | zouanyang@cmii.chinamobile.com | 行业组南区 |
| 111 | 闫少普 | E0003260162 | 18802881206 | 63886 | yanshaopu@cmii.chinamobile.com | 行业组南区 |
| 112 | 王佳章 | E1000047237 | 18802880882 | 63881 | wangjiazhang@cmii.chinamobile.com | 行业组南区 |
| 113 | 刘长杰 | E0003260049 | 13608177983 | 63807 | liuchangjie@cmii.chinamobile.com | 行业组北区 |
| 114 | 何源 | E0003260064 | 13666181777 | 63911 | heyuan@cmii.chinamobile.com | 行业组北区 |
| 115 | 覃小龙 | E0003260166 | 18802880145 | 63897 | qinxiaolong@cmii.chinamobile.com | 行业组北区 |
| 116 | 陈一溶 | E1000064296 | 15008491662 | 63930 | chenyirong@cmii.chinamobile.com | 行业组北区 |
| 117 | 唐飞 | E0003260158 | 18802880112 | 63899 | tangfei@cmii.chinamobile.com | 行业组北区 |
| 118 | 杨尧 | E0003260193 | 18802881998 | 63814 | yangyao@cmii.chinamobile.com | 行业组北区 |
| 119 | 贾金岩 | E0003260263 | 18802880610 | 63863 | jiajinyan@cmii.chinamobile.com | 行业组北区 |

View File

@@ -0,0 +1,76 @@
# 用户权限控制逻辑与验证步骤
## 权限控制逻辑
```mermaid
flowchart TD
A[用户发起注册] --> B{检查操作人角色}
B -->|超级管理员| C[直接创建用户 - 状态 active]
B -->|管理员| D{目标角色}
B -->|普通用户| E{目标角色}
B -->|三方用户| F[拒绝 - 无权限]
D -->|normal/third| G[创建用户 - 状态 disabled<br/>创建工单等待审批]
D -->|其他| F
E -->|third| G
E -->|其他| F
G --> H[超级管理员审批]
H -->|通过| I[用户状态改为 active]
H -->|拒绝| J[用户保持 disabled]
```
## 验证步骤
### 1. 用户注册工单测试
1. 使用 **非超级管理员** (如 admin 或 normal 用户) 登录。
2. 对于 **Normal 用户**:
- 侧边栏点击 **用户管理**
- 点击 **新建用户**,应跳转到 `/user/register-user`
- 提交注册后,应跳转到 `/user/workflows` (我的工单)。
3. 对于 **Admin 用户**:
- 进入 **系统管理 -> 用户管理**
- 点击 **新建用户**,应跳转到 `/admin/users/register`
- 提交注册后,应跳转到 `/admin/workflows` (工单管理)。
4. 填写注册信息,点击提交。
- 预期:提示“注册申请已提交”,不直接创建可用用户。
5. 切换为 **超级管理员** (superadmin) 登录。
6. 进入 **我的工单** 或工单管理页面,查看待审批的注册工单。
7. 点击工单详情,查看注册信息是否正确显示。
8. 审批通过工单。
- 预期:工单状态变为 Approved用户状态变为 active。
9. 在用户管理列表中验证新用户已存在且为激活状态。
### 2. 用户广场与管理功能测试
1. **用户广场 (User Square)**
- 登录普通用户。
- 侧边栏点击 **用户广场** (替代原通讯录)。
- 验证页面展示是否类似项目列表(支持卡片/表格切换)。
- 验证搜索和筛选功能是否正常。
- 验证点击用户仅弹出详情,**无**编辑/删除按钮。
- **数据验证**:应能看到所有 active 用户(包括其他管理员创建的),但看不到 active 以外的用户。
2. **用户管理 (User Management)**
- 侧边栏点击 **用户管理**
- **普通用户**:验证只能看到 **自己创建的** 用户(包括待审核、已禁用等状态)。不能看到别人创建的用户。
- **管理员**:验证能看到所有用户。
- 验证 **编辑/删除** 按钮是否出现,并能正常触发工单流程。
3. **用户注册 (User Registration)**
- 侧边栏点击 **用户管理 -> 新建用户**(或通过路由 `/user/register-user`)。
- 验证是否进入注册页面。
### 3. 用户管理工单测试
1. 使用 **管理员** (admin) 登录。
2.**用户管理** 列表中,对一个 **普通用户** (normal) 或 **三方用户** (third) 进行编辑。
3. 修改信息并填写 **变更理由**,点击更新。
- 预期:提示“修改申请已提交”。
4. 对同一用户点击 **删除** 按钮,填写 **删除理由**,点击确认。
- 预期:提示“删除申请已提交”。
5. 切换为 **超级管理员** (superadmin) 登录。
6. 查看相应的管理工单,审批通过。
7. 验证用户信息已更新或用户已被删除。

View File

@@ -0,0 +1,112 @@
# 用户认证模块
## 用户体系
### 项目初始化数据
1. [公司通信录](0-设计方案\9-rmdc-user-auth\9-user-contact-list.md)应该作为项目数据库初始化的数据导入到数据库中
### 用户结构体
1. 用户ID
2. 用户中文名 必须要真实姓名
1. 默认为[公司通信录]中的姓名
3. 用户英文名 也是昵称 可以为任意
1. 默认为[公司通信录]中邮箱去除掉@之后的部分
4. 用户头像ID avatar_id
5. 用户头像框ID avatar_frame_id
6. 性别 gender
7. 电子邮箱
8. 手机号
9. 短号
10. 工号 work_id
11. 所属小组 group_name 产品与解决方案组
12. 状态 user_status active, locked, disabled 默认为 locked 删除为 disabled
13. 注册人ID registered_by_id 被谁注册的
14. 密码 需要保存的是加密后的密码 默认值是 supercyy.1加密后的hash值
15. 密码过期时间 password_expires_at
16. 开发角色 dev_role 后端开发 backend, 前端开发 frontend, 测试工程师 test, 全干工程师 ops, 行业解决方案专家 seller, 未知 unknown 默认为 unknown
17. RMDC系统角色 rmdc_role 超级管理员,管理员,普通用户,三方用户 superadmin, admin, normal, third 默认为normal
18. 注册时间
19. 更新时间
20. 删除时间(设置为disabled的时间)
## 页面功能
### 用户管理
1. 只有超级管理员具有此页面的权限
1. 管理用户的信息
1. 新增用户
2. 修改用户信息
3. 删除用户
4. 启用注册用户
2. 开启注册权限
1. 开放自己注册的功能
2. 用户自行注册之后的状态默认是 locked
### 通信录页面
1. normal用户及以上具有通信录页面的权限
2. 展示部分用户的信息,方便联系其他的用户
3. 默认使用列表的形式展示,点击用户之后可以查看用户详细信息
4. 前端支持搜索,支持通过用户中文名,英文名 手机号 短号 快速搜索到用户
## 认证体系
1. 用户使用默认密码登录之后, 强制要求修改密码
2. 用户的密码有效期为3个月,过期需要强制修改密码
3. 前端和后端之间密码的传输不能是明文的,需要进行RSA加密传输
4. RMDC后端项目启动之后,需要创建一个RSA密钥对,并保存到数据库中
1. RSA密钥对的有效期应该设置为30天,启动之后应该解析密钥对,并保存到内存中
2. 如果密钥对过期,需要重新创建密钥对,并保存到数据库中
5. 前端登录需要调用后端获取RSA公钥,然后使用公钥加密密码,再将加密后的密码发送给后端
6. 后端接收到加密后的密码之后,使用自己的私钥解密密码,然后进行密码验证
## 授权体系
1. 各个模块的授权均应该放置在此模块中进行
## 用户注册、管理功能
2026年1月8日 结合工单系统,开发非超级管理员账号的注册功能
### 用户注册、管理权限
1. RMDC角色为管理员的用户
1. 可以注册、管理(修改信息、启用、禁用、删除)普通用户权限的账户
2. 可以注册、管理(修改信息、启用、禁用、删除)三方用户权限的账户
2. RMDC角色为普通用户的用户
1. 只能注册三方用户权限的账户
2. 不能注册普通用户权限的账户
3. 只能管理(修改信息、启用、禁用、删除)自己注册的三方用户权限的账户
3. RMDC角色为三方用户的用户
1. 不能注册任何权限的账户
2. 不能管理(修改信息、启用、禁用、删除)任何用户权限的账户
4. RMDC角色为超级管理员的用户
1. 可以注册任何权限的账户
2. 可以管理(修改信息、启用、禁用、删除)任何用户权限的账户
5. 用户管理的原则为:谁注册谁管理
1. 用户管理页面的功能
2. 注册用户的注册人负责管理被注册用户的生命周期
3. 超级管理员负责审核所有用户注册的工单
### 用户注册工单流程
1. 非超级管理员用户的在用户注册之后
1. 用户状态默认为disabled
2. 启动用户注册工单流程
1. 自动创建用户注册工单
2. 自动提交给超级管理员
3. 超级管理员审核
1. 审核通过
1. 自动修改用户状态为 active, 用户启用
2. 审核不通过
1. 回退到用户注册阶段
### 用户管理工单流程
1. 非超级管理员用户的在用户管理之后
2. 启动用户管理工单流程
1. 自动创建用户管理工单
2. 自动提交给超级管理员
3. 超级管理员审核
1. 审核通过
1. 根据管理的内容,修改用户相应的信息
2. 审核不通过
1. 回退到用户管理阶段
### 用户注册页面
1. 请基于管理用户注册页面进行开发
2. 设计的更加好看