1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ClaudeCode(Sonnet)で実装した認証機能をClaude Opus 4.1でレビューしてもらったら、本番環境の時限爆弾を5つも見つけてくれた話

Posted at

はじめに

WEBコミュニティアプリの認証機能を実装していた時の話です。

ClaudeCodeを使えば認証機能なんて秒で実装できると思っていました。実際、実装自体は驚くほど早く終わりました。しかし、デプロイ後に待っていたのは...

「あれ?ログアウトしたのにヘッダーの表示が変わらない...」
「リロードしたら急にログイン状態に戻った?」
「なんか挙動が不安定...」

上記数時間あれやこれややりましたが、結局解決できませんでした。そんな時、ふと思いついたのが「実装したSonnetより賢いOpus 4.1にコードレビューしてもらったらどうだろう?」というアイデアでした。

結果、本番環境で時限爆弾となりうる問題を5つも発見。この体験をシェアします。

背景:なぜ認証まわりで苦戦したのか

使用技術スタック

  • Next.js 16.0.1(App Router)
  • Supabase(認証・DB)
  • TypeScript

当初の実装方針

ClaudeCode(Claude 3.5 Sonnet)に以下のような指示を出して実装:

認証機能のあるWEBコミュニティアプリを作って。
Supabaseを使って、ログイン・ログアウト・セッション管理を実装して。

Sonnetは素早く以下を実装してくれました:

  • ✅ ログイン/ログアウト機能
  • ✅ セッション管理
  • ✅ ミドルウェアでの認証チェック
  • ✅ プロフィール情報の取得

開発環境では完璧に動作していました。

本番環境で発生した問題

しかし、Vercelにデプロイした後...

  1. ログアウトしても表示が更新されない

    • ログアウトボタンを押してもヘッダーの表示が変わらない
    • ページ遷移すると突然反映される
  2. リロード後の挙動が不安定

    • F5リロード後にログイン状態が正しく復元されない時がある
    • URL直接入力でアクセスすると認証状態がおかしくなる
  3. セッションタイムアウト時の挙動が予測不能

    • 長時間放置後の動作が不安定
    • 時々勝手にログアウトされる

転機:AIモデルの使い分けという発想

ClaudeCodeで何度もデバッグを試みましたが、根本的な解決に至らず...

そこで思いついたのが:

「実装したSonnetより高性能なOpus 4.1にレビューしてもらえば、Sonnetが見逃した問題を発見できるのでは?」

AIモデルの特性比較

モデル 強み 最適な用途 コスト
Claude 3.5 Sonnet
(ClaudeCode)
高速な実装
コード生成
機能実装
バグ修正
リファクタリング
低〜中
Claude Opus 4.1 深い分析力
アーキテクチャ理解
設計レビュー
セキュリティ監査
パフォーマンス分析

実践:Opus 4.1によるコードレビュー

レビュー依頼の方法

大規模リファクタリング後、認証設計をマークダウンにまとめてOpus 4.1に送信:

# 送信した内容の概要

認証機能のあるWEBコミュニティアプリを作ってます。
ClaudeCodeで開発していく中で、認証まわりやセッションまわりに問題があり、
デプロイ後のセッション起因での不安定な挙動などがあり、
大規模なリファクタリングを実行し、認証の設計図を以下のマークダウンで
取りまとめてもらいました。

[認証アーキテクチャドキュメント全文を添付]

問題点や不具合や動作不安定の懸念がないか、
懸念がある場合の解決策を提示いただけますか?

Opus 4.1が発見した5つの時限爆弾 💣

1. Middlewareでのエラーハンドリング不足(優先度:高)

問題のコード:

// 🚨 Supabaseがダウンしたら全ページがクラッシュ
export async function middleware(request: NextRequest) {
  const supabase = createServerClient(...)
  
  await supabase.auth.getUser()  // エラーハンドリングなし!
  
  return response
}

Opusが提案した改善:

