Sushi SaaS がリクエストを振り分ける仕組み
ミドルウェアがユーザーと運用に与える効果、選択した組織を URL に残す理由、変更できるルーティング方針を説明します。
Sushi SaaS のミドルウェアは、リクエスト単位の情報を扱います。認証や業務上の認可は行いません。言語別ルーティング、リクエストの追跡、選択した組織の受け渡しは、いずれもユーザーに見える挙動を生むため、方針を意識して選ぶ必要があります。
ユーザーが体験すること
- ページは
next-intlにより、適切な言語のルートへ解決されます。 - 選択した組織をセッションだけでなく
?org=<slug>で表すため、二つのタブで別々の組織を開いたままにできます。 - アカウントページのリンクを共有すると、対象の組織を URL から判別できます。
すべてのレスポンスに x-request-id が付き、問い合わせと構造化ログを対応付けられます。API リクエストでは言語判定を省きますが、同じリクエスト情報と組織情報を受け取ります。
実装は 7580470 の src/middleware.ts です。
ミドルウェアが信頼する情報
ページリクエストの組織情報は URL のクエリパラメーターから取得し、呼び出し元が付けた組織ヘッダーは削除します。API では共通クライアントが x-organization-slug を送信できます。URL にも値がある場合は URL を優先します。
どちらも認可の根拠にはなりません。src/services/authz.ts がログイン中のユーザーの所属を確認し、複数の組織に属するユーザーから届いた、対象組織が曖昧な API リクエストを拒否します。ミドルウェアが検証するのは、組織情報を安全に受け渡せるかどうかだけです。
外部から届いたリクエスト ID は、長さとログに安全な形式を満たす場合だけ受け入れます。それ以外の場合は UUID を生成します。ID はルートへ転送し、レスポンスにも付けます。
変更できる選択
言語別ルーティング
言語コード付きのページと自動言語判定が必要なら、next-intl を維持します。単一言語にするなら、ミドルウェアの分岐とともに言語別ルート、メッセージカタログ、テストを削除します。仕組みを半分だけ消すと、リダイレクトとリンクが食い違います。
組織の選択方法
既定のクエリ文字列はタブごとに独立し、既存の URL にも追加しやすい方式です。/acme/account のようにパスでテナントを表す方式は URL の階層が明確ですが、リンク生成、コールバック、マッチャー、組織情報の解決方法を変更する必要があります。セッションだけに保存する方式は簡単に見えますが、二つのタブが同じ選択中の組織を上書きします。その挙動を許容できる場合だけ選んでください。
リクエストの追跡
ほぼすべての本番プロダクトで、相関 ID を維持する価値があります。プロキシや可観測性サービスがトレース ID を発行する場合は、その信頼済みの値をロガーの契約に対応付けるか、両方を保持します。外部から受け取った長さ無制限の文字列をログに入れないでください。
API の組織情報
複数の組織に属するユーザーには対象組織を明示させることで、操作が直前に選んだテナントへ無言で入るのを防ぎます。API が確実に単一テナントだけを扱う場合に限り、簡略化できます。
ミドルウェアに処理を追加する条件
ルーティング前に必須で、高速かつエッジ環境で実行できる処理だけを追加します。組織への所属確認、DB に依存する認可、課金判断、その他の業務ルールはサービス層に置きます。
変更後は、言語別ページ、/api、静的ファイル、リクエスト ID の転送、不正な組織情報、二つのタブでの組織切り替えを試します。アーキテクチャとエラー契約と組織とチームも確認してください。