検索/マルチテナントの自動化ツールを、テナントとエディションを混ぜずに作る

マルチテナントの自動化ツールを、テナントとエディションを混ぜずに作る

コミュニティ版・エンタープライズ版・ホスティング版があるマルチテナントの自動化ツールのコードを書く時に使う。クエリを正しいプロジェクトで絞り、外へのHTTP通信を安全なクライアントに通してSSRFを防ぎ、依存関係を使うワークスペースに書き、全部のエディションでテストしてから終える。

このAIルールを使うには
## テナントのデータを分け、有料版のコードをコミュニティ版に入れない テナントの適用範囲、製品エディション、機能へのアクセス、ブランド表現を、安全性と動作を定める契約として扱う。 ### 分離を徹底する - プラットフォーム、プロジェクト、ユーザーの各階層で所有権を明示的にモデル化する。 - すべてのデータベースクエリを、正しいプロジェクト識別子またはプラットフォーム識別子で絞り込む。呼び出し側が後から結果を絞り込むことに決して依存しない。 - すべてのエンドポイントにアクセス制御の宣言を必須とする。 - 保護対象の動作より先にバックエンドの認可と機能ミドルウェアを適用し、利用できない有料機能には標準の`402`レスポンスを返す。フロントエンドのガードとクエリの有効化にも同じ制限を反映する。 ### エディション間の依存方向を保つ - プレミアム版やホスティング版は、登録済みのフックまたはインターフェースを通じてコミュニティ版の中核を拡張する。 - プレミアム版専用のアプリケーションコードをコミュニティ版のコードへ決してインポートしない。 - コミュニティ版のデフォルトには特定ブランドを付けず、ホスティング環境では設定済みのブランド表現を適用し、セルフホストのエンタープライズ版では適切なプラン機能に基づいてブランド表現を制限する。 - 顧客向けの動作を、コミュニティ版セルフホスト、エンタープライズ版セルフホスト、無料ホスティング版、有料ホスティング版、エンタープライズ向けホスティング版という5つの経路で検証する。 - 顧客向けの名前、色、ロゴ、サインイン画面、メッセージはすべて、製品ブランドをハードコードせず、設定された外観から決まるようにする。 ## 依存関係を使うワークスペースに書き、複数サーバーのデータをロックで守る 依存関係の所有元と並行データ処理の動作を明示し、ローカルでの成功が本番デプロイでも再現されるようにする。 ### パッケージ境界を維持する - 共有ライブラリは、薄くフレームワークに依存しない基盤から、厚いアプリケーションレベルのパッケージへ順序付ける。 - 再利用可能な連携機能と実行エンジンは薄いパッケージだけに依存させ、必要なアプリケーション動作は狭いフレームワーク層を通じて公開する。 - 各実行時依存関係はそれをインポートするワークスペースに宣言し、各テスト用またはツール用の依存関係はそのワークスペースの開発依存関係に宣言する。 - ルートのマニフェストは、リポジトリ全体のツールまたは本当に必要な起動要件だけに使う。 - バージョンを一貫して固定し、依存関係を変更した後は正規のインストーラーでロックファイルを更新する。 ### 永続化と並行処理を保護する - オブジェクトマッパーが新しいエンティティを自動検出しない場合は、明示的に登録する。 - 副作用を専用モジュールへ分離し、変更処理が成功した後に明示的に呼び出す。 - 複数サーバーで処理する場合は、分散ロック、キューの重複排除、または`skip-locked`セマンティクスを備えた行ロックを使う。 - マネージドサービスで利用できないデータベース拡張機能を避ける。 - 外部から渡されたオブジェクトは、データベースへ保存する前にサニタイズする。 ## anyや無理な型キャストを使わず、プロジェクト共通のヘルパーを使う 予測可能なインターフェース、データフロー、ファイル構成、共有ユーティリティを使う。 ### 型の整合性を保つ - `any`を使わない。正確な型を使うか、`unknown`を型ガードと組み合わせる。 - 型キャストで値を無理に通さない。元の型を修正するか、検証を追加するか、値の型を絞り込む。 - APIを使う前にライブラリのドキュメントを確認し、非推奨と記されたものは置き換える。 - 引数が1つを超える関数では、分割代入する単一のオブジェクト引数を使う。 - 関数の境界をまたぐデータフローは不変に保つことを優先し、呼び出し側が所有するオブジェクトを変更せず、新しいコレクションを構築して返す。 ### 規約を明示する - 同期および非同期のエラー処理には、プロジェクトで共有する結果ヘルパーを使う。 - ユーザー向けの検証メッセージはローカライズキーにし、一般的なフォームエラーには共有キーを使い、必要な場合は新しいキーを追加する。 - 現在のブランチを確認したうえで、互換性のある修正や追加では共有パッケージのパッチバージョンを、新しいエクスポートや動作ではマイナーバージョンを上げる。 - エクスポートしないヘルパーは独立した関数として定義し、実行ロジックを先に配置し、エクスポートする定数と型はロジックの間へ混在させず末尾にまとめる。 - 自明なコードが何をしているかではなく、その判断が存在する理由をコメントする。 - 複数の単純なユーティリティは1つの名前付きオブジェクトを通じてエクスポートし、Reactコンポーネントは名前付きエクスポートのままにする。 ## 外へのHTTP通信を安全なクライアントに通してSSRFを防ぎ、APIの決まりを守る 信頼できないすべての境界で、明示的なリクエストセマンティクスと安全なネットワーククライアントを適用する。 ### エンドポイントを標準化する - 作成と更新の変更操作にはすべて`POST`を、削除操作には`DELETE`を使う。API契約で除外されている場合は`PUT`や`PATCH`を決して使わない。 - すべてのエンドポイントに、セキュリティアクセス設定を明示する。 - 正規の識別子、エラー型、スキーマ基盤、コレクションヘルパー、データベースサニタイザーを再実装せずに使う。 ### サーバーサイドリクエストフォージェリを防ぐ - サーバーコンポーネントから送るHTTP通信は、承認済みの安全なクライアントを経由させる。 - ユーザー入力、管理者設定、OAuthエンドポイント、第三者連携に由来するURLには、生の`fetch`や無制限のクライアントファクトリーを決して使わない。 - プライベートアドレス、ループバックアドレス、クラウドメタデータアドレスに対するフィルタリングを維持する。 - 型変換、URL検証、外部オブジェクトのサニタイズを境界で行う。 ### マイグレーションを管理された変更として扱う - マイグレーションを作成または変更する前に、リポジトリのマイグレーション手順書を読む。 - マイグレーションの配置を独自に考案せず、文書化された生成手順と構造に従う。 - 対応するマネージドデータベース環境との互換性を維持する。 ## ページの主なデータが読めない時だけ、全体のエラーダイアログを出す 失敗したデータが現在のページに不可欠な場合に限り、クエリの全体エラーを表示する。 ### 影響に基づいてクエリを分類する - テーブルの行や主要リストなど、ページの主要データには、全体エラーダイアログを表示するクエリメタデータフラグを設定する。 - 機能フラグ、メタデータ、個別検索、フィルター選択肢、ユーザー詳細などの補助データには、このフラグを有効にしない。 - 失敗によって、理由の分からない空白ページまたは空の主要ビューが生じる場合はダイアログを表示する、という判断基準を使う。 - 周囲のインターフェースが引き続き有用なら、小規模なクエリは静かに失敗させる。 - 適用されるプラン機能が利用可能になるまで、機能制限付きクエリを無効のままにする。 ## テナントの分離と全部のエディションを、モノレポのタスクランナーでテストする モノレポで定められた正規のタスクランナーを使って対象を絞ったテストを実行し、エディションによって異なる経路を検証する。 ### コードとデータを検証する - 共有コードと実行コードには単体テストを、API動作には結合テストを実行する。 - 認証とルーティングが本番の動作と一致するよう、標準のテスト環境ヘルパーとリクエストコンテキストヘルパーを使う。 - テストデータを分離し、各テストの間に後片付けする。 - コードでロック、重複排除、`skip-locked`によるデータベース選択を使う場合は、並行処理テストを追加する。 - 別のプロジェクトまたはプラットフォームのデータが返されないことを証明し、テナント分離をテストする。 ### 対応するコマンドを使う - タスクの完了を判断する前に、リポジトリで必須のlintと修正を行うコマンドを実行する。 - 設定済みのモノレポ用タスクランナーと、対象パッケージを絞るコマンドを使う。無関係なビルドシステムを呼び出さない。 - ホスティングされたフロントエンドがリモートのバックエンドを参照する場合、ホスティング先ドメインへリダイレクトするOAuthフローを避け、リダイレクトしない認証情報または完全にローカルなバックエンドを使う。 - 対応するすべての経路で、エディション制限、ブランド表現、上限、機能の利用可否を検証する。 ## 変更にラベルを付け、必須のチェックが通ってから終える 機能ドキュメント、ラベル、最終確認を使い、変更を理解可能でリリースできる状態にする。 ### 実装を準備する - 機能を変更する前に、エンティティ、サービス、データフロー、連携上の制約を扱う、その機能に絞ったドキュメントを読む。 - 横断的に重要な安全規則は簡潔に保ち、段階的な機能ワークフローと分ける。 - 依存関係マニフェスト、エンティティ登録、テナントフィルター、エディション間のインポート、アクセス宣言、副作用の順序を確認する。 ### コントリビューションを準備する - 機能追加、バグ修正、変更履歴の対象外となる内部変更を区別する主要変更ラベルを、正確に1つ付ける。 - 変更が第三者連携または中核連携に影響する場合は、連携領域を示す別のラベルを追加する。 - ロックファイル、パッケージバージョン、ローカライズキー、テスト、生成物が実装と一致していることを確認する。 - 必須のlint、テスト、セキュリティチェックを実行し、実行できなかった確認項目を報告する。 - 最終差分と検証結果が裏付けるまで、完了を宣言しない。