<!-- Generated by scripts/build-prompts.mjs — do not edit by hand. -->
# このツールを作ってください: Klassenfahrt

*以下がすべて機能要件です。書かれているとおりに実装してください。書かれていない点は自分で判断し、何を前提にしたかを述べてください。*

## 出発点

**openToolbox** テンプレートを使ってください：https://github.com/m-dohmen/openToolbox。まずそのリポジトリの `AGENTS.md` を読むこと — スキーマの形、フィールド型、単一ファイルビルドを壊す禁止事項について、そこが正典です。業務固有の内容はすべて `src/domain.js` 一つに収めます。

> openToolbox skill を導入済みなら（`claude plugin install opentoolbox@opentoolbox`）、このファイルを貼るだけで足ります。テンプレートは skill が自分で取得します。

## 背景にある問題

校外学習が近づいています。28 枚の用紙を配り、19 枚が戻り、うち 3 枚は署名なし、1 枚は裏にアレルギーが書かれています。出発 2 日前になっても 4 家庭からの集金が終わりません。担任はこれを、共有できない表で管理しています。アレルギーや泳力が書かれているからです。ここにはほとんど数値がありません。あるのは状態で、意味のある合計は「あといくら足りないか」だけです。毎週月曜の朝に出る問い（「どの家庭の用紙がまだ？」「誰がまだ払っていない？」）は毎週同じです——リストの頭の上に「保存ビュー」として 置くものであって、毎回手で組み直すものではありません。同意の流れそのものが小さなカンバンです：保留 → 受領 → 拒否、用紙が届くたびに左から右へ流します。

## 最終的に何が出来ていればよいか

ダブルクリックで開ける自己完結型の HTML ファイル 1 つ。サーバーもインストールも不要です。ファイル自体がデータベースでもあり、保存するとレコードを埋め込んだ新しい HTML ファイルが書き出されます。

## レコード

1 件は **Kind**、複数は **Kinder**。

**フィールド**

| キー | ラベル | 型 | 補足 |
| --- | --- | --- | --- |
| `name` | Kind | text | 必須 |
| `guardian` | Erziehungsberechtigte | text | 表ヘッダー `Eltern` |
| `phone` | Telefon für Notfälle | text | 表ヘッダー `Telefon` |
| `consent` | Einverständnis | enum | 次のいずれか：ausstehend · liegt vor · verweigert, 表ヘッダー `Einv.` |
| `consentForm` | Unterschriebener Zettel | attachment | アップロードしたファイル。レコード内に格納, 表ヘッダー `Zettel` |
| `payment` | Zahlung | enum | 次のいずれか：offen · teilweise · vollständig · Zuschuss beantragt · erlassen |
| `paid` | Bezahlt (€) | number | 表ヘッダー `€` |
| `swim` | Schwimmabzeichen | enum | 次のいずれか：ja · nein · unbekannt, 表ヘッダー `Schwimmen` |
| `diet` | Essen (Allergien, vegetarisch …) | text | 表ヘッダー `Essen` |
| `medical` | Medizinisches | text | 複数行, 表ヘッダー `Medizin` |
| `roomWish` | Zimmerwunsch | text | 表ヘッダー `Zimmer` |
| `note` | Notiz | text | 複数行 |
| `open` | Noch offen (€) | computed | 計算値。保存はしない, 表ヘッダー `Offen` |

**表示**

- 主列：`name`
- 主列の下に置く 2 行目：`guardian`
- 表の列（この順）：`name`, `guardian`, `consent`, `payment`, `paid`, `open`, `swim`
- サイドバーの絞り込み：`consent`, `payment`, `swim`
- 概要で合計する：`paid`
- 未完了として数えなくなる条件：`r.consent === 'verweigert' || (r.consent === 'liegt vor' && (r.payment === 'vollständig' || r.payment === 'erlassen'))`
- 赤で強調する条件：`!isDone(r)`

**計算フィールド**

描画のたびに算出し、レコードには絶対に書き戻しません。保存した派生値は、入力のどれかが変わった瞬間に誤りになります。

- `open` (Noch offen (€)):

  ```js
  if (r.payment === 'erlassen') return 0
  return Math.max(0, FEE - (Number(r.paid) || 0))
  ```

