概要

項目内容
案件IDMAS-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.jssetupAllSchemas(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.jssetupAllSchemas 関数末尾(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.jsMENU_DEFINITION 内、'📋 サイドバー: 🔧 開発・設定' カテゴリ(L240〜252)の items 配列に以下を追加(追加位置は setupAllSchemasIncremental(L245)の直後を推奨):

        { label: '🎨 完了行の書式を再適用', funcName: 'applyCompletionFormattingRules_', description: '完了済み行を条件付き書式でグレーアウト(MAS-131)' },

サイドバー UI(templates/operations_sidebar.html)は MENU_DEFINITION を読んでボタンを生成しているため、本追加だけで両方に反映される。

影響範囲

範囲内容
変更ファイル100_config/101_sys_config.jssetupAllSchemas 末尾に 1 行追加 + 新関数 applyCompletionFormattingRules_ 追加)
000_infra/002_constants.jsMENU_DEFINITION に項目 1 件追加)
変更行数約 110 行追加(うち 100 行が新関数本体)
既存ロジック影響なし(新規追加のみ。setupAllSchemas の他処理は不変)
既存条件付き書式対象シートの既存ルールは clearConditionalFormatRules() で消去される。BUD_SUBS の自動更新アラート用ルール(L1126〜1131)は setupAllSchemas が再生成するため次回 DDL 実行で復元されるが、ユーザーが手動で追加したルールは復元されない
性能1 シートあたり clearConditionalFormatRules + setConditionalFormatRules の 2 API コール。10 シート対象で実測 1 秒未満
データ整合性書式変更のみ。データ自体は不変

注意事項

  1. 既存の手動条件付き書式は消去される: clearConditionalFormatRules() は対象シートの全ルールを一掃する。手動でユーザーが設定した条件付き書式(例: 特定行のマーキング)も消える。本案件のリリース前に運用ユーザーへ周知し、必要なルールはあらかじめ DDL 化(setupAllSchemas 内の宣言)するか、本書式と統合する。
  2. 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 実行後は確実に解決される。フォールバックとして物理シート名も指定済み。
  3. headers.indexOf()-1 の場合のガード: ステータス列・空行判定列のいずれかが見つからない場合は skipped に積んで対象シートをスキップ。DDL 列名変更時の安全装置。
  4. applyCompletionFormattingRules_ はトップレベル関数として定義: setupAllSchemas のネスト内に定義するとメニュー呼出しできなくなる(GAS のスコープ仕様)。updateMenuCatalog_(L1651)と同じトップレベル配置とする。
  5. _ サフィックス命名でもメニュー呼出し可能: GAS の _ サフィックスはコード内のプライベート慣習であり、メニュー MENU_DEFINITION.funcName に文字列指定すれば実行できる(updateMenuCatalog_ が稼働実績あり)。本案件もこの慣例に従い、内部ユーティリティ寄りの位置づけを示すために _ を付与する。
  6. 適用範囲は (2行目, 1列目)〜(maxRow, lastColumn) に固定: getMaxRows() 全行に適用するため、シートに行追加されてもルール側の自動拡張は不要(ただし setupAllSchemasmaxRows を伸縮した場合は本書式も再実行が必要)。

エッジケース

