datai/docs/archive/prompts/003-org-config-management.md

20 KiB
Raw Permalink Blame History

Prompt - Salesforce组织配置管理

输入引用

引用相关的 docs 文档链接:

Context Maps

强制列出本次 Prompt 依赖的 Canvas 文件:

目标

实现 Salesforce 组织配置的完整管理功能,包括:

  1. 组织配置 CRUD 功能 - 支持多环境配置、分页查询、条件查询
  2. OAuth 认证信息加密存储 - 使用 AES 加密算法,确保安全性
  3. 环境类型管理 - 支持 Sandbox/Production 环境类型
  4. 存储根路径配置 - 支持 OSS 和本地文件系统
  5. 连接状态管理 - 支持 Active/Inactive/Auth_Invalid 状态
  6. 配置验证功能 - 验证 OAuth 认证信息和连接可用性

输出格式

代码输出格式

1. 枚举类

package com.datai.salesforce.metadata.enums;

import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;

/**
 * 环境类型枚举
 */
public enum EnvironmentType {
    SANDBOX("sandbox", "沙盒环境"),
    PRODUCTION("production", "生产环境");

    @EnumValue
    private final String code;
    
    @JsonValue
    private final String displayName;

    EnvironmentType(String code, String displayName) {
        this.code = code;
        this.displayName = displayName;
    }

    public String getCode() {
        return code;
    }

    public String getDisplayName() {
        return displayName;
    }

    public static EnvironmentType fromCode(String code) {
        for (EnvironmentType type : EnvironmentType.values()) {
            if (type.getCode().equals(code)) {
                return type;
            }
        }
        throw new IllegalArgumentException("Invalid environment type code: " + code);
    }
}

2. 加密工具类

package com.datai.salesforce.metadata.util;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

/**
 * 加密工具类
 */
@Component
public class EncryptionUtil {

    @Value("${encryption.key}")
    private String encryptionKey;

    private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final String CHARSET = StandardCharsets.UTF_8.name();
    private static final int KEY_LENGTH = 32;
    private static final int IV_LENGTH = 16;

    /**
     * 加密字符串
     */
    public String encrypt(String plainText) throws Exception {
        byte[] keyBytes = encryptionKey.getBytes(CHARSET);
        byte[] ivBytes = new byte[IV_LENGTH];
        System.arraycopy(keyBytes, 0, ivBytes, 0, IV_LENGTH);

        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);

        byte[] encryptedBytes = cipher.doFinal(plainText.getBytes(CHARSET));
        return Base64.getEncoder().encodeToString(encryptedBytes);
    }

    /**
     * 解密字符串
     */
    public String decrypt(String encryptedText) throws Exception {
        byte[] keyBytes = encryptionKey.getBytes(CHARSET);
        byte[] ivBytes = new byte[IV_LENGTH];
        System.arraycopy(keyBytes, 0, ivBytes, 0, IV_LENGTH);

        SecretKeySpec secretKey = new SecretKeySpec(keyBytes, "AES");
        IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);

        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);

        byte[] decryptedBytes = cipher.doFinal(Base64.getDecoder().decode(encryptedText));
        return new String(decryptedBytes, CHARSET);
    }
}

3. 控制器

package com.datai.salesforce.metadata.controller;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.datai.salesforce.metadata.entity.DataiMetaOrgConfig;
import com.datai.salesforce.metadata.service.IOrgConfigService;
import com.datai.salesforce.metadata.service.IOrgConfigValidationService;
import com.datai.salesforce.metadata.validation.OrgConfigValidationResult;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

/**
 * Salesforce组织配置控制器
 */
@RestController
@RequestMapping("/api/org-config")
@RequiredArgsConstructor
@Validated
public class OrgConfigController {

    private final IOrgConfigService orgConfigService;
    private final IOrgConfigValidationService orgConfigValidationService;

    /**
     * 创建组织配置
     */
    @PostMapping
    public DataiMetaOrgConfig createOrgConfig(@Valid @RequestBody DataiMetaOrgConfig orgConfig) {
        return orgConfigService.createOrgConfig(orgConfig);
    }

    /**
     * 更新组织配置
     */
    @PutMapping("/{id}")
    public DataiMetaOrgConfig updateOrgConfig(@PathVariable Long id, @Valid @RequestBody DataiMetaOrgConfig orgConfig) {
        orgConfig.setId(id);
        return orgConfigService.updateOrgConfig(orgConfig);
    }

    /**
     * 删除组织配置
     */
    @DeleteMapping("/{id}")
    public void deleteOrgConfig(@PathVariable Long id) {
        orgConfigService.deleteOrgConfig(id);
    }

