issue_49 #51
@@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					## Why
 | 
				
			||||||
 | 
					当前项目中,控制器层与服务层、仓库层之间存在严重的领域侵入问题。具体表现为:
 | 
				
			||||||
 | 
					1.  **服务层直接吐出数据库模型:** 导致控制器层直接感知并操作领域模型,增加了控制器与数据持久化细节的耦合。
 | 
				
			||||||
 | 
					2.  **服务层接收数据库对象或仓库层特定结构:** 控制器层直接构建数据库模型或仓库层查询选项并传递给服务层/仓库层,使得服务层接口不够抽象,且控制器承担了不应有的数据转换职责。
 | 
				
			||||||
 | 
					3.  **业务逻辑散落在控制器层:** 控制器层包含了大量的业务规则判断、领域对象的创建与验证、以及对仓库层和领域服务的直接协调,这违反了控制器层应只做数据校验、绑定解析和调用服务层方法的原则,导致业务逻辑分散、难以维护和测试。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					这些问题导致了代码的紧密耦合、可维护性差、测试困难,并且不利于后续的业务扩展和架构演进。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## What Changes
 | 
				
			||||||
 | 
					本次重构旨在解决上述领域侵入问题,明确各层的职责,提升代码质量。主要变更包括:
 | 
				
			||||||
 | 
					-   **服务层接口标准化:** 确保服务层方法只接收 DTO 或基本参数,并只返回 DTO 或业务领域对象(而非数据库模型)。
 | 
				
			||||||
 | 
					-   **控制器层职责收敛:** 控制器层将仅负责请求参数的绑定与校验、调用服务层方法,并将服务层返回的 DTO 转换为 HTTP 响应。所有业务逻辑、领域对象的创建与验证、以及与仓库层的直接交互都将从控制器层移除并下沉到服务层。
 | 
				
			||||||
 | 
					-   **DTO 转换逻辑下沉:** 将数据库模型与 DTO 之间的转换逻辑从控制器层移动到服务层内部或专门的转换器中。
 | 
				
			||||||
 | 
					-   **业务错误处理优化:** 服务层将返回更抽象的业务错误,控制器层根据这些抽象错误进行统一的 HTTP 响应处理,避免直接依赖仓库层或服务层内部的具体错误类型。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**BREAKING**:本次变更将涉及服务层接口的修改,以及控制器层对服务层调用的调整,可能对依赖这些接口的代码造成影响。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Impact
 | 
				
			||||||
 | 
					-   **Affected specs:**
 | 
				
			||||||
 | 
					    -   `specs/monitor/spec.md` (如果存在,需要更新服务层返回 DTO 的要求)
 | 
				
			||||||
 | 
					    -   `specs/device/spec.md` (如果存在,需要更新服务层返回 DTO 的要求)
 | 
				
			||||||
 | 
					    -   `specs/pig-farm/spec.md` (如果存在,需要更新服务层返回 DTO 的要求)
 | 
				
			||||||
 | 
					    -   `specs/plan/spec.md` (如果存在,需要更新服务层返回 DTO 的要求)
 | 
				
			||||||
 | 
					    -   `specs/user/spec.md` (如果存在,需要更新服务层返回 DTO 的要求)
 | 
				
			||||||
 | 
					-   **Affected code:**
 | 
				
			||||||
 | 
					    -   `internal/app/controller/monitor/monitor_controller.go`
 | 
				
			||||||
 | 
					    -   `internal/app/controller/device/device_controller.go`
 | 
				
			||||||
 | 
					    -   `internal/app/controller/management/pig_farm_controller.go`
 | 
				
			||||||
 | 
					    -   `internal/app/controller/plan/plan_controller.go`
 | 
				
			||||||
 | 
					    -   `internal/app/controller/user/user_controller.go`
 | 
				
			||||||
 | 
					    -   `internal/app/service/monitor_service.go` (及其实现)
 | 
				
			||||||
 | 
					    -   `internal/app/service/device_service.go` (及其实现)
 | 
				
			||||||
 | 
					    -   `internal/app/service/pig_farm_service.go` (及其实现)
 | 
				
			||||||
 | 
					    -   `internal/app/service/plan_service.go` (及其实现)
 | 
				
			||||||
 | 
					    -   `internal/app/service/user_service.go` (及其实现)
 | 
				
			||||||
 | 
					    -   `internal/infra/repository/*.go` (可能需要调整接口,以适应服务层接收 DTO 的变化)
 | 
				
			||||||
 | 
					    -   `internal/infra/models/*.go` (可能需要添加或修改 DTO 转换方法)
 | 
				
			||||||
 | 
					    -   `internal/app/dto/*.go` (可能需要添加新的 DTO 或修改现有 DTO 的构造函数)
 | 
				
			||||||
							
								
								
									
										96
									
								
								openspec/changes/refactor-business-logic-layering/tasks.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										96
									
								
								openspec/changes/refactor-business-logic-layering/tasks.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,96 @@
 | 
				
			|||||||
 | 
					## 1. 准备工作
 | 
				
			||||||
 | 
					- [ ] 1.1 阅读并理解 `openspec/changes/refactor-business-logic-layering/proposal.md`。
 | 
				
			||||||
 | 
					- [ ] 1.2 确保本地环境干净,并拉取最新代码。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 2. 统一服务层接口输入输出为 DTO
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.1 `monitor` 模块
 | 
				
			||||||
 | 
					- [ ] 2.1.1 **修改 `internal/app/service/monitor_service.go` 接口:**
 | 
				
			||||||
 | 
					    - [ ] 将所有 `List...` 方法的 `opts repository.ListOptions` 参数替换为服务层自定义的查询 DTO 或一系列基本参数。
 | 
				
			||||||
 | 
					    - [ ] 将所有 `List...` 方法的返回值 `[]models.Xxx` 替换为 `[]dto.XxxResponse`。
 | 
				
			||||||
 | 
					- [ ] 2.1.2 **修改 `internal/app/service/impl/monitor_service_impl.go` 实现:**
 | 
				
			||||||
 | 
					    - [ ] 调整 `List...` 方法的签名以匹配接口变更。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将服务层查询 DTO 转换为 `repository.ListOptions`。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将 `repository` 返回的 `models` 对象转换为 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					- [ ] 2.1.3 **修改 `internal/app/controller/monitor/monitor_controller.go`:**
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中构建 `repository.ListOptions` 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中将 `models` 转换为 `dto.NewList...Response` 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接使用 `models` 进行枚举类型转换的逻辑,将其下沉到服务层或 DTO 转换逻辑中。
 | 
				
			||||||
 | 
					    - [ ] 调整服务层方法的调用,使其接收新的服务层查询 DTO 或基本参数,并直接处理服务层返回的 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.2 `device` 模块
 | 
				
			||||||
 | 
					- [ ] 2.2.1 **修改 `internal/app/service/device_service.go` 接口:**
 | 
				
			||||||
 | 
					    - [ ] 为 `CreateDevice`, `UpdateDevice`, `CreateAreaController`, `UpdateAreaController`, `CreateDeviceTemplate`, `UpdateDeviceTemplate` 方法定义并接收 DTO 作为输入。
 | 
				
			||||||
 | 
					    - [ ] 将 `GetDevice`, `ListDevices`, `GetAreaController`, `ListAreaControllers`, `GetDeviceTemplate`, `ListDeviceTemplates` 方法的返回值 `models.Xxx` 或 `[]models.Xxx` 替换为 `dto.XxxResponse` 或 `[]dto.XxxResponse`。
 | 
				
			||||||
 | 
					    - [ ] 调整 `ManualControl` 方法,使其接收 DTO 或基本参数,而不是 `models.Device`。
 | 
				
			||||||
 | 
					- [ ] 2.2.2 **修改 `internal/app/service/impl/device_service_impl.go` 实现:**
 | 
				
			||||||
 | 
					    - [ ] 调整方法签名以匹配接口变更。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将输入 DTO 转换为 `models` 对象。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将 `repository` 返回的 `models` 对象转换为 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					    - [ ] 将 `SelfCheck()` 验证逻辑从控制器移入服务层。
 | 
				
			||||||
 | 
					    - [ ] 将 `Properties`, `Commands`, `Values` 的 JSON 序列化逻辑移入服务层。
 | 
				
			||||||
 | 
					    - [ ] 将 `ManualControl` 中的业务逻辑(如动作映射)移入服务层。
 | 
				
			||||||
 | 
					- [ ] 2.2.3 **修改 `internal/app/controller/device/device_controller.go`:**
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接创建 `models.Device`, `models.AreaController`, `models.DeviceTemplate` 对象的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接调用 `SelfCheck()` 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接调用 `repository` 方法的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中通过检查 `repository` 错误信息处理业务规则的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 调整服务层方法的调用,使其接收新的服务层输入 DTO 或基本参数,并直接处理服务层返回的 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.3 `pig-farm` 模块
 | 
				
			||||||
 | 
					- [ ] 2.3.1 **修改 `internal/app/service/pig_farm_service.go` 接口:**
 | 
				
			||||||
 | 
					    - [ ] 将 `CreatePigHouse`, `GetPigHouseByID`, `ListPigHouses`, `UpdatePigHouse`, `CreatePen`, `GetPenByID`, `ListPens`, `UpdatePen`, `UpdatePenStatus` 方法的返回值 `models.Xxx` 或 `[]models.Xxx` 替换为 `dto.XxxResponse` 或 `[]dto.XxxResponse`。
 | 
				
			||||||
 | 
					- [ ] 2.3.2 **修改 `internal/app/service/impl/pig_farm_service_impl.go` 实现:**
 | 
				
			||||||
 | 
					    - [ ] 调整方法签名以匹配接口变更。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将 `repository` 返回的 `models` 对象转换为 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					    - [ ] 将控制器中处理服务层特定业务错误(如 `service.ErrHouseNotFound`)的逻辑移入服务层,服务层应返回更抽象的错误或直接返回 DTO。
 | 
				
			||||||
 | 
					- [ ] 2.3.3 **修改 `internal/app/controller/management/pig_farm_controller.go`:**
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中手动将领域实体转换为 DTO 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接处理服务层特定业务错误类型的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 调整服务层方法的调用,使其直接处理服务层返回的 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.4 `plan` 模块
 | 
				
			||||||
 | 
					- [ ] 2.4.1 **修改 `internal/app/service/plan_service.go` 接口:**
 | 
				
			||||||
 | 
					    - [ ] 为 `CreatePlan`, `UpdatePlan` 方法定义并接收 DTO 作为输入。
 | 
				
			||||||
 | 
					    - [ ] 将 `GetPlanByID`, `ListPlans` 方法的返回值 `models.Plan` 或 `[]models.Plan` 替换为 `dto.PlanResponse` 或 `[]dto.PlanResponse`。
 | 
				
			||||||
 | 
					    - [ ] 调整 `ListPlans` 方法的 `opts repository.ListPlansOptions` 参数替换为服务层自定义的查询 DTO 或一系列基本参数。
 | 
				
			||||||
 | 
					    - [ ] 调整 `DeletePlan`, `StartPlan`, `StopPlan` 方法,使其接收 DTO 或基本参数,并封装所有业务逻辑。
 | 
				
			||||||
 | 
					- [ ] 2.4.2 **修改 `internal/app/service/impl/plan_service_impl.go` 实现:**
 | 
				
			||||||
 | 
					    - [ ] 调整方法签名以匹配接口变更。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将输入 DTO 转换为 `models` 对象。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将 `repository` 返回的 `models` 对象转换为 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					    - [ ] 将控制器中所有的业务规则判断(计划类型检查、状态检查、执行计数器重置、ContentType 自动判断)移入服务层。
 | 
				
			||||||
 | 
					    - [ ] 将控制器中对 `repository` 方法的直接调用移入服务层。
 | 
				
			||||||
 | 
					    - [ ] 将控制器中对 `analysisPlanTaskManager` 的协调移入服务层。
 | 
				
			||||||
 | 
					    - [ ] 将控制器中处理仓库层特有错误(`gorm.ErrRecordNotFound`)的逻辑移入服务层。
 | 
				
			||||||
 | 
					- [ ] 2.4.3 **修改 `internal/app/controller/plan/plan_controller.go`:**
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接创建 `models.Plan` 对象和 `repository.ListPlansOptions` 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中所有的业务规则判断。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接调用 `repository` 方法的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接协调 `analysisPlanTaskManager` 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接处理仓库层特有错误的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 调整服务层方法的调用,使其接收新的服务层输入 DTO 或基本参数,并直接处理服务层返回的 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### 2.5 `user` 模块
 | 
				
			||||||
 | 
					- [ ] 2.5.1 **修改 `internal/app/service/user_service.go` 接口:**
 | 
				
			||||||
 | 
					    - [ ] 为 `CreateUser`, `Login` 方法定义并接收 DTO 作为输入。
 | 
				
			||||||
 | 
					    - [ ] 将 `CreateUser`, `Login` 方法的返回值 `models.User` 替换为 `dto.CreateUserResponse` 或 `dto.LoginResponse`。
 | 
				
			||||||
 | 
					    - [ ] 调整 `ListUserHistory` 方法的 `opts repository.UserActionLogListOptions` 参数替换为服务层自定义的查询 DTO 或一系列基本参数,并将其返回值 `[]models.UserActionLog` 替换为 `[]dto.ListUserActionLogResponse`。
 | 
				
			||||||
 | 
					- [ ] 2.5.2 **修改 `internal/app/service/impl/user_service_impl.go` 实现:**
 | 
				
			||||||
 | 
					    - [ ] 调整方法签名以匹配接口变更。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将输入 DTO 转换为 `models` 对象。
 | 
				
			||||||
 | 
					    - [ ] 在服务层内部将 `repository` 返回的 `models` 对象转换为 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					    - [ ] 将 `CreateUser` 中处理用户名重复的业务逻辑移入服务层。
 | 
				
			||||||
 | 
					    - [ ] 将 `Login` 中进行密码验证的业务逻辑和协调 `tokenService` 的逻辑移入服务层。
 | 
				
			||||||
 | 
					    - [ ] 将 `ListUserHistory` 中强制覆盖 `UserID`、构建仓库层查询选项、枚举类型转换、以及处理服务层特定错误的逻辑移入服务层。
 | 
				
			||||||
 | 
					- [ ] 2.5.3 **修改 `internal/app/controller/user/user_controller.go`:**
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中直接创建 `models.User` 对象和 `repository.UserActionLogListOptions` 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中处理用户名重复的业务逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中进行密码验证的业务逻辑和协调 `tokenService` 的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 移除控制器中强制覆盖 `UserID`、构建仓库层查询选项、枚举类型转换、以及处理服务层特定错误的逻辑。
 | 
				
			||||||
 | 
					    - [ ] 调整服务层方法的调用,使其接收新的服务层输入 DTO 或基本参数,并直接处理服务层返回的 `dto.XxxResponse`。
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## 3. 验证与测试
 | 
				
			||||||
 | 
					- [ ] 3.1 运行所有单元测试和集成测试,确保重构没有引入新的问题。
 | 
				
			||||||
 | 
					- [ ] 3.2 针对受影响的 API 接口进行手动测试,验证功能是否正常。
 | 
				
			||||||
 | 
					- [ ] 3.3 确保日志输出和审计记录仍然准确无误。
 | 
				
			||||||
		Reference in New Issue
	
	Block a user