SaaSプラットフォームで組織を無効化する処理は、active = falseのようなフィールドを変更するだけで済ませるべきではありません。この変更によって画面上ではアカウントが非表示になっても、ユーザーのセッションが有効なまま、連携機能がデータを送信し続ける、またはキュー内のジョブがリソースを変更し続ける可能性があります。PHP製SaaSで組織アカウントを確実に無効化するには、各状態の意味を定義し、ID管理、処理、データへの影響を調整する必要があります。
目標は、操作の結果を検証可能にし、途中で失敗した場合でも、影響を重複させたり権限に不整合を残したりせずに続行できるようにすることです。そのためには、ライフサイクルだけでなく、実行と復旧の手順も設計する必要があります。
一時停止、終了、削除を区別する

これらの用語は、それぞれ異なる判断を表します。一時停止は通常、一時的な措置です。組織を再有効化できるように保持しながら、特定の操作を禁止します。終了は運用上の関係が終わったことを示し、アクセスの失効やタスクのキャンセルを伴うことがあります。削除はデータに影響するため、保持ルール、法的義務、製品ポリシーに従う必要があります。
この3つの状況を1つのフラグで表すのは避けてください。明示的なモデルには、active、suspending、suspended、closing、closed、deletion_pendingなどの状態を含められます。具体的な名前は製品によって異なりますが、各状態の意味、遷移条件、許可される操作を定めることが重要です。
- 一時停止:新たな業務操作を禁止しつつ、データを保持し、必要な管理操作は許可する。
- 終了:通常の活動を停止し、アクセスを無効化して、終了処理を完了する。
- 削除:一時停止の暗黙の結果とせず、定められたポリシーに従ってデータを削除または匿名化する。
状態遷移と権限をモデル化する
ステートマシン、またはそれに相当する遷移ルールを定義します。たとえば、有効な組織は一時停止状態に遷移できます。終了要求によってclosing状態に入り、所定の確認が完了した後にのみclosedへ移行します。許可されていない遷移は、理解しやすく記録可能な理由とともにアプリケーションで拒否する必要があります。
認可チェックでは、ユーザーのロールに加えて、サーバー側で組織の状態も評価します。画面上のボタンを非表示にしても権限は失効しません。PHPアプリケーションでは、コントローラーに分散した検証に依存せず、この判断をドメインサービス、ミドルウェア、または再利用可能なポリシーに集約してください。
各段階で許可される操作を明確にします。たとえばclosing中は、エクスポートや請求書の閲覧を許可しつつ、ユーザーの作成、業務プロセスの開始、連携設定の変更は禁止する場合があります。この取り決めにより、各コンポーネントが「無効」を互いに矛盾する意味で解釈することを防げます。
アクセス、セッション、認証情報を失効させる
終了処理では、組織に関連するすべてのアクセス経路を対象にします。Webセッション、APIトークン、サービスキー、保留中の招待、OAuth認証情報、委任アクセスが含まれます。それぞれの発行元と無効化方法を特定してください。未承諾の招待も将来アクセスを付与する可能性があるため、取り消すか、使用できない状態にする必要があります。
セッションの失効方法は、その管理方式によって異なります。サーバー側に保存するセッションであれば直接無効化できますが、自己完結型トークンを使う場合は、リクエストごとに組織の状態を確認する、失効リストを使う、または有効期限を短くする、といった対策が必要になることがあります。適切な方法はリスクレベルと性能要件によって異なりますが、まだ有効期限を迎えていないトークンよりも終了状態を優先しなければなりません。
複数の組織に所属するユーザーも考慮してください。ある企業を無効化しても、そのユーザーの個人アカウントや他の顧客への正当なアクセスまで自動的にブロックすべきではありません。制御は組織のコンテキストと、各リクエストで有効な権限に対して適用します。
キュー、Webhook、連携を停止する
データベースの状態を変更しただけでは、すでにキューに登録されたジョブはキャンセルされません。キューのコンシューマー、スケジュールタスク、インポート・エクスポート処理、同期、通知を確認してください。各ワーカーは処理を実行する前に、その操作について組織が引き続き有効かを確認する必要があります。必要に応じて保留中のジョブを破棄またはキャンセルし、停止できなかったものを記録します。
送信Webhookについては、すでに生成されたイベントを配信するのか、キャンセルするのか、監査用に保持するのかを定めます。受信側の連携では、外部プロバイダーが終了通知をまだ受け取っていなくても、認証情報を無効化し、新たなリクエストを拒否します。第三者が期限内に切断を完了することを前提にしないでください。
分散システムでは、これらの処理とデータベース更新が単一のアトミックなトランザクションを構成するとは限りません。手順を管理された順序で実行し、適切であればトランザクショナル・アウトボックスパターンを使って状態変更イベントを発行します。コンシューマーでは、冪等な操作によってメッセージの重複に対応できるようにしてください。
利用停止を再開可能かつ監査可能にする
利用停止は、識別子、開始日時、実行者、該当する場合は理由、フローのバージョン、各段階の結果を持つ操作として表現します。段階には、操作のブロック、認証情報の失効、タスクのキャンセル、連携先への通知、確認処理などがあります。保留中、完了、失敗といった状態を、診断に役立つ情報とともに記録します。ただし、秘密情報や不要な個人データは保存しないでください。
いずれかの段階で失敗した場合、有害な影響を繰り返さずに再試行できるようにします。たとえば、すでに失効済みの認証情報を再度失効させても安全であるべきです。再試行できる一時的なエラーと、対応が必要なエラーを区別してください。非同期タスクを開始しただけで、終了処理を完了とマークしてはなりません。
再有効化の意味も定義します。一時停止は許可された操作を復元することで解除できますが、終了済みの組織を再有効化しても、削除済みの認証情報やキャンセル済みのジョブを自動的に復元すべきではありません。何を復元するのか、何に管理者の操作が必要なのか、何が取り消せないのかをポリシーで明確にします。
データの扱いを決める
データを削除する前に、組織だけに依存するレコード、運用上または法的な理由で保持すべきレコード、共有情報の一部であるレコードを特定します。ドキュメント、監査ログ、請求書、バックアップ、外部プロバイダーに保存されたデータの扱いも明確にしてください。アカウントを削除しても、すべてのコピーが直ちに消えるとは限りません。システムで保証できない期限を約束せず、適用されるルールを説明します。
削除を非同期で行う場合は、deletion_pendingやdeletedなどの状態を明示し、データの種類ごとに結果を記録します。匿名化する場合は、合理的な再識別を防ぎ、保持すべき参照関係を壊さないことを確認してください。判断は、製品に適用される義務とポリシーに沿う必要があります。
処理全体を検証し、テストする

利用停止が完了したことは、成功メッセージだけでなく、検証によって証明できなければなりません。組織で禁止対象の操作ができないこと、対象となる認証情報が使えないこと、招待が無効化されていること、矛盾するジョブが実行中でないことを確認します。連携の状態と、継続的な対応が必要な例外も確認してください。
代表的な状況を対象に、自動テストと運用テストを実施します。
- 一時停止または終了の重複要求によって、影響が重複しないこと。
- アクセス失効後、連携の停止前に失敗するケース。
- ネットワークエラーやプロバイダーの応答失敗後の再試行。
- 一時停止した組織の再有効化と、終了済みアカウントに対する制限。
- 複数の組織で有効なユーザーと、状態変更前に開始されたキュー内のジョブ。
確認可能なチェックリストに、保留中および失敗した処理のメトリクスを組み合わせると、停止したままの終了処理を検出しやすくなります。重要なのは、利用停止を状態、権限、影響が定義された業務プロセスとして扱うことです。こうすることで、PHP製SaaSの組織アカウントの無効化は単独の変更ではなく、すべてのコンポーネントにおいて制御可能で復旧でき、一貫性のある状態遷移になります。



