snack-mall/CLAUDE.md

191 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## 项目概览
零食商城(毕业设计)— 前后端分离的电商平台,**SpringBoot 4 + Vue 3** 单体多模块仓库:
| 目录 | 角色 | 技术栈 |
|------|------|--------|
| `server-snack/` | 后端 API | Spring Boot 4.0.6、Java 21、MyBatis-Plus 3.5、Sa-Token 1.45、Redis、MySQL 8、Knife4j 4.6 |
| `admin-snack/` | 管理后台前端 | Vue 3.5 + Vite 6 + TypeScript 5 + Element Plus 2.9 + Pinia 2 + ECharts 5 |
| `db/` | 数据库脚本与设计文档 | `schema.sql`(建库 + 21 张表 DDL、`seed.sql`(演示数据)、`BUSINESS_DESIGN.md` |
| `功能设计文档.md` | 完整功能与接口设计(仓库根) | v1.2,覆盖用户端/管理端/客服/公告/优惠券/抢购 6 大模块 |
> 用户端 `web-snack` 模块当前未在本仓库中(设计文档中描述),当前实际前端仅有 `admin-snack` 管理端。
## 常用命令
### 后端(`server-snack/`
```bash
# 构建(首次会下载依赖,可能需要较长时间)
mvn clean package
# 跳过测试运行
mvn spring-boot:run
# 单独跑测试
mvn test
mvn test -Dtest=类名#方法名 # 单个测试方法
# 开发工具热重启
mvn spring-boot:run -Dspring-boot.run.fork=true
```
- 启动类:`com.snack.server.ServerSnackApplication`
- 监听端口:**8080**
- 接口文档Knife4j`http://localhost:8080/doc.html`
- MySQL 默认连接:`jdbc:mysql://localhost:3306/snack_mall`(账号 `root` / `123456`,见 `application.yml`
- Redis 默认:`localhost:6379`
- **本地上传文件** 存储到 `server-snack/uploads/`,通过 `/uploads/**` 暴露为静态资源
### 数据库(`db/`
```bash
mysql -u root -p < schema.sql # 建库 + 21 张表
mysql -u root -p < seed.sql # 演示数据(管理员 admin/123456user001~user005/123456
```
### 管理端(`admin-snack/`
```bash
# 要求 Node ≥ 20
npm install
npm run dev # 开发服务器http://localhost:5173已配置 /api 和 /uploads 代理到 8080
npm run build # 类型检查 + 生产构建(默认 mode
npm run build:test # 测试环境构建
npm run build:prod # 生产环境构建
npm run type-check # vue-tsc 类型检查
npm run lint # ESLint --fix
npm run format # Prettier 格式化
```
> 仓库内 `pnpm-lock.yaml` 已存在,但 `package.json` 脚本未区分包管理器;如本机用 pnpm命令相同`pnpm dev` 等)。
> 项目内默认账号 `admin` / `123456`(管理端登录页 + 数据库 seed 同步)。
## 架构与约定
### 后端分层
每个业务模块位于 `server-snack/src/main/java/com/snack/server/module/<name>/`,统一包结构:
```
module/<name>/
├── controller/ # @RestController按"用户端 / 管理端"分文件(如 ProductPublicController / ProductAdminController
├── service/ # 业务接口
│ └── impl/ # 业务实现
├── mapper/ # MyBatis-Plus BaseMapper
├── entity/ # 数据库表实体(含 createTime / updateTime会被 MetaObjectHandler 自动填充)
├── dto/req # 入参(带 jakarta.validation 注解)
├── vo/ # 出参(视图对象)
├── enums/ # 模块内枚举
└── constant/ # 模块内常量
```
跨模块共享放在 `com.snack.server.{common,config,constant,exception,handler,utils,enums,websocket}`
### 关键技术点
1. **认证 — Sa-Token注意不是 JWT**
- 用户端与管理端走**两套登录体系**`LoginType.USER` / `LoginType.ADMIN`),通过 `SaRouter.match` 区分
- Token 通过 `Authorization` 请求头传递(前端 `Bearer ${token}`
- 拦截器在 `config/SaTokenConfig.java` 集中维护,按 URL 模式做登录校验
- 业务异常401/403`GlobalExceptionHandler` 统一转 `Result<Void>`
2. **统一响应 — `Result<T>`**
- 结构:`{ code, message, data }`,封装在 `common/Result.java`
- 业务码集中在 `common/ResultCode.java`200/400/401/403/404/500 + 1xxx 业务码)
- **前端 axios 拦截器在 `code === 200` 时直接返回 `data`**`utils/request.ts`)— 这是已解包约定,调用方拿到的就是业务数据
3. **MyBatis-Plus 约定**
- 逻辑删除字段:`deleted`0 未删 / 1 已删),全局生效
- 主键自增:`id-type: auto`
- 实体类继承 `com.baomidou.mybatisplus.annotation.*`,自动填充 `createTime` / `updateTime``MybatisPlusMetaObjectHandler`
- 复杂 SQL 走 XML`src/main/resources/com/snack/server/module/<name>/mapper/*.xml`
- **建表 DDL 与 `entity` 字段必须保持一致**,新增字段要同步两边
4. **Redis 键命名**`constant/RedisKey.java`
- 抢购库存:`seckill:stock:{activityId}:{productId}`
- 用户抢购记录(限购):`seckill:user:{userId}:{activityId}:{productId}`
- 客服在线用户集合:`chat:online:users`
- 会话未读数:`chat:unread:{sessionId}`
- 验证码:`captcha:{uuid}`
5. **WebSocket 客服模块**`websocket/` 当前为占位 `gitkeep``BUSINESS_DESIGN.md` 有详细方案)
- Spring WebSocket + STOMP握手时验证 JWT
- 消息全部落库 `chat_message`,离线消息不丢
- 用户端用 `stomp.js`;管理端会话页在 `views/chat/`
6. **防超卖**(抢购核心)
- Redis `DECR` 原子扣减库存 → 失败直接返回"已抢完"
- 写入异步队列 → 消费端落 MySQL详见 `功能设计文档.md` 3.6.2
7. **接口规范**
- 用户端路径:`/api/<资源>`(例:`/api/cart`、`/api/orders/{id}/pay`
- 管理端路径:`/api/admin/**`(登录、验证码、文件上传除外)
- RESTful列表 `GET`、创建 `POST`、详情 `GET {id}`、删除 `DELETE {id}`
### 前端约定(`admin-snack/`
1. **路径别名**`@` → `src/`Vite + tsconfig 双侧配置)
2. **自动导入**`unplugin-auto-import` + `unplugin-vue-components`
- 自动导入 Vue / Vue Router / Pinia API、Element Plus 组件
- 类型声明由插件生成到 `src/types/auto-imports.d.ts``src/types/components.d.ts`
- 业务文件中**不要**手动 `import { ref, computed } from 'vue'` — 插件已处理
3. **状态管理 — Pinia + 持久化**
- `stores/modules/user.ts` 持久化 key 为 `snack-admin-user`
- 用 Composition API 写法(`defineStore('user', () => { ... })`),不是 Options API
4. **请求层**`utils/request.ts`
- axios 实例baseURL 取 `VITE_API_BASE_URL``.env.development` 默认 `http://localhost:8080`
- **响应拦截器已解包**`code === 200` 时直接 `return data`,调用方拿到的就是业务数据
- 401 自动清空登录态并跳 `/login`
- 所有 API 文件(`api/*.ts`)用 `request<T>(config)` 二次封装
5. **路由**`router/`
- `index.ts`基础路由login、404、仪表盘占位
- `async-routes.ts`:业务路由清单(与 `index.ts` 同步维护,权限动态挂载用)
- 路由守卫在 `src/permission.ts`,白名单 `['/login', '/404']`
- 默认页签布局:`layouts/BasicLayout.vue`(侧栏 + 顶栏 + TabsNav
6. **样式**
- SCSS 全局变量由 `vite.config.ts``additionalData` 自动注入 `@use "@/styles/variables.scss" as *;`
- 业务组件中**直接使用变量**即可,不要重新 import
- 设计令牌:主色 `#1E40AF` / `#3B82F6`,圆角 6/10px背景 `#F8FAFC`(详见 `admin-snack/README.md`
7. **Mock**
- `src/mock/index.ts` 启动时拦截 API 返回本地假数据(基于 `mockjs` + `axios-mock-adapter`
- **联调后端时注释掉 `main.ts` 里的 `import './mock'` 即可关闭**
8. **设计系统**Minimalism · Data-Dense Dashboard状态色 success `#10B981` / warning `#F59E0B` / danger `#EF4444`,圆角与阴影三档(`admin-snack/README.md` 有完整表)
### 全局约定
- **不要 commit 真实密钥**`.env.*.local`、`server-snack/application-local.yml`、`*.pem/*.key/*.crt` 已被 `.gitignore` 排除
- **Java 版本**21`<java.version>21</java.version>`
- **Node 版本**:≥ 20
- **包管理器**:管理端 `pnpm-lock.yaml` 已存在
- **Maven 仓库**:内置了华为云、阿里云镜像加速
- **不需要写** README、通用开发规范、显而易见的"添加注释"等指令
## 关键文档
| 文档 | 路径 | 何时读 |
|------|------|--------|
| 功能设计总览 | `功能设计文档.md` | 任何新模块开发前 |
| 业务核心设计WebSocket + 防超卖) | `db/BUSINESS_DESIGN.md` | 客服/抢购相关开发前 |
| 数据库表结构 | `db/schema.sql` + `db/README.md` | 新增/修改实体前 |
| 管理端技术栈与命令 | `admin-snack/README.md` | 前端环境问题排查 |
## 调试与排错
- **后端启动失败**:先检查 MySQL/Redis 是否启动、端口是否被占用、knife4j 文档能否打开
- **前端 401 风暴**:检查 `VITE_API_BASE_URL`、浏览器是否带了 `Authorization` 头、Sa-Token 拦截器路径配置
- **抢购超卖**:先看 Redis 中 `seckill:stock:*` 键值,再用 `BUSINESS_DESIGN.md` 对照流程
- **类型错误**:运行 `npm run type-check`(管理端),不要绕过 `vue-tsc` 直接 build
- **本地上传文件访问不到**:确认 `WebMvcConfig.addResourceHandlers``/uploads/**``file:./uploads/` 配置,并查看 `snack.upload.domain` 是否正确