基本の14章 · 13

コードは「誰が、どこまでできるか」から読む

ファイルを上から全部読む必要はない。Open Bankingと他行送金を比べ、呼出し元・認可・業務・記帳の境界をたどる。

本文の説明・図・掲載コードだけで読み進められます。出典リンクは、権限のある人向け(非公開GitHub)です。GitHubで閲覧権限がある方だけ開けます。

この記事でわかること

  • 画面の名前より、呼出し元と認可の根拠から入口を見つける
  • 同じ振込でも、依頼を作る権限と資金を動かす権限を分ける
  • 型・コメント・契約・実装の役割を区別し、最終定義まで追う
この記事の目次
01 / READ THE SYSTEM

1. 最初に一つ、具体的な問いを持つ

コードを読む目的を「システムを全部理解する」にすると、ファイルの多さに負けてしまいます。最初は「外部アプリから振込を頼んだら、その瞬間にお金は動くのか」という一問で十分です。入口、権限、状態の変更、仕訳という順に、問いに関係する道だけをたどります。

MiniBankのファイルには、画面、HTTPの窓口、入力の形、サービス、データベースの業務処理があります。画面は人に見せる場所、HTTPの窓口は要求を受ける場所、サービスは窓口からDB処理を呼ぶ接続役です。RPCは、名前を指定してデータベース内の処理を呼び出す仕組みだと考えてください。RPCという名前だけで安全が決まるわけではなく、その先で何を確かめるかが重要です。

01呼出し元顧客・管理者・第三者のどれか
02認証と認可誰か、何を許されているか
03業務の処理状態と条件を確かめる
04記録と応答何を保存し、どう返すか

この図は読む順番であって、すべての経路の実行順序を一律に表すものではありません。たとえば第三者用APIでは、入力の検査を先に行い、トークンの権限確認はDB内で行います。

出典:第三者からの振込依頼のHTTP入口(非公開GitHub・要権限)

02 / READ THE SYSTEM

2. v16の入口は「第三者が持つ同意」を確かめる

Open Bankingの振込依頼は、src/app/api/open-banking/v1/transfers/route.tsから読めます。POST処理は、操作を識別するIdempotency-Keyと、金額・宛先などの形を検査します。正しければwithGatewayへinitiate_transferという処理名を渡します。ここには、預金残高を直接書き換える処理はありません。

次にwithGatewayを定義するhttp.tsを開くと、Bearerトークンを取り出し、callObGatewayへ渡すことが分かります。OpenBankingService.tsでは、公開RPCのob_gatewayが呼ばれます。匿名用の接続を使うという記述は「誰でもデータを読める」という意味ではありません。この経路ではDB自身が第三者用トークンを検証するからです。

DBのob_gatewayからresolve_tokenへ進むと、トークンの形式・期限・失効、クライアントの停止状態、顧客の同意、必要な権限の範囲を確かめています。口座を読む場合も、渡された口座IDだけを信じず、トークンに結びつく顧客の口座かを検査します。「ログイン済み」と「その口座を読んでよい」は別の問いです。

出典:Bearerトークンを渡す窓口(非公開GitHub・要権限)

出典:公開RPCへの接続(非公開GitHub・要権限)

出典:ob_gatewayとresolve_token(非公開GitHub・要権限)

03 / READ THE SYSTEM

3. transfers.writeは「振込完了」までの権限ではない

仮に架空の家計簿アプリが、花さんの同意を受けて5,000円の振込を依頼したとします。transfers.writeという権限名だけを見て、「このアプリがお金を動かせる」と判断すると誤読です。業務処理のinitiate_transferまで進むと、既存のrequest_transferを呼び、顧客による確認待ちの依頼を作ることが分かります。

応答のPENDING_CUSTOMER_APPROVALは、「お客様の承認待ち」です。実際に資金が動くには、顧客本人がMiniBank側で認証アプリの確認コード(TOTP)による確認を行う必要があります。第三者用の入口で、既存の本人確認や金額制限を省略した別の送金処理を作っているわけではありません。

