refactor(sync-backend-api): update documentation for syncing frontend with backend API
This commit is contained in:
@@ -1,110 +1,378 @@
|
|||||||
---
|
---
|
||||||
name: sync-backend-api
|
name: sync-backend-api
|
||||||
description: Sync frontend code with backend OpenAPI specification
|
description: Sync this Next.js frontend with backend API documentation
|
||||||
---
|
---
|
||||||
|
|
||||||
# sync-backend-api
|
# sync-backend-api
|
||||||
|
|
||||||
根据用户指定的模块或接口,根据后端文档更新前端代码(服务层、仓库层、UI层)。
|
根据后端文档同步当前 Next.js / TypeScript 项目的前端代码。
|
||||||
|
|
||||||
## 使用场景
|
## 使用场景
|
||||||
|
|
||||||
当后端 API 发生变更时(如新增接口、修改参数),使用此 skill 同步更新前端代码。
|
当后端 API 新增、删除、字段结构调整、响应语义变化时,使用本 skill 更新:
|
||||||
|
|
||||||
## 可用模块
|
- 网络层
|
||||||
|
- schema / DTO
|
||||||
|
- repository
|
||||||
|
- storage
|
||||||
|
- XState store
|
||||||
|
- UI 调用逻辑
|
||||||
|
- mock 数据
|
||||||
|
- 单元测试
|
||||||
|
|
||||||
| 模块 | 说明 | API 路径 |
|
## 当前项目结构
|
||||||
| -------- | ---------- | -------------- |
|
|
||||||
| `auth` | 认证模块 | /api/auth/\* |
|
|
||||||
| `chat` | 聊天模块 | /api/chat/\* |
|
|
||||||
| `user` | 用户模块 | /api/user/\* |
|
|
||||||
| `verify` | 验证码模块 | /api/verify/\* |
|
|
||||||
|
|
||||||
## 使用方式
|
| 层级 | 路径 | 说明 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| API Path | `src/data/services/api/api_path.ts` | 统一维护接口路径 |
|
||||||
|
| API Service | `src/data/services/api/*_api.ts` | 调用 `httpClient` 并解析响应 |
|
||||||
|
| Schema | `src/data/schemas/<module>/*.ts` | Zod schema,负责防御性解析 |
|
||||||
|
| DTO | `src/data/dto/<module>/*.ts` | DTO class,封装 `fromJson/toJson` |
|
||||||
|
| Repository Interface | `src/data/repositories/interfaces/i*_repository.ts` | 仓库接口 |
|
||||||
|
| Repository | `src/data/repositories/*_repository.ts` | 业务仓库实现 |
|
||||||
|
| Storage | `src/data/storage/*` | 本地持久化 |
|
||||||
|
| Store | `src/stores/<module>/*` | XState 状态机、actors、helpers、sync |
|
||||||
|
| UI | `src/app/**` | Next.js app router UI |
|
||||||
|
| Mock | `src/data/mock/<module>/**` | 模拟请求 / 响应数据 |
|
||||||
|
| Tests | `**/__tests__/*.test.ts` | DTO、helper、machine transition 测试 |
|
||||||
|
|
||||||
### 按模块更新(可多选,用逗号分隔)
|
## 支持模块
|
||||||
|
|
||||||
```bash
|
| 模块 | API 路径 | 主要文件 |
|
||||||
根据后端文档更新 auth,chat 模块
|
| --- | --- | --- |
|
||||||
```
|
| `auth` | `/api/auth/*`, `/api/verify/*` | `auth_api.ts`, `auth_repository.ts`, `src/stores/auth/*` |
|
||||||
|
| `chat` | `/api/chat/*` | `chat_api.ts`, `chat_repository.ts`, `src/stores/chat/*` |
|
||||||
|
| `user` | `/api/user/*` | `user_api.ts`, `user_repository.ts`, `src/stores/user/*` |
|
||||||
|
| `payment` | `/api/payment/*` | `payment_api.ts`, `payment_repository.ts`, `src/stores/payment/*` |
|
||||||
|
| `metrics` | `/api/metrics/*` | `metrics_api.ts`, `metrics_repository.ts` |
|
||||||
|
|
||||||
### 按接口更新(可多选,用逗号分隔)
|
## 后端文档来源
|
||||||
|
|
||||||
```bash
|
优先读取用户指定的文档或文件片段。
|
||||||
根据后端文档更新接口 /api/auth/sendCode
|
|
||||||
根据后端文档更新接口 /api/chat/send
|
|
||||||
根据后端文档更新接口 /api/auth/register,/api/user/profile
|
|
||||||
```
|
|
||||||
|
|
||||||
### 混合同步
|
常见文档:
|
||||||
|
|
||||||
```bash
|
- `FRONTEND_VIP_CREDIT_API.md`
|
||||||
根据后端文档更新 auth 模块和接口 /api/chat/send
|
- `PAYWALL_API.md`
|
||||||
```
|
- `docs-change.md`
|
||||||
|
- `docs/backend/openapi.json`
|
||||||
|
|
||||||
## OpenAPI 文档路径
|
如果用户没有指定文档,先搜索相关 API 路径或模块名,再选择最相关文档。
|
||||||
|
|
||||||
- 测试环境: `docs/backend/openapi.json`
|
|
||||||
|
|
||||||
## 更新流程
|
## 更新流程
|
||||||
|
|
||||||
### 1. 读取 OpenAPI 文档
|
### 1. 检查工作区
|
||||||
|
|
||||||
读取 `docs/backend/openapi.json`,根据用户指定的模块筛选接口。
|
开始前必须执行:
|
||||||
|
|
||||||
### 2. 分析接口变更
|
```bash
|
||||||
|
git status --short
|
||||||
- 新增接口:创建对应的模型、API 方法
|
|
||||||
- 修改接口:更新现有模型字段
|
|
||||||
- 删除接口:移除不再使用的代码
|
|
||||||
|
|
||||||
### 3. 更新数据模型 (lib/data/models/)
|
|
||||||
|
|
||||||
- 根据 schema 创建/更新 freezed 模型
|
|
||||||
|
|
||||||
### 4. 更新 API 客户端 (lib/data/services/)
|
|
||||||
|
|
||||||
- 更新 `*_api_client.dart` 中的接口定义
|
|
||||||
- 更新 `api_path.dart` 中的路径常量(如有新增)
|
|
||||||
- 运行 build_runner 生成 `*_api_client.g.dart`
|
|
||||||
|
|
||||||
### 5. 更新仓储层 (lib/data/repositories/)
|
|
||||||
|
|
||||||
- 更新 `*_repository.dart` 接口定义
|
|
||||||
- 更新 `*_repository_impl.dart` 实现
|
|
||||||
|
|
||||||
### 6. 更新 UI 层
|
|
||||||
|
|
||||||
- 根据功能模块更新对应 BLoC/ViewModel
|
|
||||||
- 更新 UI 调用逻辑
|
|
||||||
|
|
||||||
### 7. 生成代码
|
|
||||||
|
|
||||||
运行 `dart run build_runner build --delete-conflicting-outputs`
|
|
||||||
|
|
||||||
## 示例
|
|
||||||
|
|
||||||
**按模块更新**:
|
|
||||||
|
|
||||||
```
|
|
||||||
根据后端文档更新 auth 模块
|
|
||||||
根据后端文档更新 auth,user,verify 模块
|
|
||||||
```
|
```
|
||||||
|
|
||||||
**按接口更新**:
|
如果存在无关未提交改动:
|
||||||
|
|
||||||
```
|
- 不要回退。
|
||||||
根据后端文档更新接口 /api/auth/sendCode
|
- 不要覆盖。
|
||||||
根据后端文档更新接口 /api/chat/send
|
- 修改前先确认本次任务需要触碰的文件。
|
||||||
根据后端文档更新接口 /api/auth/register,/api/user/profile
|
- 提交时只暂存本次任务相关文件。
|
||||||
|
|
||||||
|
### 2. 阅读后端文档
|
||||||
|
|
||||||
|
确认:
|
||||||
|
|
||||||
|
- API method
|
||||||
|
- API path
|
||||||
|
- 请求参数
|
||||||
|
- 响应结构
|
||||||
|
- 字段是否可空
|
||||||
|
- 旧字段是否废弃
|
||||||
|
- 是否需要认证 token
|
||||||
|
- 是否影响本地持久化
|
||||||
|
- 是否影响状态机或 UI
|
||||||
|
|
||||||
|
如果用户明确要求“不兼容旧字段,彻底更新”,不要保留旧字段 fallback。
|
||||||
|
|
||||||
|
否则 schema 应尽量防御性解析,例如:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
z.string().nullable().transform((v) => v ?? "").default("")
|
||||||
```
|
```
|
||||||
|
|
||||||
**混合同步**:
|
项目已有通用 helper:
|
||||||
|
|
||||||
```
|
```ts
|
||||||
根据后端文档更新 auth 模块和接口 /api/chat/send
|
src/data/schemas/nullable-defaults.ts
|
||||||
```
|
```
|
||||||
|
|
||||||
## 注意事项
|
### 3. 更新 API Path
|
||||||
|
|
||||||
|
新增或修改:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
src/data/services/api/api_path.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
static readonly userEntitlements = `${ApiPath._user}/entitlements`;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. 更新 Schema
|
||||||
|
|
||||||
|
在对应模块下新增或修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/schemas/<module>/*.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
要求:
|
||||||
|
|
||||||
|
- 使用 Zod。
|
||||||
|
- 输出类型用 `z.output<typeof Schema>`。
|
||||||
|
- 输入类型用 `z.input<typeof Schema>`。
|
||||||
|
- 对后端可能返回 `null` 的字段做防御性处理。
|
||||||
|
- 不要在 schema 中写 UI 逻辑。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export const XxxResponseSchema = z.object({
|
||||||
|
id: z.string(),
|
||||||
|
count: z.number().default(0),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type XxxResponseInput = z.input<typeof XxxResponseSchema>;
|
||||||
|
export type XxxResponseData = z.output<typeof XxxResponseSchema>;
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. 更新 DTO
|
||||||
|
|
||||||
|
在对应模块下新增或修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/dto/<module>/*.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
DTO 统一模式:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
export class XxxResponse {
|
||||||
|
declare readonly id: string;
|
||||||
|
|
||||||
|
private constructor(input: XxxResponseInput) {
|
||||||
|
const data = XxxResponseSchema.parse(input);
|
||||||
|
Object.assign(this, data);
|
||||||
|
Object.freeze(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
static from(input: XxxResponseInput): XxxResponse {
|
||||||
|
return new XxxResponse(input);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromJson(json: unknown): XxxResponse {
|
||||||
|
return XxxResponse.from(json as XxxResponseInput);
|
||||||
|
}
|
||||||
|
|
||||||
|
toJson(): XxxResponseData {
|
||||||
|
return XxxResponseSchema.parse(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 更新 API Service
|
||||||
|
|
||||||
|
修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/services/api/<module>_api.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
统一调用方式:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const env = await httpClient<ApiEnvelope<unknown>>(ApiPath.xxx, {
|
||||||
|
method: "POST",
|
||||||
|
body: request.toJson(),
|
||||||
|
});
|
||||||
|
return XxxResponse.fromJson(unwrap(env) as Record<string, unknown>);
|
||||||
|
```
|
||||||
|
|
||||||
|
注意:
|
||||||
|
|
||||||
|
- 不要直接返回 `unknown`。
|
||||||
|
- 不要在 API 层处理 UI 行为。
|
||||||
|
- multipart 仍使用 `FormData`。
|
||||||
|
|
||||||
|
### 7. 更新 Repository
|
||||||
|
|
||||||
|
修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/repositories/interfaces/i<module>_repository.ts
|
||||||
|
src/data/repositories/<module>_repository.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
Repository 返回项目通用 `Result<T>`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
async getXxx(): Promise<Result<XxxResponse>> {
|
||||||
|
return Result.wrap(() => this.api.getXxx());
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Repository 可以做轻量编排,例如:
|
||||||
|
|
||||||
|
- request DTO 构造
|
||||||
|
- 多接口组合
|
||||||
|
- 本地 storage 同步
|
||||||
|
- local model 与 DTO 转换
|
||||||
|
|
||||||
|
不要把 React / UI 逻辑放进 repository。
|
||||||
|
|
||||||
|
### 8. 更新 Storage
|
||||||
|
|
||||||
|
如果接口影响本地持久化,修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/storage/storage_keys.ts
|
||||||
|
src/data/storage/<module>/*
|
||||||
|
```
|
||||||
|
|
||||||
|
原则:
|
||||||
|
|
||||||
|
- 只持久化业务需要的最小字段。
|
||||||
|
- 不要为了接口响应完整而盲目存完整 payload。
|
||||||
|
- storage 使用 `SpAsyncUtil` 和 Zod schema 校验。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
getEntitlementSnapshot(): Promise<Result<UserEntitlementSnapshotData | null>> {
|
||||||
|
return SpAsyncUtil.getJson(
|
||||||
|
StorageKeys.userEntitlementSnapshot,
|
||||||
|
UserEntitlementSnapshotSchema,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 9. 更新 Store / 状态机
|
||||||
|
|
||||||
|
如果接口影响状态流,修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/stores/<module>/<module>-state.ts
|
||||||
|
src/stores/<module>/<module>-events.ts
|
||||||
|
src/stores/<module>/<module>-machine.ts
|
||||||
|
src/stores/<module>/<module>-machine.actors.ts
|
||||||
|
src/stores/<module>/<module>-machine.helpers.ts
|
||||||
|
src/stores/<module>/<module>-context.tsx
|
||||||
|
src/stores/<module>/*-sync.tsx
|
||||||
|
```
|
||||||
|
|
||||||
|
项目约定:
|
||||||
|
|
||||||
|
- API 调用放在 `actors.ts`。
|
||||||
|
- 纯函数转换放在 `helpers.ts`。
|
||||||
|
- 跨 store 监听放在 `*-sync.tsx`。
|
||||||
|
- 页面组件不承担全局监听职责。
|
||||||
|
- 状态机事件应表达业务事实,而不是 UI 操作细节。
|
||||||
|
|
||||||
|
### 10. 更新 UI
|
||||||
|
|
||||||
|
只有在接口变更影响展示或用户明确要求时,才修改:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/app/**
|
||||||
|
```
|
||||||
|
|
||||||
|
原则:
|
||||||
|
|
||||||
|
- UI 只负责渲染和派发事件。
|
||||||
|
- 不在页面组件里直接写复杂业务编排。
|
||||||
|
- 全局监听逻辑优先放到 `stores/*/*-sync.tsx`。
|
||||||
|
|
||||||
|
### 11. 更新桶文件
|
||||||
|
|
||||||
|
如果新增 schema / DTO / component,更新对应 `index.ts`:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/schemas/<module>/index.ts
|
||||||
|
src/data/dto/<module>/index.ts
|
||||||
|
src/app/**/components/index.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
如果项目使用 barrelsby 生成,不要手动破坏现有导出格式。
|
||||||
|
|
||||||
|
### 12. 更新 Mock 数据
|
||||||
|
|
||||||
|
如果新增或调整数据结构,按一个结构一个文件的原则放到:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/mock/<module>/requests
|
||||||
|
src/data/mock/<module>/responses
|
||||||
|
src/data/mock/<module>/websocket-events
|
||||||
|
```
|
||||||
|
|
||||||
|
不要把多个结构塞进一个大 JSON。
|
||||||
|
|
||||||
|
### 13. 更新测试
|
||||||
|
|
||||||
|
优先补充:
|
||||||
|
|
||||||
|
- DTO / schema parse 测试
|
||||||
|
- helper 纯函数测试
|
||||||
|
- XState transition 测试
|
||||||
|
- repository 编排测试(如已有测试基础)
|
||||||
|
|
||||||
|
常见位置:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/data/dto/<module>/__tests__/*.test.ts
|
||||||
|
src/stores/<module>/__tests__/*.test.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
### 14. 验证
|
||||||
|
|
||||||
|
至少运行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pnpm exec tsc --noEmit
|
||||||
|
pnpm exec eslint <changed files>
|
||||||
|
pnpm exec vitest run <related tests>
|
||||||
|
```
|
||||||
|
|
||||||
|
如果没有相关测试,需要说明未覆盖的风险。
|
||||||
|
|
||||||
|
## 常见任务模板
|
||||||
|
|
||||||
|
### 新增接口
|
||||||
|
|
||||||
|
1. 文档确认 path / method / payload。
|
||||||
|
2. `api_path.ts` 新增路径。
|
||||||
|
3. 新增 schema。
|
||||||
|
4. 新增 DTO。
|
||||||
|
5. API service 新增方法。
|
||||||
|
6. repository interface + implementation 新增方法。
|
||||||
|
7. 如需要,接入 store actor / event。
|
||||||
|
8. 补 mock 和测试。
|
||||||
|
9. 运行验证。
|
||||||
|
|
||||||
|
### 修改响应字段
|
||||||
|
|
||||||
|
1. 更新 schema。
|
||||||
|
2. 更新 DTO declare 字段和 `toJson`。
|
||||||
|
3. 更新 mapper/helper。
|
||||||
|
4. 更新 UI 或状态机依赖字段。
|
||||||
|
5. 更新 mock 和测试。
|
||||||
|
6. 运行验证。
|
||||||
|
|
||||||
|
### 删除旧接口
|
||||||
|
|
||||||
|
1. 搜索所有引用。
|
||||||
|
2. 删除 API path / API method / repository method。
|
||||||
|
3. 删除 DTO/schema/mock/test。
|
||||||
|
4. 更新状态机和 UI 调用。
|
||||||
|
5. 运行 `rg` 确认无残留引用。
|
||||||
|
6. 运行验证。
|
||||||
|
|
||||||
1. **测试覆盖**: 更新后运行相关测试确保正常
|
|
||||||
|
|||||||
Reference in New Issue
Block a user