<!-- Generated by scripts/build-prompts.mjs — do not edit by hand. -->
# Construa esta ferramenta para mim: Verarbeitungsverzeichnis

*Tudo o que segue é a especificação funcional. Siga-a como está; onde ela se calar, decida e diga o que assumiu.*

## Ponto de partida

Use o modelo **openToolbox**: https://github.com/m-dohmen/openToolbox. Leia primeiro o `AGENTS.md` desse repositório — ele é a autoridade sobre a forma do esquema, os tipos de campo e as regras que quebram uma compilação de arquivo único. Tudo o que é do domínio vai em um único arquivo, `src/domain.js`.

> Se o skill do openToolbox estiver instalado (`claude plugin install opentoolbox@opentoolbox`), basta colar este arquivo — ele mesmo busca o modelo.

## O problema por trás disso

Pelo art. 30 do RGPD quase toda empresa precisa manter um registro de atividades de tratamento. Quase nenhuma mantém um que mereça o nome, e o motivo raramente é má vontade — é a coleta. As respostas estão com doze pessoas diferentes: as candidaturas no RH, a ferramenta de newsletter no marketing, as câmeras com o zelador. Quem tenta preencher de forma central escreve doze e-mails e recebe nove. Por isso a ferramenta precisa funcionar como algo que se envia: cada área declara o próprio tratamento, salva e devolve.

## O que precisa existir no fim

Um único arquivo HTML autocontido, aberto com duplo clique, sem servidor e sem instalação. O arquivo também é o banco de dados: salvar escreve um novo HTML com os registros embutidos.

## O registro

Um registro é **Verarbeitung**, vários são **Verarbeitungen**.

**Campos**

| Chave | Rótulo | Tipo | Detalhe |
| --- | --- | --- | --- |
| `name` | Verarbeitungstätigkeit | text | obrigatório |
| `area` | Bereich | enum | um de: Personal · Vertrieb · Marketing · IT · Buchhaltung · Empfang |
| `contact` | Ansprechperson | text | cabeçalho de tabela `Kontakt` |
| `purpose` | Zweck der Verarbeitung | text | multilinha, cabeçalho de tabela `Zweck` |
| `subjects` | Betroffene | enum | um de: Beschäftigte · Bewerberinnen und Bewerber · Kundinnen und Kunden · Interessenten · Lieferanten · Besucher |
| `categories` | Datenkategorien | text | multilinha, cabeçalho de tabela `Daten` |
| `basis` | Rechtsgrundlage | enum | um de: Vertrag (Art. 6 I b) · Rechtliche Pflicht (Art. 6 I c) · Berechtigtes Interesse (Art. 6 I f) · Einwilligung (Art. 6 I a) · noch zu klären, cabeçalho de tabela `Grundlage` |
| `system` | System / Ablage | text | cabeçalho de tabela `System` |
| `processor` | Auftragsverarbeiter | text | cabeçalho de tabela `AV` |
| `thirdCountry` | Drittlandtransfer | enum | um de: nein · ja · unklar, cabeçalho de tabela `Drittland` |
| `retention` | Löschfrist | text | cabeçalho de tabela `Frist` |
| `risk` | Risiko | enum | um de: gering · mittel · hoch |
| `status` | Status | enum | um de: gemeldet · in Prüfung · freigegeben · nachzubessern |
| `reviewed` | Zuletzt geprüft | date | cabeçalho de tabela `Geprüft` |
| `note` | Notiz | text | multilinha |
| `age` | Tage seit Prüfung | computed | calculado, nunca armazenado, cabeçalho de tabela `Alter` |

**Apresentação**

- Coluna principal: `name`
- Segunda linha abaixo: `area`
- Colunas da tabela, nesta ordem: `name`, `area`, `basis`, `subjects`, `retention`, `age`, `status`
- Filtros da barra lateral: `area`, `status`, `risk`
- Deixa de contar como aberto quando: `r.status === 'freigegeben'`
- Marcado em vermelho quando: `!r.reviewed || r.reviewed < iso(-365)`

**Campos calculados**

São derivados a cada renderização e nunca gravados no registro — uma derivação armazenada fica desatualizada assim que uma de suas entradas muda.

- `age` (Tage seit Prüfung):

  ```js
  const reviewed = localDateFromIso(r.reviewed)
  if (!reviewed) return ''
  /* Ganze lokale Tage über die Date.UTC-Differenz der Tageskompo-
     nenten - exakt ganzzahlig, ohne Rundungsrettung und ohne den
     Mix aus UTC-Mitternacht und Lokal-Mitternacht. */
  const now = new Date()
  return (
    (Date.UTC(now.getFullYear(), now.getMonth(), now.getDate()) -
      Date.UTC(reviewed.getFullYear(), reviewed.getMonth(), reviewed.getDate())) /
    86400000
  )
  ```

**Regras de validação**

Condições entre campos. Precisam valer em um único lugar, para que o formulário, a importação CSV e o que a IA propuser passem pela mesma verificação.

- **Quando** `r.basis === 'Einwilligung (Art. 6 I a)'` → **Então** `note`
  **Mensagem:** „Bei einer Einwilligung gehört in die Notiz, wie und wo sie eingeholt wird.“
- **Quando** `r.thirdCountry === 'ja'` → **Então** `processor`
  **Mensagem:** „Bei einem Drittlandtransfer muss stehen, wer dort verarbeitet.“
- **Quando** `r.status === 'freigegeben'` → **Então** `purpose`, `categories`, `retention`, `reviewed`
  **Mensagem:** „Freigeben lässt sich nur, was Zweck, Datenkategorien, Löschfrist und Prüfdatum hat.“
