---
url: /docs/api/procedures.md
---
# 查询与变更接口

## 两类操作

查询使用 `.query()`，不产生业务写入；变更使用 `.mutation()`，用于创建、修改和删除。输入使用 Zod 定义，私有操作使用 `protectedProcedure`。

以下是独立示例，演示接口结构；若加入项目，还要注册路由。

```ts
import { z } from "zod";
import { protectedProcedure, router } from "../lib/trpc";

export const profileRouter = router({
  summary: protectedProcedure.query(({ ctx }) => ({
    id: ctx.user.id,
    name: ctx.user.name,
  })),
  validateName: protectedProcedure
    .input(z.object({ name: z.string().trim().min(1).max(100) }))
    .mutation(({ input }) => ({ name: input.name })),
});
```

`validateName` 仅返回校验后的输入，不保存资料。真实写入还需数据模型、权限校验及相应测试。

## 注册与调用

在 `apps/api/lib/app.ts` 的 `appRouter` 中加入新路由，客户端类型随之更新。工作台使用统一 tRPC 客户端；把查询键、请求及失效逻辑放在 `apps/app/lib/queries/`。

## 安全与幂等

登录不代表可以读取任意用户或组织资源。查询条件需要同时包含当前身份范围；写入必须重新验证。涉及积分、支付和可重试任务时，使用唯一业务事件键与数据库事务，避免重复扣费。

限制输入大小及返回字段，只返回调用方需要的数据。列表接口设数量上限并选择明确排序，避免无界查询。

## 验证

至少检查合法输入、非法输入、未登录、越权及重复请求。纯格式展示改动无需新增接口测试；新增数据边界应使用真实数据库语义测试，见 [测试与排查](../testing.md)。
