0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

「役割が不明なボタンは非表示でいいのでは?」に即答してはいけない — Laravel + laravel-adminで“唯一の導線”を追跡した記録

0
Posted at

環境情報

項目 内容
PHP 8.2
Laravel 10.x
encore/laravel-admin 1.8.x
MySQL 8.0
フロント Blade + AdminLTE 3
画面数 / データ量 管理画面 約40画面 / 会員 約12,000件
状況 仕様書なし・前任者退職済み・テストコードなし

何が起きたか

某会員管理システムの改修中、クライアントからこんな提案が飛んできました。

「このボタン、役割が分からないので非表示でいいのでは?」

対象は、会員一覧の行アクションに並ぶラベルだけの小さなボタンでした。押すと一覧が再描画されるだけで、画面上はほとんど何も変わりません。仕様書はなく、前任者は不在。即答は危険だと判断して「一度持ち帰ります」と保留しました。

結論から言うと、このボタンを非表示にすると、完全削除機能そのものが使えなくなるという危険な提案でした。コードを追った結果、当該ボタンは「ソフト無効化」を実行するもので、完全削除ボタンを表示させる唯一の導線だったのです。

なぜ「見た目」で判断してはいけないのか

管理画面のUIは、フレームワークが提供する描画ロジックの上に乗っています。laravel-admin の場合、行アクションは次のように条件分岐で出し分けられます。

// app/Admin/Controllers/MemberController.php
$grid->actions(function ($actions) {
    $model = $actions->row;

    if (is_null($model->disabled_at)) {
        // こちらが「役割不明」と言われたボタン
        $actions->append(new SoftDisableAction());
    } else {
        // disabled_at が入っている行にしか描画されない
        $actions->append(new ForceDeleteAction());
    }
});

つまり ForceDeleteAction は、disabled_at が埋まっている行にしか存在しません。そして disabled_at を埋められるのは SoftDisableAction だけ。ボタンを消す = 状態遷移の入口を塞ぐ = 後続のボタンが永遠に現れない、という構造でした。

// app/Admin/Actions/Grid/SoftDisableAction.php
namespace App\Admin\Actions\Grid;

use Encore\Admin\Actions\RowAction;
use Illuminate\Database\Eloquent\Model;

class SoftDisableAction extends RowAction
{
    public $name = '無効化';

    public function handle(Model $model)
    {
        $model->disabled_at = now();
        $model->save();

        return $this->response()
            ->success('無効化しました。再読み込みすると完全削除が選べます。')
            ->refresh();
    }
}
// app/Admin/Actions/Grid/ForceDeleteAction.php
class ForceDeleteAction extends RowAction
{
    public $name = '完全削除';

    public function handle(Model $model)
    {
        $model->forceDelete(); // SoftDeletes を貫通する
        return $this->response()->success('完全削除しました。')->refresh();
    }
}

調査手順(実際にやった5ステップ)

  1. ルーティングをgrepしてエンドポイントを特定する
  2. 表示中HTMLから data-url / form action を拾い、遷移先を確定する
  3. コントローラ → RowAction → Model → migration の順に追う
  4. DBの実データで「押された形跡」を確認する
  5. 他画面からの遷移・権限・バッチなど依存関係を洗う

Step 1: ルーティングを探す

grep -rn "member" routes/admin.php
php artisan route:list | grep -i member

Step 4: データで裏を取る

ここが一番効きました。「使われていないのでは」という仮説を、事実で潰します。

SELECT
  COUNT(*) AS total,
  COUNT(disabled_at) AS disabled_cnt,
  SUM(CASE WHEN disabled_at IS NOT NULL AND deleted_at IS NOT NULL THEN 1 ELSE 0 END) AS force_deleted_cnt
FROM members;

結果は total 12,480 / disabled_cnt 1,203 / force_deleted_cnt 87完全削除された87件は、すべて無効化を経由していることが確認できました。非表示にすれば、この運用フローが丸ごと止まります。

非表示にした場合の比較

観点 非表示にする 残す
完全削除 到達不能になる 従来どおり可能
誤操作リスク 下がる 変わらない(要改善)
法令対応(削除請求) 対応手段が消える 維持できる
改修コスト 小(ラベル改善のみ)
将来の復旧 気づくまで誰も困らない 影響なし

ハマりポイント

  • $grid->disableDelete()$actions->disableDelete() は別物。前者は一括削除、後者は行アクション。混同すると「消したつもりで消えていない」
  • $actions->row でリレーションを触るとN+1が発生する。with() を忘れずに
  • カスタムアクションはPOSTで飛ぶ。CSRF・ミドルウェア・権限(Admin::user()->can())を確認する
  • Blade側に @can で隠しているケースもあり、PHPだけ読むと見落とす
  • 設定キャッシュ(php artisan config:clear)を忘れて「反映されない」とハマる

最終的に提案した2ステップ運用ルール

  1. 無効化 → 30日後に完全削除(誤操作の取り消し猶予を確保)
  2. 完全削除は管理者2名の承認を必須にする

ボタンは残し、ラベルを「無効化(→30日後に削除可能)」に変更して意味を明示しました。

FAQ

Q. 使われていないボタンは消すべきでは?
A. 「使われていない」をデータで証明できてからです。updated_at やフラグ列の分布を見れば数分で検証できます。

Q. 仕様書がない場合はどうする?
A. ルーティング → コントローラ → アクション → モデル → migration の順に上から下へ追うのが最短です。

Q. 最短で“重要度”を見極める方法は?
A. 「そのボタンを消したとき、他のボタンやバッチが到達不能にならないか」を確認する。状態遷移の入口になっているボタンは消してはいけません。

まとめ

UIの見た目は、機能の要否を判断する材料になりません。特に管理画面の行アクションは、条件分岐で出し分けられる状態遷移の一部です。提案を受けたら、まずコードとデータを読み、影響範囲を確定させてから答える。これだけで「便利だから消した」という事故をかなり防げます。


この記事を書いた人

BENTEN Web Works — 業務自動化・システム開発のフリーランスエンジニアです。

GAS / Python / RPA を使った業務自動化や、Web制作・システム開発のご相談を承っています。
「こんなこと自動化できる?」というご質問だけでもお気軽にどうぞ。

👉 BENTEN Web Works — 詳細・お問い合わせはこちら
🐦 X(旧Twitter) — 日々の知見を発信中

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?