
2-2.承認済みパトロールの編集ロック不完全
SafetyPatrolController.php saveDraft()メソッドshow.blade.phpのUIは$isLockedフラグで編集を無効化しているが、saveDraftエンドポイントにはis_finalizedチェックがなく、直接POSTで承認済みデータを上書き可能
修正
php
public function saveDraft(Request $request, Project $project, $id)
{
$this->authorizeProject($project);
$safetyPatrol = SafetyPatrol::findOrFail($id);
// 承認済みは変更不可 if ($safetyPatrol->is_finalized) { return response()->json([‘success’ => false, ‘message’ => ‘確認済みの記録は変更できません。’], 403); } //
2-3.CLAUDE.md との相違点
| 項目 | 問題 | 対象箇所 |
|---|---|---|
| session(‘success’)表示 | CLAUDE.mdでは `toast.blade.phpは error のみ表示とあるが、`show.blade.phpに独自のsuccess表示が存在 | show.blade.php` L23-27 |
| ` 未使用 | 一覧のボタン群が直接 <button class=”bg-indigo-600…”>等で実装されている | index.blade.php` L43-53 |
| ファイル先頭の説明コメント欠如 | コントローラ・モデルの先頭に「このファイルの説明文」がない | SafetyPatrolController.php` 等全般 |
| インラインスクリプト | index.blade.phpの flash メッセージ消去処理がインライン<script>内に記述 | index.blade.php` L26-35 |
1.【安全パトロール】コードの健全性検証
1.セキュリティ・脆弱性
エラーメッセージ漏洩
safetyPatrolController.php:210
php
// 現状:例外メッセージをそのまま返している
return response()->json([‘success’ => false, ‘message’ => ‘システムエラー: ‘ . $e->getMessage()]);
PHPの例外メッセージ(DBパス・APIキー名・内部構造等)がそのままフロントエンドに露出する
修正
php
// 固定文言に変更
return response()->json([‘success’ => false, ‘message’ => ‘システムエラーが発生しました。時間をおいて再試行してください。’]);
// ログには詳細を記録
\Log::error(‘AI checklist generation error: ‘ . $e->getMessage());
1-2.ファイルアップロードのバリデーション欠如
SafetyPatrolController.phpstore()
php
// 現状:バリデーションなしで直接 store()
$filePath = $request->file(‘attached_file’)->store(‘patrol_files’, ‘public’);
ファイルタイプ・サイズ制限がないため、実行ファイルや大容量ファイルのアップロードが可能な状態
修正
php
$request->validate([
‘attached_file’ => ‘nullable|file|mimes:pdf,jpg,jpeg,png,gif,webp|max:10240’,
‘patrol_datetime’ => ‘required|date’,
‘inspector_name’ => ‘required|string|max:100’,
]);
1-3.CSP方針違反 インラインイベントハンドラ
CLAUDE.md に「`onclick=””等のインラインハンドラを使わず、必ず `addEventListenerで登録する」と明記されているが、以下の箇所に違反が存在する
| ファイル | 行 | 内容 |
|---|---|---|
| show.blade.php | L105, L109, L113, L117 | onchange=”updateRowColor(…); autoSave()” |
| create.blade.php | L82 | onclick=”runAiProcess(…)” |
| index.blade.php | L43, L47, L51, L103, L115 | onclick=”window.location.href=…” |
修正方針:** 各ボタンに `data-url属性を付与し、外部JSで `addEventListenerに移行
2.データ喪失リスク
SafetyPatrolController.php destroy()` メソッド
php
// 現状:attached_file_path のみ削除
if ($patrol->attached_file_path) {
Storage::disk(‘public’)->delete($patrol->attached_file_path);
}
$patrol->delete();
// → safety_patrol_photos テーブルのレコードと画像ファイルは残存
パトロール削除時に、紐づく写真ファイル(storage/public/patrol_photos/)とDBレコードが削除されない。時間とともにストレージを圧迫する
php
// 写真ファイルとレコードを先に削除
$patrol->safetyPatrolPhotos()->each(function ($photo) {
Storage::disk(‘public’)->delete($photo->file_path);
$photo->delete();
});
$patrol->delete();
3.不要・廃止済みコード
| 対象ファイル | 内容 | 推奨対応 |
|---|---|---|
| app/Models/PatrolPhoto.php | SafetyPatrolPhoto` に移行済みの旧モデル。テーブルも実質不使用 | 削除 |
| resources/views/safety_patrols/old_index.blade.php | 旧ファイルが残存 | 削除 |
| SafetyPatrol::photos()` リレーション | 旧PatrolPhotoを参照しているが、実際のコードでは `SafetyPatrolPhotoを直接クエリしているため未使用 | SafetyPatrolPhoto` に修正 |
| workCategories` のハードコード | create()` メソッド内にカテゴリ一覧が直書きされている | 設定ファイルまたはDBマスタへ移行 |
4.共通ルーチン化の可能性
Claude API呼び出し処理の共通化を推奨。
現在SafetyPatrolController::generateAiChecklist() に実装されているClaude API通信(HTTPリクエスト・JSONパース・エラーハンドリング)は、施工計画書・工程計画等の他機能でも同パターンが使われている→ app/Services/AnthropicService.php などの共通サービスクラスにまとめることで保守性が向上し、APIキーやモデル設定の一元管理が可能になる。
5.実施内容一覧
| # | 優先度 | 対象メソッド/ファイル | 内容 | 状態 |
|---|---|---|---|---|
| 1 | 最優先 | store() | ファイルアップロードバリデーション追加 | ✅ 完了 |
| 2 | 最優先 | destroy() | 写真ファイルのカスケード削除 | ✅ 完了 |
| 3 | 最優先 | generateAiChecklist() | エラーメッセージ固定文言化 | ✅ 完了 |
| 4 | 優先 | saveDraft() | 承認済みチェック追加 | ✅ 完了 |
| 5 | 優先 | PatrolPhoto.php/old_index.blade.php | 廃止コード削除 | ✅ 完了 |
| 6 | 優先 | SafetyPatrol::photos() | リレーション修正 | ✅ 完了 |

