「刷新したい。でも止められない」——基幹システムの移行で最後まで残るのが、この一文です。一括カットオーバーで一晩に全部を切り替えるやり方は、止められる業務であれば成立します。けれども 24 時間稼働の現場では、止められる枠そのものが存在しないか、あってもごく短時間しか取れません。

本記事は、拠点 12 箇所で 24 時間動き続ける物流の基幹システムを、業務を止めずに新スタックへ刷新した実証ケーススタディです。鍵になったのは、ドメインを移行ウェーブに分ける設計と、業務ユーザー自身が旧画面と新画面を切り替えられる Feature Flag、そして並行運用から旧画面削除までを段階リリースで進める運用でした。費用半減を主題にしたレガシー刷新を通常見積もり半分でリプレイスした事例とは別軸で、「止めずに移行できるか」という検討層の最大の不安に絞って深掘りします。

プロジェクト概要

対象は、入荷・格納・在庫・出荷・配車・請求の 6 ドメインを抱える物流基幹システムでした。拠点 12 箇所、夜間も稼働する倉庫オペレーションを支えており、現場端末は約 150 台。稼働は文字どおり 24 時間 365 日で、計画停止枠は四半期に一度、しかも最大 90 分という制約でした。

旧システムは PHP で書かれたモノリスで、運用 8 年。ハンディターミナル連携や WMS との API が密結合になっており、1 ドメインの変更が他ドメインに波及するのが常態化していました。クライアントは「インフラ保守の終了が迫っているので刷新は不可避。ただし一晩で全部切り替えるのは絶対に避けたい」という明確な要望を持っていました。

そこで FIXIT は、フロントエンドを React + TypeScript、ドメイン API を Node.js + TypeScript に分割し、AI 駆動開発で実装を加速しつつ、移行そのものは段階リリースで進める方針を立てました。全体の期間は約 5 ヶ月、うち新旧を並行で動かす並行運用期間が 6 週間です。

課題: 業務停止枠が限られる中での刷新ジレンマ

このプロジェクトの本質的な難しさは、技術選定でも実装量でもなく、「切り替えのリスクをどう分散するか」にありました。整理すると課題は次の構図です。

計画停止枠が四半期に一度・最大 90 分しかないため、一括カットオーバーは現実的に不可能でした。仮に全ドメインを一晩で切り替えようとすると、データ移行・疎通確認・ロールバック判断のすべてを 90 分に収める必要があり、どこか 1 つでも想定外が起きれば翌朝のオペレーションが止まります。物流の現場が止まれば、その日の入出荷がそのまま遅延し、顧客への納品に直結します。

さらに、旧システムの仕様が属人化しており、「現場が当たり前に使っている裏ワザ的な運用」が大量に存在しました。これらはドキュメントに残っておらず、新システムで再現できているかを切り替え前に確認しきれません。一括移行ではこの確認が「本番一発勝負」になってしまいます。

結論として、リスクを時間軸に沿って薄く分散する以外に道はありませんでした。ドメインを小さく区切り、ウェーブごとに新旧を並行で動かし、現場が納得したら旧を消す。この段階移行を、止まらない前提で設計することがプロジェクトの中心命題になりました。段階移行の全体像はシステム刷新を段階的に進める手順ガイドで体系立てて解説していますが、本記事は実プロジェクトでどう運用したかに踏み込みます。

アプローチ1: ドメイン分割と移行ウェーブ設計

最初に着手したのは、6 ドメインの依存関係を洗い出し、安全に切り出せる順序を決めることでした。

Claude Code に旧 PHP リポジトリと DB スキーマ、過去 2 年分の障害チケットを読み込ませ、ドメイン間の参照関係と「変更が波及するホットスポット」を一覧化しました。人間だけで依存マップを引くと、暗黙の参照を見落として後から事故になりがちです。AI に参照箇所を行番号付きで列挙させ、人間が業務優先度で並べ替えるという協業で、移行順序の精度を上げています。

その結果、6 ドメインを 4 ウェーブに分割しました。

flowchart LR
  A[在庫] --> B[入荷]
  A --> C[出荷]
  B --> D[格納]
  C --> E[配車]
  C --> F[請求]

依存の根にあたる在庫ドメインを単独で最初のウェーブに置き、続いて入荷と格納、次に出荷と配車、最後に請求という順序です。請求を最後にしたのは、月次の締め処理という時間的制約があり、月初をまたぐ切り替えを避けたかったためでした。

