mcpField
B
backend-patterns

backend-patterns

github.com/kensaurus开发938 次安装2 周前更新
代码仓库

关于 backend-patterns

backend-patterns 是面向后端开发的技能,帮助根据现有架构选择和实现合适的服务端模式。内容涵盖请求处理、数据库、缓存、后台任务及分布式系统,并强调验证与安全。

主要功能

  1. 01先检查现有架构与实现
  2. 02提供 Server Actions 和 tRPC 模式
  3. 03涵盖数据库、缓存与后台任务
  4. 04介绍限流和分布式系统模式
  5. 05验证认证、输入、错误与幂等性

适用场景

  1. 01为 Next.js Server Actions 设计安全的写入流程
  2. 02为订单等副作用设置可重试的后台任务
  3. 03在数据库操作中处理并发更新或软删除
  4. 04为敏感接口增加限流与输入验证

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kensaurus/skills --skill backend-patterns

安装后在 Claude Code 中输入/backend-patterns确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
architecture-patterns.md
data-and-jobs.md
request-patterns.md

详细介绍

后端模式技能

自由度:混合。 应用哪种模式[高自由度]; 现有架构探查和验证清单[低自由度 — 按原样执行]。

推理方式

  1. 观察 — 现有的 server/api/actions、ORM、队列、缓存
  2. 解读 — 缺少模式、模式重复,还是层级错误
  3. 分类 — 复用 / 添加队列 / 添加缓存 / 添加速率限制 / 边缘函数
  4. 确定严重程度 — 未经身份验证的变更优先级高于缺少缓存

示例

观察: createOrder 会在请求中同步发送邮件;没有 Inngest/队列;结账 p95 为 4s。 解读: 确认邮件属于响应后的工作,而非请求路径的一部分。 分类: 使用 after() 或 order/created 任务;保持写入操作的事务性。 验证: 订单行成功提交;邮件/库存处理在响应后运行;重试不会导致重复扣款。

报告前自我审查

  • 先检查现有实现 — 添加第二种模式前,已搜索 server/api/actions
  • 身份验证 + 验证 — 每个变更操作都会检查会话并使用 Zod
  • 幂等 — 新路径上的重试不会重复应用操作
  • 明确负责人 — 选择哪种架构 → audit-backend-architecture

使用现代模式和最佳实践,设计可扩展、易维护的后端架构。

代码示例主要使用 Next.js App Router + Supabase/Prisma。这些模式与技术栈无关——请根据检测到的生态系统调整 ORM、客户端库和部署目标。

先检查现有实现 [低自由度 — 按原样执行]

实现任何后端模式之前,请先确认:

  1. 检查现有架构:
ls -la src/server/ src/api/ app/api/ supabase/functions/ 2>/dev/null
cat package.json | grep -i "prisma\|drizzle\|supabase\|trpc"
  1. 检查现有模式:
rg "createTRPCRouter|publicProcedure" --type ts -l
rg "'use server'" --type ts -l
ls -la supabase/migrations/*.sql 2>/dev/null | tail -5
  1. 检查数据库设置:
cat prisma/schema.prisma 2>/dev/null | head -50
cat supabase/config.toml 2>/dev/null

原因: 后端更改影响范围广。请先了解现有架构。

Server Actions(Next.js 16+) [高自由度]

Next.js 16:默认使用 Turbopack;使用 'use cache' + cacheComponents;设置 reactCompiler: true;middleware.ts → proxy.ts(同时 grep 两者)。即时导航 → enhance-web-instant-nav。

  • 每个 action 内的顺序:身份验证检查 → Zod safeParse → 执行 → 映射已知错误(Prisma P2002)→ 通用失败消息。
  • 返回 ActionResult<T>:{ success: true, data } 或 { success: false, error, fieldErrors? };绝不向客户端抛出异常。
  • 成功写入后调用 revalidatePath。
  • 响应后的工作(确认邮件、库存、通知)应放在来自 next/server 的 after() 中,确保写入操作具有事务性。
'use server'
import { after } from 'next/server'

export async function createOrder(formData: FormData) {
  const order = await db.order.create({ data: { /* ... */ } })
  after(async () => {                      // runs after the response is sent
    await sendOrderConfirmation(order.id)
    await updateInventory(order.items)
  })
  revalidatePath('/orders')
  return { success: true, data: order }
}

完整的 createUser action 和 after() 示例:references/request-patterns.md §Server Actions。

tRPC 设置 [高自由度]

  • 任何人都可执行的读取操作使用 publicProcedure;任何使用 ctx.session 的操作都使用 protectedProcedure。
  • 每个 procedure 都有 Zod .input();变更操作从会话中设置 createdById,而非使用输入值。
  • 列表端点使用游标分页:获取 limit + 1 条记录,将多出的一条移出并作为 nextCursor。

