KYCの状態遷移
本人確認を、顧客の申請と管理者の審査に分けて理解します。
台帳、振込、KYC、権限、監査、照合をMinibankの実装と結び付ける。
先に学ぶ内容 — Prerequisite: 基礎 / 銀行業務学ぶこと — LEARNING GOALS
このページで学ぶこと
- KYCが必要な理由
- 許可された状態遷移
- 並行審査と再試行をDBでどう扱うか
体験04 · KYC(本人確認)
申請したら、いつ使えるようになるか確かめよう
まずは予想をひと言。本文を読んだ後、顧客の申請と管理者の審査を見比べます。
- 01まず予想する — PREDICT
まずここだけ:思ったことをひと言書く
本人確認の申請を出したら、その場ですぐに口座が使えるようになると思いますか?
正解でなくて大丈夫です。「〜だと思う」から始めてみましょう。
ヒント1を見る
申請してすぐと、審査が終わった後で、状態は同じでしょうか?
ヒント2を見る
却下された申請を、もう一度出し直すことはできるでしょうか?
もっと詳しく:この問いで使う専門用語
- KYC(Know Your Customer、本人確認)は、取引の相手が誰かを確認する手続きです。
- State(状態)は、申請が未申請・審査中・承認・却下のどこにあるかを表します。
- Approve / Reject(承認・却下)は、管理者だけが行える審査結果の確定です。
- Row Lock(行のロック)は、同時に2人が同じ申請を審査しないようにする仕組みです。
日常語で理解する — PLAIN LANGUAGE
まず、ここだけつかむ
KYCは本人確認です。書類を出したかだけでなく、未提出・審査中・承認・否認という状態の移り方を厳密に管理します。
同時に承認と否認が届いても、両方を成功させてはいけません。DBで対象行をロックし、現在状態を確認してから1つだけ確定します。
画面の表示ではなく、口座作成や管理RPCの中でもKYC状態を確認して初めて安全になります。
順番に理解する — DIFFICULT PARTS, STEP BY STEP
難しいポイントを、順番にほどく
専門用語を覚えることより、「なぜ必要か」「このシステムのどこで使うか」を理解することが目標です。
状態機械
許可された状態と、その間の移動だけを定める考え方です。
文字列を自由に更新すると、承認済みから審査中へ戻すなど不正な遷移が起きます。
submit、approve、rejectの各RPCが現在状態を検査し、許可された場合だけ変更します。
FOR UPDATE lock
審査中の1件に一時的な鍵をかけ、他の処理を待たせます。
承認と否認が同時に古いpending状態を読み、双方が成功する競合を防ぎます。
管理者の承認・否認処理で対象KYC行をロックしてから状態を判断します。
自然な冪等性
同じ操作を繰り返しても、状態が二重に進まない性質です。
二重クリックや通信再送が起きても、審査を二重処理しないためです。
1回目でpendingではなくなるため、同じ承認・否認の再実行は状態検査で拒否されます。
口座作成との整合
KYC承認と口座保有の条件が矛盾しないことです。
画面だけで制限すると、API直呼びで未確認顧客が口座を作れる可能性があります。
口座開設のDB処理が顧客のverified状態を確認することが防御の中心です。
発展 — ADVANCEDもっと詳しく確認する最初の学習では読まなくても問題ありません。仕組みをもっと深く理解したい場合に開いてください。
KYCとは
KYCはKnow Your Customerの略で、取引主体を確認する手続きです。Minibankでは、口座開設と振込の前提条件として顧客の `kyc_status` を使います。これは外部本人確認サービスではなく、学習用の状態管理です。
許可された状態遷移
- 01not_started(未申請)
- 02pending(審査中)
- 03verified(承認)または rejected(却下)
- 04rejectedから再申請するとpending
- pendingでの再申請は更新しない自然な冪等処理
- verifiedから再申請は拒否
- approve/rejectはpendingからだけ許可
- 顧客行をFOR UPDATEでロックし、同時承認・却下を直列化
実際のMinibankでは
顧客は `submit_kyc_application()`、activeな管理者は `approve_kyc()` または `reject_kyc()` を呼びます。管理操作はidempotency keyとrequest fingerprintを `admin.operation_requests` に保存し、同じ要求の再送では保存済み結果を返します。
体験学習の続き · LEARNING LOOP
ここまで読めましたか?続けて確認してみましょう
KYCの状態遷移を読んだところで、実際の申請画面と審査画面を見比べ、自分の言葉で説明してみます。
- 02実際に操作する — OPERATE
同じ仕組みを、動く画面から観察する
まず顧客画面で本人確認を申請し、この教材へ戻ります。リンクは新しいタブで開きます。ログインが必要です。
アカウントがない場合は新規登録が必要です。本人確認・口座開設には管理者承認が必要です。承認前や操作できない場合も、この教材内の図・説明・Source Trail(教材の参照元)で代替学習し、次へ進めます。
ログイン・新規登録の入口を開く ↗操作できない場合:教材の参照元で確認する ↓ - 03証拠を確認する — EVIDENCE
何を見たか、1つずつ確かめる
Evidence(判断の根拠となる記録)を確認したらチェックします。各項目の「何を見るか」を手がかりにしてください。
画面を開けない項目は、Source Trail(教材の参照元)と教材の説明で確認できます。失敗を実際に起こす必要はありません。
- 04コードの処理経路を追う — CODE TRAIL
コードを書く必要はありません
ここでは「説明されている仕組みが、実際のMini Bankのどこに実装されているか」を確認します。まずは日本語の役割説明を読み、入力した依頼がどこへ渡るかをつかみましょう。コードの全文を読む必要はありません。
基本の順序は、画面 → API Route(依頼を受ける窓口)→ TransferService(処理をつなぐサービス)→ DB / RPC(記録の保存場所と、その処理の呼び出し)です。まず最初の2つを見て、続くサービスは「もっと詳しく」で確認します。
顧客が本人確認を申請するボタン。押した後にどんな依頼が送られるかを探します。
src/components/customer/SubmitKycButton.tsxMigration(DB定義の変更履歴)。顧客からの申請・再申請を受け付ける定義を確認します。
supabase/migrations/20260822090001_create_submit_kyc_application_function.sql教材の参照元を確認する — Source Trail ↓もっと詳しく見る:残りのファイルと処理の約束
Migration(DB定義の変更履歴)。審査中の申請だけを承認・却下できる定義を確認します。
supabase/migrations/20260822090002_restrict_kyc_review_to_pending.sqlRow Lock(行のロック)は、同時に2人が同じ申請を審査しないようにする仕組みです。
- 05自分の言葉で説明する — EXPLAIN
LEVEL 1 — やさしい説明(まずここだけ)
なぜ承認・却下は、審査中(pending)の申請にしかできないのでしょうか? 短い2文を目安に説明してください。
日常語だけで完了できます。専門用語の数や正誤を自動採点するものではありません。
ヒント1を見る
「申請中」と「承認済み」という2つの状態を使って書いてみましょう。
ヒント2を見る
なぜ承認は、審査中の申請にしかできないのかを考えてみましょう。
もっと詳しく:LEVEL 2 — 専門用語を使った説明(任意)
State(状態)、Row Lock(行のロック)、冪等性の3つを使って、同時審査が起きたときの挙動を説明してみましょう。
挑戦する場合は、上の説明欄に追記できます。追加しなくても完了できます。
説明の確認ポイント — Checkpoint- 申請から承認までに「審査中」という段階があると説明できる
- 審査中の申請だけが承認・却下の対象になると説明できる
理解を確かめる — CHECK YOUR UNDERSTANDING
3問で理解チェック
答えを頭の中で考えてから、各項目を開いて確認してください。
Q1なぜ承認ボタンを1度だけ押せるUIでは不十分ですか?
別端末、API直呼び、通信再送、複数管理者の同時操作をUIだけでは止められないからです。
Q2承認と否認が同時に来たら何が必要ですか?
対象行のlockと、lock取得後の現在状態の再確認が必要です。
Q3KYC済みという表示だけで口座開設を許可できますか?
できません。口座を作るDB処理自身が正式なKYC状態を確認する必要があります。
完全に暗記する必要はありません。大切な考え方を説明できそうなら押してください。
教材の参照元 — SOURCE TRAIL
根拠と関連教材
CURRENT IMPLEMENTATIONは確認したrepository内の実装です。HISTORICAL IMPLEMENTATIONは導入・修正の履歴で、後続migrationによる再定義があり得ます。RELATED LESSONは教材への案内で、実装の一次Sourceではありません。ASSUMPTIONは仮定、UNKNOWNは未確認を表します。
確認基点: d02eae8914f39cbf06bfe422dc39c71886f82b3e / 2026-09-11。稼働環境への適用確認: UNKNOWN。パス実在の自動検査と、記述した技術的事実の確認は別です。
- 過去の実装 — HISTORICAL IMPLEMENTATION
supabase/migrations/20260822090001_create_submit_kyc_application_function.sqlsubmit_kyc_application()顧客による申請・再申請 - 過去の実装 — HISTORICAL IMPLEMENTATION
supabase/migrations/20260822090002_restrict_kyc_review_to_pending.sqlapprove_kyc() / reject_kyc()pending限定の管理審査 - 現在の実装 — CURRENT IMPLEMENTATION
scripts/regression/suites/kyc.mjsKYC状態遷移のDB回帰テスト - 現在の実装 — CURRENT IMPLEMENTATION
scripts/regression/api/kyc.mjsKYC APIの回帰テスト