会計ソフトAの内部APIを叩くハンズオン記事を3本書いていた。ハンズオン編・エクスポート編・インポート編の3本だ。ハンズオン編だけが「DevTools Consoleに1コマンドずつ叩いて何が返るかを確認する」スタイルになっていて、残り2本は古いスタイルのまま残っていた。スタイルをそろえ、Chrome DevTools MCPで全Stepを実機で叩いて、数値も挙動も実機で再現できる形に書き直した。
3記事のスタイル統一
3本のうちエクスポート編とインポート編が旧スタイルで取り残されていたので、Claude Codeに「DevTools Console に1コマンドずつ打ち込んで、何が返るかを確認する」視点で書き直してもらった。
- エクスポート編:Consoleで未登録明細を全件取得 → 整形 → JSONダンプまで
- インポート編:単純仕訳と複合仕訳のPOSTを1コマンドずつ実行する流れ
- ハンズオン編:関連リンクが旧スタイル前提だったので、3本の整合性を取り直し
書き直してもらったあと自分で開いて読み返したら、コードブロックのコピーボタンが消えていた。コードを1コマンドずつConsoleに貼る記事なのに、コピーできないと読者の作業が止まる。
ProsePre.vueにコピーボタンを復活させる
ProsePre.vueを開かせて状況を確認した。copyCode()関数は残っていて、テンプレート側のボタンだけが消えている状態だった。ホバー時に右上にCopyボタンを出すパターンに戻してもらった。
<button v-if="!copied" class="copy-btn" @click="copyCode">⧉ Copy</button>
<button v-else class="copy-btn copied">✓ Copied</button>
クリックで2秒間「✓ Copied」に変わる挙動も入れ直した。
console.log側に説明文を出す
ヘルパー関数を書き直したあと、Console出力が'mfh ready, cti =', 'kwri2sDmetFNBaNj5Qcz8g'のような形で出ていた。これだと何の値なのか読み手が分からない。最初は「関数定義のコメントに『各メソッドが何を返すか』を書いてほしい」と頼んだつもりだった。
Claude Codeはヘルパー関数の中にinlineコメントを埋めて返してきた。それを見て「違う、返ってくる出力のところにコメントを出してほしい」と指示し直したら、今度は記事内の出力ブロックに注釈を入れてくる。記事の中ではコメントが見えるが、実際のConsole画面には何も出ない。
3回目で「コンソール画面に実際に表示される出力に注釈を含めたい」と意図が伝わった。console.log()を「値 + 説明文」の形に書き換えてもらった。
console.log('cti(今期のID)=', cti)
console.log('CSRFトークン文字数 =', csrf.length)
実画面で何が出ているのか目で確認できる状態になった。
ページ遷移するとwindow.mfhが消える問題
ハンズオン編の手順を試していて気づいた。仕訳登録のPOSTがStep 10で、結果確認はStep 11だ。ところがStep 11のために仕訳帳ページに移動した瞬間、window.mfhもctiも全部消える。SPA遷移ではなく通常のページ遷移だから、Console上の状態が引き継げない。
解決策として、3記事のStep 0.1「ブラウザの準備」に「どのページで作業するか」と「ページ遷移はしない」を明記してもらった。ハンズオン編にはStep 10.5として「同じタブのConsoleから仕訳帳APIを直接叩いて登録結果を確認する」手順を追加した。
const journals = await mfh.fetchJson(`/api/v1/journals?cti=${cti}&per_page=5`)
console.log('仕訳帳 最新5件 =', journals.data?.journals)
仕訳帳のページに行かなくても、Consoleから/api/v1/journalsを叩けば最新仕訳を確認できる。
Chrome DevTools MCPで全Stepを実機実行
ここで「記事の内容を一通り実機で叩いて、出力を全部取って記事に反映してほしい」と頼んだ。Chrome DevTools MCPでログイン済みChromeに繋がっているので、出力もネットワークも全部取れる。テストで作った仕訳は最後に削除するまでが条件。
実機で叩いてみると、記事のサンプル値と実機の数値がだいぶ違っていた。
税区分マスタの label が実機は短縮形
記事のサンプルでは税区分マスタのlabelを"課税仕入 10%"と書いていた。実機で叩いたら"課仕 10%"という短縮形だった。件数も例の58件に対して実機は151件。Chrome拡張側の実装も同じくkeywords[1]で"課税仕入 10%"を探していて、これは動かない状態だった。
正しいキーは半角スペース付きの"課仕 10%"。3記事全部とChrome拡張のコードを実機データに置き換えた。
未登録明細の件数
記事の例では211件と書いていた。実機は457件・5ページ。これも全部実機データに置き換えた。
仕訳登録POSTで「事業主貸」だと思っていたら「みずほ銀行」だった
Step 10で仮払金 32,325 / 普通預金 32,325 のテスト仕訳をPOSTした。No.6として登録され、journalId = qHUEvp3WohXohjTTn9ikFwが返ってきた。仕訳帳APIで照合したら、もうひとつ気になる仕訳が出てきた。
No.5として「仮払金 25,809 / 普通預金 25,809」が登録されていた。all[0]は政策公庫(国) -25,809。これは前のテストでPOSTしたまま消し忘れていたものだった。「事業主貸が貸方に入っているはず」と思い込んでいたら、実際には連携先のみずほ銀行が貸方に入って登録されていた。明細の登録元が「みずほ銀行(連携サービスのサイト)」のため、貸方は連携先銀行になる仕様だった。
「事業主貸 / 仮払金」で仕訳帳をgrepしても出てこないわけで、自分の見落としに気づいた。No.5とNo.6を両方DELETEした。
削除APIで「対象外」になるはずが、別ステータスへ
DELETEのあと、元の明細は「対象外」状態になるはずだと記事に書いていた。確認したら対象外フィルタには0件。journalizing_suggestionsにも戻っていない。trans_listを全ステータスで見ても0件。
記事の説明と実機挙動が違ったので、実機挙動に合わせて記事を直した。「対象外になります」と断定していた部分を、実機で観測した挙動に書き換えた。
新APIパターンの発見
「対象外を解除する」APIを実機で動かそうとして、レガシーのignore_cancelを叩いたら404。廃止済みだった。JSバンドルから新APIパターンを探したら、別系統のエンドポイントが見つかった。
/api/v1/journalable_dists/register(登録)/api/v1/journalable_dists/ignore(対象外)
ペイロード構造は{ cti, journalableDist: { id: "..." } }。最初は400 Bad Requestが返って、idの形式がわからなかった。React fiber を辿って各行のpropsを読むと、journalCandidateIdという新フィールドが<hash>::<index>形式で入っていた。
Jotaiストア(__JOTAI_DEFAULT_STORE__)も探って、JSバンドルからn.idの生成元を追いかけた。結論としてidは<hash>::<index>のhash部分のみだった。これを渡したら200が返るようになった。
解除APIはno-op
「対象外→未入力」に戻す解除APIを探した。DELETEは404、toggle仮説でPOST .../ignoreを2回叩いても200だけ返って状態は変わらない。POST /api/v1/voucher_journals/journal_candidates/exclusionsも試したが、PAYPAL明細がjournalizing_suggestionsに戻ったかを確認するとpaypalCount: 1のまま。
つまりPOST ignoreは200を返すが、実際にはno-opだった。idがjournalCandidateIdのhash部分で、本来のjournalableDist.idとは違うのかもしれない。
幸いno-opなのでユーザーのデータは変更されていない。深追いせずに実機検証はここで終わらせた。
最後にユーザーデータの確認
仕訳帳のページを再読み込みして、No.4とNo.3だけが残っていることを確認した。自分が登録したNo.6と取り残しのNo.5は両方DELETE済み。元のデータは元通り。
学び
- 「記事のサンプル値」と「自分の事業者の実機値」は普通に違う。実機で叩かないと数値の桁数も件数も見えない
- 仕訳の貸方は「連携サービスの銀行」が入る場合がある。「事業主貸」だと思い込むと仕訳帳でgrepしても出てこない
- 内部APIは廃止される。
ignore_cancelは404になっていた。新パターンはjournalable_dists/registerとjournalable_dists/ignoreだった - ID形式の特定はReact fiberとJotaiストアを両方見ないと辿れない。
<hash>::<index>のhash部分だけが本物だった - 解除APIが200を返してもno-opのことがある。確認は別APIで取り直す
- 「記事の説明」と「実機挙動」が違ったら、記事の説明を直す。実機が正
ハンズオン記事は実機で1コマンドずつ叩いて検証して初めて、サンプル値の食い違いや挙動の差異が拾える。Console出力に説明文を埋め込む書き換えも、記事の中で説明するより実画面で意味が分かるほうが読者の負担が軽い。