完整的 usersRouter(getById、create、游标分页列表):references/request-patterns.md §tRPC router 定义。

Supabase Edge Functions [高自由度]

  • 使用 Deno.serve;首先使用 CORS 标头响应 OPTIONS。
  • 解析 JSON 前,先根据原始请求体验证 webhook 签名;不匹配时返回 401。
  • 来自 SUPABASE_SERVICE_ROLE_KEY 的管理客户端会绕过 RLS;只能在函数内部使用。
  • 捕获所有异常;在服务端记录日志,并返回带有 CORS 标头的通用 500 JSON 响应体。

完整的 process-webhook 函数:references/request-patterns.md §Supabase Edge Function。

数据库模式 [HIGH freedom]

  • 乐观锁 — 使用 version INT 列;执行 UPDATE ... WHERE id = $1 AND version = $2,并将影响 0 行视为发生了并发更新。
  • 软删除 — 使用可空的 deletedAt 并为其建立索引;每次读取都筛选 deletedAt: null;删除时设置时间戳。
  • 审计日志 — 通过使用 TG_OP、row_to_json 和 auth.uid() 的 SECURITY DEFINER 触发器填充 audit_logs(table_name, record_id, action, old_data, new_data, user_id)。
UPDATE orders SET status = 'shipped', version = version + 1
WHERE id = $1 AND version = $2;   -- 0 rows → concurrent update, retry or surface conflict

Prisma 软删除模型和完整审计触发器:references/data-and-jobs.md §Soft deletes、§Audit logging。

缓存模式 [HIGH freedom]

  • Next.js:使用 fetch(url, { next: { revalidate, tags } });按需调用 revalidateTag;在数据库查询外层使用带标签的 unstable_cache。
  • Redis(Upstash):使用一个 getCachedData(key, fetcher, ttl) 助手,采用 cache-aside 模式;按实体和 ID 设置键(user:${id})。
  • 根据可容忍的数据陈旧程度选择 TTL,并始终添加标签,以便写入操作能够使缓存失效。
const getCachedUser = unstable_cache(
  async (id: string) => db.user.findUnique({ where: { id } }),
  ['user'],
  { revalidate: 3600, tags: ['users'] }
)

Next.js 缓存调用和 Redis 助手:references/data-and-jobs.md §Next.js cache、§Redis caching。

后台任务 [HIGH freedom]

  • 默认使用 Inngest。inngest.createFunction({ id }, { event }, async ({ event, step }) => ...);将每个副作用放在单独的 step.run 中,这样重试时会从中断处继续,而不是重新开始。
  • 写入提交后,通过 Server Action 调用 inngest.send({ name: 'order/created', data }) 触发任务。
  • 提前退出(缺货)应使用 step.run 并执行 return { status: 'cancelled' },而不是抛出异常。
export const processOrder = inngest.createFunction(
  { id: 'process-order' }, { event: 'order/created' },
  async ({ event, step }) => {
    const payment = await step.run('charge-payment', () => chargeCustomer(event.data.paymentMethod))
    await step.run('send-confirmation', () => sendOrderConfirmation(event.data.orderId))
    return { status: 'completed', paymentId: payment.id }
  }
)

完整的 Inngest 函数和 Trigger.dev 定时任务替代方案:references/data-and-jobs.md §Background jobs、§Alternatives。

速率限制 [HIGH freedom]

  • 使用 @upstash/ratelimit,通过 Redis.fromEnv() 配置 Ratelimit.slidingWindow(10, '10 s')。
  • 使用用户 ID(匿名用户则使用 IP)作为键;在 !success 时,返回 Too many requests,并根据 reset 返回以秒为单位的 retryAfter。

完整的 rateLimitedAction:references/request-patterns.md §Rate limiting。

架构模式(分布式系统) [HIGH freedom]

Gateway、BFF、bulkhead、circuit breaker、outbox+CDC、saga、hexagonal、ACL 和 strangler-fig → references/architecture-patterns.md。根据拓扑选择模式(单体架构无需服务网格;只有读写出现分化时才采用 CQRS)。超时/重试/幂等性 → audit-resilience;结构性缺口报告 → audit-backend-architecture。

验证 [LOW freedom — 不要跳过]

实现后端模式后:

  1. 错误处理 → 捕获并记录所有错误,返回安全的响应
  2. 身份验证检查 → 每次变更操作都验证身份
  3. 输入验证 → 对所有输入使用 Zod schema
  4. 速率限制 → 保护敏感端点
  5. 幂等性 → 关键操作能够处理重试
  6. 日志记录 → 记录结构化日志,不包含敏感数据
  7. 测试 → 为业务逻辑编写单元测试,为 API 编写集成测试

评论

支持 Markdown