3.3 KiB
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 derauth-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.jsexportiertquery(text, params)undpool. 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.jsfü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 materialisiertpair_categories. ⚠️ BrauchtANTHROPIC_API_KEYund verursacht echte LLM-Kosten — auch lokal beinpm 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_categorieswird daraus abgeleitet (src/lib/pairCategories.jsderivePairCategories) — beim Pair-Publish (routes/pairs.js,routes/pipeline.js) und im Job.GET /auth/statsliefert daraus die Punkte je Kategorie fürs Profil;GET /auth/meliefertlanguage_target_greeting(Spaltelanguages.greeting, de/en/sv geseedet). Async-Batch-Status liegt incategory_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 inindex.jsdurchreichen, nicht selbst 500en. - Listen-Endpoints:
limit/offsetaus Query,limithart begrenzen (z. B.Math.min(parseInt(limit), 500)). - Status-Felder gegen eine
STATUSES-Whitelist prüfen → bei Verstoß400. - Sprachen-Suffixe:
_de,_en,_sv._seist veraltet (falscher ISO-639-1-Code) und wird beim Boot zu_svumbenannt — niemals neue_se-Spalten anlegen.
Auth (zwei Pfade, siehe src/middleware/auth.js)
- Statische Tokens aus
API_TOKENS(komma-separiert) → Server-zu-Server / Admin, keine Rollenprüfung. - JWT aus
/auth/login·/auth/register. Rolleend-userbekommt auf allen/api/*bewusst 403 (App-Gating).
Öffentlich (ohne Auth): GET /health, /auth/*.
Konfig über .env (siehe .env.example). Deployment via Coolify/Docker.