Commit Graph

152 Commits

Author SHA1 Message Date
Jörg Lohrer 998e08e073 feat(snapshot): config validiert BOOTSTRAP_RELAY-prefix
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:20:29 +02:00
Jörg Lohrer 1827817ad5 docs(snapshot): drop-check-semantik dokumentiert
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:20:01 +02:00
Jörg Lohrer 715c1f5e1e fix(snapshot): tagsAll filtert tags ohne value
Vorher konnten malformed tags wie ['t'] (ohne second element)
undefined ins string[]-array werfen, das im JSON als null landete.
Code-review-feedback aus etappe 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:19:51 +02:00
Jörg Lohrer 848cdf763e fix(snapshot): NIP-09-filter beachtet zeitliche reihenfolge
Per NIP-09 darf ein deletion nur events mit created_at <= deletion.created_at
loeschen. Vorher wurde ein re-publizierter post nach geloeschtem vorgaenger
stumm wegfiltern. Code-review-feedback aus etappe 2.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:19:20 +02:00
Jörg Lohrer 0755498937 feat(snapshot): output-writer (index.json + posts/<slug>.json)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:12:01 +02:00
Jörg Lohrer a199f1daf1 feat(snapshot): cache-state fuer last-known-good
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:11:36 +02:00
Jörg Lohrer 2af44035b8 feat(snapshot): cover-image-HEAD-probe-modul
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:11:17 +02:00
Jörg Lohrer 4b2c157938 feat(snapshot): post-json-builder mit fallback-summary
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:10:55 +02:00
Jörg Lohrer 7e38b73785 feat(snapshot): plausibilitaets-checks (relay-quorum, drop, min-events)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:10:07 +02:00
Jörg Lohrer ccd7daf14d feat(snapshot): NIP-09-filter
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:09:37 +02:00
Jörg Lohrer 300cd9bea9 feat(snapshot): dedup-by-d-tag
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:09:14 +02:00
Jörg Lohrer 45df54f2b3 feat(snapshot): config-loader mit env-validierung
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:08:46 +02:00
Jörg Lohrer b6366ea1fe feat(snapshot): modul-skelett
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:08:17 +02:00
Jörg Lohrer c391df0d55 chore(render): alte dompurify-deps entfernt + design-rationale-kommentar
Dead-code aus etappe 1 nachgezogen:
- dompurify + @types/dompurify aus package.json (jetzt isomorphic-dompurify
  als einziger sanitizer, bringt eigene typen mit)
- design-rationale-kommentar fuer markedInstance zurueckgebracht
  (Spec §3: lokale ersetzbarkeit der engine — nicht aus dem code ablesbar)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:05:37 +02:00
Jörg Lohrer e0d723df14 feat(render): renderMarkdown auf isomorphic-dompurify umgestellt
Funktioniert jetzt sowohl in Browser/jsdom als auch in Node (SvelteKit-Build).
Schritt 1 der prerender-snapshot-migration. Verhalten in der SPA unveraendert.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:00:56 +02:00
Jörg Lohrer f606748c3e test: failing node-test fuer renderMarkdown
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 08:00:13 +02:00
Jörg Lohrer 0b287f9ff6 docs: jsonld via svelte-tag statt {@html}
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>
2026-04-28 07:56:58 +02:00
Jörg Lohrer 7428930a76 docs: implementation-plan fuer prerender-snapshot
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>
2026-04-28 07:54:18 +02:00
Jörg Lohrer a278f65edf docs: prerender-snapshot-spec — drei klarstellungen
- 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>
2026-04-28 07:46:51 +02:00
Jörg Lohrer fdab93e829 docs: top-level-rollen geklaert + status-stempel
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>
2026-04-28 07:30:44 +02:00
Jörg Lohrer 050a38d51a docs: plaene ins archiv verschoben
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>
2026-04-28 07:30:31 +02:00
Jörg Lohrer 9017ed1926 docs: spec-header-konvention vereinheitlicht + cleanup-spec
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>
2026-04-28 07:30:24 +02:00
Jörg Lohrer 11e406e5de docs: prerender-snapshot spec-klarstellungen + implementation-plan
spec:
- deploy upload-reihenfolge: drei-phasen-flow (assets → html → delete)
  mit präziser beschreibung statt flag-kombi-raten
- migrations-schritt 4 + 5 entkoppelt: 4 liefert snapshot primär mit
  runtime-fallback für nostr-first-posts, 5 entfernt fallback erst
  nach stabilem cutover
- exclude-glob im delete-pass für extern verwaltete files

plan (20 tasks, tdd):
- snapshot/ als deno-modul mit config, relays, dedup, plausibility,
  cover, extract, write — voll unit-getestet
- renderMarkdown auf isomorphic-dompurify
- sveltekit-route mit prerender=true, entries, og/twitter/json-ld/
  hreflang im head, snapshot-primary + runtime-fallback
