• TypeScript 96.8%
  • Dockerfile 1.5%
  • JavaScript 0.9%
  • CSS 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Stefan Huber 5b12fb212d Add rate limiting for login and registration
In-memory Rate-Limiter (ausreichend für eine einzelne App-Instanz):
Login max. 5 Versuche pro Konto und 20 pro Besucher innerhalb von
15 Minuten, Registrierung max. 5 Versuche pro Besucher und Stunde.
Schützt vor automatisiertem Durchprobieren von Passwörtern bzw. des
Einladungscodes. Besucher werden über X-Forwarded-For identifiziert,
den ein Reverse Proxy (Caddy/nginx) setzen muss.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-20 14:48:28 +02:00
prisma Add recipe app: auth, CRUD, tags, ratings, print view, AI photo import 2026-09-20 12:23:30 +02:00
public Add recipe app: auth, CRUD, tags, ratings, print view, AI photo import 2026-09-20 12:23:30 +02:00
src Add rate limiting for login and registration 2026-09-20 14:48:28 +02:00
.env.example Gate registration behind an optional invite code 2026-09-20 14:42:46 +02:00
.gitignore Add GPU-free CPU-OCR pipeline (Tesseract) for server hosting 2026-09-20 13:35:38 +02:00
AGENTS.md Initial commit from Create Next App 2026-09-20 12:00:30 +02:00
CLAUDE.md Initial commit from Create Next App 2026-09-20 12:00:30 +02:00
docker-compose.yml Gate registration behind an optional invite code 2026-09-20 14:42:46 +02:00
Dockerfile Add recipe app: auth, CRUD, tags, ratings, print view, AI photo import 2026-09-20 12:23:30 +02:00
eslint.config.mjs Initial commit from Create Next App 2026-09-20 12:00:30 +02:00
next.config.ts Add recipe app: auth, CRUD, tags, ratings, print view, AI photo import 2026-09-20 12:23:30 +02:00
package-lock.json Add GPU-free CPU-OCR pipeline (Tesseract) for server hosting 2026-09-20 13:35:38 +02:00
package.json Add GPU-free CPU-OCR pipeline (Tesseract) for server hosting 2026-09-20 13:35:38 +02:00
postcss.config.mjs Initial commit from Create Next App 2026-09-20 12:00:30 +02:00
prisma7.config.ts Add recipe app: auth, CRUD, tags, ratings, print view, AI photo import 2026-09-20 12:23:30 +02:00
README.md Add rate limiting for login and registration 2026-09-20 14:48:28 +02:00
tsconfig.json Initial commit from Create Next App 2026-09-20 12:00:30 +02:00

Isis Rezepte

Eine private Rezeptsammlung: Rezepte per Foto (z.B. Instagram-Screenshot) einlesen lassen, in einer einheitlichen Form speichern, mit Tags versehen, bewerten und ausdrucken.

Was die App kann

  • Login für mehrere Personen (Familie), gemeinsame Rezeptsammlung
  • Rezept per Foto hochladen → KI liest Zutaten & Zubereitung automatisch aus
  • Rezepte manuell anlegen/bearbeiten, mit Tags versehen
  • Durchsuchbar nach Titel, Zutat und Tag
  • 5-Sterne-Bewertung pro Person
  • Saubere Druckansicht pro Rezept

Lokal entwickeln

Voraussetzung: Node.js 22+, Docker.

docker compose up -d db        # lokale Postgres-Datenbank starten
npx prisma migrate dev         # Datenbankschema anlegen
npm run dev                    # App unter http://localhost:3000

.env ist bereits für die lokale Postgres-Instanz aus docker-compose.yml vorkonfiguriert.

Foto-Erkennung: drei austauschbare Varianten

Gesteuert über RECIPE_AI_PROVIDER in .env:

Wert Wie es funktioniert Braucht GPU? Kosten
ollama (lokaler Dev-Standard) Ein lokales Bild-Modell über Ollama liest das Foto direkt aus. Am genauesten der beiden kostenlosen Optionen. Ja (oder zumindest viel RAM) kostenlos
tesseract (empfohlen für Server ohne GPU) Reine CPU-Texterkennung (Tesseract, kein KI-Modell) liest den Text aus dem Bild, danach bringt ein kleiner Text-KI-Schritt (RECIPE_STRUCTURE_PROVIDER) das Ergebnis in Form. Läuft auf jedem normalen Server. Nein kostenlos (bei RECIPE_STRUCTURE_PROVIDER=ollama) oder Cent-Bereich (bei =anthropic)
anthropic Die Claude API liest das Foto direkt aus. Am zuverlässigsten, aber kostenpflichtig. Nein Cent-Bereich pro Rezept

Für lokale Entwicklung auf diesem Rechner ist ollama voreingestellt, da hier bereits eine passende GPU/Ollama-Installation vorhanden ist – das funktioniert aber nur, solange die App auch auf diesem Rechner läuft.

Sobald die App auf einem fremden Server ohne GPU läuft (z.B. bei deinem Freund), auf tesseract umstellen:

RECIPE_AI_PROVIDER="tesseract"
RECIPE_STRUCTURE_PROVIDER="ollama"
OLLAMA_BASE_URL="https://ai.fidefi.de"   # oder eine andere erreichbare eigene Ollama-Instanz
OLLAMA_TEXT_MODEL="gemma4:e4b"

