Files
seclusion/CLAUDE.md
charilezhou e7496ed41b docs: 更新 CLAUDE.md 补充权限系统和代码生成器说明
新增内容:
- pnpm generate 代码生成命令
- 前端权限控制(PermissionGuard 组件、usePermissionStore)
- 后端权限控制(@RequirePermission 装饰器、PermissionModule)
- 代码生成器生成内容说明
- DataTable 通用组件说明

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 20:50:23 +08:00

344 lines
11 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.
## Project Overview
Seclusion 是一个基于 Next.js + NestJS 的 Monorepo 项目模板,使用 pnpm workspace + Turborepo 管理。
### 环境要求
- Node.js >= 20.0.0
- pnpm >= 9.0.0
## Commands
```bash
# 启动数据库 (PostgreSQL + Redis)
docker compose -f deploy/docker-compose.yml up -d
# 开发(同时启动前后端)
pnpm dev
# 构建
pnpm build
# 代码检查
pnpm lint
pnpm format # 格式化
pnpm format:check # 检查格式
# 测试
pnpm test
cd apps/api && pnpm test:watch # 单个测试文件监听
cd apps/api && pnpm test:cov # 测试覆盖率报告
# 数据库
pnpm db:generate # 生成 Prisma Client
pnpm db:push # 推送 schema 到数据库
pnpm db:migrate # 运行迁移
cd apps/api && pnpm db:studio # 打开 Prisma Studio
# 代码生成
pnpm generate # CRUD 模块生成器(交互式,生成后端+前端+类型+种子脚本)
```
## Architecture
### Monorepo 结构
- **apps/web** - Next.js 16 前端 (端口 3000),使用 React 19 + Tailwind CSS v4
- **apps/api** - NestJS 10 后端 (端口 4000API 文档: /api/docs)
- **packages/shared** - 共享类型定义、工具函数和加密模块
- **packages/eslint-config** - 共享 ESLint 9 flat config 配置
- **packages/typescript-config** - 共享 TypeScript 配置
### 前端架构 (apps/web)
**状态管理分类**
| 状态类型 | 管理方式 | 示例 |
|----------|----------|------|
| 服务端状态 | TanStack Query | 用户列表、详情数据 |
| 客户端全局状态 | Zustand | 认证信息、主题设置 |
| 组件本地状态 | useState | 表单输入、弹窗开关 |
| URL 状态 | Next.js Router | 分页参数、筛选条件 |
**前端权限控制**:使用 `<PermissionGuard>` 组件包裹需要权限的 UI 元素:
```tsx
<PermissionGuard permission="user:create">
<CreateButton />
</PermissionGuard>
// 多个权限OR 关系)
<PermissionGuard permission={['user:update', 'user:delete']}>
<ActionMenu />
</PermissionGuard>
// 多个权限AND 关系)
<PermissionGuard permission={['user:update', 'user:delete']} mode="all">
<AdminPanel />
</PermissionGuard>
```
权限数据通过 `usePermissionStore` 管理,登录后自动缓存,退出时清除。
**数据请求分层**
```
Component → Hook (TanStack Query) → Service → http
```
- **Service 层** (`services/*.service.ts`): 封装 API 调用
- **Hook 层** (`hooks/use*.ts`): 封装 TanStack Query提供 queryKey 管理
- **http** (`lib/http.ts`): Axios HTTP 客户端封装含加密处理、Token 自动刷新
### 后端模块 (apps/api)
NestJS 采用模块化架构:
- **PrismaModule** - 全局数据库服务,内置软删除扩展
- **CryptoModule** - 全局加密服务AES-256-GCM 请求/响应加密
- **AuthModule** - JWT 认证注册、登录、token 验证)
- **UserModule** - 用户 CRUD继承 CrudService 基类
- **CaptchaModule** - 验证码服务,支持多场景验证
- **PermissionModule** - 权限管理(角色、权限、菜单)
认证流程:使用 `@Public()` 装饰器标记公开接口,其他接口需要 JWT Bearer Token。使用 `@CurrentUser()` 装饰器获取当前登录用户信息(类型为 `AuthUser`)。
**权限控制**:使用 `@RequirePermission()` 装饰器控制接口权限,配合 `PermissionGuard` 使用:
```typescript
@UseGuards(JwtAuthGuard, PermissionGuard)
@RequirePermission('user:create')
@Post()
create(@Body() dto: CreateUserDto) { ... }
```
权限码格式:`{resource}:{action}`(如 `user:create``user:read``user:update``user:delete`
**后端导入规范:禁止使用 Barrel Imports**
后端代码禁止使用 `index.ts` 统一导出barrel exports必须直接从具体文件导入
```typescript
// ❌ 错误 - 使用 barrel import
import { RequirePermission } from '@/permission';
import { PrismaService } from '@/prisma';
// ✅ 正确 - 直接导入具体文件
import { RequirePermission } from '@/permission/decorators/require-permission.decorator';
import { PrismaService } from '@/prisma/prisma.service';
// ✅ 正确 - 模块内部使用相对路径
import { RequirePermission } from '../decorators/require-permission.decorator';
```
原因:
- 避免循环依赖
- 更清晰的依赖关系
- 更好的 IDE 跳转体验
### 软删除机制
PrismaService 使用 `$extends` 实现底层自动软删除,自动检测 schema 中有 `deletedAt` 字段的模型:
- **查询自动过滤**: `findMany``findFirst``findUnique``findFirstOrThrow``findUniqueOrThrow``count``aggregate``groupBy` 自动添加 `deletedAt: null` 条件
- **更新保护**: `update``updateMany` 自动过滤已删除记录,防止误更新
- **删除自动转换**: `delete``deleteMany` 自动转换为设置 `deletedAt` 时间戳
- **绕过过滤**: 显式指定 `deletedAt` 条件可查询已删除数据,如 `where: { deletedAt: { not: null } }`
启用软删除只需在 `schema.prisma` 中为模型添加 `deletedAt DateTime?` 字段,运行 `pnpm db:generate` 后自动生效。
### 通信加密
基于 AES-256-GCM 的请求/响应 Body 加密,通过 `ENABLE_ENCRYPTION` 环境变量控制:
- **后端**: `CryptoModule` 提供 `CryptoService``EncryptionInterceptor`
- **前端**: `apps/web/src/lib/crypto.ts` 封装加密客户端
- **共享**: `packages/shared/src/crypto/` 提供跨平台加密实现
- **跳过加密**: 使用 `@SkipEncryption()` 装饰器标记不需要加密的接口
### CRUD 基类
`apps/api/src/common/crud/` 提供通用 CRUD 服务和 DTO
- `CrudService<T>` - 泛型基类,提供分页查询、软删除、恢复等方法
- `PaginationQueryDto` - 分页查询参数 DTO
- `createPaginatedResponseDto(ItemDto)` - 分页响应 DTO 工厂函数
分页响应 DTO 使用示例:
```typescript
import { createPaginatedResponseDto } from '@/common/crud';
export class UserResponseDto { ... }
export class PaginatedUserResponseDto extends createPaginatedResponseDto(UserResponseDto) {}
```
### Swagger 文档规范
所有 API 接口必须完整定义 Swagger 文档:
**Controller 装饰器要求:**
- `@ApiTags()` - 接口分组标签
- `@ApiOperation()` - 接口描述
- `@ApiOkResponse()` / `@ApiCreatedResponse()` - 成功响应类型
- `@ApiBearerAuth()` - 需要认证的接口(非 `@Public()` 接口)
**DTO 定义要求:**
- 所有请求和响应都必须定义对应的 DTO class
- 使用 `@ApiProperty()` / `@ApiPropertyOptional()` 装饰每个字段
- 必须包含 `example``description` 属性
**示例:**
```typescript
// dto/example.dto.ts
export class ExampleResponseDto implements ExampleResponse {
@ApiProperty({ example: 'clxxx', description: '记录 ID' })
id: string;
}
// example.controller.ts
@ApiTags('示例')
@ApiBearerAuth()
@Controller('example')
export class ExampleController {
@Get(':id')
@ApiOperation({ summary: '获取示例详情' })
@ApiOkResponse({ type: ExampleResponseDto, description: '示例详情' })
findOne(@Param('id') id: string): Promise<ExampleResponseDto> {
return this.service.findOne(id);
}
}
```
### 共享包使用
```typescript
// 类型导入
import type { User, AuthUser, UserResponse, TokenPayload } from '@seclusion/shared';
import type { ApiResponse, PaginatedResponse } from '@seclusion/shared';
// 工具函数
import { formatDate, generateId } from '@seclusion/shared';
// 加密模块
import { createBrowserCrypto, createNodeCrypto } from '@seclusion/shared/crypto';
// 常量(使用 const + type 模式)
import { CaptchaScene } from '@seclusion/shared';
```
**注意**: `packages/shared` 中的工具函数应优先使用 lodash-es 实现。
### 前后端共享类型设计规范
为避免类型重复定义和前后端不一致,遵循以下设计原则:
**类型定义位置**
| 类型 | 定义位置 | 说明 |
|------|----------|------|
| 枚举/常量 | `packages/shared` | 使用 `const + type` 模式 |
| 接口类型 | `packages/shared` | 纯类型定义,无装饰器 |
| 后端 DTO | `apps/api` | 实现共享接口,添加 Swagger/验证装饰器 |
| 前端特有类型 | `apps/web/src/types/` | 组件 Props、表单状态等 |
**枚举定义方式(使用 const + type 替代 enum**
```typescript
// packages/shared/src/types/index.ts
export const CaptchaScene = {
LOGIN: 'login',
REGISTER: 'register',
} as const;
export type CaptchaScene = (typeof CaptchaScene)[keyof typeof CaptchaScene];
```
**后端 DTO 实现共享接口**
```typescript
// apps/api/src/xxx/dto/example.dto.ts
import type { ExampleResponse } from '@seclusion/shared';
export class ExampleResponseDto implements ExampleResponse {
@ApiProperty({ description: '示例字段', example: 'value' })
field: string;
}
```
**新增共享类型检查清单**
- [ ] 类型定义在 `packages/shared/src/types/`
- [ ] 枚举使用 `const + type` 模式
- [ ] 后端 DTO 使用 `implements` 实现共享接口
- [ ] 前端直接从 `@seclusion/shared` 导入使用
## Environment Variables
环境变量在各应用目录下独立配置:
| 位置 | 文件 | 用途 | 是否提交 |
|------|------|------|---------|
| apps/api | `.env.example` | 后端配置模板 | ✅ |
| apps/api | `.env` | 后端默认配置 | ✅ |
| apps/api | `.env.local` | 后端本地覆盖(敏感信息) | ❌ |
| apps/web | `.env` | 前端默认配置 | ✅ |
| apps/web | `.env.local` | 前端本地覆盖 | ❌ |
### 加密相关配置
```bash
# apps/api/.env
ENABLE_ENCRYPTION=false
ENCRYPTION_KEY=<32字节Base64密钥>
# apps/web/.env
NEXT_PUBLIC_ENABLE_ENCRYPTION=false
NEXT_PUBLIC_ENCRYPTION_KEY=<与后端相同的密钥>
```
生成密钥: `openssl rand -base64 32`
## Documentation
项目文档统一存放在 `docs/` 目录下:
```
docs/
├── web/ # 前端相关文档
│ └── DESIGN.md # Web 前端设计文档
├── api/ # 后端相关文档
└── shared/ # 共享模块文档
```
| 文档 | 说明 |
|------|------|
| `docs/web/DESIGN.md` | Web 前端整体设计(技术栈、目录结构、状态管理、实施计划) |
## Key Files
- `deploy/docker-compose.yml` - PostgreSQL + Redis 容器配置
- `apps/api/prisma/schema.prisma` - 数据库模型定义PostgreSQLID 使用 cuid2
- `apps/api/src/prisma/prisma.service.ts` - Prisma 服务,含软删除扩展
- `apps/api/src/common/crud/` - CRUD 基类和分页 DTO
- `apps/api/src/common/crypto/` - 后端加密模块
- `packages/shared/src/types/` - 共享类型定义
- `packages/shared/src/crypto/` - 跨平台加密实现
- `apps/web/src/types/` - 前端特有类型定义
### 代码生成器
`pnpm generate` 启动交互式代码生成器,可一键生成完整 CRUD 模块:
- **后端**: Controller、Service、DTO、Module
- **前端**: Service、Hooks、Table、CreateDialog、EditDialog、Page
- **共享类型**: TypeScript 接口定义
- **Prisma Model**: 数据库模型
- **种子脚本**: 菜单和权限初始化数据
生成的代码自动集成权限控制(`@RequirePermission` + `PermissionGuard`)。详见 `plop/README.md`
### 通用组件
**DataTable** (`components/shared/DataTable/`): 封装 TanStack Table 的通用数据表格组件
- 支持服务端分页、排序、搜索
- 内置加载状态、错误状态、空状态渲染
- 使用示例见 `components/*/XxxTable.tsx`