Files
business-card-scanner/CLAUDE.md
Lucas Orth ab993e98e1 Visitenkarten-Scanner: Stapelscan, Extraktion, Übersicht, vCard-Export
Selbst gehostete PWA, die Visitenkarten von einem Foto freistellt, ausliest
und als Kontakt bereitstellt.

- Stapelscan: OpenCV findet die Kartenrechtecke über mehrere Binärmasken,
  entzerrt sie perspektivisch und schneidet sie einzeln aus. Ohne Fund gilt
  das ganze Foto als eine Karte.
- Extraktion: ein Aufruf je Zuschnitt an das Vision-Modell mit
  JSON-Schema. Kein vorgeschaltetes OCR - das würde Layout und
  Schriftgrößen wegwerfen, aus denen die Feldzuordnung entsteht.
- Metadaten: Aufnahmezeit und GPS aus den EXIF-Daten des Fotos, Ortsname
  über Nominatim, Browserstandort nur als Rückfallebene.
- Übersicht mit Volltextsuche und Filtern, Detailansicht mit Korrekturmaske.
- Notizfeld je Karte, Erinnerungen per Mail inklusive Nachholen verpasster
  Termine nach einem Neustart.
- vCard 3.0 einzeln und als Sammeldatei, Karte gilt danach als exportiert.
- Anmeldung über ein Passwort, Sitzung als signiertes Cookie.
- Deployment per Tag-Push nach den Konventionen in DEPLOY.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 11:45:56 +02:00

4.8 KiB

CLAUDE.md

Behavioral guidelines to reduce common LLM coding mistakes. Merge with project-specific instructions as needed.

Tradeoff: These guidelines bias toward caution over speed. For trivial tasks, use judgment.

1. Think Before Coding

Don't assume. Don't hide confusion. Surface tradeoffs.

Before implementing:

  • State your assumptions explicitly. If uncertain, ask.
  • If multiple interpretations exist, present them - don't pick silently.
  • If a simpler approach exists, say so. Push back when warranted.
  • If something is unclear, stop. Name what's confusing. Ask.

2. Simplicity First

Minimum code that solves the problem. Nothing speculative.

  • No features beyond what was asked.
  • No abstractions for single-use code.
  • No "flexibility" or "configurability" that wasn't requested.
  • No error handling for impossible scenarios.
  • If you write 200 lines and it could be 50, rewrite it.

Ask yourself: "Would a senior engineer say this is overcomplicated?" If yes, simplify.

3. Surgical Changes

Touch only what you must. Clean up only your own mess.

When editing existing code:

  • Don't "improve" adjacent code, comments, or formatting.
  • Don't refactor things that aren't broken.
  • Match existing style, even if you'd do it differently.
  • If you notice unrelated dead code, mention it - don't delete it.

When your changes create orphans:

  • Remove imports/variables/functions that YOUR changes made unused.
  • Don't remove pre-existing dead code unless asked.

The test: Every changed line should trace directly to the user's request.

4. Goal-Driven Execution

Define success criteria. Loop until verified.

Transform tasks into verifiable goals:

  • "Add validation" → "Write tests for invalid inputs, then make them pass"
  • "Fix the bug" → "Write a test that reproduces it, then make it pass"
  • "Refactor X" → "Ensure tests pass before and after"

For multi-step tasks, state a brief plan:

1. [Step] → verify: [check]
2. [Step] → verify: [check]
3. [Step] → verify: [check]

Strong success criteria let you loop independently. Weak criteria ("make it work") require constant clarification.


These guidelines are working if: fewer unnecessary changes in diffs, fewer rewrites due to overcomplication, and clarifying questions come before implementation rather than after mistakes.


Projekthinweise

Sprache

Code-Kommentare, Docstrings, Oberflaeche und Commit-Nachrichten auf Deutsch. Bezeichner im Code auf Englisch.

Deployment

Diese App wird per Tag-Push deployt, nicht manuell hochgeladen. Die verbindlichen Konventionen stehen in DEPLOY.md. Vor Aenderungen an Dockerfile, docker-compose.yml oder .gitea/workflows/ dort nachsehen.

Kurzfassung der Regeln, die man leicht bricht:

  • Kein ports: im Compose. Der Proxy erreicht den Container ueber das Netz nginx-proxy-manager_default unter seinem container_name.
  • name: im Compose ist Pflicht (fester Projektname), sonst legt der CI-Job einen zweiten Stack an.
  • Keine relativen Bind-Mounts. Compose laeuft im Job-Container, der Pfad zeigt auf dem Host ins Leere. Persistente Daten in named volumes mit festem name:.
  • Healthcheck ist Pflicht, der Deploy nutzt ihn als Gate. Hier zeigt er auf /healthz. Abweichung von der Vorlage: python -c statt node -e, weil das Image kein Node enthaelt.
  • Secrets kommen aus dem Repo-Secret DOTENV, nie in die Compose-Datei.
  • Tests laufen im Workflow vor dem Deploy-Schritt.

Entscheidungen, die nicht aus dem Code hervorgehen

Kein separater OCR-Schritt. Das Kartenbild geht direkt an das Vision-Modell. Tesseract vorzuschalten wuerde Layout und Schriftgroessen wegwerfen - genau die Information, aus der die Feldzuordnung entsteht.

OpenCV macht die Geometrie, das Modell den Inhalt. Bounding Boxes vom Modell zu erfragen waere naheliegend, ihre Koordinaten sind aber zu ungenau fuer saubere Zuschnitte. Umgekehrt kann OpenCV nichts lesen.

Das ganze Stapelfoto in einem Aufruf funktioniert nicht. Die API skaliert grosse Bilder herunter; jede Karte landet dann bei ein paar hundert Pixeln Breite, und Telefonnummern in 7-Punkt-Schrift sind darin nicht mehr lesbar. Deshalb ein Aufruf je Zuschnitt.

EXIF schlaegt Browserstandort. Der Zeitpunkt und Ort des Fotos sind verlaesslicher als die des Uploads.

Serverseitige Speicherung statt Offline-First. Es gibt ohnehin einen Server (fuer den API-Schluessel), damit ist SQLite plus Bilder auf der Platte einfacher als IndexedDB mit Synchronisation.

Die 180-Grad-Lage einer Karte ist geometrisch nicht bestimmbar. Bleibt die Extraktion leer, wird einmal gedreht nachgefasst.

Modellwahl

Standard ist claude-opus-5, ueberschreibbar per ANTHROPIC_MODEL. Die Extraktion laeuft mit output_config.effort: "low" - reines Ablesen, keine Denkarbeit - und mit strukturiertem JSON-Schema statt freiem Text.