| title | Project.md(CLB デザインプロジェクト固有ルール) | ||||
|---|---|---|---|---|---|
| status | current | ||||
| scope | 会計コア | ||||
| audience |
|
||||
| growth | append | ||||
| updated | 2026-09-02 | ||||
| supersedes | |||||
| related |
|
このデザインプロジェクト固有の前提を書く。ClaudeCodeForDesigner/ の汎用ルールはここに書かない。
企画・仕様・進捗は ../docs/(索引: ../docs/README.md)、判断の経緯は ../docs/decisions/ にある。
- BusinessAppSQLite(本アプリの唯一のデータソース)
- 種別: SQLite / 実体は
<REPO_ROOT>/LocalData/db/配下(Git 追跡外) AllowCliSqlAccess: true(ローカル専用 DB。本番を指さない)- 認証部品の
app_usersと、マイグレーションの台帳schema_migrationsも同居する。 一時ファイルのtemporary_filesは未作成(appsettings.jsonは参照しているので、FileField/ImageFieldを置くならテーブルを先に作る)
- 種別: SQLite / 実体は
- サーバ側
BusinessApp.Server/appsettings(.Development).jsonにも同名データソースの定義が要る (変更時はサーバ再起動)
- テーブル・列: snake_case 英語(例
journal_entries.entry_date)。PK はidINTEGER 自動採番 - モジュール・フィールド: PascalCase 英語(例
JournalEntry/EntryDate)。 画面表示名(DisplayName)は日本語 - CLB のシステム予約名(
Id/LogicalDelete/OptimisticLocking/CreatedAt/UpdatedAt/Creator/Updater)はその綴りのまま使う - 主要テーブル名の正典は
../docs/04_会計ドメイン設計.md
テンプレート由来の
AppUserモジュールだけはフィールド名が日本語(ユーザー識別名等)である。 認証部品の資産なので改名しない。新規モジュールは上記の規約に従う。
Design/Modules/ のトップレベルのフォルダ=アプリ(部品)(開発者の決定。2026-08-28。
「Modules 下のトップレベルのフォルダはアプリにしましょう」)。
フォルダ名の割り当ては設計判断——Accounting/(会計コア)・Partners/(取引先)・
Platform/(どの部品にも属さないもの。AppUser 等)。
アプリの中の分け方(Books/ Journals/ Masters/ Settings/)はその下に置く。
- フォルダ(アプリ)と PageFrame(役割ごとの導線)は別の軸である。一致させない (ADR-0035 §2)。 前回プロジェクトは両者を一致させようとして、フレームを 7 回作り直したうえに 「勘定科目は業務マスタのフレームだがシステムマスタのフォルダ」という食い違いが残った
- モジュール名はデザイン全体でフラットな名前空間なので、フォルダを動かしても参照は壊れない。
ただし移動後は
designcheck→ deploy → 実機まで通す
何をどう見せるかと、その理由は ../docs/09_画面の原則.md が持つ。
ここには CLB での書き方だけを置く(同じ規則を 2 か所に書かない)。
| 原則(09 が持つ) | CLB での書き方 |
|---|---|
| 金額列は右詰め・3 桁カンマ | Format: "#,0"。text-align では効かない・列見出し(<th>)に class が付かない(qa/01 D-15・D-16)。フォーム入力欄と列見出しは左のまま |
| 識別子は左詰め | 何も付けない(既定) |
| ○/— フラグ列は中央寄せ | Boolean に TrueText: "○" / FalseText: "—" を付ける |
| 検索条件は既定で開く | SearchLayouts[""].Layout.IsExpanderDefaultOpened: true(CLB の一般則 LayoutGuidelines.md とは逆の選択)。検索欄を持つレイアウトだけ——空の検索レイアウトを開くと空箱が出る(2026-08-30 に 9 モジュールへ適用) |
| 帳簿を並べ替えさせない | 列の CanUserSort: false。PageFrame 側でも切る(両方書く) |
必須の欄に赤い * |
詳細レイアウトのラベル側の要素に "ClassName": "required-label"(app.css の ::after が印を出す)+ フォームの先頭行に RequiredLegendLabel。ラベルが RelativeField でその欄を指しているときは、CLB が自分で * を足すのでクラスを付けない(付けると * が 2 つ並ぶ。qa/01 F-32。認証部品の AppUser がこの形)。一覧・明細表の見出しには付けられない——ListElement.ClassName は <td> にしか付かない(qa/01 D-16)ので、見出しの文字列そのものに * を入れる(「勘定科目 *」。したがって明細の印だけ黒い) |
| ボタンの色は 3 値だけ | Variant に 09 §4 の 3 値以外を書かない |
| 押せないボタンを灰色にしない | まだ無い。 押せなくする手段は IsViewOnly か IsVisible: false で、ButtonField に disabled は無い(qa/01 D-01・F-14)。半透明にするなら app.css に opacity: .45(Bootstrap 既定の .65 より薄く)。cursor は効かない——IsViewOnly は pointer-events: none になる |
CLB 固有の寸法・組み方(09 には無い。ここだけが持つ)
- 検索レイアウトの行は
IsWrap: trueを標準にする。1 行は 3 組(ラベル+入力)まで - 「ラベル列 + 入力列」の 2 カラム行では、ラベル列に
VerticalAlignment: "Middle"を必ず設定 - ラベル列の幅は「最長ラベルの文字数 × 18px + 40px」を目安に、フォーム内で揃える(下限 96px)
- 参照フィールドの幅: 詳細レイアウトで取引先を入れるカラムは 440px (既定幅では収まらない。幅は行ではなく列に効くので、その行の合計を他の行と揃える。「作業中に得た知見」の 2026-08-26)。 いま適用してあるのは取引先の詳細だけで、一覧や仕訳明細には幅を付けていない
正典は ../docs/04_会計ドメイン設計.md。ここには CLB 実装に直接効くものだけを再掲する。
- 計上済み(posted)の仕訳は変更・削除しない。 訂正・取消は反対仕訳で行う
(
../docs/decisions/0004-優良な電子帳簿への準拠と仕訳の不変性.md) - 金額は整数円。貸借が一致しない伝票は計上できない
- 締め済み期間への計上・訂正はできない
- 損益科目の仕訳行には部門が必須(貸借科目の行は任意)
- 税率・控除割合・閾値はマスタ参照。ハードコード禁止
- 会計ロジックは CLB スクリプトに書かない。
AccountingCore(C#)に置く (../docs/decisions/0008-CLBとCSharpライブラリの責務分担.md)
pwsh -NoProfile -File tools/clb/deploy.ps1Designer/Design 一式を zip 化して LocalData/designs/App.zip に配置する。
FileWatcher が検知して hot-reload する(デザイナ GUI「送信」の代替)。
- zip 仕様: エントリ名はバックスラッシュ区切り・ディレクトリエントリ無し・
app.clprjはルート直下・designer.settings*.jsonは含めない *.mod.cs(スクリプト)変更・DB スキーマ変更はサーバ再起動が必要- サーバ起動:
dotnet run --project BusinessApp/BusinessApp.Server --launch-profile http
CLB 全般の「静かな失敗」は ../docs/qa/01_CLB静かな失敗.md に集約してある。
ここにはこのプロジェクト固有の実測だけを書く。
-
2026-08-23: 初期状態は
EmptyAuthテンプレート(AppUser+Homeの 2 モジュール)。 -
2026-08-24:
sqlCLI は--outを省くと結果 JSON が標準出力に来る。PowerShell から呼ぶときはProcessStartInfo.ArgumentListに 1 引数ずつ足してRedirectStandardOutputで受ける。Start-Process -ArgumentListだと--query内の'...'が壊れてincomplete inputになる。 この形なら SQL ファイルも結果ファイルも作らずに済む(CLAUDE.md §3-2-2)。 -
2026-08-24: デザイナ exe は WinExe なので、PowerShell の
&で呼ぶと待たずに戻る。 終了コードを見るにはStart-Process -Wait -PassThruかProcess.WaitForExit()を使う。 -
2026-08-24: デザイン enum は複数形で名づける(
TaxationTypes/RateKinds)。enum 名は モジュール・PageFrame と同じ型名空間に入るため、単数形だと同名のフィールドと衝突し、designcheckに「スクリプトではフィールド名が優先されます」と指摘される。 -
2026-08-24: 予約名フィールドは規定のデザイン型で作る。
OptimisticLockingはOptimisticLockingFieldDesign+IncrementVersion: true(SQLite)。型が違うと designcheck 緑・HTTP 200 のまま更新だけが失敗する(qa/01 F-09)。creator/updater列は型が未決なので、当面モジュールに持たせない (優良な電子帳簿のチェックシート対応表を書くときに、記録事項の棚卸しと一緒に決める。qa/02 R5-08)。 -
2026-08-24: マスタは物理削除させない(
CanDelete: false。「削除ではなく無効化」——docs/08_マスタ台帳)。 一覧の削除ボタンは PageFrame のLink.ListPageDesign.ListFieldDesign.CanDeleteでも切る。 -
2026-08-24: 一覧の既定の並び順は PageFrame の
Link...SearchCondition.SortConditionsで指定する。 指定しないと降順で出る(マスタでは使いものにならない)。 -
2026-08-24: ヘッダ+明細(仕訳伝票と明細)の正典(
Docs/AppPatterns/header_detail.md): 明細表はListField(DetailListFieldではない。名前に反するので最頻出の誤り)。 子の親 FK はIdFieldDesign+IsManualInput: false(NumberFieldは不可)。 親の詳細レイアウトにListFieldを置き、SearchCondition.ConditionにFieldMatchCondition→FieldVariableMatchCondition(SearchTargetVariable= 子の FK、Variable= 親のId.Value)を入れて逆引きする。列定義は子モジュールのListLayouts[""].Elements。 親の Submit で子の Add/Update/Delete が 1 トランザクションにまとまる。 親詳細のLimitCountは全件(0にすると明細が消える)。 -
2026-08-24: LinkField の候補ダイアログは、一覧画面とは別に絞り込みと並び順を持つ。 フィールド側の
SearchConditionにSortConditionsとConditionを設定する。 マスタを指す LinkField はIsActive.Value = trueで絞る(is_activeは「入力候補に出すか」の意味。docs/08_マスタ台帳)。 設定しないと無効にした科目が候補に出てしまい、降順で並ぶ。designcheckは findings 0。DB にtemporary_filesは未作成(「接続先 DB / データソース」も参照)。2026-08-30 追記——本則は「入力の欄」にだけ掛かる。 同日の朝の時点では 振替伝票の伝票と明細の 6 本が絞られておらず、上に書いた症状がそのまま起きていた。 フェーズ 2.5 の B で全部に当てた(並び順も付けた)。絞らない側は 2 種類ある。
絞らないもの 理由 検索の欄(帳簿も、振替伝票・登録番号の一覧も。会計年度・科目・補助科目・部門・取引先) 無効にしたマスタで過去を引けなくなる(qa/01 X-05)。検索は「これから入力するもの」ではない。並び順は付ける——無指定だと降順で、勘定科目 105 件が逆順に並ぶ(2026-08-31 に付けた)。2026-08-31 に「帳簿の」を外した——振替伝票・登録番号の一覧は帳簿ではない(ADR-0027)が、検索の欄である点は同じで、狭い書き方だと新しい一覧がどの行にも当たらなくなる 取引先の「名寄せの親」 名寄せは「同一人格の表明」であって入力候補ではなく、無効にした取引先を親にする場面が正常に起こる(ADR-0028) 登録番号の取引先を選ぶ欄は 2026-08-31 に消えた——入力を取引先の詳細へ移し、 親 FK を
IdFieldDesignにしたので、絞る対象そのものが無くなった(docs/07 §3-4)。 「例外は名寄せの親だけ」と書いていた(2026-08-30)が、帳簿の 8 本が抜けていた (自己レビューで発見。qa/02 R25-25)——破れている本則に但し書きを被せると、 次の人が「他は守られている」と読む。 -
2026-08-26: デザイン JSON は
json.load→json.dumps(indent=2, ensure_ascii=False)で 往復できる(3 つのモジュールで実測。末尾の改行を除いてバイト単位に一致する)。手で JSON を書き換えるより安全。 ただし Python の text mode は Windows で CRLF を書くので、open(path,'wb')で LF のまま書く(.gitattributesが正規化する前にdesigncheckと差分が汚れる)。 末尾の改行だけは往復しない(json.dumpsは付けない。2026-08-30 に 1 ファイル落として気づいた)。 末尾改行の有無はファイルごとに違うので、読んだときの状態を覚えて同じように書き戻す (揃えようとすると、無関係な 1 行が次の差分に混ざる)。 -
2026-08-26: レイアウトの
Widthは行ではなくレイアウト全体に効く。 1 つの列に 幅を付けると、同じ位置にある他の行の入力欄まで一緒に動く(実測。CLB 1.3.20)。 幅を付ける前は自動の列が伸びて登録ボタンが画面の外に出ていたので、 取引先の詳細は 140+300+140+440 = 1020px に行ごとの合計を揃えて収めた。designcheckは緑のままなので、実機で見る。 -
2026-08-30:
IsRequired: trueは「利用者が埋める必須欄」の意味に限る。 画面が自動で入れてIsViewOnlyにしてある欄(伝票のStatus・明細のLineNo・FiscalYear)には立てない。 立てると CLB の「必須項目です」が、利用者に直しようのない欄について先に鳴り、 サーバ側の整った文言に永久に到達しない(FiscalYearで実際に起きた。qa/02 R24-25)。 DB のNOT NULLと関門は別に守っているので、外しても穴は開かない。 この 1 意味に揃えてあるから、lint_design.pyが「必須欄のラベルに印があるか」を素直に検査できる。 -
2026-08-30:
PageFrameのLink.Titleに/を書くとサイドバーが階層になる (_specs/PageFrame.md。多階層も可)。1 件しかない群を作らない—— 階層にすると 1 クリック増えるだけなので、振替伝票と他フレームへのリンクは最上位のままにした。 -
2026-08-30: 1 行しか持たないモジュールは、
LinkのModulePageType: "Detail"+Id: "1"で 一覧を挟まずに開く(自社情報。CHECK (id = 1)が 1 行を保証する。ADR-0005)。 -
2026-08-30:
LinkFieldの候補は、選んだ勘定科目で補助科目を絞れていない(未解決)。 明細行の中で兄弟のフィールド(同じ行のAccount)を参照する条件になるので、FieldVariableMatchConditionのVariableに何を書けば行の中を指せるかが分かっていない。 判断は 05 のフェーズ 2.5 の B が持つ。