銀行エンジニアリング Lab 01:Ledger Lab(二重記帳を起こそうとする)
ローカルの架空データ環境で、正常な記帳・取消・訂正と、二重記帳・残高不足・二重取消などの異常操作を自分で試し、仕組みがどう止めるかを確かめます。
v8以降に実装した台帳・記帳エンジンなどを実際に動かし、正常時と異常時の両方から銀行システムの構造を学ぶ。
Prerequisite: BANKING SYSTEMLEARNING GOALS
このページで学ぶこと
- ローカルSimulator環境の起動方法
- 正常系:記帳→トレース→取消→訂正
- 異常系:同じキーで別金額、残高不足、二重取消
PLAIN LANGUAGE
まず、ここだけつかむ
ローカルの架空データ環境だけを使い、本番やPreviewには接続しません。
正常系(記帳・トレース・取消・訂正)と異常系(二重記帳・残高不足・二重取消・権限不足)を試します。
異常操作のあと、何も書き込まれていないことを確かめます。
DIFFICULT PARTS, STEP BY STEP
難しいポイントを、順番にほどく
専門用語を覚えることより、「なぜ必要か」「このシステムのどこで使うか」を理解することが目標です。
ローカルSimulator
自分のPCだけで動く練習用の銀行です。
本物のデータやサービスに影響を与えないためです。
scripts/local/platform-runtime.mjs。minibank_*test のDBだけに接続します。
トレース
1件の出来事を記録の終点まで追うことです。
結果の理由を説明できるか確かめるためです。
/admin/ledger/events/[id]。
拒否の確認
異常操作が止まり、何も残らないことの確認です。
止まったように見えて一部だけ書かれる事故を防ぐためです。
記帳件数と残高が変わらないことをDBテストでも確認します。
準備:安全なローカル環境だけを使う
このLabは本番やPreviewには接続しません。ローカルPostgreSQLに作った minibank_*test という名前のDBと、架空ユーザーだけを使います。ローカル実行環境はループバック以外のDBやテスト用以外のDB名を拒否します。
# 空のローカルDBへmigrationを適用し、架空の管理者・顧客を作る
export PGHOST=127.0.0.1 PGPORT=5432 PGUSER=postgres PGDATABASE=minibank_platform_demo_test
npm run test:banking:bootstrap
node scripts/local/platform-seed.mjs
# アプリとローカル認証を起動し、管理者としてログインする
node scripts/local/platform-runtime.mjs
open 'http://localhost:54336/local/login?as=manager&next=/admin/ledger'正常系の演習
| 手順 | 操作 | 確かめること |
|---|---|---|
| 1 | Ledger・Postingで DEPOSIT_INTEREST_PAYMENT を架空顧客の口座に記帳 | 一覧に「通常」のイベントが増え、仕訳IDが付く |
| 2 | イベント名をクリックしてトレースを開く | ルール名・借方=貸方の明細・記帳後の残高・監査ログ POSTING_EVENT_POSTED |
| 3 | 理由を入れて取消 | 連鎖に「取消」が増え、口座残高が記帳前に戻る |
| 4 | 別のイベントを訂正(金額を変更) | 取消と訂正の2件が同時に増える |
| 5 | Posting整合性チェックを実行 | 問題0件 |
異常系の演習
| 試すこと | 期待される結果 | 止めている仕組み |
|---|---|---|
| 同じ内容を通信エラー後に再送 | イベントは1件のまま | Idempotency Key の一意制約と fingerprint 照合 |
| 同じキーで金額だけ変えて送る(DBテストで再現) | PE009 で拒否 | request fingerprint の不一致 |
| 残高を超える手数料を記帳 | 「残高が不足しています」 | 記帳前の残高確認(PE010) |
| 凍結口座へ記帳 | 口座が凍結中である旨のエラー | 口座状態の確認(PE004) |
| 取消済みイベントをもう一度取消 | 取消ボタンが表示されない。RPCを直接呼んでも PE011 | reverses_event_id と reversal_of_entry_id の一意制約 |
| 運用者(operator)ロールで取消 | 権限エラー | platform.require_operator(true) による AD004 |
振り返り
- どの異常も、画面の制御だけでなくDBの関数・制約で止まっていたか
- 止まったとき、何も書き込まれていないことを残高と一覧で確認できたか
- トレース画面で、イベントから残高までを説明できるか
CHECK YOUR UNDERSTANDING
3問で理解チェック
答えを頭の中で考えてから、各項目を開いて確認してください。
Q1Labで使ってよいDB名の条件は?
ループバック上の minibank_*test という名前のDBです。
Q2取消済みイベントのトレース画面に取消ボタンは出ますか?
出ません。
Q3operatorロールで取消するとどうなりますか?
権限エラー(AD004)で拒否されます。
完全に暗記する必要はありません。大切な考え方を説明できそうなら押してください。
SOURCE TRAIL
根拠と関連教材
CURRENT IMPLEMENTATIONは確認したrepository内の実装です。HISTORICAL IMPLEMENTATIONは導入・修正の履歴で、後続migrationによる再定義があり得ます。RELATED LESSONは教材への案内で、実装の一次Sourceではありません。ASSUMPTIONは仮定、UNKNOWNは未確認を表します。
確認基点: d02eae8914f39cbf06bfe422dc39c71886f82b3e / 2026-09-11。稼働環境への適用確認: UNKNOWN。パス実在の自動検査と、記述した技術的事実の確認は別です。
Implementation Status: IMPLEMENTED IN MINIBANK(この教材が扱うコードの範囲)
- RELATED LESSON/docs/be-idempotency-integrity冪等性と整合性検査
- CURRENT IMPLEMENTATION
scripts/local/platform-runtime.mjsLabで使うローカル実行環境(架空データのみ) - CURRENT IMPLEMENTATION
src/app/admin/(protected)/ledger/page.tsxLedgerPostingPage()管理画面 Ledger・Posting - CURRENT IMPLEMENTATION
scripts/banking/v8-posting.test.mjs冪等性・同時実行・取消・訂正・整合性検出のDBテスト