Ships `dev` as **v0.11.0**. `main` contains nothing that `dev` does not, so this is a clean sync. ## Headline changes since v0.10.0 - **Journal & Journal Studio** — photo essays at `/journal`, split-screen block editor with live preview, drafts, per-entry passwords, cover images - **First-run setup wizard at `/install`** — configure a fresh deployment from the browser; credentials are verified against Immich before anything is written, and the wizard is gated by a one-time token - **About page editor and toggle** in the admin panel - **Per-album photo order** independent of Immich, with a drag & drop editor - **Custom favicon upload** - **Experimental portfolio features** — justified grid, `cover` hero, unlisted subpages, per-album grid overrides, cover focal points, external nav links - **Security** — asset tokens length-capped before decoding (#423), journal author markdown escaped rather than filtered, journal file paths contained, admin session key derived with scrypt (#432), Next.js 16.3.0 for CVE-2025-13465 - **Fixed** — client proofing honours its own configuration again (#454); journal photo rendering (#432) Full detail in [CHANGELOG.md](CHANGELOG.md#0110--2026-08-15). ## Verified `npx tsc --noEmit` clean · `npx vitest run` 435 tests pass · `npm run build` succeeds · lint 0 errors · `prettier --check` clean · local `docker build` of the release tree. ## After merge Tag `v0.11.0` on `main` and publish the release — that triggers `docker-publish.yml`, which pushes the image and moves `latest`. 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: ralksta <ralksta@users.noreply.github.com> Co-authored-by: lancetm714 <108419425+lancetm714@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
6.5 KiB
6.5 KiB
Design-Spezifikation: Journal Studio (Foto-Essays & Stories)
Status: Entwurf genehmigt (Brainstorming abgeschlossen) · Datum: 2026-08-14
1. Understanding Summary
- Ziel & Vision: Bereitstellung eines intuitiven, erstklassigen Journal Studios für Fotografen, um Bild-Text-Reportagen, Reisetagebücher und Ausstellungsberichte (im Stil von Leica Journal / National Geographic) zu verfassen und zu veröffentlichen.
- Zielgruppe:
- Besucher: Immersives, typografisch elegantes Leseerlebnis mit progressiv ladenden Bildern (ThumbHash), responsiven Layouts und Lightbox-Interaktion.
- Fotograf: Mühelose Redaktion im Admin-Panel mit Live-Split-Screen-Vorschau und universeller Immich-Bildauswahl.
- Konzept: Reines Markdown mit Frontmatter im Content-Volume (
content/journal/*.md), verwaltet über eine dedizierte Admin-UI und ausgeliefert über saubere Next.js Server Components. - Kern-Vorteile:
- Trennung von Galerie-Konfiguration (
gallery.yaml) und redaktionellen Inhalten. - Volle Git- & Backup-Kompatibilität durch Standard-Markdown.
- Schnelle Erstellung ohne manuelle UUID-Eingabe.
- Trennung von Galerie-Konfiguration (
2. Annahmen (Assumptions)
- Storage-Pfad: Journal-Einträge werden standardmäßig unter
content/journal/[slug].mdgespeichert. - Bild-Referenzierung: Bilder verweisen über
auf Immich-Assets und werden über den internen Image-Proxy mit Cache und ThumbHash ausgeliefert. - Theming: Die Leseansicht (
/journal/[slug]) bindet sich nahtlos an das global konfigurierte Design-Theme an (CSS-Variablen, Fonts, Margins). - Resilienz: Nicht auffindbare Bilder führen nicht zu einem Seitenabsturz, sondern werden durch neutrale Platzhalter ersetzt.
3. Decision Log
| # | Entscheidung | Alternativen | Begründung |
|---|---|---|---|
| 1 | Nomenklatur "Journal" | Stories, Photo Essays, Magazin | "Stories" wirkt wie flüchtige Social-Media-Inhalte. "Journal" spiegelt zeitlose, fotografische Wertigkeit (wie Leica Journal) wider. |
| 2 | Architektur-Ansatz 1 (Eigenständiges Studio) | Subpage-Drawer, Quick-Fix | Maximale Schreib- und Layout-Ergonomie durch echten Split-Screen und Entkopplung von gallery.yaml. |
| 3 | Persistenz als .md-Dateien |
Strings in gallery.yaml, SQLite/DB |
Behält das dateibasierte, zustandsarme Self-Hosting-Paradigma bei; einfache Versionierung via Git. |
| 4 | Bidirektionaler Editor (Blöcke ↔ Markdown) | Nur WYSIWYG, Nur Markdown | Fotografen können visuell Blöcke anordnen oder direkt mit Markdown-Code arbeiten, ohne Datenverlust. |
| 5 | Sicherheit via Slug-Sanitisierung | Ungeprüfte Dateinamen | Verhindert Path Traversal (../) im Docker-Container/Dateisystem. |
4. Technische Architektur & Komponenten
A. Dateisystem & Datenmodell
Jeder Eintrag ist eine .md-Datei mit folgendem Schema:
---
title: 'Expedition Nordkap'
subtitle: 'Mit dem Bulli durch die Fjorde'
date: '2026-08-14'
author: 'Ralf'
coverAssetId: 'b8c2d111-0000-4000-8000-000000000000'
password: '' # Optionaler Passwortschutz (scrypt)
draft: false # Entwurf oder öffentlich
---
Hier beginnt der Text der Reportage...

Unterstützte Block-Typen:
- Heading:
# H1,## H2,### H3 - Paragraph: Fliesstext mit Inline-Markdown (
**fett**,*kursiv*,[Link](url)) - Pullquote:
> Zitattextmit optionalem— Autor - Photo (Fullbleed / Wide / Contained):
 - Photo-Pair (2-Spaltig): Zwei aufeinanderfolgende
asset:-Bilder
B. Admin API Endpunkte (/api/admin/journal)
GET /api/admin/journal: Liefert Liste aller Einträge (geparstes Frontmatter, Slug, Cover-Thumbnail, Word Count / Read Time).GET /api/admin/journal/[slug]: Liefert vollen Inhalt & Metadaten eines spezifischen Eintrags.PUT /api/admin/journal/[slug]: Speichert den Eintrag atomar (Write to.tmp➔ Rename), legt.bak-Sicherungen an und validiert den Markdown-Baum.DELETE /api/admin/journal/[slug]: Löscht die.md-Datei nach Bestätigung.
C. UI: Das Journal Studio (/admin ➔ Tab "Journal")
- Journal Dashboard:
- Übersicht aller Einträge als Karten mit Thumbnail, Status (Draft, Live, Protected), Erstellungsdatum.
- Button
+ New Journal Entry.
- Studio Split-Screen Editor:
- Top Navigation: Titel-Eingabe, Slug, Status-Schalter, Metadaten-Modal (Autor, Datum, Passwort, Cover-Foto) und Save-Button (
Cmd+S). - Linker Bereich (Authoring):
- Umschaltbar zwischen [Visual Blocks] (Karten mit Drag & Drop Griffleisten) und [Raw Markdown].
- Universeller Asset-Picker für Fotos aus allen Immich-Alben.
- Rechter Bereich (Live Preview):
- 1:1 Rendering via
EssayViewmit den CSS-Variablen des aktiven Themes. - Viewport-Umschalter (Desktop / Mobile).
- 1:1 Rendering via
- Top Navigation: Titel-Eingabe, Slug, Status-Schalter, Metadaten-Modal (Autor, Datum, Passwort, Cover-Foto) und Save-Button (
D. Frontend Routing & Rendering
/journal: Übersicht aller veröffentlichten Journal-Einträge mit Cover-Bildern und Exzerpten./journal/[slug]: Detailansicht der Reportage mit Passwort-Gate (PasswordGate) bei geschützten Einträgen.- Subpage-Integration: Kompatibilität mit
gallery.yaml(essayFile: "nordkap.md") bleibt vollständig erhalten.
5. Test- & Absicherungsstrategie
- Unit-Tests (
lib/__tests__/journal.test.ts):- Frontmatter-Parsing & -Serialisierung.
- XSS-Sanitisierung bei bösartigem Markdown-HTML.
- Block-Transformation (Fullbleed, Pairs, Quotes).
- API-Tests (
app/api/admin/journal/__tests__/route.test.ts):- Auth-Schutz (401/403 bei nicht-angemeldeten Requests).
- Path-Traversal-Abwehr (Rejection von
../,%2e%2e%2f). - Atomare Speicherung und Fehlerbehandlung bei Disk-Fehlern.
- E2E / Integration:
- Aufruf von
/journal/[slug]im Browser und Verifikation des Lightbox-Klicks auf eingebettete Fotos.
- Aufruf von