## 功能概述
- 实现动态数据源的延迟加载机制,支持应用启动时只加载主库,从库按需动态加载和切换
- 从库配置存储在主库中,支持运行时灵活切换从库库名
- 使用现有的 @DataSource 注解进行数据源切换,业务代码无需修改
## 新增功能
- 动态数据源管理接口 IDynamicDataSourceManager
- 动态数据源服务接口 IDynamicDataSourceService
- 动态数据源服务实现 DynamicDataSourceServiceImpl
- 数据源管理控制器 DatasourceController
- 数据源配置表 sys_datasource_config
## 新增文档
- 需求文档: docs/requirements/2026-01-21-001-动态数据源延迟加载.md
- 设计文档: docs/design/2026-01-21-001-动态数据源延迟加载设计.md
- 决策记录: docs/decisions/2026-01-21-001-ADR-动态数据源延迟加载.md
- SQL 脚本: docs/sql/2026-01-21-001-sys_datasource_config.sql
- 提示词: docs/prompts/2026-01-21-001-动态数据源延迟加载代码生成提示词.md
- 会话记录: docs/sessions/2026-01-21-001-session.md
- 变更日志: docs/changelog/2026-01-21-001-changelog.md
- 复盘文档: docs/retros/2026-01-21-001-retro.md
- API 文档: docs/api-docs/2026-01-21-001-api.md
- 根目录变更日志: CHANGELOG.md
## 修改功能
- 扩展 DataSourceManager 类,添加动态数据源管理方法
- 扩展 SysDatasourceConfigMapper 接口,添加 selectSysDatasourceConfigByDsName 方法
- 更新项目索引和 Authentication.canvas
## 修复问题
- 修复循环依赖问题:创建 IDynamicDataSourceManager 接口解决 datai-system 和 datai-framework 互相依赖
- 修复导入错误:删除 DynamicDataSourceServiceImpl 中未使用的导入
- 修复异常处理:将 setFilters() 调用移到 try-catch 块内
## API 接口
- POST /system/datasource/loadSlave - 加载从库数据源
- POST /system/datasource/switchSlave/{dbName} - 切换从库库名
- GET /system/datasource/getSlaveConfig - 获取从库配置
- POST /system/datasource/switch/{dsName} - 切换数据源
- DELETE /system/datasource/{dsName} - 移除数据源
924 lines
28 KiB
Markdown
924 lines
28 KiB
Markdown
# 阶段 2:方案设计技能书
|
||
|
||
## A. 元数据 (Metadata)
|
||
|
||
**name**: `phase2-design`
|
||
|
||
**description**: 在 Datai 项目中,基于已创建的需求文档,进行技术方案设计、架构设计、数据模型设计和接口设计,生成标准化的设计文档,并更新索引和会话记录。此技能是连接需求与实现的关键桥梁。
|
||
|
||
---
|
||
|
||
## B. 触发与定位 (Triggers & Scope)
|
||
|
||
### 触发关键词
|
||
当用户输入包含以下关键词时,必须觉醒此技能:
|
||
- "设计方案"、"设计文档"、"技术方案"
|
||
- "架构设计"、"系统设计"
|
||
- "接口设计"、"API 设计"
|
||
- "数据模型设计"、"数据库设计"
|
||
- "进入阶段 2"、"下一阶段"
|
||
- "设计"、"设计图"、"设计稿"
|
||
|
||
### 触发场景
|
||
- 用户确认阶段 1 完成,要求进入阶段 2
|
||
- 用户要求创建设计文档
|
||
- 用户询问如何设计某个功能的技术方案
|
||
- 用户提到"按照项目规则"或"SSOT 流程"进行设计
|
||
|
||
### 操作路径
|
||
此技能涉及以下文件和目录的操作:
|
||
- **读取**: `docs/requirements/YYYY-MM-DD-00X-需求名.md` (阶段 1 创建的需求文档)
|
||
- **创建**: `docs/design/YYYY-MM-DD-00X-设计名.md`
|
||
- **更新**: `docs/index.md`
|
||
- **更新**: `docs/requirements/YYYY-MM-DD-00X-需求名.md` (添加设计文档引用)
|
||
- **更新**: `docs/sessions/YYYY-MM-DD-00X-session.md`
|
||
- **读取**: `.trae/rules/project_rules.md` (项目规则)
|
||
- **读取**: `docs/Prompt/0004-单一真源文档驱动架构师.md` (SSOT 架构师提示词)
|
||
|
||
### SSOT 依赖
|
||
必须参考以下"唯一真源":
|
||
- [需求文档](file:///d:\idea_demo\datai\docs\requirements\YYYY-MM-DD-00X-需求名.md) - 阶段 1 创建的需求文档
|
||
- [project_rules.md](file:///d:\idea_demo\datai\.trae\rules\project_rules.md) - 项目规则和阶段定义
|
||
- [0004-单一真源文档驱动架构师.md](file:///d:\idea_demo\datai\docs\Prompt\0004-单一真源文档驱动架构师.md) - SSOT 架构师提示词
|
||
- `docs/design/` 目录下的现有设计文档(作为格式参考)
|
||
- `datai-modules-*/src/main/java/` 目录下的现有代码(作为架构参考)
|
||
|
||
---
|
||
|
||
## C. 核心指令集 (Instructions)
|
||
|
||
### 架构约束
|
||
|
||
#### 1. 文档命名规范(强制)
|
||
- 必须使用格式:`YYYY-MM-DD-00X-设计名.md`
|
||
- `YYYY-MM-DD`:当前日期(如 2026-01-21)
|
||
- `00X`:需求编号(与阶段 1 保持一致)
|
||
- `设计名`:简洁描述,使用中文,如"用户登录功能-设计"、"订单导出优化-设计"
|
||
- **严禁**使用英文、拼音或无意义的文件名
|
||
|
||
#### 2. 文档结构约束(强制)
|
||
设计文档必须包含以下章节,顺序不能改变:
|
||
```markdown
|
||
# 设计文档
|
||
|
||
## 元数据
|
||
- 需求编号:001
|
||
- 创建时间:YYYY-MM-DD
|
||
- 创建人:AI Assistant
|
||
- 状态:进行中
|
||
|
||
## 设计概述
|
||
[设计概述]
|
||
|
||
## 架构设计
|
||
[架构设计]
|
||
|
||
## 技术方案
|
||
[技术方案]
|
||
|
||
## 数据模型
|
||
[数据模型]
|
||
|
||
## 接口设计
|
||
[接口设计]
|
||
|
||
## 实现要点
|
||
[实现要点]
|
||
|
||
## 相关文档
|
||
- [需求文档](../requirements/YYYY-MM-DD-00X-需求名.md)
|
||
- [决策记录](../decisions/YYYY-MM-DD-00X-ADR-决策名.md)
|
||
```
|
||
|
||
#### 3. 设计原则约束(强制)
|
||
- **必须**遵循 Spring Boot 最佳实践
|
||
- **必须**遵循若依(RuoYi Geek)框架规范
|
||
- **必须**遵循 MyBatis Plus 使用规范
|
||
- **必须**考虑 Salesforce API 集成规范(如果涉及)
|
||
- **必须**遵循 RESTful API 设计规范
|
||
- **必须**考虑数据安全和权限控制
|
||
- **必须**考虑性能优化和可扩展性
|
||
|
||
#### 4. 索引更新约束(强制)
|
||
- 必须在创建设计文档后立即更新 `docs/index.md`
|
||
- 必须更新需求文档,添加设计文档引用
|
||
- 采用增量更新策略,**严禁**删除现有内容
|
||
- 索引链接格式:`[文档名](./相对路径/文件名.md)`
|
||
- 必须在 `docs/index.md` 中添加到"设计文档"部分
|
||
|
||
#### 5. 会话记录约束(强制)
|
||
- 必须更新 `docs/sessions/YYYY-MM-DD-00X-session.md`
|
||
- 必须更新当前阶段为"阶段 2:方案设计"
|
||
- 必须记录关键设计决策
|
||
- 必须记录设计文档链接
|
||
|
||
### 业务逻辑 SOP(标准操作流程)
|
||
|
||
#### 步骤 1:需求分析(Let's think step by step)
|
||
在创建设计文档前,必须执行以下分析:
|
||
|
||
1. **分析需求的技术要求**
|
||
- 读取阶段 1 创建的需求文档
|
||
- 识别需求中的功能需求和非功能需求
|
||
- 识别需求中的技术约束
|
||
- 识别需求中的成功标准
|
||
|
||
2. **确定技术栈和架构方案**
|
||
- **框架层**:Spring Boot 版本、Spring Security、Spring Cloud(如果需要)
|
||
- **数据层**:MyBatis Plus、数据库类型(MySQL/PostgreSQL)
|
||
- **业务层**:若依框架模块(如 `datai-modules-system`、`datai-modules-salesforce`)
|
||
- **集成层**:Salesforce API、其他第三方服务
|
||
- **前端层**:Vue 3、Element Plus(如果涉及)
|
||
|
||
3. **识别关键设计决策点**
|
||
- 是否需要引入新的技术组件
|
||
- 是否需要设计新的数据表
|
||
- 是否需要调用外部 API
|
||
- 是否需要考虑分布式事务
|
||
- 是否需要考虑缓存策略
|
||
- 是否需要考虑消息队列
|
||
|
||
#### 步骤 2:架构设计
|
||
1. **系统架构设计**
|
||
- 绘制系统架构图(使用 Mermaid 或文字描述)
|
||
- 识别系统分层(Controller、Service、Mapper、Entity)
|
||
- 识别模块划分(若依框架模块)
|
||
- 识别依赖关系
|
||
|
||
2. **模块架构设计**
|
||
- 确定涉及的若依模块(如 `datai-modules-system`、`datai-modules-salesforce`)
|
||
- 确定涉及的包结构(如 `controller`、`service`、`mapper`、`domain`)
|
||
- 确定涉及的类(如 `XxxController`、`XxxService`、`XxxMapper`、`Xxx`)
|
||
|
||
3. **数据流设计**
|
||
- 描述数据从输入到输出的完整流程
|
||
- 识别数据转换点
|
||
- 识别数据验证点
|
||
- 识别数据持久化点
|
||
|
||
#### 步骤 3:技术方案设计
|
||
1. **技术选型**
|
||
- 列出使用的技术组件(如 Spring Security、JWT、Redis)
|
||
- 说明选择理由(性能、安全性、可维护性)
|
||
- 说明版本要求
|
||
|
||
2. **核心算法设计**(如果涉及)
|
||
- 描述核心算法的逻辑
|
||
- 描述算法的复杂度
|
||
- 描述算法的优化点
|
||
|
||
3. **集成方案设计**(如果涉及)
|
||
- 描述与外部系统的集成方式
|
||
- 描述数据交换格式(JSON、XML)
|
||
- 描述错误处理机制
|
||
- 描述重试机制
|
||
|
||
#### 步骤 4:数据模型设计
|
||
1. **数据库表设计**(如果涉及)
|
||
- 列出需要创建或修改的表
|
||
- 列出表的字段(字段名、类型、长度、是否必填、默认值)
|
||
- 列出表的索引(主键索引、唯一索引、普通索引)
|
||
- 列出表的关系(一对一、一对多、多对多)
|
||
|
||
2. **实体类设计**
|
||
- 列出需要创建的实体类
|
||
- 列出实体类的属性
|
||
- 列出实体类的注解(`@TableName`、`@TableId`、`@TableField`)
|
||
- 列出实体类的基类(如 `BaseEntity`)
|
||
|
||
3. **数据字典设计**(如果涉及)
|
||
- 列出需要添加的数据字典
|
||
- 列出字典类型和字典数据
|
||
|
||
#### 步骤 5:接口设计
|
||
1. **RESTful API 设计**
|
||
- 列出需要创建的接口(Controller 方法)
|
||
- 确定接口的 HTTP 方法(GET、POST、PUT、DELETE)
|
||
- 确定接口的 URL 路径(如 `/api/system/user/login`)
|
||
- 确定接口的请求参数(路径参数、查询参数、请求体)
|
||
- 确定接口的响应格式(成功响应、错误响应)
|
||
|
||
2. **接口权限设计**
|
||
- 确定接口的权限要求(如 `@PreAuthorize("@ss.hasPermi('system:user:list')")`)
|
||
- 确定接口的数据权限(如 `@DataScope`)
|
||
- 确定接口的角色要求
|
||
|
||
3. **接口文档设计**
|
||
- 描述接口的功能
|
||
- 描述接口的请求参数
|
||
- 描述接口的响应参数
|
||
- 提供接口示例
|
||
|
||
#### 步骤 6:实现要点设计
|
||
1. **关键实现逻辑**
|
||
- 描述核心功能的实现逻辑
|
||
- 描述关键算法的实现步骤
|
||
- 描述关键数据的处理流程
|
||
|
||
2. **异常处理设计**
|
||
- 列出可能出现的异常
|
||
- 描述异常的处理方式
|
||
- 描述异常的提示信息
|
||
|
||
3. **性能优化设计**
|
||
- 描述性能优化策略(如缓存、索引、分页)
|
||
- 描述性能优化目标(如响应时间、并发数)
|
||
|
||
4. **安全设计**
|
||
- 描述数据加密方式
|
||
- 描述权限控制方式
|
||
- 描述防注入方式(SQL 注入、XSS 攻击)
|
||
|
||
#### 步骤 7:创建设计文档
|
||
1. **确定文档路径**
|
||
- 路径:`docs/design/YYYY-MM-DD-00X-设计名.md`
|
||
- 使用 Write 工具创建文件
|
||
- 确保目录存在(使用 LS 工具检查)
|
||
|
||
2. **填充文档内容**
|
||
- **元数据**:填写需求编号、创建时间、状态
|
||
- **设计概述**:用 2-3 句话描述设计的核心内容
|
||
- **架构设计**:包含系统架构图、模块架构图、数据流图
|
||
- **技术方案**:包含技术选型、核心算法、集成方案
|
||
- **数据模型**:包含数据库表设计、实体类设计、数据字典设计
|
||
- **接口设计**:包含 RESTful API 设计、接口权限设计、接口文档
|
||
- **实现要点**:包含关键实现逻辑、异常处理、性能优化、安全设计
|
||
- **相关文档**:添加需求文档链接,决策记录链接暂时为空
|
||
|
||
3. **文档质量检查**
|
||
- 使用 Read 工具读取刚创建的文档
|
||
- 检查是否符合文档结构约束
|
||
- 检查是否有遗漏的章节
|
||
- 检查设计是否合理、可行
|
||
|
||
#### 步骤 8:更新索引和需求文档
|
||
1. **读取现有索引**
|
||
- 使用 Read 工具读取 `docs/index.md`
|
||
- 找到"设计文档"部分
|
||
- 如果不存在,则创建该部分
|
||
|
||
2. **添加新设计链接**
|
||
- 在"设计文档"部分追加新设计
|
||
- 格式:`- [设计名](./design/YYYY-MM-DD-00X-设计名.md) - [状态]`
|
||
- 示例:`- [用户登录功能-设计](./design/2026-01-21-001-用户登录功能-设计.md) - 进行中`
|
||
|
||
3. **更新需求文档**
|
||
- 使用 Read 工具读取需求文档
|
||
- 在"相关文档"部分添加设计文档链接
|
||
- 格式:`- [设计文档](../design/YYYY-MM-DD-00X-设计名.md)`
|
||
- 使用 Write 工具更新需求文档
|
||
|
||
4. **保存索引**
|
||
- 使用 Write 工具更新 `docs/index.md`
|
||
- **严禁**删除现有内容,只追加新内容
|
||
|
||
#### 步骤 9:更新会话记录
|
||
1. **读取现有会话记录**
|
||
- 使用 Read 工具读取 `docs/sessions/YYYY-MM-DD-00X-session.md`
|
||
|
||
2. **更新阶段 2 信息**
|
||
- 更新"当前阶段"为"阶段 2:方案设计"
|
||
- 更新"阶段 2:方案设计"的状态为"已完成"
|
||
- 添加生成文档链接
|
||
- 添加关键设计决策
|
||
|
||
3. **保存会话记录**
|
||
- 使用 Write 工具更新会话记录
|
||
|
||
#### 步骤 10:确认与询问
|
||
1. **向用户确认**
|
||
- 显示设计文档的链接
|
||
- 询问:"设计方案是否合理?"
|
||
- 询问:"是否进入下一阶段(方案决策)?"
|
||
|
||
2. **等待用户反馈**
|
||
- 如果用户不满意,询问具体需要修改的地方
|
||
- 如果用户要求回退,执行回退机制(见错误陷阱部分)
|
||
- 如果用户确认,标记阶段 2 为已完成,准备进入阶段 3
|
||
|
||
### 工具调用
|
||
|
||
#### 必须使用的工具
|
||
1. **Read 工具**:读取现有文件
|
||
- 使用场景:读取需求文档、读取索引、读取会话记录
|
||
- 命令:`Read(file_path="d:\\idea_demo\\datai\\docs\\requirements\\2026-01-21-001-用户登录功能.md")`
|
||
|
||
2. **Write 工具**:创建或更新文件
|
||
- 使用场景:创建设计文档、更新索引、更新需求文档、更新会话记录
|
||
- 命令:`Write(file_path="d:\\idea_demo\\datai\\docs\\design\\2026-01-21-001-用户登录功能-设计.md", content="...")`
|
||
|
||
3. **LS 工具**:检查目录是否存在
|
||
- 使用场景:创建文档前检查 `docs/design/` 目录
|
||
- 命令:`LS(path="d:\\idea_demo\\datai\\docs")`
|
||
|
||
4. **SearchCodebase 工具**:搜索现有代码
|
||
- 使用场景:查找现有的 Controller、Service、Mapper 类作为参考
|
||
- 命令:`SearchCodebase(information_request="查找 datai-modules-system 模块下的 Controller 类")`
|
||
|
||
#### 可选使用的工具
|
||
1. **Glob 工具**:查找文件
|
||
- 使用场景:查找所有设计文档
|
||
- 命令:`Glob(pattern="docs/design/*.md")`
|
||
|
||
2. **TodoWrite 工具**:管理任务
|
||
- 使用场景:跟踪阶段执行进度
|
||
- 命令:`TodoWrite(todos=[...])`
|
||
|
||
---
|
||
|
||
## D. 错误陷阱与验证 (Anti-Patterns & Checklist)
|
||
|
||
### 常见错误(Anti-Patterns)
|
||
|
||
#### 错误 1:不读取需求文档直接设计
|
||
**错误示例**:
|
||
```
|
||
用户:进入阶段 2
|
||
AI:直接创建设计文档,不读取需求文档
|
||
```
|
||
|
||
**正确示例**:
|
||
```
|
||
用户:进入阶段 2
|
||
AI:让我先读取需求文档,分析技术要求...
|
||
AI:读取需求文档:[链接]
|
||
AI:分析需求的技术要求、技术栈、关键设计决策点...
|
||
AI:基于需求分析,开始创建设计文档...
|
||
```
|
||
|
||
#### 错误 2:设计文档缺少关键章节
|
||
**错误示例**:
|
||
```markdown
|
||
# 设计文档
|
||
|
||
## 设计概述
|
||
用户登录功能设计
|
||
|
||
## 技术方案
|
||
使用 Spring Security
|
||
```
|
||
|
||
**问题**:
|
||
- 缺少元数据
|
||
- 缺少架构设计
|
||
- 缺少数据模型设计
|
||
- 缺少接口设计
|
||
- 缺少实现要点
|
||
|
||
**正确示例**:
|
||
```markdown
|
||
# 设计文档
|
||
|
||
## 元数据
|
||
- 需求编号:001
|
||
- 创建时间:2026-01-21
|
||
- 创建人:AI Assistant
|
||
- 状态:进行中
|
||
|
||
## 设计概述
|
||
基于 Spring Security 和若依框架,实现用户登录功能的设计,包括认证、授权、会话管理等核心功能。
|
||
|
||
## 架构设计
|
||
[系统架构图]
|
||
[模块架构图]
|
||
[数据流图]
|
||
|
||
## 技术方案
|
||
[技术选型]
|
||
[核心算法]
|
||
[集成方案]
|
||
|
||
## 数据模型
|
||
[数据库表设计]
|
||
[实体类设计]
|
||
[数据字典设计]
|
||
|
||
## 接口设计
|
||
[RESTful API 设计]
|
||
[接口权限设计]
|
||
[接口文档]
|
||
|
||
## 实现要点
|
||
[关键实现逻辑]
|
||
[异常处理]
|
||
[性能优化]
|
||
[安全设计]
|
||
|
||
## 相关文档
|
||
- [需求文档](../requirements/2026-01-21-001-用户登录功能.md)
|
||
- [决策记录](../decisions/2026-01-21-001-ADR-用户登录功能-技术选型.md)
|
||
```
|
||
|
||
#### 错误 3:不更新需求文档的设计文档引用
|
||
**错误示例**:
|
||
```
|
||
AI:创建设计文档
|
||
AI:更新 docs/index.md
|
||
AI:完成(忘记更新需求文档)
|
||
```
|
||
|
||
**正确示例**:
|
||
```
|
||
AI:创建设计文档
|
||
AI:更新 docs/index.md,添加设计文档链接
|
||
AI:更新需求文档,添加设计文档引用
|
||
AI:完成
|
||
```
|
||
|
||
#### 错误 4:接口设计不符合 RESTful 规范
|
||
**错误示例**:
|
||
```
|
||
POST /api/system/user/getUser
|
||
GET /api/system/user/createUser
|
||
DELETE /api/system/user/deleteUser
|
||
```
|
||
|
||
**问题**:
|
||
- HTTP 方法使用错误
|
||
- URL 路径不符合 RESTful 规范
|
||
|
||
**正确示例**:
|
||
```
|
||
GET /api/system/user/{userId}
|
||
POST /api/system/user
|
||
PUT /api/system/user/{userId}
|
||
DELETE /api/system/user/{userId}
|
||
```
|
||
|
||
#### 错误 5:数据模型设计不考虑若依框架规范
|
||
**错误示例**:
|
||
```java
|
||
public class User {
|
||
private Long id;
|
||
private String username;
|
||
private String password;
|
||
}
|
||
```
|
||
|
||
**问题**:
|
||
- 没有继承若依的基类
|
||
- 没有使用 MyBatis Plus 的注解
|
||
- 没有包含审计字段
|
||
|
||
**正确示例**:
|
||
```java
|
||
@Data
|
||
@EqualsAndHashCode(callSuper = true)
|
||
@TableName("sys_user")
|
||
public class SysUser extends BaseEntity {
|
||
@TableId(value = "user_id", type = IdType.AUTO)
|
||
private Long userId;
|
||
|
||
@TableField("user_name")
|
||
private String userName;
|
||
|
||
@TableField("password")
|
||
private String password;
|
||
|
||
@TableField("dept_id")
|
||
private Long deptId;
|
||
|
||
@TableField("status")
|
||
private String status;
|
||
}
|
||
```
|
||
|
||
#### 错误 6:不询问用户确认就进入下一阶段
|
||
**错误示例**:
|
||
```
|
||
AI:创建设计文档
|
||
AI:进入阶段 3:方案决策(未询问用户)
|
||
```
|
||
|
||
**正确示例**:
|
||
```
|
||
AI:创建设计文档
|
||
AI:设计文档已创建:[链接]
|
||
AI:设计方案是否合理?
|
||
AI:是否进入下一阶段(方案决策)?
|
||
```
|
||
|
||
### 验收清单(Checklist)
|
||
|
||
在完成阶段 2 前,必须检查以下项目:
|
||
|
||
#### 文档完整性检查
|
||
- [ ] 设计文档已创建在 `docs/design/` 目录下
|
||
- [ ] 文档命名符合 `YYYY-MM-DD-00X-设计名.md` 格式
|
||
- [ ] 文档包含所有必需章节(元数据、设计概述、架构设计、技术方案、数据模型、接口设计、实现要点、相关文档)
|
||
- [ ] 元数据已正确填写(需求编号、创建时间、状态)
|
||
- [ ] 设计概述清晰、无歧义
|
||
- [ ] 架构设计包含系统架构图、模块架构图、数据流图
|
||
- [ ] 技术方案包含技术选型、核心算法、集成方案
|
||
- [ ] 数据模型包含数据库表设计、实体类设计、数据字典设计
|
||
- [ ] 接口设计包含 RESTful API 设计、接口权限设计、接口文档
|
||
- [ ] 实现要点包含关键实现逻辑、异常处理、性能优化、安全设计
|
||
|
||
#### 设计合理性检查
|
||
- [ ] 架构设计符合若依框架规范
|
||
- [ ] 技术选型合理,有充分的理由
|
||
- [ ] 数据模型设计符合数据库规范
|
||
- [ ] 接口设计符合 RESTful 规范
|
||
- [ ] 接口权限设计符合若依权限系统
|
||
- [ ] 实现要点考虑了性能优化
|
||
- [ ] 实现要点考虑了安全性
|
||
|
||
#### 索引更新检查
|
||
- [ ] `docs/index.md` 已更新
|
||
- [ ] 新设计链接已添加到"设计文档"部分
|
||
- [ ] 索引链接格式正确:`[文档名](./相对路径/文件名.md)`
|
||
- [ ] 索引更新采用增量策略,未删除现有内容
|
||
|
||
#### 需求文档更新检查
|
||
- [ ] 需求文档已更新
|
||
- [ ] 需求文档的"相关文档"部分已添加设计文档链接
|
||
- [ ] 设计文档链接格式正确:`[设计文档](../design/YYYY-MM-DD-00X-设计名.md)`
|
||
|
||
#### 会话记录更新检查
|
||
- [ ] 会话记录已更新
|
||
- [ ] 会话记录的"当前阶段"已更新为"阶段 2:方案设计"
|
||
- [ ] 会话记录的"阶段 2:方案设计"状态已更新为"已完成"
|
||
- [ ] 会话记录包含设计文档链接
|
||
- [ ] 会话记录包含关键设计决策
|
||
|
||
#### 用户确认检查
|
||
- [ ] 已向用户显示设计文档链接
|
||
- [ ] 已询问用户"设计方案是否合理?"
|
||
- [ ] 已询问用户"是否进入下一阶段?"
|
||
- [ ] 已等待用户反馈
|
||
|
||
#### 回退机制检查(如果需要)
|
||
- [ ] 如果用户不满意,已询问具体需要修改的地方
|
||
- [ ] 如果用户要求回退,已删除设计文档
|
||
- [ ] 如果用户要求回退,已撤销索引更新
|
||
- [ ] 如果用户要求回退,已撤销需求文档更新
|
||
- [ ] 如果用户要求回退,已更新会话记录
|
||
|
||
### Correct vs Incorrect 代码对比
|
||
|
||
#### Incorrect(错误示例)
|
||
```markdown
|
||
# 设计文档
|
||
|
||
## 设计概述
|
||
用户登录功能设计
|
||
|
||
## 技术方案
|
||
使用 Spring Security
|
||
|
||
## 接口设计
|
||
POST /api/system/user/login
|
||
```
|
||
|
||
**问题**:
|
||
- 缺少元数据
|
||
- 缺少架构设计
|
||
- 缺少数据模型设计
|
||
- 技术方案过于简单
|
||
- 接口设计不完整
|
||
|
||
#### Correct(正确示例)
|
||
```markdown
|
||
# 设计文档
|
||
|
||
## 元数据
|
||
- 需求编号:001
|
||
- 创建时间:2026-01-21
|
||
- 创建人:AI Assistant
|
||
- 状态:进行中
|
||
|
||
## 设计概述
|
||
基于 Spring Security 和若依框架,实现用户登录功能的设计,包括认证、授权、会话管理等核心功能。
|
||
|
||
## 架构设计
|
||
|
||
### 系统架构
|
||
```
|
||
用户 -> 前端 -> Controller -> Service -> Mapper -> 数据库
|
||
-> Security -> 认证中心
|
||
```
|
||
|
||
### 模块架构
|
||
- **Controller 层**:`SysLoginController`,处理登录请求
|
||
- **Service 层**:`SysLoginService`,处理登录业务逻辑
|
||
- **Mapper 层**:`SysUserMapper`,查询用户信息
|
||
- **Entity 层**:`SysUser`,用户实体类
|
||
|
||
### 数据流
|
||
```
|
||
用户输入 -> 前端验证 -> Controller -> Service -> 查询用户 -> 验证密码 -> 生成 Token -> 返回 Token
|
||
```
|
||
|
||
## 技术方案
|
||
|
||
### 技术选型
|
||
- **认证框架**:Spring Security 6.x
|
||
- **Token 生成**:JWT (JSON Web Token)
|
||
- **密码加密**:BCrypt
|
||
- **会话管理**:Redis 存储 Token
|
||
- **权限框架**:若依权限系统
|
||
|
||
### 核心算法
|
||
1. **密码验证算法**:
|
||
- 使用 BCrypt 加密算法
|
||
- 加密强度:10
|
||
- 验证流程:用户输入密码 -> BCrypt 加密 -> 与数据库密码比对
|
||
|
||
2. **Token 生成算法**:
|
||
- 使用 JWT 生成 Token
|
||
- Token 有效期:2 小时
|
||
- Token 包含:用户 ID、用户名、角色、权限
|
||
|
||
### 集成方案
|
||
- **与若依权限系统集成**:使用 `@PreAuthorize` 注解控制权限
|
||
- **与 Redis 集成**:使用 Redis 存储 Token,实现单点登录
|
||
- **与 Salesforce 集成**:如果需要,通过 Salesforce API 获取用户信息
|
||
|
||
## 数据模型
|
||
|
||
### 数据库表设计
|
||
|
||
#### sys_user 表(已存在,需要修改)
|
||
| 字段名 | 类型 | 长度 | 必填 | 默认值 | 说明 |
|
||
|--------|------|------|------|--------|------|
|
||
| user_id | bigint | - | 是 | - | 用户 ID(主键) |
|
||
| user_name | varchar | 30 | 是 | - | 用户名 |
|
||
| password | varchar | 100 | 是 | - | 密码(BCrypt 加密) |
|
||
| dept_id | bigint | - | 否 | - | 部门 ID |
|
||
| status | char | 1 | 是 | 0 | 状态(0 正常 1 停用) |
|
||
| login_ip | varchar | 128 | 否 | - | 最后登录 IP |
|
||
| login_date | datetime | - | 否 | - | 最后登录时间 |
|
||
|
||
### 实体类设计
|
||
|
||
#### SysUser.java
|
||
```java
|
||
@Data
|
||
@EqualsAndHashCode(callSuper = true)
|
||
@TableName("sys_user")
|
||
public class SysUser extends BaseEntity {
|
||
@TableId(value = "user_id", type = IdType.AUTO)
|
||
private Long userId;
|
||
|
||
@TableField("user_name")
|
||
private String userName;
|
||
|
||
@TableField("password")
|
||
private String password;
|
||
|
||
@TableField("dept_id")
|
||
private Long deptId;
|
||
|
||
@TableField("status")
|
||
private String status;
|
||
|
||
@TableField("login_ip")
|
||
private String loginIp;
|
||
|
||
@TableField("login_date")
|
||
private Date loginDate;
|
||
}
|
||
```
|
||
|
||
### 数据字典设计
|
||
|
||
#### sys_dict_type 表(已存在,需要添加)
|
||
| 字典类型 | 字典名称 | 状态 |
|
||
|----------|----------|------|
|
||
| sys_user_status | 用户状态 | 0 |
|
||
|
||
#### sys_dict_data 表(已存在,需要添加)
|
||
| 字典类型 | 字典键值 | 字典标签 | 状态 |
|
||
|----------|----------|----------|------|
|
||
| sys_user_status | 0 | 正常 | 0 |
|
||
| sys_user_status | 1 | 停用 | 0 |
|
||
|
||
## 接口设计
|
||
|
||
### RESTful API 设计
|
||
|
||
#### 1. 用户登录
|
||
- **请求方式**:POST
|
||
- **请求路径**:`/api/system/auth/login`
|
||
- **请求参数**:
|
||
```json
|
||
{
|
||
"username": "admin",
|
||
"password": "123456",
|
||
"code": "1234",
|
||
"uuid": "abc123"
|
||
}
|
||
```
|
||
- **响应参数**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"token": "eyJhbGciOiJIUzUxMiJ9..."
|
||
}
|
||
```
|
||
|
||
#### 2. 用户登出
|
||
- **请求方式**:POST
|
||
- **请求路径**:`/api/system/auth/logout`
|
||
- **请求参数**:无
|
||
- **响应参数**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "退出成功"
|
||
}
|
||
```
|
||
|
||
#### 3. 获取用户信息
|
||
- **请求方式**:GET
|
||
- **请求路径**:`/api/system/auth/getInfo`
|
||
- **请求参数**:无(从 Token 中获取用户 ID)
|
||
- **响应参数**:
|
||
```json
|
||
{
|
||
"code": 200,
|
||
"msg": "操作成功",
|
||
"user": {
|
||
"userId": 1,
|
||
"userName": "admin",
|
||
"deptId": 103
|
||
},
|
||
"roles": ["admin"],
|
||
"permissions": ["*:*:*"]
|
||
}
|
||
```
|
||
|
||
### 接口权限设计
|
||
|
||
#### 1. 用户登录
|
||
- **权限要求**:无需登录即可访问
|
||
- **注解**:`@Anonymous`
|
||
|
||
#### 2. 用户登出
|
||
- **权限要求**:需要登录
|
||
- **注解**:`@PreAuthorize("@ss.hasPermi('system:auth:logout')")`
|
||
|
||
#### 3. 获取用户信息
|
||
- **权限要求**:需要登录
|
||
- **注解**:`@PreAuthorize("@ss.hasPermi('system:auth:getInfo')")`
|
||
|
||
### 接口文档
|
||
|
||
#### 用户登录接口
|
||
**功能描述**:用户使用用户名和密码登录系统
|
||
|
||
**请求参数**:
|
||
| 参数名 | 类型 | 必填 | 说明 |
|
||
|--------|------|------|------|
|
||
| username | String | 是 | 用户名 |
|
||
| password | String | 是 | 密码 |
|
||
| code | String | 是 | 验证码 |
|
||
| uuid | String | 是 | 验证码唯一标识 |
|
||
|
||
**响应参数**:
|
||
| 参数名 | 类型 | 说明 |
|
||
|--------|------|------|
|
||
| code | Integer | 状态码(200 成功,其他失败) |
|
||
| msg | String | 提示信息 |
|
||
| token | String | JWT Token |
|
||
|
||
**示例**:
|
||
```bash
|
||
curl -X POST http://localhost:8080/api/system/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"username":"admin","password":"123456","code":"1234","uuid":"abc123"}'
|
||
```
|
||
|
||
## 实现要点
|
||
|
||
### 关键实现逻辑
|
||
|
||
#### 1. 登录流程
|
||
1. 前端发送登录请求(用户名、密码、验证码)
|
||
2. Controller 接收请求,验证验证码
|
||
3. Service 查询用户信息
|
||
4. 验证用户状态(是否停用)
|
||
5. 验证密码(BCrypt 加密比对)
|
||
6. 生成 JWT Token
|
||
7. 存储 Token 到 Redis
|
||
8. 更新用户最后登录 IP 和时间
|
||
9. 返回 Token 给前端
|
||
|
||
#### 2. 登出流程
|
||
1. 前端发送登出请求(携带 Token)
|
||
2. Controller 接收请求,验证 Token
|
||
3. 从 Redis 中删除 Token
|
||
4. 返回登出成功
|
||
|
||
#### 3. 获取用户信息流程
|
||
1. 前端发送请求(携带 Token)
|
||
2. Controller 接收请求,验证 Token
|
||
3. 从 Token 中解析用户 ID
|
||
4. Service 查询用户信息
|
||
5. Service 查询用户角色和权限
|
||
6. 返回用户信息、角色、权限
|
||
|
||
### 异常处理
|
||
|
||
#### 1. 验证码错误
|
||
- 异常类型:`CaptchaException`
|
||
- 异常信息:"验证码错误"
|
||
- 处理方式:返回错误码 500,提示用户重新输入验证码
|
||
|
||
#### 2. 用户不存在
|
||
- 异常类型:`UserNotExistsException`
|
||
- 异常信息:"用户不存在"
|
||
- 处理方式:返回错误码 500,提示用户检查用户名
|
||
|
||
#### 3. 密码错误
|
||
- 异常类型:`UserPasswordNotMatchException`
|
||
- 异常信息:"用户密码错误"
|
||
- 处理方式:返回错误码 500,提示用户检查密码
|
||
|
||
#### 4. 用户已停用
|
||
- 异常类型:`UserDeletedException`
|
||
- 异常信息:"用户已停用"
|
||
- 处理方式:返回错误码 500,提示用户联系管理员
|
||
|
||
### 性能优化
|
||
|
||
#### 1. 缓存优化
|
||
- 使用 Redis 缓存用户信息,减少数据库查询
|
||
- 缓存过期时间:30 分钟
|
||
|
||
#### 2. 数据库优化
|
||
- 在 `sys_user` 表的 `user_name` 字段上创建索引
|
||
- 使用 MyBatis Plus 的分页插件,避免全表扫描
|
||
|
||
#### 3. Token 优化
|
||
- Token 有效期设置为 2 小时,避免频繁登录
|
||
- 使用 Redis 存储 Token,实现单点登录
|
||
|
||
### 安全设计
|
||
|
||
#### 1. 密码加密
|
||
- 使用 BCrypt 加密算法,加密强度为 10
|
||
- 密码在数据库中存储为加密后的字符串
|
||
|
||
#### 2. Token 安全
|
||
- 使用 JWT 生成 Token,包含用户 ID、用户名、角色、权限
|
||
- Token 有效期为 2 小时,过期后需要重新登录
|
||
- Token 存储在 Redis 中,实现单点登录
|
||
|
||
#### 3. 防注入
|
||
- 使用 MyBatis Plus 的预编译 SQL,防止 SQL 注入
|
||
- 使用 Spring Security 的 CSRF 防护,防止 CSRF 攻击
|
||
- 使用 XSS 过滤器,防止 XSS 攻击
|
||
|
||
## 相关文档
|
||
- [需求文档](../requirements/2026-01-21-001-用户登录功能.md)
|
||
- [决策记录](../decisions/2026-01-21-001-ADR-用户登录功能-技术选型.md)
|
||
```
|
||
|
||
---
|
||
|
||
## 附录:快速参考
|
||
|
||
### 文件路径速查
|
||
- 需求文档:`docs/requirements/YYYY-MM-DD-00X-需求名.md`
|
||
- 设计文档:`docs/design/YYYY-MM-DD-00X-设计名.md`
|
||
- 主索引:`docs/index.md`
|
||
- 会话记录:`docs/sessions/YYYY-MM-DD-00X-session.md`
|
||
- 项目规则:`.trae/rules/project_rules.md`
|
||
- SSOT 架构师提示词:`docs/Prompt/0004-单一真源文档驱动架构师.md`
|
||
|
||
### 工具命令速查
|
||
```powershell
|
||
# 读取需求文档
|
||
Read(file_path="d:\\idea_demo\\datai\\docs\\requirements\\2026-01-21-001-用户登录功能.md")
|
||
|
||
# 创建设计文档
|
||
Write(file_path="d:\\idea_demo\\datai\\docs\\design\\2026-01-21-001-用户登录功能-设计.md", content="...")
|
||
|
||
# 读取索引
|
||
Read(file_path="d:\\idea_demo\\datai\\docs\\index.md")
|
||
|
||
# 更新索引
|
||
Write(file_path="d:\\idea_demo\\datai\\docs\\index.md", content="...")
|
||
|
||
# 搜索现有代码
|
||
SearchCodebase(information_request="查找 datai-modules-system 模块下的 Controller 类")
|
||
|
||
# 查找所有设计文档
|
||
Glob(pattern="docs/design/*.md")
|
||
```
|
||
|
||
### 阶段 2 输出清单
|
||
- [ ] 设计文档:`docs/design/YYYY-MM-DD-00X-设计名.md`
|
||
- [ ] 更新的索引:`docs/index.md`
|
||
- [ ] 更新的需求文档:`docs/requirements/YYYY-MM-DD-00X-需求名.md`
|
||
- [ ] 更新的会话记录:`docs/sessions/YYYY-MM-DD-00X-session.md`
|
||
|
||
### 下一阶段提示
|
||
如果用户确认进入下一阶段,请参考:
|
||
- [project_rules.md](file:///d:\idea_demo\datai\.trae\rules\project_rules.md) 的"阶段 3:方案决策"
|
||
- 准备创建决策记录(ADR)
|
||
- 准备分析至少两种技术方案
|
||
- 准备记录最终决策和理由
|