v2.4: Medienbibliothek+WebP, Varianten-Matrix, Litestream-Backups, intelligentere Analytics
P1 Medien: eigener Admin-Bereich /admin/medien (Grid, Mehrfach-Upload, Drag&Drop, Alt-Text, URL kopieren, Loeschen). Upload konvertiert JPG/PNG via sharp zu WebP (Qualitaet 82, max 2000px), Original wird verworfen; WebP/SVG/GIF/AVIF unveraendert; Konvertierungsfehler -> Original behalten statt 500. media um alt/width/height erweitert. Wiederverwendbarer Medien-Picker (public/media-picker.js) ersetzt den URL-Prompt im Block-Editor, Produkt-Editor (Karte/Galerie/Varianten-Bild), Slides und Popups. JSON-Quelle /api/admin/media (session-gesichert). P2 Varianten: products.options_json + Tabelle product_variants. Produkt-Editor mit Options-Definition + Matrix-Generator (Preis-Override/Bestand/SKU/Bild/aktiv je Variante). PDP-Selektoren -> Variante; Cart/Checkout tragen sku+Options, Order-Item bekommt sku/variant, Variantenpreis serverseitig verifiziert. Produkte ohne Optionen unveraendert. P3 Litestream: Binary im Dockerfile, docker-entrypoint.sh (Restore+replicate nur bei LITESTREAM_REPLICA_URL, sonst reiner Node-Start), litestream.yml, Backup-Status unter Einstellungen, README + .env.example. P4 Analytics: Bestseller, Top-Suchbegriffe, Umsatz/Quelle, Umsatz-Zeitreihe, AOV, Wiederkaufrate, Lager-Warnungen. Neue Dep sharp. +19 Unit-Tests (49 gesamt gruen), Build + Smoke (P1-P4) gruen.
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
import Admin from '../../../layouts/Admin.astro';
|
||||
import { adminBase } from '../../../lib/auth.js';
|
||||
const base = adminBase();
|
||||
import { getSettings, setSetting, resolvePaymentProvider, FEATURE_KEYS, feature, abandonedCartStats, countPendingReviews } from '../../../lib/store.js';
|
||||
import { getSettings, setSetting, resolvePaymentProvider, FEATURE_KEYS, feature, abandonedCartStats, countPendingReviews, backupStatus } from '../../../lib/store.js';
|
||||
import { mailerStatus } from '../../../lib/mailer.js';
|
||||
|
||||
const FEATURE_LABELS = {
|
||||
@@ -50,6 +50,7 @@ const mail = mailerStatus();
|
||||
const acStats = abandonedCartStats();
|
||||
const pendingReviews = countPendingReviews();
|
||||
const cronToken = (process.env.CRON_TOKEN || '').trim();
|
||||
const backup = backupStatus();
|
||||
---
|
||||
<Admin title="Einstellungen" active="einstellungen" crumbs={[{ label: 'Einstellungen' }]}>
|
||||
<div class="s-stack">
|
||||
@@ -129,6 +130,19 @@ const cronToken = (process.env.CRON_TOKEN || '').trim();
|
||||
<p class="s-help"><b>{pendingReviews}</b> Bewertung(en) warten auf Freigabe — <a href={base + '/bewertungen'}>jetzt prüfen</a>.</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div class="s-card s-card-pad">
|
||||
<div class="s-section-title" style="margin-bottom:8px">Backup (Litestream)</div>
|
||||
{backup.configured ? (
|
||||
<>
|
||||
<p class="s-help" style="margin-bottom:6px"><span class="s-badge green">aktiv</span> Streaming-Backup nach <b>{backup.target}</b>{backup.endpoint ? ` (Endpoint ${backup.endpoint})` : ''}.</p>
|
||||
{!backup.fullCredentials && <p class="s-help" style="color:#b3261e">Achtung: Zugangsdaten unvollständig — LITESTREAM_ACCESS_KEY_ID / LITESTREAM_SECRET_ACCESS_KEY prüfen.</p>}
|
||||
<p class="s-help">DB: <code>{backup.dbPath}</code>. Restore: <code>litestream restore -if-replica-exists {backup.dbPath}</code></p>
|
||||
</>
|
||||
) : (
|
||||
<p class="s-help"><span class="s-badge gray">inaktiv</span> Kein Replica konfiguriert. Setze <b>LITESTREAM_REPLICA_URL</b> (S3/Backblaze B2) plus Zugangsdaten als ENV, um stündliche Streaming-Backups zu aktivieren (siehe README).</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user