0004. login_id 方式の認証 (合成メールへの決定的変換)¶
- ステータス: Accepted(実装済み)
- 関連: 0002 Supabase を採用 / 0005 ロールモデル / 0011 公開オンボーディング
コンテキストと課題¶
処理業者のメンバー (ドライバー・一般スタッフ) の多くは、業務で使える個人のメールアドレスを 持たない。一方で Supabase Auth は メール + パスワード を前提とする。「メールを持たない社員でも ログインできる」ようにしつつ、Supabase Auth をそのまま使いたい。
決定¶
ログインは login_id で行い、内部で決定的に合成メールへ変換して Supabase Auth に渡す。
// apps/web/src/lib/auth-login-id.ts
export const LOGIN_EMAIL_DOMAIN = 'members.waste-link.local';
export function loginIdToEmail(identifier: string): string {
const v = identifier.trim();
if (v.includes('@')) return v; // すでにメールならそのまま
return `${v.toLowerCase()}@${LOGIN_EMAIL_DOMAIN}`; // login_id → 合成メール
}
- 例:
yamada→yamada@members.waste-link.local。@を含む入力は実メールとみなし素通し。 - 同じ変換規則を 3 箇所で一致 させる: Web のログイン (
AuthContext)、API のメンバー作成 (team.tsのsyntheticEmail)、公開サインアップ (signup.tsのsignupLoginIdToEmail)。 login_id の形式は^[a-z0-9][a-z0-9._-]{2,}$(英小文字/数字始まり・._-可・3 文字以上)。 - DB 側は
profiles.login_id列 (全体で一意・部分インデックス) を追加し (migration 32)、 メール非保有メンバーを許容するためprofiles.emailを nullable 化 (migration 35)。 - login_id の衝突は合成メールの一意制約で検出する (重複 = 422 を「login_id の衝突」として扱う)。
影響 (Consequences)¶
良い点¶
- 実メールを持たない社員でも login_id + パスワード でログインでき、Supabase Auth の メール+パスワード機構を改造せず流用できる。
- 変換が 決定的 なので、管理者は login_id だけを管理すればよく、ユーザーにメールを意識させない。
- テストアカウント (
admin1/driver1など) も同じ仕組みで*@members.waste-link.localに マップされ、ローカル/開発で一貫してログインできる。
トレードオフ / 注意点¶
*.members.waste-link.localは 非ルータブルな.localドメイン で実メールは届かない。 そのため login_id ユーザーには パスワードリセットのメール導線が無い (管理者によるリセット運用が前提)。- 変換規則が Web と API の 複数箇所に重複している。片方だけ変えると login_id 衝突判定や ログインが壊れるため、変更時は全箇所を揃える必要がある (各ファイルにその旨のコメントあり)。
- 実メールを持つユーザー (
@を含む入力) と login_id ユーザーが混在し得る。loginIdToEmailの@素通しがその両対応を担う。
根拠 (典拠)¶
apps/web/src/lib/auth-login-id.ts:1-6—LOGIN_EMAIL_DOMAIN = 'members.waste-link.local'とloginIdToEmail。apps/web/src/contexts/AuthContext.tsx:1—import { loginIdToEmail }(ログインで使用)。apps/api/src/routes/team.ts:9-11,99-100,109—LOGIN_EMAIL_DOMAIN/LOGIN_ID_RE/syntheticEmail = ${loginId}@${LOGIN_EMAIL_DOMAIN}/ 422 を login_id 衝突として扱うコメント。apps/api/src/routes/signup.ts:44-57—LOGIN_EMAIL_DOMAIN/SIGNUP_LOGIN_ID_RE = /^[a-z0-9][a-z0-9._-]{2,}$//signupLoginIdToEmail。supabase/migrations/00000000000032_profiles_login_id.sql:1-4—login_id列追加 +where login_id is not nullの部分一意インデックス。supabase/migrations/00000000000035_profiles_email_nullable.sql:1-2—emailを nullable 化。README.md:164-166,225— login_id ログインと決定的変換、.localは非ルータブル (実メール不達) の注記。