自作会計システムに消費税を通した日。composable の await 連続で Nuxt コンテキストが消えた
朝いちで投げた質問が「これってなんか積み残しありましたっけ。これ何のプロジェクトでしたっけ」だった。
自分で作ったものを、自分で忘れている。
返ってきた棚卸しはこうだった。自作の会計システムの MVP。Nuxt 4 と Nuxt UI 4、Drizzle、libSQL/SQLite で組んであって、pnpm dev を叩くと 3300 番で立ち上がる。Phase1 から Phase5 までは実装もコミットも終わっている。ユニットテストをその場で走らせたら67件が全通過した。
積み残しは4つ挙がった。Phase6 の消費税がまるごと未着手。トップページが「セットアップ中」の文言で止まっている。反対仕訳の自動起票が無い。Phase3 から Phase5 の E2E が足りていない。
「じゃあこれ順次続けてください」とだけ返した。
スキーマから始めた消費税対応
タスク管理ツールに積み直させてから、コード全体を読み込ませた。着手は Phase6 の消費税からにした。
順番は下から上に固定した。スキーマ、ドメイン関数、API と seed、最後に UI。
マイグレーションは ALTER TABLE の ADD COLUMN だけで適用し、既存のトリガーはそのまま残した。ドメイン関数まで通ったところで最初のタスクが閉じた。
次は API と seed だった。既存の仕訳フローを確認させてから、税区分マスタと消費税集計の API を足した。
税額の計算をどこに置くかだけは自分で決めた。仕訳の検証ロジックに、税区分の解決と消費税明細の生成をまとめて組み込ませた。検証を通った仕訳には必ず税額がついている状態になる。入力画面が増えても、税の出し方は一箇所しか無い。seed も合わせて更新させた。
UI では、仕訳入力画面に税区分の選択と税額プレビューを載せた。仕訳を入力する画面は2つあるので、共通のロジックは composable に切り出して両方から呼ばせた。
ここまでは詰まらずに進んだ。
Chrome DevTools MCP が繋がらない
描画を確認するため dev サーバーを起動させた。Chrome DevTools MCP がブラウザに接続できない。
繋げる工夫で粘るのはやめて、Playwright での確認に切り替えさせた。やりたいのは接続の復旧ではなく、画面が正しく描けているかの確認だ。
切り替えた先で不具合が出た。
composable の await と Nuxt コンテキスト
原因は composable の中にあった。await を連続させていて、その先で Nuxt のコンテキストが失われていた。形としてはこういう並びになる。
const useTaxPreview = () => {
// 1つめの await までは通る
// その先の await のあとでは Nuxt のインスタンスを拾えない
// composable が内部で当てにしている機能が、そこから効かなくなる
}
仕訳画面から共通ロジックを引き剥がしたときに await が増えて、そのまま踏み抜いたのだと思う。
修正させたら、画面はすべて正常に出た。
既存の E2E も税の追加で壊れたので、設定を見直させた。Phase6 の E2E 6件が全部通ったところで消費税対応が閉じた。
トップページ、反対仕訳、管理画面
「セットアップ中」のままだったトップページをダッシュボードに変えさせた。続けて反対仕訳の自動起票を実装させた。借方と貸方を入れ替えた仕訳を、手で打ち直さずに起こせるようにする。
型チェックを回しながら、E2E 用に既存ページの testid を確認させた。テストを書き足す前に共通ヘルパーを切り出させて、そのあとで消費税、帳票、反対仕訳の3系統を追加した。13件が全通過。
最後がユーザー管理と会社設定の画面だった。ここまで足して E2E は18件になった。
エラーメッセージの中身と二重表示
新しい画面を動かしていて気づいた。エラーメッセージにサーバー側の理由が出ていない。共通の取り出し処理を入れて全画面に適用させた。
今度は同じエラーがモーダルの中とページ上部の両方に出た。モーダルを開いている間はページ側を隠すよう直させた。
もう一度描画を確認させたら、会社設定のヒント文が入力欄から離れて浮いていた。ここも詰めさせた。
コミットと学習ゲート
コミットしようとしたら、pre-commit の学習ゲートに止められた。/learn を起動したところで、こちらから「学習ゲートはパスでいい」と伝えた。理由を残してスキップコミットにした。ローカル設定の .claude/ は扱いの判断が要るので、コミットからは外してある。
積み残し7件をすべて実装して c81e87c でコミットした。ユニット100件、E2E18件、型チェックがすべて通った。画面は Playwright で実際に描かせて確認してある。
朝に走らせたときは67件だった。
そこでセッションの制限が近づいた。ドキュメントに詳細を残すよう頼んで、作業ログを memo 配下に1本書かせて 0bec8b9 でコミットした。作業ツリーはクリーンな状態で終わった。
「何のプロジェクトでしたっけ」と聞くところから始めて、積み残し7件が消えた。また同じことを聞く日は来る。そのときのために残したログでもある。
学び
- ブラウザに繋がらないときは、繋げる工夫で粘らない。描画を確認するだけなら Playwright で足りる
- composable への切り出しでは、中の await を数える。Nuxt のコンテキストは await をまたぐと失われる
- テストを足す前に共通ヘルパーを切り出す。この順番は今回も効いた
- エラー表示は「出るか」ではなく「理由が読めるか」で点検する。二重表示も同じ見方で拾える
- 学習ゲートは黙って回避せず、理由を残したスキップで通す。判断そのものがログに残る