backend-patterns について
backend-patternsは、既存の構成を踏まえてサーバー側の設計パターンを選び実装するためのスキルです。リクエスト処理、データベース、キャッシュ、バックグラウンドジョブ、分散システムを扱い、検証と安全性を重視します。
主な機能
- 01既存アーキテクチャと実装の事前確認
- 02Server ActionsとtRPCのパターン
- 03データベース、キャッシュ、バックグラウンドジョブ
- 04レート制限と分散システムのパターン
- 05認証、入力、エラー、冪等性の検証
活用シーン
- 01Next.js Server Actionsの安全な書き込みフロー設計
- 02注文処理などの再試行可能な副作用のジョブ化
- 03データベースでの同時更新や論理削除への対応
- 04重要なエンドポイントへのレート制限と入力検証の追加
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kensaurus/ skills --skill backend-patternsインストール後、Claude Code で/backend-patternsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/architecture-patterns.mddata-and-jobs.mdrequest-patterns.md詳細
バックエンドパターンのスキル
自由度:混在。 適用するパターンの選択は[自由度:高]。 既存アーキテクチャの調査と検証リストは[自由度:低 — 必ずそのまま実行]です。
考え方
- 観察 — 既存のサーバー/API/アクション、ORM、キュー、キャッシュを確認します
- 解釈 — パターンが不足しているのか、重複しているのか、レイヤーが間違っているのかを判断します
- 分類 — 再利用/キューの追加/キャッシュの追加/レート制限の追加/エッジ関数
- 重大度 — 未認証の変更は、キャッシュ不足よりも優先度が高くなります
作業例
観察:
createOrderがメールをインラインで送信しています。Inngest/キューはなく、チェックアウトの p95 は 4 秒です。 解釈: 確認処理はリクエスト後の作業であり、リクエスト処理経路には含めません。 分類:after()またはorder/createdジョブを使います。書き込みはトランザクション内に保ちます。 検証: 注文の行がコミットされること、メール/在庫処理がレスポンス後に実行されること、再試行で二重請求が発生しないことを確認します。
報告前の自己批評
- 既存のものを優先 — 2つ目のパターンを追加する前に、server/api/actions を検索しました
- 認証 + 検証 — すべての変更処理でセッションと Zod を確認します
- 冪等性 — 新しい経路で再試行しても、処理が二重に適用されません
- 適切な担当者 — どのアーキテクチャを選ぶか →
audit-backend-architecture
最新のパターンとベストプラクティスを使って、スケーラブルで保守しやすいバックエンドアーキテクチャを設計します。
コード例は Next.js App Router + Supabase/Prisma を中心にしています。パターンは スタックに依存しないため、検出されたエコシステムに合わせて ORM、クライアントライブラリ、デプロイ先を 調整してください。
まず既存のものを確認する [自由度:低 — 必ずそのまま実行]
バックエンドパターンを実装する前に、必ず次の項目を確認してください。
- 既存のアーキテクチャを確認する:
ls -la src/server/ src/api/ app/api/ supabase/functions/ 2>/dev/null
cat package.json | grep -i "prisma\|drizzle\|supabase\|trpc"
- 既存のパターンを確認する:
rg "createTRPCRouter|publicProcedure" --type ts -l
rg "'use server'" --type ts -l
ls -la supabase/migrations/*.sql 2>/dev/null | tail -5
- データベースの設定を確認する:
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 を使用します。
- すべてのアクション内の順序:認証チェック → Zod
safeParse→ 実行 → 既知のエラー(PrismaP2002)をマッピング → 汎用エラーメッセージ。 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 アクションと after() の例:references/request-patterns.md §Server Actions。
tRPC の設定 [自由度:高]
- 誰でも実行できる読み取りには
publicProcedureを使い、ctx.sessionを使う処理にはprotectedProcedureを使います。 - すべてのプロシージャに Zod
.input()を設定します。ミューテーションでは入力ではなく、セッションからcreatedByIdを設定します。 - リストエンドポイントはカーソルでページネーションします。
limit + 1件を取得し、余分な行を取り除いてnextCursorとします。
完全な usersRouter(getById、create、カーソルページネーション付きの list):references/request-patterns.md §tRPC router definition。
Supabase Edge Functions [自由度:高]
Deno.serveを使い、まず CORS ヘッダーを付けてOPTIONSに応答します。- JSON の解析前に、生のボディに対する Webhook 署名を検証します。一致しない場合は
401を返します。 SUPABASE_SERVICE_ROLE_KEYから作成した管理者クライアントは RLS をバイパスします。関数内でのみ使用してください。- すべてのエラーを捕捉し、サーバー側でログに記録して、CORS ヘッダー付きの汎用
500JSON ボディを返します。
完全な process-webhook 関数:references/request-patterns.md §Supabase Edge Function。
データベースパターン [HIGH freedom]
- 楽観的ロック —
version INT列を使用します。UPDATE ... WHERE id = $1 AND version = $2を実行し、更新された行が 0 件の場合は、同時更新として扱います。 - 論理削除 — インデックスを付けた NULL 許容の
deletedAtを使用します。すべての読み取りでdeletedAt: nullに絞り込み、削除時にタイムスタンプを設定します。 - 監査ログ —
SECURITY DEFINERトリガーを使い、TG_OP、row_to_json、auth.uid()によって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 §論理削除、§監査ログ。
キャッシュパターン [HIGH freedom]
- Next.js:
fetch(url, { next: { revalidate, tags } })を使用し、必要に応じてrevalidateTagを呼び出します。タグ付きで DB クエリをunstable_cacheで囲みます。 - Redis(Upstash):
getCachedData(key, fetcher, ttl)ヘルパーを 1 つ用意し、キャッシュアサイド方式を使います。エンティティと 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 キャッシュ、§Redis キャッシュ。
バックグラウンドジョブ [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 §バックグラウンドジョブ、§代替案。
レート制限 [HIGH freedom]
Redis.fromEnv()を使い、@upstash/ratelimitとRatelimit.slidingWindow(10, '10 s')を組み合わせます。- ユーザー ID(匿名の場合は IP)をキーにします。
!successの場合は、resetの値から算出したretryAfter秒とともにToo many requestsを返します。
rateLimitedAction の完全な例:references/request-patterns.md §レート制限。
アーキテクチャパターン(分散システム) [HIGH freedom]
ゲートウェイ、BFF、バルクヘッド、サーキットブレーカー、アウトボックス+CDC、サーガ、ヘキサゴナルアーキテクチャ、ACL、ストラングラーフィグについては →
references/architecture-patterns.md。トポロジーに合ったパターンを選びます
(モノリスにメッシュは不要です。読み取りと書き込みに違いがない限り、CQRS も不要です)。タイムアウト/再試行/冪等性
→ audit-resilience。構造的なギャップのレポート → audit-backend-architecture。
検証 [LOW freedom — do not skip]
バックエンドパターンの実装後に、次の項目を確認します。
- エラー処理 → すべてのエラーを捕捉してログに記録し、安全なレスポンスを返す
- 認証チェック → すべての変更処理で認証を検証する
- 入力検証 → すべての入力に Zod スキーマを適用する
- レート制限 → 機密性の高いエンドポイントを保護する
- 冪等性 → 重要な処理で再試行に対応する
- ログ記録 → 機密データを含まない構造化ログを使用する
- テスト → ビジネスロジックにはユニットテスト、API には統合テストを実施する