条件挙動対策
ステータス列がシートに存在しない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 を返す(シート未作成)早期 returnif (!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_ORDR31_wrk_orderL783
WRK_INVC32_wrk_invoiceL784
WRK_BANK33_wrk_bankL785
WRK_RCPT35_wrk_receiptL821
BUD_HC22_bud_headcountL776
BUD_SUBS23_bud_subscriptionL778
BUD_CAPEX24_bud_capex_loanL775
BUD_FIN25_bud_financeL779
BUD_ADHOC26_bud_adhocL780
BUD_PIPE21_bud_pipelineL777

空行判定列(emptyCheckCol)— CLAUDE.md「列 B = ID 列」規約の適用

シート列 A列 BemptyCheckCol(採用)採用理由
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処理日時管理IDA 列が ID(チェックボックスなし)。DDL で A=管理ID と確定(L898)
21〜26 BUD_*有効フラグ(チェックボックス)管理ID管理IDB = ID 列

挿入位置の確定

操作ファイル内容
新関数追加100_config/101_sys_config.jsL1539 直後(既存 setupAllSchemas 関数の閉じ括弧 L1538 の直後)function applyCompletionFormattingRules_() { ... } をトップレベルに新設
setupAllSchemas 内呼び出し100_config/101_sys_config.jsL1531 と L1532 の間(DDL 完了監査ログの直後・成功ダイアログの直前)try { applyCompletionFormattingRules_(); } catch (e) { errorLog.push('[MAS-131 conditional format] ' + e.message); }
メニュー項目追加000_infra/002_constants.jsL245(setupAllSchemasIncremental の項目)の直後{ label: '🎨 完了行の書式を再適用', funcName: 'applyCompletionFormattingRules_', description: '完了済み行を条件付き書式でグレーアウト(MAS-131)' },

依存定数(Constants.COLORS

定数名定義位置
Constants.COLORS.DISABLED_BG#d9d9d9000_infra/002_constants.js L45
Constants.COLORS.DISABLED_FC#999999000_infra/002_constants.js L46

関連ドキュメント

  • CLAUDE.md「データアクセス」セクション — 「シートへの書き込み位置は列 B(ID 列)で最終行を判定(列 A のチェックボックス回避)」規約。本案件の emptyCheckCol 設計の根拠
  • 000_infra/002_constants.jsConstants.COLORS.DISABLED_BG/DISABLED_FC 定義、MENU_DEFINITION メニュー定義
  • 100_config/101_sys_config.jssetupAllSchemas 本体、プルダウン定義(L1301〜1310)
  • MAS-130 開発仕様書(未作成・予定) — フィルタービュープリセット(行積み上がり対策 A)。本案件と併用前提
  • MAS-132 開発仕様書(未作成・予定) — 月次行グルーピング(対策 D)
  • MAS-133 開発仕様書(未作成・予定) — 年度跨ぎアーカイブ(対策 E)

人間が検討すべき事項

  1. 既存手動条件付き書式の取扱い(最重要): clearConditionalFormatRules() により対象シートの手動ルールが全て消える。リリース前に運用ユーザーへ事前周知し、保持したいルールがあれば DDL 化(setupAllSchemas 内宣言)するか、本書式の setConditionalFormatRules([rule, ...保持ルール]) に追記する形に拡張する必要があるか検討する。
  2. 「取消」ステータスもグレーアウト対象に含めるか: 31_wrk_order の '取消'、32_wrk_invoice の '取消'、33_wrk_bank の '差戻'、35_wrk_receipt の 'SKIP:取消'/'SKIP:金額なし'/'未登録' 等も「終端 = 以降の対応不要」とみなしてグレーアウトすべきか。本仕様書では '完了/決済完了/消込済' のみを採用しているが、運用上「取消も含めて全終端を薄くしたい」要望が出る可能性あり。doneVals を拡張するだけで対応可能(コード変更なし)。
  3. 35_wrk_receipt の SKIP: 系の扱い: 上記 2 と関連。SKIP: は「処理対象外」だが「未対応」ではなく「対応済(不要と判定)」に近い。完了扱いするか別の薄表示色(例: #f3f3f3 の更に薄いグレー)を割り当てるか、運用と要相談。
  4. 20番台予算タブの「最終起票年月日」だけで完了判定して良いか: RPA 再起票を許容する運用(同一行を翌月分として再利用するケース)がある場合、最終起票年月日 が値を持っていても「次月分は未起票」となり、グレーアウトすると逆効果になる可能性がある。起票ターゲット月 列との比較(起票ターゲット月 <= 最終起票年月日 の YM)を追加する案も検討余地あり。
  5. 数万行規模での描画速度: 条件付き書式は行数に応じて再計算が走るため、5 万行規模で体感的にカクつく可能性がある。MAS-132(月次グルーピング)・MAS-133(年度跨ぎアーカイブ)と組み合わせ、現行タブの行数自体を抑える設計(例: アーカイブ後は本書式も対象外)が望ましい。
  6. DDL 列追加時の書式範囲自動追従: 本実装は getLastColumn() で取得した実列数までを範囲とする。DDL 列追加時は次回 applyCompletionFormattingRules_() 実行で自動拡張されるが、増分 DDL(setupAllSchemasIncremental)が走らずユーザーが「🎨 完了行の書式を再適用」を明示実行しないと反映されない。setupAllSchemasIncremental の末尾でも本関数を呼び出すか検討。
  7. ステータス名称の将来変更耐性: プルダウン定義(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-30v1.1 (リネーム + MAS- 化整合): ファイル名 dev_mas-131_conditional_formatting.mddev_mas-131_conditional_formatting.mdgit 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 {現在のブランチ}
```