library-picturebook-activity/.cursor/rules/multi-tenant.mdc

102 lines
2.2 KiB
Plaintext
Raw Permalink Normal View History

---
description: 多租户数据隔离规范(所有涉及数据库操作的代码必须遵守)
globs:
alwaysApply: true
---
# 多租户处理规范
⚠️ **极其重要**:所有业务数据查询必须包含 `tenantId` 条件!
## 核心原则
### 1. 数据库查询
- **必须**:所有业务表查询必须包含 `tenantId` 条件
- 超级租户(`isSuper = 1`)可以访问所有租户数据
```typescript
// ✅ 正确示例
const users = await this.prisma.user.findMany({
where: {
tenantId,
validState: 1,
},
});
// ❌ 错误示例 - 缺少 tenantId
const users = await this.prisma.user.findMany({
where: {
validState: 1,
},
});
```
### 2. 获取租户ID
在控制器中使用 `@CurrentTenantId()` 装饰器:
```typescript
@Get()
async findAll(@CurrentTenantId() tenantId: number) {
return this.service.findAll(tenantId);
}
```
### 3. 创建数据
创建数据时自动设置 `tenantId`
```typescript
async create(createDto: CreateDto, tenantId: number) {
return this.prisma.model.create({
data: {
...createDto,
tenantId,
},
});
}
```
### 4. 更新/删除数据
更新或删除前验证数据属于当前租户:
```typescript
async update(id: number, updateDto: UpdateDto, tenantId: number) {
// 先验证数据属于当前租户
const existing = await this.prisma.model.findFirst({
where: { id, tenantId },
});
if (!existing) {
throw new NotFoundException('数据不存在或不属于当前租户');
}
return this.prisma.model.update({
where: { id },
data: updateDto,
});
}
```
## 数据库表设计
所有业务表必须包含:
- `tenantId`: Int - 租户ID必填
- `creator`: Int? - 创建人ID
- `modifier`: Int? - 修改人ID
- `createTime`: DateTime @default(now())
- `modifyTime`: DateTime @updatedAt
- `validState`: Int @default(1) - 有效状态1-有效2-失效)
## 审查清单
在代码审查时,重点检查:
- [ ] 所有 `findMany`、`findFirst`、`findUnique` 包含 `tenantId` 条件
- [ ] 创建操作设置了 `tenantId`
- [ ] 更新/删除操作验证了 `tenantId`
- [ ] 新的 Prisma 模型包含了 `tenantId` 字段