Der Text-Strukturierungsschritt (RECIPE_STRUCTURE_PROVIDER) kann dabei entweder auf eine eigene, öffentlich erreichbare Ollama-Instanz zeigen (kostenlos, aber nur verfügbar solange dieser Rechner läuft und erreichbar ist) oder auf die Claude API:

RECIPE_STRUCTURE_PROVIDER="anthropic"
ANTHROPIC_API_KEY="..."
ANTHROPIC_TEXT_MODEL="claude-haiku-4-5-20251001"

(Kostenloses Anthropic-Konto unter https://console.anthropic.com/. Da hier nur Text statt Bild verarbeitet wird, sind die Kosten pro Rezept noch geringer als bei RECIPE_AI_PROVIDER="anthropic".)

Deployment (für Hosting durch Dritte)

Die App ist komplett in Docker verpackt und braucht nur:

cp .env.example .env
# .env ausfüllen: NEXTAUTH_SECRET, POSTGRES_PASSWORD, ANTHROPIC_API_KEY, NEXTAUTH_URL
docker compose up -d --build

Das startet zwei Container:

  • db: PostgreSQL, Daten liegen dauerhaft im Docker-Volume db_data
  • app: Die Next.js-App, wendet beim Start automatisch alle Datenbank-Migrationen an

Hochgeladene Rezeptfotos landen im Docker-Volume uploads.

Wichtig für den Betrieb hinter einer echten Domain:

  • NEXTAUTH_URL muss auf die öffentliche URL zeigen (z.B. https://rezepte.example.com)
  • Am besten einen Reverse Proxy (z.B. Caddy oder nginx) mit TLS vor den app-Container schalten, Port 3000 muss dann nicht mehr nach außen offen sein. Caddy und nginx setzen den X-Forwarded-For-Header standardmäßig – darauf verlässt sich das eingebaute Rate-Limiting (siehe unten), um Anmelde-/Registrierungsversuche pro Besucher statt pauschal zu begrenzen
  • REGISTRATION_CODE setzen (siehe unten), sonst kann sich jede/r im Internet ein Konto anlegen

Umgebungsvariablen

Variable Zweck
DATABASE_URL Verbindung zur Postgres-Datenbank
NEXTAUTH_URL Öffentliche URL der App
NEXTAUTH_SECRET Geheimer Schlüssel für Sessions, erzeugen mit openssl rand -base64 32
REGISTRATION_CODE Code, den man bei /register zusätzlich eingeben muss. Frei wählbar, nur an die Familie weitergeben. Leer = offene Registrierung für alle im Internet
RECIPE_AI_PROVIDER tesseract (CPU-OCR, für Server ohne GPU empfohlen), ollama (lokales Bild-Modell) oder anthropic (Cloud, kostenpflichtig)
TESSERACT_LANG Nur bei RECIPE_AI_PROVIDER=tesseract: Sprachen für die Texterkennung, z.B. deu+eng
RECIPE_STRUCTURE_PROVIDER Nur bei RECIPE_AI_PROVIDER=tesseract: ollama oder anthropic für den Text-Strukturierungsschritt
OLLAMA_BASE_URL / OLLAMA_VISION_MODEL / OLLAMA_TEXT_MODEL Für RECIPE_AI_PROVIDER=ollama bzw. RECIPE_STRUCTURE_PROVIDER=ollama relevant
ANTHROPIC_API_KEY / ANTHROPIC_TEXT_MODEL Nötig bei RECIPE_AI_PROVIDER=anthropic oder RECIPE_STRUCTURE_PROVIDER=anthropic. Kostenloses Konto unter https://console.anthropic.com/
POSTGRES_PASSWORD Passwort der Datenbank (nur für docker-compose)

Neue Nutzer anlegen

Es gibt keine Einladungs-Verwaltung mit Admin-Oberfläche: Jede/r, der/die den REGISTRATION_CODE kennt, kann sich unter /register selbst ein Konto anlegen. Den Code also nur privat weitergeben (z.B. per WhatsApp), nicht öffentlich posten.

Sicherheit beim Betrieb im Internet – Checkliste

  • REGISTRATION_CODE gesetzt (siehe oben) – sonst kann sich jede/r registrieren
  • NEXTAUTH_SECRET einzigartig und lang (mit openssl rand -base64 32 erzeugt, nicht das Beispiel aus dieser Anleitung wiederverwenden)
  • POSTGRES_PASSWORD ein echtes, langes Passwort (nicht rezepte)
  • Zugriff nur über HTTPS (Reverse Proxy mit TLS, siehe oben) – sonst werden Passwörter und Sessions unverschlüsselt übertragen
  • Reverse Proxy setzt X-Forwarded-For weiter (bei Caddy/nginx Standard) – sonst wirkt das Rate-Limiting für alle Besucher wie eine einzige Person
  • .env wird nicht öffentlich geteilt/committed (ist bereits in .gitignore)

Was die App bereits automatisch absichert: Passwörter werden gehasht gespeichert (nie im Klartext), alle Rezept-Seiten verlangen Login, Sessions laufen über signierte, httpOnly-Cookies. Anmeldung ist zusätzlich pro Konto auf 5 und pro Besucher auf 20 Versuche innerhalb von 15 Minuten begrenzt, Registrierung auf 5 Versuche pro Stunde und Besucher – beides schützt vor automatisiertem Durchprobieren von Passwörtern bzw. des Einladungscodes.