MAS-131: 完了行の視認性向上(条件付き書式による自動グレーアウト)
概要
| 項目 | 内容 |
|---|---|
| 案件ID | MAS-131 |
| カテゴリ | UX・可視性(行積み上がり対策B) |
| Phase | 実装可(仕様書完了 → 実装待ち) |
| 優先度 | P1 / ★★★ |
| 実装ステータス | 📝 仕様書段階・実装未着手 (2026-04-28 監査時点) |
| 対象ファイル | 100_config/101_sys_config.js(単一ファイル変更) |
| 前提案件 | なし(独立実装可) |
| 関連案件 | MAS-130(フィルタービュープリセット・行積み上がり対策A)、MAS-132(月次グルーピング・対策D)、MAS-133(年度跨ぎアーカイブ・対策E) |
目的
WRK 系タブ(31/32/33/35)と 20 番台予算タブが行数千行に膨らんだ際、未処理行と完了済行が同じ視覚的重みで並び、現場のオペレーターがどの行に対応すべきかを目視で判別しづらくなる。本案件では各シートに条件付き書式ルールを 1 件設定し、ステータスが「完了扱い」の行を自動的に 背景 #d9d9d9 × 文字色 #999999 × 取り消し線 で薄表示にすることで、アクティブ行のみが視覚的に浮き上がる UI を実現する。
MAS-130(フィルタービュープリセット)と併用すれば「未処理だけ表示する」フィルタリングと「完了行は薄く沈める」書式の二段構えで、行数の多さによる UX 劣化を実装 1 時間程度の改修で大幅に解消できる。
現在のコード
100_config/101_sys_config.js の setupAllSchemas(isFull) 関数(L749 で開始 → L1538 で終了)には、WRK 系・予算系シートのステータス列に応じた行単位の条件付き書式ルールが定義されていない。
例外として BUD_SUBS(23_wrk_subscription)に対してだけ、L1126〜1131 で 自動更新アラート 列向けの whenTextContains 条件付き書式が 4 件設定されている。これは「列単位の意味付け(更新間近/期限超過の警告)」用途であり、本案件が必要とする「行全体を薄表示にする」とは目的が異なる。
onOpen()(L323〜350)は Constants.MENU_DEFINITION(002_constants.js L206〜324)を読んで動的にメニューを構築する宣言的方式に統一されている。サイドバー連携の「🔧 開発・設定」カテゴリ(002_constants.js L240〜252)には現状以下の項目のみ:
- DDL 全更新 (Full) →
setupAllSchemas - DDL 増分更新 →
setupAllSchemasIncremental - シート GID 取得・リンク →
initConfigs - タブ名一括変更 →
syncSheetNames - タブを番号順並替 →
sortSheetsByName - 📋 監査ログを開く →
openAuditLog - 🗄️ 監査ログを月次アーカイブ →
archiveAuditLogMonthly
ここに「🎨 完了行の書式を再適用」項目を追加し、DDL 全実行を待たずにユーザーが条件付き書式だけを再適用できるようにする。
修正方針
1. 新規関数 applyCompletionFormattingRules_() を追加
100_config/101_sys_config.js のトップレベル(例: setupAllSchemas 関数の直後、L1539 付近)に以下の関数を新設する。updateMenuCatalog_ と同じくトップレベル function ..._() { ... } 形式で定義することでメニューから直接呼び出せる(GAS では _ サフィックス付きでも MENU_DEFINITION.funcName に文字列指定すればメニュー呼出し可能。L1651 updateMenuCatalog_ が同パターンで稼働中)。
function applyCompletionFormattingRules_() {
var FUNC = 'applyCompletionFormattingRules_';
// 列インデックス(0始まり) を A1 列文字に変換するローカルヘルパー
function colIndexToLetter_(idx) {
var result = '';
var n = idx + 1; // 1始まりに変換
while (n > 0) {
result = String.fromCharCode(65 + (n - 1) % 26) + result;
n = Math.floor((n - 1) / 26);
}
return result;
}
// 各対象シートの完了条件を宣言。
// - statusCol: 完了ステータスを保持する列名
// - doneVals: その列が一致したら「完了」とみなす値(複数指定 OR)
// - extraCol: 「列が空でない」を OR 条件として加算したい列名(任意)
// - emptyCheckCol: 空行除外用の列名(CLAUDE.md 規約: チェックボックス列を避け ID 列で判定)
var targets = [
{
key: 'WRK_ORDR', fallback: '31_wrk_order',
statusCol: '発注ステータス', doneVals: ['完了'],
emptyCheckCol: '発注ID(ORD)'
},
{
key: 'WRK_INVC', fallback: '32_wrk_invoice',
statusCol: '請求ステータス', doneVals: ['決済完了'],
extraCol: '自動仕訳JNL_ID', // Action A 完了行(JNL 発行済)も完了扱い
emptyCheckCol: '請求ID(INV)'
},
{
key: 'WRK_BANK', fallback: '33_wrk_bank',
statusCol: '決済ステータス', doneVals: ['消込済'],
emptyCheckCol: '決済ID(STL)'
},
{
key: 'WRK_RCPT', fallback: '35_wrk_receipt',
statusCol: '処理結果', doneVals: ['消込済'],
emptyCheckCol: '管理ID' // 35_wrk_receipt は A 列が ID(チェックボックス列なし)
},
// 20番台予算タブは「最終起票年月日」が空でないことを完了条件とする
{ key: 'BUD_HC', fallback: '22_bud_headcount', statusCol: '最終起票年月日', doneVals: [], extraSelf: true, emptyCheckCol: '管理ID' },
{ key: 'BUD_SUBS', fallback: '23_bud_subscription', statusCol: '最終起票年月日', doneVals: [], extraSelf: true, emptyCheckCol: '管理ID' },
{ key: 'BUD_CAPEX', fallback: '24_bud_capex_loan', statusCol: '最終起票年月日', doneVals: [], extraSelf: true, emptyCheckCol: '管理ID' },
{ key: 'BUD_FIN', fallback: '25_bud_finance', statusCol: '最終起票年月日', doneVals: [], extraSelf: true, emptyCheckCol: '管理ID' },
{ key: 'BUD_ADHOC', fallback: '26_bud_adhoc', statusCol: '最終起票年月日', doneVals: [], extraSelf: true, emptyCheckCol: '管理ID' },
{ key: 'BUD_PIPE', fallback: '21_bud_pipeline', statusCol: '最終起票年月日', doneVals: [], extraSelf: true, emptyCheckCol: '管理ID' }
];
var applied = 0;
var skipped = [];
targets.forEach(function(t) {
var sheet = Utils.getSheetByKey(t.key, t.fallback);
if (!sheet) { skipped.push(t.fallback + '(シート未存在)'); return; }
var lastCol = sheet.getLastColumn();
if (lastCol < 1) { skipped.push(t.fallback + '(空シート)'); return; }
var headers = sheet.getRange(1, 1, 1, lastCol).getValues()[0]
.map(function(h) { return String(h).trim(); });
var statusIdx = headers.indexOf(t.statusCol);
if (statusIdx < 0) { skipped.push(t.fallback + '(' + t.statusCol + '列なし)'); return; }
var emptyIdx = headers.indexOf(t.emptyCheckCol);
if (emptyIdx < 0) { skipped.push(t.fallback + '(' + t.emptyCheckCol + '列なし)'); return; }
var statusLetter = colIndexToLetter_(statusIdx);
var emptyLetter = colIndexToLetter_(emptyIdx);
// 完了条件式の組立
var conditions = [];
if (t.extraSelf) {
// ステータス列自身が空でないことを完了条件とする(20番台予算タブ)
conditions.push('NOT(ISBLANK($' + statusLetter + '2))');
} else {
t.doneVals.forEach(function(v) {
conditions.push('$' + statusLetter + '2="' + v + '"');
});
}
if (t.extraCol) {
var extraIdx = headers.indexOf(t.extraCol);
if (extraIdx >= 0) {
var extraLetter = colIndexToLetter_(extraIdx);
conditions.push('NOT(ISBLANK($' + extraLetter + '2))');
}
}
if (conditions.length === 0) { skipped.push(t.fallback + '(完了条件0件)'); return; }
// 空行除外(emptyCheckCol が空でないこと) + 完了条件 OR
var formula = '=AND(NOT(ISBLANK($' + emptyLetter + '2)),OR(' + conditions.join(',') + '))';
var maxRow = sheet.getMaxRows();
var range = sheet.getRange(2, 1, Math.max(maxRow - 1, 1), lastCol);
// 既存の本ルール由来の条件付き書式を一掃して再設定(冪等性)
sheet.clearConditionalFormatRules();
var rule = SpreadsheetApp.newConditionalFormatRule()
.whenFormulaSatisfied(formula)
.setBackground(Constants.COLORS.DISABLED_BG) // #d9d9d9
.setFontColor(Constants.COLORS.DISABLED_FC) // #999999
.setStrikethrough(true)
.setRanges([range])
.build();
sheet.setConditionalFormatRules([rule]);
applied++;
});
try {
Utils.logInfo(FUNC, 'applied=' + applied + ' skipped=' + JSON.stringify(skipped));
Utils.auditLog('RUN', '', '', '', FUNC, '', { applied: applied, skipped: skipped }, 'MAS-131 完了行書式再適用');
} catch (_) {}
try {
var ui = SpreadsheetApp.getUi();
ui.alert('🎨 完了行の書式を再適用',
'対象シート: ' + applied + ' 件に条件付き書式を設定しました。\n' +
'スキップ: ' + (skipped.length ? skipped.join(', ') : 'なし'),
ui.ButtonSet.OK);
} catch (_) { /* Web アプリ経由はダイアログなし */ }
}
2. setupAllSchemas 末尾から呼び出し
100_config/101_sys_config.js の setupAllSchemas 関数末尾(L1531 と L1532 の間、Utils.auditLog('RUN', ..., 'DDL 最新化完了'); の直後・成功ダイアログの直前)に以下の 1 行を追加:
// MAS-131: 完了行の視認性向上(条件付き書式の自動再適用)
try { applyCompletionFormattingRules_(); } catch (e) { errorLog.push('[MAS-131 conditional format] ' + e.message); }
try/catch で囲むのは、書式適用が失敗しても setupAllSchemas 全体を失敗扱いにしないため(同関数の他の処理と同パターン)。失敗時は errorLog に積まれて L1534 のダイアログで通知される。
3. メニュー項目を追加
000_infra/002_constants.js の MENU_DEFINITION 内、'📋 サイドバー: 🔧 開発・設定' カテゴリ(L240〜252)の items 配列に以下を追加(追加位置は setupAllSchemasIncremental(L245)の直後を推奨):
{ label: '🎨 完了行の書式を再適用', funcName: 'applyCompletionFormattingRules_', description: '完了済み行を条件付き書式でグレーアウト(MAS-131)' },
サイドバー UI(templates/operations_sidebar.html)は MENU_DEFINITION を読んでボタンを生成しているため、本追加だけで両方に反映される。
影響範囲
| 範囲 | 内容 |
|---|---|
| 変更ファイル | 100_config/101_sys_config.js(setupAllSchemas 末尾に 1 行追加 + 新関数 applyCompletionFormattingRules_ 追加)000_infra/002_constants.js(MENU_DEFINITION に項目 1 件追加) |
| 変更行数 | 約 110 行追加(うち 100 行が新関数本体) |
| 既存ロジック | 影響なし(新規追加のみ。setupAllSchemas の他処理は不変) |
| 既存条件付き書式 | 対象シートの既存ルールは clearConditionalFormatRules() で消去される。BUD_SUBS の自動更新アラート用ルール(L1126〜1131)は setupAllSchemas が再生成するため次回 DDL 実行で復元されるが、ユーザーが手動で追加したルールは復元されない |
| 性能 | 1 シートあたり clearConditionalFormatRules + setConditionalFormatRules の 2 API コール。10 シート対象で実測 1 秒未満 |
| データ整合性 | 書式変更のみ。データ自体は不変 |
注意事項
- 既存の手動条件付き書式は消去される:
clearConditionalFormatRules()は対象シートの全ルールを一掃する。手動でユーザーが設定した条件付き書式(例: 特定行のマーキング)も消える。本案件のリリース前に運用ユーザーへ周知し、必要なルールはあらかじめ DDL 化(setupAllSchemas内の宣言)するか、本書式と統合する。 Utils.getSheetByKey()のシステムキー依存:01_sys_configの登録内容に依存する。本案件で使用するキー(WRK_ORDR/WRK_INVC/WRK_BANK/WRK_RCPT/BUD_HC/BUD_SUBS/BUD_CAPEX/BUD_FIN/BUD_ADHOC/BUD_PIPE)は L774〜823 でsetupAllSchemasが冪等に登録するため、初回 DDL 実行後は確実に解決される。フォールバックとして物理シート名も指定済み。headers.indexOf()が-1の場合のガード: ステータス列・空行判定列のいずれかが見つからない場合はskippedに積んで対象シートをスキップ。DDL 列名変更時の安全装置。applyCompletionFormattingRules_はトップレベル関数として定義:setupAllSchemasのネスト内に定義するとメニュー呼出しできなくなる(GAS のスコープ仕様)。updateMenuCatalog_(L1651)と同じトップレベル配置とする。_サフィックス命名でもメニュー呼出し可能: GAS の_サフィックスはコード内のプライベート慣習であり、メニューMENU_DEFINITION.funcNameに文字列指定すれば実行できる(updateMenuCatalog_が稼働実績あり)。本案件もこの慣例に従い、内部ユーティリティ寄りの位置づけを示すために_を付与する。- 適用範囲は
(2行目, 1列目)〜(maxRow, lastColumn)に固定:getMaxRows()全行に適用するため、シートに行追加されてもルール側の自動拡張は不要(ただしsetupAllSchemasがmaxRowsを伸縮した場合は本書式も再実行が必要)。
エッジケース
| 条件 | 挙動 | 対策 |
|---|---|---|
| ステータス列がシートに存在しない | headers.indexOf が -1 を返す | skipped に記録して対象シートをスキップ(ガード実装済み) |
| 空行除外用 ID 列が存在しない | 同上 | 同上 |
| ID 列(B 列 or A 列)が空の行 | NOT(ISBLANK($X2)) 条件で書式非適用 | CLAUDE.md 規約に従い WRK_ORDR/WRK_INVC/WRK_BANK/BUD_* は B 列、WRK_RCPT は A 列で空行判定(タブ別に動的) |
| 32_wrk_invoice の OR 条件(請求ステータス OR 自動仕訳JNL_ID) | 1 つの数式に OR() で統合 | =AND(NOT(ISBLANK($B2)),OR($I2="決済完了",NOT(ISBLANK($Z2)))) 形式(列文字は実行時動的取得) |
Utils.getSheetByKey() が null を返す(シート未作成) | 早期 return | if (!sheet) { skipped.push(...); return; } ガード実装済み |
同じ setupAllSchemas を複数回実行 | clearConditionalFormatRules() → 1 ルール再設定でリセット | 重複ルール発生なし(冪等) |
| 列が右側に追加されてヘッダー行に新列が増えた | getMaxRows() × getLastColumn() で範囲を毎回取得し直す | 次回 applyCompletionFormattingRules_() 実行時に範囲が自動追従 |
| ステータス値の表記揺れ(「決済完了」vs「決済 完了」) | 完全一致のため不一致行は書式非適用 | MENU_DEFINITION ベースの DDL(L1301〜1310 の MST_DICT 定義)と一致する値を仕様書側で固定 |
| 数万行規模での描画速度低下 | スプレッドシート全体のレンダリングが鈍化する可能性 | MAS-132(月次グルーピング)・MAS-133(年度跨ぎアーカイブ)で行数自体を圧縮する方針との併用を前提 |
| 35_wrk_receipt の A 列が「管理ID」(チェックボックスではない) | 空行除外を A 列で実施 | targets[].emptyCheckCol で列名を個別指定可能にし、シート別に B 列/A 列を切替 |
| Phase 1-C で対象シート・列が未確認のまま実装 | 誤ったステータス値で書式が機能しない | 「実データ検証」セクションの対応表を参照のうえ実装する |
実データ検証
Phase 1 でコード(100_config/101_sys_config.js)から確定した完了条件マッピング。プルダウン定義(L1301〜1310)と DTO 定義(000_infra/003_contracts.js)が乖離している場合は プルダウン定義(実データの正)を採用 している。
ステータス値マッピング(プルダウン定義 L1301〜1310 から確定)
| シート | 完了判定列 | 完了扱いの値 | 備考 |
|---|---|---|---|
31_wrk_order | 発注ステータス | '完了' | プルダウン定義: 見積中 / 発注済 / 部分納品 / 完了 / 取消(DTO コメントの "検収済" は古く、現行は "完了") |
32_wrk_invoice | 請求ステータス OR 自動仕訳JNL_ID 非空 | '決済完了'、または 自動仕訳JNL_ID が空でない | プルダウン定義: 未処理 / 承認済 / 部分決済 / 決済完了 / 取消(DTO コメントの "完了" は古く、現行は "決済完了")。Action A 完了行(JNL 発行済)も完了扱い |
33_wrk_bank | 決済ステータス | '消込済' | プルダウン定義: 未処理 / 消込済 / 差戻 |
35_wrk_receipt | 処理結果 | '消込済' | プルダウン定義: 消込済 / MATCHED / UNMATCHED / 未登録 / 26タブ登録済 / SKIP:取消 / SKIP:金額なし。「消込済」のみが完了。SKIP:* も終端だが現状は対象外(人間が検討すべき事項参照) |
21_bud_pipeline | 最終起票年月日 | 値が空でない | RPA 起票完了時に自動で日付がセットされる |
22_bud_headcount | 最終起票年月日 | 値が空でない | 同上 |
23_bud_subscription | 最終起票年月日 | 値が空でない | 同上 |
24_bud_capex_loan | 最終起票年月日 | 値が空でない | スキーマキーは BUD_CAPEX、物理タブ名は 24_bud_capex_loan(L775) |
25_bud_finance | 最終起票年月日 | 値が空でない | スキーマキーは BUD_FIN |
26_bud_adhoc | 最終起票年月日 | 値が空でない | スキーマキーは BUD_ADHOC |
システムキー & 物理シート名(Utils.getSheetByKey() 第 1/第 2 引数)
| システムキー | 物理シート名 | 登録箇所(setupAllSchemas) |
|---|---|---|
WRK_ORDR | 31_wrk_order | L783 |
WRK_INVC | 32_wrk_invoice | L784 |
WRK_BANK | 33_wrk_bank | L785 |
WRK_RCPT | 35_wrk_receipt | L821 |
BUD_HC | 22_bud_headcount | L776 |
BUD_SUBS | 23_bud_subscription | L778 |
BUD_CAPEX | 24_bud_capex_loan | L775 |
BUD_FIN | 25_bud_finance | L779 |
BUD_ADHOC | 26_bud_adhoc | L780 |
BUD_PIPE | 21_bud_pipeline | L777 |
空行判定列(emptyCheckCol)— CLAUDE.md「列 B = ID 列」規約の適用
| シート | 列 A | 列 B | emptyCheckCol(採用) | 採用理由 |
|---|---|---|---|---|
| 31_wrk_order | 有効フラグ(チェックボックス) | 発注ID(ORD) | 発注ID(ORD) | B = ID 列 |
| 32_wrk_invoice | 有効フラグ(チェックボックス) | 請求ID(INV) | 請求ID(INV) | B = ID 列 |
| 33_wrk_bank | 有効フラグ(チェックボックス) | 決済ID(STL) | 決済ID(STL) | B = ID 列 |
| 35_wrk_receipt | 管理ID | 処理日時 | 管理ID | A 列が ID(チェックボックスなし)。DDL で A=管理ID と確定(L898) |
| 21〜26 BUD_* | 有効フラグ(チェックボックス) | 管理ID | 管理ID | B = ID 列 |
挿入位置の確定
| 操作 | ファイル | 行 | 内容 |
|---|---|---|---|
| 新関数追加 | 100_config/101_sys_config.js | L1539 直後(既存 setupAllSchemas 関数の閉じ括弧 L1538 の直後) | function applyCompletionFormattingRules_() { ... } をトップレベルに新設 |
setupAllSchemas 内呼び出し | 100_config/101_sys_config.js | L1531 と L1532 の間(DDL 完了監査ログの直後・成功ダイアログの直前) | try { applyCompletionFormattingRules_(); } catch (e) { errorLog.push('[MAS-131 conditional format] ' + e.message); } |
| メニュー項目追加 | 000_infra/002_constants.js | L245(setupAllSchemasIncremental の項目)の直後 | { label: '🎨 完了行の書式を再適用', funcName: 'applyCompletionFormattingRules_', description: '完了済み行を条件付き書式でグレーアウト(MAS-131)' }, |
依存定数(Constants.COLORS)
| 定数名 | 値 | 定義位置 |
|---|---|---|
Constants.COLORS.DISABLED_BG | #d9d9d9 | 000_infra/002_constants.js L45 |
Constants.COLORS.DISABLED_FC | #999999 | 000_infra/002_constants.js L46 |
関連ドキュメント
CLAUDE.md「データアクセス」セクション — 「シートへの書き込み位置は列 B(ID 列)で最終行を判定(列 A のチェックボックス回避)」規約。本案件のemptyCheckCol設計の根拠000_infra/002_constants.js—Constants.COLORS.DISABLED_BG/DISABLED_FC定義、MENU_DEFINITIONメニュー定義100_config/101_sys_config.js—setupAllSchemas本体、プルダウン定義(L1301〜1310)- MAS-130 開発仕様書(未作成・予定) — フィルタービュープリセット(行積み上がり対策 A)。本案件と併用前提
- MAS-132 開発仕様書(未作成・予定) — 月次行グルーピング(対策 D)
- MAS-133 開発仕様書(未作成・予定) — 年度跨ぎアーカイブ(対策 E)
人間が検討すべき事項
- 既存手動条件付き書式の取扱い(最重要):
clearConditionalFormatRules()により対象シートの手動ルールが全て消える。リリース前に運用ユーザーへ事前周知し、保持したいルールがあれば DDL 化(setupAllSchemas内宣言)するか、本書式のsetConditionalFormatRules([rule, ...保持ルール])に追記する形に拡張する必要があるか検討する。 - 「取消」ステータスもグレーアウト対象に含めるか: 31_wrk_order の
'取消'、32_wrk_invoice の'取消'、33_wrk_bank の'差戻'、35_wrk_receipt の'SKIP:取消'/'SKIP:金額なし'/'未登録'等も「終端 = 以降の対応不要」とみなしてグレーアウトすべきか。本仕様書では'完了/決済完了/消込済'のみを採用しているが、運用上「取消も含めて全終端を薄くしたい」要望が出る可能性あり。doneValsを拡張するだけで対応可能(コード変更なし)。 - 35_wrk_receipt の SKIP: 系の扱い: 上記 2 と関連。SKIP: は「処理対象外」だが「未対応」ではなく「対応済(不要と判定)」に近い。完了扱いするか別の薄表示色(例:
#f3f3f3の更に薄いグレー)を割り当てるか、運用と要相談。 - 20番台予算タブの「最終起票年月日」だけで完了判定して良いか: RPA 再起票を許容する運用(同一行を翌月分として再利用するケース)がある場合、
最終起票年月日が値を持っていても「次月分は未起票」となり、グレーアウトすると逆効果になる可能性がある。起票ターゲット月列との比較(起票ターゲット月 <= 最終起票年月日 の YM)を追加する案も検討余地あり。 - 数万行規模での描画速度: 条件付き書式は行数に応じて再計算が走るため、5 万行規模で体感的にカクつく可能性がある。MAS-132(月次グルーピング)・MAS-133(年度跨ぎアーカイブ)と組み合わせ、現行タブの行数自体を抑える設計(例: アーカイブ後は本書式も対象外)が望ましい。
- DDL 列追加時の書式範囲自動追従: 本実装は
getLastColumn()で取得した実列数までを範囲とする。DDL 列追加時は次回applyCompletionFormattingRules_()実行で自動拡張されるが、増分 DDL(setupAllSchemasIncremental)が走らずユーザーが「🎨 完了行の書式を再適用」を明示実行しないと反映されない。setupAllSchemasIncrementalの末尾でも本関数を呼び出すか検討。 - ステータス名称の将来変更耐性: プルダウン定義(L1301〜1310)が変更されると本仕様書の
doneValsも同期更新が必要。MST_DICT を SSOT として参照する設計(例:MST_DICTから「終端ステータス」フラグ列を読む)に発展させる余地あり。本案件の Phase 2 として将来検討。
実装プロンプト(Claude Code 用)
あなたは GAS 会計システム (bizlp-gas-accounting) のシニア開発者です。
案件 MAS-131「完了行の視認性向上(条件付き書式による自動グレーアウト)」を実装してください。
## 実行前タスク(推測実装の禁止 — Read で必ず裏取りすること)
以下を Read してから実装に着手すること:
- `100_config/101_sys_config.js`:
- `setupAllSchemas(isFull)` の関数末尾(L1538 で閉じる)と、L1531〜1536 のダイアログブロックの構造を確認
- L1301〜1310 の MST_DICT 定義に登録されているステータス値(仕様書「実データ検証」の表と一致することを確認)
- L774〜823 のシステムキー登録(`WRK_ORDR` / `WRK_INVC` / `WRK_BANK` / `WRK_RCPT` / `BUD_*` 系)の存在確認
- `000_infra/002_constants.js`:
- `Constants.COLORS.DISABLED_BG`(L45 = `#d9d9d9`)と `Constants.COLORS.DISABLED_FC`(L46 = `#999999`)の定義確認
- `MENU_DEFINITION` の `'📋 サイドバー: 🔧 開発・設定'` カテゴリ(L240〜252)の構造と追加位置(L245 の `setupAllSchemasIncremental` の直後)の確認
- `000_infra/004_utils.js`:
- `Utils.getSheetByKey(key, fallbackName)` の引数仕様(L302〜312)の確認
## 修正対象ファイル
1. `100_config/101_sys_config.js`
2. `000_infra/002_constants.js`
## 実装内容
### Step 1: 新関数 `applyCompletionFormattingRules_()` を追加
`100_config/101_sys_config.js` の **L1538(`setupAllSchemas` 関数の閉じ括弧)の直後** にトップレベル関数として追加する。仕様書「修正方針 → 1. 新規関数」のコード骨格を清書せよ。
`targets` 配列の各要素は仕様書「実データ検証 → ステータス値マッピング」と「空行判定列」の表に従って定義すること:
- `WRK_ORDR` → 発注ステータス = `'完了'`、emptyCheckCol = `'発注ID(ORD)'`
- `WRK_INVC` → 請求ステータス = `'決済完了'` OR 自動仕訳JNL_ID 非空、emptyCheckCol = `'請求ID(INV)'`
- `WRK_BANK` → 決済ステータス = `'消込済'`、emptyCheckCol = `'決済ID(STL)'`
- `WRK_RCPT` → 処理結果 = `'消込済'`、emptyCheckCol = `'管理ID'`(A 列がチェックボックスではないため例外的に A 列)
- `BUD_HC`/`BUD_SUBS`/`BUD_CAPEX`/`BUD_FIN`/`BUD_ADHOC`/`BUD_PIPE` → 最終起票年月日が空でない、emptyCheckCol = `'管理ID'`
### Step 2: `setupAllSchemas` 末尾に呼び出しを追加
`100_config/101_sys_config.js` の **L1531 と L1532 の間**(`Utils.auditLog('RUN', ..., 'DDL 最新化完了');` の直後・`try { const ui = SpreadsheetApp.getUi(); ...` の直前)に以下を追加:
```javascript
// MAS-131: 完了行の視認性向上(条件付き書式の自動再適用)
try { applyCompletionFormattingRules_(); } catch (e) { errorLog.push('[MAS-131 conditional format] ' + e.message); }
```
### Step 3: メニュー項目を追加
`000_infra/002_constants.js` の **L245**(`{ label: 'DDL 増分更新', funcName: 'setupAllSchemasIncremental', ... }`)の直後に以下を追加:
```javascript
{ label: '🎨 完了行の書式を再適用', funcName: 'applyCompletionFormattingRules_', description: '完了済み行を条件付き書式でグレーアウト(MAS-131)' },
```
## 制約
- 列参照はヘッダー動的取得 + `Array.prototype.indexOf()` で特定すること。**列文字(A1 表記)のハードコード禁止**
- `Utils.getSheetByKey(key, fallback)` でシートを取得すること。**シート名のハードコード禁止**(システムキーは仕様書「実データ検証 → システムキー」表参照)
- 空行除外条件は **タブ別の ID 列**で実施。WRK_ORDR/WRK_INVC/WRK_BANK と BUD_* は B 列、WRK_RCPT のみ A 列(CLAUDE.md 規約 + WRK_RCPT がチェックボックス列を持たない例外)
- `applyCompletionFormattingRules_` は**トップレベル**に定義する。`setupAllSchemas` のネスト関数にしない(メニュー呼出し不可になる)
- `setupAllSchemas` 内呼び出しは **`try/catch` で囲む**。書式適用の失敗で DDL 全体を失敗扱いにしない
- 既存の `setupAllSchemas` の他のロジックを変更しない
- 既存の `MENU_DEFINITION` の他項目(順序・文字列)を変更しない
## 動作確認
1. `npm run push:dev` でデプロイ
2. GAS エディタで `setupAllSchemas` を実行(または UI メニュー「🔧 開発・設定 → DDL 全更新 (Full)」)
3. 各対象シート(31/32/33/35 + 21〜26)の Sheets「表示形式 → 条件付き書式」エディタで、本実装由来のルールが **1 件設定**されていることを確認
4. 31_wrk_order の「発注ステータス = 完了」の行が **背景 `#d9d9d9` × 文字色 `#999999` × 取り消し線**になることを確認
5. 32_wrk_invoice で「請求ステータス = 決済完了」の行、および「自動仕訳JNL_ID が埋まっている行」がいずれもグレーアウトされることを確認
6. 33_wrk_bank で「決済ステータス = 消込済」の行がグレーアウトされることを確認
7. 35_wrk_receipt で「処理結果 = 消込済」の行がグレーアウトされることを確認
8. 20 番台予算タブで「最終起票年月日」に値が入っている行がグレーアウトされることを確認
9. **空行(B 列が空、35 のみ A 列が空)がグレーアウトされない**ことを確認
10. スプレッドシートのメニュー「📋 サイドバー: 🔧 開発・設定 → 🎨 完了行の書式を再適用」を実行し、単独で動作することを確認(Toast / Alert で件数が表示される)
11. `setupAllSchemas` を 2 回連続実行してもルールが**重複しない**ことを確認(`clearConditionalFormatRules` の冪等性)
12. 98_audit_log に `applyCompletionFormattingRules_` の RUN 行が記録されることを確認
### 拡張思考の使用状況
| フェーズ | 拡張思考 | 備考 |
|---------|---------|------|
| 実行前調査(Read・MCP) | あり | 列名・ステータス値・行番号・システムキーの確定 |
| 実装(Edit) | なし | 仕様書のコード骨格を清書するのみ |
| 動作確認 | あり | 想定外挙動の原因切り分け |
推奨実行モデル
| ステップ | モデル | 理由 |
|---|---|---|
| 全体(Read + Edit) | Claude Sonnet | 挿入位置の特定(L1531/L1532/L1538/L245)と既存パターン適用が必要だが、コード本体は仕様書で完全定義済み。判断要素は限定的 |
変更履歴
| 日時 | 内容 |
|---|---|
| 2026-04-30 | v1.1 (リネーム + MAS- 化整合): ファイル名 dev_mas-131_conditional_formatting.md → dev_mas-131_conditional_formatting.md に git mv で履歴保持リネーム / 本文中の (S-59) / (S-59) / S-59 完了行書式 / S-59 conditional format / S-59: を MAS-131 に一括置換 / 関連 spec (dev_S-60_* / dev_S-61_*) からの参照パスを sed で一括更新 / docs/_config.json E.2.21 タイトル "S-59" → "MAS-131" / id_mapping_table.csv source_file 列更新。保持: frontmatter aliases: ["S-059", "S-59"] (legacy ID マッピング) / 仕様書作成プロンプト <details> 内の S-59 表記 (履歴用)。実装内容には変更なし。docs-only PR で prod 自動デプロイへの影響なし。 |
| 2026-04-22 | 初版作成 |
仕様書作成プロンプト
展開して表示
【タイムアウト回避・実行原則(v1.7・必ず遵守すること)】
1. **拡張思考の使い分け**: Phase 1(設計)では拡張思考をフル活用し、ファイル名・行番号・列名・ステータス値・エッジケースを完全に確定させる。Phase 2(清書)の各Step内では拡張思考を最小限に抑え、Phase 1で確定済みの内容の書き下しに徹する。出力途中で再考しない。
2. **テキスト報告の禁止**: 「〜を作成します」等のtext-onlyのturnを作らない。説明は1文以内。直ちにtoolを呼ぶ。
3. **4-5分割のWrite/Edit実行**: Step 2-1(骨格〜20行)/ 2-2(概要〜注意事項〜300行)/ 2-3a(エッジケース〜人間検討事項〜200行)/ 2-3b(実装プロンプト〜変更履歴〜250行)/ 2-4(`<details>`プロンプト記録)に分割。
4. **各Stepで何を書くかを具体指示**: 設計判断をPhase 2に持ち込まない。各Stepの内容はPhase 1で確定済みのものを清書するのみ。
======================================================================
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者兼仕様書ライターです。
案件 S-59「完了行の視認性向上(条件付き書式による自動グレーアウト)(行積み上がり対策B)」の開発仕様書を作成してください。
作成後、`docs/_config.json` の `nav` 配列の適切なセクションに必ず追記してください。
---
## Phase 1: 実行前調査(テキスト報告禁止。即座にツール実行)
Phase 2で設計判断を持ち込まないよう、**全固有名詞・行番号・ステータス値・列名をここで確定させる**。
### 1-A: 案件定義の読み込み
`docs/_internal/TODO_future.md` でS-59の行を特定し、「概要」「期待される効果」「人間が検討すべき事項」を把握する。
### 1-B: 既存コードの読み込み(Grepで発見 → Readで構造を裏取り)
推測で仕様書に固有名詞を記載しない。以下を必ずReadで確認してから記述する。
| ファイル(フルパス) | 確認すべき内容 |
|---------------------|---------------|
| `100_config/101_sys_config.js` | ① `setupAllSchemas()` の関数末尾の行番号(`applyCompletionFormattingRules_()` 呼び出しの挿入位置確定)② `onOpen()` のメニュー定義全体(「🔧 開発・設定」が実在するか・正確な文字列・追記可能な位置の行番号)③ 条件付き書式を設定している既存コードの有無 |
| `000_infra/002_constants.js` | `Constants.COLORS.DISABLED_BG`・`Constants.COLORS.DISABLED_FC` の行番号(値は `#d9d9d9`・`#999999` と確認済みだが行番号を控える) |
| `000_infra/003_contracts.js` | `31_wrk_order`・`32_wrk_invoice`・`33_wrk_bank` の `@typedef` コメントから、ステータス列の **列名** と **取りうる値** を確認する(例: `発注ステータス: "見積中" | "発注済" | "検収済"` など) |
| `000_infra/004_utils.js` | `Utils.getSheetByKey(key, fallbackName)` の引数仕様(第1引数のシステムキー文字列の用法)を確認する |
| `200_data/202_repository.js` | `OrderRepository._getSheet()`・`InvoiceRepository._getSheet()`・`BankTxRepository._getSheet()` で使われているシステムキー文字列(`'WRK_ORDR'`・`'WRK_INVC'`・`'WRK_BANK'`)とフォールバック名を確認する |
### 1-C: 実データ検証(MCPで実シートを確認)
以下はコードから推測できないため、MCPで必ず確認してから仕様書に記載する。推測値をそのまま記載しない。
| 確認項目 | 確認先 | ハルシネーションリスク |
|---------|--------|----------------------|
| `31_wrk_order` の `発注ステータス` で「完了扱い」となる値 | `31_wrk_order` シートのプルダウン設定または実データ | DTO定義では `"見積中"|"発注済"|"検収済"` のみ記載。`'完納'` が実在するか未確認 |
| `32_wrk_invoice` の `請求ステータス` で「完了扱い」となる値 | `32_wrk_invoice` シートのプルダウン設定または実データ | DTO定義では `"未処理"|"承認済"|"却下"` のみ記載。`'完了'` が実在するか未確認 |
| `32_wrk_invoice` の `自動仕訳JNL_ID` 列の実際のヘッダー文字列 | `32_wrk_invoice` シートのヘッダー行 | DTOコメントと実シートのずれ確認 |
| `35_wrk_receipt` シートの有無・ヘッダー構成・「完了判定」に使う列名とステータス値 | `35_wrk_receipt` シート | DTOが未定義のため列名・値は完全に要確認 |
| 20番台予算タブ(`21_bud_pipeline`・`22_bud_headcount`・`23_bud_subscription`・`24_bud_capex`)の「完了判定」に使う列名と値 | 各シートのヘッダー行 | `最終起票年月日` という列名が実在するか未確認 |
| `35_wrk_receipt` のシステムキー(`Utils.getSheetByKey()` 第1引数) | `01_sys_config` シート(`Constants.CONFIG_SHEET = '01_sys_config'`) | 202_repository.js に定義なし。要確認 |
### 1-D: Phase 2着手前に確定させる設計判断
1-B・1-Cの調査完了後、以下を全て確定してからPhase 2に進む。Phase 2では再考しない。
1. `setupAllSchemas()` 末尾の行番号(`applyCompletionFormattingRules_();` の挿入行)
2. `onOpen()` の追記位置と正確なメニュー文字列(造語禁止。読み取った文字列のみ使用)
3. 対象シートごとの完了条件(ステータス値は1-Cの実確認値を使用)
4. 空行除外条件として `NOT(ISBLANK($B2))` を採用すること(CLAUDE.md規約: 「列Aはチェックボックス回避。書き込み位置はB列=ID列で判定」)
5. `35_wrk_receipt` と20番台タブの要否(シートが存在しない場合は対象外とする)
---
## Phase 2: 仕様書の分割作成
出力先: `docs/dev/dev_mas-131_conditional_formatting.md`
**1回のツール呼び出しで全内容を出力しない。以下のStep分割を厳守すること。**
### Step 2-1: 骨格の作成(File Write、〜20行)
以下の見出しのみのファイルを作成する(本文は空で可)。
### Step 2-2: 概要〜注意事項の追記(File Edit または Bash heredoc、〜300行)
Phase 1の調査結果に基づき、概要テーブル / 目的 / 現在のコード / 修正方針(コード骨格付き) / 影響範囲 / 注意事項 を記載。
### Step 2-3a: エッジケース〜人間が検討すべき事項の追記(File Edit または Bash、〜200行)
エッジケーステーブル / 実データ検証セクション / 関連ドキュメント / 人間が検討すべき事項 を記載。
### Step 2-3b: 実装プロンプト〜変更履歴の追記(File Edit または Bash、〜250行)
実装プロンプト(4スペースインデント) / 推奨実行モデル / 変更履歴 を記載。
### Step 2-4: 仕様書作成プロンプトの記録(File Edit または Bash)
仕様書末尾の `## 仕様書作成プロンプト` セクションに `<details><summary>展開して表示</summary>` ブロックで、この `<instruction>` タグの全文を記録する。
---
## Phase 3: `_config.json` への追記・changelog追記・コミット
### 3-A: `docs/_config.json` に追記
§E.2(バグ修正・バリデーション)に以下を追加:
```json
{ "file": "dev/dev_mas-131_conditional_formatting.md", "title": "E.2.X MAS-131 完了行の視認性向上(条件付き書式)" }
```
### 3-B: `docs/_internal/changelog.md` に追記
先頭行(ヘッダー直後)に追記:
```
| 2026-04-20 | [dev_mas-131_conditional_formatting.md](dev_mas-131_conditional_formatting.md) | 初版作成。完了行グレーアウト(条件付き書式)の設計書 |
```
### 3-C: コミット&プッシュ
```
git add docs/dev/dev_mas-131_conditional_formatting.md docs/_config.json docs/_internal/changelog.md
git commit -m "docs: MAS-131 完了行の視認性向上(条件付き書式)の開発仕様書を作成
applyCompletionFormattingRules_() による条件付き書式自動設定の設計書。
対象: 31_wrk_order / 32_wrk_invoice / 33_wrk_bank / 35_wrk_receipt / 20番台予算タブ
https://claude.ai/code/session_XXXXX"
git push -u origin {現在のブランチ}
```