unopim-code-review について
UnoPim のコード変更をレビューするスキルです。`unopim-standards` に基づき、追加・変更行を確認します。セキュリティ、規模、移植性、ローカライズなどの阻止要因を扱い、所定の指摘形式を定めています。
主な機能
- 01差分に限定したレビュー範囲
- 02十項目の阻止要因チェック
- 03優先度の高い規約確認
- 04規約と実例パスの引用必須
- 05構造化された指摘形式
活用シーン
- 01UnoPim のプルリクエストのレビュー
- 02追加ルートと ACL 規則の照合
- 03データベースクエリの規模・移植性監査
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ unopim/ agent-skills --skill unopim-code-reviewインストール後、Claude Code で/unopim-code-reviewを入力して読み込まれたか確認します。
詳細
UnoPim コードレビュー
必須の前提知識: unopim-standards を使用してください。参照ファイル(laravel13.md、security.md、performance.md、scale.md、extensibility.md、localization.md、comments.md)がルールブックです。このスキルは、それらを差分に適用するためのチェックリストです。
対象範囲 — 掘り起こしではなく、変更箇所を絞って確認
変更によって追加または修正された行をレビューしてください。未変更行にある既存の違反は、せいぜい指摘にとどめ、ブロッカーにしないでください。ファイル全体をブロッカーにすると、レガシーコードの変更がすべて停滞します。新たに追加された違反は、周囲のレガシーコードをまねたものであっても、必ず対象です。
ブロッカーとなる項目(いずれかに該当したら変更を要求)
1. コメントのノイズ — 開発者から最も多く寄せられる不満
- メソッド本体、オブジェクト/配列リテラル、ルートグループ、Blade マークアップ内に追加されたコメントは、どのようなものでもブロッカーです。1行の「理由」コメント、セクション区切り(
// Views、// ----)、説明書きの{{-- --}}も含みます。 - プロジェクトの基準はインラインコメントゼロです。
packages/Webkul/Product/src/Repositories/ProductRepository.php(18個のメソッド)とpackages/Webkul/Product/src/Type/AbstractType.php(988行)には、インラインコメントがありません。 - 本当に自明でない根拠は、クラス/メソッドの PHPDoc またはコミットメッセージに記載します。メソッドの PHPDoc は命令形の1行要約にし、
@param/@returnはネイティブ型ヒントがない場合にのみ記載します。 - 機械的なチェック:
git diff -U0で追加された行のうち、^\+\s*(//|/\*|\{\{--)に一致するものはすべて指摘対象です。
2. ハードコードされた色
- ブロッカー:16進数/rgb のリテラル、
style="..."、<style>ブロック、任意の値(bg-[#...])、デフォルトの意図別スケール(violet-*、purple-*、red-*、green-*、blue-*)、および新しいコードでのレガシーなcherry-*/sky-*/unopim-primary-*。 - 必須:セマンティックトークンのみを使用します。
primary(+50–900)、primary-hover、success、warning、danger、infoを使い、packages/Webkul/Admin/src/Resources/assets/css/app.css(:rootと.dark)の CSS 変数をpackages/Webkul/Admin/tailwind.config.jsでマッピングします。リテラルは.darkの変数切り替えに追従できないため、ダークモードで表示が崩れます。 - ニュートラルカラーには、
text-primary-700 dark:text-primary-400のように、ダークモード用の対応色が必要です。
3. x-admin:: コンポーネントがある箇所での生の HTML
- 管理画面のビューで生の
<input>、<select>、<textarea>、<label>を使うとブロッカーです。x-admin::form.control-groupと.label/.control/.errorが利用できます。 - 独自に組み立てた一覧テーブルはブロッカーです。
x-admin::datagridを使用してください。固定表示や背景表示用の div を独自に作るのもブロッカーです。x-admin::modal(およびmodal.confirm)またはx-admin::drawerを使用してください。 - 約140個のコンポーネント Blade が
packages/Webkul/Admin/src/Resources/views/componentsにあります。独自マークアップを採用する前に、ここを確認してください(switcher、flat-picker、tinymce、tabs、accordion、dropdown、tree、badge、shimmer)。 - セレクトには
track-by/label-byを指定した:options="json_encode(...)"を使用してください。<option>に対して@foreachを使ってはいけません。
4. 重複
- 2回以上出現するブロック(ロジックまたはマークアップ)は、メソッド、コンポーネント、またはパーシャルに切り出す必要があります。再利用する既存の場所を明記してください。
5. スケーラビリティ — 数百万行を想定する
- カタログテーブルに対する無制限の
->all()/->get()/->pluck()はブロッカーです。バッチスキャンにはchunkById()/lazyById()を使用します(packages/Webkul/Completeness/src/Jobs/BulkProductCompletenessJob.php)。 - この観点のほとんどはフックで検出できません。終了コードで検出できたと思い込まず、差分を確認してください。 フックでブロックされるのは
Model::all()、$someRepository->all()、select('*')のみです。->get()で終わる流暢なメソッドチェーン、foreach内のクエリ、Eager Load の欠落、Blade テンプレート内のクエリ、ShouldQueueジョブをディスパッチせずにコントローラーでカタログをループする処理は、すべてゲートからは見えず、ここではブロッカーです。 - 一括検索では
array_chunk($keys, 1000)とwhereInを使用します(packages/Webkul/DataTransfer/src/Helpers/Importers/Product/SKUStorage.php)。ループ内で行ごとにクエリを実行してはいけません。 - エクスポート元では、ID カーソルを使ったキーセットページネーションでストリーミングします(
packages/Webkul/DataTransfer/src/Helpers/Sources/Export/ProductCursor.php)。AbstractExporter のsource->all()デフォルトが許容されるのは、小規模なエンティティに限られます。 - 複数バッチにまたがる処理は
ShouldQueueジョブにし、リクエスト内で直接実行してはいけません。データマイグレーションもストリーミングします(cursor/chunkById)。 - 新しい
where/orderBy/フィルタリング可能な DataGrid 列にはインデックスが必要です。ループや Blade 内でクエリを実行してはいけません。たどるすべてのリレーションを Eager Load してください。
6. 移植性 — MySQL と PostgreSQL、テーブルプレフィックス、オプションの Elasticsearch
- テーブル名を指定する Raw SQL フラグメント(
DB::raw、selectRaw、whereRaw、orderByRaw)には、DB::getTablePrefix()を前置する必要があります(packages/Webkul/Measurement/src/DataGrids/UnitDataGrid.php)。ハードコードされたwk_はブロッカーです。このようなプレフィックスは存在せず、DB_PREFIXのデフォルトは空です。 - MySQL 専用 SQL(GROUP_CONCAT、バッククォート、DATE_FORMAT、CAST AS SIGNED)はブロッカーです。
DB::rawQueryGrammar()(packages/Webkul/Core/src/Helpers/Database/Grammars/MySQLGrammar.php、packages/Webkul/Core/src/Helpers/Database/Grammars/PostgresGrammar.php)を使ったクロス DB 対応、またはDB::getDriverName() === 'pgsql'の分岐を使用してください。 - Elasticsearch への呼び出しは、DB フォールバックを備えた
config('elasticsearch.enabled')による制御がなければ、ブロッカーです(packages/Webkul/Product/src/Factories/ProductQueryBuilderFactory.php)。
7. セキュリティ
- ACL はルート名によってフェイルオープンになります(
packages/Webkul/User/src/Http/Middleware/Bouncer.php)。書き込みルート(store、update、destroy、mass_*(snake_case のキー)、test-connection)がどの acl.php にも記載されていない場合、ログイン済みのすべての管理者がアクセスでき、ブロッカーとなります。'also_authorizes'を使って書き込みルートを紐付けてください(packages/Webkul/Core/src/Tree.php)。 - すべてのエンドポイントに FormRequest を使ってください。インラインの
request()->validate()はブロッカーです。authorize(): trueを使えるのは、ルート名が ACL で制御されている場合のみです。それ以外ではauthorize()内で Bouncer によるチェックを行ってください(packages/Webkul/Admin/src/Http/Requests/TinyMCEUploadRequest.php)。共有エンドポイントまたはルートを持たないエンドポイントは、コントローラー内でアクセスを制御してください(packages/Webkul/Admin/src/Http/Controllers/MagicAI/MagicAIController.php)。 - アップロード:MIME タイプの許可リスト、最大サイズ、
FileMimeExtensionMatchを適用してください(packages/Webkul/Core/src/Rules/FileMimeExtensionMatch.php)。svg/html の受け入れはブロッカーです(スクリプトを仕込めるため)。 - 一括代入:明示的な
#[Fillable]許可リストを使い、権限に関するカラムは含めないでください。$guarded = []はブロッカーです。保存時のシークレットには'encrypted'キャスト、#[Hidden]、$auditExcludeのすべてが必要です(packages/Webkul/AiAgent/src/Models/Credential.php)。$auditExcludeだけでは暗号化されません。 - 外部送信 URL は SSRF 対策として検証してください(
packages/Webkul/Webhook/src/Validators/SafeWebhookUrl.php)。CSV エクスポートでは数式演算子をエスケープしてください(packages/Webkul/DataTransfer/src/Helpers/Formatters/EscapeFormulaOperators.php)。リクエスト入力を SQL または DataGrid のクロージャ内の HTML に補間しないでください。 - 上記のブロッカーのうち 2 つにはフックがなく、対応できるのはあなた自身だけです。ACL のルートカバレッジ(複数ファイルにまたがる確認です。ファイル単位のゲートでは確認できないため、ルートファイルとすべての
acl.phpを合わせて読む必要があります)と、orderByRaw("$column $direction")(商品フィルターにある正当なwhereRaw("$column IS NULL")と同じ行に見えるためです)。 書き込みルートを追加する PR ごとにacl.phpを開き、ルートファイルと照合してください。どちらについても「フックが通った」ことを根拠として受け入れないでください。
8. ローカライズ
- ユーザーに表示されるハードコード文字列はすべてブロッカーです。プレースホルダー、ツールチップ、JS のアラート、「Loading…」というステータステキストも含みます。まず
Resources/lang/en_US/にキーを用意してtrans()/@langを使い、その後すべての 33 ロケールに自然な翻訳を追加してください(英語のままのコピーは不可)。:placeholdersはそのまま保持してください。 enという名前だけのディレクトリにあるキーはブロッカーです。読み込まれません。フォールバックロケールはen_USです。
9. Octane の安全性
- リクエストまたは認証情報の状態を保持する
singleton()バインディングはブロッカーです。代わりにscoped()をバインドしてください(packages/Webkul/Core/src/Providers/CoreServiceProvider.php、packages/Webkul/Core/src/RequestMemo.php)。singleton()はステートレスなインフラストラクチャのみに使用してください。
10. 検証の証拠
- PR には、各ゲートを実際に実行したことを示す必要があります:
vendor/bin/pint --test、composer test(Pest v5、MySQL と PgSQL)、composer phpstan、composer rector-dry、UI/管理画面の変更に対する Playwright、php artisan unopim:translations:check。「通るはず」とだけ記載され、出力がない場合は未検証です。実行を依頼してください。 - ゲートを通すために新しい
ignoreErrorsまたはwithSkipの項目を追加するのはブロッカーです。
高優先度(マージ前に修正。即時ブロックではありません)
- Concord のプロキシ/コントラクトを持たない新しいモデル、またはリポジトリがあるのに
new Model()を直接使っている場合。リポジトリがWebkul\Core\Eloquent\Repositoryを継承していない場合。 - Laravel 13/PHP 8.4 のイディオムが不足している場合:昇格コンストラクタープロパティ、戻り値の型、列挙型、
casts()メソッド、モデルの#[Fillable]/#[Table]属性がない場合。 - マイグレーションの配置先が誤っている場合。コアパッケージでは
src/Database/Migrations/(複数形)を使用し、プラグイン形式のパッケージのみルート直下のDatabase/Migration/(単数形)を使用します。 - プロバイダーがルート、設定のマージ(メニューは
'menu.admin'、acl、インポーター/エクスポーター)、マイグレーション、翻訳/ビューの名前空間を読み込んでいない場合。 - 新しい動作に対するテストがない場合、
assertDatabaseHas/assertDatabaseMissingがない場合、Pest のit()/describe()スタイルを使っていない場合。 - イベント名が
{domain}.{entity}.{action}.{before|after}形式ではない場合、ルート名がドット区切りではない場合。
判定形式
[Dimension] [Blocker|High|Medium]: one-sentence statement of the violation
Location: file:line (added/changed line)
Standard: unopim-standards/<reference file> e.g. comments.md, security.md, scale.md
Pattern: a real exemplar path under packages/Webkul showing the correct form
Fix: the minimal change
すべての判定には、標準の参照ファイルと実際の模範例のパスの両方を必ず記載してください。関連する指摘はまとめ、標準が存在する理由は一節で示し、段落にはしないでください。
コメント
Markdown 対応