5,000円の依頼を受け付けた直後に応答が消えた場合も、同じキーで照会します。同じキー・同じ内容なら元の依頼へ戻り、内容が変われば衝突として拒否します。ここで新しいキーを作ると、利用者の意図が同じでも別の依頼になります。入力欄の検査だけでなく、保存されたキーと内容の照合まで読む理由がここにあります。

このOpen Bankingは閉じた教育用Sandboxです。実際の第三者サービスや銀行ネットワークに接続するものではなく、通知の配信も外向き通信をしない模擬動作です。

出典:振込依頼に限定した権限とSandboxの範囲(非公開GitHub・要権限)

出典:initiate_transferからrequest_transferへの接続(非公開GitHub・要権限)

04 / READ THE SYSTEM

4. v9の他行送金は、管理画面からの別の道

次は「他行宛送金を受け付ける」という管理画面を読みます。src/app/admin/(protected)/interbank/page.tsxには、domainがinterbank、actionがsubmitのフォームがあります。この二つを手掛かりに、管理用の汎用API、src/app/api/v1/admin/platform/[domain]/route.tsへ進みます。

この入口は、同じサイトからの要求であること、許された業務名か、入力の形、管理画面の認証済みセッションがあるかを確かめます。requireAdminSessionの名前から権限まで保証すると決めつけないでください。実装では利用者の存在を確認し、担当者か管理責任者かという業務権限の判断はDBに残しています。

PlatformServiceは、PLATFORM_RPCという対応表からadmin_interbankを選びます。対応表は、任意のDB関数名を外から指定できないようにする一覧です。その先のadmin_interbankでは操作ごとにplatform.require_operatorを呼び、通常の担当者でよい操作と、管理責任者が必要な再送などを分けています。

つまり読む道は、管理画面のフォーム、管理API、接続サービス、許可されたRPC、操作ごとの権限確認です。Open Bankingの同意付きトークンとは、権限の根拠が違います。二つの入口を「どちらも振込API」とまとめてしまうと、誰の責任で何ができるのかが見えなくなります。

出典:他行送金フォーム(非公開GitHub・要権限)

出典:管理APIの検査(非公開GitHub・要権限)

出典:セッション確認の責任範囲(非公開GitHub・要権限)

出典:業務名とRPCの対応表(非公開GitHub・要権限)

05 / READ THE SYSTEM

5. 同じ「応答なし」でも、照会する事実が違う

v9では、管理者が架空の顧客を代理して送金指図を受け付けます。受付で顧客預金から送金額と手数料330円を確保し、送信・受理・決済へ進みます。v16の「依頼しただけでは資金を動かさない」とは、開始時点の業務が違います。

架空の他行に5,000円を送って応答が消えたとき、相手側のシミュレーターには受理済みの記録があるかもしれません。MiniBank側の表示が結果不明でも、相手の事実まで失敗とは言えません。v9はend_to_end_idという一貫した支払IDで相手側の帳簿を照会し、状態を確定します。未受信の照会結果が2回そろった場合だけ、管理責任者が同じIDで再送できる設計です。

一方、v16でまず照会するのは、同意した顧客とクライアントに結びついた振込依頼の状態です。通知が重複したり順番が逆になったりしても、通知から再び資金を動かしてはいけません。IDで重複を除き、連番の欠けは正規のイベント列で埋めます。結果の伝達と、結果を確定する業務を分けて読む練習になります。

出典:v9の資金確保と結果不明の規則(非公開GitHub・要権限)

出典:v16の状態照会とイベント列(非公開GitHub・要権限)

06 / READ THE SYSTEM

6. 型、コメント、契約、実装は違う証拠

domain/platform/interbank.tsには、状態名や画面で出せる操作の一覧があります。これは言葉を理解する地図として便利です。ただしavailableActionsのコメント自身が、真の規則はRPC側で強制すると説明しています。ボタンが非表示だから安全なのではなく、別の呼出し方をされてもDBが拒否する必要があります。

