このドキュメントは Web App (React + Vite + TypeScript + GAS SPA) のフロントエンド UI 実装に特化したプロンプト集です。
GAS バックエンド向けの汎用テンプレートは dev_spec_prompt_template.md を参照してください。


使い方

シナリオ使うパターン
cockpit / multiyear / sidebar に新しいパネルを追加するパターン A: 新規パネル作成
既存パネルのレイアウト・ロジック・スタイルを変更するパターン B: 既存パネル改修
v0.dev や Galileo AI 等で生成したコードをプロジェクトに取り込むパターン C: v0.dev 産物の取り込み

どのパターンでも 共通チェックリスト を必ず確認すること。


パターン A: 新規パネル作成

使用タイミング

webapp_client/src/cockpit/ または multiyear/ に新しい *Panel.tsx を追加するとき。

プロンプト本文

あなたは bizlp 管理会計 Web App (React 18 + Vite 5 + TypeScript + GAS SPA) の
フロントエンドエンジニアです。以下の仕様に従って新しいパネルコンポーネントを実装してください。

## 案件情報
- 案件 ID: [MAS-XXX]
- ファイル: webapp_client/src/cockpit/[ComponentName]Panel.tsx
- 配置先: CockpitApp.tsx の [Step X / 位置] に追加

## TypeScript インターフェース(先に定義・実装前に確認を取ること)
```ts
interface [ComponentName]PanelProps {
  [props の定義をここに記述]
}

interface [ComponentName]Inputs {
  [入力値の型定義]
}

interface [ComponentName]Result {
  [計算結果の型定義]
}

レイアウト(ASCII アート)

[パネルの大まかな構造をここに描く] 例: ┌─────────────────────────────┐ │ タイトル │ ├──────────┬──────────────────┤ │ 入力フォーム │ 結果表示 │ └──────────┴──────────────────┘

状態マトリクス(全状態を実装すること)

状態表示内容実装方針
ローディング中[表示内容]isLoading state
データあり(正常)[表示内容]
データ空 / 未入力[表示内容]空配列・null・undefined 全対応
エラー[エラーメッセージ]ErrorBoundary または try-catch
数値 00 を表示(非表示にしない)明示的な !== null チェック
数値マイナス赤色表示(.value-negative クラス)

GAS エンジン連携(必要な場合)

  • 使用エンジン: [window.XxxEngine]
  • sync-engines.mjs への追加: [必要 / 不要]
  • cockpit-main.tsx への副作用 import 追加: [必要 / 不要] ← failure_patterns #33 必須確認

CSS ルール

  • 新規クラスは必ず .mas[XXX]-* プレフィックスを付ける
  • Tremor コンポーネントを使う場合は必ず .tremor-root で囲む
  • 既存の .cockpit-wrap .panel-* .step-* クラスは変更しない

やらないこと(制約)

  • CDN URL からの import 禁止(GAS CSP 違反)
  • package.json にない npm パッケージの追加禁止(確認を取ること)
  • any 型の使用禁止
  • cockpit.css の既存スタイルの変更・削除禁止
  • google.script.run を使う場合は必ず withFailureHandler を設定する

受け入れ条件

  • TypeScript エラーなし
  • 全状態が正しく表示される
  • 既存パネルの表示が変化しない
  • npm run build:cockpit が成功する
  • financial_cockpit.html が [目標サイズ] 以下

### 品質チェックリスト(実装後確認)

- [ ] `google.script.run` を使っている場合、`withSuccessHandler` / `withFailureHandler` が両方設定されているか
- [ ] `Infinity` / `NaN` を GAS 側 bootstrap レスポンスに含めていないか(failure_patterns #29)
- [ ] 新規エンジンを追加した場合、`cockpit-main.tsx` に副作用 import を追加したか(failure_patterns #33)
- [ ] `useMemo` / `useCallback` factory 内で参照するヘルパーが宣言より**前**に書かれているか(failure_patterns #32)
- [ ] Tremor コンポーネントを `.tremor-root` ラッパーで囲んでいるか(MAS-356 CSS 分離要件)

---

<a id="pattern-b"></a>
## パターン B: 既存パネル改修

### 使用タイミング
既存の `*Panel.tsx` / `*App.tsx` の見た目・ロジック・props を変更するとき。

### プロンプト本文

あなたは bizlp 管理会計 Web App の React コンポーネントを改修するエンジニアです。 以下の指示に従って 外科的に 変更を加えてください。

対象ファイル

[webapp_client/src/cockpit/XxxPanel.tsx]

現在の動作

[改修前の動作を具体的に説明]

変更内容(できるだけ具体的に)

[何をどう変えたいかを記述]

変更しない範囲(必ず守ること)

  • [変更してはいけないロジック・スタイル・props を列挙]
  • 既存のイベントハンドラーの削除・名称変更禁止
  • 既存のテスト ID / aria-label の変更禁止

影響範囲の確認(実装前に報告すること)

以下のファイルが影響を受ける可能性があります。変更が必要な場合は着手前に確認します:

  • CockpitApp.tsx(props 変更の場合)
  • cockpit.css(スタイル変更の場合)
  • 関連する他パネル

リグレッション防止

変更後に以下が正常動作することを確認してください:

  • [確認すべき既存機能 1]
  • [確認すべき既存機能 2]

### 品質チェックリスト(実装後確認)

- [ ] 変更対象外のファイルが改変されていないか(`git diff` で確認)
- [ ] props の型変更がある場合、呼び出し元(CockpitApp.tsx 等)も更新されているか
- [ ] CSS クラスの追加・変更が他パネルの見た目に影響していないか(ブラウザ確認)
- [ ] ビルドサイズが大幅に増加していないか

---

<a id="pattern-c"></a>
## パターン C: v0.dev / Galileo AI 産物の取り込み

### 使用タイミング
v0.dev や Galileo AI 等のツールで生成したコードをプロジェクトに組み込むとき。

> **パターン C の全体フロー**
> ```
> Step 1: v0.dev 向けプロンプトを書く(下記ひな形)
>             ↓
> Step 2: v0.dev に入力して生成コードを取得
>             ↓
> Step 3: Claude Code にサニタイズ・統合プロンプトを渡す(下記プロンプト本文)
> ```
> Step 1 で制約を先に埋め込んでおくと、Step 3 のサニタイズ作業が最小化できる。

---

### Step 1: v0.dev 向けプロンプトひな形

v0.dev に渡す前に必ず以下の制約節を含める。これにより生成コードに禁止パターンが混入しにくくなる。

コンテキスト

  • GAS Web App 内 iframe で動作する SPA
  • 外部フォント・外部 CDN 参照禁止(import url / link rel="stylesheet" 不可)
  • すべての Tremor コンポーネントは
    でラップ
  • Props 経由でデータを受け取る(fetch / axios 禁止)
  • TypeScript + 型定義を出力(any 禁止)

生成するコンポーネント: [ComponentName]

[コンポーネントの目的を 1-2 文で説明]

Props

```ts interface Props { [型定義をここに記述] } ```

表示要件

  • [要件 1]
  • [要件 2]
  • [参考スクリーンショットがあれば添付]

制約

  • Props 経由でデータを受け取る(fetch 禁止)
  • TypeScript + 型定義を出力

**記入例**(役員報酬比較カード):

コンテキスト

  • GAS Web App 内 iframe で動作する SPA
  • 外部フォント・外部 CDN 参照禁止
  • すべての Tremor コンポーネントは
    でラップ
  • Props 経由でデータを受け取る(fetch 禁止)
  • TypeScript + 型定義を出力

生成するコンポーネント: ApproachComparisonCard

4 つの役員報酬アプローチを横並びカードで表示する。

Props

```ts interface Props { approaches: { key: 'A' | 'B' | 'C' | 'D'; name: string; tag: string; color: 'blue' | 'green' | 'amber' | 'violet'; value: number; inRange: boolean; pct: number; }[]; recommendedMin: number; recommendedMax: number; recommendedMedian: number; } ```

表示要件

  • 4 カードを横並び (grid 2×2 または flex wrap)
  • 各カード: アプローチ名・タグ・ProgressBar・年収・推奨レンジ内なら緑バッジ
  • ProgressBar の色はアプローチごとに異なる (A=blue, B=green, C=amber, D=violet)
  • 上部に推奨レンジ (min〜max・中央値) をサマリー表示
  • クリックで選択状態 (ハイライト)

---

### Step 3: Claude Code サニタイズ・統合プロンプト本文

あなたは bizlp 管理会計 Web App のフロントエンドエンジニアです。 外部ツール(v0.dev)で生成した以下のコードを、プロジェクトのスタックと制約に 合わせてサニタイズ・統合してください。

生成コード

[v0.dev / Galileo AI の出力コードをここにペースト]

サニタイズ要件(以下を必ず処理すること)

1. 禁止 import の除去

以下のパターンが含まれている場合は削除または npm パッケージに置き換える:

  • import ... from 'https://...' → 削除(GAS CSP 違反)
  • import ... from 'cdn.skypack.dev/...' → 削除
  • プロジェクトの package.json にない npm パッケージ → 確認を取る

2. Tailwind / CSS の処理

  • Tremor コンポーネントを使っている場合、最外ラッパーに className="tremor-root" を追加
  • @apply ディレクティブは使わない(cockpit.css 直接記述に変換)
  • 新規 CSS クラスは .mas[XXX]-* プレフィックスで cockpit.css 末尾に追記

3. TypeScript 対応

  • any 型を適切な型に置き換える
  • 既存の型定義(sidebar_api.d.ts / engine 型)と整合させる
  • props の型は interface で明示的に定義する

4. ハードコードデータの置き換え

  • ダミーデータをコンポーネントの props / state に差し替える
  • GAS エンジンの計算結果を受け取る場合は window.XxxEngine 経由で取得

5. GAS SPA 固有の制約

  • fetch() / axios による外部 API 呼び出し → google.script.run に変換
  • localStorage / sessionStorage は使用可(ただし cockpit_* プレフィックス推奨)
  • window.location / history.pushState は GAS 制約で動作しない場合がある

組み込み先

[CockpitApp.tsx の Step X / 既存コンポーネント名]

確認事項(着手前に報告すること)

  1. 禁止 import の有無
  2. 新規 npm パッケージの追加が必要か
  3. 推定バンドルサイズへの影響

### 品質チェックリスト(取り込み後確認)

- [ ] `grep -r "from 'https://"` でゼロ件であること
- [ ] `npm run type-check` がエラーなし
- [ ] `npm run build:cockpit` が成功する
- [ ] ブラウザで該当コンポーネントが表示される
- [ ] 取り込み前後でバンドルサイズの増分が許容範囲内(目安: +50KB 以内 / 要確認)

---

<a id="common-checklist"></a>
## 共通チェックリスト

### プロジェクト固有の GAS / SPA 制約

| 制約 | 詳細 |
|-----|-----|
| CDN import 禁止 | GAS HtmlService CSP。`import ... from 'https://...'` は即ビルドエラー |
| `Infinity` / `NaN` をレスポンスに含めない | V8→Java シリアライズで silent null 化(failure_patterns #29) |
| `google.script.run` 関数名に末尾 `_` 禁止 | GAS で private 扱いとなりクライアントから到達不可(failure_patterns #28) |
| エンジン追加時は cockpit-main.tsx に副作用 import | sync-engines.mjs だけでは bundle に含まれない(failure_patterns #33) |
| `useMemo` factory 内のヘルパーは前方宣言 | TDZ エラー回避(failure_patterns #32) |
| Tremor は `.tremor-root` で囲む | Tailwind preflight と cockpit.css の衝突防止(MAS-356) |
| バンドルサイズ目標 | `financial_cockpit.html` Phase 1: 600 KB / Phase 2 (Firebase 後): 200 KB |

### 状態マトリクス(常に全状態を実装する)

| 状態 | チェック |
|-----|---------|
| ローディング中 | スケルトン or スピナー表示 |
| データあり(正常) | 通常表示 |
| データ空 / 未入力 | 空メッセージ(`null` / `undefined` / `[]` / `""` 全対応) |
| エラー | エラーメッセージ + 必要に応じてリトライ |
| 数値 0 | 非表示にせず 0 を表示(`value && <span>` パターン NG) |
| 数値マイナス | 赤色 / `.value-negative` クラスで視覚区別 |

### UI 実装 失敗パターン早見表

| # | 症状 | 原因 | 対策 |
|:--:|-----|-----|-----|
| FP-28 | `google.script.run.xxx is not a function` | GAS 関数名の末尾 `_` | クライアント呼び出し関数に末尾 `_` を付けない |
| FP-29 | `withSuccessHandler` が null を受け取る | レスポンスに `Infinity` / `NaN` | scrub 処理 + クライアント側 null チェック |
| FP-32 | `Cannot access 'xxx' before initialization` | `const` ヘルパーの後置 + `useMemo` factory | ヘルパーを `useMemo` より前に宣言 |
| FP-33 | エンジン計算が反映されない | `cockpit-main.tsx` の副作用 import 漏れ | エンジン追加時の 3 点セット(sync / import / build)を確認 |
| FP-UI-01 | 既存パネルの余白・フォントが崩れる | Tailwind preflight が cockpit.css を上書き | `.tremor-root` スコープを必ず付与 |
| FP-UI-02 | ボタン押下後 UI がフリーズしたように見える | `google.script.run` 中の loading 表示漏れ | 呼び出し前後で `isLoading` を ON / OFF |

---

## 変更履歴

| 日時 | バージョン | 変更内容 |
|-----|-----------|---------|
| 2026-05-03 | v1.1 | パターン C に v0.dev 向けプロンプトひな形(Step 1)と全体フロー図を追加。制約を事前埋め込みするとサニタイズ作業が最小化できる旨を明記 |
| 2026-05-03 | v1.0 | 初版作成。パターン A(新規パネル)/ B(既存改修)/ C(v0.dev 取り込み)+ 共通チェックリスト整備 |