376 lines
12 KiB
Markdown
376 lines
12 KiB
Markdown
# Architecture Decision Record - 元数据任务定义管理
|
||
|
||
## 元数据
|
||
|
||
- **ADR 编号**: ADR-0013
|
||
- **创建日期**: 2026-01-18
|
||
- **状态**: 已接受
|
||
- **决策者**: Datai Team
|
||
- **相关需求**: [REQ-010-4](../requirements/REQ-010-4.md) - 元数据任务定义管理
|
||
|
||
## 上下文和问题陈述
|
||
|
||
### 背景
|
||
|
||
REQ-010-4 需求要求实现元数据任务定义的完整管理功能,包括任务的增删改查、package.xml内容配置、API版本选择、调度类型选择、Cron表达式配置、任务验证等。
|
||
|
||
### 问题
|
||
|
||
需要设计元数据任务定义管理的技术方案,解决以下关键问题:
|
||
|
||
1. **数据模型设计**: 如何设计元数据任务定义的数据模型,支持任务配置、package.xml内容、API版本、调度类型等
|
||
2. **package.xml管理**: 如何管理和验证package.xml内容,确保符合Salesforce Metadata API规范
|
||
3. **调度配置**: 如何支持Manual和Cron两种调度类型,如何验证Cron表达式
|
||
4. **任务验证**: 如何验证package.xml和调度配置,确保任务可执行
|
||
5. **API设计**: 如何设计RESTful API接口,支持任务的CRUD操作
|
||
|
||
## 决策驱动因素
|
||
|
||
### 技术约束
|
||
|
||
- 必须基于现有的Spring Boot 3 + Vue 3技术栈
|
||
- 必须使用MyBatis Plus作为持久层框架
|
||
- 必须遵循Authentication.canvas中定义的架构和调用关系
|
||
- 必须在datai-salesforce-metadata模块下实现
|
||
|
||
### 业务需求
|
||
|
||
- 支持任务的增删改查功能
|
||
- 支持package.xml内容配置和验证
|
||
- 支持API版本选择和验证
|
||
- 支持调度类型选择(Manual/Cron)
|
||
- 支持Cron表达式配置和验证
|
||
- 支持任务验证功能
|
||
|
||
### 非功能需求
|
||
|
||
- 代码符合项目编码规范,有清晰的注释
|
||
- 操作界面友好易用,提供清晰的错误信息
|
||
- 代码结构清晰,易于扩展和维护
|
||
|
||
## 考虑的选项
|
||
|
||
### 选项1:使用XML文件存储package.xml
|
||
|
||
**描述**: 将package.xml内容作为XML字符串存储在数据库中,使用XML解析库进行验证。
|
||
|
||
**优点**:
|
||
- 实现简单,直接存储XML内容
|
||
- 易于验证XML格式
|
||
- 符合Salesforce Metadata API规范
|
||
|
||
**缺点**:
|
||
- XML字符串可能很长,占用数据库空间
|
||
- 需要额外的XML解析库
|
||
- 难以可视化编辑
|
||
|
||
**风险评估**: 中
|
||
|
||
### 选项2:使用JSON格式存储package.xml配置
|
||
|
||
**描述**: 将package.xml内容解析为JSON格式存储在数据库中,使用时再转换为XML。
|
||
|
||
**优点**:
|
||
- JSON格式更易于处理和验证
|
||
- 可以使用现有的JSON工具库
|
||
- 便于前端可视化编辑
|
||
|
||
**缺点**:
|
||
- 需要JSON和XML之间的转换
|
||
- 可能丢失XML的某些特性
|
||
- 转换过程可能引入错误
|
||
|
||
**风险评估**: 中
|
||
|
||
### 选项3:使用结构化数据存储package.xml
|
||
|
||
**描述**: 将package.xml内容解析为结构化数据(元数据类型列表),存储在关联表中。
|
||
|
||
**优点**:
|
||
- 数据结构清晰,易于查询和管理
|
||
- 便于前端可视化编辑
|
||
- 可以支持更复杂的验证逻辑
|
||
|
||
**缺点**:
|
||
- 实现复杂,需要设计多个关联表
|
||
- 需要处理XML和结构化数据之间的转换
|
||
- 可能无法支持所有XML特性
|
||
|
||
**风险评估**: 高
|
||
|
||
## 决策结果
|
||
|
||
### 选定方案:选项1 - 使用XML文件存储package.xml
|
||
|
||
**理由**:
|
||
|
||
1. **符合规范**: 直接存储XML内容,完全符合Salesforce Metadata API规范,避免转换过程中的错误
|
||
2. **实现简单**: 实现复杂度最低,开发周期短
|
||
3. **验证准确**: 可以直接使用XML解析库验证XML格式,验证结果准确
|
||
4. **扩展性好**: 未来如果需要支持更复杂的配置,可以在此基础上扩展
|
||
|
||
### 拒绝其他选项的理由
|
||
|
||
- **选项2**: JSON和XML之间的转换可能引入错误,且无法完全保留XML的所有特性
|
||
- **选项3**: 实现复杂度高,开发周期长,且可能无法支持所有XML特性
|
||
|
||
## 技术方案
|
||
|
||
### 数据模型设计
|
||
|
||
#### 主表:datai_meta_task
|
||
|
||
```sql
|
||
CREATE TABLE `datai_meta_task` (
|
||
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '任务ID',
|
||
`task_name` varchar(255) NOT NULL COMMENT '任务名称',
|
||
`task_type` varchar(50) NOT NULL COMMENT '任务类型(retrieve/deploy)',
|
||
`org_config_id` bigint NOT NULL COMMENT '组织配置ID',
|
||
`package_xml` longtext COMMENT 'package.xml内容',
|
||
`api_version` varchar(20) NOT NULL COMMENT 'API版本',
|
||
`schedule_type` varchar(20) NOT NULL COMMENT '调度类型(Manual/Cron)',
|
||
`cron_expression` varchar(100) COMMENT 'Cron表达式',
|
||
`status` varchar(20) NOT NULL COMMENT '任务状态(Active/Inactive)',
|
||
`description` varchar(500) COMMENT '任务描述',
|
||
`created_by` varchar(100) COMMENT '创建人',
|
||
`created_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||
`updated_by` varchar(100) COMMENT '更新人',
|
||
`updated_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||
PRIMARY KEY (`id`),
|
||
KEY `idx_org_config_id` (`org_config_id`),
|
||
KEY `idx_task_type` (`task_type`),
|
||
KEY `idx_status` (`status`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='元数据任务定义表';
|
||
```
|
||
|
||
### API设计
|
||
|
||
#### 1. 创建任务
|
||
|
||
- **接口路径**: POST /metadata/task
|
||
- **请求参数**:
|
||
```json
|
||
{
|
||
"taskName": "任务名称",
|
||
"taskType": "retrieve",
|
||
"orgConfigId": 1,
|
||
"packageXml": "<?xml version=\"1.0\"...",
|
||
"apiVersion": "58.0",
|
||
"scheduleType": "Cron",
|
||
"cronExpression": "0 0 0 * * ?",
|
||
"description": "任务描述"
|
||
}
|
||
```
|
||
- **响应**: 返回创建的任务ID
|
||
|
||
#### 2. 查询任务列表
|
||
|
||
- **接口路径**: GET /metadata/task/list
|
||
- **请求参数**:
|
||
- pageNum: 页码
|
||
- pageSize: 每页大小
|
||
- taskName: 任务名称(可选)
|
||
- taskType: 任务类型(可选)
|
||
- status: 任务状态(可选)
|
||
- **响应**: 返回任务列表和分页信息
|
||
|
||
#### 3. 查询任务详情
|
||
|
||
- **接口路径**: GET /metadata/task/{id}
|
||
- **响应**: 返回任务详细信息
|
||
|
||
#### 4. 更新任务
|
||
|
||
- **接口路径**: PUT /metadata/task/{id}
|
||
- **请求参数**: 同创建任务
|
||
- **响应**: 返回更新结果
|
||
|
||
#### 5. 删除任务
|
||
|
||
- **接口路径**: DELETE /metadata/task/{id}
|
||
- **响应**: 返回删除结果
|
||
|
||
#### 6. 验证任务
|
||
|
||
- **接口路径**: POST /metadata/task/{id}/validate
|
||
- **响应**: 返回验证结果
|
||
|
||
### package.xml验证
|
||
|
||
#### 验证规则
|
||
|
||
1. **格式验证**: 使用XML解析库验证XML格式是否正确
|
||
2. **元数据类型验证**: 验证package.xml中配置的元数据类型是否在支持的类型列表中
|
||
3. **通配符验证**: 验证通配符使用是否正确
|
||
4. **API版本验证**: 验证API版本是否在支持的版本列表中
|
||
|
||
#### 验证实现
|
||
|
||
```java
|
||
public class PackageXmlValidator {
|
||
|
||
public ValidationResult validate(String packageXml) {
|
||
try {
|
||
// 解析XML
|
||
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
|
||
DocumentBuilder builder = factory.newDocumentBuilder();
|
||
Document doc = builder.parse(new InputSource(new StringReader(packageXml)));
|
||
|
||
// 验证根元素
|
||
NodeList types = doc.getElementsByTagName("types");
|
||
if (types.getLength() == 0) {
|
||
return ValidationResult.error("package.xml必须包含types元素");
|
||
}
|
||
|
||
// 验证元数据类型
|
||
for (int i = 0; i < types.getLength(); i++) {
|
||
Element type = (Element) types.item(i);
|
||
String typeName = type.getTextContent();
|
||
if (!isSupportedMetadataType(typeName)) {
|
||
return ValidationResult.error("不支持的元数据类型: " + typeName);
|
||
}
|
||
}
|
||
|
||
return ValidationResult.success();
|
||
} catch (Exception e) {
|
||
return ValidationResult.error("package.xml格式错误: " + e.getMessage());
|
||
}
|
||
}
|
||
|
||
private boolean isSupportedMetadataType(String typeName) {
|
||
// 检查元数据类型是否在支持的类型列表中
|
||
return MetadataTypeRegistry.contains(typeName);
|
||
}
|
||
}
|
||
```
|
||
|
||
### Cron表达式验证
|
||
|
||
#### 验证规则
|
||
|
||
1. **格式验证**: 使用Cron表达式解析库验证Cron表达式格式是否正确
|
||
2. **解析验证**: 验证Cron表达式是否能够正确解析
|
||
3. **预览验证**: 提供Cron表达式预览,显示下次执行时间
|
||
|
||
#### 验证实现
|
||
|
||
```java
|
||
public class CronExpressionValidator {
|
||
|
||
public ValidationResult validate(String cronExpression) {
|
||
try {
|
||
// 使用Quartz的CronExpression验证
|
||
CronExpression cron = new CronExpression(cronExpression);
|
||
|
||
// 验证是否有效
|
||
if (!cron.isValid()) {
|
||
return ValidationResult.error("Cron表达式格式错误");
|
||
}
|
||
|
||
// 验证是否能够计算下次执行时间
|
||
Date nextValidTime = cron.getNextValidTimeAfter(new Date());
|
||
if (nextValidTime == null) {
|
||
return ValidationResult.error("Cron表达式无法计算下次执行时间");
|
||
}
|
||
|
||
return ValidationResult.success(nextValidTime);
|
||
} catch (Exception e) {
|
||
return ValidationResult.error("Cron表达式解析错误: " + e.getMessage());
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 调度类型管理
|
||
|
||
#### 枚举定义
|
||
|
||
```java
|
||
public enum ScheduleType {
|
||
MANUAL("Manual", "手动调度"),
|
||
CRON("Cron", "Cron调度");
|
||
|
||
private final String code;
|
||
private final String description;
|
||
|
||
ScheduleType(String code, String description) {
|
||
this.code = code;
|
||
this.description = description;
|
||
}
|
||
|
||
public String getCode() {
|
||
return code;
|
||
}
|
||
|
||
public String getDescription() {
|
||
return description;
|
||
}
|
||
}
|
||
```
|
||
|
||
### API版本管理
|
||
|
||
#### 版本列表
|
||
|
||
```java
|
||
public class MetadataApiVersion {
|
||
|
||
private static final List<String> SUPPORTED_VERSIONS = Arrays.asList(
|
||
"58.0", "57.0", "56.0", "55.0", "54.0"
|
||
);
|
||
|
||
public static List<String> getSupportedVersions() {
|
||
return SUPPORTED_VERSIONS;
|
||
}
|
||
|
||
public static boolean isSupported(String version) {
|
||
return SUPPORTED_VERSIONS.contains(version);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 后果
|
||
|
||
### 正面影响
|
||
|
||
1. **开发效率**: 实现简单,开发周期短
|
||
2. **维护性**: 代码结构清晰,易于维护
|
||
3. **扩展性**: 未来可以在此基础上扩展更多功能
|
||
4. **准确性**: 直接存储XML,避免转换错误
|
||
|
||
### 负面影响
|
||
|
||
1. **存储空间**: XML字符串可能占用较多数据库空间
|
||
2. **可视化**: 需要额外的XML编辑器组件支持可视化编辑
|
||
3. **查询性能**: XML字符串查询可能不如结构化数据高效
|
||
|
||
## 回滚策略
|
||
|
||
如果本决策在实践中出现问题,可以考虑回滚到选项2或选项3:
|
||
|
||
1. **回滚条件**: 如果XML字符串存储导致严重的性能问题或存储空间不足
|
||
2. **回滚步骤**:
|
||
- 设计结构化数据模型
|
||
- 实现XML和结构化数据之间的转换
|
||
- 迁移现有数据
|
||
3. **回滚风险**: 数据迁移可能引入新的错误
|
||
|
||
## 相关文档
|
||
|
||
- [REQ-010-4](../requirements/REQ-010-4.md) - 元数据任务定义管理需求
|
||
- [metadata-module.md](../reference-code/com/docs/metadata-module.md) - Salesforce Metadata API 模块说明
|
||
- [file/index.md](../api-docs/file/index.md) - 文件模块 API 文档索引
|
||
- [Authentication.canvas](../Authentication.canvas) - 项目架构视觉化展示
|
||
|
||
## 审核记录
|
||
|
||
| 日期 | 审核人 | 审核结果 | 审核意见 |
|
||
|------|--------|----------|----------|
|
||
| 2026-01-18 | Datai Team | 已接受 | 方案合理,可以实施 |
|
||
|
||
## 变更历史
|
||
|
||
| 日期 | 版本 | 变更内容 | 变更人 |
|
||
|------|------|---------|--------|
|
||
| 2026-01-18 | v1.0.0 | 初始版本 | Datai Team |
|