- deploy-script auf lftp drei-phasen
- dokumentation in HANDOFF und CLAUDE.md

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 17:20:25 +02:00
Jörg Lohrer fd093dff5e docs: markdown-rendering aus snapshot in svelte-build verschoben
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>
2026-04-21 17:08:10 +02:00
Jörg Lohrer 48d05f8d2d docs: spec-review-eingearbeitet (HTML-render, Felder, Migration)
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>
2026-04-21 17:05:43 +02:00
Jörg Lohrer 708c86aa29 docs: spec für prerender-snapshot (SEO + social-media-cards)
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>
2026-04-21 16:56:41 +02:00
Jörg Lohrer d12ed3c40e docs: status/handoff/readme/claude.md auf multilingual-stand
- 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>
2026-04-21 16:31:16 +02:00
Jörg Lohrer 9040e5ac02 feat(app): sprach-switcher direkt im post (📖 DE | EN)
statt text-hinweis "auch verfügbar in: ..." zeigt der post jetzt einen
kompakten switcher (📖 aktiver-code | anderer-code). klick auf den
anderen code setzt die ui-sprache global und navigiert zur sprach-
variante — alles konsistent.

language names raus (unused): displayLanguage + tests entfernt, da die
darstellung nun nur noch sprachcodes (DE/EN) zeigt. auch i18n-keys
lang.de/lang.en und post.also_available_in aufgeräumt.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 16:09:33 +02:00
Jörg Lohrer 238b2a0938 feat(app): impressum-seitentitel lokalisiert (inhalt bleibt DE) 2026-04-21 14:15:04 +02:00
Jörg Lohrer 259d7949dd feat(app): post-route + komponenten lokalisiert (titel, datum, hinweise) 2026-04-21 14:13:59 +02:00
Jörg Lohrer 3411af610e feat(app): archiv-seite lokalisiert + nach locale gefiltert 2026-04-21 14:08:42 +02:00
Jörg Lohrer d7510953d2 feat(app): startseite lokalisiert + liste nach aktivem locale gefiltert 2026-04-21 14:07:17 +02:00
Jörg Lohrer d256670b56 feat(app): layout-header lokalisiert + sprach-switcher eingebunden 2026-04-21 14:00:26 +02:00
Jörg Lohrer 617b3dfccc feat(app): LanguageSwitcher-komponente mit de/en-buttons
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:33:40 +02:00
Jörg Lohrer 22997138f9 feat(app): i18n-init registriert messages und syncs mit activeLocale
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:33:19 +02:00
Jörg Lohrer 8f513495e3 feat(app): activeLocale-store mit persistence + initial-detection 2026-04-21 13:32:34 +02:00
Jörg Lohrer f799223836 chore(app): svelte-i18n + ui-messages-files (de/en)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:30:39 +02:00
Jörg Lohrer 5bab73def7 docs: plan 3/3 für multilinguale SPA (svelte-i18n + listen-filter)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:29:38 +02:00
Jörg Lohrer 0fca9cbfa2 fix(app): post-route lädt reaktiv via $effect statt onMount
bei navigation zwischen slugs innerhalb der gleichen [...slug]-route
bleibt die komponente montiert — onMount feuert dann nicht mehr, und
der neue post lud erst nach manuellem reload. $effect auf dtag löst
das und rendert die neue view sofort.

race-condition-guard: currentDtag wird pro effect-lauf festgefroren;
stale responses werden verworfen.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 13:17:41 +02:00
Jörg Lohrer bf7b52ab9b feat(content): erste englische übersetzung (bible-selfies) + bidirektionaler a-tag
- 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>
2026-04-21 12:53:59 +02:00
Jörg Lohrer 4a06213d03 feat(app): LanguageAvailability-komponente in PostView eingebunden 2026-04-21 12:49:59 +02:00
Jörg Lohrer 7f48644dfc feat(app): loadTranslations liefert sprach-varianten eines posts 2026-04-21 12:43:52 +02:00
Jörg Lohrer 8f4125fcc9 feat(app): displayLanguage code→anzeigename 2026-04-21 12:41:29 +02:00
Jörg Lohrer ef20e13172 feat(app): parseTranslationRefs extrahiert a-tags mit marker translation 2026-04-21 12:37:08 +02:00
Jörg Lohrer c28a64ed49 docs: plan 2/3 für multilinguale SPA (a-tag-resolving + sprachhinweis)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 12:32:13 +02:00
Jörg Lohrer b9eb2c0bab test: re-trigger action nach contentRoot-pfad-fix
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 10:18:51 +02:00
Jörg Lohrer ccbfc61a7c fix(publish): changedPostDirs gibt pfade mit original-contentRoot zurück 2026-04-21 10:18:20 +02:00
Jörg Lohrer 6055a8c1cc test: trigger action-smoketest nach contentRoot-fix
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 10:12:22 +02:00
Jörg Lohrer b89442bf5c fix(publish): changedPostDirs normalisiert ../-präfix im contentRoot 2026-04-21 10:10:01 +02:00
Jörg Lohrer 367af9df9f test: trigger github-action nach struktur-migration
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-21 09:59:14 +02:00