**検証ルール**

フィールドをまたぐ条件です。入力フォーム、CSV 取り込み、AI の提案がすべて同じチェックを通るよう、一箇所で効かせてください。

- **条件** `r.consent === 'liegt vor'` → **要求** `guardian`, `phone`
  **メッセージ:** „Zum Einverständnis gehört, wer unterschrieben hat und wie man diese Person erreicht.“
- **条件** `r.payment === 'vollständig'` → **要求** `Number(r.paid) >= FEE`
  **メッセージ:** „Vollständig heißt 185 € — sonst stimmt die Kassenaufstellung nicht.“
- **条件** `r.payment === 'erlassen'` → **要求** `note`
  **メッセージ:** „Ein Erlass gehört begründet — die Kasse wird geprüft.“
- **条件** `Boolean(r.medical?.trim())` → **要求** `phone`
  **メッセージ:** „Wo Medizinisches steht, muss eine Telefonnummer daneben stehen.“

**保存ビュー**

検索・絞り込み・並び替えをまとめた名前付きの組み合わせを、リスト先頭のドロップダウンで提供します。ここで宣言したものがツールに同梱されます。受取側独自のビューは `settings.views` に保存されます。マージ：同じ名前では最後に編集した側が勝ちます。

`name`（一意）、`query`（検索ボックスと同じ）、`filters`（`{ フィールド: spec }`。`v` のみの `spec` は同名ファセットを起動し、`op` 付きの `spec` はフィールドフィルタ）、`sort`（`{ key, dir }`、`dir` は `1` か `-1`）。`entity` は任意で、複数エンティティ用に予約されています。

- プリセット：**Alle** — —; sort: `name ↑`
- プリセット：**Zettel ausstehend** — Einverständnis = ausstehend; sort: `name ↑`
- プリセット：**Geld offen** — Zahlung = offen; sort: `open ↓`

**ボード**

エンティティごとの任意の Kanban で、*リスト* と *ダッシュボード* の横にあるタブ列から開きます。この宣言がなければビュー自体が存在しません。ダッシュボードやガイド付き入力と同じ姿勢です——スキーマでの宣言があって初めて有効になります。

`columnField`（既存の enum フィールドのキー。`values` が宣言順に列となり、最初の値が左端）、`cardFields`（カードのタイトル下に表示される最大 3 つの追加フィールドキー。省略時はタイトル・列・計算・添付ではない最初の 3 フィールド）、`limit`（列ごとのカード上限、デフォルト `50`）。カードを別の列へドラッグすると、フォームと同じ `mutate` を通るため、操作は Undo スタックと 変更ログに載ります。読み取り専用コピーのボードではドラッグが無効になります。

- `columnField` — `consent` (Einverständnis); 列は enum の `values` を宣言順に並べたもの.
- `cardFields` — *Erziehungsberechtigte*, *Telefon für Notfälle*, *Zahlung*.
- 値が空、もしくは `values` に無いレコードは右側の小さな『未分類』に入ります.

## ダッシュボード

絞り込み後ではなく、レコード全体を対象とするタイルです。

- 数値 1 つ：**Kinder** — 件数 · „in der Klasse“
- 数値 1 つ：**Noch offen** — 件数（フィルタに一致するレコードのみ）: `!isDone(r)` · „Zettel oder Geld fehlt“
- 数値 1 つ：**Eingegangen** — `paid` (Bezahlt (€)) · „€ von 2590 €“
- `payment` の値ごとのドーナツ
- `consent` の値ごとの棒。指標は 件数 — **Einverständnisse**
- `swim` の値ごとの棒。指標は 件数 — **Schwimmabzeichen**

## ガイド付き入力

1 件だけ報告すればよく、ツールに不慣れな人のための短い手順です。最後の手順を確定するまで何も書き込まれません。途中でやめても何も残らないこと。

タイトル：**Rückläufer aufnehmen**

> Ein Kind nach dem anderen. Was noch fehlt, einfach leer lassen — die Übersicht zeigt es nachher von selbst an.

