データ保持・削除ポリシーは、単一のDELETE文では実装できません。PHPアプリケーションでは、同じ情報が複数のテーブル、ファイル、キャッシュ、ログ、外部サービスに存在する場合があります。主テーブルの行だけを削除すると有効なコピーが残ることがあり、依存関係を確認せずに削除すると、処理に支障をきたしたり、保持すべきデータを消したりするおそれがあります。
実務上の目標は、各ルールを、対象データの特定、適切な処理の適用、例外への対応、検証可能な証跡の記録を行うフローにすることです。ポリシーは、プロダクト、技術、データの各担当部門と合意し、事業に適用される要件と照らし合わせる必要があります。普遍的な法定保存期間があると決めつけてはいけません。期間は状況によって異なるため、自動化する前に検証する必要があります。
データの分類と保持ルールから始める

削除を設計する前に、目的と用途に応じて情報を分類します。プロフィール、未完了の処理に必要な住所、活動履歴、会計記録は、同じアカウントに関連付けられていても、それぞれ異なるルールが適用される場合があります。
各カテゴリについて、少なくとも次の項目を記録してください。
- 目的と責任者:保存する理由と、保持について判断するチーム。
- ルールを開始するイベント:アカウントの閉鎖、関係の終了、検証済みの申請など。
- 期間と条件:正当な理由による一時停止の可能性を含め、処理を確認または実行する時期。
- 処理:削除、匿名化、アクセスを制限した保持、または手動レビューへの移行。
- 依存関係:案件の解決を宣言する前に完了すべきシステムとプロセス。
「保持する」とは、便宜上、無期限に保存することではありません。理由、範囲、見直し日または見直し条件が必要です。情報の一部を業務上の必要性から保持する場合は、それをほかの情報から分離し、アクセスできる人を制限してください。
コピー、参照、接続先システムを棚卸しする
棚卸しでは、データベースのスキーマだけでなく、データの実際の流れを追う必要があります。関連テーブル、JSONフィールド、アップロードされたファイル、エクスポート、検索インデックス、キャッシュ、キュー、アプリケーションログ、連携システムを調査してください。また、レポート、サポートツール、分析、インポート処理など、コピーを生成するフローも含めます。
各保存先について、データの検索に使う識別子、責任者、削除または更新の方法、システムが利用できない場合の対応を記録します。外部キーとアプリケーションロジックを通じた関係も確認してください。データベースの制約によって連鎖削除が妨げられることもあれば、連鎖削除によって想定以上のデータが消えることもあります。
バックアップは別のケースとして扱ってください。バックアップ全体を復元しないと個別項目を削除できない場合があります。アクセス制限の方法、保存期間、復元後に削除済みデータが稼働中のシステムへ戻るのを防ぐ手順を定めます。この判断を文書化し、インフラストラクチャとコンプライアンスの担当者に確認してください。
削除、匿名化、保持のいずれにするか決める
物理削除は稼働中のシステムからデータを取り除きますが、すべての記録に適した方法とは限りません。統計情報を保持する必要があり、個人との紐付けを実効的に取り除ける場合は、匿名化が適切なことがあります。名前を固定IDに置き換えるだけでは、関係を復元できる別のテーブルが存在する場合、不十分です。
業務処理や、妥当性が確認された義務のために引き続き必要なデータは、アクセスを制限して保持できる場合があります。そのデータを分離し、専用の権限と見直しルールを設定してください。紛争、依存関係の不明、本人情報の不一致など、適用すべき処理を安全に判断できない場合は、場当たり的に処理せず、レビューキューに回してください。
機能上の影響も確認する必要があります。アカウントの削除後に、注文、サブスクリプション、チケット、APIキー、共有ドキュメントをどう扱うかを明確にしてください。動作は、インターフェース、PHPロジック、接続先サービスの間で明示され、一貫している必要があります。
冪等性と可観測性を備えたフローを実装する
削除処理は、キューまたはスケジュールタスクを使ってバックグラウンドで実行することがよくあります。たとえば、申請済み、検証済み、処理中、外部システム待ち、完了、レビュー要、といった明示的な状態で案件をモデル化します。許可される状態遷移と、誰が再試行または例外をクローズできるかを定義してください。
冪等性は不可欠です。ある段階を繰り返しても、副作用が重複したり損害が生じたりしてはなりません。ファイルを削除する前に存在を確認し、申請を処理する際は現在の状態を検証してください。外部サービスを呼び出す場合、利用可能であれば冪等性の仕組みを使用します。冪等性を保証できない場合は、応答を記録し、盲目的に再試行する前に照合の手順を設計してください。
PHPでの概念的な構成では、オーケストレーションとシステムごとの処理を分離できます。
foreach ($steps as $step) {
if ($step->isComplete($requestId)) {
continue;
}
$step->execute($subjectReference);
$step->markComplete($requestId);
}
この例では、分散トランザクションの問題は解決できません。データベースと外部プロバイダーが同じトランザクションを共有するとは限らないためです。進捗を確実に保存し、各段階のエラーを処理して、作業を再開できるようにしてください。処理が途中で失敗した場合は、残作業が状態から分かるようにし、完了として扱ってはいけません。
新たな個人データのコピーを作らずに実行を記録する
トレーサビリティがあれば、誰またはどのプロセスが、いつ、どの申請に対して、どのような結果で処理したかを確認できます。運用ID、状態、処理段階、診断に役立つエラーコードを記録してください。氏名、メールアドレス、書類、ファイルの内容、APIリクエスト全体をログにコピーしないでください。
仮名化されたユーザーIDも、本人を再特定できる場合は機微な情報であり続けます。ログへのアクセスを制限し、保存期間を限定し、可能な限り運用情報と本人情報を分離してください。エラーメッセージでは、監視ツールに個人データを漏らさず、影響を受けたシステムを特定できるようにします。
結果を確認し、例外に備える
テストでは、通常ケースと部分的な失敗の両方を扱う必要があります。テストデータを使い、主テーブルだけでなく、棚卸しで特定した保存先を確認してください。削除を妨げる関係、存在しないファイル、利用できない外部プロバイダー、再試行、レビューが必要な例外などのシナリオを含めます。
運用チェックリストでは、次の点を確認します。既知のコピーをすべて特定できたか。各カテゴリに予定した処理を適用したか。未完了の段階は残っているか。外部システムは結果を確認したか。ログには必要な情報だけが含まれているか。再試行しても処理の安全性は保たれるか。棚卸しから漏れた新しいテーブル、連携、データ経路を検出するため、定期的な確認も追加してください。
仮定の例:アカウントの閉鎖

ある人がPHPアプリケーションでアカウントの閉鎖を申請したとします。フローは申請を検証し、プロフィール、ファイル、活動履歴、未完了の業務処理に関連する情報について定められたルールを確認します。対象となるプロフィールとファイルは削除されます。承認済みの理由がある場合は、一部の記録をアクセス制限付きで保持します。分析用データは、実効的に匿名化されている場合に限り残します。
アプリケーションは、メールアドレスやファイルの内容を含めずに各段階を記録します。外部サービスが応答しない場合、案件は保留となり、ポリシーに応じて後続プロセスが再試行するか、担当者の介入を求めます。必要なすべての処理が確認された場合、または正式な例外が文書化され承認された場合に限り、完了としてマークします。
実装前に、未決事項を解消してください。データを含むシステム、例外を承認する担当者、保存先ごとの「完了」の定義、バックアップの扱い、失敗を確認する担当者を明確にします。この定義によって、削除の意図を、保守・検証が可能で安全なプロセスにできます。



