コンテンツにスキップ

組織ブートストラップ手順 (bootstrap-org)

scripts/bootstrap-org.mjs は、任意の Supabase 環境 (特に 本番) に

  • 組織 (tenant) 1 つ
  • その最初の管理者 (admin) ログインアカウント 1 つ

を作成するための ワンオフ・ブートストラップスクリプトです。

これは「初回の種火」を 1 回だけ灯すための道具です。 本番にまだ誰もログインできるアカウントが無い状態を解消するためのもので、 恒久的なテナント / ユーザー登録は実装済みのオンボーディング機能で行います (招待コードによる /registerPOST /signupapps/web/src/pages/RegisterOrgPage.tsx / apps/api/src/routes/signup.ts。詳細は docs/signup-onboarding.md)。

アプリのビルド対象外 (scripts/ 配下) で、scripts/setup-demo-users.mjs と同じ Supabase Admin API 方式を踏襲しています (auth.users への直接 SQL INSERT は GoTrue の内部スキーマ検証と相性が悪く "Database error querying schema" を招くため)。


1. 何が作られるか

対象 collector (処理業者) discharger (排出事業者)
public.tenants 1 行 ✅ (name, type=collector) ✅ (name, type=discharger)
auth ユーザー (admin) ✅ Admin API で作成 ✅ Admin API で作成
app_metadata { tenant_id, tenant_type:'collector', role:'admin' } { tenant_id, tenant_type:'discharger', role:'admin' }
public.profiles 1 行 ✅ (login_id, display_name, role='admin') ❌ 作らない

collector と discharger の差: discharger は app_metadata だけでテナント解決でき、 profiles 行を必要としません (排出事業者ユーザーは現状ロール区分なしで全員 admin 相当)。 collector はチーム管理 (profiles ベース) があるため、admin の profiles 行を作ります。

ログイン方式

ログインは ログインID + パスワードです。auth email はログインIDから決定的に導出します (apps/web/src/lib/auth-login-id.tsloginIdToEmail と一致):

email = <login_id>@members.waste-link.local

ログインIDは内部で trim + 小文字化されます (例: Adminadmin)。email と profiles.login_id の両方に同じ正規化済みの値が使われます。


2. 本番での実行手順 (ユーザー向け)

