
Summary
この文書の要点
- 表示順は配列の位置ではなく永続化する順序値として持つ。
- ドラッグ中の一時状態と保存済み状態を分ける。
- 表示順は配列の位置ではなく、永続化しやすいsort_keyやpositionとして設計する。
- 画像アップロード、並び替え、削除を別々の操作として監査できるようにする。
どこが設計の難所か
画像一覧をドラッグで並べ替えるUIでは、フロントエンド上の配列順をそのまま保存しがちです。しかし、別ユーザーの更新、画像削除、アップロード直後の並び順、保存失敗を考えると単純ではありません。
画像ファイルはストレージにあり、メタデータはDBにあります。並び替えはファイル移動ではなくメタデータ更新です。また、ドラッグ操作が使いづらい利用者向けに代替操作も考える必要があります。
画像管理画面では、アップロードした画像を並べ替えるだけに見えても、複数ユーザーの編集、処理中サムネール、削除済み画像、保存前の並び順が混ざります。画面上の配列だけを真実にすると、更新競合で順序が壊れます。
境界をどう切るか
DBには画像ID、所有対象ID、表示順、状態、更新時刻を持たせます。React側ではドラッグ中の順序を一時状態として扱い、保存時に画像IDの配列をAPIへ送ります。API側で対象画像の集合が変わっていないか確認します。
設計では、画像本体、表示用メタデータ、並び順、処理状態を分けます。dnd-kitなどでUI操作を実装しても、APIへ送るのは全配列ではなく、移動対象と前後関係、または更新後のsort_keyにします。
実装で効く細部
dnd-kitなどを使う場合、ドラッグ終了時に一時順序を更新し、保存ボタンまたは自動保存でAPIへ送ります。APIではトランザクション内で順序を再採番し、存在しない画像IDや権限外画像を拒否します。
Laravel側では、imagesテーブルにstatus、sort_key、storage_key、checksumを持たせます。React側はドラッグ中の暫定順序と保存済み順序を分け、保存失敗時に元へ戻せるようにします。
- 連番positionは挿入や大量並び替えで更新範囲が広くなるため、間隔を持ったsort_keyを検討する。
- アップロード直後はprocessing状態として表示し、サムネール生成完了後にavailableにする。
- 削除は即物理削除ではなく、参照確認や取り消しを考慮して論理削除にする。
壊れ方を観測する
検証では、並び替え後の保存失敗、別ユーザーによる削除、画像追加直後の順序、キーボード操作、モバイル操作を確認します。E2Eでは並び順が再読み込み後も保たれることを見ます。
検証では、連続ドラッグ、保存失敗、別ユーザーが同時に並び替えた状態、処理中画像の移動を確認します。APIテストでは、存在しない画像IDや権限外画像が並び替え対象に混ざった場合も拒否します。
捨てた選択肢とトレードオフ
自動保存は操作が軽い一方で、通信失敗時の説明が難しくなります。保存ボタン方式は明確ですが手数が増えます。業務上の重要度と利用頻度で選ぶのが現実的です。
UIで即時反映すると操作感は良くなりますが、保存失敗時の復帰が必要です。保存完了まで反映しないと安全ですが、操作が重く感じます。楽観更新を使うなら、差分と元状態を必ず保持する設計が必要です。
現場に残す判断軸
並び替えUIは見た目の操作だけでなく、順序をどう永続化し、競合時にどう守るかが重要です。UI状態と保存済み状態を分けることで、扱いやすく壊れにくい画像管理になります。
画像の並び替えは、気持ちよいUIと壊れない順序管理を同時に考える領域です。画面の配列とDB上の順序を分けると、同時編集や失敗に強くなります。