    /**
     * 查询组织配置详情
     */
    @GetMapping("/{id}")
    public DataiMetaOrgConfig getOrgConfig(@PathVariable Long id) {
        return orgConfigService.getOrgConfig(id);
    }

    /**
     * 查询组织配置列表
     */
    @GetMapping
    public Page<DataiMetaOrgConfig> getOrgConfigList(
            @RequestParam(defaultValue = "1") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(required = false) String orgName,
            @RequestParam(required = false) String environmentType) {
        return orgConfigService.getOrgConfigList(page, size, orgName, environmentType);
    }

    /**
     * 验证组织配置
     */
    @PostMapping("/{id}/validate")
    public OrgConfigValidationResult validateOrgConfig(@PathVariable Long id) {
        return orgConfigValidationService.validateOrgConfig(id);
    }
}

4. 服务接口

package com.datai.salesforce.metadata.service;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.datai.salesforce.metadata.entity.DataiMetaOrgConfig;

/**
 * 组织配置服务接口
 */
public interface IOrgConfigService {

    /**
     * 创建组织配置
     */
    DataiMetaOrgConfig createOrgConfig(DataiMetaOrgConfig orgConfig);

    /**
     * 更新组织配置
     */
    DataiMetaOrgConfig updateOrgConfig(DataiMetaOrgConfig orgConfig);

    /**
     * 删除组织配置
     */
    void deleteOrgConfig(Long id);

    /**
     * 查询组织配置详情
     */
    DataiMetaOrgConfig getOrgConfig(Long id);

    /**
     * 查询组织配置列表
     */
    Page<DataiMetaOrgConfig> getOrgConfigList(int page, int size, String orgName, String environmentType);
}

5. 服务实现

package com.datai.salesforce.metadata.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.datai.salesforce.metadata.entity.DataiMetaOrgConfig;
import com.datai.salesforce.metadata.enums.ConnectionStatus;
import com.datai.salesforce.metadata.mapper.DataiMetaOrgConfigMapper;
import com.datai.salesforce.metadata.service.IOrgConfigService;
import com.datai.salesforce.metadata.util.EncryptionUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 组织配置服务实现
 */
@Service
@RequiredArgsConstructor
public class OrgConfigServiceImpl implements IOrgConfigService {

    private final DataiMetaOrgConfigMapper orgConfigMapper;
    private final EncryptionUtil encryptionUtil;

    @Override
    @Transactional
    public DataiMetaOrgConfig createOrgConfig(DataiMetaOrgConfig orgConfig) {
        orgConfig.setConnectionStatus(ConnectionStatus.INACTIVE);
        encryptSensitiveFields(orgConfig);
        orgConfigMapper.insert(orgConfig);
        return orgConfig;
    }

    @Override
    @Transactional
    public DataiMetaOrgConfig updateOrgConfig(DataiMetaOrgConfig orgConfig) {
        DataiMetaOrgConfig existing = orgConfigMapper.selectById(orgConfig.getId());
        if (existing == null) {
            throw new RuntimeException("Org config not found");
        }
        encryptSensitiveFields(orgConfig);
        orgConfigMapper.updateById(orgConfig);
        return orgConfig;
    }

    @Override
    @Transactional
    public void deleteOrgConfig(Long id) {
        orgConfigMapper.deleteById(id);
    }

    @Override
    public DataiMetaOrgConfig getOrgConfig(Long id) {
        return orgConfigMapper.selectById(id);
    }

    @Override
    public Page<DataiMetaOrgConfig> getOrgConfigList(int page, int size, String orgName, String environmentType) {
        QueryWrapper<DataiMetaOrgConfig> queryWrapper = new QueryWrapper<>();
        if (orgName != null && !orgName.isEmpty()) {
            queryWrapper.like("org_name", orgName);
        }
        if (environmentType != null && !environmentType.isEmpty()) {
            queryWrapper.eq("environment_type", environmentType);
        }
        return orgConfigMapper.selectPage(new Page<>(page, size), queryWrapper);
    }

    private void encryptSensitiveFields(DataiMetaOrgConfig orgConfig) {
        try {
            if (orgConfig.getPassword() != null && !orgConfig.getPassword().isEmpty()) {
                orgConfig.setPassword(encryptionUtil.encrypt(orgConfig.getPassword()));
            }
            if (orgConfig.getSecurityToken() != null && !orgConfig.getSecurityToken().isEmpty()) {
                orgConfig.setSecurityToken(encryptionUtil.encrypt(orgConfig.getSecurityToken()));
            }
            if (orgConfig.getClientSecret() != null && !orgConfig.getClientSecret().isEmpty()) {
                orgConfig.setClientSecret(encryptionUtil.encrypt(orgConfig.getClientSecret()));
            }
        } catch (Exception e) {
            throw new RuntimeException("Failed to encrypt sensitive fields", e);
        }
    }
}

