コンテンツにスキップ

0005. ロールモデル (処理業者の admin / normal / driver と排出業者)

コンテキストと課題

waste-link には性質の異なる 2 種類の事業者が参加する:

  • 排出業者 (discharger): マニフェスト発行・処理業者選定・回収依頼を行う。
  • 処理業者 (collector): 受注・配車・運搬・処分を行う。

処理業者は社内に管理者・事務スタッフ・ドライバーといった職掌があり、権限を分けたい。一方、排出業者は 当面ロール区分が不要 (実質全員が管理者相当)。テナント種別とユーザーロールを表現する必要がある。

決定

テナント種別 (tenants.type) とユーザーロール (profiles.role) の 2 軸でモデル化する。

  • テナント種別: tenants.typecheck (type in ('discharger', 'collector')) で固定 (migration 3)。 JWT には app_metadata.tenant_type として乗り、current_tenant_type() で参照する。
  • 処理業者のロール: admin / normal / driver の 3 種。
    • 当初 (migration 3 / 8) は admin / driver の 2 種だった (profiles.role default 'driver'check (role in ('admin','driver'))is_valid_role も 2 値)。
    • migration 27 で normal (一般スタッフ) を追加し、check (role in ('admin','normal','driver')) に拡張。同時に工場・配車・コスト等の書込ポリシーを ('admin','normal') 許可へ広げた。
  • 排出業者のロール: role は null (区分なし)。アプリ上は「ロール未設定でも admin 相当」として扱う。 ランディング解決 (resolveLandingPath) も tenant_type === 'discharger' なら role を見ずに /discharger へ送る。

フロントの型・定数は単一の出典 (AuthContext.tsx) に集約:

export type UserRole = 'admin' | 'normal' | 'driver';
export const COLLECTOR_STAFF_ROLES: readonly UserRole[] = ['admin', 'normal'];
// role は UserRole | null (discharger は null = admin 相当)

影響 (Consequences)

良い点

  • テナント種別とロールを分離したことで、「処理業者の中の職掌」と「排出業者 vs 処理業者」を 独立に扱える。RLS もアプリも同じ tenant_type / role を JWT から共有できる。
  • normal 追加が check 制約と is_valid_role の更新 + ポリシー拡張で完結し、後方互換に導入できた。

トレードオフ / 注意点

  • 排出業者の「role = null = admin 相当」は暗黙のルール。null を admin と読み替える前提が アプリ各所 (RoleGuard・ランディング) に散らばるため、排出業者にロールを導入する際は影響範囲が広い。
  • ロールを後から増やした (driver/admin+normal) ため、「admin のみ」だった古いポリシーを 順次 admin|normal へ広げる必要があった (権限の起点が migration をまたぐ)。
  • ロールの権威は JWT。ロール変更はトークン再取得まで反映されない (ADR 0003)。

根拠 (典拠)

  • supabase/migrations/00000000000003_tenant_types_and_roles.sql:5-9,19-36,75-81 — 事業者種別の説明、tenants.typecheck (type in ('discharger','collector'))is_valid_role 初期 ('admin','driver')。
  • supabase/migrations/00000000000008_profiles.sql:20,23role text not null default 'driver' / check (role in ('admin','driver'))(初期)。
  • supabase/migrations/00000000000027_role_normal.sql:5-13profiles_role_check('admin','normal','driver') へ拡張、is_valid_role 更新。
  • apps/web/src/contexts/AuthContext.tsx:21-30,78-80UserRole 型、COLLECTOR_STAFF_ROLES、discharger は role null で admin 相当の注記。
  • apps/web/src/contexts/AuthContext.test.ts:68{ tenantType: 'discharger', role: null, expected: '/discharger' }
  • README.md:197-213 — テストアカウント (collector admin/normal/driver、discharger は「role なし」)。