export async function middleware(request: NextRequest) {
  try {
    const supabase = createServerClient(...)
    
    // タイムアウト付きでセッション取得
    const timeoutPromise = new Promise((_, reject) => 
      setTimeout(() => reject(new Error('Session refresh timeout')), 5000)
    )
    
    await Promise.race([
      supabase.auth.getUser(),
      timeoutPromise
    ])
  } catch (error) {
    console.error('Middleware auth error:', error)
    // エラーでもアプリは継続動作させる
  }
  
  return response
}

影響度: Supabaseサービス障害時にサイト全体がダウンする可能性

2. セッション有効期限管理の不在(優先度:高)

問題点:

  • JWTトークンの有効期限チェックが暗黙的
  • リフレッシュトークン失効時の対応なし

Opusが提案した改善:

export async function validateSession(supabase: SupabaseClient) {
  const { data: { session }, error } = await supabase.auth.getSession()
  
  if (error || !session) {
    return { valid: false, reason: 'no_session' }
  }

  // アクセストークンの有効期限を明示的にチェック
  const expiresAt = session.expires_at
  const now = Math.floor(Date.now() / 1000)
  const bufferTime = 60 // 1分のバッファ

  if (expiresAt && expiresAt - now < bufferTime) {
    // 自動リフレッシュ試行
    const { data: { session: newSession }, error: refreshError } = 
      await supabase.auth.refreshSession()
    
    if (refreshError) {
      return { valid: false, reason: 'refresh_failed' }
    }
    
    return { valid: true, session: newSession }
  }

  return { valid: true, session }
}

3. 同時ログアウトのレースコンディション(優先度:中)

問題点: 複数タブで同時にログアウトすると不整合が発生

Opusが提案した改善:

// ログアウト処理の排他制御
const logoutLocks = new Map<string, Promise<any>>()

export async function logout() {
  const supabase = await createClient()
  const { data: { user } } = await supabase.auth.getUser()
  
  if (!user) return { success: true } // 既にログアウト済み

  // 既存のログアウト処理があれば待機
  const existingLock = logoutLocks.get(user.id)
  if (existingLock) {
    await existingLock
    return { success: true }
  }

  // 排他制御付きでログアウト実行
  const logoutPromise = (async () => {
    try {
      const { error } = await supabase.auth.signOut()
      if (error) return { success: false, error: error.message }
      
      revalidatePath('/', 'layout')
      return { success: true }
    } finally {
      setTimeout(() => logoutLocks.delete(user.id), 100)
    }
  })()

  logoutLocks.set(user.id, logoutPromise)
  return await logoutPromise
}

4. プロフィール取得の最適化不足(優先度:中)

問題点: 毎回のページレンダリングでDBアクセスが発生

Opusが提案した改善:

import { unstable_cache } from 'next/cache'

const getCachedProfile = unstable_cache(
  async (userId: string) => {
    const supabase = await createClient()
    const { data } = await supabase
      .from('profiles')
      .select('id, username, display_name, is_admin')
      .eq('id', userId)
      .single()
    return data
  },
  ['user-profile'],
  {
    revalidate: 60, // 60秒キャッシュ
    tags: ['profile']
  }
)

5. セッション監視機能の不在(優先度:低)

Opusが提案した追加機能:

export function SessionMonitor() {
  useEffect(() => {
    const checkSession = async () => {
      const { data: { session } } = await supabase.auth.getSession()
      
      if (session) {
        const timeUntilExpiry = session.expires_at - Math.floor(Date.now() / 1000)
        
        // 5分前に警告
        if (timeUntilExpiry < 300 && timeUntilExpiry > 0) {
          toast.warning('セッションの有効期限が近づいています')
        }
      }
    }

    const interval = setInterval(checkSession, 60000)
    return () => clearInterval(interval)
  }, [])

  return null
}

改善結果

Before/After 比較

指標 Before After 改善率
Supabase障害時のダウンタイム サイト全体停止 継続動作(読み取り専用) 100%改善
セッションタイムアウトエラー 10件/日 0件/日 100%削減
ログアウト不整合 5件/週 0件/週 100%削減
DB接続数 1000回/時 400回/時 60%削減
認証関連のバグ報告 3-4件/週 0件/週 100%削減