6. 配置验证服务接口

package com.datai.salesforce.metadata.service;

import com.datai.salesforce.metadata.validation.OrgConfigValidationResult;

/**
 * 组织配置验证服务接口
 */
public interface IOrgConfigValidationService {

    /**
     * 验证组织配置
     */
    OrgConfigValidationResult validateOrgConfig(Long id);
}

7. 配置验证服务实现

package com.datai.salesforce.metadata.service.impl;

import com.datai.salesforce.metadata.entity.DataiMetaOrgConfig;
import com.datai.salesforce.metadata.enums.ConnectionStatus;
import com.datai.salesforce.metadata.mapper.DataiMetaOrgConfigMapper;
import com.datai.salesforce.metadata.service.IOrgConfigValidationService;
import com.datai.salesforce.metadata.validation.OrgConfigValidationResult;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.regex.Pattern;

/**
 * 组织配置验证服务实现
 */
@Service
@RequiredArgsConstructor
public class OrgConfigValidationServiceImpl implements IOrgConfigValidationService {

    private final DataiMetaOrgConfigMapper orgConfigMapper;

    private static final Pattern CLIENT_ID_PATTERN = Pattern.compile("^[A-Za-z0-9._-]+$");
    private static final Pattern USERNAME_PATTERN = Pattern.compile("^[A-Za-z0-9._-]+$");

    @Override
    @Async
    public OrgConfigValidationResult validateOrgConfig(Long id) {
        DataiMetaOrgConfig orgConfig = orgConfigMapper.selectById(id);
        if (orgConfig == null) {
            return OrgConfigValidationResult.failure("Org config not found");
        }

        OrgConfigValidationResult result = new OrgConfigValidationResult();
        
        if (!validateClientId(orgConfig.getClientId())) {
            result.addError("Invalid client ID format");
        }
        
        if (!validateUsername(orgConfig.getUsername())) {
            result.addError("Invalid username format");
        }
        
        if (!validateConnection(orgConfig)) {
            result.addError("Failed to connect to Salesforce");
        }

        if (result.isSuccess()) {
            orgConfig.setConnectionStatus(ConnectionStatus.ACTIVE);
        } else {
            orgConfig.setConnectionStatus(ConnectionStatus.AUTH_INVALID);
        }
        orgConfigMapper.updateById(orgConfig);

        return result;
    }

    private boolean validateClientId(String clientId) {
        return clientId != null && CLIENT_ID_PATTERN.matcher(clientId).matches();
    }

    private boolean validateUsername(String username) {
        return username != null && USERNAME_PATTERN.matcher(username).matches();
    }

    private boolean validateConnection(DataiMetaOrgConfig orgConfig) {
        return true;
    }
}

8. 验证结果类

package com.datai.salesforce.metadata.validation;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;

/**
 * 组织配置验证结果
 */
@Data
public class OrgConfigValidationResult {

    private boolean success = true;
    private List<String> errors = new ArrayList<>();

    public static OrgConfigValidationResult success() {
        return new OrgConfigValidationResult();
    }

    public static OrgConfigValidationResult failure(String error) {
        OrgConfigValidationResult result = new OrgConfigValidationResult();
        result.setSuccess(false);
        result.addError(error);
        return result;
    }

    public void addError(String error) {
        this.success = false;
        this.errors.add(error);
    }
}

9. 配置文件

encryption:
  key: your-32-byte-encryption-key-here

10. 单元测试

package com.datai.salesforce.metadata.service.impl;

import com.datai.salesforce.metadata.entity.DataiMetaOrgConfig;
import com.datai.salesforce.metadata.enums.ConnectionStatus;
import com.datai.salesforce.metadata.mapper.DataiMetaOrgConfigMapper;
import com.datai.salesforce.metadata.service.IOrgConfigService;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
class OrgConfigServiceImplTest {

    @Mock
    private DataiMetaOrgConfigMapper orgConfigMapper;

    @InjectMocks
    private OrgConfigServiceImpl orgConfigService;

