7.1 KiB
CLAUDE.md — Arbeitsvereinbarung für hd-commerce
Diese Datei ist die verbindliche Kurzanleitung für jede KI (Claude/Cowork/Codex) und jeden Menschen,
die an hd-commerce arbeiten. Vor Code-Änderungen lesen. Sie ergänzt README.md (Feature-Referenz)
und HANDOVER.md (Betrieb/Go-Live).
1. Was das hier ist
hd-commerce ist ein brand-neutrales, wiederverwendbares E-Commerce-Backend (Produkt, kein Einzelprojekt).
Eine Codebasis → beliebig viele Shops, unterschieden nur durch settings + ENV. Die mitgelieferte Demo
heißt „Brittas Nähkiste" und ist nur Beispiel — niemals Demo-spezifische Hacks fest in den Code schreiben.
Leitsatz: Alles, was sich pro Shop unterscheidet, gehört in settings/ENV/DB — nicht in den Quellcode.
2. Stack (nicht ohne Grund wechseln)
- Astro 5 SSR (
output: 'server',@astrojs/nodestandalone,security.checkOrigin: false). - better-sqlite3 (synchron, WAL) — die einzige Datenschicht. Kein ORM, bewusst.
- sharp (WebP), nodemailer (SMTP), stripe (Stripe-SDK; Mollie über
fetch/REST). - Self-hosted Fonts Fraunces + Public Sans (
@fontsource-variable). Kein Google-CDN. Chart.js via cdnjs. - Node 22. Docker
node:22-slim. Port 4321. Persistentes Volume auf/data.
EU/DSGVO-first (HD-Linie): keine US-SaaS-Abhängigkeit ohne Grund. Zahlung Default Mollie, Mail Listmonk/SMTP,
Backup Litestream → Backblaze B2 (EU). Analytics ist first-party (eigene events-Tabelle), kein externer Tracker.
3. Goldene Regeln (die teuren Fehler)
- Preise immer in Cent (Integer). Keine Floats für Geld. Helper:
taxFromGross(gross, rate),shippingFor(country, subtotal),discountAmount(...). - Block-Shape ist FLACH: ein Block ist
{ type, headline, html, image, ... }— NICHT unterdata: {}verschachtelt. Das API-Manifest liest sich missverständlich; maßgeblich sindsrc/components/BlockRenderer.astro+ der Editor. Beim Erzeugen/Ändern vonpages.blocksimmer die flache Form verwenden. - Datenzugriff nur über
src/lib/store-sqlite.js(bzw.store.js-Fassade). Kein SQL verstreut in Seiten. Das ist die Postgres-Exit-Versicherung (Portal-Empfehlung): SQLite-Spezifika hinter der Fassade halten. - Migrationen idempotent: neue Spalten via
ensureColumn(...), neue Tabellen viaCREATE TABLE IF NOT EXISTS, System-Seiten viaensureSystemPages(). Alles läuft bei jedem Boot — muss mehrfach gefahrlos sein. Kein Migrations-Framework. - Geld/Rabatt/Versand serverseitig re-validieren (in
/api/checkout), nie dem Client-Cart-Preis trauen. Gleiches für Varianten-Preise. - Sanitizen: jeglicher roher HTML-Output (richtext/html-Blöcke, Seiten-
body) läuft durchsanitizeHtml()aussrc/lib/sanitize.js. Niemals ungefiltertesset:html. - Secrets (Passwörter, Tokens, API-Keys) gehören in ENV, nie ins Repo, nie in Memory/Doku.
.envist gitignored;.env.examplezeigt nur Platzhalter. - Rollen serverseitig gaten (
owner/redaktion/versand) — nicht nur die Nav ausblenden. Auth insrc/lib/auth.js; Kunden-Session getrennt incustomer-auth.js.
4. Projektkarte (wo liegt was)
src/lib/
store-sqlite.js Datenschicht: Schema, Seed, alle CRUD-/Rechen-Helper (Single Source of Truth)
store.js dünne Fassade über store-sqlite (Import-Stabilität)
auth.js Admin-Session (HMAC-Cookie, scrypt, Rollen, Rate-Limit, resolveSecret/cookieSecure)
customer-auth.js Kunden-Session (Cookie hdc_customer), getrennt vom Admin
payments.js Provider-Abstraktion mollie|stripe|demo (+ publicBase aus X-Forwarded-*/PUBLIC_BASE_URL)
mailer.js listmonk|smtp|Log-Fallback (Tabelle email_log)
sanitize.js sanitizeHtml() — Pflicht für jeden rohen HTML-Output
blocks.js Block-Typ-Definitionen/Defaults
seed.js Demo-Seed-Daten
src/components/BlockRenderer.astro rendert pages.blocks (flache Felder!)
src/middleware.js ADMIN_PATH-Rewrite + Auth-Gate
src/pages/admin/** Admin-UI (Astro-Seiten, rollen-gegatet)
src/pages/api/** Endpunkte (checkout, discount, review, upload, cron/abandoned, payments/webhook, admin/*)
src/pages/{index,shop,produkt/[slug],warenkorb,checkout,suche,merkliste,konto/*,seite/[slug]}.astro Storefront
mcp/ eigenständiger MCP-Server (stdio) über die Admin-API
test/unit.mjs Unit-Tests (Geld/Versand/Rabatt/Sanitizer)
scripts/sync-css.mjs prebuild: CSS-Sync
Dockerfile, docker-entrypoint.sh, litestream.yml Container + optionales Litestream-Backup
5. Entwickeln, testen, bauen
npm install
npm run dev # http://localhost:4321 (Storefront /, Admin /admin)
npm test # Unit-Tests — MUSS grün sein vor jedem Commit (nutzt temporäre DB)
npm run build && node ./dist/server/entry.mjs # Produktiv-Lauf lokal prüfen
- Vor jedem Commit
npm test. Neue Geld-/Rabatt-/Versand-/Sanitizer-Logik bekommt einen Test dazu. - Erst-Login lokal mit
ADMIN_EMAIL/ADMIN_PASSaus.env. ADMIN_PATHtesten, wenn an Auth/Middleware angefasst wird (Defaultadmin; abweichend ⇒/adminmuss 404 sein).
6. Deploy (Coolify) — und die Stolpersteine
Deploy via Coolify (Docker-Build aus dem Repo). Nach jedem Deploy gilt:
- App
control restartausführen. Rolling-Updates lassen zeitweise Altcontainer stehen → sonst gemischte 401/404/502. - Verifizieren mit cache-bustendem
curl(nicht WebFetch — cacht): Storefront 200, Login 200, ein API-Call. - Coolify-Gotchas:
application create_publicverwirft den Git-Host → danachapplication updatemit vollerhttps://till:TOKEN@…-URL.- Änderung von
ports_exposesregeneriert die Traefik-Labels nicht → bei Port-Wechselcustom_labels(base64) manuell setzen. - Domain-Wechsel http→https regeneriert die Labels (anders als ports_exposes) → danach restart gegen Altcontainer.
- Migrationen brauchen keinen Sonderschritt — sie laufen idempotent beim Boot (siehe Regel 4).
- Sandbox-Hinweis (Cowork): der FUSE-Mount erlaubt kein
rm/Symlinks → in/tmpklonen/bauen, nicht im Mount. Push braucht Tills Gitea-Token (anonymer Clone ist read-only).
7. Versionierung
package.json#version + sprechende Commit-Message pro Feature-Stufe (v2.4: …). Aktueller Stand: 2.4 (Medien/WebP, Varianten-Matrix, Litestream, intelligentere Analytics). Bei Schema-/ENV-Änderung: README-Tabelle, .env.example und HANDOVER.md mitziehen.
8. „Selbst bauen vs. kaufen" — Leitplanke
Eigenbau ist gerechtfertigt, weil hd-commerce ein mehrfach ausrollbares HD-Produkt ist (Wartung amortisiert über die Care-Abo-Basis). Für einen einzelnen 08/15-Shop bleibt Shopware/Medusa/Snipcart pragmatischer. Halte den Code deshalb generisch und wartungsarm — jede Demo-Sonderlocke und jede SQLite-Spezifik außerhalb der Store-Fassade erhöht genau die laufende Wartung, die das Produkt rechtfertigen muss. Belegte Einordnung: Portal-Research „SQLite-Eigenbau-Commerce — realistisch oder Overkill?".