Synthetic data / Demo掲載している画面はすべて合成データです。実顧客・実案件・本番運用の記録ではありません。
00CASE STUDYProject Progress Manager

Automation / 情報設計

このシステムは何をするか

複数の案件と作業の進み具合を、いま使っている Google スプレッドシートをそのまま正本として、登録・依存関係・判断待ち・進捗の集計まで管理する仕組みです。

01検証system必須項目と依存関係の形を確認する。
02ロックsystemLockService.tryLock(200) で同時操作を待たせずに断る。200ms fail-fast
03冪等性systemsubmissionId + payloadHash で再送を無害化する。
04循環検出system同一送信に含まれる依存を DFS で走査し、循環があれば 1 行も書かずに拒否する。書き込み前に拒否
05採番system型別の ID を採番する。使った番号は再利用しない。
06書込systemProject → Work Item → Relation → Decision の順に行を書く。
07Activitysystem変更前後の値つきで履歴に追記する。記録に失敗すれば変更ごと取り消す。
08コミットsystem失敗時は書いた行を逆順に削除して戻す。ダッシュボード再構築はこのトランザクションの外。
01想定業務課題

想定業務課題

  1. 複数人が同じ表を同時に触ると、途中で失敗した登録が中途半端な行として残る。
  2. 案件・作業・依存関係・判断待ちが別々の表に散り、突き合わせが手作業になる。
02使う人と、いまのやり方

使う人と、いまのやり方

使うのは小規模チームの進行役と担当者です。表計算ソフトは日常的に使いますが、新しいツールの導入には慎重で、管理を専任で見る人はいません。いまは案件ごとに表を作り、状況は口頭で補い、集計は手で数えて別のシートへ転記しています。

03満たすべきこと

満たすべきこと

機能

  • 案件・作業項目・判断待ち・依存関係を、1 回の送信でまとめて登録できる
  • 二重登録の防止(冪等性/submissionId + payloadHash)と、同時操作の保護(LockService)
  • 不正なタスク依存の検出(DFS /循環検出)と、使った番号を再利用しない採番(ID の非再利用採番)
  • 集計表の作り直し(ダッシュボードの再集計)— メニューを押したときだけ動く

制約

  • いま使っている Google スプレッドシートを正本にし、外部サービスへ通信しない
  • 後から項目(列)を足せる(列を追加しても壊れない設計/Header-based column resolution)
  • 未実装の画面を、実装済みに見せない
04作ったもの

作ったもの

01メニュー「進捗管理」初期セットアップ、デモデータ投入、登録フォーム、集計の更新
02登録フォーム(サイドバー)案件・作業・依存・判断待ちを 1 回でまとめて入力
03作業一覧のシート案件・状態・担当・期限・止まっている理由を扱う
04共有ダッシュボード進行中・健全度・判断待ち・期限超過を色分けで示す
05活動履歴のシート変更の記録が追記だけで積み上がる
06まだ作っていない画面シート上に「実装予定」と表示したまま置いてある
05なぜこの設計にしたか

なぜこの設計にしたか

  • スプレッドシートそのものを正本にした。

    利用者は既に Google スプレッドシートで運用している。

    外部データベースを持たず、シートを source of truth にした。

    却下した案 — 却下したのは、外部にデータベースを用意して専用画面を作る案です。いま使っている表を捨てることになります。

    代償 — 中途半端な書き込みの防止(トランザクション/ロールバック)は書いた行を逆順に消す方式であり、原子性そのものではありません。

  • 壊れ方のほうを先に設計した。

    複数人が同じ表を同時に触ると、途中で失敗した登録が中途半端な行として残る。

    二重登録は送信の識別で防ぎ(submissionId + payloadHash)、同時操作は待たせずに断る(LockService の 200ms 打ち切り)。循環する依存は書き込む前に止める。

    却下した案 — 順番待ちの行列を作る案は、待たされた側が二重に押すため却下しました。

    代償 — 検出できるのは同一送信の中の循環までです。既存行と新規分が組み合わさって生じる循環は対象外。

  • 列は番号ではなく見出しの名前で解決する(Header-based column resolution)。

    運用者が列を 1 本足した瞬間に全体がずれる。

    列番号を埋め込まず、見出し名で列を解決する。

    却下した案 — 却下したのは、列番号をコードに埋め込む案です。既存の見出しを保った列の追加・並べ替えでは列ずれが起きません。

    代償 — 見出しの名前を変える/必要な列を消すと動かなくなります。見出し行がスキーマそのものです。

06見どころ

見どころ

同じ登録を 2 回送っても、行は 1 件のままです。

また「A は B を待ち、B は A を待つ」設定は、その登録の中で見つけて 1 行も書かずに拒否します。動画に異常系として収録しています。

集計はメニュー操作で作り直され、遅れ・判断待ち・健全度が色で分かります。

自動では動きません。時間主導トリガーは 1 件も登録していません。

PPM-V02正本を Google スプレッドシートのまま運用する案件ごとの状況・期限・注意点を 1 画面で確認。集計はメニュー操作でのみ作り直される。

この画面で確認できること

  • 案件・作業・期限・判断待ちが 1 枚のシート上で読める
  • 集計はメニュー操作でのみ作り直され、自動再計算では書き換わらない
  • 正本が Google スプレッドシートのまま変わっていない

Evidence の対象外

  • 冪等性の証拠ではない(同一送信の二重登録は自動テストの管轄)
  • 実案件・実運用の記録ではない(合成データ)
この画像の出所と、拡大
種別
Screenshot(Google Sheets アドオンのダッシュボード)
出所
assets/progress-manager/publish/03-dashboard.png
掲載サイズ
1920×1280
倍率
等倍 1.000
SHA256
ccb91212…
誰が・いつ・何を・何から何に変えたかが履歴に残ります。

