User-feedback: <script type="application/ld+json"> kann svelte direkt
rendern. Kein @html-Notausgang noetig, sauberere variante mit
auto-escape.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Frischer plan gegen die ueberarbeitete spec (fallback_url raus,
OG-default joerg-profil-2024.webp, prerender+runtime-fallback klar
als adapter-static-default). Sechs etappen, jede einzeln testbar
und rollback-bar:
1. renderMarkdown auf isomorphic-dompurify (node-faehig)
2. Snapshot-modul (deno) mit 9 testbaren cores + cli
3. Snapshot in CI
4. Detail-route auf prerender mit runtime-fallback
5. Runtime-fallback entfernen (snapshot ist quelle)
6. lftp mirror in drei phasen (optional, nicht-blockierend)
Alter plan bleibt im archive als geschichte.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- fallback_url im cover_image rausgenommen (YAGNI; primary url
reicht, blossom ist content-addressed). Beim ersten konkreten
bedarf nachreichen.
- Site-default-OG-bild auf app/static/joerg-profil-2024.webp
festgelegt (vorhandenes asset, nicht spekulativ).
- prerender + runtime-fallback klarer formuliert: das ist das
default-verhalten von adapter-static mit fallback, kein
workaround. ReplyList/ReplyComposer-hydration als
verifikations-punkt im plan-schritt 4 vermerkt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
README/STATUS/HANDOFF/CLAUDE jeweils ein rollensatz oben:
- README = aussenseite
- STATUS = logbuch (stand + erledigt-chronologie)
- HANDOFF = konventions-handbuch (workflows + stolperfallen)
- CLAUDE.md = session-einstieg
HANDOFF erhaelt zusaetzlich eine Single-Source-of-Truth-sektion,
damit klar ist welche fakten wo gepflegt werden.
README-linkliste auf 3 specs eingedampft (SPA, pipeline, multilingual)
und auf das plan-archiv verlinkt statt einzelplaene. CLAUDE.md
verlinkt zusaetzlich die prerender-snapshot-spec mit kennzeichnung.
STATUS.md verzeichnis-baum spiegelt das archiv wider.
Wiki-entwuerfe + redaktions-doku + github-ci-setup-doku haben
explizite status-stempel (eingefroren / schnappschuss / aktuell-aber-zu-ersetzen),
damit man nicht mehr raten muss.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Alle 6 plaene unter docs/superpowers/plans/archive/. Davon 5 abgearbeitet
(SPA, publish-pipeline, 3x multilingual), 1 eingefroren (prerender-snapshot).
Checkboxen wurden waehrend der umsetzung nicht gepflegt — verbindlicher
stand ist STATUS.md und die jeweilige spec, das archive/README.md macht
die zuordnung sichtbar.
plans/ bleibt mit .gitkeep als verzeichnis bestehen, damit neue plaene
sofort wieder dort landen koennen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Status-Header aller specs nach neuer konvention:
Entwurf | In Umsetzung | Umgesetzt (live seit YYYY-MM-DD) | Eingefroren | Verworfen.
Die zwei aeltesten specs (SPA, publish-pipeline) standen formal noch
auf "ausstehende User-Freigabe", obwohl seit 2026-04-18 live —
nun korrekt als umgesetzt markiert. Bild-metadaten-spec als
Phase 1 umgesetzt mit Phase-2-vermerk. Multilingual-spec angeglichen.
Prerender-snapshot-spec von "Stand:" auf "Status: Entwurf" mit
hinweis auf eingefrorenen plan im archiv.
Cleanup-spec selbst dokumentiert die konvention.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der Snapshot liefert content_markdown, nicht content_html. Rendering
(marked + DOMPurify + highlight.js) passiert im SvelteKit-Prerender-
Schritt über das bereits existierende \$lib/render/markdown.ts —
keine Duplikation in Deno, kein gemeinsames Policy-Modul nötig.
Für Blaupausen-Nutzung ist rohes Markdown portabler: alternative
Renderer (Astro, Eleventy) bringen eigenen Markdown-Prozessor mit.
Konsequenz für Migration: Schritt 1 ist jetzt \"renderMarkdown
Node-kompatibel machen\" (isomorphic-dompurify) statt \"shared/
markdown-policy.ts ergänzen\".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nachschärfungen nach Review:
- content_html als primary im Snapshot-JSON (marked + DOMPurify +
highlight.js, gemeinsame Policy in shared/markdown-policy.ts)
- content_markdown bleibt daneben (Debug + alternative Renderer)
- translations[] um title ergänzt (SPA-Switcher ohne Relay-Fetch)
- published_at vs. created_at semantisch klar getrennt (OG vs. Update)
- cover_image.fallback_url mit dokumentiertem Nutzungsszenario
- Fallback-Politik für fehlende summary/image/published_at
- --allow-shrink-Flag und kind:5-gestützte automatische Override
- Upload-Reihenfolge für Hash-benannte Bundles (Assets → HTML → Delete)
- /tag/<name>/-Verhalten in Nicht-Zielen erwähnt
- Edge-Case „Repo-Post + alle Relay-Events gelöscht" in Fehlertabelle
- Migrations-Weg um shared/markdown-policy.ts als Schritt 1 erweitert
- pro Migrations-Schritt explizite Rollback-Strategie
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Design-Dokument für die dreistufige Pipeline
publish → snapshot → build+deploy, die Post-Detailseiten mit echten
OG-Metadaten und prerendered Content versorgt, ohne Runtime-Relay-Fetch
und ohne Node-/Go-Server auf dem Shared-Hosting.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- README: neue plan-referenzen (3x multilingual), repo-struktur auf
content/posts/<lang>/<slug>/, svelte-i18n + translations im app-tree
- STATUS: event-count 27 (26 de + 1 en), kurzfassung um mehrsprachigkeit,
multilingual-abschnitt in „erledigt" (pipeline, spa, i18n + bugfixes)
- HANDOFF: option D entfernt (erledigt), neuer abschnitt „wie man eine
übersetzung anlegt", frontmatter-template um a:-platzhalter,
deploy-target-stolperfalle verschärft, vr-post-pfad aktualisiert
- Multilingual-spec: status von „noch nicht implementiert" auf „umgesetzt"
+ anmerkung zum post-switcher (📖 DE | EN statt text-hinweis)
- CLAUDE.md neu: knapper einstieg für agent-sessions mit commit-konvention,
deploy-falle, zsh-globbing, forgejo-mirror-timing
- workflow-skill generalüberholt: post-cutover-stand, multilingual,
publish-pipeline, activeLocale, 73 pipeline-tests
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- neue sprach-variante content/posts/en/bible-selfies/ verweist auf dt. original
- dt. bibel-selfies verweist zurück auf bible-selfies
- plan 2/3: npm test → npm run test:unit (existing script name)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- nip-09-delete-event für duplikat 1744905463975 festgehalten
- open-todos ergänzt: kind:5-filter in spa, repo/nostr-konflikt-mgmt,
delete-subcommand in pipeline
- option 3 (menü+impressum+startseite) als design-todo klargestellt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
spa → main gemergt, github-actions-workflow manuell verifiziert
(run #1: signer ok, outbox ok, blossom-liste ok, mode=diff posts=0).
der 24-task-plan aus docs/superpowers/plans/2026-04-16-publish-pipeline.md
ist offiziell durch. pipeline läuft sowohl lokal als auch in ci,
auto-trigger bei content-push ist konfiguriert (aber noch nicht real
ausgelöst worden — beiläufig mitzunehmen, wenn mal ein post editiert
wird).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docs/github-ci-setup.md dokumentiert:
- forgejo → github push-mirror
- die 4 github-repository-secrets (bunker-url, author-pubkey-hex,
bootstrap-relay, client-secret-hex) — letzteres identisch mit
.env.local für stabile amber-app-identität
- wie man sie rotiert
- migrations-pfad weg von github (woodpecker, cron)
status + handoff reflektieren: pipeline live, alle 18 posts publiziert,
91 bilder auf blossom, ci-setup steht, cutover als nächster schritt
möglich.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
validatePost akzeptiert jetzt auch string-dates im YYYY-MM-DD- oder
ISO-8601-format und coerced sie in ein Date-objekt in-place. vorher
schlug die validation für 13 von 18 altposts fehl, weil deren yaml
`date: "2023-02-26"` quoted war (hugo-konvention) und der yaml-parser
strings statt Date-instanzen liefert.
migration durchgelaufen (log in docs/publish-logs/): 18/18 success,
91 bilder auf beiden blossom-servern, 5 write-relays — bis auf
relay.damus.io, der bei 6 posts nicht auf OK antwortet (üblich bei
damus, rate-limiting). alle 7 multi-relay-posts haben weiter mindestens
4 acks (über MIN_RELAY_ACKS=2).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- spec publish-pipeline aktualisiert: blossom-only (rsync-legacy-pfad raus)
- plan publish-pipeline (24 tasks in 12 phasen), blaupausen-tauglich:
alle projekt-konstanten via env (BUNKER_URL, AUTHOR_PUBKEY_HEX,
BOOTSTRAP_RELAY, CONTENT_ROOT, CLIENT_TAG, MIN_RELAY_ACKS)
- spec bild-metadaten-konvention (phase 1, yaml-basiert)
- wiki-entwurf deutsch + englisch: inline-markdown-konvention zur
bildattribution mit mapping zu nip-92 imeta-tags. konvention für
menschen, parser passt sich an; bei ambiguität eskalation zur
redaktion statt stillem raten
- redaktions-checkliste für bild-durchgang (abgearbeitet, bleibt
zum abgleich bei späteren migrationen)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- docs/STATUS.md: was ist getan, was läuft live, wo liegen die Fäden
- docs/HANDOFF.md: nächste Optionen (Publish-Pipeline, Menü, Cutover),
Dev-Kommandos, bekannte Stolperfallen
- .claude/skills/joerglohrerde-workflow.md: repo-spezifischer Skill
zum Session-Start — Konventionen, API-Eigenheiten, wiederkehrende
Kommandos, wie mit Jörg arbeiten
- README.md als Navigation zu allen Dokumenten
Damit kann die nächste Session ohne Kontextverlust fortgeführt werden.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deckt die vollständige SPA-Spec ab: Setup + adapter-static, Daten-
ebene (Relay-Pool, Loader, Profil, Markdown, Signer), Routing mit
Legacy-URL-Normalisierung, Tag-Filter, Reactions, NIP-07-Kommentare.
TDD für pure Transformationen (URL-Parser, naddr, Markdown), E2E mit
Playwright für Happy-Paths.
Deploy-Ziel: svelte.joerg-lohrer.de. spa.joerg-lohrer.de bleibt als
Vanilla-Mini-Spike-MVP erhalten (Referenz-Verhalten).
Publish-Pipeline hat eigene Spec und bekommt separaten Plan.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Revidiert das URL-Schema: die lange Hugo-Form /YYYY/MM/DD/<dtag>.html/
wird als Legacy behandelt, die kurze Form /<dtag>/ als kanonisch.
Gründe: schöner zu teilen, skaliert über die 18 Altposts hinaus,
Datumskomponente fügt keinen Informationswert (Datum steht im Event
als published_at).
Legacy-URLs werden clientseitig via history.replaceState ohne Reload
auf die kurze Form normalisiert — Backlinks bleiben funktional,
Bookmarks konvergieren zur kurzen Form. Keine .htaccess-Redirects.
Im Mini-Spike bereits umgesetzt und live auf spa.joerg-lohrer.de.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Die produktive SPA soll Events wahrheitsgetreu darstellen und nicht
defensiv korrigieren. Daten-Anomalien (doppelte t-Tags etc.) bleiben
sichtbar, damit der Autor sie wahrnimmt. Bereinigung gehört in
separate Audit-Werkzeuge, nicht in die SPA-Renderlogik.
Der Mini-SPA-Spike dedup'te pragmatisch — explizit als Abweichung
vom Zielverhalten vermerkt.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Häufige Sorge ("kann mein einfaches Webspace-Paket SvelteKit hosten?")
explizit beantwortet: SvelteKit mit adapter-static produziert reine
statische Dateien, exakt analog zu Hugos public/. Webspace, FTP und
.htaccess reichen vollständig — keine Node-Runtime, keine Datenbank,
kein vServer nötig.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Publish-Pipeline für den Weg Markdown → signiertes kind:30023 → Relays,
plus Bilder-Upload (Legacy: rsync zu All-Inkl für die 18 Altposts;
Blossom: BUD-01-Upload für neue Posts).
Kernpunkte:
- Deno-Runtime, gemeinsame Library und CLI für lokal + GitHub Action
- NIP-46 Bunker (Amber-Stufe, später Optiplex-Stufe ohne Code-Change)
- Relay- und Blossom-Server-Listen via kind:10002 / kind:10063
(manuell einmalig publiziert, identisch mit SPA-Nutzung)
- Git-Diff als Change-Detection, --force-all für Migration/Reimport
- State-los im Repo, keine Lock-Files, keine Commits zurück
- Pre-Flight `deno task check` validiert alle Voraussetzungen
Beziehung zur SPA-Spec: gemeinsame Event-Verträge (kind:30023, 10002,
10063) sind in dieser Spec normativ; SPA-Spec verweist darauf.
Publish läuft einmalig für die 18 Altposts (SPA-Migrationsschritt C)
vor dem SPA-Cutover (Schritt D).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Die Relay-Liste wird zur Laufzeit aus dem NIP-65-Outbox-Event geholt
(via Bootstrap-Relay), mit hartcodierter Fallback-Liste als Sicherheit.
Damit teilen SPA und Publish-Pipeline eine gemeinsame Quelle der
Wahrheit für Relay-Konfiguration — Änderungen erfordern nur ein neues
Event, keinen Code-Deploy.
Publish-Spec wird das normative Schema für kind:10002 und kind:10063
definieren; SPA-Spec verweist darauf.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SvelteKit-SPA, die Blog-Posts live aus signierten kind:30023-Events
von Public-Relays rendert. Ablösung der Hugo-Seite auf All-Inkl ohne
eigene Infrastruktur in Phase 1; Stubs, eigener Relay und Blossom als
Evolutionspfad.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>