最終更新: 2026/06/22 18:56
MAS-198: Backlog API連携(課題管理同期)
Context
BizLP GAS Accounting に Backlog(課題管理ツール)との連携機能を新規実装する。 スプレッドシート上の不整合タスク(96_backlog_tasks)を Backlog API 経由で課題登録し、ステータスを双方向同期できるようにする。
既知の Spec/Code 不整合を一括登録する registerKnownIssues() も提供し、手動でのタスク起票コストを削減する。
変更対象ファイル
| # | ファイル | 変更内容 |
|---|---|---|
| 1 | 000_infra/001_env.js | Backlog用スクリプトプロパティのアクセサ4件追加 |
| 2 | 000_infra/002_constants.js | ID_PREFIX_MAP に TASK_ エントリ追加 |
| 3 | 100_config/101_sys_config.js | DDLスキーマ, config行, MST_DICT, SYS_DROP, メニュー, setVali 追加 |
| 4 | 800_ops/804_backlog.js | 新規作成 - Backlog API連携モジュール |
| 5 | 900_test/901_test_runner.js | T9: Backlog連携テスト追加 |
実装ステップ
Step 1: 000_infra/001_env.js — Backlog プロパティアクセサ追加
setReceiptFolderId の後(L64付近)に4つのメソッドを追加:
backlogSpace: function () {
return _getProps().getProperty('BACKLOG_SPACE') || '';
},
backlogApiKey: function () {
return _getProps().getProperty('BACKLOG_API_KEY') || '';
},
backlogProjectId: function () {
return _getProps().getProperty('BACKLOG_PROJECT_ID') || '';
},
backlogIssueTypeId: function () {
return _getProps().getProperty('BACKLOG_ISSUE_TYPE_ID') || '';
},
パターン: 既存の geminiApiKey() / receiptFolderId() と同一。
Step 2: 000_infra/002_constants.js — ID_PREFIX_MAP 追加
ID_PREFIX_MAP 配列の末尾(15_mst_dictionary の後)に追加:
{ pattern: '96_backlog_tasks', prefix: 'TASK_', digit: 4, isDate: true }
isDate: true → ID形式は TASK_YYYYMMDD_NNNN。
Step 3: 100_config/101_sys_config.js — DDL・メニュー・バリデーション
7箇所の変更が必要。
3a. config行の自動登録 (setupAllSchemas 内, SYS_TEST 付近)
if (!existKeys.includes('BKL_TASK')) confSheet.appendRow(['BKL_TASK', '', '96_backlog_tasks', 'Backlog課題管理']);
3b. schemas オブジェクトに追加 (WRK_RCPT の後)
'BKL_TASK': {
headers: ["有効フラグ","タスクID","Backlog課題キー","ステータス","優先度","カテゴリ","対象ファイル","不整合ID","タイトル","詳細","関連仕様書","関連コード","担当者","期限","Backlog同期日時","備考"],
color: "#795548"
},
3c. MST_DICT 自動挿入 (newEntries 配列の末尾)
['Backlogステータス', [['BKL_OPEN','未対応'], ['BKL_PROG','処理中'], ['BKL_DONE','処理済み'], ['BKL_CLOS','完了']]],
['Backlog優先度', [['BKL_HI','高'], ['BKL_MID','中'], ['BKL_LO','低']]],
['Backlogカテゴリ', [['BKL_SPEC','spec修正'], ['BKL_CODE','code修正'], ['BKL_REV','要検討']]],
3d. SYS_DROP に3列追加
dropHeaders 配列の末尾("UI有効フラグ" の後)に追加:
"UIBacklogステータス", "UIBacklog優先度", "UIBacklogカテゴリ"
formulas 配列の末尾(={TRUE;FALSE} の後)に3つのFILTER式追加:
`=IFERROR(FILTER('${dictName}'!D2:D, '${dictName}'!B2:B="Backlogステータス", ('${dictName}'!A2:A=TRUE)+('${dictName}'!A2:A="TRUE")),"")`, // AJ列
`=IFERROR(FILTER('${dictName}'!D2:D, '${dictName}'!B2:B="Backlog優先度", ('${dictName}'!A2:A=TRUE)+('${dictName}'!A2:A="TRUE")),"")`, // AK列
`=IFERROR(FILTER('${dictName}'!D2:D, '${dictName}'!B2:B="Backlogカテゴリ", ('${dictName}'!A2:A=TRUE)+('${dictName}'!A2:A="TRUE")),"")`, // AL列
3e. setVali 追加 (WRK_RCPT の後)
setVali('BKL_TASK', 4, 'AJ', '96_backlog_tasks'); // ステータス → UIBacklogステータス
setVali('BKL_TASK', 5, 'AK', '96_backlog_tasks'); // 優先度 → UIBacklog優先度
setVali('BKL_TASK', 6, 'AL', '96_backlog_tasks'); // カテゴリ → UIBacklogカテゴリ
flagTabs 配列に 'BKL_TASK' を追加(有効フラグの TRUE/FALSE バリデーション)。
3f. スキーマUI設定 — inputCols / autoCols (WRK_RCPT ブロックの後)
if (key === 'BKL_TASK') {
sheet.getRange("N2:N").setNumberFormat('yyyy-mm-dd'); // 期限
sheet.getRange("O2:O").setNumberFormat('yyyy-mm-dd hh:mm'); // Backlog同期日時
inputCols = [1,4,5,6,7,8,9,10,11,12,13,14,16]; // 入力列
autoCols = [2,3,15]; // 自動列: タスクID, Backlog課題キー, 同期日時
}
3g. メニュー追加 — ⚙️ メンテナンス に3件
既存の .addItem('🔎 ...', 'checkInvStlConsistency') と .addToUi() の間に:
.addSeparator()
.addItem('📋 Backlog課題を登録', 'syncTasksToBacklog')
.addItem('📋 Backlogステータス同期', 'pullBacklogStatus')
.addItem('📋 不整合タスク自動生成', 'registerKnownIssues')
Step 4: 800_ops/804_backlog.js — 新規作成
4a. backlogFetch_(method, path, payload) — API共通ヘルパー
Env.backlogSpace()/Env.backlogApiKey()で認証情報取得- 未設定時は
SpreadsheetApp.getUi().alert()でセットアップ手順案内 → return null - URL:
https://${space}/api/v2/${path}?apiKey=${key}(space はフルドメイン) - POST時:
contentType: 'application/json',payload: JSON.stringify(payload) - GET時:
method: 'get' muteHttpExceptions: true- 503リトライ: 3回、
Utilities.sleep(5000)間隔 (502_receipt_reader.js のパターンを踏襲) - 200以外はエラーログ出力 + throw
- 返却:
JSON.parse(response.getContentText())
4b. syncTasksToBacklog()
getWebSpreadsheet_()→Utils.getSheetByKey('BKL_TASK', '96_backlog_tasks')- ヘッダー行からカラムインデックスをビルド (ヘッダー名ベースの
indexOf) - 有効フラグ=TRUE かつ Backlog課題キー空の行をフィルタ
- 各行について:
- priorityId マッピング:
{'高':2, '中':3, '低':4}(Backlog API仕様) - description テンプレート組み立て(## 不整合内容 / ## 修正内容 / ## 関連ファイル)
backlogFetch_('post', 'issues', { projectId, summary, description, issueTypeId, priorityId, dueDate })- 返却
issueKeyをシートに書き戻し(Backlog課題キー列) - Backlog同期日時に
new Date()を書き戻し Utilities.sleep(1000)レート制限
- priorityId マッピング:
- toast で結果サマリー表示
4c. pullBacklogStatus()
- 96タブから Backlog課題キーが空でない行を取得
- 各行:
backlogFetch_('get', 'issues/' + issueKey)でステータス取得 - Backlog JP locale の
status.nameがそのまま未対応/処理中/処理済み/完了に対応 - シートのステータス列を更新、Backlog同期日時を更新
Utilities.sleep(1000)レート制限- toast で結果表示
4d. registerKnownIssues()
- 96タブの既存データを読み込み、不整合ID列で Set を構築(重複チェック用)
- 3件の既知の不整合を定義:
#6: noCash cashPlug補正未実装, 06_datamart_ingest.js, 高, spec修正#7: Finance ORD開始年月のDate→YYYY-MM変換, 04_bat_rpa.js:1557, 中, code修正#11: STL決済口座ハードコード定数化, 08_subledger_engine.js:101, 低, code修正
- 不整合IDが既存 Set に含まれていなければ追加
- タスクID生成:
TASK_YYYYMMDD_NNNN(列Bスキャンで最大連番+1) - シート末尾に書き込み (列Bで最終行判定 →
Utils.getTrueLastRow(sheet, 2)) - toast で結果表示
Step 5: 900_test/901_test_runner.js — T9テスト追加
runAllTests() に T9 呼び出しを追加:
T9-01: registerKnownIssues 実行後、96タブに3件存在
T9-02: 不整合ID #6, #7, #11 が存在
T9-03: 重複実行しても行数が増えない(冪等性)
T9-04: 有効フラグが全てTRUE
T9-05: タスクIDがTASK_形式
再利用パターン
この実装で踏襲する既存パターンの一覧。今後の同種開発で参照できる。
DDLスキーマ追加手順 (101_sys_config.js)
setupAllSchemas()内の config行自動登録セクションにconfSheet.appendRow追加schemasオブジェクトにヘッダー配列+色を追加- 必要に応じて
newEntries(MST_DICT) にプルダウン値追加 SYS_DROPのdropHeaders+formulasに列追加setVali()でターゲットシートの列にバリデーション設定inputCols/autoColsで入力・自動列の背景色設定
外部API連携パターン (502_receipt_reader.js 準拠)
Envモジュールにスクリプトプロパティのアクセサ追加UrlFetchApp.fetch()+muteHttpExceptions: true- 503リトライループ (最大3回, 5秒間隔)
- レスポンスの
getResponseCode()+JSON.parse(getContentText()) - 未設定時は
ui.alert()で案内して return
メニュー追加手順 (101_sys_config.js onOpen)
- 既存メニューの
.addToUi()の前に.addSeparator()+.addItem()を追加 - 関数名はグローバルスコープに公開(GAS の制約)
検証手順
npm run push:devで開発環境にデプロイ- GASエディタで
setupAllSchemas実行 → 96_backlog_tasks タブが作成されること - メニュー「⚙️ メンテナンス」に Backlog 関連3項目が表示されること
- 「📋 不整合タスク自動生成」実行 → 3件投入、再実行で増えないこと
- テスト:
runAllTestsで T9 が PASS すること - (APIキー設定済みの場合) 「📋 Backlog課題を登録」で課題作成 + キー書き戻し確認
- (APIキー設定済みの場合) 「📋 Backlogステータス同期」でステータス取得確認
セットアップ要件
GAS の「プロジェクトの設定」→「スクリプトプロパティ」に以下を設定:
| プロパティ | 説明 | 例 |
|---|---|---|
BACKLOG_SPACE | Backlog スペースのフルドメイン | mycompany.backlog.com |
BACKLOG_API_KEY | Backlog API キー | (ユーザー設定画面から取得) |
BACKLOG_PROJECT_ID | 対象プロジェクトの数値ID | 12345 |
BACKLOG_ISSUE_TYPE_ID | 使用する課題種別の数値ID | 67890 |
実装プロンプト(Claude Code 用)
あなたはGAS会計システム(bizlp-gas-accounting)のシニア開発者です。
案件 MAS-198「Backlog API連携」を本仕様書「## 実装ステップ」Step 1-5 に従って実装してください。
## Phase 1: 実行前タスク(Read で実物を確認。行番号・関数名は推測しない)
1. `000_infra/001_env.js` — 既存の `geminiApiKey()` / `receiptFolderId()` / `setReceiptFolderId()` の実装パターン(`_getProps()` 経由・デフォルト空文字)を確認。Backlog 用アクセサ4件は同一パターンで追加。
2. `000_infra/002_constants.js` — `ID_PREFIX_MAP` 配列の既存エントリ(特に `15_mst_dictionary` のエントリ)と、`isDate: true` 形式の ID 採番パターンを確認。
3. `100_config/101_sys_config.js` — 以下を特定:
- `schemas` オブジェクト内の `WRK_RCPT` エントリ(新エントリ `BKL_TASK` はこの直後に追加)
- `setupAllSchemas()` 内の config行自動登録セクションで `SYS_TEST` が登録される箇所
- `newEntries`(MST_DICT 追加用)配列の末尾
- `SYS_DROP` 生成セクションの `dropHeaders` / `formulas` 定義
- `setVali(...)` 呼び出し群の位置(`WRK_RCPT` 付近)
- `flagTabs` 配列の位置
- `inputCols` / `autoCols` を設定する分岐(`WRK_RCPT` ブロック)
- `onOpen()` のメニュー定義(`⚙️ メンテナンス` カテゴリ、`.addToUi()` の直前)
4. `500_import/502_receipt_reader.js` — 外部 API 連携の既存パターン(`UrlFetchApp.fetch()` + `muteHttpExceptions: true` + 503 リトライ 3 回・5 秒間隔)を確認し、`backlogFetch_` ヘルパーで踏襲。
5. `000_infra/004_utils.js` — `Utils.getSheetByKey` / `Utils.getTrueLastRow` / `Utils.auditLog` のシグネチャを確認。列 B の末尾行スキャンで ID 採番する。
6. `900_test/901_test_runner.js` — 既存テスト T1-T8 の構造(関数名・assert パターン)を確認し、T9 を同形式で追加。
## Phase 2: 修正対象ファイル
- `000_infra/001_env.js` — Backlog プロパティアクセサ 4 件追加(Step 1)
- `000_infra/002_constants.js` — `ID_PREFIX_MAP` に `TASK_` エントリ追加(Step 2)
- `100_config/101_sys_config.js` — DDL・MST_DICT・SYS_DROP・setVali・メニュー追加(Step 3a-3g)
- `800_ops/804_backlog.js`(新規) — API ヘルパー・同期関数 3 件(Step 4a-4d)
- `900_test/901_test_runner.js` — T9 追加(Step 5)
## Phase 3: 実装内容
本仕様書「## 実装ステップ」Step 1 ~ Step 5 のコードブロックをそのまま適用する。重要ポイントのみ再掲:
### Step 4 (800_ops/804_backlog.js 新規作成) の注意点
- `backlogFetch_` は空の `BACKLOG_SPACE` / `BACKLOG_API_KEY` 時に `SpreadsheetApp.getUi().alert()` でセットアップ手順案内 → return null。Utils.logError に投げない(ユーザー側の初期設定未完了は例外ではないため)。
- URL: `https://${space}/api/v2/${path}?apiKey=${key}`。POST 時は `apiKey` を URL クエリに残しつつ、body に JSON で他パラメータ。
- `syncTasksToBacklog`: 書き込み順序は **Backlog 課題作成 → キー書き戻し → 同期日時書き戻し**。途中で失敗した場合、`Backlog課題キー` が空のままになるため、再実行で重複登録されるリスク。対策: API 成功後に**トランザクション的**にシートへ書き戻し(失敗時は `Utils.logError` + スキップ、次行へ)。
- `pullBacklogStatus`: Backlog の `status.name` が日本語 (`未対応` / `処理中` / `処理済み` / `完了`) で返るため、MST_DICT の `Backlogステータス` 表示値とそのまま一致。マッピング不要。
- `registerKnownIssues`: 3 件の既知不整合は仕様書「Step 4d」の ID(`#6` / `#7` / `#11`)で固定。既存データに同じ不整合 ID があればスキップ(冪等性)。
### ID 採番パターン(TASK_YYYYMMDD_NNNN)
- 列 B(タスクID)を下から走査して当日分の最大 `NNNN` を取得
- `NNNN` は 0001 ~ 9999 の 4 桁ゼロパディング
- `ID_PREFIX_MAP` の `isDate: true` フラグで日次リセット
## 制約
- 列番号ハードコード禁止。すべて `indexOf('タスクID')` 等のヘッダー名ベースで取得。
- 列 B を末尾行判定に使用(列 A はチェックボックスのため使用不可)。
- MCP `add_rows` 非使用(先頭に挿入されるため)。`Utils.getTrueLastRow(sheet, 2)` + `Range.setValues` で末尾書き込み。
- Backlog API のレート制限回避: 書き込み系は `Utilities.sleep(1000)` を各リクエスト間に挿入。
- セキュリティ: `BACKLOG_API_KEY` をコード・ログに出力しない。`backlogFetch_` 内でもエラーログはパスとステータスコードのみ記録。
## エッジケース
| 条件 | 動作 |
|------|------|
| `BACKLOG_SPACE` / `BACKLOG_API_KEY` 未設定 | `ui.alert()` でセットアップ案内 → 処理中断 |
| Backlog API が 503 | 3 回リトライ(5 秒間隔)。それでも失敗なら `Utils.logError` + throw |
| Backlog 課題作成後にキー書き戻し失敗 | `Utils.logError` + 次行へ。再実行時は `Backlog課題キー` 空の行が対象となり、API で二重登録リスクあり → 運用で警告 |
| `registerKnownIssues` の重複実行 | 不整合 ID Set で冪等性担保(0 件追加) |
| 96_backlog_tasks シート未作成 | `setupAllSchemas()` 未実行。Step 3a で config 行が登録されているため、再度 `setupAllSchemas` 実行で作成される |
| Backlog プロジェクトが削除済 | API が 404 → `Utils.logError` + 該当行スキップ |
## 実データ検証(実装直前に実施)
- Backlog API のテストスペース/プロジェクト/課題種別の ID を取得し、スクリプトプロパティに設定
- `priorityId` マッピング (`{'高':2, '中':3, '低':4}`) が対象 Backlog スペースで実際に有効か確認(カスタム優先度がある場合は要調整)
- 日本語 locale 以外のスペースでは `status.name` が英語になる可能性あり。テストスペースの locale を確認
## 動作確認
1. `npm run push:dev` → デプロイ
2. GAS スクリプトプロパティに `BACKLOG_SPACE` / `BACKLOG_API_KEY` / `BACKLOG_PROJECT_ID` / `BACKLOG_ISSUE_TYPE_ID` 設定
3. GAS エディタで `setupAllSchemas` 実行 → `96_backlog_tasks` タブが作成され、ヘッダー・MST_DICT・プルダウンが正しく設定されること
4. メニュー「⚙️ メンテナンス」に Backlog 関連 3 項目が表示されること
5. 「📋 不整合タスク自動生成」実行 → 3 件投入、再実行で 0 件追加(冪等)
6. 「📋 Backlog課題を登録」実行 → Backlog 側に課題が作成され、シート側に `Backlog課題キー` が書き戻されること
7. Backlog 側で課題のステータスを変更 → 「📋 Backlogステータス同期」で反映されること
8. T9 テスト全項目 PASS
### 拡張思考の使用状況
| フェーズ | 拡張思考 | 備考 |
|---------|---------|------|
| Phase 1(調査) | あり | 101_sys_config の 7 箇所の挿入位置特定・既存パターンの踏襲確認 |
| Phase 2(実装) | 部分的 | 各 Step の挿入位置を再確認する局面のみ。コード自体は仕様書に明記済み |
推奨実行モデル
| 工程 | 推奨モデル | 理由 |
|---|---|---|
| Phase 1 調査(101_sys_config の 7 箇所特定) | Claude Opus 4.7 | 複数セクションの位置関係・既存パターンの理解が必要 |
| Step 1-3(Env・Constants・sys_config の編集) | Claude Sonnet 4.6 | 定型的な DDL 拡張だが挿入位置の正確性が必要 |
| Step 4(804_backlog.js 新規作成) | Claude Sonnet 4.6 | 502_receipt_reader パターンを踏襲しつつ API 仕様を反映 |
| Step 5(テスト追加) | Claude Haiku 4.5 | 既存 T1-T8 パターンの踏襲 |
変更履歴
| 日付 | 変更内容 |
|---|---|
| 2026-04-13 23:55 | 初版作成 |
| 2026-04-20 | 実装プロンプト + 推奨実行モデル セクション追加 |