v2.3: Feature-Module live — Suche, Merkliste, Kundenkonten+Adressbuch, Bewertungen, Abandoned-Cart
- 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)
This commit is contained in:
@@ -2,16 +2,16 @@
|
||||
import Admin from '../../../layouts/Admin.astro';
|
||||
import { adminBase } from '../../../lib/auth.js';
|
||||
const base = adminBase();
|
||||
import { getSettings, setSetting, resolvePaymentProvider, FEATURE_KEYS, feature } from '../../../lib/store.js';
|
||||
import { getSettings, setSetting, resolvePaymentProvider, FEATURE_KEYS, feature, abandonedCartStats, countPendingReviews } from '../../../lib/store.js';
|
||||
import { mailerStatus } from '../../../lib/mailer.js';
|
||||
|
||||
const FEATURE_LABELS = {
|
||||
feature_newsletter: ['Newsletter', 'Newsletter-Popup & Anmeldung im Storefront'],
|
||||
feature_accounts: ['Kundenkonten', 'Registrierung & Login für Kund:innen (in Vorbereitung)'],
|
||||
feature_reviews: ['Bewertungen', 'Produktbewertungen (in Vorbereitung)'],
|
||||
feature_wishlist: ['Merkliste', 'Wunschliste / Merken (in Vorbereitung)'],
|
||||
feature_abandoned_cart: ['Warenkorb-Erinnerung', 'Abandoned-Cart-Mails (in Vorbereitung)'],
|
||||
feature_search: ['Suche', 'Produktsuche im Storefront (in Vorbereitung)'],
|
||||
feature_accounts: ['Kundenkonten', 'Registrierung, Login, Bestellhistorie & Adressbuch für Kund:innen; Adresse im Checkout vorbefüllt'],
|
||||
feature_reviews: ['Bewertungen', 'Sterne-Bewertungen auf Produktseiten mit Moderation (Freigabe im Admin)'],
|
||||
feature_wishlist: ['Merkliste', 'Herz-Button auf Produktkarten & Detailseite; Merkliste unter /merkliste (clientseitig)'],
|
||||
feature_abandoned_cart: ['Warenkorb-Erinnerung', 'Begonnene Checkouts speichern & per Mail erinnern (Cron /api/cron/abandoned)'],
|
||||
feature_search: ['Suche', 'Volltextsuche im Storefront-Header mit Ergebnisseite /suche'],
|
||||
};
|
||||
|
||||
let flash = '';
|
||||
@@ -47,6 +47,9 @@ const stripeSet = /^sk_(test|live)_[A-Za-z0-9]{16,}/.test((process.env.STRIPE_SE
|
||||
const providerSetting = s.payment_provider || '';
|
||||
|
||||
const mail = mailerStatus();
|
||||
const acStats = abandonedCartStats();
|
||||
const pendingReviews = countPendingReviews();
|
||||
const cronToken = (process.env.CRON_TOKEN || '').trim();
|
||||
---
|
||||
<Admin title="Einstellungen" active="einstellungen" crumbs={[{ label: 'Einstellungen' }]}>
|
||||
<div class="s-stack">
|
||||
@@ -111,6 +114,21 @@ const mail = mailerStatus();
|
||||
<div class="s-section-title" style="margin-bottom:12px">System</div>
|
||||
<p class="s-help">Datenbank: SQLite (<b>DB_PATH</b>). Admin-Zugang über Session-Login; Initial-Owner aus <b>ADMIN_EMAIL</b> / <b>ADMIN_PASS</b>. Admin-Pfad über <b>ADMIN_PATH</b>.</p>
|
||||
</div>
|
||||
|
||||
{feature('feature_abandoned_cart') && (
|
||||
<div class="s-card s-card-pad">
|
||||
<div class="s-section-title" style="margin-bottom:12px">Warenkorb-Erinnerung</div>
|
||||
<p class="s-help" style="margin-bottom:6px">Gespeicherte Warenkörbe: <b>{acStats.total}</b> · offen <b>{acStats.open}</b> · erinnert <b>{acStats.reminded}</b> · wiederhergestellt <b>{acStats.recovered}</b></p>
|
||||
<p class="s-help">Versand-Trigger: <b>POST /api/cron/abandoned</b> (Header <code>Authorization: Bearer <CRON_TOKEN></code> oder <code>?token=</code>). {cronToken ? 'CRON_TOKEN gesetzt.' : 'CRON_TOKEN noch nicht gesetzt — Endpoint bleibt gesperrt.'}</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{feature('feature_reviews') && pendingReviews > 0 && (
|
||||
<div class="s-card s-card-pad">
|
||||
<div class="s-section-title" style="margin-bottom:8px">Bewertungen</div>
|
||||
<p class="s-help"><b>{pendingReviews}</b> Bewertung(en) warten auf Freigabe — <a href={base + '/bewertungen'}>jetzt prüfen</a>.</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user