管理用の ID の列は保護範囲を設定し、直接編集を制限しています。

07実装範囲

実装範囲

個人開発です。シート構造の設計、登録処理、集計、履歴、テストまでを 1 人で実装しました。実運用中のスプレッドシートとは接続しておらず、投入されるデータはすべて架空です。外部連携とスケジュール実行は含めていません。

08品質の担保方法

品質の担保方法

  • 何を確認しているか — ID の衝突、循環の検出、途中失敗の取り消し、二重送信、同時実行の競合、先頭 = のエスケープ、履歴の記録、集計の再構築、安全なエラー、直接編集の許可リスト。
  • 履歴の記録も登録処理に含めています(Activity ログをトランザクションに含む)。記録に失敗すればデータの変更ごと取り消します。デモデータの投入も通常と同じ経路です(デモ専用の裏道が無い設計)。
  • 自動の動作チェック(vm サンドボックス/Apps Script ランタイム不要)は Google アカウント無しで再実行できます。77 passed / 0 failed(2026-08-15 に npm test)。列を足しても壊れないこと自体の回帰テストは未整備です。

77 passed / 0 failednpm test(2026-08-15 / CI run 32023326469)

09安全性とデータの扱い

安全性とデータの扱い

01触ってはいけない列のロック(Range Protection / onEdit /許可リスト)自動計算される列を誤って上書きできません。手編集はロック対象外の列では自由で、所有者は編集者として残るため「防止」ではなく「抑止」です。
02数式の誤作動防止(Formula Injection prevention)= で始まる文字が計算式になりません(対象は先頭 = のみ)。
03安全なエラー表示(Safe Error / secret masking)エラー表示に鍵や個人情報を出しません。
04追記のみの履歴(Append-only Activity)と外部通信ゼロのテスト固定履歴は後から書き換えず、通信するコードが 1 行も無いことを確認しています。できないのではなく、このデモに含めていません。
10運用と納品物

運用と納品物

区分内容
渡すものsrc/ 一式(JavaScript 9 + サイドバー HTML 1)と appsscript.json、docs/architecture.md、README のセットアップ手順(clasp 利用時は .clasp.example.json を複製して Script ID を記入)
依頼者側で行うことスプレッドシートの作成とスクリプト配置、メニュー「進捗管理」→「初期セットアップ」の実行(12 シート・入力規則・保護レンジを作成)
日常の操作登録フォームからの登録と、メニュー「ダッシュボードを更新」。時間主導トリガーは 1 件も登録しない(ScriptApp.newTrigger の出現 0 件。動くのは onOpen / onEdit の 2 つのみ)
非エンジニア向け操作マニュアルあり — assets/progress-manager/USER-GUIDE.md(15 節 / 画像 6 枚)。Case Study 資産であり、公開リポジトリには同梱していない
実データのシート・Script ID同梱しない
11できること・含めていないこと

できること・含めていないこと

ImplementedNot IncludedWhy
一括登録・集計・活動履歴自動実行トリガー手動再構築のみ。勝手に動く処理を入れない方針
同一送信内の循環依存の検出と拒否既存行と組み合わさって生じる循環の検出1 回の送信を検証単位としているため。複数送信にまたがる循環は検出範囲の外
列を見出し名で解決(追加・並べ替えに耐える)見出しのリネーム・必要列の削除への耐性見出し行をスキーマそのものとして扱う設計。名前が変わればスキーマが変わる
先頭 = の数式化対策+ - @ の変換現在の挙動としてテストで固定しているもの。CSV インジェクション全般への対策ではない
書き込んだ行の逆順削除による取り消しデータベースのトランザクションシートを正本にする構成のため。完全な原子性は保証しない
表示 8 / 管理 4 の 12 シートボード / ロードマップ / AI 提案Phase 2 以降の予定。シート上に「実装予定」と表示している
外部通信なし(テストで固定)外部サービス連携・LLM 連携できないのではなく、このデモに含めていない
Apps Script ランタイム不要のテスト列変更耐性そのものの回帰テスト未整備
12規模の目安

規模の目安

項目実測値取得方法
シート12(表示 8 / 管理 4)src/config.js の DISPLAY_SHEETS(8)と ADMIN_SHEETS(4)。初期セットアップが作成する数と一致
スクリプトJavaScript 9 ファイル + サイドバー HTML 1src 配下の JavaScript 9 ファイルと、サイドバー用の HTML 1 ファイル
管理する種別5(Project / Work Item / Decision / Relation / Activity)src/schema.js で見出しを持つ 8 シートのうち、業務データを保持するのはこの 5 種
テスト77 passed / 0 failednpm test(2026-08-15 実行。2026-08-20 に再実行し同数を確認)/ CI run 32023326469
外部通信0src/ に UrlFetchApp の呼び出しが 1 件も無いことを、テストで固定している
13対応可能な作業の例

対応可能な作業の例

以下は対応できる作業の種類であり、受注実績ではありません。

  • Google スプレッドシートを使った業務管理の仕組み化(案件・作業・依存・判断待ち)
  • Google Apps Script による入力・集計・履歴記録の自動化
  • 複数人が同時に使う表計算シートの、壊れない入力フロー設計
  • 既存シートを作り直さずに項目を足せる構造への整理
14技術詳細
15証拠へのリンク

証拠へのリンク

CI 実行ログは GitHub Actions で確認できます。閲覧には GitHub へのサインインが必要な場合があります。

原寸表示。掲載側の crop はレイアウト上の切り抜きで、ここでは全体を表示している。