ウェーブ設計で意識したのは、1 ウェーブを「90 分の停止枠なしで切り替えられる粒度」に保つことです。ドメインをまたぐデータ整合は新旧両 DB の双方向同期で吸収し、切り替え自体は画面単位で行えるように API を疎結合に設計しました。これにより、各ウェーブのリリースは深夜帯を狙う必要すらなく、業務時間中に少人数で切り替えられる状態になりました。

アプローチ2: 業務ユーザーが操作するFeature Flagの設計

段階リリースの心臓部が Feature Flag です。一般的な Flag は開発者がダッシュボードで切り替えるものですが、今回は現場の業務ユーザー自身が、画面上のトグルで旧 UI と新 UI を切り替えられる設計にしました。

LaunchDarkly をベースに、Flag の評価軸を「拠点」「ロール」「個人」の 3 階層にしています。たとえば在庫ドメインの新画面を、まず本社の在庫管理者 3 名だけに開放し、問題がなければ特定拠点の全ユーザーへ、最終的に全拠点へと、対象を段階的に広げられるようにしました。現場の担当者が「今日は新画面で試して、不安なら旧画面に戻す」という判断を自分でできることが、心理的な安全につながりました。

Flag を入れるコード自体は単純ですが、設計で効いたのは次の 3 点です。

  1. Flag の単位を機能ではなく業務画面に合わせました。現場の人が「この作業はこっち」と認識できる粒度にしないと、切り替え判断ができません。
  2. 新旧どちらの画面を使っても書き込み先のデータを一本化しました。新画面で登録した在庫が旧画面に反映されないと現場は混乱します。両 DB の同期で整合を保ち、見た目だけ切り替わるようにしています。
  3. Flag の状態を監視ダッシュボードに出し、どの拠点が新画面に何割移行したかを運用側が一目で追えるようにしました。

Flag の評価ロジックや同期処理は AI 駆動開発で素早く組みました。Claude Code に「拠点・ロール・個人の優先順位で評価する Flag ラッパー」を仕様として渡し、Vitest のテストを先に書いてから実装を生成させています。型を新旧 API で共有していたため、AI が整合性のあるコードを書きやすい土台が整っていました。

アプローチ3: 並行運用→旧画面削除の段階リリース運用

ウェーブと Flag が揃ったところで、実際のリリースは「並行運用してから旧を消す」という流れで回しました。各ウェーブで共通のリズムを設けています。

1 週目は、対象ドメインの新画面をベータ利用者 3〜5 名に開放し、旧画面と並行で稼働させます。ここでは新画面で実業務をしてもらい、現場の「裏ワザ運用」が再現できているかを洗い出します。2〜3 週目で対象拠点の全ユーザーへ開放し、旧画面も引き続き使える状態を維持。新旧のデータ差分を毎日自動で突き合わせ、不整合がゼロの日が一定期間続いたら旧画面の利用率を確認します。新画面の利用率が安定して高くなり、現場から戻したいという声が出なくなった段階で、はじめて旧画面を削除しました。

この運用で重要なのは、旧画面削除の判断基準を事前に数値で決めておくことです。今回は「新旧データ差分ゼロが連続 10 営業日」「新画面利用率 95% 以上が連続 5 営業日」という 2 つの条件を満たしたら旧画面を撤去する、と合意しておきました。基準を後から決めると、現場の不安と開発の都合がぶつかって意思決定が止まります。

データ移行は段階移行と並走する最大のリスクでした。双方向同期の整合をどう担保するか、リハーサルをどう設計するかはデータ移行と ETL リハーサルの実践プレイブックで詳述していますが、本案件でも移行スクリプトの生成と差分検証に AI を活用し、リハーサルを繰り返して同期のエッジケースを潰しました。

成果の実数値

段階リリースで進めた結果、業務を一度も止めずに全 6 ドメインの刷新を完了しました。主要な指標を整理します。

指標当初想定実績差分
計画停止時間 (移行による)90 分 × 4 回0 分-100%
並行運用期間 (全ウェーブ合計)想定 12 週6 週-50%
1 ウェーブの切り替え所要時間数時間30〜45 分大幅短縮
カットオーバー後の P1 障害想定 4〜61-80%
現場からの旧画面復帰要望延べ 3 件
機能リリース所要日数 (中央値)12 日2 日-83%

最も大きな成果は、移行を理由とした計画停止がゼロ分だった点です。各ウェーブの切り替えは業務時間中に少人数で行え、現場のオペレーションを一度も止めていません。並行運用期間は当初 12 週を見込んでいましたが、ドメインを小さく区切ったことで新旧データ差分が早期に安定し、合計 6 週で旧画面の撤去まで完了しました。

