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

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

## 出発点

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

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

## 背景にある問題

どの工場も、どの職人企業も、どの保育施設も、一定間隔で点検しなければならない機器を持っています。ドリル、延長コード、コーヒーメーカー、ヒートガン。点検そのものは数分です。ところが管理が午後を丸ごと食いつぶします。記録はバインダーの中、期限は親方の頭の中。そして事故のあと、労災保険はただ一つ聞きます。**この機器を最後に点検したのはいつですか。**

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

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

## レコード

1 件は **Betriebsmittel**、複数は **Betriebsmittel**。

**フィールド**

| キー | ラベル | 型 | 補足 |
| --- | --- | --- | --- |
| `name` | Gerät | text | 必須 |
| `kind` | Art | enum | 次のいずれか：Handmaschine · Verlängerung/Leitung · Küchengerät · Messgerät · Ladegerät · Ortsfest |
| `serial` | Inventar-/Seriennummer | text | 表ヘッダー `Nr.` |
| `location` | Standort | enum | 次のいずれか：Werkstatt · Baustellenwagen · Lager · Büro · Küche · ausgeliehen, 表ヘッダー `Ort` |
| `holder` | In der Hand von | text | 表ヘッダー `Bei` |
| `interval` | Prüfintervall (Monate) | enum | 次のいずれか：6 · 12 · 24, 表ヘッダー `Int.` |
| `lastTest` | Letzte Prüfung | date | 表ヘッダー `Geprüft` |
| `tester` | Prüfer | text | — |
| `result` | Ergebnis | enum | 次のいずれか：bestanden · bestanden mit Mangel · nicht bestanden · noch nicht geprüft |
| `defect` | Festgestellter Mangel | text | 複数行, 表ヘッダー `Mangel` |
| `protocol` | Prüfprotokoll | attachment | アップロードしたファイル。レコード内に格納, 表ヘッダー `Protokoll` |
| `note` | Notiz | text | 複数行 |
| `due` | Nächste Prüfung | computed | 計算値。保存はしない, 表ヘッダー `Fällig` |
| `daysLeft` | Tage bis zur Prüfung | computed | 計算値。保存はしない, 表ヘッダー `Tage` |

**表示**

- 主列：`name`
- 主列の下に置く 2 行目：`location`
- 表の列（この順）：`name`, `kind`, `location`, `lastTest`, `due`, `daysLeft`, `result`
- サイドバーの絞り込み：`kind`, `location`, `result`
- 未完了として数えなくなる条件：`() => false`
- 赤で強調する条件：`{ if (r.result === 'nicht bestanden') return true const d = dueDate(r) return !d || d < iso(0) }`

**計算フィールド**

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

- `due` (Nächste Prüfung):

  ```js
  const d = dueDate(r)
  if (!d) return ''
  const [y, m, day] = d.split('-')
  return `${day}.${m}.${y}`
  ```
- `daysLeft` (Tage bis zur Prüfung):

  ```js
  const d = localDateFromIso(dueDate(r))
  if (!d) return ''
  // Beide Seiten als ganze lokale Tage: Date.UTC über die Tages-
  // komponenten hält die Differenz exakt ganzzahlig - ohne die
  // Rundungsrettung, die ab UTC+12 kippt, und ohne den Mix aus
  // UTC-Mitternacht und Lokal-Mitternacht.
  const now = new Date()
  return (
    (Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()) -
      Date.UTC(now.getFullYear(), now.getMonth(), now.getDate())) /
    86400000
  )
  ```

**検証ルール**

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

- **条件** `r.result !== 'noch nicht geprüft'` → **要求** `lastTest`, `tester`
  **メッセージ:** „Ein Prüfergebnis ohne Datum und Prüfer ist im Ernstfall wertlos.“
- **条件** `r.result === 'bestanden mit Mangel' || r.result === 'nicht bestanden'` → **要求** `defect`
  **メッセージ:** „Zu einem Mangel gehört, worin er besteht.“
