コンテンツにスキップ

ベータ開始時の本番データ移行仕様

目的

公開デモ用データを本番データへ安全に置き換える。デモの園児・家庭・保護者情報を残さず、CSVから取り込んだ家庭、園児、保護者アカウントおよび保護者表示情報の整合性を保証する。

この移行は通常運用の追加・更新インポートとは区別する。通常のCSVインポートには削除機能がなく、既存DBを部分的に削除して再利用すると、デモ由来の関連データや家庭共有プロフィールが残る可能性がある。

現在認識しているリスク

保護者情報が複数の場所に存在する

保護者に関係する情報は、主に次の場所へ保存される。

データ 用途
Family.shared_profile 家庭の共有連絡情報。現行実装では保護者プロフィールも持つが、部分紐づけを壊すため、ベータ移行では園児の閲覧権限を決定しない
Guardian 園児ごとの保護者表示情報
ParentAccount 保護者ポータルへログインするアカウントと連絡先
ParentChildLink 保護者アカウントが閲覧・操作できる園児を示す唯一の権限関係。続柄、主連絡先も保持する

家庭情報の同期では、既存のGuardianを削除し、Family.shared_profileから作り直す。このため、古いFamily.shared_profileが残っていると、CSVで投入した情報が古い保護者名で上書きされる可能性がある。

現行の家庭CSVは家庭名、住所、電話番号のみを扱い、Family.shared_profileを扱わない。また、ParentAccountParentChildLinkを取り込んでも、家庭共有プロフィールを自動構築する契約は現在ない。この状態で空DBへ取り込むと、デモ名が残らなくても園児一覧の保護者欄が空になる、またはアカウント情報と一致しない可能性がある。

家庭内リンクの直積化(ベータ開始前のブロッカー)

現行のsync_parent_child_links()は、同じ家庭に属する保護者アカウントと園児の既存リンクを削除し、家庭内の全保護者×全園児の直積として再生成する。CSVに存在しない組には、続柄保護者と、最小アカウントIDを基準にした主連絡先の既定値が設定される。

また、現行の保護者ポータルはParentChildLinkよりParentAccount.family.childrenを優先して閲覧対象を決めるため、リンクを部分的に保存できても同じ家庭の全園児を閲覧できる。この2点は、明示されていない園児へのアクセスを付与し得るため、ベータ開始前のブロッカーとする。

ベータ・本番では次を正規の契約とする。

  • family_idは住所・電話等を共有する家庭グループを表し、園児の閲覧権限を付与しない。
  • ParentChildLinkだけを、保護者アカウントが閲覧・操作できる園児の根拠とする。
  • 同じ家庭内でも、保護者アカウントを一部の園児だけへ紐づけられる。部分紐づけを正式にサポートする。
  • CSVに存在しない保護者・園児の組を自動生成しない。
  • sync_parent_child_links()は直積生成を廃止し、明示リンクの保持と、家庭移動等で無効になったリンクの検出・削除に限定する。
  • 保護者ポータルの園児一覧、詳細、連絡、通知、アンケート等のアクセス判定は、すべて明示的なParentChildLinkを使用する。
  • Family.shared_profileまたは家庭共有情報の同期によって、CSVにないGuardianParentChildLinkを全園児へ追加しない。
  • 園児別のGuardian表示を移行データから構築する場合も、当該園児への明示リンクまたは園児別保護者データだけを使用する。

移行事前検証では、現行ロジックを適用した場合にCSV外で生成される組を家庭ごとに計算し、「家庭名、CSV明示件数、自動生成予定件数」を表示する。自動生成予定件数が1件以上の場合は警告表示だけで確定可能にせず、実装修正が完了するまで確定を拒否する。

同姓同名

実在データでは同姓同名が正当な場合があるため、本番データに「同姓同名は2組まで」などの上限制約を設けない。デモ生成時の重複抑制ルールは本番移行へ適用しない。

照合および重複判定では、表示名や自然キーではなく、後述する移行元IDを主キーとして使用する。氏名カナ、生年月日、メールアドレス、家庭名、電話番号等は、移行元IDが指すデータの整合性確認と警告に使用する。

内部IDと移行元IDの混同(ベータ開始前のブロッカー)

現行CSVのID家庭ID保護者ID園児IDは、open-hoikuictのDB内部主キーである。指定された値はsession.get()で検索され、空DBに存在しなければエラーになる。これらは移行元システムのIDではなく、空DBへの新規取込では使用できない。

このため、ベータ移行では次の2種類を明確に分離する。