カットオーバー後の P1 障害は 1 件のみで、これも配車ドメインの帳票フォーマットに関する軽微なもので、旧画面に一時的に戻すことで現場影響なく解消しています。「戻せる」という設計が、障害時の被害を最小化しました。

再利用可能なナレッジと、ありがちな落とし穴

このプロジェクトで得た知見は、止められない基幹システムの移行に幅広く再利用できます。

ナレッジ1: リスクは「分散」できる。時間軸に薄く伸ばす

止められないシステムの移行は、リスクをゼロにはできません。できるのは、リスクを時間軸に沿って薄く分散することです。ドメインを小さく区切り、ウェーブごとに並行運用してから旧を消す。この発想に切り替えると、「一晩で全部切り替えられるか」という問いそのものが不要になります。

ナレッジ2: Feature Flag は現場の意思決定ツール

Flag を開発者の道具と捉えると、価値の半分しか引き出せません。業務ユーザーが自分で切り替えられる Flag は、現場が移行のオーナーになるための装置です。戻せる安心が、新画面への移行を現場主導で進める原動力になりました。

ナレッジ3: 旧の撤去基準を数値で先に決める

並行運用は楽ですが、放っておくと新旧の二重保守が永遠に続きます。「データ差分ゼロが連続何日」「新画面利用率何%が連続何日」という撤去基準を着手前に合意しておくことで、撤去の意思決定が淡々と進みました。

落とし穴1: 双方向同期を甘く見る

新旧並行運用の肝は両 DB の同期です。片方向だけの同期で済ませると、旧画面で更新したデータが新画面に反映されず現場が混乱します。同期のエッジケース (NULL 許容カラム、文字コード、タイムゾーン) はリハーサルで徹底的に洗い出すべきで、ここを省くと並行運用そのものが破綻します。

落とし穴2: ウェーブを大きく取りすぎる

並行運用の手間を惜しんで 1 ウェーブに 3 ドメイン以上を詰め込むと、切り替え判断が複雑になり「90 分なしで切り替えられる粒度」を超えてしまいます。粒度はあくまで小さく、ウェーブ数を増やしてでも 1 回の切り替えを軽くするほうが安全です。

落とし穴3: AI に旧仕様の要約を鵜呑みにさせる

属人化した旧仕様を AI に読み解かせるのは有効ですが、要約だけを信じると現場の裏ワザ運用が抜け落ちます。コードと障害チケットの両方を読ませ、要約に引用元の行番号を添えさせる運用にすると、現場が想定していた裏ワザ運用の取りこぼしをほぼ防げました。

よくある質問

Q. 24 時間稼働でも本当に無停止で移行できますか?

A. 条件次第で可能です。鍵はドメインを小さく区切り、新旧両 DB の双方向同期で整合を保ちながら画面単位で切り替えられるよう設計することです。本案件では移行を理由とした計画停止をゼロ分に抑えました。ただし「全機能を一晩で切り替える」前提だと無停止は困難です。段階リリースを前提にした設計が必須になります。

Q. 段階移行の費用と期間の目安は?

A. ドメイン数とデータ移行の難易度で変動しますが、本案件相当 (6 ドメイン、並行運用 6 週間) の規模で、1,500 万〜2,400 万円が 1 つの目安です (税抜)。一括カットオーバーに比べると並行運用とデータ同期のぶん工数は増えますが、業務を止めない価値と障害時のリスク低減を考えると、止められない基幹システムでは妥当な投資だと考えています。

Q. 並行運用の二重保守がずっと続く心配はありませんか?

A. 撤去基準を数値で先に合意しておくことで防げます。本案件では「新旧データ差分ゼロが連続 10 営業日」かつ「新画面利用率 95% 以上が連続 5 営業日」を旧画面撤去の条件としました。基準を事前に決めておくと、並行運用は一時的な状態にとどまり、ずるずると延びることがありません。

Q. AI 駆動開発は段階移行のどこで効きますか?

A. 旧仕様の読み解き、Feature Flag の評価ロジックや同期処理の実装、移行スクリプトの生成と差分検証で効果が大きいです。テストを先に書いて Claude Code に実装を生成させるスタイルで、新旧 API の型を共有しておくと整合性のあるコードが速く揃います。移行の戦術設計は人間が、定型的な実装と検証は AI が担う協業が現実的です。

止められない基幹システムをどう刷新するか、自社のケースで成立するかを具体的に検討したい方は、ぜひ一度ご相談ください。ドメイン分割や移行ウェーブの初期設計から、止めずに刷新する進め方を一緒に描きます。詳しくはシステム刷新サービスをご覧ください。