liveview-code-review について
Phoenix LiveView プロジェクト向けのコードレビュースキルです。ライフサイクル、データ管理、コンポーネント、セキュリティを確認し、根拠を検証してから指摘する手順を備えています。
主な機能
- 01LiveView ライフサイクルの確認
- 02assigns、streams、非同期状態の指針
- 03関数コンポーネントと LiveComponent のレビュー
- 04認可とクライアントデータ検証の確認
- 05根拠と状況に応じたレビューゲート
活用シーン
- 01LiveView イベントの認可確認
- 02非同期処理の読み込みとエラー対応の確認
- 03大規模なコレクションのデータ処理評価
- 04コンポーネントと slot の使い方のレビュー
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ existential-birds/ beagle --skill liveview-code-reviewインストール後、Claude Code で/liveview-code-reviewを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/assigns-streams.mdcomponents.mdlifecycle.mdsecurity.md詳細
LiveView コードレビュー
クイックリファレンス
| 問題の種類 | リファレンス |
|---|---|
| mount、handle_params、handle_event、handle_async | references/lifecycle.md |
| assigns と streams の使い分け、AsyncResult | references/assigns-streams.md |
| 関数コンポーネントと LiveComponent、スロット、属性 | references/components.md |
| イベントごとの認可、phx-value の信頼性 | references/security.md |
レビューチェックリスト
重大な問題
- ソケットを非同期関数にコピーしていない(先に値を取り出す)
- すべての handle_event で認可を検証している
- assigns に機密データが含まれていない(DOM から見える)
- phx-value のデータを検証している(ユーザーが変更可能)
ライフサイクル
- サブスクリプションを
connected?(socket)でラップしている - URL ベースの状態には handle_params を使用している
- handle_async で :loading と :error の状態を処理している
データ管理
- 大規模なコレクション(100 件以上)には streams を使用している
- レンダリング後に不要なデータには temporary_assigns を使用している
- 読み込み状態には AsyncResult パターンを使用している
コンポーネント
- LiveComponent より関数コンポーネントを優先している
- LiveComponent が update/2 で :inner_block を保持している
- スロットで適切な attr 宣言を使用している
- テキスト入力に phx-debounce を設定している
有効なパターン(指摘しない)
- {:ok, socket} を返す空の mount - シンプルな LiveView では有効です
- 小さなリストに assigns を使用する - streams が必要なのは 100 件以上の場合のみです
- update/2 のない LiveComponent - デフォルトの update/2 がすべてを assigns に割り当てます
- phx-value のない phx-click - イベントでデータが不要な場合があります
- heex 内のインライン関数 - シンプルな変換では有効です
コンテキスト依存のルール
| 問題 | 次の場合にのみ指摘 |
|---|---|
| debounce の欠落 | 入力が text/textarea で、かつサーバーイベントを発生させる |
| streams の使用 | コレクションが 100 件以上、またはページ分割されている |
| 認可チェックの欠落 | イベントがデータを変更し、かつ mount に認可処理がない |
重大なアンチパターン
ソケットのコピー(最重要)
# BAD - socket copied into async function
def handle_event("load", _, socket) do
Task.async(fn ->
user = socket.assigns.user # Socket copied!
fetch_data(user.id)
end)
{:noreply, socket}
end
# GOOD - extract values first
def handle_event("load", _, socket) do
user_id = socket.assigns.user.id
Task.async(fn ->
fetch_data(user_id) # Only primitive copied
end)
{:noreply, socket}
end
認可の欠落
# BAD - trusts phx-value without auth
def handle_event("delete", %{"id" => id}, socket) do
Posts.delete_post!(id) # Anyone can delete any post!
{:noreply, socket}
end
# GOOD - verify authorization
def handle_event("delete", %{"id" => id}, socket) do
post = Posts.get_post!(id)
if post.user_id == socket.assigns.current_user.id do
Posts.delete_post!(post)
{:noreply, stream_delete(socket, :posts, post)}
else
{:noreply, put_flash(socket, :error, "Unauthorized")}
end
end
ハードゲート(順番に適用)
各 合格条件 が客観的に満たされている場合にのみ次へ進みます(根拠のない報告を防ぐため):
| ゲート | 合格条件 |
|---|---|
| G1 — 根拠となるファイル | レビュー対象のパスの明示的な一覧(例:*.ex、*.heex、またはユーザーが指定したパス)があること。すべての指摘で、その一覧に含まれるファイルを挙げること。 |
| G2 — 検証プロトコル | review-verification-protocol を読み込み、指摘として扱う前に、その Pre-Report Verification(および該当する問題の種類のセクション)を適用していること。 |
| G3 — 行アンカー | 各指摘で [FILE:LINE] を使用し、その行が現在のファイルに存在すること(推測ではなく、読み取り/grep の出力で確認済みであること)。 |
| G4 — 有効なパターンの確認 | 指摘を 有効なパターン(指摘しない) および コンテキスト依存のルール と照合していること。「指摘しない」ケースに該当する、または「次の場合にのみ指摘」の条件を満たさない場合は、報告しないこと。 |
問題の形式
各指摘には [FILE:LINE] ISSUE_TITLE を使用してください。
コメント
Markdown 対応