種類 用途
内部ID ID家庭ID保護者ID園児ID 同じopen-hoikuict DBからエクスポートしたデータの更新。新規空DB移行では空欄にする
移行元ID 移行元ID移行元家庭ID移行元保護者ID移行元園児ID 外部台帳・旧システム内での識別とCSV間参照

ベータ移行用CSV一式には、移行対象ごとの移行元IDを必須とする。CSV間の参照は移行元IDで解決し、内部IDを手作業で転記しない。

移行元IDはsource_systemと組み合わせて永続化し、データ種別ごとに一意とする。source_systemは移行パッケージ全体のマニフェストまたはCLI引数で指定する。同じsource_system + 移行元IDを再投入した場合は新規作成せず、同じレコードの更新または同一内容のスキップとして扱う。

移行元に安定したIDがない場合は、CSV作成前の変換工程で一意の移行元IDを付与し、その対応表を移行記録として保存する。氏名、生年月日、メールアドレス等の自然キーだけを、確定取込時の主照合キーにはしない。

移行方式

原則

既存のデモDBを直接削除・再利用せず、新しい空DBへ本番データを取り込む。検証に合格したDBへ接続先を切り替える方式を標準とする。

既存DBを直接消去するseed_demo_100.py --wipe-allは、デモ・ローカル検証専用とし、本番移行手順には使用しない。

起動時シード禁止

過去のinitialize_application()は、DB作成後に次の処理を実行していた。

  • seed_classroom_data()
  • seed_extended_care_fee_rules()
  • seed_sample_data()
  • seed_parent_portal_data()
  • seed_calendar_data()
  • seed_staff_classroom_assignments()

このうち、seed_sample_data()は田中・佐藤・伊藤家等のサンプル家庭・園児・保護者を、seed_parent_portal_data()はサンプル保護者アカウントを、seed_calendar_data()はサンプル職員アカウント等を空テーブルへ投入していた。

通常起動からこれらのシード呼び出しを削除し、main・デモ・ベータ・本番のすべてで、アプリ起動だけでは業務データを生成しない。デモデータが必要な場合は、デモ・ローカルDBに対してpython -m scripts.seed_demo_100を明示実行する。

ベータおよび本番の起動処理は、スキーマ作成、マイグレーション、安全な整合性処理等に限定し、クラス、料金ルール、人物、家庭、カレンダー等の業務データを自動生成してはならない。「対象テーブルが空であること」は、サンプルデータ投入を許可する条件として扱わない。

デモ・サンプル用シードは専用コマンドからのみ実行できるものとし、通常のアプリ起動経路から呼び出さない。ベータ・本番の運用手順、コンテナentrypoint、起動スクリプトにもデモシードコマンドを含めない。

最低限、以下の自動テストを追加する。

  • 空の一時DBを開発・デモ・ベータ・本番の各設定でinitialize_application()し、業務データが0件のままであること。
  • 上記の起動を複数回行っても、サンプルデータが追加されないこと。
  • デモ・ローカル環境では、専用コマンドを明示実行した場合に限りデモデータを投入できること。

非Web取込ランナー

新規DBの準備および障害時の再実行をWeb UIだけに依存させないため、initialize_application()のデモシードを経由しないCLI取込ランナーを用意することが望ましい。

CLI取込ランナーはスキーマ作成・マイグレーションを実行したうえで、Web UIと同じCSV解析、事前検証、確定処理および実行履歴を利用する。独自の検証ルールを重複実装しない。事前検証のみの--dry-runと、エラー時の全件ロールバックを提供する。

CLIランナーの有無にかかわらず、実運用モードでの自動デモシード禁止は必須とする。CLIだけを追加しても、空DBが将来通常起動された際の混入リスクは解消しない。

初期管理者の作成(必須)

職員が0人のDBでは管理画面へログインして最初の職員を作成できないため、初期管理者の作成はWeb UIへ依存させない。一回限りのオフラインCLIをベータ開始前に実装し、アプリケーションを外部公開する前に実行する。

CLIは、最低限次を行う。

  • 外部認証側で事前作成・本人確認済みの職員識別子と、open-hoikuictのUserを対応付ける。
  • 表示名、メールアドレス、admin権限、必要な業務権限を明示的に設定する。
  • パスワード、アクセストークン、秘密鍵をコマンドライン引数、CSVまたはアプリケーションログへ保存しない。
  • 同じ外部認証識別子またはメールアドレスに別の職員が存在する場合はエラーにする。
  • 有効な管理者が既に存在する場合は、通常実行では新しい初期管理者を作らない。
  • 実行者、承認者、実行日時、対象DB、作成した内部ユーザーID、外部認証識別子の秘匿済み表現を監査記録へ残す。

