Files
snakkimo-API/CLAUDE.md

3.3 KiB

CLAUDE.md

REST-API für das snakkimo-Projekt. Node/Express + PostgreSQL (pg, kein ORM), Bild-Assets auf Hetzner Object Storage (S3-kompatibel). Ausführliche API-Doku in README.md.

Befehle

  • npm run dev — lokaler Server mit nodemon (Hot-Reload)
  • npm start — Produktion (node src/index.js)
  • Keine Tests / kein Linter konfiguriert.

Architektur

  • Einstieg: src/index.js — registriert alle Routen, jede /api/*-Route ist mit der auth-Middleware geschützt.
  • Migrationen laufen automatisch beim Boot (src/db-migrate.js), bevor der Server lauscht. Idempotent halten: CREATE TABLE IF NOT EXISTS, Spalten-Renames mit .catch(() => {}). Es gibt kein separates Migrations-Tool — Schema-Änderungen hier eintragen.
  • src/db.js exportiert query(text, params) und pool. Immer parametrisierte Queries ($1, $2 …), nie String-Interpolation von User-Input.
  • src/routes/ — eine Datei pro Entität. src/lib/, src/middleware/, src/s3.js, src/voices.js für geteilte Logik.
  • Hintergrund-Job (Auto-Kategorisierung): src/index.js startet ~30 s nach dem Boot und stündlich runCategorizationTick() (src/lib/classifyWords.js). Er klassifiziert in Pairs verwendete Wörter ohne Kategorie per Anthropic Message Batches API (Haiku, asynchron, ~50 % günstiger) gegen die feste Taxonomie und materialisiert pair_categories. ⚠️ Braucht ANTHROPIC_API_KEY und verursacht echte LLM-Kosten — auch lokal bei npm run dev. Manuell anstoßen: POST /api/categories/auto-assign (?sync=true = sofort/synchron statt Batch, &reset=true = bestehende Zuordnungen verwerfen und neu klassifizieren).
  • Kategorie-Datenfluss: Kategorien hängen an Wörtern (word_categories, feste Taxonomie wird in src/db-migrate.js geseedet). pair_categories wird daraus abgeleitet (src/lib/pairCategories.js derivePairCategories) — beim Pair-Publish (routes/pairs.js, routes/pipeline.js) und im Job. GET /auth/stats liefert daraus die Punkte je Kategorie fürs Profil; GET /auth/me liefert language_target_greeting (Spalte languages.greeting, de/en/sv geseedet). Async-Batch-Status liegt in category_batches.

Konventionen

  • Code-Kommentare auf Deutsch, Code/Bezeichner auf Englisch (dem Bestand folgen).
  • Route-Handler-Muster: async (req, res, next) => { try { … } catch (err) { next(err); } }. Fehler an den zentralen Error-Handler in index.js durchreichen, nicht selbst 500en.
  • Listen-Endpoints: limit/offset aus Query, limit hart begrenzen (z. B. Math.min(parseInt(limit), 500)).
  • Status-Felder gegen eine STATUSES-Whitelist prüfen → bei Verstoß 400.
  • Sprachen-Suffixe: _de, _en, _sv. _se ist veraltet (falscher ISO-639-1-Code) und wird beim Boot zu _sv umbenannt — niemals neue _se-Spalten anlegen.

Auth (zwei Pfade, siehe src/middleware/auth.js)

  1. Statische Tokens aus API_TOKENS (komma-separiert) → Server-zu-Server / Admin, keine Rollenprüfung.
  2. JWT aus /auth/login · /auth/register. Rolle end-user bekommt auf allen /api/* bewusst 403 (App-Gating).

Öffentlich (ohne Auth): GET /health, /auth/*.

Konfig über .env (siehe .env.example). Deployment via Coolify/Docker.