Files
mp-pilates/CLAUDE.md
2026-04-05 21:35:30 +08:00

6.3 KiB
Raw Blame History

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

项目概述

普拉提工作室预约与会员管理的微信小程序。TypeScript monorepo包含三个包

  • packages/server — NestJS 后端REST API、Prisma ORM、PostgreSQL
  • packages/app — Vue 3 + Pinia 前端,基于 Uni-app目标平台 mp-weixin
  • packages/shared — 前后端共用的 TypeScript 类型、枚举和常量

常用命令

开发

pnpm dev:server          # NestJS watch 模式 (localhost:3000)
pnpm dev:app             # 微信小程序开发服务器
pnpm build:shared        # 必须先构建 shared再构建 server/app

测试(仅 server

cd packages/server
pnpm test                        # 运行全部测试
pnpm test -- auth.service.spec   # 运行单个测试文件
pnpm test:watch                  # watch 模式
pnpm test:cov                    # 覆盖率报告

Jest 配置内联在 packages/server/package.json。测试文件位于 __tests__/ 子目录(如 src/auth/__tests__/auth.service.spec.ts),匹配模式:*.spec.ts

数据库

cd packages/server
pnpm prisma:generate     # schema 变更后重新生成 Prisma Client
pnpm prisma:migrate      # 运行迁移(交互式)
pnpm prisma:seed         # 填充种子数据

代码检查

pnpm lint                # 所有包的 ESLint 检查

架构

数据流

微信小程序 → Uni-app (Vue 3) → REST API (NestJS) → Prisma → PostgreSQL
                 ↕                      ↕
            Pinia stores       @nestjs/schedule (定时任务)

后端模块结构

每个功能是一个 NestJS 模块,遵循 controller → service → Prisma 模式。核心模块:

  • auth — 微信 OAuth 登录code2Session、JWT 令牌、手机号绑定
  • booking — 创建/取消预约,含会员卡验证和容量检查
  • time-slot — 课程时段管理;SlotGeneratorService 根据 WeekTemplate 自动生成
  • membership — 基于卡的会员制TIMES 次卡、DURATION 时效卡、TRIAL 体验卡)
  • payment — 微信支付集成,用于购卡
  • scheduler — 定时任务02:00 自动生成时段02:30 清理过期时段

前端结构

  • pages/ — 按路由组织的页面home、booking、card、profile、admin
  • stores/ — Pinia 状态管理user、booking、studio、admin
  • utils/request.ts — 封装 uni.request 的 HTTP 客户端,自动携带 JWT
  • utils/auth.ts — 微信登录流程uni.login → 服务端 /auth/login → 存储 token

Shared 包

所有 API 类型、DTO、枚举和业务常量定义在 packages/shared/src/,前后端通过 @mp-pilates/shared 引用。路径别名配置在 tsconfig.base.json 和 Jest 的 moduleNameMapper 中。

数据库 Schema

Prisma schema 位于 packages/server/prisma/schema.prisma,关键约定:

  • Model 用 PascalCase表名用 snake_case@@map
  • 字段用 camelCase列名用 snake_case@map
  • 所有 ID 为 UUID
  • 金额字段使用 Decimal(10, 0)
  • 关键唯一约束:TimeSlot@@unique([date, startTime, endTime])Booking@@unique([userId, timeSlotId])

核心业务规则

  • 预约需要有效的会员卡(剩余次数或有效期内)
  • 取消预约需在课程开始前 cancelHoursLimit 小时(默认 2 小时,可在 StudioConfig 中配置)
  • 时段根据 WeekTemplate 自动生成未来 14 天的课程
  • 默认时段容量为 1私教课

环境配置

需要 Node 20+.nvmrc、pnpm 8+、PostgreSQL。复制 packages/server/.env.example.env.local,需配置 DATABASE_URL、JWT_SECRET 及微信相关凭证APPID、SECRET、MCH_ID、MCH_KEY、证书路径

开发约定

  • API 前缀:所有路由在 /apisetGlobalPrefix
  • 参数校验:全局 ValidationPipe启用 whitelist + forbidNonWhitelisted + transform
  • 鉴权守卫:受保护路由使用 @UseGuards(JwtAuthGuard),通过 @Req() 从 JWT 载荷提取用户
  • 角色MEMBER 和 ADMIN管理员路由使用自定义角色守卫
  • 异常处理:使用 NestJS 内置异常BadRequestException、NotFoundException 等)
  • 分页:统一使用 PaginatedResponse<T>,包含 data、total、page、limit
  • pnpm:使用 shamefully-hoist=true.npmrc为 Uni-app 兼容所需

前端样式规范

主题色变量(必用)

所有色值必须使用 packages/app/src/uni.scss 中定义的 SCSS 变量,禁止在 Vue/Scss 文件中硬编码色值。

主题色系:

$primary-color:       #a9bfcc;   /* 主色-柔雾蓝灰 */
$primary-dark:        #7ba5be;   /* 主色-深蓝灰 */
$primary-light:       #c8d8e4;   /* 主色-浅蓝灰 */
$primary-bg:         #f0f6f9;   /* 页面背景-冷白蓝 */
$primary-border:      #d8eaf4;   /* 边框-淡蓝灰 */
$primary-selected-bg: #EFF6F9;  /* 选中态背景 */

通用语义变量(已同步主题色):

变量 用途
$accent-color #7ba5be 强调色
$warning-color #e8a87c 警告色
$brand-light #c8d8e4 品牌浅色
$border-color rgba(180,160,130,0.2) 边框(中性)
$text-primary #4A4035 主文字(深棕灰)
$text-secondary #7A6A5A 次文字
$text-hint #A09080 弱提示文字

变量替换规则

旧硬编码 替换为
#c9a87c(旧暖棕金) $primary-dark
#d4b896(旧浅棕金) $primary-color
#C4956A(旧警告橙棕) $warning-color
#B08050(旧深棕) $accent-color
#7d6608(旧深暖绿) #5a7a8a(冷青灰)
#e8c88a#b49868(旧暖渐变) $primary-color / $primary-dark

CSS 变量规范

组件内部的多处共用颜色(如阴影、遮罩)若无法用 SCSS 变量,需用 rgba($primary-dark, 0.x) 形式动态构造,不可直接写死十六进制值。

新增页面/组件

新增页面或组件时:

  1. 优先查阅 uni.scss 已有变量
  2. 若需要新增语义化变量,先更新 uni.scss,再在组件中引用
  3. 禁止在 <style> 块内直接写十六进制颜色值(背景色、文字色、边框、阴影均需走变量)