初期管理者作成後、限定ベータ環境を外部非公開または接続元制限付きで起動し、当該管理者が本番認証でログイン・ログアウトできることを確認する。この確認が終わるまで、残りの初期構成および利用者への公開へ進まない。

起動時シードに代わる正規の初期構成

クラスから保護者・園児紐づけまでの移行パッケージとは別に、次の運用初期データを明示的に設定する。空テーブルを検出してサンプル値を補う処理は使用しない。

対象 正規の投入方法 切替前の確認
初期管理者 外部認証と対応付ける一回限りのオフラインCLI 本番認証でログイン・ログアウトでき、adminがちょうど意図した人数存在する
その他の職員 初期管理者ログイン後の職員管理画面、または監査可能な職員用CLIインポート 氏名、メール、ロール、業務権限、有効状態、外部認証対応が職員台帳と一致する
担当クラス 職員管理画面の担当クラス設定、または職員用CLIインポート 対象年度、担当クラス、担当期間が一致する
延長保育料金ルール /extended-care-fees/settingsから管理者が明示的に作成する。将来CLI化する場合も同じ検証ロジックを使用する 適用期間、開始時刻、猶予、丸め、単価、日額上限を二者確認する
施設共有・行事カレンダー カレンダー画面で管理者が明示的に作成し、職員を共有メンバーへ設定する。将来CLI化する場合も同じ権限検証を使用する カレンダー数、所有者、メンバー、権限、初期予定を確認する

延長保育料金またはカレンダーを限定ベータの対象外にする場合は、未設定のまま放置せず、「利用しないため0件」と移行承認記録へ明記し、関連画面・計算・通知が誤って利用されないよう無効化または運用禁止を設定する。

職員アカウントのCSVやCLIには認証資格情報を含めない。外部認証は本人識別を担当し、open-hoikuictはロール、業務権限、担当クラス等の認可情報を管理する。

切替前の初期構成順序

  1. 新規DBへスキーマとマイグレーションを適用する。
  2. クラス、家庭、園児、保護者アカウント、紐づけ等の移行パッケージを確定する。
  3. 外部認証を設定し、オフラインCLIで初期管理者を1人以上作成する。
  4. 環境を外部非公開または接続元制限付きで起動し、初期管理者の本番認証を確認する。
  5. 職員管理画面または職員用CLIで、残りの職員・権限・担当クラスを登録する。
  6. 利用する延長保育料金ルールを管理画面で登録し、二者確認する。
  7. 利用する施設共有・行事カレンダーとメンバーを登録する。
  8. 初期構成の期待件数と実件数を照合し、監査記録とバックアップを取得する。
  9. 再起動不変検査とスモークテストに合格してから利用者へ公開する。

作業条件

  • 移行元CSV一式と現在のDBを事前にバックアップする。
  • 取込中はアプリケーションを停止し、利用者による更新を発生させない。
  • 本番用環境変数と新規DBの接続先を作業前に確認する。
  • 事前検証から確定まで、同一の移行マニフェストとCSV一式を使用する。全ファイルのハッシュ値を事前検証結果へ記録し、確定時に再照合する。
  • 事前検証後に、open-hoikuictの内部IDをCSVへ追記する等の手作業を行わない。変更が必要な場合は新しい移行パッケージとして事前検証からやり直す。
  • いずれかの取込または整合性検査が失敗した場合は、接続先を切り替えず新規DBを破棄して再実行する。
  • 旧DBはロールバック可能な期間、読み取り専用で保管する。

必要なCSVと取込順序

次の順序で取り込む。

  1. クラス
  2. 家庭
  3. 園児
  4. 保護者アカウント
  5. 保護者・園児紐づけ
  6. 家庭共有プロフィールの構築・同期

ベータ移行ランナーは、1から6を個別の手作業として実行せず、移行パッケージ全体を先に事前検証し、依存順に1トランザクションで確定する。途中で失敗した場合は全データ種別をロールバックする。

ベータ移行用の識別列

CSV 必須の移行元識別列 参照方法
クラス 移行元ID クラス自身の識別
家庭 移行元ID 家庭自身の識別
園児 移行元ID移行元家庭ID、必要に応じて移行元クラスID 家庭・クラスCSVの移行元IDを参照
保護者アカウント 移行元ID移行元家庭ID 家庭CSVの移行元IDを参照
保護者・園児紐づけ 移行元保護者ID移行元園児ID。紐づけ自体に旧システムIDがある場合は移行元ID 保護者・園児CSVの移行元IDを参照

