Compare commits
2 Commits
10e455a078
...
40785df346
| Author | SHA1 | Date |
|---|---|---|
|
|
40785df346 | |
|
|
54eb0b62cb |
87
README.md
87
README.md
|
|
@ -1,46 +1,97 @@
|
||||||
# joerg-lohrer.de
|
# joerg-lohrer.de
|
||||||
|
|
||||||
Persönliche Webseite. In Transition von einer Hugo-basierten, statischen Seite
|
Persönliche Webseite. Nach einer Transition von einer Hugo-basierten,
|
||||||
hin zu einer SvelteKit-SPA, die Blog-Posts live aus signierten Nostr-Events
|
statischen Seite läuft `joerg-lohrer.de` jetzt als SvelteKit-SPA, die
|
||||||
(NIP-23, `kind:30023`) rendert.
|
Blog-Posts live aus signierten Nostr-Events (NIP-23, `kind:30023`) rendert.
|
||||||
|
|
||||||
## Aktueller Stand
|
## Aktueller Stand
|
||||||
|
|
||||||
- **`https://joerg-lohrer.de/`** — Hugo-Seite, läuft noch.
|
- **`https://joerg-lohrer.de/`** — SvelteKit-SPA, Cutover am 2026-04-18 erfolgt.
|
||||||
- **`https://spa.joerg-lohrer.de/`** — Vanilla-HTML-Mini-Spike (Proof of Concept).
|
- **`https://staging.joerg-lohrer.de/`** — Staging (gleicher Build, ein Schritt vor Prod).
|
||||||
- **`https://svelte.joerg-lohrer.de/`** — produktive SvelteKit-SPA (Ziel).
|
- **`https://svelte.joerg-lohrer.de/`** — Entwicklungs-Deploy-Target der Pipeline.
|
||||||
|
- **`https://spa.joerg-lohrer.de/`** — Vanilla-HTML-Mini-Spike (Proof of Concept, historisch).
|
||||||
|
|
||||||
Detailliert in [`docs/STATUS.md`](docs/STATUS.md).
|
Detailliert in [`docs/STATUS.md`](docs/STATUS.md).
|
||||||
|
|
||||||
|
## Wie die Seite funktioniert
|
||||||
|
|
||||||
|
1. **Inhalte** liegen als Markdown in `content/posts/<slug>/index.md` mit
|
||||||
|
strukturierten Bild-Metadaten im Frontmatter (Alt-Text, Lizenz, Autor:innen).
|
||||||
|
2. **Publish-Pipeline** (`publish/`, Deno) lädt Bilder auf Blossom-Server
|
||||||
|
(content-addressed) und publiziert signierte `kind:30023`-Events via
|
||||||
|
NIP-46-Bunker (Amber) auf 5 Relays.
|
||||||
|
3. **SvelteKit-SPA** (`app/`) lädt diese Events zur Laufzeit und rendert
|
||||||
|
Post-Liste + Detailseiten. Keine Server-Komponente, Static-Hosting reicht.
|
||||||
|
4. **CI**: GitHub Actions triggert die Publish-Pipeline bei Push auf `main`
|
||||||
|
(via Forgejo→GitHub Push-Mirror).
|
||||||
|
|
||||||
|
Identität und Assets:
|
||||||
|
- **Pubkey:** `npub1f7jar3qnu269uyx5p0e4v24hqxjnxysxudvujza2ur5ehltvdeqsly2fx9`
|
||||||
|
- **NIP-05:** `joerglohrer@joerg-lohrer.de` (statisches `.well-known/nostr.json`)
|
||||||
|
- **Blossom-Server:** `blossom.edufeed.org`, `blossom.primal.net`
|
||||||
|
- **Relays:** `relay.damus.io`, `nos.lol`, `relay.primal.net`, `relay.tchncs.de`, `relay.edufeed.org`
|
||||||
|
|
||||||
## Navigation
|
## Navigation
|
||||||
|
|
||||||
- 📍 **Stand und Live-URLs:** [`docs/STATUS.md`](docs/STATUS.md)
|
- 📍 **Stand und Live-URLs:** [`docs/STATUS.md`](docs/STATUS.md)
|
||||||
- 🔜 **Wie es weitergeht:** [`docs/HANDOFF.md`](docs/HANDOFF.md)
|
- 🔜 **Wie es weitergeht:** [`docs/HANDOFF.md`](docs/HANDOFF.md)
|
||||||
- 📐 **SPA-Spec:** [`docs/superpowers/specs/2026-04-15-nostr-page-design.md`](docs/superpowers/specs/2026-04-15-nostr-page-design.md)
|
- 📐 **SPA-Spec:** [`docs/superpowers/specs/2026-04-15-nostr-page-design.md`](docs/superpowers/specs/2026-04-15-nostr-page-design.md)
|
||||||
- 📐 **Publish-Pipeline-Spec:** [`docs/superpowers/specs/2026-04-15-publish-pipeline-design.md`](docs/superpowers/specs/2026-04-15-publish-pipeline-design.md)
|
- 📐 **Publish-Pipeline-Spec:** [`docs/superpowers/specs/2026-04-15-publish-pipeline-design.md`](docs/superpowers/specs/2026-04-15-publish-pipeline-design.md)
|
||||||
|
- 📐 **Bild-Metadaten-Konvention:** [`docs/superpowers/specs/2026-04-16-image-metadata-convention.md`](docs/superpowers/specs/2026-04-16-image-metadata-convention.md)
|
||||||
- 🛠 **SvelteKit-SPA-Plan:** [`docs/superpowers/plans/2026-04-15-spa-sveltekit.md`](docs/superpowers/plans/2026-04-15-spa-sveltekit.md) (35 Tasks, abgeschlossen)
|
- 🛠 **SvelteKit-SPA-Plan:** [`docs/superpowers/plans/2026-04-15-spa-sveltekit.md`](docs/superpowers/plans/2026-04-15-spa-sveltekit.md) (35 Tasks, abgeschlossen)
|
||||||
|
- 🛠 **Publish-Pipeline-Plan:** [`docs/superpowers/plans/2026-04-16-publish-pipeline.md`](docs/superpowers/plans/2026-04-16-publish-pipeline.md) (24 Tasks, abgeschlossen)
|
||||||
- 🤖 **Claude-Workflow-Skill:** [`.claude/skills/joerglohrerde-workflow.md`](.claude/skills/joerglohrerde-workflow.md)
|
- 🤖 **Claude-Workflow-Skill:** [`.claude/skills/joerglohrerde-workflow.md`](.claude/skills/joerglohrerde-workflow.md)
|
||||||
|
|
||||||
## Branches
|
## Branches
|
||||||
|
|
||||||
- **`main`** — kanonisch (Content, Specs, Pläne, Deploy-Scripts, Skill).
|
- **`main`** — kanonisch. Seit Cutover (2026-04-18) Produktions-Quelle.
|
||||||
- **`spa`** — aktueller Arbeitszweig mit allen SvelteKit-Commits. Wird beim
|
- **`spa`** — historischer SvelteKit-Arbeitszweig, inzwischen gemerged.
|
||||||
Cutover nach `main` gemerged.
|
|
||||||
- **`hugo-archive`** — eingefrorener Hugo-Zustand als Orphan-Branch.
|
- **`hugo-archive`** — eingefrorener Hugo-Zustand als Orphan-Branch.
|
||||||
Rollback über `git checkout hugo-archive && hugo build`.
|
Rollback-Option über `git checkout hugo-archive && hugo build`.
|
||||||
|
|
||||||
## Repo-Struktur
|
## Repo-Struktur
|
||||||
|
|
||||||
```
|
```
|
||||||
content/posts/ Markdown-Posts (Quelle für Nostr-Events)
|
content/posts/ Markdown-Posts (Quelle für Nostr-Events, 18 Stück)
|
||||||
app/ SvelteKit-SPA (Ziel-Implementation)
|
content/impressum.md Statisches Impressum (wird von SPA geladen)
|
||||||
preview/spa-mini/ Vanilla-HTML-Mini-Spike (Referenz)
|
app/ SvelteKit-SPA (Laufzeit-Renderer)
|
||||||
scripts/deploy-svelte.sh FTPS-Deploy nach svelte.joerg-lohrer.de
|
publish/ Deno-Publish-Pipeline (Blossom + Nostr)
|
||||||
static/ Site-Assets (Favicons, Profilbild)
|
preview/spa-mini/ Vanilla-HTML-Mini-Spike (historische Referenz)
|
||||||
docs/ Specs, Pläne, Status, Handoff
|
scripts/deploy-svelte.sh FTPS-Deploy, Targets: svelte/staging/prod
|
||||||
.claude/ Claude-Code-Sessions (transparenz) + Skills
|
static/ Site-Assets (Favicons, Profilbild, .well-known/)
|
||||||
|
docs/ Specs, Pläne, Status, Handoff, Wiki-Entwürfe
|
||||||
|
.github/workflows/ GitHub-Actions CI (Publish-Pipeline-Trigger)
|
||||||
|
.claude/ Claude-Code-Sessions (Transparenz) + Skills
|
||||||
|
```
|
||||||
|
|
||||||
|
## Entwicklung
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# SPA lokal
|
||||||
|
cd app && npm run dev
|
||||||
|
|
||||||
|
# SPA testen
|
||||||
|
cd app && npm run test:unit
|
||||||
|
cd app && npm run test:e2e
|
||||||
|
cd app && npm run check
|
||||||
|
|
||||||
|
# Publish-Pipeline
|
||||||
|
cd publish && deno task check # pre-flight
|
||||||
|
cd publish && deno task publish --dry-run # Simulation
|
||||||
|
cd publish && deno task publish # diff-modus echt
|
||||||
|
cd publish && deno task publish --post <slug> # ein Post
|
||||||
|
cd publish && deno task test # Tests
|
||||||
|
|
||||||
|
# Deploy
|
||||||
|
DEPLOY_TARGET=staging ./scripts/deploy-svelte.sh
|
||||||
|
DEPLOY_TARGET=prod ./scripts/deploy-svelte.sh
|
||||||
```
|
```
|
||||||
|
|
||||||
## Lizenz
|
## Lizenz
|
||||||
|
|
||||||
Siehe [LICENSE](LICENSE).
|
Inhalte: [CC0 1.0 Universal](https://creativecommons.org/publicdomain/zero/1.0/deed.de)
|
||||||
|
(Namensnennung erwünscht, aber rechtlich nicht erforderlich), sofern nicht
|
||||||
|
anders vermerkt. Drittinhalte sind beim jeweiligen Bild mit Autor:innen und
|
||||||
|
Lizenz gekennzeichnet.
|
||||||
|
|
||||||
|
Code: siehe [LICENSE](LICENSE).
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
<script lang="ts">
|
||||||
|
// CC-Zero-Badge: kombination aus CC-Heart + Zero-Logo, monochrom via
|
||||||
|
// currentColor. Icons aus dem offiziellen CC-Press-Kit
|
||||||
|
// (creativecommons.org/mission/branding/). Inline hier, weil statische
|
||||||
|
// svg-imports mit ?raw in vite problematisch sind.
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class="cc-badge" aria-hidden="true">
|
||||||
|
<!-- CC-Heart (vereinfachtes herz aus dem offiziellen logo) -->
|
||||||
|
<svg viewBox="0 0 46296 40689" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M23204.91 7530.98c2944.63,-3188.84 6384.04,-4639.01 10366.38,-4077.21 4110.34,579.88 7609.97,3518.41 8854.17,7479.01 957.39,3047.58 559.96,6460.83 -722.09,9573.35 -1993.98,4840.97 -7886.31,11722.09 -18555.24,16532.85 -10668.92,-4810.76 -16561.25,-11691.88 -18555.24,-16532.85 -1282.05,-3112.52 -1679.47,-6525.77 -722.09,-9573.35 1244.19,-3960.6 4743.83,-6899.13 8854.17,-7479.01 3982.46,-561.82 7421.94,888.46 10366.64,4077.48 5.4,5.84 56.52,61.37 56.53,61.36 0.04,0.04 51.9,-56.36 56.79,-61.63zm-56.79 -4522.44c-6431.69,-5048.01 -16512.25,-3730.83 -21147.65,3855.94 -1539.08,2519.03 -2117.14,5447.75 -1981.3,8355.45 235.64,5043.59 2412.75,9452.27 5610.61,13256.78 4306.02,5122.9 10531.26,9148.59 17382.21,12152.72 9.53,4.18 88.63,38.56 136.13,59.69 41.66,-17.53 114.6,-50.41 137.01,-60.3 6815.65,-3004.07 13075.56,-7030.12 17381.33,-12152.12 3198.08,-3804.33 5374.97,-8213.2 5610.61,-13256.78 135.85,-2907.7 -442.2,-5836.43 -1981.3,-8355.45 -4635.4,-7586.77 -14715.95,-8903.95 -21147.65,-3855.94z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M22983.64 21630.19l-2928.01 -1451.38c-1017.73,1483.99 -1758.21,2488.33 -3897.08,1902.25 -1678.91,-460.05 -2175.85,-2300.18 -2239.67,-3843.76 -87.17,-2108.39 649.94,-4543.46 3168.15,-4413.24 1609.13,83.19 2294.75,1032.23 2661.15,1885.36l3196.99 -1638.9c-1574.75,-3004.31 -5265.13,-4026.05 -8393.32,-3188.81 -3328.66,890.9 -5014.61,3952.95 -4955.5,7255.23 60.43,3375.58 1680.8,6291.51 5161.55,7052.54 1697.16,371.06 3545.13,284.81 5116.74,-503.18 1216.27,-609.83 2567.56,-1786.86 3109,-3056.12zm13802.46 0l-2928.01 -1451.38c-1017.73,1483.99 -1758.21,2488.33 -3897.08,1902.25 -1678.91,-460.05 -2175.86,-2300.18 -2239.67,-3843.76 -87.18,-2108.39 649.94,-4543.46 3168.15,-4413.24 1609.13,83.19 2294.74,1032.23 2661.15,1885.36l3196.99 -1638.9c-1574.75,-3004.31 -5265.14,-4026.05 -8393.32,-3188.81 -3328.66,890.9 -5014.61,3952.95 -4955.5,7255.23 60.42,3375.58 1680.8,6291.51 5161.55,7052.54 1697.16,371.06 3545.13,284.81 5116.74,-503.18 1216.27,-609.83 2567.56,-1786.86 3109,-3056.12z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<!-- CC-Zero (kreis + 0 aus dem cc-0-logo) -->
|
||||||
|
<svg viewBox="-0.5 0.5 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M31.5,14.08c-10.565,0-13.222,9.969-13.222,18.42c0,8.452,2.656,18.42,13.222,18.42c10.564,0,13.221-9.968,13.221-18.42C44.721,24.049,42.064,14.08,31.5,14.08z M31.5,21.026c0.429,0,0.82,0.066,1.188,0.157c0.761,0.656,1.133,1.561,0.403,2.823l-7.036,12.93c-0.216-1.636-0.247-3.24-0.247-4.437C25.808,28.777,26.066,21.026,31.5,21.026z M36.766,26.987c0.373,1.984,0.426,4.056,0.426,5.513c0,3.723-0.258,11.475-5.69,11.475c-0.428,0-0.822-0.045-1.188-0.136c-0.07-0.021-0.134-0.043-0.202-0.067c-0.112-0.032-0.23-0.068-0.336-0.11c-1.21-0.515-1.972-1.446-0.874-3.093L36.766,26.987z"
|
||||||
|
/>
|
||||||
|
<path
|
||||||
|
fill="currentColor"
|
||||||
|
d="M31.433,0.5c-8.877,0-16.359,3.09-22.454,9.3c-3.087,3.087-5.443,6.607-7.082,10.532C0.297,24.219-0.5,28.271-0.5,32.5c0,4.268,0.797,8.32,2.397,12.168c1.6,3.85,3.921,7.312,6.969,10.396c3.085,3.049,6.549,5.399,10.398,7.037c3.886,1.602,7.939,2.398,12.169,2.398c4.229,0,8.34-0.826,12.303-2.465c3.962-1.639,7.496-3.994,10.621-7.081c3.011-2.933,5.289-6.297,6.812-10.106C62.73,41,63.5,36.883,63.5,32.5c0-4.343-0.77-8.454-2.33-12.303c-1.562-3.885-3.848-7.32-6.857-10.33C48.025,3.619,40.385,0.5,31.433,0.5z M31.567,6.259c7.238,0,13.412,2.566,18.554,7.709c2.477,2.477,4.375,5.31,5.67,8.471c1.296,3.162,1.949,6.518,1.949,10.061c0,7.354-2.516,13.454-7.506,18.33c-2.592,2.516-5.502,4.447-8.74,5.781c-3.2,1.334-6.498,1.994-9.927,1.994c-3.468,0-6.788-0.653-9.949-1.948c-3.163-1.334-6.001-3.238-8.516-5.716c-2.515-2.514-4.455-5.353-5.826-8.516c-1.333-3.199-2.017-6.498-2.017-9.927c0-3.467,0.684-6.787,2.017-9.949c1.371-3.2,3.312-6.074,5.826-8.628C18.092,8.818,24.252,6.259,31.567,6.259z"
|
||||||
|
/>
|
||||||
|
</svg>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.cc-badge {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.15em;
|
||||||
|
color: var(--accent);
|
||||||
|
vertical-align: -0.2em;
|
||||||
|
}
|
||||||
|
.cc-badge svg {
|
||||||
|
width: 1.1em;
|
||||||
|
height: 1.1em;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import { onMount } from 'svelte';
|
import { onMount } from 'svelte';
|
||||||
import { page } from '$app/state';
|
import { page } from '$app/state';
|
||||||
import { bootstrapReadRelays } from '$lib/stores/readRelays';
|
import { bootstrapReadRelays } from '$lib/stores/readRelays';
|
||||||
|
import CcZeroBadge from '$lib/components/CcZeroBadge.svelte';
|
||||||
|
|
||||||
let { children } = $props();
|
let { children } = $props();
|
||||||
|
|
||||||
|
|
@ -37,11 +38,28 @@
|
||||||
|
|
||||||
<footer class="site-footer">
|
<footer class="site-footer">
|
||||||
<div class="footer-inner">
|
<div class="footer-inner">
|
||||||
<span class="footer-copy">© Jörg Lohrer</span>
|
<span class="footer-license">
|
||||||
|
<a
|
||||||
|
href="https://creativecommons.org/publicdomain/zero/1.0/deed.de"
|
||||||
|
target="_blank"
|
||||||
|
rel="license noopener"
|
||||||
|
aria-label="CC0 1.0 Universal Public Domain Dedication"
|
||||||
|
title="CC0 1.0 Universal"
|
||||||
|
>
|
||||||
|
<CcZeroBadge />
|
||||||
|
<span class="cc-label">CC0</span>
|
||||||
|
</a>
|
||||||
|
Jörg Lohrer
|
||||||
|
</span>
|
||||||
<span class="footer-sep">·</span>
|
<span class="footer-sep">·</span>
|
||||||
<a href="/impressum/">Impressum</a>
|
<a href="/impressum/">Impressum</a>
|
||||||
<span class="footer-sep">·</span>
|
<span class="footer-sep">·</span>
|
||||||
<span class="footer-meta">Nostr-basiert</span>
|
<a
|
||||||
|
href="https://github.com/joerglohrer/joerglohrerde"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener"
|
||||||
|
title="Quellcode, Making-of und Nostr-Publish-Pipeline"
|
||||||
|
>Nostr-basiert – Making-of im Repo</a>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
|
|
@ -129,7 +147,17 @@
|
||||||
.footer-sep {
|
.footer-sep {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
.footer-meta {
|
.footer-license a {
|
||||||
opacity: 0.7;
|
color: var(--accent);
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.25em;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
.footer-license a:hover .cc-label {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.cc-label {
|
||||||
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ Die Inhalte unserer Seiten wurden mit größter Sorgfalt erstellt. Für die Rich
|
||||||
Mein Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte ich keinen Einfluss habe. Deshalb kann ich für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werde ich derartige Links umgehend entfernen.
|
Mein Angebot enthält Links zu externen Webseiten Dritter, auf deren Inhalte ich keinen Einfluss habe. Deshalb kann ich für diese fremden Inhalte auch keine Gewähr übernehmen. Für die Inhalte der verlinkten Seiten ist stets der jeweilige Anbieter oder Betreiber der Seiten verantwortlich. Die verlinkten Seiten wurden zum Zeitpunkt der Verlinkung auf mögliche Rechtsverstöße überprüft. Rechtswidrige Inhalte waren zum Zeitpunkt der Verlinkung nicht erkennbar. Eine permanente inhaltliche Kontrolle der verlinkten Seiten ist jedoch ohne konkrete Anhaltspunkte einer Rechtsverletzung nicht zumutbar. Bei Bekanntwerden von Rechtsverletzungen werde ich derartige Links umgehend entfernen.
|
||||||
|
|
||||||
### Urheberrecht
|
### Urheberrecht
|
||||||
Die durch den Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Die Vervielfältigung, Bearbeitung, Verbreitung und jede Art der Verwertung außerhalb der Grenzen des Urheberrechtes bedürfen jedoch nicht der schriftlichen Zustimmung des jeweiligen Autors bzw. Erstellers. Downloads und Kopien dieser Seite sind sowohl für den privaten, als auch für den kommerziellen Gebrauch unter Namensnennung und der Creative Commons Lizenz [CC BY-SA](https://creativecommons.org/licenses/by-sa/4.0/deed.de) gestattet. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Solltest Du trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitten ich um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werde ich derartige Inhalte umgehend entfernen.
|
Die durch den Seitenbetreiber erstellten Inhalte und Werke auf diesen Seiten unterliegen dem deutschen Urheberrecht. Soweit nicht anders angegeben, stelle ich eigene Inhalte und Werke unter der Creative-Commons-Lizenz [CC0 1.0 Universal (Public Domain Dedication)](https://creativecommons.org/publicdomain/zero/1.0/deed.de) zur Verfügung — sie dürfen ohne Rückfrage für jeden Zweck, auch kommerziell, kopiert, bearbeitet, verbreitet und weiterverwendet werden. Eine Namensnennung ist rechtlich nicht erforderlich, aber ich freue mich natürlich, wenn Du mich als Quelle nennst. Wo eine abweichende Lizenz gilt, ist sie beim jeweiligen Inhalt vermerkt. Soweit die Inhalte auf dieser Seite nicht vom Betreiber erstellt wurden, werden die Urheberrechte Dritter beachtet. Insbesondere werden Inhalte Dritter als solche gekennzeichnet. Solltest Du trotzdem auf eine Urheberrechtsverletzung aufmerksam werden, bitte ich um einen entsprechenden Hinweis. Bei Bekanntwerden von Rechtsverletzungen werde ich derartige Inhalte umgehend entfernen.
|
||||||
|
|
||||||
### Datenschutz
|
### Datenschutz
|
||||||
Die Nutzung meiner Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf meiner Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder eMail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Deine ausdrückliche Zustimmung nicht an Dritte weitergegeben. Ich weise darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich. Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.
|
Die Nutzung meiner Webseite ist in der Regel ohne Angabe personenbezogener Daten möglich. Soweit auf meiner Seiten personenbezogene Daten (beispielsweise Name, Anschrift oder eMail-Adressen) erhoben werden, erfolgt dies, soweit möglich, stets auf freiwilliger Basis. Diese Daten werden ohne Deine ausdrückliche Zustimmung nicht an Dritte weitergegeben. Ich weise darauf hin, dass die Datenübertragung im Internet (z.B. bei der Kommunikation per E-Mail) Sicherheitslücken aufweisen kann. Ein lückenloser Schutz der Daten vor dem Zugriff durch Dritte ist nicht möglich. Der Nutzung von im Rahmen der Impressumspflicht veröffentlichten Kontaktdaten durch Dritte zur Übersendung von nicht ausdrücklich angeforderter Werbung und Informationsmaterialien wird hiermit ausdrücklich widersprochen. Die Betreiber der Seiten behalten sich ausdrücklich rechtliche Schritte im Falle der unverlangten Zusendung von Werbeinformationen, etwa durch Spam-Mails, vor.
|
||||||
156
docs/HANDOFF.md
156
docs/HANDOFF.md
|
|
@ -5,87 +5,87 @@ Dieses Dokument sagt: was ist der Zustand, was wartet, wo liegen die Fäden.
|
||||||
|
|
||||||
## Zustand (Details in `STATUS.md`)
|
## Zustand (Details in `STATUS.md`)
|
||||||
|
|
||||||
**Die Nostr-Publish-Pipeline ist live.** Alle 18 Posts sind publiziert als
|
**Cutover am 2026-04-18 abgeschlossen.** `joerg-lohrer.de` läuft als
|
||||||
`kind:30023`-Events auf 5 Relays, 91 Bilder auf 2 Blossom-Servern. Die
|
SvelteKit-SPA, rendert 18 Nostr-Langform-Posts live aus 5 Relays, Bilder
|
||||||
SvelteKit-SPA unter `svelte.joerg-lohrer.de` rendert alles ordentlich.
|
auf 2 Blossom-Servern. Hugo-Altbestand liegt als `hugo-archive`-Branch
|
||||||
|
eingefroren.
|
||||||
|
|
||||||
**Das inhaltliche Kernziel des Gesamtprojekts ist damit erreicht.**
|
Der Rest sind Feinschliff-Aufgaben.
|
||||||
|
|
||||||
Der Rest sind Feinschliff- und Cutover-Aufgaben.
|
## Was als Nächstes ansteht (priorisiert)
|
||||||
|
|
||||||
## Was als Nächstes ansteht
|
### Option A — Repo/Nostr-Konflikt-Management (priorisiert)
|
||||||
|
|
||||||
### Option 1 — CI-Push-Auto-Trigger verifizieren (optional)
|
**Warum jetzt:** Es gibt **9 Langform-Events auf Nostr, die keine
|
||||||
|
Markdown-Entsprechung im Repo haben** — alle via Client (Habla / Yakihonne)
|
||||||
|
direkt auf Nostr erstellt, zum Teil mit problematischen d-tags (Emojis,
|
||||||
|
Doppelpunkte, Umlaute, Trailing-Dashes, oder leer).
|
||||||
|
|
||||||
**Status:** Workflow-Manual-Trigger ist grün (Run #1 am 18.04.2026).
|
**Liste der verwaisten Nostr-Events** (d-tag → event-id-Prefix):
|
||||||
Automatischer Auto-Trigger bei Content-Push noch nicht ausprobiert —
|
|
||||||
kann jederzeit beiläufig mitgenommen werden:
|
|
||||||
|
|
||||||
1. Minimaler Edit in einem Post (z. B. Typo) → commit → push `main`
|
| d-tag | event-id | Probleme |
|
||||||
2. Forgejo synct automatisch zu GitHub → Workflow triggert → 1 Post als
|
|---|---|---|
|
||||||
`update` publiziert
|
| `richter-oder-rcher-banksy-als-moderner-prophet-vor-dem-high-court` | `bb2c2cea…` | Umlaut-Abdecker (`Rächer` → `rcher`) |
|
||||||
3. Log-Artefakt in GitHub Actions prüfen
|
| `die-kraft-der-gemeinschaft-wahre-strke-liegt-nicht-in-strukturen-sondern-in-prozessen` | `27d7fbee…` | Umlaut-Abdecker (`Stärke` → `strke`) |
|
||||||
|
| `nostr-und-open-educational-practices-oep-` | `0baa3615…` | Trailing-Dash, unschön |
|
||||||
|
| `religionsbezogene-bildung-mit-rollenkarten:-ki-bilder-als-impulsgeber` | `3ac719ca…` | `:` ungültig für URL-Slug |
|
||||||
|
| `📢-empowering-learners-for-the-age-of-ai-–-der-neue-review-draft-des-ai-literacy-frameworks-für-schule-ist-da!` | `3c005996…` | Emoji + `!` + Umlaute + extrem lang |
|
||||||
|
| `🟠-prompts-für-die-religionsbezogene-bildung-posten-und-diskutieren-auf-nostr` | `f726fcd5…` | Emoji + Umlaute |
|
||||||
|
| `ki-mitmachen` | `a1368d2e…` | sauber, aber fehlt im Repo |
|
||||||
|
| `bibel-selfies` | `00cbe5f3…` | Langform-Version; Duplikat mit Unix-Timestamp wurde bereits gelöscht |
|
||||||
|
| `""` (leer!) | `d75857dc…` | leerer d-tag — SPA-kritisch, Event hat keinen Slug |
|
||||||
|
|
||||||
Kein Ziel mehr, nur Bestätigung. Pipeline ist funktional vollständig.
|
**Zielbild:** Repo ist die Quelle der Wahrheit. Jeder Post existiert als
|
||||||
|
Markdown mit sauberem Slug. d-tags sind URL-freundlich (ASCII, keine
|
||||||
|
Sonderzeichen außer `-`).
|
||||||
|
|
||||||
### Option 2 — Cutover auf `joerg-lohrer.de`
|
**Empfohlener Flow (Reihenfolge nicht tauschen!):**
|
||||||
|
|
||||||
**Voraussetzung:** Option 1 optional, aber nicht blockierend. Die Pipeline
|
1. **Content exportieren.** Pro Event: `nak req -i <event-id> <relay>` →
|
||||||
läuft ja schon, ob manuell oder via CI ist für den Cutover egal.
|
JSON mit Content + Tags. Manuell in neue Markdown-Datei umwandeln
|
||||||
|
(`content/posts/<YYYY-MM-DD>-<saubererslug>/index.md`). Titel,
|
||||||
|
published_at, ggf. summary und bestehende image-Tags übernehmen.
|
||||||
|
Bilder nach `images/` kopieren (falls noch erreichbar), sonst
|
||||||
|
Blossom-URLs im Markdown belassen und beim Publish neu hashen.
|
||||||
|
2. **Slugs bereinigen.** Neue, saubere, ASCII-only d-tags wählen. Doku
|
||||||
|
in `docs/redaktion-bild-metadaten.md` oder einem neuen
|
||||||
|
`docs/nostr-reimport-mapping.md` festhalten (alter d-tag → neuer slug).
|
||||||
|
3. **Neu publizieren.** `deno task publish --post <slug>` pro Datei.
|
||||||
|
Pipeline hasht Bilder zu Blossom, signiert mit stabiler Identität.
|
||||||
|
4. **Alte Events löschen** via NIP-09 (`kind:5`). Heute noch manuell per
|
||||||
|
`nak event -k 5 -t e=<old-event-id>`, siehe Option D. Oder: erst
|
||||||
|
Option D bauen, dann diesen Schritt per Pipeline-Subcommand.
|
||||||
|
5. **Verifikation.** Post-Count pro Relay checken, SPA-Post-Liste
|
||||||
|
visuell prüfen.
|
||||||
|
|
||||||
**Schritte:**
|
**Edge Cases:**
|
||||||
1. In All-Inkl KAS die Domain `joerg-lohrer.de` auf den SvelteKit-Webroot
|
- Das leere-d-tag-Event (`d75857dc…`): wenn es noch sinnvoller Content
|
||||||
umhängen (aktuell: `svelte.joerg-lohrer.de` → `/www/htdocs/v109928/joerglohrer28/`
|
ist, als neuer Post re-importieren. Sonst einfach löschen.
|
||||||
oder welcher Ordner auch immer).
|
- Bilder in alten Events zeigen auf externe Server (nicht Blossom). Beim
|
||||||
2. SvelteKit-SPA deployen, sofern sie nicht schon dort liegt.
|
Re-Publish lädt die Pipeline sie herunter und hasht sie neu. Wenn die
|
||||||
3. Live-Check: `curl -sI https://joerg-lohrer.de/` → sollte die neue SPA
|
Quelle tot ist, muss das Bild manuell beschafft oder der Post mit
|
||||||
liefern, nicht mehr Hugo.
|
Platzhalter markiert werden.
|
||||||
|
- `relay.damus.io` liefert mehr Events als andere Relays — bei
|
||||||
|
Nicht-Auffindbarkeit auf anderen Relays trotzdem löschen, damus.io
|
||||||
|
respektiert den NIP-09.
|
||||||
|
|
||||||
Hugo-Altbestand bleibt als Archiv im `hugo-archive`-Branch.
|
### Option B — SPA respektiert NIP-09-Deletion-Events
|
||||||
|
|
||||||
### Option 3 — Startseite + Menü-Navigation + Impressum in der SPA
|
|
||||||
|
|
||||||
**Unabhängig von Cutover**, aber Voraussetzung für diesen: ohne Design wäre
|
|
||||||
die Hauptdomain eine rohe Post-Liste.
|
|
||||||
|
|
||||||
- **Startseite** bekommt ein eigenes Design (nicht nur Post-Liste dump)
|
|
||||||
- **Menü-Navigation** in `app/src/routes/+layout.svelte` (Home, Archiv,
|
|
||||||
Impressum, Mastodon-Link)
|
|
||||||
- **Impressum** als Static-Page (SvelteKit-Route `/impressum/`), **nicht**
|
|
||||||
als Nostr-Event — soll nicht als Blog-Beitrag in Listen erscheinen.
|
|
||||||
Text ist bereits im `content/`-Ordner (Repo-Quelle); die einzige
|
|
||||||
rechtlich relevante HTML-Datei, die auf dem Server liegt.
|
|
||||||
|
|
||||||
### Option 4 — SPA respektiert `kind:5`-Deletion-Events
|
|
||||||
|
|
||||||
**Status:** aktuell filtert die SPA nicht nach NIP-09. Wenn ein Event per
|
**Status:** aktuell filtert die SPA nicht nach NIP-09. Wenn ein Event per
|
||||||
`kind:5`-Referenz gelöscht wurde (z. B. `7f5d08b8…` deletet `89609df5…`
|
`kind:5`-Referenz gelöscht wurde, zeigen Relays es meist nicht mehr aus —
|
||||||
für `d=1744905463975` am 18.04.), zeigen Relays es meist nicht mehr aus —
|
|
||||||
aber die SPA würde es trotzdem rendern, falls ein Relay es doch liefert.
|
aber die SPA würde es trotzdem rendern, falls ein Relay es doch liefert.
|
||||||
|
|
||||||
**Zu tun:** im `kind:30023`-Loader (`app/src/lib/nostr/...`) einen
|
**Zu tun:** im `kind:30023`-Loader (`app/src/lib/nostr/…`) einen
|
||||||
Cross-Check auf `kind:5`-Events einbauen. Events, deren Addressable-Pointer
|
Cross-Check auf `kind:5`-Events einbauen. Events, deren Addressable-Pointer
|
||||||
(`30023:pubkey:d-tag`) in einem `kind:5` referenziert ist, werden
|
(`30023:pubkey:d-tag`) in einem `kind:5` referenziert ist, werden
|
||||||
gefiltert. Defensive Maßnahme für zukünftige Duplikate / Soft-Deletes.
|
gefiltert. Defensive Maßnahme für zukünftige Duplikate / Soft-Deletes.
|
||||||
|
|
||||||
### Option 5 — Repo/Nostr-Konflikt-Management
|
### Option C — Postfach `webmaster@joerg-lohrer.de`
|
||||||
|
|
||||||
**Warum:** aktuell ist die Pipeline eine einseitige Straße — Repo → Nostr.
|
User-Task: im All-Inkl KAS als Weiterleitung anlegen. Der Link im
|
||||||
Wenn du via Client (Habla, Yakihonne, Amber) auf Nostr editierst,
|
Footer und in den Social-Icons zeigt bereits darauf.
|
||||||
überschreibt der nächste Pipeline-Lauf deine Client-Edits mit dem (alten)
|
|
||||||
Repo-State. Das ist ein echter Datenverlust-Risikofaktor.
|
|
||||||
|
|
||||||
**Zu tun:**
|
### Option D — NIP-09-Delete als Pipeline-Subcommand
|
||||||
- **Defensiv (`created_at`-Check):** Pipeline liest vor Publish das
|
|
||||||
aktuelle Event vom Relay und vergleicht `created_at`. Wenn das
|
|
||||||
Remote-Event neuer ist: Abbruch mit Warnung.
|
|
||||||
- **Reverse-Sync (`pull-from-nostr`-Subcommand):** liest Events, vergleicht
|
|
||||||
mit Repo, zeigt Diffs. Manuelle Konfliktauflösung.
|
|
||||||
|
|
||||||
Keine Eile, solange du nicht parallel editierst. Erst relevant, wenn du
|
|
||||||
dich an Habla & Co. gewöhnst.
|
|
||||||
|
|
||||||
### Option 6 — NIP-09-Delete als Pipeline-Subcommand
|
|
||||||
|
|
||||||
**Status:** heute einmalig per `nak event -k 5 …` mit neu erzeugter Bunker-
|
**Status:** heute einmalig per `nak event -k 5 …` mit neu erzeugter Bunker-
|
||||||
URL erledigt (Duplikat `1744905463975`). Das war ein Workaround um das
|
URL erledigt (Duplikat `1744905463975`). Das war ein Workaround um das
|
||||||
|
|
@ -100,9 +100,10 @@ deno task publish-delete --slug <slug>
|
||||||
deno task publish-delete --event-id <hex>
|
deno task publish-delete --event-id <hex>
|
||||||
```
|
```
|
||||||
|
|
||||||
Jetzt nicht dringend — nur bauen, wenn der Fall öfter eintritt.
|
**Sinnvollerweise mit Option A kombinieren** — in der Re-Import-Kampagne
|
||||||
|
werden 9 NIP-09 hintereinander gebraucht.
|
||||||
|
|
||||||
### Option 7 — Pipeline weg von GitHub (self-hosted CI)
|
### Option E — Pipeline weg von GitHub (self-hosted CI)
|
||||||
|
|
||||||
**Wann:** Wenn der Optiplex-Server steht und ein zentraler Ort für Dienste
|
**Wann:** Wenn der Optiplex-Server steht und ein zentraler Ort für Dienste
|
||||||
existiert.
|
existiert.
|
||||||
|
|
@ -116,6 +117,17 @@ existiert.
|
||||||
Der Pipeline-Code selbst (`publish/src/**`) ist CI-agnostisch — nur die
|
Der Pipeline-Code selbst (`publish/src/**`) ist CI-agnostisch — nur die
|
||||||
Trigger-Konfiguration ändert sich.
|
Trigger-Konfiguration ändert sich.
|
||||||
|
|
||||||
|
### Option F — Design-Refinements
|
||||||
|
|
||||||
|
**Wann:** irgendwann, wenn Lust drauf ist.
|
||||||
|
|
||||||
|
- Parallax-Effekte, Animations
|
||||||
|
- Dark-Mode-Feinschliff (aktuell `prefers-color-scheme`, könnte Toggle bekommen)
|
||||||
|
- Typografie-Experimente (Variable Fonts?)
|
||||||
|
- Bildergalerie-Komponente für Posts mit vielen Bildern
|
||||||
|
|
||||||
|
Alles nicht-blockierend, die SPA funktioniert solide.
|
||||||
|
|
||||||
## Schnell-Orientierung für die nächste Claude-Session
|
## Schnell-Orientierung für die nächste Claude-Session
|
||||||
|
|
||||||
Lies in dieser Reihenfolge:
|
Lies in dieser Reihenfolge:
|
||||||
|
|
@ -134,7 +146,8 @@ cd app && npm run check
|
||||||
cd app && npm run dev
|
cd app && npm run dev
|
||||||
|
|
||||||
# SPA-Build + Deploy
|
# SPA-Build + Deploy
|
||||||
cd app && npm run build && cd .. && ./scripts/deploy-svelte.sh
|
DEPLOY_TARGET=staging ./scripts/deploy-svelte.sh
|
||||||
|
DEPLOY_TARGET=prod ./scripts/deploy-svelte.sh
|
||||||
|
|
||||||
# Publish-Pipeline
|
# Publish-Pipeline
|
||||||
cd publish && deno task check # pre-flight
|
cd publish && deno task check # pre-flight
|
||||||
|
|
@ -142,7 +155,7 @@ cd publish && deno task publish --dry-run # diff-modus simulation
|
||||||
cd publish && deno task publish # diff-modus echt
|
cd publish && deno task publish # diff-modus echt
|
||||||
cd publish && deno task publish --force-all # alle posts
|
cd publish && deno task publish --force-all # alle posts
|
||||||
cd publish && deno task publish --post <slug> # einen post
|
cd publish && deno task publish --post <slug> # einen post
|
||||||
cd publish && deno task test # 59 tests
|
cd publish && deno task test # tests
|
||||||
```
|
```
|
||||||
|
|
||||||
## Bekannte Stolperfallen
|
## Bekannte Stolperfallen
|
||||||
|
|
@ -161,6 +174,9 @@ cd publish && deno task test # 59 tests
|
||||||
- **Hugo-quotierte Dates:** `date: "2023-02-26"` ist ein YAML-String, nicht
|
- **Hugo-quotierte Dates:** `date: "2023-02-26"` ist ein YAML-String, nicht
|
||||||
ein Date-Objekt. `validatePost` coerced das automatisch; in neuen Posts
|
ein Date-Objekt. `validatePost` coerced das automatisch; in neuen Posts
|
||||||
am besten ohne Quotes schreiben.
|
am besten ohne Quotes schreiben.
|
||||||
|
- **Deploy-Targets:** `svelte` → Entwicklung, `staging` → Pre-Prod,
|
||||||
|
`prod` → `joerglohrer26/` (Produktion seit Cutover). Script parst
|
||||||
|
`.env.local` per awk (wegen Sonderzeichen in FTP-Passwörtern).
|
||||||
|
|
||||||
## Offene UNKNOWN-Einträge zur späteren Recherche
|
## Offene UNKNOWN-Einträge zur späteren Recherche
|
||||||
|
|
||||||
|
|
@ -177,10 +193,14 @@ Pipeline loggt Warnungen, publisht aber trotzdem. Recherche-Notizen in
|
||||||
## Session-Kontext
|
## Session-Kontext
|
||||||
|
|
||||||
Hilfreich beim Wiedereinstieg mit Claude:
|
Hilfreich beim Wiedereinstieg mit Claude:
|
||||||
- Branch-Check: `git log --oneline -10 spa main`
|
- Branch-Check: `git log --oneline -10 main`
|
||||||
- Live-Check SPA: `curl -sI https://svelte.joerg-lohrer.de/`
|
- Live-Check: `curl -sI https://joerg-lohrer.de/`
|
||||||
- Event-Count: `nak req -k 30023 -a 4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41 wss://relay.primal.net 2>/dev/null | jq -s 'length'` → 18
|
- Event-Count Repo vs. Relays:
|
||||||
- Pipeline-Tests: `cd publish && deno task test` → 59 grün
|
```sh
|
||||||
|
ls content/posts/ | wc -l
|
||||||
|
nak req -k 30023 -a 4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41 wss://relay.edufeed.org 2>/dev/null | jq -s 'length'
|
||||||
|
```
|
||||||
|
- Pipeline-Tests: `cd publish && deno task test`
|
||||||
|
|
||||||
## Community-Wiki-Entwürfe
|
## Community-Wiki-Entwürfe
|
||||||
|
|
||||||
|
|
|
||||||
158
docs/STATUS.md
158
docs/STATUS.md
|
|
@ -1,63 +1,63 @@
|
||||||
# Projekt-Status: joerg-lohrer.de → Nostr-basierte SPA
|
# Projekt-Status: joerg-lohrer.de → Nostr-basierte SPA
|
||||||
|
|
||||||
**Stand:** 2026-04-18
|
**Stand:** 2026-04-18 (Cutover abgeschlossen)
|
||||||
|
|
||||||
## Kurzfassung
|
## Kurzfassung
|
||||||
|
|
||||||
Jörg Lohrers persönliche Webseite wird von einem Hugo-basierten statischen
|
`joerg-lohrer.de` läuft als SvelteKit-SPA, die Blog-Posts live aus
|
||||||
Site-Generator zu einer dezentralen Nostr-basierten SPA überführt. Posts
|
signierten Nostr-Events (NIP-23, `kind:30023`) auf 5 Public-Relays rendert.
|
||||||
existieren als signierte Events (NIP-23, `kind:30023`) auf Public-Relays und
|
Bilder liegen content-addressed auf 2 Blossom-Servern. Die Hugo-basierte
|
||||||
werden zur Laufzeit im Browser gerendert.
|
Altseite ist als `hugo-archive`-Branch eingefroren.
|
||||||
|
|
||||||
## Vier parallele Webseiten
|
**Das inhaltliche Kernziel des Gesamtprojekts ist erreicht.**
|
||||||
|
|
||||||
|
## Live-URLs
|
||||||
|
|
||||||
| URL | Status | Rolle |
|
| URL | Status | Rolle |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `https://joerg-lohrer.de/` | live, unverändert | **Hugo-Altbestand** (bleibt bis Cutover) |
|
| `https://joerg-lohrer.de/` | live | **Produktion**, SvelteKit-SPA (Cutover 2026-04-18) |
|
||||||
| `https://spa.joerg-lohrer.de/` | live | **Vanilla-HTML-Mini-Spike** (Proof of Concept) |
|
| `https://staging.joerg-lohrer.de/` | live | **Staging**, letzter Pre-Prod-Build |
|
||||||
| `https://svelte.joerg-lohrer.de/` | live | **SvelteKit-SPA** (35-Task-Plan komplett) |
|
| `https://svelte.joerg-lohrer.de/` | live | **Entwicklung**, Deploy-Target der Pipeline |
|
||||||
| `https://staging.joerg-lohrer.de/` | live, leer | **Staging** (Webroot `joerglohrer26/` für Pipeline-Entwicklung; FTP-Creds in `.env.local`) |
|
| `https://spa.joerg-lohrer.de/` | live | **Historisch**, Vanilla-HTML-Mini-Spike |
|
||||||
|
|
||||||
Die SvelteKit-SPA unter `svelte.joerg-lohrer.de` ist die Ziel-Implementierung.
|
|
||||||
`spa.joerg-lohrer.de` bleibt als schlanke Referenz erhalten. Hugo läuft weiter,
|
|
||||||
bis die Publish-Pipeline steht und der Cutover auf die Hauptdomain erfolgt.
|
|
||||||
|
|
||||||
## Was auf Nostr liegt
|
## Was auf Nostr liegt
|
||||||
|
|
||||||
- **Autoren-Pubkey:** `npub1f7jar3qnu269uyx5p0e4v24hqxjnxysxudvujza2ur5ehltvdeqsly2fx9`
|
- **Autoren-Pubkey:** `npub1f7jar3qnu269uyx5p0e4v24hqxjnxysxudvujza2ur5ehltvdeqsly2fx9`
|
||||||
(hex: `4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41`)
|
(hex: `4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41`)
|
||||||
- **Publizierte Events:** **18 Langform-Posts** (`kind:30023`) — alle Altposts
|
- **NIP-05:** `joerglohrer@joerg-lohrer.de` (via `/.well-known/nostr.json`)
|
||||||
via Publish-Pipeline migriert (Commit `0c6fdd1`, Log in
|
- **Publizierte Events:** **18 Langform-Posts** (`kind:30023`) aus dem Repo,
|
||||||
`docs/publish-logs/2026-04-18-force-all-migration.json`).
|
plus **9 nicht-Repo-Events** (via Client wie Habla/Yakihonne erstellt,
|
||||||
|
siehe HANDOFF → Option 5 für Konflikt-Management-Plan).
|
||||||
- **Relay-Liste** (`kind:10002`): `relay.damus.io`, `nos.lol`,
|
- **Relay-Liste** (`kind:10002`): `relay.damus.io`, `nos.lol`,
|
||||||
`relay.primal.net`, `relay.tchncs.de`, `relay.edufeed.org`
|
`relay.primal.net`, `relay.tchncs.de`, `relay.edufeed.org`
|
||||||
- **Blossom-Server** (`kind:10063`): `blossom.edufeed.org`, `blossom.primal.net`
|
- **Blossom-Server** (`kind:10063`): `blossom.edufeed.org`, `blossom.primal.net`
|
||||||
|
- **91 Bilder** auf beiden Blossom-Servern, alle Events enthalten
|
||||||
**91 Bilder** auf beiden Blossom-Servern. Alle Events enthalten hash-basierte
|
hash-basierte Blossom-URLs.
|
||||||
Blossom-URLs. SPA rendert alle Posts einheitlich — kein Legacy-Pfad, keine
|
|
||||||
rsync-Artefakte.
|
|
||||||
|
|
||||||
## Repo-Struktur
|
## Repo-Struktur
|
||||||
|
|
||||||
```
|
```
|
||||||
joerglohrerde/
|
joerglohrerde/
|
||||||
├── content/posts/ # 18 Markdown-Posts, alle mit structured images: im Frontmatter
|
├── content/posts/ # 18 Markdown-Posts, alle mit strukturierten images:
|
||||||
├── app/ # SvelteKit-SPA (Ziel-Implementation)
|
├── content/impressum.md # Statisches Impressum (wird von SPA geladen)
|
||||||
├── preview/spa-mini/ # Vanilla-HTML-Mini-Spike (Referenz)
|
├── app/ # SvelteKit-SPA (Laufzeit-Renderer)
|
||||||
├── publish/ # NOCH NICHT ANGELEGT — Publish-Pipeline (Task 1 aus Plan)
|
├── publish/ # Deno-Publish-Pipeline (Blossom + Nostr)
|
||||||
|
├── preview/spa-mini/ # Vanilla-HTML-Mini-Spike (historisch)
|
||||||
├── scripts/
|
├── scripts/
|
||||||
│ └── deploy-svelte.sh # FTPS-Deploy nach svelte.joerg-lohrer.de
|
│ └── deploy-svelte.sh # FTPS-Deploy, Targets: svelte/staging/prod
|
||||||
├── docs/
|
├── docs/
|
||||||
│ ├── STATUS.md # Dieses Dokument
|
│ ├── STATUS.md # Dieses Dokument
|
||||||
│ ├── HANDOFF.md # Wie man hier weitermacht
|
│ ├── HANDOFF.md # Wie man hier weitermacht
|
||||||
│ ├── redaktion-bild-metadaten.md # Checkliste, Bild-Durchgang (abgearbeitet)
|
│ ├── redaktion-bild-metadaten.md
|
||||||
│ ├── wiki-entwurf-nostr-bild-metadaten.md # Wiki-Konvention deutsch
|
│ ├── wiki-entwurf-nostr-bild-metadaten.md
|
||||||
│ ├── wiki-draft-nostr-image-metadata.md # Wiki-Konvention englisch
|
│ ├── wiki-draft-nostr-image-metadata.md
|
||||||
|
│ ├── github-ci-setup.md
|
||||||
│ └── superpowers/
|
│ └── superpowers/
|
||||||
│ ├── specs/ # SPA + Publish-Pipeline + Bild-Metadaten-Konvention
|
│ ├── specs/ # SPA + Publish-Pipeline + Bild-Metadaten-Konvention
|
||||||
│ └── plans/
|
│ └── plans/
|
||||||
│ ├── 2026-04-15-spa-sveltekit.md # erledigt
|
│ ├── 2026-04-15-spa-sveltekit.md # erledigt
|
||||||
│ └── 2026-04-16-publish-pipeline.md # ⬅ als nächstes
|
│ └── 2026-04-16-publish-pipeline.md # erledigt
|
||||||
|
├── .github/workflows/ # publish.yml (Forgejo→GitHub Push-Mirror-Trigger)
|
||||||
├── .claude/
|
├── .claude/
|
||||||
│ ├── skills/ # Repo-spezifischer Claude-Skill
|
│ ├── skills/ # Repo-spezifischer Claude-Skill
|
||||||
│ └── settings.local.json # Claude-Session-State (gitignored)
|
│ └── settings.local.json # Claude-Session-State (gitignored)
|
||||||
|
|
@ -66,80 +66,78 @@ joerglohrerde/
|
||||||
|
|
||||||
## Branch-Layout (Git)
|
## Branch-Layout (Git)
|
||||||
|
|
||||||
- **`main`** — kanonischer Zweig.
|
- **`main`** — kanonischer Zweig, Produktions-Quelle seit Cutover.
|
||||||
- **`spa`** — aktueller Arbeits-Branch, vor `main`. SvelteKit-SPA live,
|
- **`spa`** — historischer SvelteKit-Arbeitszweig, gemerged.
|
||||||
Content-Migration (Bild-Metadaten) abgeschlossen, Publish-Pipeline geplant.
|
|
||||||
- **`hugo-archive`** — Orphan-Branch mit Hugo-Zustand, eingefroren.
|
- **`hugo-archive`** — Orphan-Branch mit Hugo-Zustand, eingefroren.
|
||||||
|
|
||||||
## Setup-Zustand
|
## Setup-Zustand
|
||||||
|
|
||||||
Einmalig manuell erledigt:
|
Einmalig manuell erledigt (gitignored in `.env.local`):
|
||||||
- ✅ Amber-Bunker-URL in `.env.local` als `BUNKER_URL`
|
- ✅ Amber-Bunker-URL als `BUNKER_URL`
|
||||||
- ✅ FTP-Creds für alle Subdomains (SPA, SVELTE, STAGING) in `.env.local`
|
- ✅ FTP-Creds für alle Targets (SVELTE/STAGING/PROD)
|
||||||
- ✅ `AUTHOR_PUBKEY_HEX` und `BOOTSTRAP_RELAY=wss://relay.primal.net` in `.env.local`
|
- ✅ `AUTHOR_PUBKEY_HEX` und `BOOTSTRAP_RELAY=wss://relay.primal.net`
|
||||||
|
- ✅ `CLIENT_SECRET_HEX` (identisch mit GitHub-Secret für stabile App-ID in Amber)
|
||||||
- ✅ `kind:10002`-Event publiziert (Relay-Liste)
|
- ✅ `kind:10002`-Event publiziert (Relay-Liste)
|
||||||
- ✅ `kind:10063`-Event publiziert (Blossom-Server)
|
- ✅ `kind:10063`-Event publiziert (Blossom-Server)
|
||||||
- ✅ Subdomains mit TLS + HSTS
|
- ✅ Subdomains mit TLS + HSTS
|
||||||
- ✅ Staging-Subdomain `staging.joerg-lohrer.de` → Webroot `joerglohrer26/`
|
- ✅ Staging → Webroot `joerglohrer26/`
|
||||||
|
- ✅ Prod → Webroot `joerglohrer26/` (Cutover 2026-04-18)
|
||||||
|
- ✅ NIP-05-JSON mit CORS-Header via `.htaccess`
|
||||||
|
|
||||||
Alles in `.env.local` — gitignored, nicht committet.
|
## Offene Punkte (Details in HANDOFF.md)
|
||||||
|
|
||||||
## Offene Punkte
|
Nach Priorität:
|
||||||
|
1. **Repo/Nostr-Konflikt-Management** — 9 verwaiste Nostr-Events haben
|
||||||
|
keine Markdown-Entsprechung. Geplanter Flow: Markdown nachziehen →
|
||||||
|
d-tags bereinigen → neu publizieren → alte löschen (NIP-09).
|
||||||
|
2. **Postfach `webmaster@joerg-lohrer.de`** als Weiterleitung in KAS anlegen.
|
||||||
|
3. **SPA respektiert NIP-09-Deletion-Events** (defensiver kind:5-Filter).
|
||||||
|
4. **NIP-09-Delete als Pipeline-Subcommand** (heute noch `nak event -k 5`).
|
||||||
|
5. **Self-hosted CI** (Woodpecker / Cron auf Optiplex), weg von GitHub.
|
||||||
|
6. **5 UNKNOWN-Einträge** im VR-Post zur späteren Recherche.
|
||||||
|
|
||||||
- **End-to-End-Test CI mit echtem Content-Push** (Workflow-Manual-Trigger
|
## Erledigt (chronologisch seit 2026-04-15)
|
||||||
ist grün; automatischer Auto-Trigger via Push-Mirror noch nicht real
|
|
||||||
ausprobiert).
|
|
||||||
- **Menü-Navigation** in der SPA (Home / Archiv / Impressum / Kontakt)
|
|
||||||
- **Impressum-Seite** (braucht rechtlichen Text)
|
|
||||||
- **Cutover auf `joerg-lohrer.de`** (Pipeline läuft, Voraussetzung erfüllt;
|
|
||||||
Hauptdomain kann auf SvelteKit-SPA umgestellt werden)
|
|
||||||
- **5 UNKNOWN-Einträge** im `virtual-reality`-Post zur späteren Recherche
|
|
||||||
(Wikipedia-Screenshot, Sketchfab-Fotograf, Ready-Player-Me, EyeMeasure-App)
|
|
||||||
- **CI-Migration** (später): weg von GitHub-Actions zu Woodpecker oder
|
|
||||||
Cron auf Optiplex — siehe `docs/github-ci-setup.md`.
|
|
||||||
|
|
||||||
## Erledigt seit 2026-04-15
|
|
||||||
|
|
||||||
- ✅ Content-Migration: alle 18 Posts haben strukturierte `images:`-Liste
|
- ✅ Content-Migration: alle 18 Posts haben strukturierte `images:`-Liste
|
||||||
im Frontmatter (91 Bilder, mit Alt-Text, Lizenz, Autor:innen, ggf. Caption
|
im Frontmatter (91 Bilder, mit Alt-Text, Lizenz, Autor:innen, ggf.
|
||||||
und Modifications). Commit `c023b59`.
|
Caption und Modifications).
|
||||||
- ✅ Erlebnispädagogik-Post: tote Amazon-Hotlinks entfernt.
|
|
||||||
- ✅ Spec, Plan und Bild-Metadaten-Konvention geschrieben.
|
- ✅ Spec, Plan und Bild-Metadaten-Konvention geschrieben.
|
||||||
- ✅ Community-Wiki-Entwürfe (DE + EN) für Nostr-Bildattribution.
|
- ✅ Community-Wiki-Entwürfe (DE + EN) für Nostr-Bildattribution.
|
||||||
- ✅ **Publish-Pipeline komplett implementiert**, 22 Tasks aus dem Plan:
|
- ✅ **Publish-Pipeline komplett implementiert** (24 Tasks, 59 Tests grün).
|
||||||
- 18 Code-Tasks (Phase 1–6), 59 Unit-Tests grün
|
- ✅ **Alle 18 Altposts publiziert** als `kind:30023`-Events.
|
||||||
- Stabile NIP-46-Anbindung via `CLIENT_SECRET_HEX` für wiederverwendbare
|
|
||||||
App-Identität in Amber
|
|
||||||
- `validatePost` akzeptiert auch string-dates (für Hugo-Kompatibilität)
|
|
||||||
- ✅ **Alle 18 Altposts publiziert** als `kind:30023`-Events (Commit `0c6fdd1`,
|
|
||||||
Log in `docs/publish-logs/2026-04-18-force-all-migration.json`).
|
|
||||||
- ✅ **91 Bilder** auf beiden Blossom-Servern.
|
- ✅ **91 Bilder** auf beiden Blossom-Servern.
|
||||||
- ✅ SPA rendert alle Posts mit Bildern von Blossom (visuell verifiziert).
|
- ✅ **GitHub-Actions-Workflow** + Forgejo→GitHub Push-Mirror + Secrets.
|
||||||
- ✅ **GitHub-Actions-Workflow** angelegt (`.github/workflows/publish.yml`).
|
- ✅ **Duplikat-Event via NIP-09 gelöscht** (`bibel-selfies` Unix-Timestamp-dup).
|
||||||
- ✅ Forgejo → GitHub Push-Mirror eingerichtet, GitHub-Secrets gesetzt.
|
- ✅ **Staging-Deploy-Infrastruktur** mit `__SITE_URL__`-Templating.
|
||||||
- ✅ **`spa` → `main` gemergt**, GitHub-Actions-Workflow manuell verifiziert
|
- ✅ **Homepage** mit Hero, Profilbild, Social-Icons (Nostr/Mastodon/
|
||||||
(Run #1: signer ok, outbox ok, blossom-liste ok, mode=diff posts=0).
|
Bluesky/LinkedIn/ORCID/Mail), Latest-Posts.
|
||||||
**Alle 24 Tasks des Publish-Pipeline-Plans abgeschlossen.**
|
- ✅ **Archiv-Seite**, **Impressum-Seite**, Menü-Navigation im Layout.
|
||||||
- ✅ **Staging-Deploy-Infrastruktur:** `scripts/deploy-svelte.sh` mit
|
- ✅ **CC0-Footer-Badge** (Heart+Zero inline SVG, monochrom).
|
||||||
drei Targets (`svelte`/`staging`/`prod`), dynamisches `og:url` und
|
- ✅ **Impressum auf CC0 umgestellt** (mit freundlichem Namensnennungs-Hinweis).
|
||||||
`canonical` via `__SITE_URL__`-Platzhalter. Staging-Subdomain
|
- ✅ **Cutover 2026-04-18** — `joerg-lohrer.de` von Hugo (`joerglohrer24/`)
|
||||||
`staging.joerg-lohrer.de` bedient jetzt `joerglohrer26/` (Cutover-Ziel).
|
auf SvelteKit-SPA (`joerglohrer26/`) umgehängt.
|
||||||
- ✅ **Duplikat-Event `1744905463975` via NIP-09 gelöscht** (Delete-Event
|
|
||||||
`7f5d08b8…`, auf alle 5 Relays). Nach Migration nicht mehr auffindbar.
|
|
||||||
|
|
||||||
## Live-Verifikation
|
## Live-Verifikation
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -sI https://svelte.joerg-lohrer.de/ | head -3
|
curl -sI https://joerg-lohrer.de/ | head -3
|
||||||
curl -sI https://staging.joerg-lohrer.de/ | head -3
|
curl -sI https://staging.joerg-lohrer.de/ | head -3
|
||||||
|
curl -s https://joerg-lohrer.de/.well-known/nostr.json | jq .
|
||||||
```
|
```
|
||||||
|
|
||||||
## Kontakt zur Implementierung
|
## Pipeline-Quick-Check
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# Event-Count pro Relay
|
||||||
|
for r in wss://relay.damus.io wss://nos.lol wss://relay.primal.net wss://relay.tchncs.de wss://relay.edufeed.org; do
|
||||||
|
echo -n "$r: "; nak req -k 30023 -a 4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41 $r 2>/dev/null | wc -l
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
## Design-Referenzen
|
||||||
|
|
||||||
Alle Design-Entscheidungen in:
|
|
||||||
- `docs/superpowers/specs/2026-04-15-nostr-page-design.md` (SPA)
|
- `docs/superpowers/specs/2026-04-15-nostr-page-design.md` (SPA)
|
||||||
- `docs/superpowers/specs/2026-04-15-publish-pipeline-design.md` (Publish, Blossom-only)
|
- `docs/superpowers/specs/2026-04-15-publish-pipeline-design.md` (Publish, Blossom-only)
|
||||||
- `docs/superpowers/specs/2026-04-16-image-metadata-convention.md` (Bild-Metadaten-YAML)
|
- `docs/superpowers/specs/2026-04-16-image-metadata-convention.md` (Bild-Metadaten-YAML)
|
||||||
- `docs/superpowers/plans/2026-04-16-publish-pipeline.md` (24 Tasks, als nächstes)
|
|
||||||
|
|
||||||
Für die nächste Session: **`docs/HANDOFF.md`** lesen.
|
Für die nächste Session: **`docs/HANDOFF.md`** lesen.
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue