feat: mirror-all-to-NAS, content reset (danger zone), in-app changelog + CHANGELOG.md, How-To refresh
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XNQ8ghPfzAfsyVYd6HgFb6
This commit is contained in:
@@ -5,7 +5,10 @@ import Base from '../layouts/Base.astro';
|
||||
<div class="howto">
|
||||
<div class="hkopf">
|
||||
<h1>So funktioniert Klarbild</h1>
|
||||
<button class="druck" onclick="window.print()">Als PDF / drucken</button>
|
||||
<div class="hkopf-akt">
|
||||
<a class="druck" href="/changelog">Changelog</a>
|
||||
<button class="druck" onclick="window.print()">Als PDF / drucken</button>
|
||||
</div>
|
||||
</div>
|
||||
<p class="lead">Aus Screenshots und Fundstücken werden druckfertige Bilder — bereinigt, freigestellt,
|
||||
im richtigen Format, optional direkt bei Picdrop. Alles geht über die Website und über Telegram.</p>
|
||||
@@ -48,6 +51,10 @@ import Base from '../layouts/Base.astro';
|
||||
<li><b>Weiterbearbeiten</b>: übernimmt ein fertiges Bild als neue Vorlage ins Studio — dort erneut
|
||||
bearbeiten, ins nächste Format bringen oder im Modus Kombinieren mit weiteren Bildern mischen.</li>
|
||||
<li><b>Vorher/Nachher</b>: zeigt den Vergleich Vorlage ↔ Ergebnis (bei reinen Text-Bildern entfällt das).</li>
|
||||
<li><b>Ordner verwalten</b>: Ordner-Chip antippen, dann ✎ zum Umbenennen (inkl. Galerie) oder ✕ zum Löschen
|
||||
(die Bilder bleiben erhalten).</li>
|
||||
<li><b>Mehrere auf einmal</b>: Bilder markieren, dann als <b>ZIP laden</b> oder gesammelt <b>in einen Ordner</b>
|
||||
verschieben.</li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
@@ -67,6 +74,16 @@ import Base from '../layouts/Base.astro';
|
||||
<p class="mini">Für Profis gibt es zusätzlich das „/"-Befehlsmenü (/neu, /rezepte, /status) — nötig ist es nicht.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>6 · Sicherung & sauber neu starten (Admin)</h2>
|
||||
<p>Im Admin-Bereich lässt sich eine <b>zweite Sicherung aufs NAS</b> einrichten (SFTP/FTPS, auch über
|
||||
Tailscale) — jedes fertige Bild wird dann zusätzlich gespiegelt und in der Bibliothek mit <b>„NAS ✓"</b>
|
||||
markiert. Mit <b>„Alle vorhandenen Bilder aufs NAS sichern"</b> lassen sich auch ältere Bilder nachsichern.</p>
|
||||
<p>Zum Aufräumen gibt es <b>„Bibliothek & Aufträge zurücksetzen"</b>: löscht alle Bilder, Aufträge und Ordner
|
||||
(Nutzer, Einstellungen, Modelle und Rezepte bleiben) — mit Sicherheitsabfrage. Am besten vorher einmal
|
||||
aufs NAS sichern.</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Tipps</h2>
|
||||
<ul>
|
||||
@@ -81,7 +98,8 @@ import Base from '../layouts/Base.astro';
|
||||
.howto{max-width:760px;margin:0 auto;}
|
||||
.hkopf{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;}
|
||||
.howto h1{font-family:var(--font-display);font-size:1.7rem;letter-spacing:-.02em;margin:6px 0 4px;}
|
||||
.druck{background:var(--card);border:1px solid var(--line);border-radius:999px;padding:8px 15px;cursor:pointer;font-family:inherit;font-size:.85rem;color:var(--ink);}
|
||||
.hkopf-akt{display:flex;gap:8px;align-items:center;}
|
||||
.druck{background:var(--card);border:1px solid var(--line);border-radius:999px;padding:8px 15px;cursor:pointer;font-family:inherit;font-size:.85rem;color:var(--ink);text-decoration:none;}
|
||||
.lead{color:var(--soft);line-height:1.6;margin:4px 0 20px;}
|
||||
.howto section{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;margin-bottom:14px;}
|
||||
.howto h2{font-size:1.05rem;margin:0 0 10px;}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { query } from '../../../lib/db';
|
||||
import { deleteObject } from '../../../lib/storage';
|
||||
|
||||
export const prerender = false;
|
||||
const json = (b: unknown, s = 200) =>
|
||||
new Response(JSON.stringify(b), { status: s, headers: { 'Content-Type': 'application/json' } });
|
||||
|
||||
/** Setzt Inhalte zurück: löscht alle Bilder/Aufträge/Ordner + zugehörige Dateien.
|
||||
* Nutzer, Einstellungen, Modelle und Rezepte bleiben erhalten.
|
||||
* Erfordert { confirm: 'RESET' }. */
|
||||
export const POST: APIRoute = async ({ request, locals }) => {
|
||||
if (locals.user?.role !== 'admin') return new Response('Forbidden', { status: 403 });
|
||||
const b = await request.json().catch(() => ({} as any));
|
||||
if (b.confirm !== 'RESET') return json({ error: 'Bestätigung fehlt (confirm=RESET).' }, 400);
|
||||
|
||||
// Zuerst alle Objekte aus dem Speicher entfernen.
|
||||
const items = await query<any>('SELECT source_path, source_paths, result_path, thumb_path FROM items');
|
||||
let objects = 0;
|
||||
for (const it of items) {
|
||||
const keys = [it.source_path, it.result_path, it.thumb_path,
|
||||
...((it.source_paths as string[]) || [])].filter(Boolean);
|
||||
for (const k of keys) { await deleteObject(k).catch(() => {}); objects++; }
|
||||
}
|
||||
|
||||
// Inhalts-Tabellen leeren (Konfiguration bleibt).
|
||||
await query('DELETE FROM print_job_items');
|
||||
await query('DELETE FROM print_jobs');
|
||||
await query('DELETE FROM share_links');
|
||||
await query('DELETE FROM telegram_drafts');
|
||||
await query('DELETE FROM items');
|
||||
await query('DELETE FROM jobs');
|
||||
await query('DELETE FROM folders');
|
||||
|
||||
return json({ ok: true, deleted_items: items.length, deleted_objects: objects });
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { APIRoute } from 'astro';
|
||||
import { storageStats, runRetention, purgeSources } from '../../../lib/maintenance';
|
||||
import { storageStats, runRetention, purgeSources, mirrorAllToNas } from '../../../lib/maintenance';
|
||||
import { one } from '../../../lib/db';
|
||||
|
||||
export const prerender = false;
|
||||
@@ -12,6 +12,7 @@ export const GET: APIRoute = async () => json({ stats: await storageStats() });
|
||||
export const POST: APIRoute = async ({ request }) => {
|
||||
const b = await request.json().catch(() => ({}));
|
||||
if (b.action === 'purge_sources') return json(await purgeSources());
|
||||
if (b.action === 'mirror_all') return json(await mirrorAllToNas());
|
||||
if (b.action === 'retention') {
|
||||
const s = await one<{ retention_days: number | null }>('SELECT retention_days FROM settings WHERE id=1');
|
||||
if (!s?.retention_days) return json({ error: 'Keine Aufbewahrungsfrist gesetzt.' }, 400);
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
import Base from '../layouts/Base.astro';
|
||||
---
|
||||
<Base title="Changelog · Klarbild">
|
||||
<div class="clog">
|
||||
<div class="ckopf">
|
||||
<h1>Changelog</h1>
|
||||
<a class="zurueck" href="/anleitung">← Zur Hilfe</a>
|
||||
</div>
|
||||
<p class="lead">Was in Klarbild neu ist. Neueste Änderungen oben.</p>
|
||||
|
||||
<section>
|
||||
<div class="ver"><span class="tag">23.07.2026</span><h2>Kombinieren, Erzeugen & zweite Sicherung</h2></div>
|
||||
<ul>
|
||||
<li><b>Kombinieren:</b> mehrere Bilder + Beschreibung zu einem neuen Bild (z. B. „…mit unserer Hündin Frieda").</li>
|
||||
<li><b>Neu erzeugen:</b> Bilder allein aus Text, ganz ohne Vorlage.</li>
|
||||
<li><b>The Frame „Erweitern":</b> Szene rund ums Motiv weiter generieren (Outpainting) statt nur zuschneiden.</li>
|
||||
<li><b>Weiterbearbeiten:</b> ein fertiges Bild als neue Vorlage übernehmen und erneut bearbeiten.</li>
|
||||
<li><b>Alternativen:</b> weitere Fassungen desselben Bildes erzeugen — gruppiert mit Umschalter.</li>
|
||||
<li><b>Ordner:</b> in der Bibliothek filtern, umbenennen, löschen; je Ordner eigene Picdrop-Galerie.</li>
|
||||
<li><b>Sammel-Aktionen:</b> mehrere Bilder als ZIP laden und auf einmal in einen Ordner verschieben.</li>
|
||||
<li><b>Vorschaubilder</b> für die Bibliothek (schnell & sparsam).</li>
|
||||
<li><b>Modelle:</b> Qualitätsstufen inkl. Open Source (FLUX.2); genutztes Modell wird angezeigt.</li>
|
||||
<li><b>Zweite Sicherung (NAS):</b> jedes Ergebnis zusätzlich per SFTP/FTPS aufs NAS (auch über Tailscale) — mit „NAS ✓"-Anzeige und „Alle Bilder aufs NAS sichern".</li>
|
||||
<li><b>Speicherverwaltung:</b> Vorschaubilder, Quellen löschen, automatische Aufbewahrungsfrist.</li>
|
||||
<li><b>Telegram komplett knopfbasiert:</b> Dauertastatur & Menü — Bearbeiten, Kombinieren, „✨ Neues Bild", Weiterbearbeiten, ganz ohne Befehle.</li>
|
||||
<li><b>Zurücksetzen:</b> Bibliothek & Aufträge sauber leeren (mit Sicherheitsabfrage).</li>
|
||||
<li><b>Hilfe-Seite</b> und dieser Changelog.</li>
|
||||
<li>Unter der Haube: echter Kostendeckel, verlässlicher Auftragsabschluss, Erreichbarkeits-Diagnose fürs NAS.</li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.clog{max-width:760px;margin:0 auto;}
|
||||
.ckopf{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;}
|
||||
.clog h1{font-family:var(--font-display);font-size:1.7rem;letter-spacing:-.02em;margin:6px 0 4px;}
|
||||
.zurueck{color:var(--accent);text-decoration:none;font-size:.9rem;}
|
||||
.lead{color:var(--soft);margin:4px 0 20px;}
|
||||
.clog section{background:var(--card);border:1px solid var(--line);border-radius:var(--radius);padding:16px 18px;margin-bottom:14px;}
|
||||
.ver{display:flex;align-items:center;gap:10px;margin-bottom:10px;flex-wrap:wrap;}
|
||||
.ver h2{font-size:1.05rem;margin:0;}
|
||||
.tag{font-family:var(--font-mono);font-size:10px;letter-spacing:.08em;background:var(--accent-bg);color:var(--accent);padding:3px 9px;border-radius:20px;}
|
||||
.clog ul{margin:0;padding-left:20px;line-height:1.65;}
|
||||
.clog li{margin-bottom:6px;}
|
||||
</style>
|
||||
</Base>
|
||||
Reference in New Issue
Block a user