内部ID列は通常のインポート・エクスポートとの互換性のため残すが、空DBへ投入するベータ移行パッケージでは空欄にする。移行元IDと名称・メール等が同時に指定された場合、移行元IDで参照先を決定し、他の値は一致検証に使用する。

6の処理はベータ開始前に実装する。ParentAccountParentChildLinkを正規の入力元として園児ごとの保護者表示情報を構築する。同じ家庭の全園児へ同じ保護者プロフィールを直積展開してはならない。家庭住所・家庭電話等の共有項目だけを家庭単位で同期し、園児別のGuardianとアクセス権限は明示リンクに従う。

氏名のカナなど、保護者アカウントCSVに存在しない必須表示項目が必要な場合は、以下のいずれかを移行実装時に決定する。

  • 保護者CSVへ不足列を追加する。
  • 家庭共有プロフィール専用CSVを追加する。
  • 移行元データから補完する変換処理を用意する。

表示名からの推測だけで氏名を分割・補完する処理は、表記揺れや外国人氏名に対応できないため標準方式にしない。

事前検証

確定取込前に、少なくとも以下をエラーまたは警告として検査する。

エラー

  • 必須CSVまたは必須列が不足している。
  • source_systemが未指定である。
  • 必須の移行元IDが空欄である。
  • 同一メールアドレスの保護者アカウントが複数存在する。
  • 同一データ種別でsource_system + 移行元IDが複数行に存在する。
  • 園児が存在しないクラスまたは家庭を参照している。
  • 保護者・園児紐づけが存在しない保護者または園児を参照している。
  • 保護者・園児紐づけの保護者と園児が異なる家庭に所属している。判定には各CSVを反映した後の予定family_idを使用する。
  • CSVにない保護者・園児リンクが、家庭同期または起動時処理によって1件以上自動生成される。
  • 1件の園児が複数の家庭へ所属している。
  • CSV間で同じ移行元IDが異なる人物・家庭を示している。
  • 新規空DB用パッケージの内部ID列に値が設定されている。
  • 日付、在園状態、メールアドレス等が規定形式に合わない。

警告

  • 氏名と生年月日が一致する園児が複数いる。
  • 氏名と電話番号が一致する保護者が複数いる。
  • 保護者アカウントのない家庭、または園児のいない家庭がある。
  • 主連絡先がいない、または複数いる園児がいる。
  • 家庭内で住所や電話番号が一致しない。
  • 現行同期処理を適用した場合にCSV外で生成されるリンクの家庭別件数。1件以上の場合は情報を警告欄に表示するとともに、上記エラーとして確定を拒否する。

同姓同名だけではエラーにしない。識別情報の衝突または参照先を一意に決定できない場合にエラーとする。

取込後の整合性検査

アプリケーションを公開する前に、次を自動検査する。

  • SQLiteの外部キー検査結果が0件である。
  • クラス、家庭、園児、保護者アカウントについて、CSVごとの入力件数とDBの作成・更新件数が一致する。
  • 保護者・園児紐づけの期待集合は、検証済みCSVの重複を除いた(移行元保護者ID, 移行元園児ID)の集合とする。期待件数はこの集合の要素数であり、Σ家庭 |保護者| × |園児|ではない。
  • 取込後の対象ParentChildLink集合が期待集合と完全一致し、CSVにないリンクが0件である。単なる件数一致ではなく組の一致を検査する。
  • 全移行元IDについて、対応する内部IDが一意に割り当てられている。
  • CSV間参照が、移行元IDと内部IDの対応表どおりに保存されている。
  • すべての園児が意図した家庭とクラスに所属している。
  • すべての有効な保護者アカウントに意図した園児との紐づけがある。
  • すべての保護者・園児紐づけについて、保護者アカウントと園児のfamily_idが一致する。
  • 家庭共有プロフィールと、その家庭に属する全園児のGuardianが一致する。
  • 保護者アカウント、続柄、主連絡先と画面上の保護者表示に矛盾がない。
  • デモ用メールアドレス、電話番号、氏名、固定IDが残っていない。
  • アプリケーションを再起動した後も、保護者名および紐づけが変化しない。
  • 再起動前後で、全ParentChildLink(parent_account_id, child_id, relationship_label, is_primary_contact)集合が変化しない。
  • 再起動前後で家庭数が変化しない。
  • 再起動前後で、全園児のid -> family_id対応が変化しない。
  • 再起動前後で、全保護者アカウントのid -> family_id対応が変化しない。