Step 1: service_role キーを取得

  1. Supabase ダッシュボードで本番プロジェクトを開く
  2. Project Settings → API
  3. Project API keysservice_roleReveal をクリックしてコピー
  4. Project URL (例: https://<project-ref>.supabase.co) もコピー

⚠️ service_role キーは DB 全権限を持つ root レベルの秘密です。 漏洩すると DB を丸ごと触られます。git にコミットしない / Slack 等に貼らない / シェル履歴に残さないよう注意してください (履歴を残したくない場合は下記の 「履歴に残さない実行例」を参照)。

Step 2: まず --dry-run で内容を確認 (DB に接続しません)

node scripts/bootstrap-org.mjs --dry-run \
  --org-name "サンプル運輸" \
  --tenant-type collector \
  --admin-login-id admin \
  --admin-name "管理者" \
  --password "<strong-password>"

作成予定のテナント / admin / profiles の内容が表示されます。問題なければ次へ。

Step 3: 本実行

SUPABASE_URL="https://<project-ref>.supabase.co" \
SUPABASE_SERVICE_ROLE_KEY="<service_role キー>" \
node scripts/bootstrap-org.mjs \
  --org-name "サンプル運輸" \
  --tenant-type collector \
  --admin-login-id admin \
  --admin-name "管理者" \
  --password "<strong-password>"

成功すると tenant_id / 管理者ログインID / ログイン方法が出力されます (パスワードと service_role キーは出力しません)。

Step 4: ログイン確認

本番 Web アプリの /signin で、

  • ログインID: admin (上で指定した --admin-login-id)
  • パスワード: --password で指定したもの

を入力してログインします。

  • collector admin → /collector (管理ダッシュボード)
  • discharger → /discharger (排出事業者ダッシュボード)

3. 引数リファレンス

引数 env フォールバック 必須 説明
--org-name <name> ORG_NAME ✅ (新規時) 組織名 (tenants.name)
--tenant-type <collector\|discharger> TENANT_TYPE ✅ (新規時) テナント種別 (tenants.type)
--admin-login-id <id> ADMIN_LOGIN_ID 管理者ログインID (@ / 空白不可)
--admin-name <name> ADMIN_NAME 管理者表示名 (collector の profiles.display_name)
--password <password> ADMIN_PASSWORD 管理者パスワード (8 文字以上)
--reuse-tenant <uuid> REUSE_TENANT_ID 既存テナントに admin を追加 (新規作成しない)
--dry-run DB に接続せず作成内容だけ表示
-h, --help ヘルプ表示

環境変数 (本実行時のみ。--dry-run では不要):

env 説明
SUPABASE_URL https://<project-ref>.supabase.co
SUPABASE_SERVICE_ROLE_KEY service_role キー (DB 全権限・厳重に秘匿)

discharger の例

SUPABASE_URL="..." SUPABASE_SERVICE_ROLE_KEY="..." \
node scripts/bootstrap-org.mjs \
  --org-name "サンプル排出株式会社" \
  --tenant-type discharger \
  --admin-login-id boss \
  --admin-name "排出管理者" \
  --password "<strong-password>"

既存テナントに admin を追加する場合 (--reuse-tenant)

新規テナントを作らず、既存テナント (例: 過去に作成済み) に admin を追加します。 --tenant-type は省略可で、種別は既存テナントから取得します (指定した場合は既存テナントの種別と一致する必要があります)。

SUPABASE_URL="..." SUPABASE_SERVICE_ROLE_KEY="..." \
node scripts/bootstrap-org.mjs \
  --reuse-tenant "<既存 tenant の uuid>" \
  --admin-login-id mgr2 \
  --admin-name "追加管理者" \
  --password "<strong-password>"

4. 冪等性・安全装置

  • admin ユーザー: 同じログインID (= email) のユーザーが既にいれば、重複作成せず パスワード / app_metadata更新します。
  • profiles (collector): user_id 競合で upsert するため、何度実行しても安全です。
  • tenant: 新規作成時に同名のテナントが既に存在すると、重複作成を避けて停止します。 既存テナントに admin を追加したい場合は --reuse-tenant <id> を、別組織なら別名を 指定してください。

5. 注意事項

  • このスクリプトはワンオフです。日常的なユーザー追加には使いません (恒久的な登録は実装済みのオンボーディング機能 /registerPOST /signup で行います)。
  • service_role キーとパスワードは秘密情報です。スクリプトはこれらをログに 出力しません。git にコミットしない / 共有しないでください。
  • ハードコードされた URL / キー / パスワードはありません。必ず env / 引数で渡します。

履歴に残さない実行例 (任意)

シェル履歴に service_role キーを残したくない場合は、read -s で対話的に渡せます:

read -rs -p "SERVICE_ROLE_KEY: " SUPABASE_SERVICE_ROLE_KEY; echo
read -rs -p "ADMIN_PASSWORD: " ADMIN_PASSWORD; echo
export SUPABASE_SERVICE_ROLE_KEY ADMIN_PASSWORD
SUPABASE_URL="https://<project-ref>.supabase.co" \
node scripts/bootstrap-org.mjs \
  --org-name "サンプル運輸" --tenant-type collector \
  --admin-login-id admin --admin-name "管理者"
# 終わったら: unset SUPABASE_SERVICE_ROLE_KEY ADMIN_PASSWORD

6. 関連ドキュメント

  • 公開オンボーディング (招待コードによる組織登録 /registerPOST /signup): docs/signup-onboarding.md恒久的な組織登録はこちら。 招待コードの発行は scripts/invite-org.mjs を使います (宛先メール + code_hash で API と整合)。
  • 認証・テナントモデルの全体像: docs/auth-and-tenants.md
  • α 検証用デモアカウント (develop の wipe → 再投入): docs/auth-and-tenants.md §2.0 / scripts/setup-demo-users.mjs