diff --git a/docs/spec/base/tools/JDCat_Master_Data_Migration_Design_Spec.md b/docs/spec/base/tools/JDCat_Master_Data_Migration_Design_Spec.md
new file mode 100644
index 00000000..003cae2e
--- /dev/null
+++ b/docs/spec/base/tools/JDCat_Master_Data_Migration_Design_Spec.md
@@ -0,0 +1,303 @@
+# JDCat マスタデータ移行プログラム 設計書
+
+対象システム: Weko3(JDCatインスタンス)
+対象作業: develop_v1.0.8系(+JDCat固有対応 `feature/jdcat_202601`)→ develop_v2.0.0 へのバージョンアップに伴うマスタデータ移行
+
+| 項目 | 内容 |
+|---|---|
+| 要求仕様 | 要求仕様:J2026-01_v4.docx |
+| 関連資料(別紙) | [別紙_v3.xlsx](attachments/別紙_v3.xlsx)(NII様提供資料。別紙1〜3を各シートに収録。1.3参照) |
+| 利用者マニュアル | [JDCat マスタデータ移行プログラム 利用者マニュアル](JDCat_Master_Data_Migration_Tool_Manual.md) |
+
+---
+
+# 1. 変更対象
+
+## 1.1 ソースコード追加対象
+
+https://github.com/RCOSDP/weko
+
+本移行は既存スクリプトを修正せず、新規の移行プログラム一式を `scripts/demo/jdcat_migration/` 配下に**追加**する。各ファイルの役割と本書内の記載箇所を下表に示す。
+
+| 記載箇所 | 追加ファイル |
+|----------|----------|
+| 3.2 | mapping_config.json(変換ルール設定ファイル。`convert_xlsx.py` の生成物。リポジトリ管理外の運用成果物) |
+| 4.1 | scripts/demo/jdcat_migration/convert_xlsx.py(xlsx回答→設定JSON変換ツール) |
+| 4.2 | scripts/demo/jdcat_migration/gen_properties.py(プロパティ定義 .py 生成補助ツール・開発時) |
+| 5(全体) | scripts/demo/jdcat_migration/__init__.py |
+| 5.1
5.3 | scripts/demo/jdcat_migration/config.py(設定JSON読込・検証) |
+| 5.2 | scripts/demo/jdcat_migration/migrate.py(CLIエントリ) |
+| 6(全体) | scripts/demo/jdcat_migration/engine.py(変換エンジン本体/フェーズ1〜3) |
+| 6.1(参考) | scripts/demo/properties/ 配下のプロパティ定義 `.py`(「新設」プロパティがある場合のみ) |
+| 6.3 | scripts/demo/jdcat_migration/report.py(dry-run/進捗/事後検証レポート) |
+
+## 1.2 代替対象(本プログラムが置き換える既存スクリプト)
+
+当初の移行依頼で実行予定だった次の4つの既存スクリプトを、本プログラムが置き換える。これらは新規構築環境を前提としており、JDCat本番に適用すると問題が生じるため、本プログラムに統合・再設計した(経緯は2.1参照)。各スクリプトの役割を下表に示す。
+
+| 既存スクリプト(実行コマンド) | 役割 |
+|----------|----------|
+| `scripts/demo/register_properties.py overwrite_all` | item_type_property の再登録(TRUNCATE→静的ファイルで全置換) |
+| `scripts/demo/renew_all_item_types.py only_specified ALL` | 全item_typeのproperty/mapping情報の再読込 |
+| `scripts/demo/update_itemtype_multiple.py` | Multiple系item_typeのproperty/mapping書き換え(別紙3相当) |
+| `scripts/demo/fix_issue_47128_jdcat.py` | 旧item/cus_プロパティID変換(別紙1・別紙2相当)※item/records_metadata変換は本プログラムでは行わない(2.4参照) |
+
+
+
+## 1.3 関連資料(別紙の定義)
+
+変換ルールの参考資料として、NII様提供の [`別紙_v3.xlsx`](attachments/別紙_v3.xlsx) を参照する。本書で「別紙1」「別紙2」「別紙3」と記載するものは、いずれも同ファイル内の各シートを指す。
+
+| シート | 内容 | 本プログラムでの扱い |
+|---|---|---|
+| 別紙1 | v2.0.0に伴う識別子(subitemキー)の変更仕様。 | 検証の正本。subitemキーは Phase2 の `reload()` が `properties/*.py` から再構成するため別紙1を直接は適用しないが、**`properties/*.py` のsubitem構造が別紙1どおりか**の検証に用いる(6.2前提条件)。 |
+| 別紙2 | 「現在のitemキー / 項目タイトル(プロパティID) / 変換先プロパティ構造(subitem構成と型)」の定義。主に Harvesting DDI(20) と構造系フィールド。select値は `properties/property_config.py` を参照。 | 参考。①itemキー変換・③プロパティID変換の妥当性検証に使用。 |
+| 別紙3 | v2.0.0で値が追加され、ハーベストでの値取得対応が必要な項目(作成者・寄与者・権利情報・助成情報 等)の要件一覧。 | 参考。記載の要件は v2.0.0 のプロパティ定義(`properties/*.py`)・mappingに反映済みで、Phase2 の `reload()` を通じて適用される(③ update_itemtype_multiple 相当)。本プログラムは別紙3を直接読み込まない。 |
+
+※ [`別紙_v3.xlsx`](attachments/別紙_v3.xlsx) はNII様提供資料。
+
+
+
+---
+
+# 2. 変更概要
+
+## 2.1 背景
+
+JDCatを `develop_v2.0.0` ベースへバージョンアップするにあたり、DDL変更・マスタデータ変更等の各種移行対応が必要となる。本書はそのうち**マスタデータ(item_type / item_type_property / item_type_mapping)の移行**を対象とする。
+
+当初、NII様からは「1.2 代替対象」の4つの既存スクリプトを順に実行する移行が依頼された。しかし事前調査(`変換ツールの調査結果.xlsx`、および本番相当DBの実態調査)により、以下の問題が判明した。
+
+- これらのスクリプトは「**新規構築(newbuild)環境=静的ファイルの定義=DBの実状態**」という前提で作られており、JDCat本番のように**独自の `item_type_property.id` 体系・独自プロパティを持つ既存DB**に適用すると、ID不一致と全置換によりデータを破壊する。
+ - 本番DB調査の結果、`item_type_property` 全139件のうち**136件(97.8%)がJDCat独自ID**(3〜176, 10001〜10011)で、標準静的定義のID(123, 301-316, 1001-1057, 3001-3021)とほぼ重複しない。
+ - `register_properties.py overwrite_all` の TRUNCATE により、この136件の独自プロパティが消失し、参照する全item_typeが破損する。
+ - `update_itemtype_multiple.py` は `item_type_property.id` を基準に処理するため、本番と静的定義でIDが異なり、実行するとデータが壊れる。
+
+以上より、**既存4スクリプトを置き換える、新規の移行プログラムを作成する**こととなった。本プログラムは、JDCat本番のID体系・独自プロパティを破壊せず、変換ルールを外部ファイルに切り出した**設定駆動・非破壊・冪等**な方式とする。
+
+## 2.2 基本方針
+
+| 方針 | 内容 |
+|---|---|
+| マスタデータのみ対象 | 本プログラムは `item_type` / `item_type_property` / `item_type_mapping` の移行のみを行う。**登録済みメタデータ(item_metadata / records_metadata)は更新しない**(2.4参照)。 |
+| 設定駆動 | 変換ルールを**外部ファイル(JSON:`mapping_config.json`)に集約**する。プログラム本体は汎用エンジンとし、ルール変更時にコード修正を不要とする。 |
+| 非破壊 | `item_type_property` を **TRUNCATEしない**。v2.0.0標準プロパティはUPDATEで更新し、JDCat独自プロパティと共存させる(独自IDと標準IDは数値域が重複しないため安全)。 |
+| 冪等 | 変換済み(新キー形式)のitem_typeはスキップする。**再実行を安全に行える**。 |
+| 安全 | dry-run(無更新の事前確認)・実行前バックアップ(運用手順。5.3)・トランザクション・失敗の記録継続。 |
+| 検証可能 | 実行前(dry-run)・実行後(旧キー残存0件・未知プロパティ参照0件)のレポートを出力する。 |
+
+## 2.3 対象範囲
+
+- 対象 item_type: **12(Multiple) / 20(Harvesting DDI)** のみ(既存スクリプト踏襲。本番DBに実在することを確認済み)。
+
+
+## 2.4 メタデータの扱い(重要)
+
+**登録済みメタデータ(`item_metadata` / `records_metadata`)は本プログラムでは変換・更新しない。**
+
+- バージョンアップ後、Wekoのハーベスト機能(**OAI-PMH / ResourceSync**)でメタデータを取得し直すため、既存メタデータをプログラムで個別変換する必要がない。
+- したがって本プログラムは、ハーベストの取り込み先となる **item_type定義・mapping・プロパティ(マスタデータ)を v2.0.0 形へ整える**ことに専念する。整備後、再ハーベストにより v2.0.0 構造でメタデータが再生成される。
+- これに伴い、旧設計にあった「メタデータ1件ごとのキー/subitem/値変換」(subitemキー変換②・構造変換 `transforms.py`・値変換 `value_maps`)は**不要となり、本設計から除外した**。
+
+
+
+---
+
+# 3. 入出力
+
+## 3.1 変換ルールの入力元(NII様回答資料)
+
+変換ルールは、NII様に記入いただく次のExcelを正本とする。
+
+- ファイル: `マッピング必要データ_XXXXXXXX.xlsx`(`XXXXXXXX` は版日付。例: `マッピング必要データ_20260423.xlsx`)
+- 各シート(「変更後」列を item_type 12/20 分のみ記入)と、本プログラムでの扱い:
+
+| シート | 内容(列) | 本プログラムでの扱い |
+|---|---|---|
+| item | 旧itemトップキー(`item_15xxxx`)→ 列「変更後」(=prop_name)、列「item_type_ids」 | ① itemトップキー変換に使用 |
+| property | 旧プロパティID(列「旧id」)→ 列「変更後ID / 新id」 | ③ プロパティID変換に使用 |
+| subitem | 旧subitemキー → 列「変更後」(=新subitemキー)、列「item_type_ids」 | **`gen_properties.py`(4.2)の subitemキー変換に使用**。移行本体(Phase1〜3)では未使用(subitemキーは `reload()` が `properties/*.py` から再構成。6.2参照)。 |
+
+※ 上記のsubitemキー再構成は「`properties/*.py` の subitem 構造が v2.0.0仕様と一致していること」が前提となる。**別紙1・別紙2** は、`properties/*.py` がその仕様どおりかを確認する**検証の正本**として用いる(6.2 前提条件参照)。
+
+## 3.2 変換ルール設定ファイル `mapping_config.json`(プログラムの実入力)
+
+`マッピング必要データ_XXXXXXXX.xlsx` の回答内容を、変換ツール(4.1 `convert_xlsx.py`)でJSONへ変換したもの。本プログラムはこのJSONのみを参照して動作する。
+
+```jsonc
+{
+ "meta": { "source": "マッピング必要データ_20260423.xlsx", "target_item_types": [12, 20] },
+
+ // ③ propertyシート「旧id→新id」由来。render の input_type "cus_<旧>" を "cus_<新>" に変換する
+ "property_id_map": { "8": 1014, "17": 1010, "67": 1001, "176": 1017 /* ... */ },
+
+ // ① itemシート由来。item_type別に「旧itemトップキー → prop_name」
+ "item_key_map": {
+ "12": { "item_1551264308487": "title", "item_1636457801246": "identifier" /* ... */ },
+ "20": { "item_1551264308487": "title", "item_1586253224033": "unit_of_analysis" /* ... */ }
+ }
+}
+```
+
+## 3.3 出力(レポート)
+
+`report.py` が次を出力する(出力先・形式は実装時に確定)。
+
+- dry-runレポート: 変換対象(item_type 12/20)の件数、未マッピング識別子の一覧、想定変更内容。
+- 進捗ログ: フェーズごとの処理結果。
+- 事後検証レポート: item_type定義に旧キー(`item_15xxxx`)残存件数、未知プロパティ参照件数。
+- **対象なしの明記**: 各フェーズで処理対象が無い場合(例: Phase1 で UPDATE対象が無い)は、レポートにその旨(対象なし)を明記する。
+
+## 3.4 item_type定義に対する変換内容(itemキー変換・プロパティID変換)
+
+本プログラムは item_type 定義(schema/form/render/mapping)に対する2階層の変換のみを行う。いずれも `マッピング必要データ_XXXXXXXX.xlsx`「property」シートで決まる「旧プロパティID → 新プロパティID」の対応を起点として導出される。`render.meta_list[- ].input_type` の値 `"cus_"` の `` は `item_type_property.id` を指すため、③はpropertyシートと一対一で対応する。
+
+```
+起点: マッピング必要データ_XXXXXXXX.xlsx「property」シート(列「旧id」→「変更後ID/新id」)
+ │
+ ├─ ③ プロパティID変換 : render.meta_list[key].input_type の "cus_<旧id>" → "cus_<新id>"
+ └─ ① itemトップキー変換 : "item_15xxxx" → "item___<連番>"
+```
+
+- subitemキー・各プロパティの内部構造は、変換後に `ItemTypes.reload()` が `properties/*.py` のプロパティ定義から再構成するため、本プログラムが個別に変換することはない。
+- (メタデータ側の subitem/構造/値の変換は再ハーベストで対応するため対象外。2.4参照。)
+
+
+
+---
+
+# 4. 追加ファイルの詳細(ツール)
+
+## 4.1 scripts/demo/jdcat_migration/convert_xlsx.py(xlsx回答 → 設定JSON変換ツール)
+
+- 入力: 記入済み `マッピング必要データ_XXXXXXXX.xlsx`(item / property シート)。
+- 出力: `mapping_config.json`(3.2のスキーマ)。
+- 処理: 各シートを読み、レイヤー別(`property_id_map` / `item_key_map`)に整形する。未記入(#N/A)や不整合(itemシートの prop_name と propertyシートの新idが同一のv2.0.0プロパティを指していない等)を**警告として出力**する。
+
+
+
+## 4.2 scripts/demo/jdcat_migration/gen_properties.py(プロパティ定義 .py の生成補助ツール・開発時)
+
+`properties/*.py` を0から手書きする工数を抑えるため、現状DBの `item_type_property` を雛形に `properties/*.py` のドラフトを生成する**開発時ツール**。生成時に subitemキーを別紙1のマップで変換する。
+
+- 入力: DB接続、対象プロパティID、subitemキー変換マップ(`マッピング必要データ` の subitem シート/別紙1 由来)、出力先ディレクトリ。
+- 出力: 既存 `properties/*.py` と同体裁の `.py`(`property_id` / `name_ja`(=DBの `name`) / `schema()` / `form()` / `forms` / `mapping`(=`DEFAULT_MAPPING`) / `add()`)。`schema`/`form`/`forms` はDB値にsubitemキー変換を適用。文字列は**UTF-8**で出力する。
+- 確認済みのDB構造(実DB調査): `item_type_property` は `schema`/`form`/`forms`(JSONB)を持ち、**`mapping` カラムは持たない**。`schema` は `properties. = {type,title,format,(enum)}`、`form` は既に `parentkey.` 形式(reloadの `parentkey` 置換規約と一致)。構造が規則的なため機械生成が可能。
+- 位置づけ・注意:
+ - **開発時に `.py` のたたき台を作るための補助ツール**であり、移行本体(Phase1〜3)では使用しない。
+ - **主用途は「新設」プロパティのドラフト生成**。対応先が既存標準にあるプロパティは既存 `properties/*.py` を用いる(旧構造の再現を避けるため生成しない)。
+ - 別紙2/3が対象とするフィールドの v2.0.0定義は概ね既存 `properties/*.py` に揃っているため、本ツールの主対象(既存定義が無い新設プロパティ)で別紙2/3の追加対応が要るケースは少ない。該当する少数のみ、生成後に別紙2・別紙3を見て**手修正で補完・検証**する(現状DBは v1.0.8世代のため、v2.0.0の追加 subitem/値は自動では入らない)。
+ - `mapping` はDBに無いため `DEFAULT_MAPPING` を置く。JPCOAR等の実マッピングは別途設定する。
+ - 補助として、生成物と既存標準 `properties/*.py` を diff すれば「現状DB構造 vs v2.0.0標準」のズレを洗い出せる(検証に有用)。
+
+
+
+---
+
+# 5. プログラム構成
+
+## 5.1 ファイル構成
+
+```
+scripts/demo/jdcat_migration/
+ __init__.py
+ config.py # mapping_config.json の読込・スキーマ検証・整合チェック
+ convert_xlsx.py # xlsx回答 → mapping_config.json(4.1)
+ gen_properties.py # DB → properties/*.py ドラフト生成(開発時。4.2)
+ engine.py # 変換エンジン本体(フェーズ1〜3。6章)
+ migrate.py # CLIエントリ(invenio shell から実行)
+ report.py # dry-run / 進捗 / 事後検証レポート
+ JDCat_Master_Data_Migration_Design_Spec.md # 本書
+```
+
+依存するDB構造(本番相当DBで確認済み):
+- `item_type(schema jsonb, form jsonb, render jsonb)` … `render.meta_list[- ].input_type = "cus_"`
+- `item_type_mapping(item_type_id, mapping jsonb)`
+- `item_type_property(id, name, schema jsonb, form jsonb, forms jsonb, delflg)`
+- プロパティ定義: `scripts/demo/properties/.py`(`property_id`/`schema()`/`form()`/`forms`/`mapping`/`add()` を公開)
+
+※ `item_metadata` / `records_metadata` は本プログラムの更新対象外(2.4)。
+
+## 5.2 実行方法(scripts/demo/jdcat_migration/migrate.py)
+
+```
+invenio shell scripts/demo/jdcat_migration/migrate.py \
+ --config mapping_config.json --item-types 12,20 \
+ --dry-run
+```
+
+- `--config` : 3.2 の設定JSONファイルのパス
+- `--item-types` : 対象item_type(既定 12,20)
+- `--dry-run` : 無更新で検証・想定変更のみ出力(事前確認用。5.3)
+
+> **補足**: `invenio shell`(実体は IPython)経由では `--` フラグが IPython に横取りされスクリプトへ届かないため、本番実行時は環境変数(`JDCAT_*`)で引数を渡す。具体的なコマンド例は[利用者マニュアル](JDCat_Master_Data_Migration_Tool_Manual.md)を参照。
+
+
+
+## 5.3 実行前の準備・事前確認(運用手順)
+
+本プログラムの本実行(Phase1〜3)の前に、運用手順として次を実施する。
+
+1. **DBバックアップ取得**(手動・本プログラム対象外): 対象テーブル(`item_type` / `item_type_mapping` / `item_type_property`)を `pg_dump` 等で取得する。異常時はこのバックアップからリストアする(7章)。
+2. **dry-run実行で事前確認**: `migrate.py --dry-run` を実行し、次を確認する(DB無更新)。
+ - 設定JSON(`mapping_config.json`)の検証: 参照する新idに対応する property定義が `properties/` に存在するか/ID重複がないか/item_type 12・20 が実際に参照する全 `cus_` が `property_id_map` で網羅されているか(未網羅は警告一覧として出力)。
+ - 変換対象・未マッピング識別子・想定変更内容(**事前レポート**)。
+
+
+
+---
+
+# 6. 処理フェーズ(engine.py)
+
+## 6.0 処理フロー概要
+
+
+
+- 本実行(Phase1〜3)の前提として、DBバックアップ取得と dry-run による事前確認を運用手順で行う(5.3参照)。本実行時も開始時に設定JSONを検証し、不正があれば中断する。
+- **Timestamp更新の抑止**:`migrate.py` は実行全体を try/finally で囲み、開始時に `weko_records` の `Timestamp.before_update` イベントリスナーを一時解除、終了時に復元する。これにより移行に伴う更新で `item_type` / `item_type_property` / `item_type_mapping` の `updated` 列が自動書き換えされないようにする(newbuild の `update_W2025-29.py` と同方式)。
+- 移行後、メタデータは OAI-PMH / ResourceSync の**再ハーベスト**により v2.0.0 構造で再取得される(本プログラム対象外。2.4参照)。
+
+
+
+## 6.1 Phase 1: properties(register_properties.py の代替・非破壊)
+
+- TRUNCATEしない。`scripts/demo/properties/` の定義から**v2.0.0標準プロパティをUPDATEで更新**する。これにより不足している標準ID(123, 301-316, 1001-1057, 3001-3021)が追加される。
+- 新設プロパティは、`properties/` 配下に `.py` を追加し `properties/__init__.py` に取り込めば本フェーズで**自動的に登録**される(設定ファイルへの記載は不要)。JDCat独自プロパティは**この時点では残置**(Phase3で掃除)。
+- **UPDATE対象(追加・更新すべきプロパティ)が無い場合は、レポートに「対象なし」を明記する**(処理が空振りしたのか、対象が元々無いのかを判別できるようにする)。
+- UPDATEのため冪等。
+
+## 6.2 Phase 2: itemtype(renew_all_item_types.py / update_itemtype_multiple.py / fix_issue_47128_jdcat.py 前半の代替)
+
+対象 item_type 12/20 について:
+1. `render.meta_list[- ].input_type` を `property_id_map` で `cus_<旧>` → `cus_<新>` に置換(既に新IDならスキップ)。
+2. `item_key_map[]` から `id_match_key` を構築(旧itemキー → `item___<連番>`)。**既に `item__*` 形式ならスキップ**(冪等)。
+3. `schema` / `form` / `render` および `item_type_mapping.mapping` を旧→新キーで置換。
+4. `ItemTypes.reload(, mapping, [], 'ALL')` で対応先プロパティの schema/form/mapping を反映する(対象を12/20に限定し、他item_typeをWeko共通定義で無差別上書きしない)。subitemキー・プロパティ内部構造はこの `reload()` で `properties/*.py` から再構成される(schema/formは置換、mappingはプロパティ既定を土台に再構成。`update_mapping_without_static`)。
+- item_type単位でcommit。
+
+**前提条件(重要)**: 上記4の `reload()` は `properties/*.py` の内容をそのまま反映するため、**対象プロパティの `properties/*.py` が v2.0.0仕様(別紙1・別紙2の subitem 構造)と一致していること**が前提となる。新設プロパティや構造変更があるプロパティは、本実行前に `properties/*.py` を別紙1・別紙2どおりに整備・検証しておく必要がある。なお、新設プロパティの `.py` は `gen_properties.py`(4.2)で現状DBから雛形生成し(subitemキー変換込み)、別紙2・別紙3で補完・検証できる。
+
+## 6.3 Phase 3: verify & cleanup(report.py)
+
+- 検証: 対象item_typeの `item_type` 定義(schema/form/render/mapping)に旧 `item_15xxxx` の残存が0件、未知プロパティ参照が0件であること。
+- (opt-in)どの item_type からも参照されなくなったJDCat独自プロパティを論理削除(`delflg=true`)。
+- 事後レポートを出力する。
+
+
+
+---
+
+# 7. 冪等性・再実行・ロールバック
+
+- dry-run(`--dry-run`)により、DBを更新せず想定変更を事前確認できる(5.3)。
+- Phase1はUPDATE、Phase2はキー形式で「変換済み」を判定してスキップするため、**何度実行しても安全**。
+- **処理中にエラーが発生した場合は当該トランザクションがロールバックされ、DBは変更前の状態に保たれる**。通常のエラーはこれで回復し、冪等な再実行で続行できる(リストアは不要)。
+- バックアップ(5.3)からのリストアは、トランザクションのロールバックや再実行で回復できない**想定外の事態**(例: 部分コミット後の不整合・データ破損)に備えた**最終手段**である。
+
+
+
+---
+
+# 8. 性能
+
+- 処理対象はマスタデータ(プロパティ群+item_type 2件)のみで件数が小さく、性能上の懸念はない(メタデータ約14.9万件はハーベスト側で再取得するため本プログラムでは処理しない)。
diff --git a/docs/spec/base/tools/JDCat_Master_Data_Migration_Tool_Manual.md b/docs/spec/base/tools/JDCat_Master_Data_Migration_Tool_Manual.md
new file mode 100644
index 00000000..7649f828
--- /dev/null
+++ b/docs/spec/base/tools/JDCat_Master_Data_Migration_Tool_Manual.md
@@ -0,0 +1,268 @@
+# JDCat マスタデータ移行プログラム 利用者マニュアル
+
+対象システム: Weko3(JDCatインスタンス)
+対象作業: develop_v1.0.8系(+JDCat固有対応 `feature/jdcat_202601`)→ develop_v2.0.0 へのバージョンアップに伴うマスタデータ移行
+
+| 項目 | 内容 |
+|---|---|
+| 要求仕様 | 要求仕様:J2026-01_v4.docx |
+| 設計書 | [JDCat マスタデータ移行プログラム 設計書](JDCat_Master_Data_Migration_Design_Spec.md) |
+| 関連資料(別紙) | [別紙_v3.xlsx](attachments/別紙_v3.xlsx)(NII様提供資料。別紙1〜3を各シートに収録) |
+| English version | [User Manual (English)](JDCat_Master_Data_Migration_Tool_Manual_en.md) |
+
+本書は、移行プログラム一式(`scripts/demo/jdcat_migration/`)の**利用者向け操作手順**をまとめたものである。プログラムの設計思想・処理内容の詳細は[設計書](JDCat_Master_Data_Migration_Design_Spec.md)を参照すること。本書は設計書 **5章「プログラム構成」** を中心に、各ツールの実行方法を具体的に記載する。
+
+---
+
+# 1. このプログラムでできること
+
+JDCat(Weko3)を `develop_v1.0.8` 系から `develop_v2.0.0` へバージョンアップする際に必要となる、**マスタデータ(`item_type` / `item_type_property` / `item_type_mapping`)の移行**を行う。
+
+- 対象 item_type は **12(Multiple)/ 20(Harvesting DDI)** のみ。
+- 変換ルールは外部設定ファイル `mapping_config.json` に集約された**設定駆動**方式。
+- `item_type_property` を TRUNCATE しない**非破壊**・再実行可能な**冪等**方式。
+- **登録済みメタデータ(`item_metadata` / `records_metadata`)は変換しない**。移行後、OAI-PMH / ResourceSync による**再ハーベスト**で v2.0.0 構造のメタデータが再生成される(設計書 2.4)。
+
+> ⚠️ **注意**: 本プログラムはマスタデータのみを扱う。メタデータの再取得(再ハーベスト)は本プログラムの対象外であり、移行完了後に別途実施する。
+
+---
+
+# 2. 前提・実行環境
+
+## 2.1 実行場所
+
+移行本体(`migrate.py`)と開発補助ツール(`gen_properties.py`)は **Weko の web コンテナ内**で `invenio shell` を通じて実行する。設定ファイル生成ツール(`convert_xlsx.py`)は **DB非依存・stdlib のみ**のため、コンテナ外の素の `python3` でも実行できる。
+
+| ツール | 実行場所 | DB接続 |
+|---|---|---|
+| `convert_xlsx.py` | 任意(素の `python3` で可) | 不要 |
+| `gen_properties.py` | web コンテナ内(`invenio shell`) | 必要(開発時のみ) |
+| `migrate.py` | web コンテナ内(`invenio shell`) | 必要 |
+
+## 2.2 プログラムの配置
+
+移行プログラム一式を、Weko 本体の `scripts/demo/jdcat_migration/` 配下に配置する(web コンテナからは `/code/scripts/demo/jdcat_migration/` として見える)。
+
+```
+scripts/demo/jdcat_migration/
+ __init__.py
+ config.py # mapping_config.json の読込・スキーマ検証・整合チェック
+ convert_xlsx.py # xlsx回答 → mapping_config.json
+ gen_properties.py # DB → properties/*.py ドラフト生成(開発時)
+ engine.py # 変換エンジン本体(フェーズ1〜3)
+ migrate.py # CLIエントリ(invenio shell から実行)
+ report.py # dry-run / 進捗 / 事後検証レポート
+```
+
+## 2.3 【重要】invenio shell と引数の渡し方
+
+`invenio shell` の実体は **IPython** であり、`--config` などの `--` フラグを **IPython 自身が横取りしてしまう**(スクリプトへ届かない)。このため、`invenio shell` 経由で実行する `migrate.py` / `gen_properties.py` では、**引数を環境変数(`JDCAT_*`)で渡す**(IPython は環境変数を触らない)。
+
+- `invenio shell` 経由(本番の実行方法) → **環境変数で渡す**(`docker compose exec -e ...`)。
+- 素の `python` 実行(開発時、app context が別途必要) → `--` フラグが使える。
+
+以降のコマンド例はこの前提に従う。
+
+---
+
+# 3. 全体の流れ
+
+```
+[1] convert_xlsx.py … 記入済みxlsx → mapping_config.json を生成
+ │
+ (必要な場合のみ)
+[2] gen_properties.py … 新設プロパティの properties/*.py ドラフトを生成(開発時)
+ │
+[3] 事前準備 … DBバックアップ取得(pg_dump 等・手動)
+ │
+[4] migrate.py --dry-run … DB無更新で想定変更を事前確認
+ │
+[5] migrate.py(本実行) … Phase1〜3 を適用
+ │
+[6] レポート確認 … 総合判定・旧キー残0件・未知プロパティ参照0件 を確認
+```
+
+- **[2] は通常スキップ可**。新設プロパティのドラフト `.py` を作りたい開発時のみ使用する(設計書 4.2)。
+- **[3][4] は本実行前に必ず実施**する(設計書 5.3)。
+
+---
+
+# 4. 実行方法
+
+## 4.1 convert_xlsx.py(記入済みxlsx → 設定JSON生成)
+
+NII様に記入いただいた `マッピング必要データ_XXXXXXXX.xlsx` を、移行プログラムの実入力である `mapping_config.json` に変換する。
+
+### 入力・出力
+
+- **入力**: 記入済み `マッピング必要データ_XXXXXXXX.xlsx`(`item` / `property` シート)
+- **出力**: `mapping_config.json`(設計書 3.2 のスキーマ)
+
+### 実行コマンド
+
+DB非依存・stdlib のみのため、素の `python3` で単体実行できる。
+
+```bash
+python3 convert_xlsx.py マッピング必要データ_20260423.xlsx mapping_config.json \
+ --item-types 12,20
+```
+
+| 引数 | 説明 |
+|---|---|
+| 第1引数(`input`) | 記入済み `マッピング必要データ_*.xlsx`(必須) |
+| 第2引数(`output`) | 出力する `mapping_config.json` のパス(必須) |
+| `--item-types` | 対象item_type(カンマ区切り。既定 `12,20`) |
+
+### 出力・警告の確認
+
+- 標準エラーへ処理結果と警告を出力する。正常時は末尾に `OK: ... を出力(property_id_map N件 / item_key_map {...})` が表示される。
+- 未記入(`#N/A`)・不整合(旧id/新idが整数でない、prop_name が識別子形式でない、キー重複 等)は `[WARN]` として、シート欠落・ヘッダ不足などの致命的問題は `[ERROR]` として出力される。**`[ERROR]` がある場合は変換に失敗し、終了コード 1** を返す。警告は内容を確認のうえ、必要ならxlsxを修正して再実行する。
+
+> 生成された `mapping_config.json` は運用成果物であり、Weko リポジトリの管理対象外。移行本体(`migrate.py`)はこの JSON のみを参照して動作する。
+
+
+
+## 4.2 gen_properties.py(プロパティ定義 .py のドラフト生成・開発時)
+
+現状DBの `item_type_property` を雛形に、既存 `properties/*.py` と同契約のドラフト `.py` を生成する**開発時の補助ツール**。生成時に subitemキーを変換マップで置換する。**移行本体(Phase1〜3)では使用しない。**
+
+> ℹ️ **通常運用ではこのツールを使う必要はない**。既存標準にプロパティが揃っている場合は既存 `properties/*.py` を用いる。本ツールの主用途は「新設」プロパティのドラフト生成であり、生成物はあくまで**たたき台**(別紙2・別紙3 を見て手修正・検証する前提)である(設計書 4.2)。
+
+### 入力・出力
+
+- **入力**: DB接続、対象 property_id、subitemキー変換マップ(任意)、出力先ディレクトリ
+- **出力**: `properties/*.py` と同体裁のドラフト `.py`(UTF-8)。`mapping` は DB に無いため `DEFAULT_MAPPING` を仮置き。
+
+### 実行コマンド(invenio shell 経由・環境変数入力)
+
+```bash
+docker compose exec \
+ -e JDCAT_GEN_IDS=1042,305 \
+ -e JDCAT_GEN_OUT=scripts/demo/jdcat_migration/_gen \
+ -e JDCAT_GEN_SUBITEM=scripts/demo/jdcat_migration/subitem_map.json \
+ web invenio shell scripts/demo/jdcat_migration/gen_properties.py
+```
+
+| 環境変数 | 説明 |
+|---|---|
+| `JDCAT_GEN_IDS` | 生成対象 property_id(カンマ区切り。**必須**) |
+| `JDCAT_GEN_OUT` | 出力ディレクトリ(**必須**。無ければ作成) |
+| `JDCAT_GEN_SUBITEM` | subitemキー変換マップ(`.json`=`{旧:新}` または `.xlsx`)。任意 |
+| `JDCAT_GEN_SUBITEM_SHEET` | xlsx時のシート名(既定 `subitem`) |
+
+### 生成後の作業
+
+1. 生成された `.py` の先頭には `★GENERATED DRAFT(要手修正)★` が付く。
+2. `mapping`・`name_en`・`multiple_flag` はDBから確定できないため、別紙2・別紙3 を見て**手修正・検証**する。
+3. 確定した `.py` を `properties/` 配下へ置き、`properties/__init__.py` に取り込むと、`migrate.py` の **Phase1 で自動的に登録**される。
+4. 補助として、生成物と既存標準 `properties/*.py` を diff すれば「現状DB構造 vs v2.0.0標準」のズレを確認できる。
+
+
+
+## 4.3 migrate.py(移行本体)
+
+`mapping_config.json` を入力に、対象 item_type(12/20)のマスタデータを v2.0.0 形へ移行する。
+
+### 4.3.1 実行前の準備(設計書 5.3)
+
+本実行の前に、運用手順として次を必ず実施する。
+
+1. **DBバックアップ取得**(手動・本プログラム対象外): 対象テーブル(`item_type` / `item_type_mapping` / `item_type_property`)を `pg_dump` 等で取得する。異常時はここからリストアする。
+2. **dry-run で事前確認**(次項): DB無更新で設定JSONの検証・想定変更内容を確認する。
+
+### 4.3.2 dry-run(DB無更新の事前確認)
+
+まず必ず dry-run で想定変更を確認する。
+
+```bash
+docker compose exec \
+ -e JDCAT_CONFIG=scripts/demo/jdcat_migration/mapping_config.json \
+ -e JDCAT_ITEM_TYPES=12,20 \
+ -e JDCAT_PHASE=all \
+ -e JDCAT_DRY_RUN=1 \
+ web invenio shell scripts/demo/jdcat_migration/migrate.py
+```
+
+### 4.3.3 本実行
+
+dry-run の内容に問題が無ければ、`JDCAT_DRY_RUN` を外して(または `0` にして)本実行する。
+
+```bash
+docker compose exec \
+ -e JDCAT_CONFIG=scripts/demo/jdcat_migration/mapping_config.json \
+ -e JDCAT_ITEM_TYPES=12,20 \
+ -e JDCAT_PHASE=all \
+ web invenio shell scripts/demo/jdcat_migration/migrate.py
+```
+
+### 4.3.4 環境変数一覧
+
+| 環境変数 | 説明 |
+|---|---|
+| `JDCAT_CONFIG` | 設定JSON(`mapping_config.json`)のパス(**必須**) |
+| `JDCAT_ITEM_TYPES` | 対象item_type(カンマ区切り。既定は設定の `target_item_types`) |
+| `JDCAT_PHASE` | 実行フェーズ `all` / `1` / `2` / `3` / `pre`(既定 `all`) |
+| `JDCAT_DRY_RUN` | `1`/`true`/`yes` で dry-run(DB無更新) |
+| `JDCAT_CLEANUP` | `1`/`true`/`yes` で Phase3 の論理削除(opt-in) |
+| `JDCAT_REPORT_OUT` | レポート出力先ファイル(未指定は標準出力/ログ) |
+
+- `JDCAT_PHASE` の `pre` は実行前検証(設定JSON × DB)のみを行う。`1`/`2`/`3` は各フェーズ単独実行。
+- `JDCAT_CLEANUP` は、どの item_type からも参照されなくなった JDCat 独自プロパティを論理削除(`delflg=true`)する。既定では実行しない(opt-in)。
+
+### 4.3.5 処理フェーズの概要(設計書 6章)
+
+| フェーズ | 内容 |
+|---|---|
+| Phase 1 | properties(非破壊UPSERT)。`properties/` の定義から v2.0.0 標準プロパティを UPDATE で更新。独自プロパティは残置。 |
+| Phase 2 | itemtype。`render` の `cus_<旧id>` → `cus_<新id>` 置換(③)、旧itemキー → 新itemキー置換(①)、`ItemTypes.reload()` でプロパティ定義を反映。 |
+| Phase 3 | verify & cleanup。旧キー残存0件・未知プロパティ参照0件 を検証。(opt-in で独自プロパティを論理削除) |
+
+- `migrate.py` は実行全体を try/finally で囲み、`weko_records` の `Timestamp.before_update` リスナーを一時解除→復元する(マスタテーブルの `updated` 列を汚さないため)。
+
+### 4.3.6 素の python 実行(開発時のみ)
+
+app context が別途用意できる開発環境では `--` フラグが使える。
+
+```bash
+python migrate.py --config mapping_config.json --item-types 12,20 \
+ --phase all --dry-run
+```
+
+| 引数 | 対応する環境変数 |
+|---|---|
+| `--config` | `JDCAT_CONFIG` |
+| `--item-types` | `JDCAT_ITEM_TYPES` |
+| `--phase` | `JDCAT_PHASE` |
+| `--dry-run` | `JDCAT_DRY_RUN` |
+| `--cleanup` | `JDCAT_CLEANUP` |
+| `--report-out` | `JDCAT_REPORT_OUT` |
+
+---
+
+# 5. レポートの見方
+
+`migrate.py` は実行後にテキストレポートを出力する(`JDCAT_REPORT_OUT` 指定時はファイルへ、未指定時は標準出力/ログへ)。主な確認ポイントは次のとおり。
+
+- **モード**: `dry-run(DB無更新)` か `本実行` か。
+- **実行前検証(設定JSON × DB)**: `[ERROR]` があると移行は中断される。`[WARN]` は内容を確認する。
+- **Phase1**: UPSERT対象の件数(追加/更新)。対象が無い場合は「対象なし」と明記される。
+- **Phase2**: item_type ごとに ③(プロパティID変換)件数・①(itemキー変換)件数、`reload` の結果コード。「変換済み/冪等スキップ」表示は既に移行済みの意味。
+- **Phase3**: item_type ごとに `OK`/`NG`、**旧キー残存件数**・**未知プロパティ参照件数**。両方 0 かつ `OK` が正常。
+- **総合判定**: 末尾に `dry-run 完了` / `本実行 完了` と「問題は検出されませんでした」もしくは要確認事項が表示される。
+
+> ✅ 移行成功の目安: 総合判定が「問題は検出されませんでした」、Phase3 が全 item_type で `OK`(旧キー残0件・未知プロパティ参照0件)。
+
+---
+
+# 6. 再実行・トラブル時の対応(設計書 7章)
+
+- **冪等**: Phase1 は UPDATE、Phase2 はキー形式で「変換済み」を判定してスキップするため、**何度実行しても安全**。dry-run → 本実行の順で進める。
+- **エラー時のロールバック**: 処理中にエラーが発生した場合、当該トランザクションはロールバックされ、DBは変更前の状態に保たれる。通常のエラーはこれで回復し、冪等な再実行で続行できる(リストア不要)。
+- **バックアップからのリストア**: トランザクションのロールバックや再実行で回復できない**想定外の事態**(部分コミット後の不整合・データ破損等)に備えた**最終手段**。事前取得したバックアップ(4.3.1)からリストアする。
+
+---
+
+# 7. 移行後の作業
+
+- マスタデータ移行の完了後、**メタデータは OAI-PMH / ResourceSync による再ハーベスト**で v2.0.0 構造として再取得される(本プログラム対象外。設計書 2.4)。
+- 移行本体はマスタデータ(`item_type` 定義・mapping・プロパティ)を整えることに専念しており、メタデータ個別変換は行わない点に留意する。
diff --git a/docs/spec/base/tools/JDCat_Master_Data_Migration_Tool_Manual_en.md b/docs/spec/base/tools/JDCat_Master_Data_Migration_Tool_Manual_en.md
new file mode 100644
index 00000000..10a13412
--- /dev/null
+++ b/docs/spec/base/tools/JDCat_Master_Data_Migration_Tool_Manual_en.md
@@ -0,0 +1,268 @@
+# JDCat Master Data Migration Program — User Manual
+
+Target system: Weko3 (JDCat instance)
+Target work: Master data migration for the version upgrade from the develop_v1.0.8 line (+ JDCat-specific support `feature/jdcat_202601`) to develop_v2.0.0
+
+| Item | Content |
+|---|---|
+| Requirement specification | Requirement Spec: J2026-01_v4.docx |
+| Design document | [JDCat Master Data Migration Program — Design Document](JDCat_Master_Data_Migration_Design_Spec.md) |
+| Related material (appendix) | [別紙_v3.xlsx](attachments/別紙_v3.xlsx) (provided by NII. Contains 別紙1–3 in separate sheets) |
+| Japanese version | [利用者マニュアル(日本語)](JDCat_Master_Data_Migration_Tool_Manual.md) |
+
+This document summarizes the **operating procedures for end users** of the migration program set (`scripts/demo/jdcat_migration/`). For the detailed design rationale and processing internals, refer to the [Design Document](JDCat_Master_Data_Migration_Design_Spec.md). This manual centers on **Chapter 5, "Program Structure"** of the design document, describing the concrete execution method for each tool.
+
+---
+
+# 1. What this program does
+
+It performs **migration of master data (`item_type` / `item_type_property` / `item_type_mapping`)** required when upgrading JDCat (Weko3) from the `develop_v1.0.8` line to `develop_v2.0.0`.
+
+- Target item types are **12 (Multiple) / 20 (Harvesting DDI)** only.
+- The conversion rules are consolidated into an external configuration file `mapping_config.json` — a **configuration-driven** design.
+- A **non-destructive**, re-runnable, **idempotent** design that does **not** TRUNCATE `item_type_property`.
+- **Registered metadata (`item_metadata` / `records_metadata`) is not converted.** After migration, metadata in v2.0.0 structure is regenerated via **re-harvesting** through OAI-PMH / ResourceSync (Design Document 2.4).
+
+> ⚠️ **Note**: This program handles master data only. Metadata re-acquisition (re-harvesting) is out of scope for this program and is performed separately after migration completes.
+
+---
+
+# 2. Prerequisites and Execution Environment
+
+## 2.1 Where to run
+
+The migration core (`migrate.py`) and the development-support tool (`gen_properties.py`) are run **inside the Weko web container** via `invenio shell`. The configuration-file generator (`convert_xlsx.py`) is **DB-independent and stdlib-only**, so it can also run with plain `python3` outside the container.
+
+| Tool | Where to run | DB connection |
+|---|---|---|
+| `convert_xlsx.py` | Anywhere (plain `python3` is fine) | Not required |
+| `gen_properties.py` | Inside web container (`invenio shell`) | Required (development only) |
+| `migrate.py` | Inside web container (`invenio shell`) | Required |
+
+## 2.2 Placement of the program
+
+Place the migration program set under `scripts/demo/jdcat_migration/` of the Weko main body (visible from the web container as `/code/scripts/demo/jdcat_migration/`).
+
+```
+scripts/demo/jdcat_migration/
+ __init__.py
+ config.py # Loads / schema-validates / consistency-checks mapping_config.json
+ convert_xlsx.py # xlsx answers -> mapping_config.json
+ gen_properties.py # DB -> properties/*.py draft generation (development)
+ engine.py # Conversion engine core (Phases 1-3)
+ migrate.py # CLI entry point (run from invenio shell)
+ report.py # dry-run / progress / post-verification report
+```
+
+## 2.3 [Important] `invenio shell` and how to pass arguments
+
+The actual implementation of `invenio shell` is **IPython**, which **intercepts `--` flags such as `--config` itself** (they never reach the script). For this reason, `migrate.py` / `gen_properties.py`, which are run via `invenio shell`, **pass arguments through environment variables (`JDCAT_*`)** (IPython does not touch environment variables).
+
+- Via `invenio shell` (the production method) → **pass via environment variables** (`docker compose exec -e ...`).
+- Plain `python` execution (development, requires a separately prepared app context) → `--` flags can be used.
+
+The command examples below follow this premise.
+
+---
+
+# 3. Overall flow
+
+```
+[1] convert_xlsx.py ... filled-in xlsx -> generate mapping_config.json
+ |
+ (only when needed)
+[2] gen_properties.py ... generate properties/*.py drafts for new properties (development)
+ |
+[3] Preparation ... take a DB backup (pg_dump etc., manual)
+ |
+[4] migrate.py --dry-run ... pre-check intended changes without updating the DB
+ |
+[5] migrate.py (real run) ... apply Phases 1-3
+ |
+[6] Check the report ... confirm overall judgment / 0 remaining old keys / 0 unknown property references
+```
+
+- **[2] can normally be skipped.** Use it only during development when you want to create draft `.py` files for new properties (Design Document 4.2).
+- **[3][4] must always be performed before the real run** (Design Document 5.3).
+
+---
+
+# 4. Execution methods
+
+## 4.1 convert_xlsx.py (filled-in xlsx -> generate config JSON)
+
+Converts `マッピング必要データ_XXXXXXXX.xlsx`, filled in by NII, into `mapping_config.json`, which is the actual input to the migration program.
+
+### Input / Output
+
+- **Input**: filled-in `マッピング必要データ_XXXXXXXX.xlsx` (`item` / `property` sheets)
+- **Output**: `mapping_config.json` (schema in Design Document 3.2)
+
+### Command
+
+Because it is DB-independent and stdlib-only, it can run standalone with plain `python3`.
+
+```bash
+python3 convert_xlsx.py マッピング必要データ_20260423.xlsx mapping_config.json \
+ --item-types 12,20
+```
+
+| Argument | Description |
+|---|---|
+| 1st arg (`input`) | filled-in `マッピング必要データ_*.xlsx` (required) |
+| 2nd arg (`output`) | path of the `mapping_config.json` to output (required) |
+| `--item-types` | target item types (comma-separated; default `12,20`) |
+
+### Checking output and warnings
+
+- Processing results and warnings are written to standard error. On success, the last line shows `OK: ... を出力(property_id_map N件 / item_key_map {...})`.
+- Unfilled cells (`#N/A`) and inconsistencies (old/new id not an integer, prop_name not in identifier form, duplicate keys, etc.) are emitted as `[WARN]`; fatal problems such as a missing sheet or missing header are emitted as `[ERROR]`. **If there is any `[ERROR]`, conversion fails and returns exit code 1.** Review the warnings and, if needed, fix the xlsx and re-run.
+
+> The generated `mapping_config.json` is an operational artifact and is not managed in the Weko repository. The migration core (`migrate.py`) operates by referencing only this JSON.
+
+
+
+## 4.2 gen_properties.py (property definition .py draft generation — development)
+
+A **development-time helper tool** that generates draft `.py` files with the same contract as existing `properties/*.py`, using the current DB `item_type_property` as templates. It replaces subitem keys with a conversion map during generation. **It is not used by the migration core (Phases 1-3).**
+
+> ℹ️ **In normal operation, you do not need to use this tool.** When properties already exist in the standard set, use the existing `properties/*.py`. The main use of this tool is draft generation for "new" properties, and its output is only a **starting draft** (assumed to be manually corrected/verified against 別紙2 and 別紙3) (Design Document 4.2).
+
+### Input / Output
+
+- **Input**: DB connection, target property_ids, subitem-key conversion map (optional), output directory
+- **Output**: draft `.py` in the same style as `properties/*.py` (UTF-8). Since `mapping` is not in the DB, `DEFAULT_MAPPING` is placed as a placeholder.
+
+### Command (via invenio shell — environment-variable input)
+
+```bash
+docker compose exec \
+ -e JDCAT_GEN_IDS=1042,305 \
+ -e JDCAT_GEN_OUT=scripts/demo/jdcat_migration/_gen \
+ -e JDCAT_GEN_SUBITEM=scripts/demo/jdcat_migration/subitem_map.json \
+ web invenio shell scripts/demo/jdcat_migration/gen_properties.py
+```
+
+| Environment variable | Description |
+|---|---|
+| `JDCAT_GEN_IDS` | property_ids to generate (comma-separated; **required**) |
+| `JDCAT_GEN_OUT` | output directory (**required**; created if it does not exist) |
+| `JDCAT_GEN_SUBITEM` | subitem-key conversion map (`.json` = `{old:new}` or `.xlsx`). Optional |
+| `JDCAT_GEN_SUBITEM_SHEET` | sheet name for xlsx (default `subitem`) |
+
+### Work after generation
+
+1. The head of each generated `.py` carries `★GENERATED DRAFT(要手修正)★` (generated draft — requires manual correction).
+2. Because `mapping` / `name_en` / `multiple_flag` cannot be determined from the DB, **manually correct and verify** them against 別紙2 and 別紙3.
+3. Place the finalized `.py` under `properties/` and register it in `properties/__init__.py`; it will then be **registered automatically in Phase 1 of `migrate.py`**.
+4. As an aid, diffing the generated output against the existing standard `properties/*.py` reveals the gap between "current DB structure vs. v2.0.0 standard".
+
+
+
+## 4.3 migrate.py (migration core)
+
+Using `mapping_config.json` as input, migrates the master data of the target item types (12/20) to the v2.0.0 form.
+
+### 4.3.1 Preparation before the run (Design Document 5.3)
+
+Before the real run, always perform the following as operational steps.
+
+1. **Take a DB backup** (manual; out of scope for this program): take the target tables (`item_type` / `item_type_mapping` / `item_type_property`) with `pg_dump` etc. Restore from here if something goes wrong.
+2. **Pre-check with dry-run** (next section): confirm config-JSON validation and intended changes without updating the DB.
+
+### 4.3.2 dry-run (pre-check without DB update)
+
+Always confirm the intended changes with a dry-run first.
+
+```bash
+docker compose exec \
+ -e JDCAT_CONFIG=scripts/demo/jdcat_migration/mapping_config.json \
+ -e JDCAT_ITEM_TYPES=12,20 \
+ -e JDCAT_PHASE=all \
+ -e JDCAT_DRY_RUN=1 \
+ web invenio shell scripts/demo/jdcat_migration/migrate.py
+```
+
+### 4.3.3 Real run
+
+If there are no problems in the dry-run output, remove `JDCAT_DRY_RUN` (or set it to `0`) and perform the real run.
+
+```bash
+docker compose exec \
+ -e JDCAT_CONFIG=scripts/demo/jdcat_migration/mapping_config.json \
+ -e JDCAT_ITEM_TYPES=12,20 \
+ -e JDCAT_PHASE=all \
+ web invenio shell scripts/demo/jdcat_migration/migrate.py
+```
+
+### 4.3.4 List of environment variables
+
+| Environment variable | Description |
+|---|---|
+| `JDCAT_CONFIG` | path to the config JSON (`mapping_config.json`) (**required**) |
+| `JDCAT_ITEM_TYPES` | target item types (comma-separated; default is the config's `target_item_types`) |
+| `JDCAT_PHASE` | execution phase `all` / `1` / `2` / `3` / `pre` (default `all`) |
+| `JDCAT_DRY_RUN` | `1`/`true`/`yes` for dry-run (no DB update) |
+| `JDCAT_CLEANUP` | `1`/`true`/`yes` for Phase 3 logical deletion (opt-in) |
+| `JDCAT_REPORT_OUT` | report output file (standard output / log if unspecified) |
+
+- `pre` of `JDCAT_PHASE` performs only pre-run validation (config JSON × DB). `1`/`2`/`3` run each phase individually.
+- `JDCAT_CLEANUP` logically deletes (`delflg=true`) JDCat-specific properties that are no longer referenced by any item type. It is not performed by default (opt-in).
+
+### 4.3.5 Overview of processing phases (Design Document Chapter 6)
+
+| Phase | Content |
+|---|---|
+| Phase 1 | properties (non-destructive UPSERT). Updates v2.0.0 standard properties from the `properties/` definitions via UPDATE. JDCat-specific properties are left in place. |
+| Phase 2 | itemtype. Replaces `cus_` -> `cus_` in `render` (③), replaces old item keys -> new item keys (①), and reflects property definitions via `ItemTypes.reload()`. |
+| Phase 3 | verify & cleanup. Verifies 0 remaining old keys and 0 unknown property references. (Opt-in: logically deletes specific properties.) |
+
+- `migrate.py` wraps the entire run in try/finally, temporarily removing and then restoring the `Timestamp.before_update` listener of `weko_records` (to avoid dirtying the `updated` column of the master tables).
+
+### 4.3.6 Plain python execution (development only)
+
+In a development environment where an app context can be prepared separately, `--` flags can be used.
+
+```bash
+python migrate.py --config mapping_config.json --item-types 12,20 \
+ --phase all --dry-run
+```
+
+| Argument | Corresponding environment variable |
+|---|---|
+| `--config` | `JDCAT_CONFIG` |
+| `--item-types` | `JDCAT_ITEM_TYPES` |
+| `--phase` | `JDCAT_PHASE` |
+| `--dry-run` | `JDCAT_DRY_RUN` |
+| `--cleanup` | `JDCAT_CLEANUP` |
+| `--report-out` | `JDCAT_REPORT_OUT` |
+
+---
+
+# 5. How to read the report
+
+After execution, `migrate.py` outputs a text report (to a file when `JDCAT_REPORT_OUT` is specified, otherwise to standard output / log). The main points to check are as follows.
+
+- **Mode**: whether `dry-run(DB無更新)` (no DB update) or `本実行` (real run).
+- **Pre-run validation (config JSON × DB)**: if there is any `[ERROR]`, the migration is aborted. Review any `[WARN]`.
+- **Phase 1**: number of UPSERT targets (add / update). If there are none, "対象なし" (no target) is stated explicitly.
+- **Phase 2**: per item type, the count of ③ (property ID conversion) and ① (item-key conversion), and the `reload` result code. A "変換済み/冪等スキップ" (already converted / idempotent skip) note means it has already been migrated.
+- **Phase 3**: per item type, `OK`/`NG`, the **number of remaining old keys** and the **number of unknown property references**. Both 0 and `OK` is normal.
+- **Overall judgment**: at the end, `dry-run 完了` / `本実行 完了` (dry-run / real run complete) is shown together with "問題は検出されませんでした" (no problems detected) or items requiring attention.
+
+> ✅ Signs of a successful migration: the overall judgment says "問題は検出されませんでした", and Phase 3 is `OK` for all item types (0 remaining old keys, 0 unknown property references).
+
+---
+
+# 6. Re-run and handling of trouble (Design Document Chapter 7)
+
+- **Idempotent**: Phase 1 uses UPDATE, and Phase 2 skips based on determining "already converted" by key format, so it is **safe to run any number of times**. Proceed in the order dry-run -> real run.
+- **Rollback on error**: if an error occurs during processing, that transaction is rolled back and the DB is kept in its pre-change state. Ordinary errors are recovered this way and can be continued with an idempotent re-run (no restore needed).
+- **Restore from backup**: a **last resort** for **unexpected situations** (inconsistency after a partial commit, data corruption, etc.) that cannot be recovered by transaction rollback or re-run. Restore from the backup taken in advance (4.3.1).
+
+---
+
+# 7. Work after migration
+
+- After the master-data migration completes, **metadata is re-acquired in v2.0.0 structure via re-harvesting through OAI-PMH / ResourceSync** (out of scope for this program; Design Document 2.4).
+- Note that the migration core focuses on preparing the master data (`item_type` definitions, mapping, properties) and does not perform per-record metadata conversion.
diff --git a/docs/spec/base/tools/README.md b/docs/spec/base/tools/README.md
index dd5e18a3..7a9f92cc 100644
--- a/docs/spec/base/tools/README.md
+++ b/docs/spec/base/tools/README.md
@@ -1 +1,9 @@
# TOOLS
+
+## JDCat マスタデータ移行プログラム
+
+develop_v1.0.8系 → develop_v2.0.0 バージョンアップに伴うマスタデータ移行プログラム(要求仕様:J2026-01_v4.docx)。
+
+- [設計書](JDCat_Master_Data_Migration_Design_Spec.md)
+- [利用者マニュアル](JDCat_Master_Data_Migration_Tool_Manual.md) / [User Manual (English)](JDCat_Master_Data_Migration_Tool_Manual_en.md)
+- 別紙: [別紙_v3.xlsx](attachments/別紙_v3.xlsx)(NII様提供資料)
diff --git "a/docs/spec/base/tools/attachments/\345\210\245\347\264\231_v3.xlsx" "b/docs/spec/base/tools/attachments/\345\210\245\347\264\231_v3.xlsx"
new file mode 100644
index 00000000..109d0bcf
Binary files /dev/null and "b/docs/spec/base/tools/attachments/\345\210\245\347\264\231_v3.xlsx" differ
diff --git a/docs/spec/base/tools/images/01_phase_flow.png b/docs/spec/base/tools/images/01_phase_flow.png
new file mode 100644
index 00000000..2211082f
Binary files /dev/null and b/docs/spec/base/tools/images/01_phase_flow.png differ
diff --git a/docs/spec/base/tools/images/01_phase_flow.svg b/docs/spec/base/tools/images/01_phase_flow.svg
new file mode 100644
index 00000000..fceb3906
--- /dev/null
+++ b/docs/spec/base/tools/images/01_phase_flow.svg
@@ -0,0 +1,62 @@
+