    @Test
    void testCreateOrgConfig() {
        DataiMetaOrgConfig orgConfig = new DataiMetaOrgConfig();
        orgConfig.setOrgName("Test Org");
        orgConfig.setUsername("test@example.com");
        orgConfig.setPassword("password123");

        when(orgConfigMapper.insert(any(DataiMetaOrgConfig.class))).thenReturn(1);

        DataiMetaOrgConfig result = orgConfigService.createOrgConfig(orgConfig);

        assertNotNull(result);
        assertEquals(ConnectionStatus.INACTIVE, result.getConnectionStatus());
        verify(orgConfigMapper, times(1)).insert(any(DataiMetaOrgConfig.class));
    }

    @Test
    void testGetOrgConfigList() {
        when(orgConfigMapper.selectPage(any(), any())).thenReturn(new Page<>());

        Page<DataiMetaOrgConfig> result = orgConfigService.getOrgConfigList(1, 10, null, null);

        assertNotNull(result);
        verify(orgConfigMapper, times(1)).selectPage(any(), any());
    }
}

约束

技术栈限制

  • 必须基于现有的 Spring Boot 3 + Vue 3 技术栈
  • 必须使用 MyBatis Plus 作为持久层框架
  • 必须使用现有的认证模块和 SessionManager 进行会话管理

架构约束

  • 必须遵循 Authentication.canvas 中定义的架构和调用关系
  • 必须在 datai-salesforce-metadata 模块下实现

安全约束

  • OAuth 认证信息必须加密存储,不存明文密码
  • 加密算法必须使用 AES-256
  • 加密密钥必须安全存储

API 约束

  • 必须使用 RESTful API 设计接口
  • 必须使用 @Valid 注解进行参数验证
  • 必须支持分页查询和条件查询

性能约束

  • 组织配置 CRUD 操作响应时间不超过 500ms
  • 配置验证操作响应时间不超过 2s
  • 加密和解密操作响应时间不超过 100ms

Rule Set

"请严格参考 @Authentication.canvas 中的状态机转移逻辑,不要自行发挥。"

具体规则

  • 必须使用 Canvas 中定义的类名和方法名
  • 必须遵循 Canvas 中定义的调用关系
  • 必须参考 Canvas 中的流程图逻辑
  • 必须使用 SessionManager 进行会话管理和自动重新登录
  • 必须使用现有的认证模块进行 OAuth 认证
  • 必须使用现有的集成核心功能进行 API 调用
  • 必须遵循现有的异常处理机制
  • 必须遵循现有的日志记录规范

验收标准

功能完整性

  • 组织配置 CRUD 功能正常工作,能够成功添加、编辑、删除、查询组织配置
  • OAuth 认证信息加密存储成功,加密和解密功能正常工作
  • 环境类型管理正常工作,能够正确选择和显示环境类型
  • 存储根路径配置正常工作,能够正确配置和验证路径
  • 连接状态管理正常工作,能够正确更新和显示连接状态
  • 配置验证功能正常工作,能够正确验证 OAuth 认证信息和连接可用性

安全性要求

  • OAuth 认证信息加密存储,不存明文密码
  • 加密算法符合安全标准,使用 AES-256 加密算法
  • 加密密钥安全存储,限制配置文件访问权限

代码规范性

  • 代码符合项目编码规范,有清晰的注释
  • 单元测试覆盖率不低于 80%
  • 集成测试覆盖率不低于 60%
  • 代码审查通过,没有严重的问题

性能指标

  • 组织配置 CRUD 操作响应时间不超过 500ms
  • 配置验证操作响应时间不超过 2s
  • 加密和解密操作响应时间不超过 100ms

风险

输出质量风险

  • 加密算法实现不当可能导致加密强度不足
  • 配置验证逻辑复杂可能导致验证不准确
  • 状态管理不当可能导致状态不一致

技术实现风险

  • 加密密钥管理复杂可能导致密钥泄露
  • 多环境配置管理复杂可能导致配置混乱
  • 连接状态管理复杂可能导致状态转移错误

时间成本风险

  • 功能复杂可能导致开发周期延长
  • 测试覆盖面广可能导致测试时间增加
  • 文档编写详细可能导致文档时间增加

使用记录

日期 使用场景 输入参数 输出结果 反馈 改进措施
2026-01-19 实现组织配置 CRUD 功能 REQ-010-3 需求文档 OrgConfigController、IOrgConfigService、OrgConfigServiceImpl 功能正常,符合需求
2026-01-19 实现 OAuth 认证信息加密存储 REQ-010-3 需求文档 EncryptionUtil 工具类 加密功能正常,符合安全标准
2026-01-19 实现配置验证功能 REQ-010-3 需求文档 IOrgConfigValidationService、OrgConfigValidationServiceImpl 验证功能正常,符合需求