Komplettes Rework der AI-Studio-Vorlage zu einem produktiven Werkzeug fuer
deutsche AcroForm-Formulare (Reha-Antraege, Arzt-Befundberichte):
- Backend: Express spawnt headless Claude CLI ('claude -p --output-format json'
via stdin-Pipe). Prompt enthaelt die Feldnamen als Ziel-Schema plus die
Arbeitsregeln (Stichwortstil, feste Zeichen-Kaestchen ohne Leerzeichen,
Vordrucke respektieren, keine geratenen Werte, nur medizinisch).
- PDF-Handling: pdfjs-dist statt pdf-lib — pdf-lib scheitert an verschluesselten
Object-Streams in DRV-Formularen. annotationStorage + saveDocument, kein
Flatten. Worker-Patch zur Laufzeit forciert Auto-Size und schwarze Schrift.
- Multi-Source-Upload: beliebig viele PDFs/Bilder + optional Freitext.
- Design: Kanagawa Design System (Preset aus ../kanagawa-design-system),
Tailwind lokal gebaut statt CDN, Dark/Light-Toggle, Progress-Indicator.
- Deployment: Multi-Stage-Dockerfile, docker-compose in matrix_default-Netz,
Claude-Credentials vom Host per Volume. PLAN.md + AGENTS.md (Alex-Schema).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
135 lines
5.5 KiB
Markdown
135 lines
5.5 KiB
Markdown
# Rentenversicherer: AcroForm Auto-Fill
|
|
|
|
Purpose
|
|
|
|
- Browser-UI nimmt ein Original-PDF (mit AcroForm-Feldern) und ein
|
|
Quelldokument (Scan, Brief, Ausweis, o.ä.) entgegen.
|
|
- Ein lokales Node-Backend ruft die Claude Code CLI (`claude -p`) als
|
|
Subprozess auf, übergibt beide Dateien und die Liste der AcroForm-
|
|
Feldnamen. Claude liefert strukturiertes JSON mit `{feldname -> wert}`.
|
|
- User reviewt/korrigiert die Werte im Browser, lädt das ausgefüllte
|
|
PDF runter.
|
|
- Das heruntergeladene PDF bleibt AcroForm (keine Flattening-Operation).
|
|
Im PDF-Reader nachträglich manuell editierbar — als hätte ein Mensch
|
|
es ausgefüllt.
|
|
|
|
## Scope
|
|
|
|
- Frontend: React/Vite, Upload + Review-Panel + Live-Preview + Download.
|
|
- Backend: Minimaler Node-Server, eine Route `POST /api/process`.
|
|
Spawnt `claude -p --output-format json` mit Temp-Files und einem
|
|
Prompt, der die Ziel-Feldnamen enthält.
|
|
- PDF-Handling: `pdfjs-dist` client-side — Widgets sammeln, Werte via
|
|
`annotationStorage.setValue(id, { value })` setzen, `doc.saveDocument()`
|
|
schreibt ein PDF ohne Flatten. (pdf-lib wurde getestet, scheitert aber
|
|
an komprimierten Object-Streams in DRV-Formularen.)
|
|
- Lokaler Single-User-Betrieb (localhost).
|
|
|
|
## Out of scope
|
|
|
|
- Gemini, Anthropic SDK, Claude Agent SDK — nur die CLI als Subprozess.
|
|
- Visual-Overlay-Modus mit Koordinaten für gescannte Flat-PDFs.
|
|
- Form-Overlay-View (Drag & Drop) im Review-Panel.
|
|
- Authentifizierung, Multi-User, Persistenz, Datenbank.
|
|
- PDF-Flattening, Signaturen, Formular-Editor, Seiten-Modifikation.
|
|
- Cloud-Deployment.
|
|
|
|
## Architektur
|
|
|
|
```
|
|
Browser (Vite :5173)
|
|
│ multipart upload: form.pdf + source.pdf + fieldNames[]
|
|
▼
|
|
Node Server (:3001, Express)
|
|
│ 1. schreibt beide PDFs in Temp-Verzeichnis
|
|
│ 2. spawnt:
|
|
│ claude -p --output-format json \
|
|
│ --permission-mode bypassPermissions \
|
|
│ "<Prompt mit Feldliste + Pfaden>"
|
|
│ 3. parst stdout → extrahiert JSON aus result-Feld
|
|
│ 4. löscht Temp-Verzeichnis
|
|
▼
|
|
Browser bekommt { fields: [...], summary: "..." }
|
|
│ User reviewt/korrigiert
|
|
│ pdfjs-dist: annotationStorage.setValue + saveDocument
|
|
│ (kein flatten; AcroForm bleibt erhalten)
|
|
▼
|
|
Download
|
|
```
|
|
|
|
## Repo-Layout
|
|
|
|
```
|
|
Rentenversicherer/
|
|
├── App.tsx # Upload → Process → Review Flow
|
|
├── components/
|
|
│ ├── FileUpload.tsx
|
|
│ └── ReviewPanel.tsx # nur List-View, Overlay-View entfernt
|
|
├── services/
|
|
│ ├── api.ts # Frontend-Client für /api/process
|
|
│ └── pdfService.ts # getPdfFields + createFilledPdf via pdfjs-dist
|
|
├── server/
|
|
│ ├── index.ts # Express: static + /api/process
|
|
│ └── claudeRunner.ts # spawn('claude', ['-p', ...]); JSON-Extraktion
|
|
├── types.ts
|
|
├── vite.config.ts # dev-proxy /api → :3001
|
|
├── package.json # dev-script: vite + server parallel
|
|
├── tsconfig.json # shared tsconfig für Client + Server
|
|
├── .gitignore
|
|
├── PLAN.md
|
|
├── AGENTS.md
|
|
└── README.md
|
|
```
|
|
|
|
## Workflow (User-Sicht)
|
|
|
|
1. Original-PDF hochladen. Client scannt AcroForm-Feldnamen
|
|
mit `getPdfFields()` und zeigt die Anzahl als Hinweis.
|
|
2. Quelldokument hochladen (PDF oder Bild).
|
|
3. "Analyze & Fill" klicken.
|
|
4. Browser sendet beide Dateien + Feldliste an `POST /api/process`.
|
|
5. Server schreibt Dateien ins Temp-Verzeichnis, baut Prompt, spawnt
|
|
Claude CLI, parst JSON, antwortet.
|
|
6. Review-Panel zeigt `{label, value, validation}`-Paare — User korrigiert,
|
|
markiert als verified.
|
|
7. "Download" → `createFilledPdf` setzt die Werte via pdfjs
|
|
`annotationStorage` und schreibt mit `doc.saveDocument()`.
|
|
**Kein** Flatten.
|
|
8. User öffnet das runtergeladene PDF → Felder sind gefüllt und
|
|
bleiben klick- und editierbar in Acrobat/Reader.
|
|
|
|
## Umsetzungsschritte
|
|
|
|
1. `package.json`: Server-Deps (`express`, `multer`, `tsx`,
|
|
`concurrently`, typings) ergänzen, Scripts aktualisieren.
|
|
2. `server/claudeRunner.ts`: `spawn` mit Windows-kompatiblem Aufruf,
|
|
stdout buffern, `--output-format json` Result-Wrapper entpacken,
|
|
inneres JSON parsen.
|
|
3. `server/index.ts`: Express-App, `multer` für Upload, Temp-Dir pro
|
|
Request, `finally`-Cleanup.
|
|
4. `vite.config.ts`: `server.proxy['/api']` nach `http://localhost:3001`.
|
|
5. `services/api.ts` als Frontend-Client; `services/geminiService.ts`
|
|
löschen.
|
|
6. `services/pdfService.ts`: auf `pdfjs-dist` umgestellt.
|
|
`getPdfFields` iteriert über Pages + Widget-Annotations,
|
|
`createFilledPdf` nutzt `annotationStorage` + `saveDocument`.
|
|
7. `components/ReviewPanel.tsx`: Form-Overlay-View entfernen, nur
|
|
List-View behalten, Koordinaten-Logik raus.
|
|
8. `App.tsx`: Fehlermeldung, falls Ziel-PDF keine AcroForm-Felder hat
|
|
(UI blockiert Upload dann).
|
|
9. Smoke-Test mit
|
|
`G2210-11_Aerztlicher_Befundbericht_Anforderung_WAG.pdf`:
|
|
`npm run dev`, ausfüllen, runterladen, in Acrobat öffnen,
|
|
Feld editieren können.
|
|
|
|
## Notes
|
|
|
|
- Claude CLI wird über dein bestehendes Login authentifiziert. Kein
|
|
API-Key im Code oder in Env-Dateien.
|
|
- `claude -p` braucht `--permission-mode bypassPermissions`, damit das
|
|
Read-Tool ohne User-Prompt auf die Temp-Files zugreifen darf.
|
|
- Temp-Verzeichnisse liegen unter `os.tmpdir()` und werden nach jedem
|
|
Request gelöscht. Kein persistenter Upload-Ordner.
|
|
- Windows-Pfad-Konvention: Server nutzt `path.join`, arbeitet also
|
|
plattformneutral. Der Claude-CLI-Aufruf läuft via `shell: true` unter
|
|
PowerShell (vgl. globale CLAUDE.md).
|