For the complete documentation index, see llms.txt. This page is also available as Markdown.

Operator Login — サインアップ・ログイン・トークン更新・アカウント削除

倉庫スタッフ向けピッキングアプリ(picking-ios)の認証エンドポイントです。スタッフはメールアドレス + パスワード、Google サインイン(Google ID token)、Sign in with Apple(identity token)、またはメールに届く確認コードでログインして operator JWT を発行します。アカウントはプラットフォーム / 管理者側で発行し、アプリ内のセルフサインアップはありません。有効期限が切れたら refresh token で更新します。/api/operator/me はログイン中スタッフの id / email / 束縛 shop 群を返します。/api/operator/account/delete は本人が自分のアカウントを即時削除します。発行された JWT は他の Operator API(/api/operator/*)の Authorization: Bearer で使います。

Base URL https://api.lmile.io · 認証 login / login/google / login/apple / login/otp/* / refresh は不要(email+password / idToken / identityToken / 確認コード / refreshToken で認証)、me / account/delete は operator JWT(Authorization: Bearer)(詳細)

エンドポイント

Method
Path
用途

POST

/api/operator/login

email + password → JWT / refreshToken / staff / shops を発行

POST

/api/operator/login/google

Google ID token(idToken)→ JWT / refreshToken / staff / shops を発行

POST

/api/operator/login/apple

Apple identity token(identityToken)→ JWT / refreshToken / staff / shops を発行

POST

/api/operator/login/otp/request

email → 確認コードをメールで送る

POST

/api/operator/login/otp/verify

email + code(確認コード)→ JWT / refreshToken / staff / shops を発行

POST

/api/operator/refresh

refreshToken → 新 JWT / refreshToken を発行

GET

/api/operator/me

ログイン中スタッフの id / email / 束縛 shop 群

POST

/api/operator/account/delete

本人アカウントを即時削除(退会)。セッションも失効

レスポンスは camelCase(routing 系と同じ)。/api/operator/* の認証系統(operator JWT・staff↔shop 束縛)は 認証 を参照してください。


POST /api/operator/login

スタッフのメールアドレスとパスワードを検証し、operator JWT・refresh token・スタッフ情報・束縛 shop 群を返します。束縛 shop が 0 件でも ok: true で返し(アプリ側が「shop 未割当」を案内できるように)、shops: [] になります。

リクエスト

ボディパラメータ

パラメータ
型
必須
説明

email

string

✓

スタッフのメールアドレス(前後空白は無視)

password

string

✓

パスワード

レスポンス

フィールド
説明

jwt

以降の /api/operator/* で Authorization: Bearer に使うアクセストークン

refreshToken

expiresAt 到来後に /api/operator/refresh へ渡す更新トークン

expiresAt

JWT の有効期限(Unix 秒。取得できない場合 null)

expiresIn

発行から失効までの秒数

tokenType

トークン種別(bearer)

staff

ログインしたスタッフの id(= ユーザー ID)/ email

shops

スタッフに束縛された shop ドメイン群(0 件は [])

shopNames

shop ドメイン → 表示名(ブランド名)の map。表示名が登録されている shop のみ含み、未登録の shop はキーに現れません(アプリはその場合 shop ドメインをそのまま表示します)。アプリの shop / 拠点選択・設定画面でドメインの代わりにブランド名を表示するために使います

挙動

  • 認証失敗(メール不存在・パスワード不一致など)は、メールアドレスの存在有無を漏らさないため一律 401 invalid_credentials です。

  • 試行回数の上限に達すると 429 rate_limited を返します。

  • 認証基盤に到達できない場合は 503 auth_unavailable(旧経路にフォールバックしません)。


POST /api/operator/login/google

Google サインインで取得した Google ID token を検証し、operator JWT・refresh token・スタッフ情報・束縛 shop 群を返します(レスポンスは login と同形)。アプリ側は expo-auth-session 等で Google ID token を取得してこのエンドポイントに渡します。staff↔shop 束縛はスタッフのユーザー単位なので、同じメールアドレスのスタッフは email + password ログインと同じ束縛 shop 群に解決されます。束縛 shop が 0 件でも ok: true + shops: [] で返します。

リクエスト

ボディパラメータ

パラメータ
型
必須
説明

idToken

string

✓

Google サインインで取得した Google ID token(前後空白は無視)

レスポンス

フィールドの意味は POST /api/operator/login と同じです。

挙動

  • ID token の検証失敗(不正・失効・別 provider の token など)は、原因の詳細を漏らさないため一律 401 invalid_id_token です。

  • 試行回数の上限に達すると 429 rate_limited を返します。

  • 認証基盤に到達できない場合は 503 auth_unavailable(旧経路にフォールバックしません)。


POST /api/operator/login/apple

Sign in with Apple で取得した Apple identity token を検証し、operator JWT・refresh token・スタッフ情報・束縛 shop 群を返します(レスポンスは login と同形)。アプリ側は expo-apple-authentication で identity token を取得してこのエンドポイントに渡します。Google サインイン併設に対する Apple ガイドライン 4.8(同等の代替ログイン)対応です。staff↔shop 束縛はスタッフのユーザー単位で、束縛が 0 件(自己登録直後や Hide My Email の新規ユーザー)でも ok: true + shops: [] で返し、アプリのオンボーディングで shop に紐付けます。

リクエスト

ボディパラメータ

パラメータ
型
必須
説明

identityToken

string

✓

Sign in with Apple で取得した Apple identity token(前後空白は無視)。認証はこの token で完結します

authorizationCode

string | null

Apple の authorization code(初回のみ。本エンドポイントの認証には未使用)

email

string | null

Apple が返すメール(初回サインイン時のみ。Hide My Email の場合は relay メール)

fullName

string | null

Apple が返す氏名(初回サインイン時のみ)

user

string

Apple の安定ユーザー ID(sub。初回のみ届く付随情報)

レスポンス

フィールドの意味は POST /api/operator/login と同じです。

挙動

  • 認証は identityToken のみで完結します(email / fullName / authorizationCode / user は初回のみ届く付随情報で、検証には使いません)。

  • identity token の検証失敗(不正・失効・別 provider の token・宛先 bundle ID 不一致など)は、原因の詳細を漏らさないため一律 401 invalid_id_token です。

  • 試行回数の上限に達すると 429 rate_limited、認証基盤に到達できない場合は 503 auth_unavailable(フォールバックしません)。


POST /api/operator/login/otp/request

スタッフのメールアドレスへ、ログイン用の確認コードを送ります。パスワードも Google / Apple のアカウントも使わないスタッフ向けのログイン方法で、届いたコードを /api/operator/login/otp/verify に渡すとログインできます。

リクエスト

ボディパラメータ

パラメータ
型
必須
説明

email

string

✓

スタッフのメールアドレス(前後空白と大文字小文字は無視)

レスポンス

挙動

  • コードを送るのは、すでにアカウントがあるメールアドレスだけです。このエンドポイントでアカウントは作られません。

  • アカウントが無いメールアドレスでも ok: true を返します(メールアドレスの存在有無を漏らさないため)。その場合メールは届きません。届かないときは、管理者にアカウントの有無を確認してください。

  • 短い間隔で繰り返すと 429 rate_limited を返します。少し待ってから送り直してください。

  • 認証基盤に到達できない場合は 503 auth_unavailable(フォールバックしません)。


POST /api/operator/login/otp/verify

メールに届いた確認コードを照合し、operator JWT・refresh token・スタッフ情報・束縛 shop 群を返します(レスポンスは login と同形)。束縛 shop が 0 件でも ok: true + shops: [] で返します。

リクエスト

ボディパラメータ

パラメータ
型
必須
説明

email

string

✓

確認コードを送ったメールアドレス

code

string

✓

メールに届いた確認コード(前後空白は無視)

レスポンス

フィールドの意味は POST /api/operator/login と同じです。

挙動

  • コードの誤り・期限切れなどは、原因の詳細を漏らさないため一律 401 invalid_code です。/api/operator/login/otp/request でコードを送り直してください。

  • 試行回数の上限に達すると 429 rate_limited、認証基盤に到達できない場合は 503 auth_unavailable(フォールバックしません)。


POST /api/operator/refresh

refresh token から新しい operator JWT を発行します(再ログイン不要のセッション継続用)。

リクエスト

ボディパラメータ

パラメータ
型
必須
説明

refreshToken

string

✓

login / 前回の refresh で受け取った更新トークン(前後空白は無視)

レスポンス

フィールド
説明

jwt / refreshToken

新しいアクセストークン / 更新トークン(更新後はこちらを保持)

expiresAt / expiresIn / tokenType

login と同じ意味

挙動

  • 失効済み・不正な refresh token は 401 invalid_refresh_token。

  • 試行回数の上限は 429 rate_limited、認証基盤に到達できない場合は 503 auth_unavailable。


GET /api/operator/me

operator JWT を検証し、ログイン中スタッフの id / email / 束縛 shop 群を返します。ログイン直後の shop 選択画面が使います。束縛 shop が 0 件でも 200 + shops: [] を返します(「shop 未割当」を案内できるように)。

リクエスト

レスポンス

フィールド
説明

staff.id

スタッフのユーザー ID(routing write の操作者記録と同じ識別子)

staff.email

JWT の email claim(無い場合 null)

shops

スタッフに束縛された shop ドメイン群(0 件は [])

shopNames

shop ドメイン → 表示名(ブランド名)の map(login と同形)。表示名が登録されている shop のみ含み、未登録の shop はアプリがドメインをそのまま表示します


POST /api/operator/account/delete

operator JWT を検証し、ログイン中のスタッフ本人のアカウントを即時削除します(アプリ内の退会導線)。削除できるのは常に JWT の持ち主自身だけで、他人の ID を指定する経路はありません。誤操作を防ぐため、リクエストボディに confirm: true が必須です。

削除すると、そのアカウントの全セッション・refresh token が即時失効し、shop 束縛も解除されます。出荷作業などの操作履歴に残る操作者 ID は匿名の UUID として保持されます(個人を特定するメールアドレスは削除されます)。

デモアカウントは削除できません。 審査・デモ用に共有しているアカウントは保護されており 403 demo_account_protected を返します。

リクエスト

ボディパラメータ

パラメータ
型
必須
説明

confirm

boolean

✓

true 固定。誤操作防止のため省略・false は 400 confirmation_required

source

string

削除の発生元メモ(監査用。例 picking-ios。最大 200 文字)

レスポンス

フィールド
説明

deleted

アカウントが削除されたら true

alreadyDeleted

既に削除済みのアカウントへの再実行で true(冪等。フィールド自体が無い場合もある)

挙動・冪等性

  • 本人のみ: 削除対象は JWT の sub(本人)。リクエストボディ等で他人を指定する手段はありません。

  • 即時ハード削除: アカウント(認証情報)を物理削除します。全セッション / refresh token は即時失効するため、削除後は同じ JWT で /api/operator/* を呼べません(401)。アプリ側はローカルのトークンを破棄してログイン画面に戻してください。

  • デモ保護: デモアカウントは 403 demo_account_protected。

  • 監査: 削除はメールアドレスのスナップショット付きで内部監査トレイルに記録されます(個人には非公開)。

  • 冪等: 既に削除済みのアカウント(有効だが失効済みの JWT を保持したケース等)に対しても 200 + deleted: true を返します。

エラー

エンドポイント固有:

Status
条件
レスポンス例

401

認証失敗(login。メール存在有無は漏らさない)

{ "ok": false, "error_kind": "invalid_credentials", "error": "invalid_credentials" }

401

確認コードが誤り / 期限切れ(login/otp/verify。原因詳細は漏らさない)

{ "ok": false, "error_kind": "invalid_code", "error": "invalid_code" }

401

ID token が不正 / 失効(login/google の Google ID token・login/apple の Apple identity token。原因詳細は漏らさない)

{ "ok": false, "error_kind": "invalid_id_token", "error": "invalid_id_token" }

401

refresh token が不正 / 失効(refresh)

{ "ok": false, "error_kind": "invalid_refresh_token", "error": "invalid_refresh_token" }

401

JWT 未提示(me)

{ "ok": false, "error_kind": "missing_token", "error": "Authorization: Bearer <jwt> required" }

401

JWT が不正 / 失効(me / account/delete)

{ "ok": false, "error_kind": "invalid_token", "error": "invalid or expired token" }

400

confirm: true 不在(account/delete)

{ "ok": false, "error_kind": "confirmation_required", "error": "confirm:true is required to delete account" }

403

デモアカウントの削除(account/delete)

{ "ok": false, "error_kind": "demo_account_protected", "error": "demo account cannot be deleted" }

500

削除監査の記録に失敗(account/delete)

{ "ok": false, "error_kind": "audit_error", "error": "failed to record deletion" }

429

試行回数の上限超過(login / login/google / login/apple / refresh)

{ "ok": false, "error_kind": "rate_limited", "error": "too many requests" }

503

認証基盤に到達できない

{ "ok": false, "error_kind": "auth_unavailable", "error": "auth service unavailable" }

共通エラー(400 / 405 / 500)は Error Codes を参照。

データモデル

  • スタッフのアカウント(メールアドレス・パスワード・確認状態)は Supabase Auth(auth.users)が管理します。アカウントの作成はプラットフォーム / 管理者側で行い(アプリ内のセルフサインアップは廃止)、login / login/google / login/apple / refresh はトークンを発行します(本サービスの SoT テーブルには直接書き込みません)。

  • sot.lm_operator_staff_shops — スタッフ(ユーザー)↔ shop の認可束縛 SoT。/api/operator/* の shop 認可(login / refresh が返す shops、各エンドポイントの 403 shop_not_authorized)はこの束縛で判定します。発行されたばかりで未割当のアカウントは未束縛です(割当は Last Mile が行います)。スタッフのメールアドレス等を含むため agent_read.* / 公開 view には露出しません(内部管理のみ)。アカウント削除時はこの束縛も連動して解除されます。

  • sot.lm_operator_account_deletions — account/delete の削除監査トレイル。削除した本人の ID・削除時点のメールアドレス snapshot・束縛 shop snapshot・削除時刻を記録します。メールアドレス(個人情報)を含むため agent_read.* / 公開 view には露出しません(内部監査のみ)。

Last updated

Was this helpful?