Files
cozsweet-frontend-nextjs/.agents/skills/sync-backend-api/SKILL.md
T

8.3 KiB
Raw Blame History

name, description
name description
sync-backend-api Sync this Next.js frontend with backend API documentation

sync-backend-api

根据后端文档同步当前 Next.js / TypeScript 项目的前端代码。

使用场景

当后端 API 新增、删除、字段结构调整、响应语义变化时,使用本 skill 更新:

  • 网络层
  • schema / DTO
  • repository
  • storage
  • XState store
  • UI 调用逻辑
  • mock 数据
  • 单元测试

当前项目结构

层级 路径 说明
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 测试

支持模块

模块 API 路径 主要文件
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

后端文档来源

优先读取用户指定的文档或文件片段。

常见文档:

  • FRONTEND_VIP_CREDIT_API.md
  • PAYWALL_API.md
  • docs-change.md
  • docs/backend/openapi.json

如果用户没有指定文档,先搜索相关 API 路径或模块名,再选择最相关文档。

更新流程

1. 检查工作区

开始前必须执行:

git status --short

如果存在无关未提交改动:

  • 不要回退。
  • 不要覆盖。
  • 修改前先确认本次任务需要触碰的文件。
  • 提交时只暂存本次任务相关文件。

2. 阅读后端文档

确认:

  • API method
  • API path
  • 请求参数
  • 响应结构
  • 字段是否可空
  • 旧字段是否废弃
  • 是否需要认证 token
  • 是否影响本地持久化
  • 是否影响状态机或 UI

如果用户明确要求“不兼容旧字段,彻底更新”,不要保留旧字段 fallback。

否则 schema 应尽量防御性解析,例如:

z.string().nullable().transform((v) => v ?? "").default("")

项目已有通用 helper

src/data/schemas/nullable-defaults.ts

3. 更新 API Path

新增或修改:

src/data/services/api/api_path.ts

示例:

static readonly userEntitlements = `${ApiPath._user}/entitlements`;

4. 更新 Schema

在对应模块下新增或修改:

src/data/schemas/<module>/*.ts

要求:

  • 使用 Zod。
  • 输出类型用 z.output<typeof Schema>
  • 输入类型用 z.input<typeof Schema>
  • 对后端可能返回 null 的字段做防御性处理。
  • 不要在 schema 中写 UI 逻辑。

示例:

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

在对应模块下新增或修改:

src/data/dto/<module>/*.ts

DTO 统一模式:

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

修改:

src/data/services/api/<module>_api.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

修改:

src/data/repositories/interfaces/i<module>_repository.ts
src/data/repositories/<module>_repository.ts

Repository 返回项目通用 Result<T>

async getXxx(): Promise<Result<XxxResponse>> {
  return Result.wrap(() => this.api.getXxx());
}

Repository 可以做轻量编排,例如:

  • request DTO 构造
  • 多接口组合
  • 本地 storage 同步
  • local model 与 DTO 转换

不要把 React / UI 逻辑放进 repository。

8. 更新 Storage

如果接口影响本地持久化,修改:

src/data/storage/storage_keys.ts
src/data/storage/<module>/*

原则:

  • 只持久化业务需要的最小字段。
  • 不要为了接口响应完整而盲目存完整 payload。
  • storage 使用 SpAsyncUtil 和 Zod schema 校验。

示例:

getEntitlementSnapshot(): Promise<Result<UserEntitlementSnapshotData | null>> {
  return SpAsyncUtil.getJson(
    StorageKeys.userEntitlementSnapshot,
    UserEntitlementSnapshotSchema,
  );
}

9. 更新 Store / 状态机

如果接口影响状态流,修改:

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

只有在接口变更影响展示或用户明确要求时,才修改:

src/app/**

原则:

  • UI 只负责渲染和派发事件。
  • 不在页面组件里直接写复杂业务编排。
  • 全局监听逻辑优先放到 stores/*/*-sync.tsx

11. 更新桶文件

如果新增 schema / DTO / component,更新对应 index.ts

src/data/schemas/<module>/index.ts
src/data/dto/<module>/index.ts
src/app/**/components/index.ts

如果项目使用 barrelsby 生成,不要手动破坏现有导出格式。

12. 更新 Mock 数据

如果新增或调整数据结构,按一个结构一个文件的原则放到:

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 编排测试(如已有测试基础)

常见位置:

src/data/dto/<module>/__tests__/*.test.ts
src/stores/<module>/__tests__/*.test.ts

14. 验证

至少运行:

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. 运行验证。