受付承認なしで新規患者が予約完了できるよう、現状の oauth/claim 動線を「LINE 経由のセルフ登録」に再構成する。
/onboarding/claim で 3 要素 (電話・フリガナ・生年月日) を入力アナログ管理から移行する際に受付負荷が極めて高い
アナログカルテはそもそも電子カルテと紐付いていない (独立した紙運用)。
新システム導入の際、患者に「導入後から予約履歴を蓄積する」と周知すれば、過去予約の移行は不要。
LINE 公式アカウントから予約導線を流すケースが大半 → LINE 一本化が業務に適合。
LINE ログイン → /onboarding でプロフィール入力 → 常に新規 User 作成 → Home
突合ロジック完全撤廃。受付運用とシステムを独立させる。
| 項目 | 現状 | 新仕様 |
|---|---|---|
| ログイン手段 | LINE / Google | LINE のみ |
| 既存カルテとの突合 | 3 要素一致 (phone / kana / dob) | しない (常に新規 User 作成) |
claim_failed 401 | あり | 廃止 |
possibly_existing_user 等の親切エラー | (検討対象) | 不要 |
| 受付の事前登録要件 | 必須 | 不要 (任意・staff-web で続行可) |
| 項目 | 影響 |
|---|---|
既存 provider: manual User | データ残置。誰とも紐付かない「孤立カルテ」扱い。staff-web からは見える |
| 「前回施術」カード | LINE 連携後の初回予約後から表示 (2 回目以降) |
| 患者から見える予約履歴 | LINE 連携後のみ |
| アナログ時代の予約参照 | 紙カルテで対応、staff-web 上は別 User として表示 |
将来必要になれば 「LINE 連携 User と旧 manual User をマージする管理画面」 を Plan 4-D-2 として別途実装する。本仕様の MVP には含めない。
POST /api/v1/auth/oauth/register現 oauth/claim を リネーム + 動作変更。Controller も OauthRegistrationController へ。
POST /api/v1/auth/oauth/register
Content-Type: application/json
{
"pending_claim_token": "<10分有効、LINE callback で発行>",
"full_name": "山田太郎",
"kana": "ヤマダタロウ",
"phone": "09011112222",
"date_of_birth": "1990-01-01"
}
| Status | body | 説明 |
|---|---|---|
| 200 | { user: { id, full_name, role: "user" } } |
新規 User 作成成功 + JWT cookie 発行 |
| 401 | { error: "claim_token_expired", message: "LINE ログインからやり直してください" } |
トークン期限切れ |
| 422 | { error: "validation_failed", details: { phone: ["..."], kana: ["..."] } } |
入力 validation 失敗 |
| 429 | { error: "rate_limited", message: "しばらく待ってから..." } |
レート制限 |
:phone_not_found:kana_mismatch:dob_required:dob_mismatch:already_linked:locked (oauth_link_locked? は廃止)def create
# Step 1: レート制限 (phone × ip_address)
return rate_limited if OauthClaimRateLimiter.over_limit?(...)
# Step 2: token decode
payload = decode_claim_token # → expired / invalid → 401
# Step 3: validation (Zod / strong params で必須項目検証)
attrs = registration_params # → 不足/不正 → 422
# Step 4: 新規 User 作成 + 紐付け
user = User.create!(
full_name: attrs[:full_name],
full_name_kana: attrs[:kana],
phone: attrs[:phone],
date_of_birth: Date.parse(attrs[:date_of_birth]),
provider: payload[:provider], # "line"
uid: payload[:uid],
role: :user,
onboarded: true
)
# Step 5: ログ + JWT 発行
OauthLinkAttemptLogger.log!(result: "success_new", ...)
set_jwt_cookie(encode_jwt(user))
render json: { user: user_payload(user) }, status: :ok
end
| カラム | 値 |
|---|---|
role | :user |
onboarded | true |
provider | :line |
uid | LINE userId |
email | nil (LINE は email 取得しない) |
patient_number | nil (来院時に受付が付与) |
full_name / full_name_kana / phone / date_of_birth | 患者入力 |
enum :provider, { line: 0, google: 1, email: 2, manual: 3 }
残置 google: 1 は将来再導入余地、migration 不要
既存患者前提・氏名なし・
不一致なら 401
セルフ登録・氏名追加・
常に新規作成成功
| ケース | メッセージ |
|---|---|
| validation_failed | 「入力内容に誤りがあります。ご確認ください」+ フィールド単位エラー |
| claim_token_expired | 「セッションが切れました [ログインへ]」 |
| rate_limited | 「しばらく待ってから再度お試しください」 |
| unknown | 「通信エラーが発生しました。再度お試しください」 |
/login) の文言変更- 受付の方が登録した後、ご自身の LINE / Google で
- ログインしてください。
+ LINE アカウントでログインしてください。
+ 初めての方はそのままご登録いただけます。
| ファイル | 内容 |
|---|---|
apps/user-web/src/components/auth/OAuthButtons.tsx | Google ボタン |
apps/api/config/routes.rb | google/callback ルート |
apps/api/app/controllers/api/v1/auth/omniauth_callbacks_controller.rb | def google_oauth2 メソッド |
apps/api/config/initializers/omniauth.rb | provider :google_oauth2, ... |
enum :provider の google: 1 (DB 値、将来再導入用)既存 OauthClaimRateLimiter を 再利用: phone × ip_address ベース、24h で 5 回。新規登録もブルートフォース対象になり得るので維持。
既存 OauthLinkAttemptLogger を 再利用。新 result 種別 success_new を追加。受付スタッフが「LINE セルフ登録された患者」を staff-web 上でフィルタできる (Plan 4-D-2 で UI 化)。
突合ロジック撤廃により 「他人の情報で誰かのカルテを覗く」経路は存在しない。LINE 連携 = 個人 1 アカウント、phone は自己申告。
spec/requests/api/v1/auth/oauth_claim_spec.rb を 書き換えapps/user-web/src/routes/onboarding-claim.test.tsx を register 対応に 書き換え「LINE 連携 → 登録 → 初回予約 → 確定」のフルパス (mock または dev seed)
provider: :manual User の cleanup / アーカイブapps/api/app/controllers/api/v1/auth/oauth_claim_controller.rbapps/user-web/src/routes/onboarding-claim.tsxapps/api/config/initializers/omniauth.rbdocs/superpowers/specs/2026-04-29-plan-1-5-security-hardening-design.mdfeat/patient-reservation-flow-redesign の次フェーズで分岐予定