diff --git a/.claude/settings.local.json b/.claude/settings.local.json
new file mode 100644
index 0000000..568d453
--- /dev/null
+++ b/.claude/settings.local.json
@@ -0,0 +1,41 @@
+{
+ "permissions": {
+ "allow": [
+ "Bash(./mvnw --version)",
+ "Bash(./mvnw help:active-profiles)",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/command/AddGoodsCommand.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/command/UpdateGoodsCommand.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsEntity.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsMapper.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsService.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/db/ShopGoodsServiceImpl.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/dto/ShopGoodsDTO.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/model/GoodsModel.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/model/GoodsModelFactory.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/query/SearchShopGoodsQuery.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/goods/GoodsApplicationService.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/command/AddCabinetCellCommand.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/db/CabinetCellEntity.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/cell/model/CabinetCellModel.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user/command/AddAb98UserCommand.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user/db/Ab98UserEntity.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/ab98/user/model/Ab98UserModel.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/command/AddUserCommand.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserEntity.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModel.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/common/core/base/BaseEntity.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/common/command/BulkOperationCommand.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/common/core/page/AbstractPageQuery.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-common/src/main/java/com/agileboot/common/core/base/BaseEntity.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-common/src/main/java/com/agileboot/common/core/page/AbstractPageQuery.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/UserApplicationService.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/db/SysUserServiceImpl.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/model/UserModelFactory.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/shop/order/OrderApplicationService.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/dto/UserDTO.java\")",
+ "Bash(cat \"/e/code/智柜宝/shop-back-end/agileboot-domain/src/main/java/com/agileboot/domain/system/user/query/SearchUserQuery.java\")"
+ ],
+ "deny": [],
+ "ask": []
+ }
+}
diff --git a/CLAUDE.md b/CLAUDE.md
new file mode 100644
index 0000000..68b8285
--- /dev/null
+++ b/CLAUDE.md
@@ -0,0 +1,300 @@
+# CLAUDE.md
+
+This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
+
+## Project Overview
+
+This is **AgileBoot** - a Spring Boot 2.7.10 + Vue3 full-stack development framework with **DDD/CQRS architecture**. The project specializes in e-commerce business scenarios and integrates Enterprise WeChat, WeChat Pay, and Smart Cabinet systems.
+
+**Key Features:**
+- DDD (Domain-Driven Design) with CQRS pattern
+- Multi-level caching (Caffeine + Guava + Redis)
+- Enterprise WeChat integration (supports corpid)
+- Smart cabinet device management
+- WeChat Pay integration (JSAPI)
+- JWT-based authentication with Spring Security
+
+## Technology Stack
+
+- **Backend**: Spring Boot 2.7.10, Java 8
+- **Database**: MySQL 8.0, MyBatis Plus 3.5.2
+- **Cache**: Caffeine (local), Redis (distributed), Guava (config)
+- **Security**: Spring Security + JWT
+- **Documentation**: SpringDoc OpenAPI 3.0
+- **Build Tool**: Maven 3.9+ (use `./mvnw` wrapper)
+- **Testing**: JUnit, Mockito
+
+## Project Structure
+
+```
+agileboot (multi-module Maven project)
+├── agileboot-admin # Management backend interface module
+├── agileboot-api # Open API module (for clients)
+├── agileboot-common # Common utilities module
+├── agileboot-domain # Business domain module (DDD)
+├── agileboot-infrastructure # Infrastructure module (config, integration)
+└── agileboot-orm # ORM configuration (legacy)
+
+agileboot-domain (DDD structure - CQRS pattern)
+├── {business-module}/
+│ ├── command/ # Command objects (data update)
+│ ├── dto/ # Data Transfer Objects
+│ ├── query/ # Query objects (data retrieval)
+│ ├── model/ # Domain models
+│ ├── db/ # Database layer
+│ │ ├── entity/ # Entity classes
+│ │ ├── service/ # Database service
+│ │ └── mapper/ # MyBatis mapper
+│ └── {Module}ApplicationService.java # Application service layer
+```
+
+## Common Commands
+
+### Build and Run
+
+```bash
+# Build entire project
+./mvnw clean install
+
+# Build specific module
+./mvnw clean package -pl agileboot-admin -am
+
+# Build with tests (tests are skipped by default)
+./mvnw clean package -pl agileboot-admin -am -DskipTests=false
+
+# Run tests
+./mvnw test
+./mvnw test -pl agileboot-domain # Test specific module
+./mvnw test -Dtest=UserModelTest # Run single test class
+
+# Use build script
+build.bat
+
+# Run admin module
+cd agileboot-admin
+./mvnw spring-boot:run
+
+# Or run with embedded database/Redis
+java -jar agileboot-admin/target/agileboot-admin.jar
+```
+
+### Application Profiles
+
+**Configuration file**: `agileboot-admin/src/main/resources/application.yml`
+
+- **dev**: Development profile (MySQL + Redis required)
+- **test**: Test profile (embedded H2 + embedded Redis)
+- **prod**: Production profile
+
+```yaml
+spring:
+ profiles:
+ active: basic,dev # Change to basic,test for embedded services
+
+agileboot:
+ embedded:
+ mysql: true # Set to true to use H2 (no external DB needed)
+ redis: true # Set to true to use embedded Redis
+```
+
+**Startup classes:**
+- Admin module: `com.agileboot.admin.AgileBootAdminApplication`
+- API module: `com.agileboot.api.AgileBooApiApplication`
+- Integration tests: `com.agileboot.integrationTest.IntegrationTestApplication`
+
+### Running the Application
+
+```bash
+# With external MySQL and Redis (default dev profile)
+1. Import database: sql/agileboot_*.sql (latest version)
+2. Configure: agileboot-admin/src/main/resources/application-dev.yml
+3. Run: ./mvnw spring-boot:run -pl agileboot-admin
+
+# Without external dependencies (test profile)
+1. Change spring.profiles.active to: basic,test
+2. Set agileboot.embedded.mysql: true
+3. Set agileboot.embedded.redis: true
+4. Run: ./mvnw spring-boot:run -pl agileboot-admin
+```
+
+**Access points:**
+- API Documentation: http://localhost:8080/v3/api-docs
+- Druid Monitor: http://localhost:8080/druid/ (admin/123456)
+- Login credentials: admin/admin123
+
+## Architecture Patterns
+
+### Request Flow (CQRS)
+
+**Queries**: Controller → `{Module}Query` → `{Module}ApplicationService` → `{Module}Service` (Db) → `{Module}Mapper`
+
+**Commands**: Controller → `{Module}Command` → `{Module}ApplicationService` → `{Module}Model` → save/update
+
+### Module Organization
+
+Each business domain follows DDD structure. Example: `agileboot-domain/src/main/java/com/agileboot/domain/{module}/`
+
+- **command/**: Command objects for data updates (Create/Update/Delete)
+- **query/**: Query objects for data retrieval
+- **dto/**: Data transfer objects for API responses
+- **model/**: Domain models with business logic
+- **db/**: Data access layer (entity, service, mapper)
+- **ApplicationService**: Transaction script layer, orchestrates domain models
+
+## Business Modules
+
+Core modules in `agileboot-domain`:
+- **system**: User, role, menu, dept, config, log, notice, post
+- **cabinet**: Smart cabinet device management
+- **shop**: E-commerce (products, orders)
+- **wx**: WeChat user integration
+- **qywx**: Enterprise WeChat integration (supports corpid)
+- **ab98**: User management with tags and balance
+- **mqtt**: MQTT server integration
+- **asset**: Asset management
+
+## Caching System
+
+**Multi-level cache architecture:**
+1. **Caffeine** (local): User, role, post, login user cache
+2. **Guava** (config): System config, dict data, dept data
+3. **Redis** (distributed, optional): Session, captcha, distributed locks
+
+**Key classes:**
+- `agileboot-infrastructure/src/main/java/.../cache/`
+- `CacheCenter`: Cache management
+- `AbstractCaffeineCacheTemplate`: Caffeine cache template
+
+## Key Configuration Files
+
+- `pom.xml`: Maven parent POM with all dependencies
+- `GoogleStyle.xml`: Code formatting template (required for IntelliJ)
+- `application.yml`: Main config (profiles, embedded services)
+- `application-dev.yml`: Dev database/Redis config
+- `application-test.yml`: Test with H2/embedded Redis
+- `sql/`: Database migration scripts (latest first)
+
+## Testing
+
+**Test structure**: Each module has `src/test/java/`
+- Unit tests in `*Test.java`
+- Integration tests in `*IntegrationTest.java`
+
+**Running tests:**
+```bash
+# All tests
+./mvnw test
+
+# Specific module
+./mvnw test -pl agileboot-domain
+
+# Single test class
+./mvnw test -Dtest=UserModelTest
+
+# With coverage
+./mvnw jacoco:report # If JaCoCo configured
+```
+
+**Note**: Tests are skipped by default in build (`true` in parent POM). Set `-DskipTests=false` to run them.
+
+## Code Standards
+
+**Required:**
+- Import `GoogleStyle.xml` into IntelliJ: Settings → Editor → Code Style → Java → Import Schema
+- Properties files encoding: Settings → Editor → File Encodings → Properties Files → Set to UTF-8
+- Use enums instead of dictionary type data
+- Centralized error handling with error codes
+- Write unit tests for business logic
+
+**IDE Setup:**
+- **IntelliJ IDEA** (recommended)
+- Lombok plugin installed
+- Google code style applied
+
+## Important Business Features
+
+### Enterprise WeChat Integration
+- Supports `corpid` field for multi-tenant enterprise WeChat
+- Module: `agileboot-domain/qywx/`
+- Documentation: `doc/智能柜系统指南.md`
+
+### Smart Cabinet System
+- Device management with cabinet/cell hierarchy
+- Real-time cell status monitoring
+- Operation logging (open/close/lock)
+- Module: `agileboot-domain/cabinet/` and `agileboot-admin/controller/cabinet/`
+
+### WeChat Pay Integration
+- JSAPI payment support
+- Refund functionality
+- Module: `agileboot-domain/shop/`
+- Documentation: `doc/微信支付集成指南.md`
+
+## Database Schema
+
+**Core tables** (~10 core tables in AgileBoot):
+- `sys_user`, `sys_role`, `sys_menu`, `sys_dept`
+- `sys_config`, `sys_dict_type`, `sys_notice`
+- Plus business tables (cabinet, shop, ab98_user, etc.)
+
+**Migration files** in `sql/` directory (latest first):
+- `agileboot-*.sql`: Base schema
+- `YYYYMMDD_*.sql`: Feature migrations (e.g., 20251029_wx_user.sql)
+
+## Development Workflow
+
+1. **New Feature**:
+ - Create domain module in `agileboot-domain/{feature}/`
+ - Implement DDD structure (command, query, model, db, service)
+ - Add controllers in `agileboot-admin/controller/{feature}/`
+ - Write unit tests
+ - Update database with migration script
+
+2. **Database Changes**:
+ - Create new migration: `sql/YYYYMMDD_feature_name.sql`
+ - Update CodeGenerator if needed
+ - Test with test profile (H2 + embedded Redis)
+
+3. **API Development**:
+ - Document with `@Operation` annotation
+ - Use proper DTOs
+ - Add to `application.yml` springdoc group-configs if needed
+
+## Troubleshooting
+
+**Port 8080 busy**: Change `server.port` in `application.yml`
+
+**Redis port conflict**: Modify `spring.redis.port` in `application-dev.yml`
+
+**MacOS embedded Redis**: High versions may not support embedded Redis - use external Redis
+
+**Build fails**: Check Java version (requires Java 8+), Maven 3.9+, ensure `./mvnw clean install` succeeds
+
+## Documentation
+
+- **README.md**: Project overview and setup guide
+- **doc/项目概述.md**: Detailed architecture overview
+- **doc/智能柜系统指南.md**: Smart cabinet system guide
+- **doc/缓存系统指南.md**: Caching system guide
+- **doc/微信支付集成指南.md**: WeChat Pay integration guide
+
+## Recent Commits (for context)
+
+```
+eb41f35 feat(wx): 添加微信小程序登录功能支持
+9562d1c 登录接口更新用户登录信息修复
+7cd08c1 refactor(docs): 重构文档结构并迁移docker安装指南
+e53ff77 feat(智能柜): 添加corpid字段支持企业微信集成
+ddc3c91 feat: 添加企业微信用户ID缓存功能
+```
+
+## Tips
+
+- Use test profile for quick development without external dependencies
+- Check `application-dev.yml` for database/Redis configuration
+- Druid monitor at `/druid/` shows SQL performance
+- API docs available at `/v3/api-docs` and `/swagger-ui.html`
+- Code style: Strictly follow GoogleStyle.xml formatting
+- All business logic should have unit tests
+- Domain models contain business logic, ApplicationService is transaction script layer
+- Use multi-level cache for performance-critical data
diff --git a/doc/DDD-CQRS开发指南-新增表完整实现.md b/doc/DDD-CQRS开发指南-新增表完整实现.md
new file mode 100644
index 0000000..01ed311
--- /dev/null
+++ b/doc/DDD-CQRS开发指南-新增表完整实现.md
@@ -0,0 +1,1342 @@
+# AgileBoot DDD/CQRS 开发指南 - 新增表完整实现
+
+## 📖 文档概述
+
+本文档详细说明了在 AgileBoot 框架中新增一张数据表后,如何按照 DDD/CQRS 架构规范写出完整的 `command`、`db`、`dto`、`model`、`query`、`ApplicationService` 等全套代码。
+
+基于对 `agileboot-domain` 模块的深度分析,结合 `system/user`、`shop`、`cabinet` 等真实业务模块的代码实践,本指南提供了可直接使用的代码模板和最佳实践。
+
+---
+
+## 🏗️ 目录结构概览
+
+新增一张表后,在 `agileboot-domain/src/main/java/com/agileboot/domain/{module}/` 目录下需要创建以下结构:
+
+```
+{module}/
+├── command/ # 命令对象(写操作)
+│ ├── Add{Module}Command.java
+│ ├── Update{Module}Command.java
+│ ├── Delete{Module}Command.java
+│ └── ...
+├── db/ # 数据层
+│ ├── entity/ # 实体类
+│ │ └── {Module}Entity.java
+│ ├── service/ # 服务层
+│ │ ├── {Module}Service.java
+│ │ └── impl/
+│ │ └── {Module}ServiceImpl.java
+│ ├── mapper/ # 数据访问
+│ │ └── {Module}Mapper.java
+│ └── do/ # 数据对象(复杂查询)
+│ └── Search{Module}DO.java
+├── dto/ # 数据传输对象
+│ ├── {Module}DTO.java
+│ ├── {Module}DetailDTO.java
+│ └── {Module}ProfileDTO.java
+├── model/ # 领域模型
+│ ├── {Module}Model.java
+│ └── {Module}ModelFactory.java
+├── query/ # 查询对象
+│ └── Search{Module}Query.java
+└── {Module}ApplicationService.java # 应用服务层
+```
+
+---
+
+## 📝 核心组件详解
+
+### 1. Entity(实体类)
+
+**位置**: `db/entity/{Module}Entity.java`
+
+**职责**: 数据库表的 Java 映射,继承 `BaseEntity` 获得通用字段
+
+**关键特性**:
+- 继承 `BaseEntity`
+- 实现 `pkVal()` 返回主键
+- 使用 MyBatis-Plus 注解:`@TableName`、`@TableId`、`@TableField`
+- 所有字段使用包装类型(Long, Integer),避免空指针
+
+#### 代码示例
+
+```java
+package com.agileboot.domain.example.user.db;
+
+import com.agileboot.common.core.base.BaseEntity;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户信息表
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("example_user")
+@ApiModel(value = "ExampleUserEntity对象", description = "用户信息表")
+public class ExampleUserEntity extends BaseEntity {
+
+ private static final long serialVersionUID = 1L;
+
+ @ApiModelProperty("用户ID")
+ @TableId(value = "user_id", type = IdType.AUTO)
+ private Long userId;
+
+ @ApiModelProperty("用户姓名")
+ @TableField("user_name")
+ private String userName;
+
+ @ApiModelProperty("年龄")
+ @TableField("age")
+ private Integer age;
+
+ @ApiModelProperty("邮箱")
+ @TableField("email")
+ private String email;
+
+ @ApiModelProperty("余额")
+ @TableField("balance")
+ private BigDecimal balance;
+
+ @ApiModelProperty("状态(1正常 2停用)")
+ @TableField("status")
+ private Integer status;
+
+ @ApiModelProperty("部门ID")
+ @TableField("dept_id")
+ private Long deptId;
+
+ @ApiModelProperty("备注")
+ @TableField("remark")
+ private String remark;
+
+ @Override
+ public Serializable pkVal() {
+ return this.userId;
+ }
+}
+```
+
+**关键点**:
+- 类名: `{Module}Entity`,表名使用下划线命名 `{module}_{name}`
+- 主键字段: `{module}_id`,类型为 `Long`,注解 `@TableId(type = IdType.AUTO)`
+- 继承 `BaseEntity` 获得: `creatorId`, `createTime`, `updaterId`, `updateTime`, `deleted`
+
+---
+
+### 2. Service(服务层)
+
+**位置**: `db/service/{Module}Service.java` 和 `impl/{Module}ServiceImpl.java`
+
+**职责**: 封装数据库操作和简单业务逻辑,继承 MyBatis-Plus 的 `IService`
+
+#### 接口定义
+
+```java
+package com.agileboot.domain.example.user.db;
+
+import com.agileboot.common.core.page.AbstractPageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * 用户信息表 服务类
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+public interface ExampleUserService extends IService {
+
+ /**
+ * 检测邮箱是否唯一
+ *
+ * @param email 邮箱
+ * @param userId 用户ID(更新时传入,排除自身)
+ * @return 是否唯一
+ */
+ boolean isEmailUnique(String email, Long userId);
+
+ /**
+ * 检测用户名是否唯一
+ *
+ * @param userName 用户名
+ * @return 是否唯一
+ */
+ boolean isUserNameUnique(String userName);
+
+ /**
+ * 获取用户的部门信息
+ *
+ * @param userId 用户ID
+ * @return 部门信息
+ */
+ Long getDeptIdOfUser(Long userId);
+
+ /**
+ * 根据条件分页查询用户列表
+ *
+ * @param query 查询参数
+ * @return 用户信息集合
+ */
+ Page getUserList(AbstractPageQuery query);
+
+ /**
+ * 根据条件分页查询用户列表(带额外字段)
+ *
+ * @param query 查询参数
+ * @return 用户信息集合(含关联字段)
+ */
+ Page getUserListWithJoin(AbstractPageQuery query);
+}
+```
+
+#### 实现类
+
+```java
+package com.agileboot.domain.example.user.db.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.agileboot.common.core.page.AbstractPageQuery;
+import com.agileboot.domain.example.user.db.ExampleUserEntity;
+import com.agileboot.domain.example.user.db.SearchUserDO;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import java.util.Objects;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+/**
+ * 用户信息表 服务实现类
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Service
+@RequiredArgsConstructor
+public class ExampleUserServiceImpl extends ServiceImpl implements ExampleUserService {
+
+ @Override
+ public boolean isEmailUnique(String email, Long userId) {
+ if (StrUtil.isEmpty(email)) {
+ return true;
+ }
+
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>()
+ .eq(ExampleUserEntity::getEmail, email)
+ .eq(ExampleUserEntity::getDeleted, 0);
+
+ // 如果是更新操作,排除自身
+ if (userId != null) {
+ wrapper.ne(ExampleUserEntity::getUserId, userId);
+ }
+
+ return !this.count(wrapper) > 0;
+ }
+
+ @Override
+ public boolean isUserNameUnique(String userName) {
+ if (StrUtil.isEmpty(userName)) {
+ return true;
+ }
+
+ LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>()
+ .eq(ExampleUserEntity::getUserName, userName)
+ .eq(ExampleUserEntity::getDeleted, 0);
+
+ return !this.count(wrapper) > 0;
+ }
+
+ @Override
+ public Long getDeptIdOfUser(Long userId) {
+ if (userId == null) {
+ return null;
+ }
+
+ ExampleUserEntity entity = this.getById(userId);
+ return entity != null ? entity.getDeptId() : null;
+ }
+
+ @Override
+ public Page getUserList(AbstractPageQuery query) {
+ return this.page(query.buildPage(), query.addQueryCondition());
+ }
+
+ @Override
+ public Page getUserListWithJoin(AbstractPageQuery query) {
+ // 自定义 SQL 查询,返回关联数据
+ return this.getBaseMapper().selectUserListWithJoin(query.buildPage(), query);
+ }
+}
+```
+
+**关键点**:
+- 接口继承 `IService`
+- 实现类继承 `ServiceImpl`
+- 简单业务逻辑在 Service 中处理
+- 复杂业务逻辑交给 Model 处理
+
+---
+
+### 3. Mapper(数据访问层)
+
+**位置**: `db/mapper/{Module}Mapper.java`
+
+**职责**: MyBatis 数据访问接口,通常使用 MyBatis-Plus 的 `BaseMapper`
+
+#### 代码示例
+
+```java
+package com.agileboot.domain.example.user.db;
+
+import com.agileboot.common.core.page.AbstractPageQuery;
+import com.agileboot.domain.example.user.db.SearchUserDO;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+/**
+ * 用户信息表 Mapper 接口
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Mapper
+public interface ExampleUserMapper extends BaseMapper {
+
+ /**
+ * 分页查询用户列表(带关联数据)
+ *
+ * @param page 分页参数
+ * @param query 查询条件
+ * @return 用户列表
+ */
+ @Select({
+ ""
+ })
+ Page selectUserListWithJoin(
+ Page page,
+ @Param("query") AbstractPageQuery query
+ );
+}
+```
+
+**关键点**:
+- 继承 `BaseMapper`
+- 复杂查询使用 `@Select` 注解或 XML 文件
+- 使用 `#{}` 进行参数绑定,避免 SQL 注入
+
+---
+
+### 4. DO(数据对象)
+
+**位置**: `db/do/Search{Module}DO.java`
+
+**职责**: 复杂查询返回的数据对象,包含关联表字段
+
+#### 代码示例
+
+```java
+package com.agileboot.domain.example.user.db;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 用户查询数据对象(包含关联字段)
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Data
+public class SearchUserDO {
+
+ private Long userId;
+
+ private String userName;
+
+ private Integer age;
+
+ private String email;
+
+ private BigDecimal balance;
+
+ private Integer status;
+
+ private Long deptId;
+
+ @TableField("dept_name")
+ private String deptName;
+
+ @TableField("role_name")
+ private String roleName;
+
+ private Date createTime;
+
+ private Date updateTime;
+
+ private String remark;
+}
+```
+
+**关键点**:
+- 用于复杂查询,包含关联表字段
+- 字段名使用数据库列名或 `as` 别名
+- 不需要继承任何类
+
+---
+
+### 5. Command(命令对象)
+
+**位置**: `command/Add{Module}Command.java`、`Update{Module}Command.java`
+
+**职责**: 封装写操作的输入参数,用于接收前端传入的数据
+
+#### 添加命令
+
+```java
+package com.agileboot.domain.example.user.command;
+
+import com.agileboot.common.annotation.ExcelColumn;
+import lombok.Data;
+
+/**
+ * 添加用户命令
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Data
+public class AddUserCommand {
+
+ @ExcelColumn(name = "用户姓名")
+ private String userName;
+
+ @ExcelColumn(name = "年龄")
+ private Integer age;
+
+ @ExcelColumn(name = "邮箱")
+ private String email;
+
+ @ExcelColumn(name = "余额")
+ private String balance; // 使用 String 接收,前端传入
+
+ @ExcelColumn(name = "状态")
+ private Integer status;
+
+ @ExcelColumn(name = "部门ID")
+ private Long deptId;
+
+ @ExcelColumn(name = "备注")
+ private String remark;
+}
+```
+
+#### 更新命令
+
+```java
+package com.agileboot.domain.example.user.command;
+
+import com.agileboot.common.annotation.ExcelColumn;
+import lombok.Data;
+
+/**
+ * 更新用户命令
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Data
+public class UpdateUserCommand extends AddUserCommand {
+
+ @ExcelColumn(name = "用户ID")
+ private Long userId;
+}
+```
+
+**关键点**:
+- 纯 POJO 类,仅用于数据传输
+- 使用 `@ExcelColumn` 注解支持 Excel 导入导出
+- 命令对象通常继承或包含基础字段
+- 字段名与前端保持一致
+
+---
+
+### 6. Query(查询对象)
+
+**位置**: `query/Search{Module}Query.java`
+
+**职责**: 封装查询条件和分页参数,构建 MyBatis 查询条件
+
+#### 代码示例
+
+```java
+package com.agileboot.domain.example.user.query;
+
+import cn.hutool.core.util.StrUtil;
+import com.agileboot.common.core.page.AbstractPageQuery;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 用户查询条件
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class SearchUserQuery extends AbstractPageQuery {
+
+ private Long userId;
+
+ private String userName;
+
+ private String email;
+
+ private Integer status;
+
+ private Long deptId;
+
+ private Integer minAge;
+
+ private Integer maxAge;
+
+ @Override
+ public QueryWrapper addQueryCondition() {
+ QueryWrapper queryWrapper = new QueryWrapper<>();
+
+ queryWrapper.like(StrUtil.isNotEmpty(userName), "user_name", userName)
+ .like(StrUtil.isNotEmpty(email), "email", email)
+ .eq(userId != null, "user_id", userId)
+ .eq(status != null, "status", status)
+ .eq(deptId != null, "dept_id", deptId)
+ .eq("deleted", 0)
+ .between(minAge != null && maxAge != null, "age", minAge, maxAge);
+
+ // 设置时间范围排序字段
+ this.timeRangeColumn = "create_time";
+
+ return queryWrapper;
+ }
+}
+```
+
+**关键点**:
+- 继承 `AbstractPageQuery`
+- 实现 `addQueryCondition()` 方法构建查询条件
+- 使用链式调用构建查询条件
+- 非空判断:`StrUtil.isNotEmpty()` 和 `!= null`
+- 设置默认排序字段
+
+---
+
+### 7. DTO(数据传输对象)
+
+**位置**: `dto/{Module}DTO.java`、`{Module}DetailDTO.java`、`{Module}ProfileDTO.java`
+
+**职责**: 向前端传输数据,支持缓存集成和字段转换
+
+#### 基础 DTO
+
+```java
+package com.agileboot.domain.example.user.dto;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.agileboot.common.annotation.ExcelColumn;
+import com.agileboot.common.annotation.ExcelSheet;
+import com.agileboot.domain.common.cache.CacheCenter;
+import com.agileboot.domain.example.user.db.ExampleUserEntity;
+import com.agileboot.domain.example.user.db.SearchUserDO;
+import java.math.BigDecimal;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * 用户DTO
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@ExcelSheet(name = "用户列表")
+@Data
+public class UserDTO {
+
+ public UserDTO(ExampleUserEntity entity) {
+ if (entity != null) {
+ BeanUtil.copyProperties(entity, this);
+
+ // 从缓存中获取关联数据
+ if (entity.getDeptId() != null) {
+ // 示例:获取部门名称(如果缓存中有)
+ // this.deptName = CacheCenter.deptCache.get(entity.getDeptId() + "")...;
+ }
+ }
+ }
+
+ public UserDTO(SearchUserDO entity) {
+ if (entity != null) {
+ BeanUtil.copyProperties(entity, this);
+ }
+ }
+
+ @ExcelColumn(name = "用户ID")
+ private Long userId;
+
+ @ExcelColumn(name = "用户姓名")
+ private String userName;
+
+ @ExcelColumn(name = "年龄")
+ private Integer age;
+
+ @ExcelColumn(name = "邮箱")
+ private String email;
+
+ @ExcelColumn(name = "余额")
+ private BigDecimal balance;
+
+ @ExcelColumn(name = "状态")
+ private String status; // 可以转换为文字描述
+
+ @ExcelColumn(name = "部门ID")
+ private Long deptId;
+
+ @ExcelColumn(name = "部门名称")
+ private String deptName;
+
+ @ExcelColumn(name = "创建时间")
+ private Date createTime;
+
+ @ExcelColumn(name = "备注")
+ private String remark;
+}
+```
+
+#### 详情 DTO(包含更多选项数据)
+
+```java
+package com.agileboot.domain.example.user.dto;
+
+import com.agileboot.domain.example.user.db.ExampleUserEntity;
+import com.agileboot.domain.system.dept.dto.DeptDTO;
+import com.agileboot.domain.system.role.dto.RoleDTO;
+import java.util.List;
+import lombok.Data;
+
+/**
+ * 用户详情DTO(包含选项数据)
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Data
+public class UserDetailDTO {
+
+ private UserDTO user;
+
+ private List deptOptions;
+
+ private List roleOptions;
+}
+```
+
+**关键点**:
+- 支持从 Entity 或 DO 转换
+- 使用 `BeanUtil.copyProperties()` 进行属性复制
+- 可以集成多级缓存获取关联数据
+- 支持 Excel 导入导出(`@ExcelColumn`)
+- 可包含选项数据(如部门列表、角色列表)
+
+---
+
+### 8. Model(领域模型)
+
+**位置**: `model/{Module}Model.java`
+
+**职责**: 领域模型,封装核心业务逻辑,包括校验、状态转换等
+
+#### 代码示例
+
+```java
+package com.agileboot.domain.example.user.model;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.agileboot.common.exception.ApiException;
+import com.agileboot.common.exception.error.ErrorCode;
+import com.agileboot.domain.example.user.command.AddUserCommand;
+import com.agileboot.domain.example.user.command.UpdateUserCommand;
+import com.agileboot.domain.example.user.db.ExampleUserEntity;
+import com.agileboot.domain.example.user.db.ExampleUserService;
+import java.math.BigDecimal;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+
+/**
+ * 用户领域模型
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@NoArgsConstructor
+public class UserModel extends ExampleUserEntity {
+
+ private ExampleUserService userService;
+
+ public UserModel(ExampleUserEntity entity, ExampleUserService userService) {
+ if (entity != null) {
+ BeanUtil.copyProperties(entity, this);
+ }
+ this.userService = userService;
+ }
+
+ public UserModel(ExampleUserService userService) {
+ this.userService = userService;
+ }
+
+ /**
+ * 加载添加用户命令
+ */
+ public void loadAddUserCommand(AddUserCommand command) {
+ if (command != null) {
+ BeanUtil.copyProperties(command, this, "userId");
+
+ // 转换余额字段
+ if (StrUtil.isNotEmpty(command.getBalance())) {
+ try {
+ this.setBalance(new BigDecimal(command.getBalance()));
+ } catch (NumberFormatException e) {
+ throw new ApiException(ErrorCode.Business.COMMON_BAD_REQUEST, "余额格式不正确");
+ }
+ }
+
+ // 设置默认值
+ if (this.getStatus() == null) {
+ this.setStatus(1); // 默认正常状态
+ }
+ }
+ }
+
+ /**
+ * 加载更新用户命令
+ */
+ public void loadUpdateUserCommand(UpdateUserCommand command) {
+ if (command != null) {
+ loadAddUserCommand(command);
+ }
+ }
+
+ /**
+ * 校验用户名唯一性
+ */
+ public void checkUserNameIsUnique() {
+ if (!userService.isUserNameUnique(getUserName())) {
+ throw new ApiException(ErrorCode.Business.USER_NAME_IS_NOT_UNIQUE);
+ }
+ }
+
+ /**
+ * 校验邮箱唯一性
+ */
+ public void checkEmailIsUnique() {
+ if (!userService.isEmailUnique(getEmail(), getUserId())) {
+ throw new ApiException(ErrorCode.Business.USER_EMAIL_IS_NOT_UNIQUE);
+ }
+ }
+
+ /**
+ * 校验关联数据是否存在
+ */
+ public void checkFieldRelatedEntityExist() {
+ // 示例:校验部门是否存在
+ if (getDeptId() != null) {
+ // 可以通过其他 Service 校验部门是否存在
+ // Example: deptService.getById(getDeptId());
+ }
+ }
+
+ /**
+ * 校验是否可以删除
+ */
+ public void checkCanBeDelete() {
+ // 业务逻辑:例如检查用户是否有未完成的订单
+ // if (hasUnfinishedOrders()) {
+ // throw new ApiException(ErrorCode.Business.COMMON_BAD_REQUEST, "用户存在未完成的订单,无法删除");
+ // }
+
+ // 示例:检查是否为系统管理员
+ if (this.getIsAdmin() != null && this.getIsAdmin()) {
+ throw new ApiException(ErrorCode.Business.COMMON_BAD_REQUEST, "系统管理员不能删除");
+ }
+ }
+
+ /**
+ * 设置密码(加密)
+ */
+ public void setEncryptedPassword(String rawPassword) {
+ // 示例:加密密码
+ // this.setPassword(PasswordUtils.encrypt(rawPassword));
+ }
+
+ /**
+ * 校验年龄是否合法
+ */
+ public void checkAgeIsValid() {
+ if (getAge() != null && (getAge() < 0 || getAge() > 150)) {
+ throw new ApiException(ErrorCode.Business.COMMON_BAD_REQUEST, "年龄必须在0-150之间");
+ }
+ }
+
+ /**
+ * 预保存校验
+ */
+ public void validateBeforeSave() {
+ if (StrUtil.isEmpty(getUserName())) {
+ throw new ApiException(ErrorCode.Business.COMMON_BAD_REQUEST, "用户名不能为空");
+ }
+
+ checkUserNameIsUnique();
+ checkEmailIsUnique();
+ checkFieldRelatedEntityExist();
+ checkAgeIsValid();
+ }
+}
+```
+
+**关键点**:
+- 继承实体类,获得所有字段
+- 注入 Service 用于数据操作
+- 包含 `load*Command()` 方法加载命令数据
+- 包含 `check*()` 方法进行业务校验
+- 包含业务逻辑处理方法
+- 在 Model 中封装所有业务规则
+
+---
+
+### 9. ModelFactory(模型工厂)
+
+**位置**: `model/{Module}ModelFactory.java`
+
+**职责**: 统一创建 Model 实例,管理依赖注入和错误处理
+
+#### 代码示例
+
+```java
+package com.agileboot.domain.example.user.model;
+
+import com.agileboot.common.exception.ApiException;
+import com.agileboot.common.exception.error.ErrorCode;
+import com.agileboot.domain.example.user.db.ExampleUserEntity;
+import com.agileboot.domain.example.user.db.ExampleUserService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Component;
+
+/**
+ * 用户模型工厂
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Component
+@RequiredArgsConstructor
+public class UserModelFactory {
+
+ private final ExampleUserService userService;
+
+ /**
+ * 根据ID加载用户模型
+ *
+ * @param userId 用户ID
+ * @return 用户模型
+ */
+ public UserModel loadById(Long userId) {
+ ExampleUserEntity entity = userService.getById(userId);
+ if (entity == null) {
+ throw new ApiException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, userId, "用户");
+ }
+ return new UserModel(entity, userService);
+ }
+
+ /**
+ * 创建新用户模型
+ *
+ * @return 用户模型
+ */
+ public UserModel create() {
+ return new UserModel(userService);
+ }
+}
+```
+
+**关键点**:
+- 使用 `@Component` 注解注入 Spring 容器
+- 使用 `@RequiredArgsConstructor` 自动注入依赖
+- `loadById()` 检查数据是否存在,不存在则抛异常
+- `create()` 创建空模型,用于新增操作
+
+---
+
+### 10. ApplicationService(应用服务)
+
+**位置**: `{Module}ApplicationService.java`
+
+**职责**: 事务脚本层,协调 Model 和 Service,处理业务流程编排
+
+#### 代码示例
+
+```java
+package com.agileboot.domain.example.user;
+
+import cn.hutool.core.convert.Convert;
+import com.agileboot.common.core.page.PageDTO;
+import com.agileboot.domain.common.command.BulkOperationCommand;
+import com.agileboot.domain.example.user.command.AddUserCommand;
+import com.agileboot.domain.example.user.command.UpdateUserCommand;
+import com.agileboot.domain.example.user.db.SearchUserDO;
+import com.agileboot.domain.example.user.dto.UserDTO;
+import com.agileboot.domain.example.user.dto.UserDetailDTO;
+import com.agileboot.domain.example.user.model.UserModel;
+import com.agileboot.domain.example.user.model.UserModelFactory;
+import com.agileboot.domain.example.user.query.SearchUserQuery;
+import com.agileboot.domain.system.dept.db.SysDeptService;
+import com.agileboot.domain.system.dept.dto.DeptDTO;
+import com.agileboot.domain.example.user.db.ExampleUserEntity;
+import com.agileboot.domain.example.user.db.ExampleUserService;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import java.util.List;
+import java.util.stream.Collectors;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 用户应用服务
+ *
+ * @author your-name
+ * @since 2025-01-01
+ */
+@Service
+@RequiredArgsConstructor
+public class UserApplicationService {
+
+ private final ExampleUserService userService;
+
+ private final SysDeptService deptService;
+
+ private final UserModelFactory userModelFactory;
+
+ /**
+ * 获取用户列表(分页)
+ */
+ public PageDTO getUserList(SearchUserQuery query) {
+ Page userPage = userService.getUserListWithJoin(query);
+ List userDTOList = userPage.getRecords()
+ .stream()
+ .map(UserDTO::new)
+ .collect(Collectors.toList());
+ return new PageDTO<>(userDTOList, userPage.getTotal());
+ }
+
+ /**
+ * 获取用户详情
+ */
+ public UserDetailDTO getUserDetailInfo(Long userId) {
+ ExampleUserEntity userEntity = userService.getById(userId);
+
+ UserDetailDTO detailDTO = new UserDetailDTO();
+ detailDTO.setUser(new UserDTO(userEntity));
+
+ // 获取部门选项
+ List deptOptions = deptService.list()
+ .stream()
+ .map(DeptDTO::new)
+ .collect(Collectors.toList());
+ detailDTO.setDeptOptions(deptOptions);
+
+ return detailDTO;
+ }
+
+ /**
+ * 添加用户
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void addUser(AddUserCommand command) {
+ UserModel model = userModelFactory.create();
+ model.loadAddUserCommand(command);
+
+ // 业务校验
+ model.validateBeforeSave();
+
+ // 保存
+ model.insert();
+ }
+
+ /**
+ * 更新用户
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void updateUser(UpdateUserCommand command) {
+ UserModel model = userModelFactory.loadById(command.getUserId());
+ model.loadUpdateUserCommand(command);
+
+ // 业务校验
+ model.checkEmailIsUnique();
+ model.checkFieldRelatedEntityExist();
+ model.checkAgeIsValid();
+
+ // 更新
+ model.updateById();
+ }
+
+ /**
+ * 删除用户(单个)
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteUser(Long userId) {
+ UserModel model = userModelFactory.loadById(userId);
+
+ // 业务校验
+ model.checkCanBeDelete();
+
+ // 软删除
+ model.deleteById();
+ }
+
+ /**
+ * 批量删除用户
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void deleteUsers(BulkOperationCommand command) {
+ for (Long userId : command.getIds()) {
+ UserModel model = userModelFactory.loadById(userId);
+ model.checkCanBeDelete();
+ model.deleteById();
+ }
+ }
+
+ /**
+ * 更改用户状态
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void changeUserStatus(Long userId, Integer status) {
+ UserModel model = userModelFactory.loadById(userId);
+
+ model.setStatus(status);
+ model.updateById();
+ }
+
+ /**
+ * 重置用户密码
+ */
+ @Transactional(rollbackFor = Exception.class)
+ public void resetPassword(Long userId, String newPassword) {
+ UserModel model = userModelFactory.loadById(userId);
+
+ model.setEncryptedPassword(newPassword);
+ model.updateById();
+ }
+}
+```
+
+**关键点**:
+- 使用 `@Service` 注解
+- 使用 `@RequiredArgsConstructor` 注入依赖
+- 写操作使用 `@Transactional` 注解保证事务
+- 协调 Model 和 Service
+- 返回 DTO 给 Controller
+- 包含完整的 CRUD 操作
+
+---
+
+## 🔄 CQRS 流程
+
+### Command(写操作)流程
+
+```
+Controller → Command → ApplicationService → Model → 业务校验 → 保存
+```
+
+**示例**:
+```java
+// 1. Controller 接收参数,封装为 Command
+AddUserCommand command = new AddUserCommand();
+// ... 设置参数
+
+// 2. ApplicationService 处理
+userApplicationService.addUser(command);
+
+// 3. ApplicationService 创建 Model 并加载 Command
+UserModel model = userModelFactory.create();
+model.loadAddUserCommand(command);
+
+// 4. Model 进行业务校验
+model.validateBeforeSave();
+
+// 5. Model 执行保存操作
+model.insert();
+```
+
+### Query(读操作)流程
+
+```
+Controller → Query → Service → Mapper → DTO
+```
+
+**示例**:
+```java
+// 1. Controller 接收查询参数,封装为 Query
+SearchUserQuery query = new SearchUserQuery<>();
+// ... 设置查询条件
+
+// 2. ApplicationService 处理
+PageDTO result = userApplicationService.getUserList(query);
+
+// 3. Service 执行查询
+Page userPage = userService.getUserListWithJoin(query);
+
+// 4. 转换为 DTO
+List userDTOList = userPage.getRecords()
+ .stream()
+ .map(UserDTO::new)
+ .collect(Collectors.toList());
+
+return new PageDTO<>(userDTOList, userPage.getTotal());
+```
+
+---
+
+## 📌 最佳实践
+
+### 1. 命名规范
+
+| 类型 | 命名规则 | 示例 |
+|------|----------|------|
+| Entity | `{Module}Entity` | `SysUserEntity` |
+| Service 接口 | `{Module}Service` | `SysUserService` |
+| Service 实现 | `{Module}ServiceImpl` | `SysUserServiceImpl` |
+| Mapper | `{Module}Mapper` | `SysUserMapper` |
+| Model | `{Module}Model` | `UserModel` |
+| ModelFactory | `{Module}ModelFactory` | `UserModelFactory` |
+| Command | `{Operation}{Module}Command` | `AddUserCommand` |
+| Query | `Search{Module}Query` | `SearchUserQuery` |
+| DTO | `{Module}DTO` | `UserDTO` |
+| ApplicationService | `{Module}ApplicationService` | `UserApplicationService` |
+
+### 2. 字段命名规范
+
+- **Entity**: 使用下划线命名,与数据库保持一致
+ - `user_id`, `user_name`, `create_time`
+- **Command/Query/DTO**: 使用驼峰命名,与前端保持一致
+ - `userId`, `userName`, `createTime`
+
+### 3. 类型选择
+
+- **主键**: 使用 `Long`(包装类型)
+- **状态/数量**: 使用 `Integer`(包装类型)
+- **金额**: 使用 `BigDecimal`(避免精度问题)
+- **字符串**: 避免基本类型,使用 `String`
+- **时间**: 使用 `Date` 或 `LocalDateTime`
+
+### 4. 空值处理
+
+- 始终使用包装类型,避免 NPE
+- 使用 `StrUtil.isNotEmpty()` 判断字符串
+- 使用 `!= null` 判断对象和数字
+- 使用 MyBatis-Plus 的链式调用:`eq(condition, "column", value)`
+
+### 5. 业务校验位置
+
+- **唯一性校验**: Model 层
+- **关联数据存在性校验**: Model 层
+- **字段格式校验**: Model 层
+- **业务规则校验**: Model 层
+- **数据库约束**: Entity 层
+
+### 6. 缓存集成
+
+DTO 中可以从缓存获取关联数据:
+```java
+public UserDTO(ExampleUserEntity entity) {
+ if (entity != null) {
+ BeanUtil.copyProperties(entity, this);
+
+ // 从缓存获取部门名称
+ if (entity.getDeptId() != null) {
+ SysDeptEntity dept = CacheCenter.deptCache.get(entity.getDeptId() + "");
+ this.deptName = dept != null ? dept.getDeptName() : "";
+ }
+ }
+}
+```
+
+### 7. 事务管理
+
+- ApplicationService 负责事务管理
+- 使用 `@Transactional(rollbackFor = Exception.class)`
+- 写操作必须开启事务
+- 读操作可以不加事务(但建议加 `@Transactional(readOnly = true)`)
+
+### 8. 异常处理
+
+- 业务异常使用 `ApiException`
+- 错误码使用 `ErrorCode` 枚举
+- Model 层抛出异常,ApplicationService 不捕获
+- Controller 层统一处理异常
+
+### 9. 代码复用
+
+- 公共方法抽取到工具类
+- 通用 DTO/Entity 放在 `common` 模块
+- 公共 Service 方法抽取到基类
+- 使用组合而非继承
+
+---
+
+## 🛠️ 开发步骤清单
+
+新增一张表后的完整开发流程:
+
+### 1. 数据库层面
+- [ ] 创建数据库表(`sql/YYYYMMDD_feature_name.sql`)
+- [ ] 添加表注释和字段注释
+- [ ] 创建必要的索引
+
+### 2. Entity 层
+- [ ] 创建 `{Module}Entity.java`,继承 `BaseEntity`
+- [ ] 配置 `@TableName`、`@TableId`、`@TableField` 注解
+- [ ] 实现 `pkVal()` 方法
+
+### 3. Mapper 层
+- [ ] 创建 `{Module}Mapper.java`,继承 `BaseMapper`
+- [ ] 添加自定义查询方法(如需要)
+
+### 4. Service 层
+- [ ] 创建 `{Module}Service.java` 接口
+- [ ] 创建 `{Module}ServiceImpl.java` 实现类
+- [ ] 继承 `ServiceImpl`
+- [ ] 实现核心业务方法
+
+### 5. Command 层
+- [ ] 创建 `Add{Module}Command.java`
+- [ ] 创建 `Update{Module}Command.java`(可选:继承基础 Command)
+- [ ] 创建其他 Command(如 `Delete{Module}Command.java`)
+
+### 6. Query 层
+- [ ] 创建 `Search{Module}Query.java`
+- [ ] 继承 `AbstractPageQuery`
+- [ ] 实现 `addQueryCondition()` 方法
+
+### 7. DTO 层
+- [ ] 创建 `{Module}DTO.java`
+- [ ] 添加构造函数(从 Entity/DO 转换)
+- [ ] 添加 `@ExcelColumn` 注解(如果需要导出)
+- [ ] 集成缓存获取关联数据(如果需要)
+
+### 8. Model 层
+- [ ] 创建 `{Module}Model.java`,继承 Entity
+- [ ] 添加 `load*Command()` 方法
+- [ ] 添加 `check*()` 业务校验方法
+- [ ] 添加业务逻辑处理方法
+
+### 9. ModelFactory 层
+- [ ] 创建 `{Module}ModelFactory.java`
+- [ ] 使用 `@Component` 注解
+- [ ] 添加 `loadById()` 方法
+- [ ] 添加 `create()` 方法
+
+### 10. ApplicationService 层
+- [ ] 创建 `{Module}ApplicationService.java`
+- [ ] 使用 `@Service` 注解
+- [ ] 注入 Service 和 ModelFactory
+- [ ] 实现 CRUD 方法
+- [ ] 添加 `@Transactional` 注解
+
+### 11. Controller 层(在 agileboot-admin 中)
+- [ ] 创建 Controller
+- [ ] 注入 ApplicationService
+- [ ] 定义 RESTful API
+- [ ] 添加 `@Operation` 注解
+
+### 12. 测试
+- [ ] 编写单元测试(Service、Model)
+- [ ] 编写集成测试
+- [ ] 测试 CRUD 操作
+- [ ] 测试业务校验
+- [ ] 测试缓存(如果使用)
+
+### 13. 文档
+- [ ] 更新 API 文档
+- [ ] 补充业务说明
+- [ ] 更新数据库文档
+
+---
+
+## 📚 参考资料
+
+### 代码结构参考
+- **System 用户管理**: `agileboot-domain/src/main/java/com/agileboot/domain/system/user/`
+- **Shop 电商模块**: `agileboot-domain/src/main/java/com/agileboot/domain/shop/`
+- **Cabinet 智能柜**: `agileboot-domain/src/main/java/com/agileboot/domain/cabinet/`
+
+### 核心类参考
+- **BaseEntity**: `com.agileboot.common.core.base.BaseEntity`
+- **AbstractPageQuery**: `com.agileboot.common.core.page.AbstractPageQuery`
+- **PageDTO**: `com.agileboot.common.core.page.PageDTO`
+- **ApiException**: `com.agileboot.common.exception.ApiException`
+- **ErrorCode**: `com.agileboot.common.exception.error.ErrorCode`
+- **CacheCenter**: `com.agileboot.domain.common.cache.CacheCenter`
+
+---
+
+## 🎯 总结
+
+AgileBoot 的 DDD/CQRS 架构通过清晰的分层和职责分离,为企业级应用开发提供了强有力的支撑:
+
+1. **Entity**: 数据库映射,继承 BaseEntity
+2. **Service**: 数据库操作和简单业务逻辑
+3. **Command**: 写操作参数封装
+4. **Query**: 读操作查询条件
+5. **DTO**: 前端数据传输,支持缓存
+6. **Model**: 领域模型,封装核心业务逻辑
+7. **ModelFactory**: 统一创建 Model
+8. **ApplicationService**: 事务脚本层,协调各组件
+
+遵循本指南的规范,可以快速构建符合 DDD/CQRS 架构的高质量代码。
+
+---
+
+**文档版本**: v1.0
+**最后更新**: 2025-01-01
+**作者**: AgileBoot Team