再起動に関する項目は必須とする。起動時のbootstrap_family_data()による家庭統合、family_id書換え、および家庭同期処理による保護者情報の上書きを検出するため、取込直後と再起動後のスナップショットを比較する。

画面確認

自動検査後、抽出した家庭について次の画面を目視確認する。

  • 園児一覧の家庭名・保護者名
  • 園児詳細の住所・電話番号・保護者情報
  • 兄弟姉妹の家庭共有情報
  • 保護者アカウント一覧
  • 保護者ポータルで閲覧できる園児

最低でも、兄弟姉妹あり、父母2名、保護者1名、同姓同名、退園児を含む家庭を確認対象にする。

部分紐づけの確認では、同じ家庭に園児が2名以上いる状態で、一方だけに紐づく保護者アカウントを用意する。当該アカウントから、紐づく園児だけが一覧・詳細・連絡・通知等で閲覧でき、もう一方の園児のURLを直接指定してもアクセスできないことを確認する。

切替およびロールバック

  1. 新規DBの自動検査と目視確認を完了する。
  2. 新規DBの最終バックアップを取得する。
  3. アプリケーションの接続先を新規DBへ切り替える。
  4. 起動後検査と主要画面のスモークテストを実施する。
  5. 問題があればアプリケーションを停止し、接続先を旧DBへ戻す。

旧DBの削除時期は別途定める個人情報の保存・廃棄ルールに従う。

監査記録

移行ごとに以下を記録する。

  • 実施日時、実施者、承認者
  • 対象環境とDB識別子
  • 使用したCSVのファイル名とハッシュ値
  • 各データ種別の入力、作成、更新、スキップ、エラー件数
  • 初期管理者、全職員、担当クラス、料金ルール、カレンダー、カレンダーメンバーの期待件数と実件数
  • 初期管理者CLIの実行結果と本番認証確認結果
  • 料金ルールおよびカレンダーを利用しない場合は、その判断、承認者、関連機能の無効化・運用禁止方法
  • 事前検証および取込後検査の結果
  • バックアップ先と復元確認結果
  • 接続先切替時刻とロールバック有無

CSVの内容そのものや個人情報を通常のアプリケーションログへ出力しない。

ベータ開始の受け入れ条件

  • 新しい空DBを使用した移行リハーサルを1回以上完了している。
  • すべての実行環境でinitialize_application()が、空DBへデモ・サンプル・業務初期データを投入しない。
  • ベータ・本番の起動手順、コンテナentrypointおよび運用スクリプトがデモシードコマンドを実行しない。
  • 空DBでの初回起動および再起動後も、デモデータが0件であることを自動テストで確認している。
  • 初期管理者作成CLIが実装され、外部認証識別子とUserを安全に対応付けられる。
  • 初期管理者が本番認証でログイン・ログアウトでき、管理画面へアクセスできる。
  • 全職員のロール、業務権限、有効状態、担当クラスが承認済み職員台帳と一致する。
  • 延長保育料金ルールとカレンダーを、明示的に設定して検証済み、または利用しないことを承認・記録済みである。
  • 職員、料金ルール、カレンダー等の初期構成件数が監査記録と一致する。
  • 内部IDとは独立したsource_system + 移行元IDによる照合とCSV間参照が実装されている。
  • 内部ID列を空欄にした移行パッケージを、途中のCSV書換えなしで空DBへ一括取込できる。
  • 同じ移行パッケージを再検証・再実行しても重複レコードが作成されない。
  • 事前検証時と確定時に全CSVのハッシュ値が一致することを確認している。
  • 家庭共有プロフィール構築・同期処理が実装され、自動テストがある。
  • sync_parent_child_links()が家庭内直積を生成せず、CSVにないリンクを追加しない。
  • 保護者ポータルの全アクセス判定がParentChildLinkを根拠とし、family.childrenによるアクセス拡張を行わない。
  • 同一家庭の一部園児だけに紐づく保護者を作成でき、未紐づけ園児を一覧・直接URL・更新APIのいずれからも閲覧・操作できない。
  • 保護者・園児紐づけの期待集合とDBの実集合が完全一致し、CSV外リンクが0件である。
  • 取込処理が途中失敗した場合に未完成DBへ切り替わらない。
  • 全事前検証エラーが解消されている。
  • 全取込後整合性検査に合格している。
  • 家庭をまたぐ保護者・園児紐づけが0件である。
  • 再起動前後で保護者情報、家庭数、全園児のfamily_id、全保護者アカウントのfamily_idが変化しない。
  • デモデータが0件であることを確認している。
  • バックアップからの復元および旧DBへの切戻しを確認している。
  • 移行実施者と承認者が結果を記録している。