PIIを漏らさずにデモとQA用のデータベースシードを作る
デモとQA向けに現実的で再現可能なデータセットを作る方法。匿名化とシナリオベースのシードスクリプトでPIIを守る方法を解説します。

なぜシードデータがデモとQAで重要なのか
空のアプリは判断しにくいです。デモで空のテーブルと数件の “John Doe” のようなレコードだけだと、優れた製品でも未完成に見えてしまいます。ワークフローやエッジケース、成果が見えません。
QAでも同じ問題が起きます。薄い、意味のないデータだとテストはハッピーパスに留まり、バグは本番の複雑さが出てくるまで隠れます。
問題点は、「現実的な」データはしばしば本番のコピーから始まることです。それがプライベート情報の漏洩につながります。
PII(個人を特定しうる情報)は、氏名、メール、電話番号、住所、政府発行ID、顧客メモ、IPアドレス、精密な位置情報、さらに生年月日と郵便番号の組み合わせのようなユニークな組み合わせまで含みます。
良いデモやQA用のシードデータは次の3つの目標をバランスします:
- 現実感: 実際の業務で扱うように見える(さまざまなステータス、タイムスタンプ、失敗や例外)。
- 再現性: 必要に応じて数分で同じデータセットをどの環境でも再構築できる。
- 安全性: 実際の顧客データを使わない、もしくは“ほぼ匿名化”のような危険な残置がない。
テストデータをプロダクト資産として扱ってください。オーナーシップ、許容基準、リリースプロセスでの扱いが必要です。スキーマが変わればシードデータも変えないと、デモが壊れ、QAが信頼できなくなります。
AppMasterのようなツールでアプリを作る場合、シードされたデータセットは認証、役割、ビジネスプロセス、UI画面のエンドツーエンド検証に役立ちます。うまく設計すれば、シードデータは誰のプライバシーも危険にさらさずにアプリを見せ、テストし、信頼する最速の方法になります。
デモやQA用データが通常どこから来て、なぜ失敗するのか
ほとんどのチームが求めるのは、現実味があり、素早く読み込めて、共有しても安全なデータです。しかし「現実的」に最速で到達する方法は、最もリスクが高いことがよくあります。
一般的なソースには、本番の完全または部分コピー、オペや財務の古いスプレッドシート、サードパーティのサンプルデータセット、名前やメール、住所を生成するランダムジェネレータがあります。
本番コピーが問題になるのは、実在の人物が含まれるからです。メールや電話、住所のような明白なフィールドを削除しても、職種+小さな町+ユニークなメモの組み合わせなどで身元が特定されることがあります。さらに、スクリーンショット1枚が営業資料で共有されるだけで報告すべき事故になり得ます。
見落とされがちなPIIは整った列に入っていません。フリーテキスト(メモ、description、チャットの書き起こし)、添付ファイル(PDF、画像、エクスポートされたレポート)、サポートチケットや内部コメント、データベースに格納された監査ログ、JSONブロブやインポートされたメタデータを注意深く見てください。
もう一つの問題は、目的に合わないデータセットを使うことです。QAはエッジケースや壊れた状態を必要とします。営業デモは分かりやすいハッピーパスが必要です。サポートやオンボーディングは認識しやすいワークフローとラベルが必要です。トレーニングは全員が同じ手順を見る再現可能な演習を必要とします。
単純な例:カスタマーサポートのデモで「速さのために」本物のZendeskエクスポートを使うと、メッセージ本文、署名、貼り付けられたスクリーンショットが含まれます。メールをマスクしても、メッセージテキストに氏名や注文番号、配送先住所が残っていることがあり、「十分に安全」だと思ったものが実は危険になることがあります。
何かを生成する前にデータルールを決める
テストデータを作る前に簡単なルールを書いてください。これがないとよくある失敗につながります:誰かが「とりあえず」で本番をコピーし、いつのまにかそれが広まることです。
まずPIIに関して厳格な線を引きます。最も安全なデフォルトは単純です:データセット内の何も実在の人、顧客、従業員のものではない。これは明白なフィールドだけでなく、組み合わせると特定につながる“ほぼPII”も含みます。
実用的な最小ルールセット:
- 実名、メール、電話番号、ID、住所、決済情報は使用しない。
- 実際のチケット、チャット、メモ、コールログの文面をコピーしない。
- アプリが特定の小さな顧客群に使われている場合、実在の会社名は使わない。
- 実際のデバイス識別子、IP、位置情報は使わない。
- 添付ファイル、画像、フリーテキストに隠れたPIIがないことを確認する。
次に、何を現実的に見せる必要があるか、何は簡略化できるかを決めます。フォーマット(メール形式、電話桁数、郵便番号)は重要で、関係性(注文には顧客が必要、チケットには担当者が必要)はさらに重要です。ただし、多くの細部はフローが機能する限り単純化して構いません。
データセットのサイズの階層をあらかじめ定義しておくと議論が減ります。小さな“スモーク”セットは高速にロードし、コアパスをカバーします。通常のQAセットは典型的な状態と役割をカバーします。重いセットはパフォーマンスチェック用で、常時使うものではありません。
最後に、どのデータセットにもラベルを付けて、環境に現れたときに何のためのものか分かるようにします:データセット名と用途(demo、QA、perf)、アプリやスキーマに対応するバージョン、作成日時、合成なのか匿名化なのか。
AppMasterのようなプラットフォームを使う場合、これらのルールをシードプロセスのそばに置いて、モデルが変わっても再生成されたアプリと再生成されたデータが整合するようにします。
現実感を保ちながら匿名化する手法
目的は明確です:データは実際の振る舞いを示すが、決して実在の人物を指さないこと。
混同されやすい3つの用語:
- マスキングは値の見た目を変える(表示専用の場合が多い)。
- **疑似匿名化(Pseudonymization)**は識別子を一貫した代替値に置き換え、テーブル間の関連を保つ。
- 真の匿名化は組み合わせても再識別できない状態にする。
形は保ちつつ意味を変える
フォーマット保持マスキングは同じ“感触”を保つので、UIやバリデーションが引き続き動作します。良い偽メールは@とドメインがあり、良い偽電話番号はアプリの許容フォーマットに合います。
例:
- Email:
[email protected]->[email protected] - Phone:
+1 (415) 555-0199->+1 (415) 555-7423 - Address line:
742 Evergreen Terrace->615 Pine Street
xxxxxx のような単純なマスクよりも、並べ替えや検索、エラー処理が本番に近い挙動になります。
関係を保つためにトークン化を使う
トークン化はテーブル間で一貫した置換をする実用的な方法です。ある顧客がOrders、Tickets、Messagesに現れるなら、全て同じ偽顧客になるべきです。
簡単な方法は元の値ごとにトークンを生成してマッピングテーブルに保存するか、決定論的な関数を使うことです。そうすれば、customer_id=123 は常に同じ偽名、偽メール、偽電話にマップされ、結合が機能します。
また、誰かを偶発的にユニークにしないように考えてください。名前を消しても、希少な職種+小さな町+正確な生年月日などで人物が特定されることがあります。日付を丸める、年齢をバケット化する、珍しい組み合わせを避けるなど、似たグループを作ることを目指してください。
PIIのホットスポット(人が忘れがちな場所も含む)を洗い出す
氏名やメールなど明白なフィールドは問題の半分に過ぎません。本当に危険なのは、組み合わせると個人が浮かび上がる場所です。
実用的な出発点は、一般的なPIIフィールドと安全な置換案のマッピングを作ることです。一貫した置換を使えばデータは本番のように振る舞います。
| Field type | Common examples | Safe replacement idea |
|---|---|---|
| Names | first_name, last_name, full_name | 固定リストから生成した名前(シード付きRNG) |
| Emails | email, contact_email | example+{id}@demo.local |
| Phones | phone, mobile | 見た目は有効だがルーティングされないパターン(例:555-01xx) |
| Addresses | street, city, zip | 地域ごとのテンプレート住所(実在する通りは使わない) |
| Network IDs | IP, device_id, user_agent | デバイスタイプごとの定番値に置換 |
フリーテキストフィールドはPIIが最も漏れやすい場所です。サポートチケット、チャットメッセージ、notes、descriptionには氏名、電話番号、アカウントID、貼り付けられたスクリーンショットが含まれます。各フィールドに対して一つの方針を決め、パターンを赤actedする、短いテンプレートに置き換える、あるいはトーン(苦情、返金要求、バグ報告)に合った無害な文章を生成してください。
ファイルや画像は別途処理が必要です。アップロードはプレースホルダで置き換え、メタデータ(写真のEXIFなど)を削除してください。PDFや添付、アバター画像もチェックします。
最後に再識別に注意してください。珍しい職種、正確な誕生日、稀な郵便番号+年齢の組み合わせ、小さな部署の一人だけのレコードは個人を特定してしまいます。値を一般化し(日付は月/年にするなど)、小さなデータセットでユニークなレコードを作らないようにしてください。
シードデータを再現可能で再構築しやすくする
シードデータが毎回ランダムだと、デモやQAの信頼性が落ちます。バグはデータが変わったせいで再現できなくなり、昨日動いたデモが今日は壊れていることがあります。
シードデータはワンオフのスクリプトではなく、ビルド成果物として扱ってください。
決定論的生成を使う(完全なランダムは避ける)
固定シードと常に同じ出力を生むルールでデータを生成します。これにより安定したID、予測可能な日付、一貫した関係が得られます。
実用的なパターン:
- データセットごとに固定シード(demo、qa-small、qa-large)。
- 決定論的ジェネレータ(同じ入力ルールで同じ結果)。
- 「過去7日」のような範囲は基準日でアンカーして意味を保つ。
シードスクリプトを冪等にする
冪等とは何度実行しても安全に動くことです。QAが環境を何度も再構築する場合や、デモDBをリセットする場合に重要です。
アップサート、安定した自然キー、明確なクリーンアップルールを使ってください。例えば、既知のキーで「demo」テナントを挿入し、その後にユーザー、チケット、注文をアップサートします。削除が必要ならスコープを厳密に(デモテナントだけ)限定して、共有データを誤って消さないようにします。
データセットをアプリと一緒にバージョン管理してください。QAがバグを報告するときに「app v1.8.3 + seed v12」で正確に再現できることが理想です。
実際のワークフローに合ったシナリオベースのデータを作る
ランダムな行は作りやすいですが、デモには向きません。良いデータセットは物語を語ります:ユーザーは誰で、何をしようとしているか、何が失敗するか。
スキーマと関係性から始め、偽名からではなく、実世界で何が最初に存在し、何がそれに依存するかを考えてください。AppMasterのData Designerのような視覚ツールがある場合は、各エンティティを順に見ていくと良いです。
シードを現実的に保つ単純な順序例:
- まず組織やアカウントを作る。
- 次にユーザーと役割を追加する。
- コアオブジェクト(チケット、注文、請求書、メッセージ)を生成する。
- コメント、明細、添付、イベントなど依存レコードを付ける。
- 最後にログや通知を加える。
それからシナリオベースにします。単に「10,000件の注文」を作るのではなく、実際のワークフローに合う数個の完結した旅程を作ります。ある顧客は登録してアップグレードし、サポートチケットを開き返金を受ける。別の顧客はオンボーディングを完了しない。別の顧客は支払い失敗でブロックされる。
意図的にエッジケースを混ぜてください。オプションフィールドが欠けている、非常に長い値(500文字の住所行)、異常に大きな数字、古いバージョンのデータを参照するレコードなど。
状態遷移も重要です。複数のステータスにまたがるエンティティをシードして、画面やフィルタに表示されるものを用意します:New、Active、Suspended、Overdue、Archived。
シナリオとステートに基づくシードデータにすれば、QAは正しい経路をテストでき、デモは本番データを必要とせずに本当の成果を見せられます。
例:カスタマーサポートデモのための現実的なデータセット
シンプルなサポートダッシュボードを想像してください:エージェントがログインしてキューのチケットを見て、1つを開き、返信して閉じる。良いシードセットはその流れを信じられるものにしますが、本物の顧客データは使いません。
小さなキャストから始めます:顧客25人、エージェント6人、過去30日間にわたる約120件のチケット。目的は量ではなく、多様性です。火曜日の午後のサポートの様子に合うバリエーションが必要です。
重要なのはパターンであり、個人の身元ではありません。名前やメール、電話は合成にして、その他は本番のように振る舞わせます。データの“形”がストーリーを売ります。
含めるべき項目:
- ビジネス時間帯にピークがあり、夜間は静かで、いくつか古いチケットがまだオープンしているようなタイムスタンプ。
- ステータスの進行:New -> In Progress -> Waiting on Customer -> Resolved、現実的な時間差をつける。
- 割り当て:あるエージェントは課金カテゴリ、別は技術カテゴリを担当、1〜2回の引き継ぎも含む。
- 会話スレッド:チケットごとに2〜6件のコメント、添付は偽のファイル名で表現。
- 関連レコード:顧客プラン、最終ログイン、文脈用の軽量な注文や請求書テーブル。
意図的な問題も入れて、厄介な部分をテストします:同じ会社名で連続する2人の顧客(重複に見える)、支払い失敗でブロックされたアカウント、解除ワークフローをトリガーするロックされたアカウントなど。
同じデータセットがデモスクリプト(「ブロックされたユーザーを表示して解決する」)とQAテストケース(ステータス変更、権限、通知の検証)両方を動かせます。
ビルドを遅くしないデータサイズの決め方
最良のデモデータは機能を証明するために最小限のデータです。再構築に10分かかるなら、誰も再構築しなくなり、データは古くなり、ミスがデモに混入します。
用途ごとに2〜3種類のサイズを用意し、同じスキーマとルールでボリュームだけ変えます。これにより日常作業は速く保ち、ページネーションやレポートのようなエッジケースもサポートできます。
ボリュームの実用的な考え方:
- Smoke/UIセット(高速): テナント1、ユーザー5〜10、コアレコード30〜50(例:チケット40)で画面が読み込めるか確認。
- Functionalセット(現実的): テナント3〜5、合計ユーザー50〜200、コアレコード500〜5,000でフィルタ、役割別アクセス、基本レポートをカバー。
- Pagination/reportingセット: 各リストビューを少なくとも3ページ超えるレコード数(多くはリストごとに200〜1,000行)。
- Performanceセット(別扱い): 負荷試験用に10x〜100xのボリューム。PIIなしで生成し、デモとしては共有しない。
量より多様性が重要です。サポートアプリなら、ステータス(New、Assigned、Waiting、Resolved)やチャネル(email、chat)に跨るチケットをシードする方が、50,000件の同一チケットを投入するよりも効果的です。
分布は決定論的に保ちます。テナントごとに固定数とステータス分布を決め、純粋なランダムではなくルールで生成します。例えば、テナントごとに正確に New 20件、Assigned 15件、Waiting 10件、Resolved 5件、さらにOverdue 2件、Escalated 1件といった具合です。決定論的なデータはテストとデモを安定させます。
シードデータのよくあるミスと罠
デモを早く動かす最短ルートは最も危険であることが多いです:本番をコピーしてざっとマスクし、それで安全だと信じること。一つの見落とし(notes列など)で氏名やメール、内部コメントが漏れ、誰かがスクリーンショットを撮るまで気づかないことがあります。
別の罠はデータを過度にランダムにすることです。更新ごとに顧客も合計もエッジケースも変わると、QAは比較できずデモは一貫性を欠きます。毎回同じベースラインで、管理された小さな変動を持たせるのが望ましいです。
壊れた関係性は一般的で見つけにくい問題です。外部キーを無視したシードは孤立したレコードや不可能な状態を作ります。あるボタンが動いたときに関連アイテムが見つからないと画面は壊れて初めて気づきます。
後々最も痛いミスの例:
- 本番クローンをスタートにして、マスキングを検証せずに信頼する。
- テーブルごとに値を独立生成して関係が一致しない。
- 各実行で全てを上書きしてQAの安定ベースラインを壊す。
- ハッピーパスだけをシードして、キャンセル、返金、リトライ、解約、支払い失敗がない。
- シードデータを一度きりの作業と見なして、アプリが変わっても更新しない。
単純な例:サポートデモに40件のオープンチケットがあるが、再オープンはなくエスカレーションもなく、解約した顧客のケースがない。表面上は綺麗に見えても「エスカレーション後に顧客がキャンセルしたら?」という質問に答えられません。
デモ環境を共有する前の簡単チェックリスト
デモを見せる前やQA環境を他チームに渡す前に、見落としがある前提で素早く確認してください。データは現実的に感じられ、動作は本番に似ていて、共有しても安全であるべきです。
多くの問題を検出する5つの速攻チェック
- PIIスニッフテスト: データベースやエクスポートファイルを検索して
@、一般的な電話番号の形(10〜15桁、+符号、括弧)、テストでチームがよく使う名前の短いリストなどを探します。一つでも本物らしいレコードが見つかったら他にもあると考えてください。 - 関係性が保たれているか: 主要な画面を開いて必要なリンクが存在するか確認(すべてのチケットに顧客がいるか、すべての注文に明細があるか、すべての請求書に支払状態があるか)。
- 時間範囲が信じられるか: 日付がさまざまな期間に分かれているか確認(今日のレコード、先月のレコード、昨年のレコード)。すべてが「5分前」に作られているとチャートやアクティビティフィードは偽物に見えます。
- 再現性とアンカーレコード: 2回再構築して同じ件数とシナリオで依存するアンカーレコード(VIP顧客、未払い請求、優先チケット)を確認します。
- 隠れたデータソースがクリーンか: ログ、ファイルアップロード、メール/SMSテンプレート、メッセージ履歴、添付ファイルをスキャンします。PIIはエラートレース、CSVインポート、PDF請求書、メモに隠れがちです。
AppMasterでデモを作る場合、この流れはリリースルーチンに自然に組み込めます:アプリを再生成し、再シードして、チーム外に公開する前にチェックリストを走らせます。
次のステップ:アプリの進化に合わせてデモデータを安全に同期し続ける
安全なデモデータは一度きりの作業ではありません。アプリが変わり、スキーマが移り、「暫定的」なエクスポートがいつの間にか共有環境になることがあります。目標はデモとQAのデータセットをオンデマンドで再構築でき、自動で検証でき、既知のバージョンとして出荷できることです。
長続きするワークフロー:
- いくつかのシナリオ(見せたい・テストしたい正確なジャーニー)を定義する。
- それらのシナリオからシードを生成する(本番エクスポートからではなく)。
- チェックを実行する(PIIスキャン、サニティチェック、リファレンシャル整合性)。
- データセットにバージョンを付けて公開する(アプリバージョンにタグ付けし簡単な変更履歴を残す)。
- 定期的に、あるいはリリースごとに再構築してドリフトを早期に検出する。
スキーマ、ロジック、シードを揃えておくのが多くのチームの苦労する点です。データモデルが変わるとシードスクリプトが壊れたり、動作はするが半分だけ有効なデータを作ってバグを隠すような状況が起きます。
AppMasterでは、Data Designer(データモデル)とBusiness Process Editor(ワークフロー)がアプリの隣にあるため、これらの作業を一緒に保つのが比較的簡単です。要件が変わればアプリを再生成し、シードフローを同じビジネスルールに合わせて更新できます。
成長に合わせて安全を保つために、データセットを共有する前に必須のチェックをいくつか追加してください:実在のメールや電話がないこと、実運用からコピーしたフリーテキストがないこと、他システム経由で実際の人に戻れるIDがないこと。
まず一つのシナリオ(例えば「新規顧客がチケットを作成しサポートが解決する」)を選び、そのための小さなPII安全なシードデータセットを作り、2回再構築して再現性を確認してから、アプリの進化に合わせてシナリオを拡張していきます。
よくある質問
Seeded dataはアプリを完成した状態で見せ、テスト可能にします。空の画面や数件のプレースホルダだけでは見えないワークフローやステータス、エッジケースを確認できます。
まずは本番から始めないこと。スキーマやワークフローに合った合成データを使い、ステータスやタイムスタンプ、失敗例などの現実的な分布を加えると、誰の情報も晒さずに本番と似た振る舞いが得られます。
PIIとは、個人を直接または間接的に特定できるものすべてです:氏名、メール、電話、住所、ID、IPアドレス、正確な位置情報、さらに生年月日と郵便番号の組み合わせなど。フリーテキストや添付ファイルは見落とされがちな場所です。
何かを生成する前に、簡潔で譲れないルールを書いてください。良い基準は「データセット内の何も実在の人、顧客、従業員に属していてはならない」というものです。実運用からコピーしたメモやチケット、チャット、アップロードファイルは禁止にしましょう。
見た目だけを保つにはフォーマット保持マスキング、テーブル間で一貫性を保つにはトークン化や疑似匿名化を使います。結びつきを残す場合は一貫した代替値を使い、偶発的に特定できるパターンを作らないように注意します。
ノートや説明、チャット、コメントなどのフリーテキストは、テンプレート化して安全な文例で置き換えるか、パターンで削除します。ファイルはプレースホルダに差し替え、画像のEXIFのようなメタデータは削除してください。
固定シードとルールに基づく生成で決定論的に作成します。時間は基準日を決めて固定し、同じ入力なら同じ出力が得られるようにします。データセットにバージョンを付けてアプリ/スキーマと紐付けると再現性が保てます。
何度実行しても安全に動くようにします。アップサートや安定したナチュラルキーを使い、削除が必要な場合は範囲を限定(例:デモテナントのみ)して共有データを消さないようにします。
ランダム行を大量に作るのではなく、完全なジャーニーをいくつか作ります。ユーザーや役割、コアオブジェクト、従属レコードを自然な順序で生成し、複数のステータスや意図的なエッジケースを混ぜます。
素早い再構築用の小さな“スモーク”セット、通常QA用の現実的セット、ページネーションやパフォーマンス用の大きなセットを分けます。多様性を重視し、体裁より量を優先してビルド時間を抑えます。


