- feature_search: Storefront-Header-Suche + /suche (SSR, SQLite LIKE, case-insensitiv; Name/Kurz/Desc/Material/Kategorie), Treffer als Karten, Leer-Zustand - feature_wishlist: Herz-Button auf Karten/PDP (localStorage, public/wishlist.js) + /merkliste - feature_accounts: getrennte Kunden-Session (Cookie hdc_customer, scrypt), /konto/registrieren|anmelden|abmelden, /konto (Bestellhistorie+Adressbuch), Tabelle customer_addresses, Checkout-Vorbefuellung + orders.customer_id-Zuordnung; Gast-Checkout bleibt - feature_reviews: Tabelle reviews (1-5, Moderation), /api/review (approved=0), PDP-Anzeige Durchschnitt+Reviews + aggregateRating-JSON-LD, Admin /bewertungen (Freigeben/Verbergen/Loeschen) + Nav-Zaehler - feature_abandoned_cart: Tabelle abandoned_carts, /api/cart-capture beim Checkout-Start, /api/cron/abandoned (CRON_TOKEN) sendet Erinnerungsmail (Mailer/Log) + reminded=1, recovered=1 bei Bestellung; Status in Einstellungen - Gating: Flag aus => Storefront-Elemente weg, Routen 302/404, Admin-Nav-Punkt entfaellt; KEIN 'in Vorbereitung' mehr - API/MCP: reviews CRUD + abandoned_carts (read) in admin-api + ai-admin.txt + MCP-Tools; Manifest v2.3 - README + .env.example (CRON_TOKEN, ABANDONED_AFTER_MINUTES); 16 neue Unit-Tests (Suche/Review-Avg/Kunden/Abandoned)
hd-commerce
hd-commerce ist ein eigenständiges, brand-neutrales E-Commerce-Backend von Heidrich Digital: eine wiederverwendbare Astro-SSR-Anwendung mit Commerce-Engine (SQLite), Session-gesichertem Admin, Visual-Block-Builder, KI-/MCP-Editierbarkeit, JSON-API und einem schlanken, neutralen Demo-Storefront.
Die mitgelieferte Demo-Instanz heißt „Brittas Nähkiste" (Kurzwaren/Nähbedarf) und dient nur als Beispiel. Name, Akzentfarbe, Texte und Logo-Wortmarke sind über die Einstellungen frei anpassbar — derselbe Code läuft für beliebige Shops.
Features
- Storefront (hell, editorial, neutral): Startseite mit Announcement-Bar, Slider, Kategorien, Featured-Produkten und Newsletter; Shop-Katalog; Produktdetailseiten; Warenkorb (localStorage); Checkout; Inhaltsseiten aus der DB — wahlweise klassisch oder über den Block-Builder gestaltet.
- Admin (Premium, „Warmth & Approachability"): Session-Login statt Browser-Basic-Auth, Rollen (Owner/Redaktion/Versand), Command-Palette (⌘K), Toasts, aufgewertetes Dashboard mit KPI-Trends, Sparkline, Aktivitäts-Feed und Schnellaktionen.
- Visual-Block-Builder: Vollbild-Editor mit Block-Liste (Drag/▲▼/duplizieren/löschen), Live-Vorschau (Desktop/Mobil) und Block-Einstellungen. Block-Typen: Hero, Rich-Text, Bild, Galerie, Slider, Feature-Grid, Produkt-Grid, CTA-Banner, Abstand, Roh-HTML.
- KI-Editierbarkeit: token-gesicherte Admin-JSON-API (
/api/admin/*) plus maschinenlesbares Manifest (/api/admin,/ai-admin.txt) und ein MCP-Server (mcp/). - Gutschein-/Rabatt-Engine (v2.1): Codes vom Typ
percent/fixed/freeshippingmit Zeitplan, Mindestbestellwert, Gesamt- und Pro-Kunde-Limit, „geheim" (nicht öffentlich listbar) und „automatisch" (greift ohne Code, wenn Bedingungen erfüllt). Admin-Bereich Rabatte (Owner/Redaktion) mit Status-Badges (Aktiv/Geplant/Abgelaufen/Aufgebraucht/Inaktiv); Storefront-Einlösung im Checkout über/api/discount; serverseitige Re-Validierung in/api/checkout; Stripe-Coupon-Anbindung. Popups können einen Code anzeigen (+ Kopieren-Button) — auch für gezielt verteilte geheime Codes; Popup-Stilemodal/slidein/bar. - Verkaufsfertig-Fundament (v2.2):
- Payment-Abstraktion (
src/lib/payments.js): einheitliche Schnittstelle für Mollie (Default, REST), Stripe und Demo. Provider via Settingpayment_provider/ ENVPAYMENT_PROVIDER, sonst Auto-Wahl nach vorhandenen Keys. Mollie-Webhook unter/api/payments/webhook; ungültiger Key ⇒ sauberer Demo-Fallback statt Fehler. - DACH-Recht: MwSt-Ausweis pro Produkt (
mwst0/7/19), Grundpreis (PAngV) überbase_amount/base_unit/base_price_per; Warenkorb/Checkout zeigen Zwischensumme, enthaltene MwSt (nach Satz gruppiert) und Versand vor dem Bezahlen. - Versandzonen (Tabelle
shipping_zones, Admin „Versand"): länderbasierte Preise mit Gratis-ab-Schwelle; HelpershippingFor(country, subtotal); Checkout berechnet Versand serverseitig neu. - Bestell-/Versandmails (
src/lib/mailer.js): Provider Listmonk (Transactional-API) / SMTP (nodemailer) / Log-Fallback (Tabelleemail_log, Admin „E-Mail-Log"). Gebrandete Bestellbestätigung bei bezahlter Bestellung. - Feature-Flags: Module pro Shop abschaltbar (
feature_newsletter,feature_accounts,feature_reviews,feature_wishlist,feature_abandoned_cart,feature_search) über Admin → Einstellungen → Module; Helperfeature(key).
- Payment-Abstraktion (
- Feature-Module (v2.3): über die jeweiligen Flags ge-gatet — ist ein Flag aus, verschwinden Storefront-Elemente, Routen liefern 302/404 und der Admin-Nav-Punkt entfällt.
- Volltextsuche (
feature_search): Suchfeld im Storefront-Header → Ergebnisseite/suche?q=(SSR, SQLite-LIKE, case-insensitiv über Name/Kurzname/Beschreibung/Material/Kategorie), Treffer als Produktkarten, „keine Treffer"-Zustand. - Merkliste (
feature_wishlist): Herz-Button auf Produktkarten & Detailseite, Speicherung clientseitig (localStorage,public/wishlist.js), Seite/merkliste. - Kundenkonten + Adressbuch (
feature_accounts): eigene Kunden-Session (Cookiehdc_customer, getrennt vom Admin; scrypt-Hash)./konto/registrieren,/konto/anmelden,/konto(Bestellhistorie + Adressbuch),/konto/abmelden. Tabellecustomer_addresses; Checkout füllt die Adresse vor und ordnet die Bestellung dem Konto zu (orders.customer_id). Gast-Checkout bleibt möglich. - Bewertungen (
feature_reviews): Tabellereviews(Sterne 1–5, Moderationapproved). Formular auf der Produktseite (/api/review, speichertapproved=0), Anzeige von Durchschnitt + freigegebenen Reviews, optionaleaggregateRatingim Produkt-JSON-LD. Admin-Bereich Bewertungen (Owner/Redaktion): Freigeben/Verbergen/Löschen, Zähler offener Reviews in der Nav. - Warenkorb-Erinnerung (
feature_abandoned_cart): beim Checkout-Start wird der Warenkorb serverseitig inabandoned_cartsgesichert (/api/cart-capture). Versand-Trigger:POST /api/cron/abandoned(HeaderAuthorization: Bearer <CRON_TOKEN>oder?token=), schickt für fällige, nicht erinnerte Karten eine gebrandete Erinnerungsmail (Mailer/Log-Fallback) und setztreminded=1. Erfolgreiche Bestellung der Adresse setztrecovered=1. Status/Zähler unter Einstellungen. Als Coolify-Scheduled-Task z. B. alle 30 Mincurl -fsS -X POST -H "Authorization: Bearer $CRON_TOKEN" https://shop.example.com/api/cron/abandonedaufrufen.
- Volltextsuche (
- Editierbare, gebrandete 404 (v2.1):
src/pages/404.astrorendert die System-Seite mit Slug404über den Block-Builder. Wird perensureSystemPages()bei jedem Boot idempotent angelegt und ist im Admin unter Inhalte editierbar. - Engine: synchron via
better-sqlite3(WAL), automatisches Seeding beim ersten Start. - First-Party-Analytics: eigene
events-Tabelle, kein externer Dienst (Session = täglich rollender Hash). - Branding konfigurierbar: Shop-Name, Akzentfarbe, Währung u. a. in einer
settings-Tabelle. - Self-hosted Fonts (Fraunces + Public Sans), kein Google-CDN. Chart.js via cdnjs.
Authentifizierung & Rollen
- Session-Login per HTML-Formular (signiertes HMAC-Cookie, „Angemeldet bleiben" = 30 Tage). Passwörter werden mit
node:crypto.scryptSync+ zufälligem Salt gehasht. - Initial-Owner wird beim ersten Boot aus
ADMIN_EMAIL/ADMIN_PASSangelegt; weitere Nutzer im Admin unter Nutzer & Zugänge (Owner-only). - Rollen:
owner(alles),redaktion(Produkte/Inhalte/Marketing/Analytics),versand(nur Bestellungen). Navigation und Seiten werden serverseitig nach Rolle gegated. - Konfigurierbarer Admin-Pfad über
ADMIN_PATH(Defaultadmin, z. B.intern→ Admin unter/intern). Direkter Zugriff auf/adminwird bei abweichendem Pfad mit 404 blockiert. - Audit-Log (Tabelle
audit) protokolliert Create/Update/Delete; Ansicht unter Aktivität (Audit) (Owner). Login-Rate-Limit: nach 5 Fehlversuchen 60 s Sperre pro IP.
Umgebungsvariablen (ENV)
| Variable | Beschreibung | Default |
|---|---|---|
DB_PATH |
Pfad zur SQLite-Datenbank (wird angelegt) | ./data/hdc.db |
ADMIN_EMAIL |
Initial-Owner-E-Mail (erster Boot) | admin@example.com |
ADMIN_PASS |
Initial-Owner-Passwort (erster Boot) | admin |
ADMIN_PATH |
Pfad-Segment des Admin-Bereichs | admin |
SESSION_SECRET |
HMAC-Geheimnis für Session-Cookies | interner Fallback (in Prod setzen!) |
HDC_API_TOKEN |
Bearer-Token für /api/admin/*. Leer ⇒ API gesperrt |
– |
STRIPE_PUBLIC_KEY |
Stripe Publishable Key (optional) | – |
STRIPE_SECRET_KEY |
Stripe Secret Key. Ohne echten Key läuft der Demo-Checkout. | – |
PAYMENT_PROVIDER |
Zahlungsanbieter erzwingen: mollie / stripe / demo. Leer ⇒ Auto-Wahl |
– |
MOLLIE_API_KEY |
Mollie API-Key (test_…/live_…). Ohne gültigen Key Demo-Fallback |
– |
MAIL_PROVIDER |
listmonk / smtp / leer (⇒ Log-Fallback in email_log) |
– |
MAIL_FROM |
Absenderadresse ausgehender Mails | – |
LISTMONK_URL / LISTMONK_USER / LISTMONK_PASS / LISTMONK_TX_TEMPLATE_ID |
Listmonk Transactional-API | – |
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_SECURE |
SMTP-Versand (nodemailer) | – |
CRON_TOKEN |
Bearer-Token für /api/cron/abandoned (Warenkorb-Erinnerung). Leer ⇒ Endpoint gesperrt |
– |
ABANDONED_AFTER_MINUTES |
Alter (Minuten), ab dem eine offene Warenkorb-Karte erinnert wird | 30 |
Siehe .env.example.
Lokal starten
npm install
npm run dev # http://localhost:4321
# oder produktiv:
npm run build
node ./dist/server/entry.mjs
Storefront: / · Admin: /admin (bzw. /${ADMIN_PATH}). Erst-Login mit ADMIN_EMAIL / ADMIN_PASS.
Block-Builder
Jede Seite (pages) hat ein Feld blocks (JSON-Array). Der Vollbild-Editor liegt unter /${ADMIN_PATH}/inhalte/editor/<id> (Button „Editor" in der Seitenliste). Gespeicherte Blöcke werden vom Storefront-Block-Renderer (src/components/BlockRenderer.astro) auf /seite/<slug> ausgegeben.
KI-Editierbarkeit (API)
Token-gesicherte JSON-API unter /api/admin/* (Header Authorization: Bearer <HDC_API_TOKEN>):
GET /api/admin— maschinenlesbares Manifest (Ressourcen, Felder, Block-Typen, Endpunkte).GET /ai-admin.txt— dieselbe Beschreibung als Klartext für LLMs.GET /api/admin/{resource}·GET /api/admin/{resource}/{id}— lesen.POST /api/admin/{resource}— Upsert (mitidoderslug⇒ Update, sonst Create).DELETE /api/admin/{resource}/{id}— löschen.POST /api/admin/pages/{id}/blocks— Block-Array einer Seite setzen.
Schreibbar: products, pages, slides, popups, settings. Nur lesbar: orders, customers. Preise in Cent.
curl -H "Authorization: Bearer $HDC_API_TOKEN" https://shop.example.com/api/admin/products
curl -H "Authorization: Bearer $HDC_API_TOKEN" -X POST https://shop.example.com/api/admin/products \
-H 'Content-Type: application/json' -d '{"name":"Neues Produkt","priceCents":1990,"category":"Test"}'
MCP-Server
Unter mcp/ liegt ein eigenständiger Model-Context-Protocol-Server (stdio), mit dem ein LLM/Agent den Shop über die Admin-API bearbeitet. Tools u. a.: list_products, upsert_product, get_page, update_page_blocks, list_orders, update_settings, create_page. Installation, ENV (HDC_BASE_URL, HDC_API_TOKEN) und Registrierung in Claude/Cowork: siehe mcp/README.md.
Docker / Coolify
docker build -t hd-commerce .
docker run -p 4321:4321 -v hdc-data:/data \
-e ADMIN_EMAIL=admin@example.com -e ADMIN_PASS=geheim \
-e SESSION_SECRET=langes-geheimnis -e HDC_API_TOKEN=token hd-commerce
Das Dockerfile (node:22-slim) baut better-sqlite3 nativ, legt /data an und setzt DB_PATH=/data/hdc.db. Auf Coolify ein persistentes Volume auf /data mounten. HEALTHCHECK prüft /.
Datenmodell
settings (inkl. Feature-Flags & payment_provider), products (inkl. mwst / base_amount / base_unit / base_price_per), orders (inkl. discount_code/discount_cents, tax_cents/shipping_cents/country, payment_provider/payment_id), customers, slides, pages (inkl. blocks; System-Seite 404), popups (inkl. style / discount_id), discounts, discount_redemptions, shipping_zones, email_log, subscribers, events, media, users, audit — alles seed-bar und im Admin pflegbar.
Hinweis: „Brittas Nähkiste" ist nur die mitgelieferte Demo-Instanz. Brand (Name, Farben, Texte) ist über Admin → Einstellungen anpassbar.
Lizenz: MIT (siehe LICENSE).