- **Quando** `r.risk === 'hoch'` → **Então** `note`
  **Mensagem:** „Ein hohes Risiko braucht eine Begründung — es kann eine Folgenabschätzung auslösen.“

## Painel

Blocos sobre todo o conjunto de registros, não sobre a visão filtrada.

- Um número: **Verarbeitungen** — a quantidade de registros · „im Verzeichnis“
- Um número: **Prüfung überfällig** — a quantidade de registros (apenas registros que atendem a um filtro): `isOverdue(r)` · „nie oder vor über einem Jahr“
- Um número: **Offene Fragen** — a quantidade de registros (apenas registros que atendem a um filtro): `r.basis === 'noch zu klären' || r.thirdCountry === 'unklar'` · „Rechtsgrundlage oder Drittland unklar“
- Um anel por valor de `status`
- Barras por valor de `area`, medindo a quantidade de registros — **Verarbeitungen je Bereich**
- Barras por valor de `risk`, medindo a quantidade de registros — **Verteilung nach Risiko**

## Captura guiada

Uma sequência curta de passos para quem precisa relatar uma coisa e não conhece a ferramenta. Nada é gravado antes da confirmação do último passo — abandonar não pode deixar rastro.

Título: **Eine Verarbeitung melden**

> Fünf kurze Schritte. Wenn Sie etwas nicht wissen, lassen Sie es leer — ein unvollständiger Eintrag ist besser als keiner. Gespeichert wird erst am Ende.

1. **Passo 1** — Was und wer: campos: `name`, `area`, `contact`
2. **Passo 2** — Zweck und Daten: campos: `purpose`, `subjects`, `categories`
3. **Passo 3** — Rechtsgrundlage: campos: `basis`, `note`
4. **Passo 4** — Wo liegt es: campos: `system`, `processor`, `thirdCountry`, `retention`
5. **Passo 5** — Risiko: campos: `risk`
   somente quando: `drafts.records?.subjects === 'Beschäftigte' || drafts.records?.subjects === 'Bewerberinnen und Bewerber' || drafts.records?.thirdCountry === 'ja'`
6. **Passo 6** — Prüfen: resumo gerado a partir do esquema

Tela final: “Danke — das ist aufgenommen. Bitte die Datei speichern und zurücksenden.”

## Padrões

Defina em `DEFAULT_SETTINGS`, `DEFAULT_COLORS` e `DEFAULT_HOME` em `src/app.jsx`.

- Título: **Verarbeitungsverzeichnis**
- Subtítulo: Art. 30 DSGVO — gemeldet von den Fachbereichen
- Nome do arquivo: `verarbeitungsverzeichnis`
- Versão: `1.0`
- Idioma da interface: `de`
- Abre como: captura guiada (a lista fica oculta)
- Cores: `accent` #3a5a8c · `band` #1b2333 · `flag` #b0472e · `ok` #3a7a5e · `pending` #c08a12

## Página inicial

O aplicativo abre com este texto. É um subconjunto pequeno de Markdown: títulos, listas, citações, negrito, itálico, código embutido e links. Use-o literalmente:

```markdown
# Verzeichnis von Verarbeitungstätigkeiten

Nach **Art. 30 DSGVO** muss fast jedes Unternehmen eines führen. Fast keines führt eines, das den
Namen verdient — und der Grund ist selten Unwille.

Es ist die Erhebung. Die Angaben liegen bei zwölf verschiedenen Leuten: die Bewerbungsmappen bei
der Personalstelle, das Newsletter-Werkzeug im Marketing, die Videoanlage beim Hausmeister. Wer das
zentral ausfüllen will, schreibt zwölf Mails und bekommt neun Antworten.

## Was diese Demo zeigt

Diese Datei ist im **Erfassungsmodus** ausgeliefert: sie öffnet direkt im Meldeformular und zeigt
die Liste gar nicht. Gedacht ist sie zum Weiterschicken — jeder Fachbereich meldet seine eigene
Verarbeitung, speichert und schickt zurück. Die Rückläufer führt man mit *Datei abgleichen*
zusammen.

Umschalten auf das vollständige Werkzeug: **Einstellungen → Anwendung → Öffnet als**.

> Erfundene Einträge, Veranschaulichung der Struktur. Keine Rechtsberatung.
```

## Dados de demonstração

Acrescente 10 registros de demonstração realistas para que o arquivo não esteja vazio ao abrir. Invente-os no estilo dos campos acima; são ilustração, não os dados do usuário. Diga a ele que os próprios dados entram por **Import CSV → replace all**.

## Pronto quando

- `npm run build` produz um único `dist/index.html` autocontido
- `npm test` passa
- o arquivo abre com duplo clique e mostra os registros de demonstração
- os campos calculados mostram valores e as regras recusam um registro que as viole
- as configurações, cores e página inicial correspondem à especificação acima

## Antes de entregar

Decida você, em vez de deixar para o destinatário: defina `copyright` para quem é dono da ferramenta, substitua o link do cabeçalho que aponta para o repositório do openToolbox e desligue `examplePrompts` se o destinatário apenas registra dados. Mencione o contador de aberturas (Configurações → Segurança) na entrega.

---

*Gerado a partir de `examples/gdpr-processing.domain.js`, o código real da [demo ao vivo](https://m-dohmen.github.io/openToolbox/demos/gdpr-processing/). Gerar de novo com `npm run prompts`.*

*Todos os dados da demo são inventados. Ela ilustra a estrutura de uma ferramenta assim — não é aconselhamento jurídico nem prova de conformidade.*
