# CLAUDE.md 本文档为 Claude Code (claude.ai/code) 在本项目中工作时提供指导。 ## 项目概述 这是一个普拉提预约微信小程序项目,后端采用 NestJS 框架。项目使用 pnpm monorepo 结构,包含 3 个包: - **packages/app** - Vue 3 + uni-app(微信小程序前端) - **packages/server** - NestJS(后端 API 服务) - **packages/shared** - TypeScript 类型定义、枚举、常量(前后端共用) ## 常用命令 ```bash # 开发 pnpm dev:server # 启动 NestJS 后端(热重载) pnpm dev:app # 构建 uni-app 为微信小程序 # 构建 pnpm build:shared # 编译共享类型 pnpm build:server # 构建 NestJS 后端 pnpm build:app # 构建微信小程序 # 测试与代码检查 pnpm test # 运行所有测试(仅 server) pnpm lint # 运行 ESLint(仅 server) # 数据库相关(位于 packages/server 目录) cd packages/server pnpm prisma:generate # 生成 Prisma 客户端 pnpm prisma:migrate # 执行数据库迁移 pnpm prisma:seed # 填充测试数据 pnpm test:watch # 监听模式运行测试 # 部署 pnpm deploy:server # 部署后端到生产环境 ``` ## 架构说明 ### 前端 (packages/app) - 基于 Vue 3 + uni-app 框架,主攻微信小程序平台 - 页面目录:`src/pages/`(包含 home、booking、card、profile、admin 等模块) - 组件目录:`src/components/` - 状态管理:Pinia - 样式:SCSS ### 后端 (packages/server) - 框架:NestJS + Prisma ORM - 核心模块:auth(认证)、user(用户)、booking(预约)、membership(会员卡)、payment(支付)、studio(场馆)、time-slot(时段)、scheduler(定时任务)、admin(管理) - 认证:JWT + 微信登录 - 定时任务:@nestjs/schedule - 数据库:SQLite(开发)/ MySQL(生产) ### 共享包 (packages/shared) - TypeScript 接口和类型定义 - 枚举值定义 - 前后端共用的 DTO 类型 ### API 结构 - 所有接口统一前缀:`/api` - RESTful 风格接口 - 全局拦截器:日志记录、响应包装 - 全局过滤器:异常处理 ### 数据库 - Prisma schema 位于 `packages/server/prisma/schema.prisma` - 核心数据模型:User、Studio、TimeSlot、Booking、Membership、CardType、Order - 注意:查询会员列表时,booking 统计通过 `groupBy` 批量获取,避免 N+1 查询 ### 卡类型枚举 - `CardTypeCategory` (TIMES/DURATION/TRIAL) 定义在 `packages/shared/src/enums.ts` - 会员管理筛选使用特殊值 `ACTIVE` 表示持有 ACTIVE 状态会员卡的会员用户(页面默认),`NONE` 表示无卡/无有效会员(两者不在卡种枚举中) - 前端选项硬编码在 `src/pages/admin/members.vue` 的 `cardTypeOptions`,需与枚举保持同步 ### 管理后台 API 模式 - `/admin/members` 支持 `page`, `limit`, `search`, `cardType` 参数 - `cardType=ACTIVE` → 持有任意 ACTIVE 状态会员卡;`cardType=NONE` → 无 ACTIVE 状态会员卡;省略参数查看全部用户;其他值对应 `CardTypeCategory` - 预约统计(total/completed/cancelled)通过 `groupBy` 批量查询 ### 筛选组件模式 - picker 筛选使用 300ms debounce 再触发加载,避免频繁请求 - 列表分页使用 `onReachBottom` + `hasMore` 标志位实现无限滚动 ### Admin Store (`src/stores/admin.ts`) - 聚合所有管理端 API 调用:weekTemplates、cardTypes、studioConfig、members、bookings、orders、stats 等 - 遵循不可变更新原则:`data` 赋值使用展开运算符 `[...newData]` ### 历史课程补录 - `LessonSupplement` 独立记录历史累计课时,归属 user 模块;DTO 放 `user/dto`,测试放 `user/__tests__`,前端入口为 `pages/admin/member-supplement.vue`。 - 补录不创建预约或时段;只增加累计已完成节数,不推测上课日期、天数、时长,不参与月度统计、活跃网格或邀请奖励。 - 可选择从本人有限次会员卡扣次;补录与扣次必须事务提交,保存实际扣次快照,撤销只返还实际扣次。请求标识用于幂等重试。 - Prisma 迁移按 `YYYYMMDDHHmmss_description/migration.sql` 存放;补录表采用增量迁移,回退说明维护在 `docs/lesson-supplement.md`,不删除审计记录。 ### 月度教学统计 - 统计归属 admin 模块,服务放 `admin/teaching-analytics.service.ts`,测试放 `admin/__tests__`;共享契约放 `shared/src/types/teaching-analytics.ts`,页面为 `pages/admin/analytics.vue`。 - 按 TimeSlot.date 所属自然月查询,不按预约创建或核销日期;日期列以 UTC 日历值读取,中国时间用于判断课程结束。 - 当前无老师归属字段,统计范围是工作室;operatorId 不是授课老师。COMPLETED 是系统完成状态,不代表签到。 - 已上课程按时段去重,时长按已完成时段累加;上课人次按 COMPLETED 预约计数,学员按 userId 去重。取消、未出席、待确认、已确认独立计数。无日期补录不参与。 - 月历、学员排行和会员卡分布统计已完成记录;明细可组合日期、学员、状态筛选。新增测试目录只放该服务的 *.spec.ts。