契約書は「何を守るべきか」を示し、コードは「どこで守るか」を示します。変更の履歴も大切です。たとえばv9当初の資料には中央銀行決済勘定が負になり得るという限界がありますが、v19の現行契約では他行送金の決済にも残高検査と共通の排他を加えたことが記されています。最初の導入ファイルだけを見て現在の制約を断定できません。

そのため、ある関数を見つけたら、後のmigrationで再定義されていないかを確かめます。migrationはDBの構造や処理の変更を順番に積むファイルです。古いコメントの版数より、実際の対応表と最後の関数定義を優先し、分からないところは「契約で確認」「実装で確認」「実行は未確認」と証拠の種類を分けます。

出典:画面上の状態と操作の型(非公開GitHub・要権限)

出典:後の版で強化された中央銀行預け金の残高検査(非公開GitHub・要権限)

07 / READ THE SYSTEM

7. 読み終えたら、成功条件と拒否条件を言葉にする

一つの道を読み終えたら、「誰が、何を渡し、何がそろえば成功し、何が足りなければ止まるか」を短い文章にします。今回なら、第三者は有効な同意とscopeで依頼を作れるが顧客の最終確認は代行しない、行内担当者の他行送金は別の状態機械で受理と決済を扱う、と説明できます。

さらに、応答が消えた場合、権限が途中で失効した場合、同じキーで金額だけ変えた場合を読みます。正常時の道は短くても、安全性は拒否する枝に表れます。DBを実行して確かめる必要はありません。まず静的に、キーの保存先、権限の照合、状態遷移、会計の呼出しのつながりを記録できます。

この読み方にも限界があります。コードを読めたことは、現在の公開環境にその版が適用済みである証明でも、実認証を通した動作確認でもありません。本章の出典は固定コミットです。ファイル間のつながりを説明する証拠として使い、環境の稼働状態や実際の決済能力を推定しないことが、最後の読み間違いを防ぎます。

SOURCE NOTES

出典と、確認できた範囲

コードの説明と、稼働環境の検証を分けます

以下のリンクは非公開GitHubへの出典で、閲覧権限が必要です。本文はリンク先を開かなくても読める構成です。固定コード・設計資料を参照していますが、今回、この読み物のために銀行の取引やDB操作、本番試験は実行していません。実装や資料にある検査と、こちらで実施した検証を混同しないようにしています。

  1. Open Bankingの振込依頼入口 ↗(非公開GitHub・要権限)
    操作キー、入力検査、依頼と最終確認の分離
  2. Open BankingのHTTP共通処理 ↗(非公開GitHub・要権限)
    BearerトークンとDB認可への接続
  3. Open BankingのRPC呼出し ↗(非公開GitHub・要権限)
    ob_gatewayなどの実際の公開入口
  4. v16の業務実装 ↗(非公開GitHub・要権限)
    トークン、scope、所有者検査と既存依頼処理の再利用
  5. v16の契約 ↗(非公開GitHub・要権限)
    同意、依頼、イベント列、閉じたSandboxの境界
  6. 管理API ↗(非公開GitHub・要権限)
    同一オリジン・入力・セッション確認と業務呼出し
  7. RPCの対応表 ↗(非公開GitHub・要権限)
    許可した業務だけへルーティングする仕組み
  8. v9の業務実装 ↗(非公開GitHub・要権限)
    操作別管理権限と他行送金処理
  9. v9の導入時の範囲 ↗(非公開GitHub・要権限)
    結果不明・照会・再送と当初の限界
  10. v19での追加制約 ↗(非公開GitHub・要権限)
    中央銀行預け金の残高検査の更新

MiniBankは学習・検証用の銀行アプリです。架空の金額や人物は、仕組みを説明するための例です。

つながる読み物

ここまで読んだ記録を、ひとつ。

自分のペースで。あとから取り消すこともできます。

次の読み物v1からv20へ:小さな銀行を通じて身につく見方
→