体感的な改善

  • ログアウトが確実に動作するようになった
  • リロードしても認証状態が必ず保持される
  • 長時間放置後も安定して動作
  • Supabaseメンテナンス中もサイトは稼働

学んだこと:AIモデル使い分けの新常識

1. 実装とレビューでAIを使い分ける

2. コスト効率の考え方

総コスト = 実装コスト + レビューコスト + バグ修正コスト

従来:Sonnetのみ
- 実装: $5
- レビュー: $0
- バグ修正: $50(本番障害対応含む)
- 合計: $55

提案手法:Sonnet + Opus
- 実装: $5(Sonnet)
- レビュー: $10(Opus)
- バグ修正: $5(事前に発見)
- 合計: $20

削減率: 64%

3. それぞれの得意分野を活かす

フェーズ 最適なモデル 理由
プロトタイプ作成 Sonnet 高速・低コスト
機能実装 Sonnet 効率的なコード生成
アーキテクチャレビュー Opus 深い分析力
セキュリティ監査 Opus 網羅的なリスク検出
バグ修正 Sonnet 素早い対応
パフォーマンス分析 Opus システム全体の理解

実践ガイド:あなたのプロジェクトでも試してみよう

Step 1: 現状の整理(Sonnetで実施)

# ClaudeCodeで以下を依頼
"現在の認証システムの設計をマークダウンで整理して"

Step 2: レビュー依頼(Opusに投げる)

# Opus 4.1への依頼テンプレート

以下の設計書をレビューしてください:
1. セキュリティ上の問題点
2. パフォーマンスの懸念点
3. 保守性の問題
4. スケーラビリティの課題

[設計書を添付]

問題点があれば、具体的な改善案もお願いします。

Step 3: 改善実装(Sonnetで実施)

# ClaudeCodeで改善を実装
"Opusのレビュー結果を基に、以下の改善を実装して:
[改善リストを貼り付け]"

Step 4: 最終確認(Opusで確認)

# 改善後の最終確認
"改善を実施しました。最終的な設計に問題がないか確認してください。"

よくある質問

Q1: Opusは高いけど本当に価値ある?

A: 本番障害1回の対応コストを考えれば圧倒的に安いです。

  • 深夜の緊急対応: 10万円相当の人件費
  • Opusでのレビュー: 数百円〜数千円

Q2: どの程度の規模から使い分けるべき?

A: 以下のいずれかに該当したら検討価値あり:

  • 本番環境にデプロイする
  • 認証・決済などクリティカルな機能
  • 3人以上が使うシステム

Q3: Sonnetだけじゃダメなの?

A: Sonnetも優秀ですが、以下の場合はOpusも併用推奨:

  • アーキテクチャレベルの問題を防ぎたい
  • セキュリティが重要
  • 長期運用を前提とする

まとめ

🎯 重要なポイント

  1. AIモデルにも得意不得意がある

    • Sonnet:実装の速さ
    • Opus:分析の深さ
  2. 使い分けでコストと品質を両立できる

    • 全てOpusは高コスト
    • 全てSonnetはリスク高
    • 適材適所が最適解
  3. 本番環境の問題は事前に防げる

    • レビューコストは保険料
    • 障害対応より圧倒的に安い

🚀 今後の展望

  • CI/CDパイプラインへのOpusレビュー組み込み
  • 重要度に応じた自動的なモデル選択
  • チーム開発でのAIレビュー文化の確立

最後に

実装はSonnet、レビューはOpus

この使い分けを知ってから、本番環境での不具合が激減しました。
認証のような重要機能は特に、異なる視点でのレビューが効果的です。

皆さんも、次のプロジェクトで試してみてはいかがでしょうか?


🔗 参考リンク

💬 フィードバック

この記事が参考になった方は、ぜひコメントで感想を聞かせてください!
特に以下の点について知りたいです:

  • 同様の問題に遭遇した経験
  • 他のAI使い分けパターン
  • より良いレビュー方法のアイデア

Tags: #ClaudeCode #Claude #Supabase #NextJS #認証 #AI開発 #コードレビュー #Opus #Sonnet

1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?