ADR 一覧

ADR(Architecture Decision Record)は、技術的な意思決定を Issue や会話に 散らさず残す短い記録です。「なぜその形にしたか」をあとから追えるようにします。 下のトグルを開いて、決定・背景・比較・結果を読んでください。git 上の Docs/adr/ が 日英の正本で、ずれたときは日本語を正とします。

一覧

  • 0001 — アプリ関連を App/ 配下に集約する · Accepted · Issue #134

  • 0002 — SPM を UI / Store / sources のレイヤーで分割する · Proposed · Issue #109

ADR-0001:アプリ関連を App/ 配下に集約する

Accepted · 2026-08-08 · Site は対象外 · 配置のみ、挙動は変えない

アプリ本体と検証物の置き場を、次の木に固定します。ディレクトリ名も変えます。 Sources / Tests のままだと「リポジトリ全体のソース」にも読め、スコープが曖昧になるためです。

App/
  Tokfuel*          … executable と各 library(旧 Tokfuel/Sources)
  Tests/
    UnitTests/      … swift test の対象
    IntegrationTests/ … 結合(後続)
    TestDocs/       … シナリオ設計(実行しない)
    E2E/            … 通し実装(swift test 対象外)

製品コードの木と、Site / Docs / Scripts などの運営物をディレクトリで分けます。 TestDocs と E2E も同じ App/ の下に足せるようにします。

以前は本体が Tokfuel/Sources、テストが Tokfuel/Tests にあり、単一 SPM target から 参照していました。シナリオ設計と通しテストをリポジトリに載せる必要が出たとき (#134)、トップレベルや別ツリーに置くと入口が増え続けます。

  • 置き場がばらけると、「どこを触るか」を毎回探し、無関係な変更が同じ PR に混ざりやすい。

  • TestDocs / E2E の親を先に決めないと、後から別慣習が生え、モジュール分割と噛み合わせにくい。

  • ルートや Tokfuel/Sources という名前は、アプリ製品の木だと一目で分からない。

  • 案1 現状維持 — TestDocs / E2E は都度別場所。ばらけ方と後続箱の課題が残る(不採用)。

  • 案2 トップレベルに並べる — 入口は揃うが Site / Docs と同じ階層で混ざる(不採用)。

  • 案3 App/ 配下に集約 — アプリ関連の親が一つ。Site は外に置いたまま(採用)。

探索しやすさ、TestDocs / E2E の伸ばしやすさ、#109(モジュール分割)との両立で 案3が優れます。移行はパス更新が必要ですが、挙動変更は不要です。

  • アプリ関連の探索入口が App/ に一つになる。

  • 運営物と製品コードの境界がディレクトリで分かる。

  • 後続のモジュール分割を「アプリの中」の話として切りやすい。

版正本の置き場やトップレベル改名まではこの決定に含めません。App/ 集約だけの範囲に 閉じます。詳細な比較表はリポジトリの ADR 本文にあります。

ADR-0002:SPM を UI / Store / sources のレイヤーで分割する

Proposed · 2026-08-08 · 前提 ADR-0001 · target 境界(木の再配置ではない)

App/ 配下の単一 SPM target をやめ、レイヤーで library target を分割します。 データの流れと依存の向きを次で固定します。

sources(Claude / Cursor / Codex / Budget …)  … 取得。情報を取る API を公開
        ↓
Store                                         … 機能名ファイルごとに UI 向けへ整形・合算
        ↓
UI                                            … Store が渡す情報を表示

依存の向き: UI → Store → sources
具象の組み立て: App(executable)
  • sources は取得軸で分ける。横断型だけ薄い TokfuelCore に置く。

  • Store はソース固有の整形を機能名ファイル(例: CursorUsage.swift)に分け、UI へ渡す形にまとめる。

  • UI は Store(と表示に必要な薄い型)だけを見る。SQLite、retok、ダッシュボード API を直接見ない。

  • Firebase、retok リソース、sqlite3 は、使う source / Analytics target に閉じる。

  • 挙動とグラウンドルール(ローカルオンリー、ゼロセットアップ、retok 無改変、python3 任意、新規パッケージ禁止)は変えない。

feature 縦割り(UI 片まで各ソースに閉じる)は採りません。変更の自然な切れ目が 「取得 → 整形 → 表示」だからです。sources を Claude / Cursor などに分けるのは レイヤーの下段の話であり、UI / Store をソース縦割りにはしません。

  • Cursor の今日分コストを直す — 取得は TokfuelCursor、整形は Store の Cursor 用ファイル、見た目だけなら TokfuelUI。

  • ポップオーバーの余白や共通レイアウト — TokfuelUI に閉じる。データが変わらないなら Store / sources は触らない。

  • データの流れ(Cursor 行)— Cursor が取る → Store が整形 → UsageStore 相当が合算 → PopoverView 相当が表示。

ADR-0001 で親を App/ に揃えたあとも、target は一つで、UI・Store・外部通信・コスト計算が 同一ディレクトリに混在していました(#109)。並行 PR の衝突を減らす feature 縦割りも 比べましたが、実データの流れは「sources が取り、Store が整形して UI に渡す」形であり、 UI を横串で直したい変更も残ります。その切れ目に合わせると境界はレイヤーになります。

  • Store / UI / driver の役割分担が文書依存で、コンパイルでは守れない。

  • 取得・整形・表示のどこを直すかが、ディレクトリ名から読み取りにくい。

  • 見た目の横断修正とソース固有の取得修正が、同じ木で交差しやすい。

  • 案1 現状維持 — 境界と見通しの課題が残る(不採用)。

  • 案2 レイヤー — データの流れと UI 横断に合う。sources は下段で分割(採用)。

  • 案3 feature 縦割り — ソース衝突には効くが、UI をまとめて直す軸と相性が悪い(不採用)。

  • 案4 極細レイヤー多数 — きれいさに対してコストが過大(不採用)。

  • 案5 ハイブリッド — 縦と層が二重になり、境界管理が重い(不採用)。

  • UI が SQLite や retok 実装を直接見ない、といった逆流をコンパイルで検知できる。

  • 「取得は Cursor target」「整形は Store の Cursor ファイル」「見た目は UI」と変更範囲を説明しやすい。

  • Store / UI は層としてホットスポットになりうる — 機能名ファイルと画面単位ファイルに分け、PR を小さく保つ。

  • 逆依存(BudgetMonitor→UI など)は target を切る前に callback / プロトコル化でほどく。

書き方と状態

1 件の決定 = 1 ディレクトリ。本文ファイル名はディレクトリ名と同じ ID-slug です。 日本語(.ja.md)と英語(.md)の両方が必須です。本文は Decision / Context / Consideration / Consequences / References の 5 セクションで、Consideration には 現状維持を必ず含めます。

  • Accepted — いま有効な決定

  • Proposed / Draft — 検討中・レビュー待ち

  • Deprecated / Superseded / Rejected — 履歴として残すもの

大きな方針変更は、先に GitHub Issue(ラベル ADR)で議論し、合意した内容を ADR に 落とします。新規 ADR を足したり状態を変えたら、同じ PR で README の一覧も更新します。