diff --git a/.claude/memory/java-backend.md b/.claude/memory/java-backend.md index f109f0c..b2273ee 100644 --- a/.claude/memory/java-backend.md +++ b/.claude/memory/java-backend.md @@ -2,6 +2,24 @@ 本项目 Java 后端开发规范,基于 Spring Boot + MyBatis-Plus 技术栈。 +## JDK 版本要求(重要) + +**必须使用 JDK 17** 进行编译和运行。 + +如果系统环境变量配置的是 JDK 1.8,请在编译前设置 `JAVA_HOME`: + +```bash +# Windows (Git Bash) - 根据实际安装路径调整 +export JAVA_HOME="/f/Java/jdk-17" +export PATH="$JAVA_HOME/bin:$PATH" + +# 编译项目 +mvn clean compile -DskipTests + +# 或者在启动时指定 +mvn spring-boot:run -Djava.home="/f/Java/jdk-17" +``` + ## 核心原则 1. **OpenAPI 规范驱动** - 前后端通过接口规范对齐 @@ -139,6 +157,92 @@ Result { - `lock:{resource}:{id}` - 分布式锁 - `rate_limit:{key}` - 限流计数器 +## 数据库索引规范(重要) + +### 唯一索引处理原则 + +**项目使用逻辑删除,唯一索引通过应用层控制,而非数据库唯一约束。** + +#### 背景问题 + +当表有逻辑删除字段(`deleted`)时,数据库唯一索引会导致: +1. 删除后无法重新添加相同数据 +2. 错误信息不友好,直接返回数据库异常 + +#### 解决方案 + +| 层级 | 职责 | 实现方式 | +|------|------|----------| +| **数据库层** | 普通索引 | `KEY idx_xxx (xxx)` 而非 `UNIQUE KEY uk_xxx (xxx)` | +| **应用层** | 重复校验 | Service 层查询 + 悲观锁 `FOR UPDATE` | +| **异常处理** | 兜底处理 | 全局异常处理器捕获 `DuplicateKeyException` | + +#### 实现示例 + +**1. 数据库迁移(Flyway)** +```sql +-- ❌ 错误:使用唯一索引 +UNIQUE KEY `uk_username` (`username`) + +-- ✅ 正确:使用普通索引 +KEY `idx_username` (`username`) +``` + +**2. Mapper 层(悲观锁查询)** +```java +/** + * 根据用户名查询用户(悲观锁,用于创建时防并发) + */ +@Select("SELECT * FROM t_user WHERE username = #{username} AND tenant_id = #{tenantId} AND deleted = 0 FOR UPDATE") +User getUserByUsernameForUpdate(@Param("username") String username, @Param("tenantId") Long tenantId); +``` + +**3. Service 层(事务 + 校验)** +```java +@Transactional(rollbackFor = Exception.class) +public UserVO createUser(CreateUserDTO dto, Long tenantId, Long operatorId) { + log.info("开始创建用户,用户名:{}", dto.getUsername()); + + // 使用悲观锁检查用户名是否已存在(防止并发) + User existingUser = userMapper.getUserByUsernameForUpdate(dto.getUsername(), tenantId); + if (existingUser != null) { + throw new BusinessException("用户名已存在"); + } + + // 插入用户 + User user = convert(dto); + userMapper.insert(user); + return convertToVO(user); +} +``` + +**4. 需要应用层校验的字段** + +以下字段需要添加应用层重复校验: + +| 表 | 字段 | 说明 | +|-----|------|------| +| t_user | username, email, phone | 用户名、邮箱、手机号 | +| t_role | code | 角色编码 | +| t_permission | code | 权限编码 | +| t_dict | code + tenant_id | 字典编码 | +| t_tenant | code | 租户编码 | +| t_sys_config | config_key | 配置键 | + +### 关联表索引规范 + +对于多对多关联表,使用普通索引而非唯一索引: + +```sql +-- t_user_role: 用户角色关联表 +KEY `idx_user_role` (`user_id`, `role_id`) + +-- t_role_permission: 角色权限关联表 +KEY `idx_role_permission` (`role_id`, `permission_id`) +``` + +**注意**:关联表的重复数据控制在应用层业务逻辑中处理。 + ### 核心环境变量 - `SPRING_PROFILES_ACTIVE` - 活跃环境 diff --git a/CLAUDE.md b/CLAUDE.md index 21ec934..20cc234 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,31 +1,60 @@ - # CLAUDE.md -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. +本文档为 Claude Code 在本项目中工作提供指导。 + +## 项目目录结构(重要) + +| 目录 | 说明 | +|------|------| +| `java-backend/` | **后端项目目录** - Spring Boot 应用 | +| `java-frontend/` | **前端项目目录** - Vue 3 应用 | + +**所有后续开发都基于这两个项目进行。** + +## JDK 版本要求(重要) + +**必须使用 JDK 17** 进行编译和运行。 + +如果系统环境变量配置的是 JDK 1.8,请在编译前设置 `JAVA_HOME`: + +```bash +# Windows (Git Bash) - 根据实际安装路径调整 +export JAVA_HOME="/f/Java/jdk-17" +export PATH="$JAVA_HOME/bin:$PATH" + +# 编译项目 +cd java-backend +mvn clean compile -DskipTests + +# 启动项目 +mvn spring-boot:run -Djava.home="/f/Java/jdk-17" +``` ## 快速开始 ```bash -# 安装所有依赖(前端 + 后端) +# 前端 - 安装依赖并启动 +cd java-frontend pnpm install - -# 同时启动前后端开发服务器 pnpm dev -# 或分别启动 -pnpm dev:frontend # 前端 http://localhost:3000 -pnpm dev:backend # 后端 http://localhost:3001 +# 后端 - 安装依赖并启动 +cd java-backend +mvn clean install +mvn spring-boot:run -Dspring.profiles.active=dev ``` ## 技术栈 -### 后端 -- **框架**: NestJS + TypeScript -- **数据库**: MySQL 8.0 + Prisma ORM -- **认证**: JWT + RBAC (基于角色的访问控制) -- **多租户**: 数据隔离架构(每个租户独立 tenantId) +### 后端 (java-backend/) +- **框架**: Spring Boot 3.2 + Java 17 +- **持久层**: MyBatis-Plus 3.5+ +- **数据库**: MySQL 8.0 + Flyway 迁移 +- **认证**: Spring Security + JWT +- **缓存**: Redis +- **对象映射**: MapStruct 1.5+ -### 前端 +### 前端 (java-frontend/) - **框架**: Vue 3 + TypeScript + Vite - **UI 组件**: Ant Design Vue - **状态管理**: Pinia @@ -33,41 +62,35 @@ pnpm dev:backend # 后端 http://localhost:3001 ## 核心命令 -### 开发 +### 后端开发 (java-backend/) ```bash -# 根目录 -pnpm dev # 同时启动前后端 -pnpm dev:frontend # 只启动前端 -pnpm dev:backend # 只启动后端 +cd java-backend -# 前端目录 -pnpm dev # 启动前端 +# 编译 +mvn clean compile -DskipTests -# 后端目录 -pnpm start:dev # 启动后端 -pnpm prisma:studio # Prisma 数据库可视化 +# 启动 +mvn spring-boot:run -Dspring.profiles.active=dev + +# 打包 +mvn clean package -DskipTests + +# 数据库迁移 +mvn flyway:migrate ``` -### 数据库迁移 +### 前端开发 (java-frontend/) ```bash -cd backend -pnpm prisma:generate # 生成 Prisma Client -pnpm prisma:migrate # 开发环境迁移 -pnpm prisma:migrate:deploy # 生产环境部署 -``` +cd java-frontend -### 构建 -```bash -pnpm build # 构建前后端 -pnpm build:frontend # 只构建前端 -pnpm build:backend # 只构建后端 -``` +# 安装依赖 +pnpm install -### 测试 -```bash -cd backend -pnpm test # 运行单元测试 -pnpm test:cov # 测试覆盖率 +# 启动开发服务器 +pnpm dev + +# 构建 +pnpm build ``` ## 架构概览 @@ -75,122 +98,88 @@ pnpm test:cov # 测试覆盖率 ### 目录结构 ``` library-picturebook-activity/ -├── backend/ # NestJS 后端 -│ ├── prisma/ # Prisma schema 和 migrations -│ ├── src/ -│ │ ├── auth/ # 认证模块 (JWT) -│ │ ├── users/ # 用户管理 -│ │ ├── roles/ # 角色权限 -│ │ ├── menus/ # 菜单管理 -│ │ ├── tenants/ # 租户管理 -│ │ ├── contests/ # 竞赛模块 -│ │ │ ├── contests/ # 竞赛管理 -│ │ │ ├── works/ # 作品管理 -│ │ │ ├── teams/ # 团队管理 -│ │ │ ├── registrations/ # 报名管理 -│ │ │ └── reviews/ # 评审管理 -│ │ ├── school/ # 学校模块 -│ │ │ ├── schools/ -│ │ │ ├── grades/ -│ │ │ ├── classes/ -│ │ │ ├── teachers/ -│ │ │ └── students/ -│ │ └── prisma/ # Prisma 服务 -│ └── package.json +├── java-backend/ # Spring Boot 后端 +│ ├── src/main/java/ +│ │ └── com/lesingle/creation/ +│ │ ├── common/ # 公共模块(常量、异常、工具) +│ │ ├── config/ # 配置类 +│ │ ├── controller/ # REST 控制器 +│ │ ├── dto/ # 数据传输对象 +│ │ ├── entity/ # 实体类 +│ │ ├── mapper/ # MyBatis Mapper +│ │ ├── service/ # 业务逻辑层 +│ │ │ └── impl/ # Service 实现 +│ │ └── vo/ # 视图对象 +│ └── src/main/resources/ +│ ├── application*.yml # 配置文件 +│ ├── db/migration/ # Flyway 迁移脚本 +│ └── mapper/ # MyBatis XML │ -└── frontend/ # Vue 3 前端 +└── java-frontend/ # Vue 3 前端 ├── src/ - │ ├── api/ # API 接口 - │ ├── views/ # 页面组件 - │ ├── components/ # 公共组件 - │ ├── stores/ # Pinia 状态 - │ ├── router/ # 路由配置 - │ └── composables/ # 组合式函数 - └── package.json + │ ├── api/ # API 接口 + │ ├── views/ # 页面组件 + │ ├── components/ # 公共组件 + │ ├── stores/ # Pinia 状态 + │ ├── router/ # 路由配置 + │ ├── composables/ # 组合式函数 + │ └── utils/ # 工具函数 + └── public/ ``` -### 模块结构(后端) +### 后端模块结构 每个功能模块包含: -- `module.ts` - 模块定义 -- `controller.ts` - REST 控制器 -- `service.ts` - 业务逻辑 -- `dto/` - 数据传输对象 - -### 多租户架构 -- 所有业务数据必须包含 `tenantId` 字段 -- 查询必须包含租户隔离条件 -- 超级租户(`isSuper = 1`)可访问所有数据 +- `XxxController.java` - REST 控制器 +- `XxxService.java` / `XxxServiceImpl.java` - 业务逻辑 +- `XxxMapper.java` - 数据访问层 +- `Xxx.java` (entity/) - 实体类 +- `XxxDTO.java` / `XxxVO.java` - 数据传输对象 ## 关键开发规范 ### 后端规范 -1. **租户隔离(强制)**:所有数据库查询必须包含 `tenantId` -```typescript -// ✅ 正确 -const data = await prisma.model.findMany({ where: { tenantId } }); +1. **三层架构原则**: + - Controller 层:DTO ↔ VO 转换 + - Service 层:使用 Entity,继承 `IService` + - Mapper 层:使用 Entity -// ❌ 错误 - 缺少 tenantId -const data = await prisma.model.findMany({}); -``` +2. **日志规范**: + - **所有日志必须使用中文** + - 使用 MDC 实现 TraceId 链路追踪 + - 开发/测试环境:DEBUG 级别 + - 生产环境:INFO/WARN 级别 -2. **审计字段**:所有表必须包含 - - `tenantId` - 租户 ID - - `creator`/`modifier` - 创建/修改人 - - `createTime`/`modifyTime` - 时间戳 - - `validState` - 有效状态(1-有效,2-失效) +3. **权限控制**:使用权限注解进行接口保护 -3. **权限控制**:使用 `@RequirePermission('module:action')` 装饰器 - -4. **DTO 验证**:使用 `class-validator` 装饰器 +4. **DTO 验证**:使用 Validation 注解 ### 前端规范 -1. **路由包含租户编码**:`/:tenantCode/xxx` +1. **API 调用**:放在 `src/api/` 目录,按模块组织 -2. **API 调用**:放在 `api/` 目录,按模块组织 +2. **状态管理**:使用 Pinia,store 命名 `xxxStore` -3. **状态管理**:使用 Pinia,store 命名 `xxxStore` +3. **组件语法**:使用 `