1. **ステップ 1** — Kind: フィールド：`name`, `guardian`, `phone`
2. **ステップ 2** — Zettel und Geld: フィールド：`consent`, `payment`, `paid`
3. **ステップ 3** — Besonderheiten: フィールド：`swim`, `diet`, `medical`, `roomWish`
   次の場合のみ表示：`drafts.records?.consent !== 'verweigert'`
4. **ステップ 4** — Klassenliste einlesen: CSV 取り込み。同じ入力セッションに合流します
5. **ステップ 5** — Prüfen: スキーマから生成される確認画面

完了画面：「Aufgenommen. Nicht vergessen: Datei speichern.」

## 既定値

`src/app.jsx` の `DEFAULT_SETTINGS`、`DEFAULT_COLORS`、`DEFAULT_HOME` に設定します。

- タイトル: **Klassenfahrt**
- サブタイトル: Rückläufer, Zahlungen und wer noch fehlt
- ファイル名: `klassenfahrt`
- バージョン: `1.0`
- 画面の言語: `de`
- 起動時の表示: 通常のツール
- 配色: `accent` #a33a63 · `band` #2b1823 · `flag` #b4442e · `ok` #3f7a5c · `pending` #c08a12

## スタートページ

アプリはこの文章から始まります。Markdown の小さな部分集合（見出し、箇条書き、引用、太字、斜体、インラインコード、リンク）です。そのまま使ってください：

```markdown
# Klassenfahrt

28 Zettel gehen raus, 19 kommen zurück, drei ohne Unterschrift, einer mit einer Allergie auf der
Rückseite. Zwei Tage vor Abfahrt fehlt das Geld von vier Familien.

## Was diese Demo zeigt

- **Ein Bestand fast ohne Zahlen**: Zustände, Ja/Nein, ein offener Restbetrag, der sich selbst
  ausrechnet.
- **Gespeicherte Ansichten** — drei Vorschläge im Dropdown am Listenkopf („Alle", „Zettel
  ausstehend", „Geld offen"), die morgens und vor jeder Überweisung dieselbe Tastaturabfolge
  ersparen. Eigene Sichten legt man in den Einstellungen an; eine davon als Start-Ansicht markiert
  öffnet die Datei immer in genau diesem Zustand.
- **Kanban-Board** — der Reiter „Board" ordnet die Kinder nach Einverständnis (ausstehend, liegt
  vor, verweigert). Eine Karte per Drag nach „liegt vor" verschieben trägt sich ins
  Änderungsprotokoll ein und lässt sich mit Strg+Z zurücknehmen; die Tastatur übernehmen Pfeil-
  und Eingabetaste.
- **Regeln, die dem Alltag folgen** — wo Medizinisches steht, muss eine Telefonnummer daneben
  stehen.
- **Der Grund, warum diese Datei verschlüsselt gehört**: hier stehen Gesundheitsangaben von
  Kindern. Einstellungen → Sicherheit → *Verschlüsseln*. Ohne Passphrase ist die Datei danach ein
  Klumpen — auch für Sie.

> Erfundene Namen und Angaben.
```

## サンプルデータ

初回起動時に空にならないよう、現実味のあるサンプルレコードを 14 件用意してください。上のフィールドに合わせて創作します。これは例示であってユーザーのデータではありません。本番データは **Import CSV → replace all** から入れる、と伝えてください。

## 完了条件

- `npm run build` が自己完結した `dist/index.html` を 1 つ出力する
- `npm test` が通る
- ダブルクリックで開き、サンプルレコードが表示される
- 計算フィールドに値が出て、ルールに反するレコードは保存を拒否される
- 設定・配色・スタートページが上の仕様どおりである

## 引き渡す前に

受け取る側に委ねず、自分で決めてください：`copyright` をツールの所有者に設定し、openToolbox リポジトリを指すヘッダーリンクを差し替え、相手がデータ入力だけなら `examplePrompts` を切ります。利用カウンター（設定 → セキュリティ）は引き渡し時に自分から伝えること。

---

*`examples/school-trip.domain.js` から生成 — [ライブデモ](https://m-dohmen.github.io/openToolbox/demos/school-trip/) の実際のソースです。再生成は `npm run prompts`。*

*デモのデータはすべて架空です。この種のツールの構造を示すものであり、法的助言でも適合性の証明でもありません。*
