プロダクトを構築

組織、チーム、テナント分離

顧客の共同作業モデルを決め、同梱の組織内の役割、招待、利用人数、テナント境界を調整します。

スターターのコミット 2a1a04a で検証済みです。

最初にプロダクト上の問いに答えます。あなたの SaaS は、一人で使う人、共同で使うチーム、複数の組織を管理する人のうち、誰に販売しますか。Sushi SaaS には「一人から始めてチームへ成長できる」モデルが含まれています。各顧客は個人用の組織から始まり、課金対象のリソースはすべて組織に属します。

同梱の共同作業モデル

動作既定将来の選択肢
リソースの所有組織内で共有can() に、作成者だけが扱える規則またはリソース単位の共有を追加
役割owneradminmember製品固有の役割または Better Auth の動的アクセス制御を追加
課金組織ごとの固定価格利用人数に応じた数量と、検証済みの日割り計算を追加
ナビゲーション?org=<slug> を使うワークスペース切替URL に強い階層が必要なら組織別のパスを追加
チーム組織への所属と招待下位グループが必要な場合だけ、入れ子のチームを有効化

すべてのアカウントに組織がある

新規登録時に個人用の組織と owner の所属記録を作成します。ユーザー所有リソースという別経路はなく、ファイル、タスク、注文、契約、クレジット、予約は org_uuid を使います。

Better Auth がメンバーシップと招待を提供し、Sushi がテナント範囲、権限、席数制限、共有残高、同時実行ガードを追加します。

ロール

階層は owneradminmember です。

操作MemberAdminOwner
データ閲覧、ファイル作成/削除、クレジット消費
招待、削除、ロール変更
組織更新
課金管理、組織削除

getOrgContext(request, optionalSlug) で利用者、組織、役割を解決し、can(ctx, action, resource) で認可します。リクエスト本文の org_uuid は信用しません。

テナント分離と席数

テナントに属する表のクエリは、モデル内で scopedToOrg(column, ctx.orgUuid) を使います。アーキテクチャテストが、組織を限定していない読み書きを検出します。

招待は 72 時間で期限切れになり、招待先メールに紐づき、有効な間は席を予約します。

プラン総席数
Free1
Plus5
Max20

招待の送信時と承認時の両方で、同じ組織単位の PostgreSQL アドバイザリーロックの下で上限を確認します。管理画面から、監査記録付きの一時的または無期限の例外も設定できます。

不変条件

  • 最後の owner は削除できません。
  • 唯一の組織から退出できません。
  • 自分より上のロールを付与できません。
  • ダウングレードは既存メンバーやデータを削除せず、新規追加だけを止めます。
  • クレジットと Stripe Customer は組織に属します。

画面は /{locale}/account/team、API は /api/account/team/* です。クエリパラメーター式の組織切り替えは含まれていますが、組織スラッグを含むルート、独自の役割、入れ子のチーム、Stripe の利用人数課金はまだありません。

変更前に、顧客データの所有者、招待・削除できる人、member が共有コンテンツを削除できるか、料金を支払う人を明文化します。二つの組織が互いの行を読めず、最後の owner を削除できず、同時招待が最後の一席を二重に使わず、ダウングレード後も既存データとメンバーが保たれれば検証完了です。次にプランと権限で利用人数上限を決め、設計上の背景はSushi SaaS の構造で確認してください。

組織、チーム、テナント分離 · Sushi SaaS