-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
User
committed
Jan 12, 2026
1 parent
aeb1860
commit 88267db
Showing
1 changed file
with
259 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| # レビューテスト用バグ一覧 | ||
|
|
||
| このドキュメントには、意図的に仕込まれたバグの詳細が記載されています。採点用の参考資料として使用してください。 | ||
|
|
||
| ## バグ一覧 | ||
|
|
||
| ### 難易度1: UIの状態管理不備 | ||
|
|
||
| **ファイル**: `components/TodoItem.tsx` | ||
| **行番号**: 97-104行目 | ||
|
|
||
| **バグ内容**: | ||
| 削除ボタンの`disabled`属性が`isDeleting`のみを考慮しており、`isUpdating`が考慮されていない。 | ||
|
|
||
| **問題コード**: | ||
| ```tsx | ||
| <button | ||
| onClick={handleDelete} | ||
| disabled={isDeleting} // isUpdatingが考慮されていない | ||
| className="text-red-600 hover:text-red-800 disabled:opacity-50 disabled:cursor-not-allowed transition-colors" | ||
| title="削除" | ||
| > | ||
| {isDeleting ? '削除中...' : '🗑️'} | ||
| </button> | ||
| ``` | ||
|
|
||
| **問題点**: | ||
| - TODOの完了状態を更新中(`isUpdating === true`)でも削除ボタンが有効になっている | ||
| - 更新処理と削除処理が同時に実行される可能性があり、データの整合性が損なわれる可能性がある | ||
| - ユーザー体験が悪化する(更新中に誤って削除してしまう可能性) | ||
|
|
||
| **影響範囲**: | ||
| - フロントエンドのUI動作 | ||
| - データ整合性への潜在的な影響 | ||
|
|
||
| **期待される修正**: | ||
| ```tsx | ||
| disabled={isDeleting || isUpdating} | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### 難易度2: データバリデーション不備 | ||
|
|
||
| **ファイル**: `app/api/todos/route.ts` | ||
| **行番号**: 34-38行目 | ||
|
|
||
| **バグ内容**: | ||
| `description`が空文字列の場合、`null`に変換されずにそのまま空文字列がデータベースに保存される。 | ||
|
|
||
| **問題コード**: | ||
| ```typescript | ||
| const todo = await prisma.todo.create({ | ||
| data: { | ||
| title: validatedData.title, | ||
| description: validatedData.description, // 空文字列がそのまま保存される | ||
| }, | ||
| }) | ||
| ``` | ||
|
|
||
| **問題点**: | ||
| - zodスキーマで`description`が`optional()`のため、空文字列がバリデーションを通過してしまう | ||
| - データベースに空文字列が保存され、`null`と空文字列が混在する可能性がある | ||
| - データの一貫性が損なわれる | ||
| - フロントエンドで`todo.description && ...`のような条件分岐が正しく動作しない可能性がある | ||
|
|
||
| **影響範囲**: | ||
| - データベースのデータ整合性 | ||
| - フロントエンドの表示ロジック | ||
|
|
||
| **期待される修正**: | ||
| ```typescript | ||
| description: validatedData.description || null, | ||
| ``` | ||
| または | ||
| ```typescript | ||
| description: validatedData.description?.trim() || null, | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### 難易度3: React Hooksの依存配列問題 | ||
|
|
||
| **ファイル**: `components/TodoList.tsx` | ||
| **行番号**: 39-41行目 | ||
|
|
||
| **バグ内容**: | ||
| `useEffect`の依存配列に`fetchTodos`が含まれているが、`fetchTodos`が毎回新しい関数として作成されるため、無限ループが発生する可能性がある。 | ||
|
|
||
| **問題コード**: | ||
| ```tsx | ||
| const fetchTodos = async () => { | ||
| // ... | ||
| } | ||
|
|
||
| useEffect(() => { | ||
| fetchTodos() | ||
| }, [fetchTodos]) // fetchTodosが毎回新しい関数として作成される | ||
| ``` | ||
|
|
||
| **問題点**: | ||
| - `fetchTodos`がコンポーネント内で定義されているため、レンダリングごとに新しい関数インスタンスが作成される | ||
| - `useEffect`の依存配列に`fetchTodos`を含めると、毎回依存が変化したと判断され、無限ループが発生する | ||
| - 不要なAPIリクエストが大量に発生し、パフォーマンスが低下する | ||
| - サーバーに負荷がかかる | ||
|
|
||
| **影響範囲**: | ||
| - フロントエンドのパフォーマンス | ||
| - サーバーへの負荷 | ||
| - ユーザー体験(画面がフリーズする可能性) | ||
|
|
||
| **期待される修正**: | ||
| ```tsx | ||
| useEffect(() => { | ||
| fetchTodos() | ||
| }, []) // 依存配列を空にする | ||
| ``` | ||
| または | ||
| ```tsx | ||
| const fetchTodos = useCallback(async () => { | ||
| // ... | ||
| }, []) | ||
|
|
||
| useEffect(() => { | ||
| fetchTodos() | ||
| }, [fetchTodos]) | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### 難易度4: セキュリティ/データ整合性問題 | ||
|
|
||
| **ファイル**: `app/api/todos/[id]/route.ts` | ||
| **行番号**: 16-20行目(GET, PATCH, DELETEすべて) | ||
|
|
||
| **バグ内容**: | ||
| IDの形式検証が行われておらず、不正なID形式(SQLインジェクションや不正な文字列)が送られても検証されない。 | ||
|
|
||
| **問題コード**: | ||
| ```typescript | ||
| try { | ||
| const { id } = await params | ||
| const todo = await prisma.todo.findUnique({ | ||
| where: { id }, // IDの形式検証がない | ||
| }) | ||
| // ... | ||
| } | ||
| ``` | ||
|
|
||
| **問題点**: | ||
| - PrismaはSQLインジェクションを防いでいるが、不正なID形式(例: 非常に長い文字列、特殊文字を含む文字列)が送られても検証されない | ||
| - 不正なIDでリクエストが送られた場合、適切なエラーメッセージが返されない可能性がある | ||
| - データベースへの不要なクエリが発生する可能性がある | ||
| - エラーハンドリングが不十分 | ||
|
|
||
| **影響範囲**: | ||
| - セキュリティ(軽微) | ||
| - エラーハンドリング | ||
| - パフォーマンス(不要なクエリ) | ||
|
|
||
| **期待される修正**: | ||
| ```typescript | ||
| // cuid形式の検証を追加 | ||
| const isValidCuid = (id: string): boolean => { | ||
| return /^c[a-z0-9]{24}$/.test(id) | ||
| } | ||
|
|
||
| try { | ||
| const { id } = await params | ||
| if (!isValidCuid(id)) { | ||
| return NextResponse.json( | ||
| { error: '不正なID形式です' }, | ||
| { status: 400 } | ||
| ) | ||
| } | ||
| // ... | ||
| } | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ### 難易度5: 本番環境での接続管理問題 | ||
|
|
||
| **ファイル**: `lib/prisma.ts` | ||
| **行番号**: 7-13行目 | ||
|
|
||
| **バグ内容**: | ||
| 本番環境でもPrismaクライアントをグローバルに保存しないため、リクエストごとに新しい`PrismaClient`インスタンスが作成される可能性がある。 | ||
|
|
||
| **問題コード**: | ||
| ```typescript | ||
| export const prisma = globalForPrisma.prisma ?? new PrismaClient({ | ||
| log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'], | ||
| }) | ||
|
|
||
| if (process.env.NODE_ENV !== 'production') { | ||
| globalForPrisma.prisma = prisma | ||
| } | ||
| ``` | ||
|
|
||
| **問題点**: | ||
| - 本番環境では`globalForPrisma.prisma`が保存されないため、Next.jsのサーバーレス環境ではリクエストごとに新しい`PrismaClient`インスタンスが作成される可能性がある | ||
| - 接続プールが適切に管理されず、データベース接続が枯渇する可能性がある | ||
| - メモリリークやパフォーマンス低下の原因になる | ||
| - 本番環境でのスケーラビリティに影響する | ||
|
|
||
| **影響範囲**: | ||
| - 本番環境のパフォーマンス | ||
| - データベース接続管理 | ||
| - スケーラビリティ | ||
| - メモリ使用量 | ||
|
|
||
| **期待される修正**: | ||
| ```typescript | ||
| export const prisma = globalForPrisma.prisma ?? new PrismaClient({ | ||
| log: process.env.NODE_ENV === 'development' ? ['query', 'error', 'warn'] : ['error'], | ||
| }) | ||
|
|
||
| // 本番環境でもグローバルに保存 | ||
| globalForPrisma.prisma = prisma | ||
| ``` | ||
|
|
||
| --- | ||
|
|
||
| ## 採点基準(参考) | ||
|
|
||
| ### 難易度1(初級) | ||
| - コードレビューで簡単に発見できる | ||
| - UIの動作を確認すれば発見できる | ||
| - 初心者でも発見可能 | ||
|
|
||
| ### 難易度2(初中級) | ||
| - データフローの理解が必要 | ||
| - バリデーションロジックの確認が必要 | ||
| - 中級者レベル | ||
|
|
||
| ### 難易度3(中級) | ||
| - React Hooksの理解が必要 | ||
| - 無限ループの原因を理解する必要がある | ||
| - 実際に動作を確認しないと発見が難しい場合がある | ||
|
|
||
| ### 難易度4(上級) | ||
| - セキュリティ意識が必要 | ||
| - エラーハンドリングの観点が必要 | ||
| - 実装経験が3年以上のエンジニアが発見可能 | ||
|
|
||
| ### 難易度5(最上級) | ||
| - 本番環境での動作を理解する必要がある | ||
| - Next.jsのサーバーレス環境の理解が必要 | ||
| - Prismaの接続管理の深い理解が必要 | ||
| - 実装経験が5年以上のエンジニアが発見可能 | ||
|
|
||
| --- | ||
|
|
||
| ## 注意事項 | ||
|
|
||
| - これらのバグは意図的に仕込まれたものです | ||
| - 実際のプロダクションコードでは、このようなバグを避けるためにコードレビューやテストを実施してください | ||
| - 採点時は、バグの発見数だけでなく、バグの重要度や影響範囲も考慮してください |