0005. ロールモデル (処理業者の admin / normal / driver と排出業者)¶
- ステータス: Accepted(実装済み)
- 関連: 0003 マルチテナント分離 / 0006 工場スコープのアクセス制御 / 0007 can_drive 能力フラグ
コンテキストと課題¶
waste-link には性質の異なる 2 種類の事業者が参加する:
- 排出業者 (discharger): マニフェスト発行・処理業者選定・回収依頼を行う。
- 処理業者 (collector): 受注・配車・運搬・処分を行う。
処理業者は社内に管理者・事務スタッフ・ドライバーといった職掌があり、権限を分けたい。一方、排出業者は 当面ロール区分が不要 (実質全員が管理者相当)。テナント種別とユーザーロールを表現する必要がある。
決定¶
テナント種別 (tenants.type) とユーザーロール (profiles.role) の 2 軸でモデル化する。
- テナント種別:
tenants.typeをcheck (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.roledefault'driver'、check (role in ('admin','driver'))、is_valid_roleも 2 値)。 - migration 27 で
normal(一般スタッフ) を追加し、check (role in ('admin','normal','driver'))に拡張。同時に工場・配車・コスト等の書込ポリシーを('admin','normal')許可へ広げた。
- 当初 (migration 3 / 8) は
- 排出業者のロール: 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.typeのcheck (type in ('discharger','collector'))、is_valid_role初期 ('admin','driver')。supabase/migrations/00000000000008_profiles.sql:20,23—role text not null default 'driver'/check (role in ('admin','driver'))(初期)。supabase/migrations/00000000000027_role_normal.sql:5-13—profiles_role_checkを('admin','normal','driver')へ拡張、is_valid_role更新。apps/web/src/contexts/AuthContext.tsx:21-30,78-80—UserRole型、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 なし」)。