データ移行 計画
位置づけ: 後続フェーズ
新CRMのデータ移行は、旧BT社DBを移行元、新CRMのデータベースを移行先とする。移行方式は年末休業期間中の一括移行を基本線とし、業務を一時停止して切り替える。申請系業務は他業務からの独立性が高いため、移行本体から切り離して先行納品する方向とする(meeting-log 2026-07 では「先行納品を検討」で先方合意。納品時期の確定は今後)。旧システムとの並行運用は行わない。切替直後の参照用に、旧DBは読み取り専用で残す。
本ページは、2026-07定例会(P4/P5ヒアリング)で確定したスケジュールとデータ移行方針を、移行計画の観点でマスタ・トランザクション・コード体系・クレンジング・検証基準まで展開したものである。フィールド定義・算出式は crm_app/app/src/lib/*.ts の実装型・実装関数を根拠とする(型そのものが移行先スキーマの実体)。
移行対象の規模感は、BT社資料「既存データ移行 お見積」に基づく旧見積の実績値(成約顧客一覧 137項目・1,687件)を参考値として引き継ぐ。対象範囲・スキーマは新CRM側の再設計に合わせて改めて棚卸しする。実データの件数・容量・PIIは本ページに記載しない。
スコープ/対象
Section titled “スコープ/対象”| 区分 | 内容 |
|---|---|
| 移行元 | 旧BT社DB |
| 移行先 | 新CRMのデータベース |
| 対象範囲 | マスタ系(商品・商社・メーカー・営業マン・価格表。商品・商社は第1弾で先行実装済みのため、旧DBの新マスタへの差分取込に限る)+トランザクション系(顧客・世帯、商談、活動ログ、見積、KPI実績) |
| 対象外 | 第1弾で先行稼働済みの催事・アイテム・商社データ(継続利用扱い。IDの衝突回避のみが論点) |
| 先行納品 | 申請系(独立業務)は移行本体と切り離し、先行納品・先行運用とする方向(定例会では「検討」で先方合意) |
データ(エンティティ表:旧DB→新DB マッピング)
Section titled “データ(エンティティ表:旧DB→新DB マッピング)”| 対象マスタ | 新DB側の受け皿 | 移行方式 | 備考 |
|---|---|---|---|
| 商品(アイテム)マスタ | 新CRMのアイテムマスタ(第1弾実装済み) | 突合・差分取込 | Product.model(型番=主キー、crm_app/app/src/lib/masters.ts)をキーに照合する。SalesPrice.productNo は型番を指す名称参照であり主キーではないため、照合は Product.model 基準で行う。旧DBの型番表記ゆれ(全角/半角・大文字小文字・ハイフン有無等)は現時点で未正規化のため、移行時に正規化ルールを別途定める |
| 商社・仕入先マスタ | 商社(卸)マスタ(第1弾実装済み) | 差分取込 | 商社別軸案件管理との整合を確認する |
| メーカーマスタ | Manufacturer(試作実装あり) | 新規整備+旧DB照合 | 価格表・見積モジュールの前提 |
| 営業マンマスタ(インセンティブ等級含む) | 新設テーブル(KPI予実で使用) | Excel等級表からの初期投入 | 本番DBに評価テーブルが存在しないため新規構築。フィールド定義は Excel等級表の受領後に確定(未実装・確認事項) |
| 価格表(PriceBook/SalesPrice) | CRM側で価格を保持(2026-07-17方針) | 現行価格の初期投入+反映日設定 | 反映日起点の現在価格導出を移行時に検証する(算出式は後述) |
フィールド表:商品・価格系(lib/masters.ts / lib/pricing.ts)
Section titled “フィールド表:商品・価格系(lib/masters.ts / lib/pricing.ts)”Product(商品マスタ。型番=主キー)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| model | string | 必須 | なし | 主キー。型番。旧DB表記ゆれの正規化対象 |
| kind | ”PV”|“BT”|“EQ”|“IH”|“AC”|“付帯” | 必須 | なし | 商材種別(ItemKind) |
| maker | string | 必須 | なし | メーカー名(自由文字列。Manufacturer.id への正規化は未実装) |
| series | string | 任意 | undefined | シリーズマスタ(Series)と名寄せ |
| name | string | 任意 | undefined | 商品名 |
| spec | string | 任意 | undefined | 容量・枚数等の既定表記 |
| leadTimeDays | number | 任意 | undefined | 納期目安。無ければメーカー単位フォールバック(LEADTIME_MASTER) |
| stock | ”潤沢”|“少”|“欠品” | 任意 | undefined | 在庫状態 |
| note | string | 任意 | undefined | 自由記述 |
無効化フラグ(廃番商品を示す論理削除列)は現行 Product 型に存在しない。「廃番商品は削除せず無効フラグ付きで移行する」という業務ルールを満たすには型拡張が前提になる(後述エッジケース参照)。
Series(シリーズマスタ)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| name | string | 必須 | なし | シリーズ名(例: UFOシリーズ) |
| maker | string | 任意 | undefined | メーカー名 |
| note | string | 任意 | undefined | 自由記述 |
Supplier(商社・仕入先マスタ)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| name | string | 必須 | なし | 商社名 |
| type | ”商社”|“メーカー直送” | 必須 | なし | |
| closingDay | string | 任意 | undefined | 締日(例: “月末”) |
| paymentSite | string | 任意 | undefined | 支払サイト(例: “翌月末払い”) |
| creditLimit | number | 任意 | undefined | 与信枠(円) |
| note | string | 任意 | undefined |
Product と同様、取引終了商社の無効化フラグは現行 Supplier 型に存在しない(同上)。
Manufacturer(メーカーマスタ)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| name | string | 必須 | なし | メーカー名 |
LoanCompany(ローン会社/信販マスタ)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| name | string | 必須 | なし | |
| daysDirect | number | 必須 | なし | 2社間: 完工書到着→入金の営業日数 |
| daysViaTrader | number | 必須 | なし | 3社間: 商社経由の営業日数 |
PriceBook(価格表。仕入先/催事×メーカー×件名×反映日)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| source | string | 必須 | なし | 仕入先/催事の名称 |
| category | ”商社”|“施工店”|“アライアンス”|“催事” | 必須 | なし | |
| manufacturerId | string | 必須 | なし | Manufacturer.id 参照 |
| title | string | 必須 | なし | 件名 |
| effectiveDate | string(YYYY-MM-DD) | 必須 | なし | 反映日(適用開始)。現在価格導出のキー |
| note | string | 任意 | undefined |
Part(価格表の1行=部材)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| bookId | string | 必須 | なし | PriceBook.id 参照 |
| no | number | 必須 | なし | 部材No(価格表内の識別番号) |
| name | string | 必須 | なし | 部材名 |
| productNo | string | 任意 | undefined | 商品No(型番参照。主キーではない) |
| retailPrice | number | 任意 | undefined | 希望小売価格 |
| netPrice | number | 必須 | なし | 貴社仕切(仕入)。値引き行は負値 |
| tier | ”必須”|“選択必須”|“オプション” | 必須 | なし | 部材そのものの区分 |
PackageSet/PackageMember(パッケージ=標準構成部材セット)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| PackageSet.id | string | 必須 | なし | 主キー |
| PackageSet.bookId | string | 必須 | なし | PriceBook.id 参照 |
| PackageSet.name | string | 必須 | なし | |
| PackageSet.members | PackageMember[] | 必須 | なし | 構成部材の配列 |
| PackageSet.setPrice | number | 必須 | なし | セット価格 |
| PackageMember.no | number | 必須 | なし | Part.no 参照(構成部材No) |
| PackageMember.qty | number | 必須 | なし | 数量 |
| PackageMember.tier | ”必須”|“選択必須”|“オプション” | 必須 | なし | このパッケージでの必要度(Part.tier とは独立管理。2026-07-22定例で確定) |
SalesPrice(販売価格。商品/部材×商流/代理店×反映日)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| productNo | string | 必須 | なし | 型番(Product.model への名称参照。主キーではない) |
| productName | string | 任意 | undefined | 表示用の商品名スナップショット |
| channel | string | 任意 | undefined(=標準) | 商流/代理店。空は標準価格を意味する |
| price | number | 必須 | なし | 販売価格(税抜) |
| startDate | string(YYYY-MM-DD) | 必須 | なし | 反映日 |
| endDate | string(YYYY-MM-DD) | 任意 | undefined(=無期限) | 未設定は「終了日なし=恒久有効」と解釈される(後述エッジケース) |
| memo | string | 任意 | undefined |
トランザクション系
Section titled “トランザクション系”| 対象データ | 新DB側の受け皿 | 移行方式 | 論点 |
|---|---|---|---|
| 顧客・世帯(Household) | Household テーブル(試作あり) | 名寄せ後に一括投入 | クレンジングの主戦場。PII取扱いルールを別途定める |
| 商談(Deal:channel/venue/createdAt 等) | Deal テーブル(試作あり) | channel区分をマッピングして投入 | 旧DB区分値→訪問販売/催事/反響/パートナーの対応表を作成する |
| 活動ログ・架電(前確)・申込・タスク | 各試作モデル | 直近分を優先して投入 | 過去分の保持期間は「確認事項」参照。活動ログは独立テーブルではない(後述) |
| 見積(quotes) | Quote テーブル(試作あり)。見積モジュールの画面は後続実装 | 進行中案件のみ移行し、完了案件はアーカイブ参照とする | 移行範囲の線引きは「確認事項」参照 |
| KPI実績(営業マン別 M1/M2実績) | 実績テーブル(新設) | Excelからの初期投入 | 予算・評価テーブルが本番DBに存在せず、移行ではなく新規構築。フィールド定義は未実装 |
旧見積(BT社資料)の「成約顧客一覧」137項目は、現行CRMの customers / contracts / contract_additional_materials 等に分解してマッピングされると推測される(未検証。data-migration 参照)。新CRMへの移行では、この旧Excel項目群を Household・Deal・見積等の新スキーマへ再マッピングする対応表を移行成果物として整備する。
フィールド表:Household/Person(lib/crm.ts)
Section titled “フィールド表:Household/Person(lib/crm.ts)”Household(世帯)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー。実装シードは Hnnn(3桁連番)形式 |
| name | string | 必須 | なし | 世帯名(代表姓) |
| postal | string | 必須 | なし | 郵便番号 |
| pref | string | 必須 | なし | 都道府県 |
| city | string | 必須 | なし | 市区町村 |
| addr | string | 必須 | なし | 番地以下 |
| adults | number | 必須 | なし | 大人の人数 |
| children | number | 必須 | なし | 子供の人数 |
| taxable | boolean | 必須 | なし | 課税事業者フラグ |
| memo | string | 任意 | undefined | 運営メモ(自由記述) |
| persons | Person[] | 必須 | なし | 世帯構成員(最低1名を代表者として扱う運用) |
Person(世帯構成員)
| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| name | string | 必須 | なし | 氏名 |
| kana | string | 必須 | なし | フリガナ。名寄せの主要キーの一つ |
| relation | ”夫”|“妻”|“子”|“本人”|“その他” | 必須 | なし | 世帯内の続柄 |
| birth | string | 任意 | undefined | 生年月日 |
| mobile | string | 任意 | undefined | 携帯番号 |
| tel | string | 任意 | undefined | 固定電話 |
| string | 任意 | undefined |
フィールド表:Deal(商談・案件。主要フィールド)
Section titled “フィールド表:Deal(商談・案件。主要フィールド)”| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー。実装シードは D-YYMM-NNN 形式(年月+連番) |
| status | DealStatus | 必須 | なし | アポ/前確/商談/成約/工事/完了/保留/失注/クーリングオフ の9値 |
| channel | Channel | 必須 | なし | 訪問販売/催事/反響/パートナー の4値 |
| hankyoMedia | string | 任意 | undefined | channel=“反響” のときの大元媒体(タイナビ等) |
| subject | ”自社”|“代理店” | 任意 | 自社 | 実施主体。登録時にログインユーザー所属から自動判定(手選択しない) |
| agency | string | 任意 | undefined | subject=“代理店” のときの代理店名 |
| venue | string | 任意 | undefined | 催事場所 |
| householdId | string | 必須 | なし | Household.id 参照。参照整合性の要 |
| property | Property | 必須 | なし | 物件情報(既存設備配列 Existing[] を含む) |
| roles | Roles | 必須 | なし | 獲得/前確/クローザー/設計(ユーザー名。実装ではFK) |
| respondentId / contractorId | string | 任意 | undefined | Person.id 参照(商談応対者/契約名義人) |
| items | DealItem[] | 必須 | なし | 商材明細(kind/maker/model/spec/warranty/supplier/deliveryDate) |
| milestones | Milestone[] | 必須 | なし | 現調・着工・完工・連携・設備認定・入金の標準6点(defaultMilestones())のキー付き進捗 |
| tasks | DealTask[] | 必須 | なし | type は「前確」「太陽光調査設計」の2種のみ |
| notes | DealNote[] | 任意 | undefined | id/date/author/text |
| postContract | PostContract | 任意 | undefined | サンキューコール/ローン審査/審査確認コール/団信(成約時に生成) |
| construction | Construction | 任意 | undefined | 施工店・現調・完了報告・完工書・連携日(着工フェーズで生成) |
| payment | Payment | 任意 | undefined | 決済方式・頭金・前金/後金・ローン条件 |
| orders | Order[] | 任意 | undefined | 発注(工事日確定後に発生) |
| applications | Application[] | 任意 | undefined | 申請(新規認定/変更認定/補助金/保証等の別軸) |
| proposal | number | 任意 | undefined | ご提案金額(税込) |
| cost | number | 任意 | undefined | 仕切り(原価) |
| margin | number | 任意 | undefined | 粗利 |
| memo | string | 任意 | undefined | 運営メモ |
| lostReason | string | 任意 | undefined | 失注・前確NGの理由。KPI分析用に必須で残す運用 |
| createdAt | string | 必須 | なし | 作成日 |
| closeDate | string | 任意 | undefined | 成約日 |
活動ログ・架電・申込・タスクの旧DB区分は、新CRMでは以下のように分解されて保持される(1テーブルに集約しない)。
| 旧DB区分(想定) | 新CRM側の対応 |
|---|---|
| 活動ログ | 独立テーブルなし。Deal.milestones/tasks/notes/createdAt・closeDate・postContract・construction・applications の各日付から画面表示時に動的生成される派生ビュー(ActivityPage.tsx の collectActivities())。旧DBの活動ログレコードは、この派生元(tasks/notes/milestones 等)へ分解して投入する必要がある |
| 架電(前確) | Deal.tasks(DealTask.type=“前確”、assignee/status/due/result/gate) |
| 契約後の架電(サンキューコール・審査確認コール・完工コール) | Deal.postContract.thanksCall/reviewCall、Deal.construction.kankoCall(いずれも CallResult: 未/不出/OK/NG) |
| 申込 | 専用エンティティなし。Deal.status=“成約” への遷移と createdAt/closeDate で表現される |
| タスク | Deal.tasks(種別は前確・太陽光調査設計の2種に限定。それ以外の旧タスク種別は要マッピング) |
フィールド表:Quote(見積)
Section titled “フィールド表:Quote(見積)”| フィールド | 型 | 必須 | 既定 | 制約・備考 |
|---|---|---|---|---|
| id | string | 必須 | なし | 主キー |
| date | string(YYYY-MM-DD) | 必須 | なし | |
| to | string | 必須 | なし | 宛名(「様」は付けない運用) |
| subject | string | 必須 | なし | 件名 |
| paymentTerms | string | 必須 | なし | 支払条件 |
| systemItems | QuoteItem[] | 必須 | なし | システム(商品)明細。小計①相当 |
| workItems | QuoteItem[] | 必須 | なし | 工事明細。小計②相当 |
| discounts | QuoteDiscount[] | 必須 | なし | label/amount。amount は負値 |
| taxRate | number | 必須 | なし | 消費税率(シードは 0.10) |
| dealId | string | 任意 | undefined | Deal.id 参照 |
| owner/ownerMobile | string | 任意 | undefined | 担当者・担当者携帯 |
QuoteItem: { name, model?, qty, unit, amount, cost? }。cost を持つ明細のみ原価集計対象(原価売り検知に使用)。
画面・機能(移行ツールと手順)
Section titled “画面・機能(移行ツールと手順)”移行はETL方式の使い捨てスクリプトで実施する。恒久的な移行専用画面は用意しない。リハーサルで同一スクリプトを繰り返し実行し、精度と所要時間を計測する。
| フェーズ | 時期 | 内容 |
|---|---|---|
| 申請系 先行納品 | 年末休業より前 | 独立業務のため単独で納品・運用を開始する |
| リハーサル移行(第1回〜N回) | 本番移行の数週間前 | 本番相当データで全スクリプトを通し、所要時間と疑義件数を計測する |
| データ凍結(フリーズ) | 年末休業初日 | 旧DBへの入力を停止し、最終バックアップを取得する |
| 本移行実行 | 休業期間中 | 抽出→変換→投入→整合チェックを一括実行する |
| 検証・受入判定 | 休業期間中〜年始直前 | 「検証・受入基準」節の基準で判定する。不合格の場合はロールバックし、旧システムで年始業務を再開する |
| 切替・年始稼働 | 年始営業初日 | 新CRMで業務を開始する。旧DBは参照用に読み取り専用で保持する |
この工程は、meeting-log 2026-07(P4/P5ヒアリング)で確定した「12月末に本丸(P1〜P5)納品→12月に研修・検証→1月完全切替」「データ移行は年末休業中」「申請系は独立業務のため先行納品を検討」(先方合意)を、移行計画の観点で展開したものである。時期・所要時間の具体値はリハーサルの実測で確定する。
フェーズ遷移(ワークフロー)
Section titled “フェーズ遷移(ワークフロー)”stateDiagram-v2
[*] --> 申請系先行納品
申請系先行納品 --> リハーサル移行
リハーサル移行 --> リハーサル移行: 再実行(精度・所要時間の計測、複数回)
リハーサル移行 --> データ凍結: リハーサル結果を確定手順に反映
データ凍結 --> 本移行実行: 最終バックアップ取得後
本移行実行 --> 検証受入判定
検証受入判定 --> 切替年始稼働: 合格(件数突合・金額整合・サンプル目検・業務シナリオ)
検証受入判定 --> ロールバック: 不合格・重大不整合
切替年始稼働 --> [*]
ロールバック --> [*]: 旧システムで年始業務を再開
本移行実行のシーケンス
Section titled “本移行実行のシーケンス”sequenceDiagram
participant Old as 旧BT社DB(読取専用)
participant ETL as 移行スクリプト(使い捨てETL)
participant Map as 旧→新コード対応表
participant New as 新CRM DB
participant Ops as 移行担当(Ouver/VE)
Ops->>Old: データ凍結(入力停止・最終バックアップ取得)
ETL->>Old: 抽出(マスタ→トランザクションの依存順)
ETL->>Map: コード変換(channel/ステータス/型番の正規化)
ETL->>New: 投入(legacy_id 付与。参照整合性順: マスタ→Household→Deal→見積…)
ETL->>New: 整合チェック(件数突合・金額整合)
New-->>Ops: 疑義リスト・不整合レポート
Ops->>Ops: 検証・受入判定(件数突合/金額整合/サンプル目検/業務シナリオ検証)
alt 合格
Ops->>New: 切替(年始営業初日に稼働開始)
else 不合格・重大不整合
Ops->>Old: ロールバック(旧システムで年始業務を再開)
end
業務ルール/ワークフロー
Section titled “業務ルール/ワークフロー”コード体系の引継ぎとID設計
Section titled “コード体系の引継ぎとID設計”- 新DBの各テーブルに旧DBのIDを保持する引継ぎカラム(
legacy_id)を設け、移行後も新旧の突合・遡及調査を可能にする。将来構想(AIエージェント、商社明細スキャンの自動取込、SaaS化・分社化)を見据え、この引継ぎカラムは拡張余地を残す設計とする。現行実装のいずれの型(Product/Household/Deal 等)にもlegacy_id相当のカラムは存在せず、新規追加が前提(未実装)。 - 現行実装のID採番は、エンティティごとに異なる書式で個別に発番されている(統一採番基盤はない)。例: Household=
Hnnn(3桁連番)、Deal=D-YYMM-NNN(年月+連番)、催事店舗マスタ=STnnn(3桁連番、event-stores.ts)、価格表・マスタ各種=英字接頭辞+2桁連番(例:SUP01,MK01,PB01)、部材・パッケージ=英字接頭辞+価格表番号2桁+連番2桁(例:PT0101,PK0101)。旧DB由来データを同じ書式帯へそのまま投入すると採番衝突の恐れがあるため、旧DB由来レコードは書式単位で採番帯を分離する。 - 商品の業務キーは Product.model(型番=主キー)であり、そのまま引き継ぐ。SalesPrice.productNo は型番を指す名称参照であり主キーではない点に注意し、Product.model×channel×反映日の複合構造と整合させる。旧DBの型番表記ゆれ(全角/半角・大文字小文字・ハイフン有無等)は現時点で未正規化のため、移行時に正規化・突合表の整備が必要。
- channel・ステータス等の区分値は「旧コード→新コード対応表」を移行成果物として作成し、先方レビューを経て確定する。対応表に存在しない旧コード値のフォールバック挙動(既定チャンネルへ丸めるか、疑義リストに回すか)は未定義(確認事項)。
- 参照整合性(Deal→Household、見積→価格表 等)は、投入順序を依存関係順に固定して担保する。
- 第1弾稼働分(催事・アイテム・商社)で発番済みのIDと旧DB由来データは、採番帯を分離して衝突を回避する。
現在価格・現在価格表の導出(反映日ロジック)
Section titled “現在価格・現在価格表の導出(反映日ロジック)”価格・価格表は反映日を持つ時間軸マスタとして保持し、「基準日時点で有効な最新版」を都度導出する(保存済みの「現在値」列は持たない)。実装は lib/pricing.ts の以下2関数が正本。
currentSalesPrice(list, productNo, channel?, baseDate):productNo一致(かつchannel指定時は一致)で、startDate <= baseDateかつ(endDate未設定 またはendDate >= baseDate)を満たすレコードのうちstartDate降順の先頭1件を返す。該当が無ければundefined(=現在有効な価格が存在しない)。currentBooks(books, baseDate):source × manufacturerId × titleをキーに、effectiveDate <= baseDateを満たす中でeffectiveDateが最大の1件を採用する。
移行時は、この2関数と同じロジックで新DB投入後のデータを検算し、「移行直後の基準日(年始稼働日)時点で1件も有効版が無いマスタ」が無いことを受入判定に含める。
入金予定の算出(経理向け)
Section titled “入金予定の算出(経理向け)”- 営業日加算は
addBusinessDays(dateISO, days)。土日およびJP_HOLIDAYS_2026(年別祝日マスタ。祝日APIやマスタからの取得は未実装、シードはハードコード)を除外して加算する。 - 入金までの営業日数
settlementDays(deal, loanCompanies):決済方式が3社間かどうかで分岐し、loanCompaniesに一致するローン会社があればそのdaysDirect/daysViaTraderを使用。一致しない場合は 3社間=6営業日/それ以外=3営業日にフォールバックする。 - 入金予定日
paymentDueDate(deal, loanCompanies):決済方式が「ローン」かつconstruction.kankoshoAt(完工書原本回収日)がある案件のみ算出対象。入金マイルストーン(milestonesのkey: "nyukin")が既に完了していればundefined。それ以外はkankoshoAt + settlementDays営業日。 - 現金半金の後金は入金タイミングの定義が未確定のため
receivables()(経理向け入金予定一覧)の対象外(実装コードのコメントに明記)。現金一括もpaymentDueDateが決済方式「ローン」のみを算出対象とするため同様に対象外となる。旧DBの入金実績データをこれらの対象外パターンに含めて移行する場合、経理向け画面には表示されない点に注意する。
消費税・端数処理
Section titled “消費税・端数処理”- 見積の消費税率はレコードごとに
taxRateを持つ(シード値は 0.10)。税額quoteTax(q) = Math.round(quoteNet(q) * q.taxRate)で四捨五入。 - 経理向け入金予定額
amount = Math.max(0, proposal - downPayment)(負値は0に丸める)。 - 移行時の金額整合検証(後述)は、これらの端数処理ロジックと突合方法を揃えたうえで実施する(丸め方式の相違は不整合として検出されうる)。
CSV出力の実装パターン(移行検証への転用)
Section titled “CSV出力の実装パターン(移行検証への転用)”現行実装には CSV出力機能が複数画面に実装済みで、移行後の検証・受入判定でそのまま流用できる。CSV**取込(インポート)**機能は現状どの画面にも実装されていない(成約顧客一覧のインポートは新規実装が前提)。
| 画面 | 実装 | 出力対象 |
|---|---|---|
| 顧客一覧 | CustomersPage.tsx の exportCsv() | 世帯ID・世帯名・〒・都道府県・市区町村・番地・大人・子供・課税事業者・案件数・代表者・フリガナ・携帯番号・メモ |
| 案件一覧 | DealsPage.tsx の exportCsv() | 案件明細 |
| タスク一覧 | TasksPage.tsx | タスク明細 |
| 活動フィード | ActivityPage.tsx | 派生ビュー(Deal横断のタイムライン) |
| レポート | ReportsPage.tsx の exportReportsCsv() | 集計セクション |
共通仕様:UTF-8 BOM付き Blob("" + csv)をブラウザ内で生成しダウンロード、サーバ保存なし。ファイル名は <種別名>_<YYYY-MM-DD>.csv。値のクォート・エスケープ処理は画面ごとに実装が異なる(案件一覧は全列をダブルクォートで囲む、活動フィードは " → "" エスケープ、タスク一覧は顧客名列のみクォート等。統一仕様ではない)。canExport(role) によるボタン表示ガードが実装されているのは顧客一覧・案件一覧のみで、タスク一覧・活動フィード・レポートのCSVボタンは権限ガードなしで表示される(外部ロールは NAV_ALLOW 上これらの画面自体に到達できないため実害はない。権限節を参照)。
クレンジング方針
Section titled “クレンジング方針”- 世帯・顧客の名寄せは、氏名・住所・電話の表記ゆれによる重複を自動統合し、判定困難な組は疑義リストとして目検する。Person.kana(フリガナ)を名寄せの主要キーの一つとして使う。
- 必須項目の欠損(連絡先なし等)や日付異常は移行前に疑義リスト化し、先方確認のうえ補正または欠損のまま取込むかを判断する。
- 廃番商品・取引終了商社は、過去トランザクションから参照が残るため削除せず、無効フラグ付きで移行する。現行 Product/Supplier 型に無効化フラグは存在しないため、移行を前提にスキーマ拡張が必要(未実装)。
- クレンジングの実施は、機械処理をOuver、業務判断をバリューエコロジー側が担当する分担とする。
- 疑義件数・補正件数は移行報告書にプレースホルダで記録し、受入判定の材料とする。
検証・受入基準
Section titled “検証・受入基準”- 件数突合: 旧DB抽出件数=新DB投入件数+除外件数(除外理由付き)が全テーブルで成立すること。
- 金額整合: 売上・粗利等の集計値が現行KPI Excel(営業マン別シート)の値と一致すること。KPIダッシュボードの正しさの前提になる。丸め方式(
Math.round等)を突合前に揃える。 - サンプル目検: 世帯・商談・見積からN件ずつ抽出し、先方担当者が画面上で旧システムと突合する。
- 業務シナリオ検証: 架電→商談→申込→タスク(前確・太陽光工程)の一連の流れが移行データ上で成立することを確認する。
- 反映日整合:
currentSalesPrice/currentBooksと同一ロジックで、移行直後の基準日時点に有効な価格・価格表が全対象商品・全対象マスタで導出できることを確認する。 - 不合格・重大不整合が生じた場合は旧システムへロールバックし、年始業務を旧システムで再開する。
- 移行実行そのもの(ETLスクリプトの実行)はDBレイヤーへの直接操作であり、アプリケーションの認可(
lib/permissions.ts)を経由しない。「移行担当」という恒久ロールは現行Role型(管理者/営業/事務(BO)/発注・申請担当/代理店/代理店(メンバー)/施工店)に存在せず、未実装。移行作業は管理者権限を持つ運用者が個別に実行する運用を前提とする。 - 移行後の検証で使うCSV出力は、既存の
canExport(role) = !isExternal(role)をそのまま踏襲する想定。isExternal(role)は代理店・代理店(メンバー)・施工店を true とする。ただし現行実装でこのガードが効いているのは顧客一覧・案件一覧のCSVボタンのみで、タスク一覧・活動フィード・レポートはボタン自体にガードがない(外部3ロールはNAV_ALLOWで当該画面に到達できないため、画面到達制限で実質的に守られている)。 - マスタ関連画面(
/master-products等)はNAV_ALLOW(lib/permissions.ts)上、事務(BO)と管理者のみアクセス可能。よって移行後のマスタ差分確認・補正は事務(BO)・管理者に限定される。 - 未知ロール(旧値の残存等)は
canSeeNavが何も許可しない設計(クラッシュ回避のフォールバック)。旧DB由来のユーザー・ロール値をそのまま新ロール体系に投入する場合、対応表に無い値は「何も見えないロール」になりうる点に注意する。
エッジケース・異常系
Section titled “エッジケース・異常系”- 型番表記ゆれ(全角/半角・大文字小文字・ハイフン有無)により Product.model 突合に失敗するケース。正規化ルール未確定のため、現時点では未マッチを疑義リスト化する運用が前提。
- SalesPrice.productNo が対応する Product.model を持たない(名称参照が孤立している)ケース。整合チェックで検知する必要がある。
currentSalesPrice/currentBooksは該当版が無ければundefinedを返す。移行直後の基準日時点で有効版が1件も無いマスタは受入不合格として扱う。- SalesPrice の
endDateが未設定のレコードは「無期限に有効」と解釈される(フィルタ条件!s.endDate || s.endDate >= baseDate)。旧DB側で終了日が単に未入力なだけのレコードをそのまま投入すると、意図せず恒久有効になる。終了日の有無は移行時に精査する。 - Deal.householdId が指す Household が存在しない参照切れ(孤立商談)。投入順序を Household→Deal に固定しても、旧DB側の参照自体が壊れているケースは疑義リストに回す。
- 活動ログは新CRM側に永続テーブルが無く、Deal 配下の milestones/tasks/notes/createdAt 等から画面表示時に動的生成される派生ビュー。旧DBの活動ログをそのまま1テーブルへ投入する先が無いため、旧レコードを tasks/notes/milestones への分解ルールとして再設計する必要がある。
- channel・ステータス等の区分値で「旧コード→新コード対応表」に存在しない値が来た場合のフォールバック挙動は未定義。既定値へ丸める/疑義リストに回すのいずれにするかは要決定。
- 廃番商品・取引終了商社の無効フラグは現行 Product/Supplier 型に存在しない。「削除せず無効フラグ付きで移行する」を実現するには型拡張が前提となる。
- 現金一括・現金半金の後金入金は
receivables()の対象外(未定義のタイミング)。旧DBの入金実績をこのパターンで移行すると、経理向け入金予定画面には反映されない。 - 祝日マスタ(
JP_HOLIDAYS_2026)は年別ハードコードのシードであり、祝日APIやマスタからの取得は未実装。年をまたぐ移行データの営業日計算で年が変わった場合、祝日マスタの更新漏れに注意する。 - 申請系は移行本体から独立して先行納品・先行運用されるため、本移行のロールバック判断とは別に、申請系データの巻き戻し要否を個別に判断する必要がある(申請系はロールバック対象に含まれない前提)。
- 旧BT社DBのスキーマ・データ品質の詳細調査は未実施。調査結果次第でクレンジング工数と移行範囲が変動する。
- 営業マンマスタ・等級表の整備状況に応じて、KPI実績(予算・評価テーブル)の新規構築スケジュールが変動する。新設テーブルのフィールド定義は未確定。
- 年末休業の実日数と移行所要時間のバランスはリハーサル計測後に確定する。不足時は範囲縮小か凍結前倒しを協議する。
- 申請系の先行納品期間中は旧新の二重メンテ(マスタ変更の反映漏れ等)が発生しうるため、同期ルールを別途定める。
- ロールバックの判断期限(年始稼働に間に合う最終判断日時)は先方と合意していない。
- 活動ログ・見積等の過去データの保持期間(過去N年分等)は先方と協議中。
- 「旧コード→新コード対応表」に存在しない区分値のフォールバック挙動(既定値への丸め/疑義リスト送り)は未確定。
- 廃番商品・取引終了商社の無効フラグをどのテーブル・カラムで持つか(Product/Supplier型の拡張仕様)は未確定。