- **条件** `r.result === 'nicht bestanden'` → **要求** `note`
  **メッセージ:** „Bei „nicht bestanden" gehört in die Notiz, wo das Gerät jetzt ist — es darf nicht weiterlaufen.“

## ダッシュボード

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

- 数値 1 つ：**Betriebsmittel** — 件数 · „im Bestand“
- 数値 1 つ：**Fällig oder gesperrt** — 件数（フィルタに一致するレコードのみ）: `isOverdue(r)` · „sofort anfassen“
- 数値 1 つ：**In den nächsten 60 Tagen** — 件数（フィルタに一致するレコードのみ）: `{ const d = dueDate(r) return d && d >= iso(0) && d <= iso(60) }` · „Prüftermin planen“
- `result` の値ごとのドーナツ
- `location` の値ごとの棒。指標は 件数 — **Geräte je Standort**
- `kind` の値ごとの棒。指標は 件数 — **Geräte je Art**

## ガイド付き入力

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

タイトル：**Prüfung eintragen**

> Drei Schritte. Für den ersten Aufbau eines Bestands hilft der Schritt „Liste einlesen".

1. **ステップ 1** — Gerät: フィールド：`name`, `kind`, `serial`, `location`, `holder`, `interval`
2. **ステップ 2** — Prüfung: フィールド：`lastTest`, `tester`, `result`, `defect`, `note`
3. **ステップ 3** — Liste einlesen: CSV 取り込み。同じ入力セッションに合流します
   次の場合のみ表示：`Boolean(drafts.records?.name)`
4. **ステップ 4** — Prüfen: スキーマから生成される確認画面

完了画面：「Eingetragen. Die nächste Fälligkeit rechnet sich von selbst.」

## 既定値

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

- タイトル: **Prüfbuch Betriebsmittel**
- サブタイトル: Wiederkehrende Prüfungen nach DGUV Vorschrift 3
- ファイル名: `pruefbuch`
- バージョン: `1.0`
- 画面の言語: `de`
- 起動時の表示: 通常のツール
- 配色: `accent` #a8541f · `band` #2a1d14 · `flag` #b3341f · `ok` #3f7a3f · `pending` #c99411

## スタートページ

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

```markdown
# Prüfbuch für ortsveränderliche Betriebsmittel

Bohrmaschine, Verlängerung, Kaffeemaschine, Heißluftgebläse: alles muss regelmäßig geprüft werden.
Die Prüfung selbst dauert Minuten. Die Verwaltung frisst den Nachmittag — weil das Protokoll im
Ordner liegt, die Fristen im Kopf des Meisters, und die Berufsgenossenschaft nach einem Unfall
genau eine Frage stellt: **wann wurde dieses Gerät zuletzt geprüft?**

## Was diese Demo zeigt

- **Sortierbare Spalten** — ein Klick auf den Spaltenkopf ordnet: Zahlen nach Größe („Tage"
  reicht von deutlich überfällig bis weit in die Zukunft), Daten chronologisch („Geprüft" spannt
  zwei Jahre), Text alphabetisch; der dritte Klick stellt die Reihenfolge des Datenblocks wieder
  her, leere Werte bleiben unten.
- **Nichts wird summiert, alles gerechnet**: die Fälligkeit ergibt sich aus letzter Prüfung und
  Intervall, die Restzeit daraus, die rote Markierung wieder daraus.
- **Regeln, die dem Ernstfall standhalten** — ein Ergebnis ohne Datum und Prüfer lässt sich nicht
  speichern, ein „nicht bestanden" nicht ohne die Angabe, wo das Gerät jetzt ist.
- **Anhänge** für das Prüfprotokoll am Gerät selbst.

> Erfundene Daten. Veranschaulichung der Struktur, keine Aussage über den Umfang Ihrer Pflichten.
```

## サンプルデータ

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

## 完了条件

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

## 引き渡す前に

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

---

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

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