docs: ci-setup-guide + status/handoff für ci-phase aktualisiert
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>
This commit is contained in:
parent
2f7f991bc6
commit
b2cbbb6390
196
docs/HANDOFF.md
196
docs/HANDOFF.md
|
|
@ -5,168 +5,140 @@ Dieses Dokument sagt: was ist der Zustand, was wartet, wo liegen die Fäden.
|
|||
|
||||
## Zustand (Details in `STATUS.md`)
|
||||
|
||||
Die SvelteKit-SPA unter `svelte.joerg-lohrer.de` ist **fertig und live**.
|
||||
Alle 18 Posts haben jetzt **strukturierte Bild-Metadaten** im Frontmatter
|
||||
(Commit `c023b59`, 91 Bilder). Der Publish-Pipeline-**Plan ist geschrieben**
|
||||
(`docs/superpowers/plans/2026-04-16-publish-pipeline.md`, 24 Tasks in 12 Phasen).
|
||||
**Die Nostr-Publish-Pipeline ist live.** Alle 18 Posts sind publiziert als
|
||||
`kind:30023`-Events auf 5 Relays, 91 Bilder auf 2 Blossom-Servern. Die
|
||||
SvelteKit-SPA unter `svelte.joerg-lohrer.de` rendert alles ordentlich.
|
||||
|
||||
**Als nächstes:** Pipeline implementieren, beginnend mit Task 1.
|
||||
**Das inhaltliche Kernziel des Gesamtprojekts ist damit erreicht.**
|
||||
|
||||
Der Rest sind Feinschliff- und Cutover-Aufgaben.
|
||||
|
||||
## Was als Nächstes ansteht
|
||||
|
||||
### Option 1 — Publish-Pipeline implementieren ⬅ empfohlen
|
||||
### Option 1 — CI-End-to-End-Test ⬅ kleinstes Offene
|
||||
|
||||
**Warum:** Spec + Plan fertig, Content vorbereitet, alle Design-Entscheidungen
|
||||
getroffen. Kann direkt losgehen.
|
||||
**Voraussetzung erledigt:** Forgejo → GitHub Push-Mirror läuft, GitHub-Secrets
|
||||
gesetzt (Details in `docs/github-ci-setup.md`).
|
||||
|
||||
**Nächster konkreter Schritt:**
|
||||
**Noch zu tun:**
|
||||
1. In GitHub → Actions → „Publish Nostr Events" → „Run workflow" → Branch
|
||||
`main`. Erwartung: Pre-Flight grün, 0 Posts (kein Content-Diff), Exit 0.
|
||||
2. Optional: Minimaler Edit in einem Post → commit → push → warten bis
|
||||
Mirror auf GitHub synct → Workflow triggert automatisch → 1 Post als
|
||||
`update` publiziert → Log-Artefakt prüfen.
|
||||
|
||||
```
|
||||
cd /Users/joerglohrer/repositories/joerglohrerde
|
||||
```
|
||||
Danach ist Task 22 komplett abgeschlossen.
|
||||
|
||||
Dann den Plan öffnen:
|
||||
```
|
||||
docs/superpowers/plans/2026-04-16-publish-pipeline.md
|
||||
```
|
||||
### Option 2 — Cutover auf `joerg-lohrer.de`
|
||||
|
||||
Und Task 1 (Deno-Projekt-Grundgerüst) starten. Der Plan nutzt TDD;
|
||||
jeder Task hat Test-First, Implementation, Commit.
|
||||
**Voraussetzung:** Option 1 optional, aber nicht blockierend. Die Pipeline
|
||||
läuft ja schon, ob manuell oder via CI ist für den Cutover egal.
|
||||
|
||||
**Ausführungsweisen:**
|
||||
- **Subagent-Driven** (im Plan empfohlen): pro Task frischer Subagent,
|
||||
Review zwischen Tasks. Skill: `superpowers:subagent-driven-development`.
|
||||
- **Inline**: alles in einer Session. Skill: `superpowers:executing-plans`.
|
||||
**Schritte:**
|
||||
1. In All-Inkl KAS die Domain `joerg-lohrer.de` auf den SvelteKit-Webroot
|
||||
umhängen (aktuell: `svelte.joerg-lohrer.de` → `/www/htdocs/v109928/joerglohrer28/`
|
||||
oder welcher Ordner auch immer).
|
||||
2. SvelteKit-SPA deployen, sofern sie nicht schon dort liegt.
|
||||
3. Live-Check: `curl -sI https://joerg-lohrer.de/` → sollte die neue SPA
|
||||
liefern, nicht mehr Hugo.
|
||||
|
||||
**Besonderheiten beim Plan:**
|
||||
- Pipeline ist **Blaupause** für andere Nostr-Repos — keine
|
||||
Projekt-Konstanten im Code, alles via Env.
|
||||
- **Env-File:** nutzt `../.env.local` (Repo-Root), wo `BUNKER_URL`,
|
||||
`AUTHOR_PUBKEY_HEX`, `BOOTSTRAP_RELAY` bereits stehen.
|
||||
- **Blossom-only**: keine rsync/SSH-Altlasten mehr; alle Bilder (auch
|
||||
die der 17 Altposts) werden zu Blossom hochgeladen.
|
||||
- **Staging:** `staging.joerg-lohrer.de` zeigt auf `/www/htdocs/v109928/joerglohrer26/`.
|
||||
Wird erst beim Cutover relevant — Pipeline selbst braucht es nicht.
|
||||
Hugo-Altbestand bleibt als Archiv im `hugo-archive`-Branch.
|
||||
|
||||
**Vorarbeiten (bereits erledigt):**
|
||||
- ✅ SSH-Zugang All-Inkl (Premium): `ssh-v109928@v109928.kasserver.com`
|
||||
mit Deploy-Key `~/.ssh/id_ed25519_joerglohrerde_deploy` (auch im KAS
|
||||
eingetragen). Wird jetzt allerdings nicht mehr für die Pipeline
|
||||
gebraucht — Blossom-only.
|
||||
- ✅ `.env.local` enthält alle Pipeline-Keys.
|
||||
- ✅ Content-Migration (18 Posts × Bild-Metadaten) abgeschlossen.
|
||||
### Option 3 — Menü-Navigation + Impressum in der SPA
|
||||
|
||||
### Option 2 — Menü-Navigation + Impressum auf der SPA
|
||||
**Unabhängig von allem anderen**, kann parallel gemacht werden.
|
||||
|
||||
**Warum:** kleine UX-Ergänzung, die das SPA-Erlebnis runder macht.
|
||||
- Header-Navigation in `app/src/routes/+layout.svelte` (Home, Archiv, Impressum,
|
||||
Mastodon-Link)
|
||||
- `/impressum/`-Route mit rechtlichem Text
|
||||
|
||||
- Header-Navigation in `app/src/routes/+layout.svelte` ergänzen (Home, Archiv,
|
||||
Impressum, evtl. Mastodon-Link)
|
||||
- `/impressum/`-Route anlegen mit rechtlichem Text
|
||||
- ggf. Archives-Route als eigene Liste mit Gruppierung nach Jahr
|
||||
**Aufwand:** 30–60 min.
|
||||
|
||||
**Aufwand:** ~30-60 min.
|
||||
### Option 4 — Pipeline weg von GitHub (self-hosted CI)
|
||||
|
||||
### Option 3 — Cutover auf Hauptdomain
|
||||
**Wann:** Wenn der Optiplex-Server steht und ein zentraler Ort für Dienste
|
||||
existiert.
|
||||
|
||||
**Voraussetzung:** Option 1 abgeschlossen und alle 18 Posts als Events
|
||||
publiziert, Bilder auf Blossom.
|
||||
**Varianten:**
|
||||
- **Cron / systemd-Timer** auf dem Optiplex, der alle X Minuten `git pull &&
|
||||
deno task publish` macht. Einfach, minimaler Setup.
|
||||
- **Woodpecker-CI** als Docker-Container neben Forgejo. Volle Push-getriggerte
|
||||
Pipeline ohne GitHub.
|
||||
|
||||
**Dann:** KAS → Domain `joerg-lohrer.de` auf den SvelteKit-Webroot
|
||||
umhängen (derselbe wie `svelte.joerg-lohrer.de` oder `joerglohrer26/`,
|
||||
je nach Entscheidung).
|
||||
|
||||
Reihenfolge: **Option 1 → Option 3**, Option 2 kann parallel laufen.
|
||||
Der Pipeline-Code selbst (`publish/src/**`) ist CI-agnostisch — nur die
|
||||
Trigger-Konfiguration ändert sich.
|
||||
|
||||
## Schnell-Orientierung für die nächste Claude-Session
|
||||
|
||||
Lies in dieser Reihenfolge:
|
||||
1. `docs/STATUS.md` (5 min)
|
||||
2. `docs/HANDOFF.md` (= dieses Dokument)
|
||||
3. Für die Pipeline: `docs/superpowers/plans/2026-04-16-publish-pipeline.md`
|
||||
4. Bei Design-Fragen:
|
||||
- Publish-Pipeline: `docs/superpowers/specs/2026-04-15-publish-pipeline-design.md`
|
||||
- Bild-Metadaten: `docs/superpowers/specs/2026-04-16-image-metadata-convention.md`
|
||||
- SPA: `docs/superpowers/specs/2026-04-15-nostr-page-design.md`
|
||||
|
||||
Nutze den Skill unter `.claude/skills/joerglohrerde-workflow.md` für
|
||||
wiederkehrende Kommandos.
|
||||
3. Für CI-Themen: `docs/github-ci-setup.md`
|
||||
4. Für Pipeline-Fragen: `docs/superpowers/specs/2026-04-15-publish-pipeline-design.md`
|
||||
|
||||
## Dev-Kommandos
|
||||
|
||||
```sh
|
||||
# Unit-Tests SPA (Vitest)
|
||||
# SPA-Tests
|
||||
cd app && npm run test:unit
|
||||
|
||||
# E2E-Tests SPA (Playwright)
|
||||
cd app && npm run test:e2e
|
||||
|
||||
# Type-Check SPA
|
||||
cd app && npm run check
|
||||
|
||||
# SPA-Dev-Server (Port 5173)
|
||||
cd app && npm run dev
|
||||
|
||||
# SPA-Production-Build + Deploy
|
||||
# SPA-Build + Deploy
|
||||
cd app && npm run build && cd .. && ./scripts/deploy-svelte.sh
|
||||
|
||||
# Publish-Pipeline
|
||||
cd publish && deno task check # pre-flight
|
||||
cd publish && deno task publish --dry-run # diff-modus simulation
|
||||
cd publish && deno task publish # diff-modus echt
|
||||
cd publish && deno task publish --force-all # alle posts
|
||||
cd publish && deno task publish --post <slug> # einen post
|
||||
cd publish && deno task test # 59 tests
|
||||
```
|
||||
|
||||
Publish-Pipeline-Kommandos (sobald implementiert):
|
||||
```sh
|
||||
cd publish && deno task check # Pre-Flight
|
||||
cd publish && deno task publish --dry-run # Simulation
|
||||
cd publish && deno task publish --post <slug> # einen Post
|
||||
cd publish && deno task publish --force-all # alle Posts
|
||||
cd publish && deno task test # Tests
|
||||
```
|
||||
|
||||
## Manuelles Publishen (Übergang, bis Pipeline fertig)
|
||||
|
||||
Siehe frühere Version dieses Dokuments. Bis die Pipeline läuft, gehen
|
||||
neue Posts manuell über `nak event` raus.
|
||||
|
||||
## Bekannte Stolperfallen
|
||||
|
||||
- **Amber-Bunker:** bei neuer Bunker-URL müssen globale Permissions in Amber
|
||||
zurückgesetzt werden, sonst hängt `nak` auf den Signatur-Request.
|
||||
Auto-Approve für `kind:30023` und `kind:24242` (Blossom-Auth) setzen.
|
||||
- **Svelte 5 Runes:** `$props()`-Werte müssen via `$derived()` in lokale
|
||||
Variablen, sonst `state_referenced_locally`-Warning.
|
||||
- **applesauce-relay API:** ist RxJS-basiert. `pool.request(relays, filter)`
|
||||
returned `Observable<NostrEvent>` (nicht die Tupel-`subscribe({next: msg
|
||||
if msg[0]==='EVENT'})`-Form).
|
||||
- **Slug-Normalisierung:** alle Frontmatter-Slugs sind lowercase (Commit
|
||||
`d17410f`). Beim Publishen 1:1 übernehmen, keine Runtime-Transformation.
|
||||
- **Dateiname mit Leerzeichen:** im Moodle-Post liegt `03-config generieren.png`.
|
||||
Pipeline muss URL-Encoding im `rewriteImageUrls`-Helper korrekt umsetzen
|
||||
(Test ist im Plan Task 5 vorgesehen).
|
||||
|
||||
## Session-Kontext
|
||||
|
||||
Hilfreich beim Wiedereinstieg mit Claude:
|
||||
- Branch-Check: `git log --oneline -10 spa main hugo-archive`
|
||||
- Live-Check: `curl -sI https://svelte.joerg-lohrer.de/`
|
||||
- Publish-Status: `nak req -k 30023 -a 4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41 wss://relay.damus.io 2>/dev/null | jq -s 'length'`
|
||||
(aktuell ~10, nach Pipeline-Lauf `--force-all`: 18)
|
||||
- **Amber-Bunker:** bei neuer Bunker-URL müssen die zwei Permissions
|
||||
(`get_public_key`, `sign_event`) in Amber auf „Allow + Always" gesetzt
|
||||
werden, bevor Publish-Requests verarbeitet werden. Siehe
|
||||
`docs/github-ci-setup.md` für Details.
|
||||
- **`CLIENT_SECRET_HEX`** in `.env.local` identisch mit GitHub-Secret —
|
||||
sorgt dafür, dass sich beide Umgebungen bei Amber mit derselben App
|
||||
anmelden. Rotieren nur bei bewusstem Neu-Pairing in Amber.
|
||||
- **`relay.damus.io`** bestätigt Events manchmal nicht mit `OK`. Bekanntes
|
||||
Damus-Verhalten, wird toleriert (MIN_RELAY_ACKS=2, andere 4 Relays sind
|
||||
zuverlässig).
|
||||
- **Svelte 5 Runes:** `$props()`-Werte via `$derived()` in lokale Variablen.
|
||||
- **Hugo-quotierte Dates:** `date: "2023-02-26"` ist ein YAML-String, nicht
|
||||
ein Date-Objekt. `validatePost` coerced das automatisch; in neuen Posts
|
||||
am besten ohne Quotes schreiben.
|
||||
|
||||
## Offene UNKNOWN-Einträge zur späteren Recherche
|
||||
|
||||
Im VR-Post (`content/posts/2021-08-15-virtual-reality/index.md`)
|
||||
sind 4 Bilder als `license: UNKNOWN / authors: UNKNOWN` markiert:
|
||||
Im VR-Post (`content/posts/2021-08-15-virtual-reality/index.md`) sind
|
||||
4 Bilder als `license: UNKNOWN / authors: UNKNOWN` markiert:
|
||||
- `01-immersion-wikipedia.jpg` (Wikipedia-Screenshot)
|
||||
- `02-mittelalterliche-kirche.jpg` (Sketchfab — Lizenz ist CC BY-NC, Fotograf fehlt)
|
||||
- `03-avatare-erstellen.jpg` (Ready Player Me)
|
||||
- `05-pupillendistanz.jpg` (EyeMeasure iOS App)
|
||||
|
||||
Pipeline loggt beim Publishen eine Warnung pro UNKNOWN, publisht aber
|
||||
trotzdem (Phase-1-Default: `STRICT_MODE=false`). Die Recherche-Todo-Liste
|
||||
steht in `docs/redaktion-bild-metadaten.md`.
|
||||
Pipeline loggt Warnungen, publisht aber trotzdem. Recherche-Notizen in
|
||||
`docs/redaktion-bild-metadaten.md`.
|
||||
|
||||
## Session-Kontext
|
||||
|
||||
Hilfreich beim Wiedereinstieg mit Claude:
|
||||
- Branch-Check: `git log --oneline -10 spa main`
|
||||
- Live-Check SPA: `curl -sI https://svelte.joerg-lohrer.de/`
|
||||
- Event-Count: `nak req -k 30023 -a 4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41 wss://relay.primal.net 2>/dev/null | jq -s 'length'` → 18
|
||||
- Pipeline-Tests: `cd publish && deno task test` → 59 grün
|
||||
|
||||
## Community-Wiki-Entwürfe
|
||||
|
||||
Noch nicht extern veröffentlicht, liegen im Repo bereit:
|
||||
Liegen im Repo, noch nicht extern veröffentlicht:
|
||||
- `docs/wiki-entwurf-nostr-bild-metadaten.md` — DE
|
||||
- `docs/wiki-draft-nostr-image-metadata.md` — EN
|
||||
|
||||
Können in die Nostr-Community eingebracht werden (z. B. als NIP-Proposal
|
||||
oder auf nostrbook.dev), sobald die Pipeline sie in der Praxis validiert.
|
||||
Können als NIP-Proposal oder auf nostrbook.dev eingebracht werden, jetzt wo
|
||||
die Konvention in der Praxis validiert ist.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
# Projekt-Status: joerg-lohrer.de → Nostr-basierte SPA
|
||||
|
||||
**Stand:** 2026-04-16
|
||||
**Stand:** 2026-04-18
|
||||
|
||||
## Kurzfassung
|
||||
|
||||
|
|
@ -26,17 +26,16 @@ bis die Publish-Pipeline steht und der Cutover auf die Hauptdomain erfolgt.
|
|||
|
||||
- **Autoren-Pubkey:** `npub1f7jar3qnu269uyx5p0e4v24hqxjnxysxudvujza2ur5ehltvdeqsly2fx9`
|
||||
(hex: `4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41`)
|
||||
- **Publizierte Events:** ~10 Langform-Posts (`kind:30023`). Die restlichen
|
||||
8 Posts warten auf die Publish-Pipeline (Events werden beim ersten
|
||||
`deno task publish --force-all`-Lauf erzeugt).
|
||||
- **Publizierte Events:** **18 Langform-Posts** (`kind:30023`) — alle Altposts
|
||||
via Publish-Pipeline migriert (Commit `0c6fdd1`, Log in
|
||||
`docs/publish-logs/2026-04-18-force-all-migration.json`).
|
||||
- **Relay-Liste** (`kind:10002`): `relay.damus.io`, `nos.lol`,
|
||||
`relay.primal.net`, `relay.tchncs.de`, `relay.edufeed.org`
|
||||
- **Blossom-Server** (`kind:10063`): `blossom.edufeed.org`, `blossom.primal.net`
|
||||
|
||||
Bisher nur die Bilder des `dezentrale-oep-oer`-Posts auf Blossom. **Designentscheidung
|
||||
2026-04-16:** Alle Bilder (inkl. der 17 Altpost-Bilder) kommen via Publish-Pipeline
|
||||
auf Blossom — kein rsync-Legacy-Pfad mehr, kein `image_source: legacy`-Flag.
|
||||
Einheitlicher Render-Pfad in der SPA.
|
||||
**91 Bilder** auf beiden Blossom-Servern. Alle Events enthalten hash-basierte
|
||||
Blossom-URLs. SPA rendert alle Posts einheitlich — kein Legacy-Pfad, keine
|
||||
rsync-Artefakte.
|
||||
|
||||
## Repo-Struktur
|
||||
|
||||
|
|
@ -87,29 +86,36 @@ Alles in `.env.local` — gitignored, nicht committet.
|
|||
|
||||
## Offene Punkte
|
||||
|
||||
- **Publish-Pipeline** — Spec + Plan vollständig, **Implementierung steht an**
|
||||
(Task 1 aus `docs/superpowers/plans/2026-04-16-publish-pipeline.md`).
|
||||
- **CI-Mirror** Forgejo → GitHub eingerichtet, GitHub-Secrets gesetzt.
|
||||
End-to-End-Test (Content-Commit, Workflow-Trigger, CI-Lauf) noch offen.
|
||||
Später: Migration auf Woodpecker oder Cron auf Optiplex möglich
|
||||
(siehe `docs/github-ci-setup.md`).
|
||||
- **Menü-Navigation** in der SPA (Home / Archiv / Impressum / Kontakt)
|
||||
- **Impressum-Seite** (braucht rechtlichen Text)
|
||||
- **Cutover auf `joerg-lohrer.de`** (nach Pipeline-Live: Hauptdomain
|
||||
bekommt die SvelteKit-SPA)
|
||||
- **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)
|
||||
|
||||
## Erledigt seit 2026-04-15
|
||||
|
||||
- ✅ Content-Migration: alle 18 Posts haben strukturierte `images:`-Liste
|
||||
im Frontmatter (91 Bilder, mit Alt-Text, Lizenz, Autor:innen, ggf. Caption
|
||||
und Modifications). Commit `c023b59`.
|
||||
- ✅ Erlebnispädagogik-Post: tote Amazon-Hotlinks entfernt, Literatur-
|
||||
Liste aufgeräumt.
|
||||
- ✅ Design-Entscheidung „Blossom-only" dokumentiert in Spec
|
||||
`docs/superpowers/specs/2026-04-15-publish-pipeline-design.md`.
|
||||
- ✅ Publish-Pipeline-Plan (24 Tasks, Blaupausen-tauglich) geschrieben:
|
||||
`docs/superpowers/plans/2026-04-16-publish-pipeline.md`.
|
||||
- ✅ Bild-Metadaten-Konvention (Phase 1) in Spec:
|
||||
`docs/superpowers/specs/2026-04-16-image-metadata-convention.md`.
|
||||
- ✅ Community-Wiki-Entwürfe (DE + EN) für Nostr-Bildattribution:
|
||||
`docs/wiki-entwurf-nostr-bild-metadaten.md` + `-draft-nostr-image-metadata.md`.
|
||||
- ✅ 5 `UNKNOWN`-Einträge im VR-Post zur Recherche markiert (bleiben erstmal so).
|
||||
- ✅ Erlebnispädagogik-Post: tote Amazon-Hotlinks entfernt.
|
||||
- ✅ Spec, Plan und Bild-Metadaten-Konvention geschrieben.
|
||||
- ✅ Community-Wiki-Entwürfe (DE + EN) für Nostr-Bildattribution.
|
||||
- ✅ **Publish-Pipeline komplett implementiert**, 22 Tasks aus dem Plan:
|
||||
- 18 Code-Tasks (Phase 1–6), 59 Unit-Tests grün
|
||||
- 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.
|
||||
- ✅ SPA rendert alle Posts mit Bildern von Blossom (visuell verifiziert).
|
||||
- ✅ **GitHub-Actions-Workflow** angelegt (`.github/workflows/publish.yml`).
|
||||
- ✅ Forgejo → GitHub Push-Mirror eingerichtet, GitHub-Secrets gesetzt.
|
||||
|
||||
## Live-Verifikation
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
# GitHub-CI-Setup für die Publish-Pipeline
|
||||
|
||||
**Kontext:** Das primäre Repo liegt in **Forgejo** (self-hosted). Für CI nutzen
|
||||
wir GitHub als **Push-Mirror-Ziel**, weil Forgejo keine Woodpecker-Integration
|
||||
hat. GitHub Actions triggert automatisch bei Push auf `main` mit Änderungen
|
||||
unter `content/posts/**`.
|
||||
|
||||
## Setup-Schritte
|
||||
|
||||
### 1. Forgejo → GitHub Push-Mirror
|
||||
|
||||
In Forgejo:
|
||||
- Repo → **Settings → Mirrors → Push Mirror hinzufügen**
|
||||
- Ziel-URL: das entsprechende GitHub-Repo (z. B. `https://github.com/<user>/joerglohrerde.git`)
|
||||
- Authentifizierung: GitHub-Personal-Access-Token (`repo`-Scope)
|
||||
- Intervall: nach Belieben (z. B. alle 8 Stunden, oder „bei jedem Push")
|
||||
|
||||
### 2. GitHub-Repository-Secrets
|
||||
|
||||
In GitHub, Repo → **Settings → Secrets and variables → Actions**:
|
||||
|
||||
Vier Repository-Secrets anlegen (nicht Environment-Secrets — wir haben keine Environments):
|
||||
|
||||
| Name | Wert | Quelle |
|
||||
|---|---|---|
|
||||
| `BUNKER_URL` | `bunker://<hex>?relay=wss://...&secret=...` | aus `.env.local` |
|
||||
| `AUTHOR_PUBKEY_HEX` | `4fa5d1c413e2b45e10d40bf3562ab701a5331206e359c90baae0e99bfd6c6e41` | aus `.env.local` |
|
||||
| `BOOTSTRAP_RELAY` | `wss://relay.primal.net` | aus `.env.local` |
|
||||
| `CLIENT_SECRET_HEX` | `929f0cd946fd5266e63ccdb066ce7a0cc93391133bfce6098fe633fc72e03e96` | aus `.env.local` |
|
||||
|
||||
**Wichtig:**
|
||||
- Alle vier **müssen** gesetzt sein, sonst schlägt der Workflow fehl.
|
||||
- Der `CLIENT_SECRET_HEX` ist **identisch** mit dem in `.env.local` — damit sich
|
||||
CI-Runner und lokaler Rechner bei Amber mit **derselben Client-Identität**
|
||||
anmelden. Die Permissions in Amber gelten dann für beide.
|
||||
|
||||
### 3. Workflow-Datei
|
||||
|
||||
Liegt in `.github/workflows/publish.yml`. Triggert auf:
|
||||
- `push` auf `main` mit Änderungen unter `content/posts/**`
|
||||
- `workflow_dispatch` (manuelles Triggern über das GitHub-UI, optional mit `force_all=true`)
|
||||
|
||||
### 4. Secrets rotieren
|
||||
|
||||
Wenn der Bunker-Pairing-Secret mal kompromittiert wird oder Amber neu
|
||||
eingerichtet wird:
|
||||
|
||||
1. In Amber neue Bunker-URL erzeugen
|
||||
2. Lokale `.env.local` aktualisieren
|
||||
3. GitHub-Secret `BUNKER_URL` ebenfalls aktualisieren (Settings → Secrets → edit)
|
||||
4. In Amber für die neue App wieder "Allow + Always" für
|
||||
`get_public_key` + `sign_event` setzen
|
||||
|
||||
Der `CLIENT_SECRET_HEX` muss in der Regel **nicht** rotiert werden — nur wenn
|
||||
du die App in Amber komplett neu pairen willst. Wenn du ihn doch änderst, muss
|
||||
Amber die App neu registrieren (siehe Setup).
|
||||
|
||||
## Monitoring
|
||||
|
||||
- **Workflow-Runs:** GitHub → Actions → "Publish Nostr Events"
|
||||
- **Logs pro Run:** pro Run ein Artefakt `publish-log` mit der `publish-*.json`,
|
||||
30 Tage Aufbewahrung
|
||||
- **Lokal laufen bleibt möglich** via `cd publish && deno task publish …` —
|
||||
CI ist eine zusätzliche Automatisierung, kein Zwang.
|
||||
|
||||
## Bekannte Einschränkungen
|
||||
|
||||
- **Amber muss online sein** während CI-Runs, sonst scheitert die Bunker-
|
||||
Signatur. Wenn das Handy tot ist: Workflow failed → einfach neu triggern,
|
||||
sobald Amber wieder erreichbar.
|
||||
- **`relay.damus.io`** antwortet gelegentlich nicht mit OK; das ist
|
||||
ein bekanntes Damus-Verhalten und wird von `MIN_RELAY_ACKS=2` toleriert.
|
||||
- **Staging-Subdomain (`staging.joerg-lohrer.de`)** hat nichts mit dieser
|
||||
Pipeline zu tun — sie gehört zum SPA-Deploy. Die Publish-Pipeline nutzt
|
||||
ausschließlich Blossom für Bild-Hosting.
|
||||
|
||||
## Migration weg von GitHub (später)
|
||||
|
||||
Wenn Woodpecker oder ein anderer self-hosted Runner aufgesetzt wird, bleibt
|
||||
der Deno-Workflow derselbe — nur die CI-Konfiguration ändert sich:
|
||||
|
||||
- `.github/workflows/publish.yml` → `.woodpecker.yaml` (oder `.gitea/workflows/`)
|
||||
- Secrets in Woodpecker statt GitHub
|
||||
- Trigger-Bedingungen analog (push main + path filter)
|
||||
|
||||
Der Pipeline-Code selbst (`publish/src/**`) ist CI-agnostisch und braucht keine
|
||||
Änderung.
|
||||
Loading…
Reference in New Issue