This repository has been archived on 2026-09-17. You can view files and clone it, but you cannot make any changes to its state, such as pushing and creating new issues, pull requests or comments.
nixos-config/docs/hdm-klon-plan.md
pijukka 5407a1d235 Atomare Self-Close-Sessions, Eskalationskette und Reviewer-Schwelle für Herdr-Rollen
Self-Close: Pane-Wrapper (herdr-self-close.nix), Rollenverträge und
Claude-Settings für graphics/administrator/agent-manager/orga, mit
Regressionstests in agents/tests/roles.sh. Reviewer bleibt bewusst
ausgeschlossen (read-only, keine Aktivierungsfreigabe).

Eskalationsentwurf (docs/herdr-eskalation-review-entwurf.md) freigegeben:
Reviewer-Pflicht ab Risikoschwelle statt bei jedem Diff, Agent-Manager
zusätzlich zum Administrator als Fixer für Rollenvertrags-Blocker
(agent-manager.md 2.0.0 -> 2.1.0), Rückfrage-Kanal zunächst nur als
Pilot bei Orga (orga.md 2.0.0 -> 2.1.0). Details in
docs/herdr-orchestration.md.

Begleitende Infrastruktur: agent-codex/orga-agent/finance-agent-Worker,
orga-agent-Client und hdm.0ff.space-Klon-Doku. graphify-out/, .agents/
und nvim.log neu gitignored (lokale Tool-Ausgabe/Debris, kein Repo-Inhalt).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011uSxdbo8zykSeH5WCMmbvp
2026-09-01 19:33:39 +02:00

255 lines
14 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Plan: 1:1-Klon von hausdermaterialisierung.org auf hdm.0ff.space
**Status: Klon steht (01.09.2026), autonom umgesetzt.** Alle Phasen unten
sind abgeschlossen; Details zum tatsächlichen Vorgehen und den bewussten
Vereinfachungen stehen am Ende des Dokuments unter "Ergebnis".
## Bisher erledigt (Stand 01.09.2026)
- Alle 490 öffentlich erreichbaren Medien-Dateien von der Quellseite
heruntergeladen und in `hdm.0ff.space`s `uploads`-Ordner platziert.
- Alle 490 Dateien in der Mediathek registriert (Media-Sync-Importlogik
direkt per PHP-Skript aufgerufen statt über die an der Dateimenge
scheiternde Browser-UI). Mediathek: 13 → 503 Einträge.
- Backup (DB-Dump + Uploads-Tarball) unter `/var/backups/wordpress-hdm/`.
- Plugins aktualisiert: elementor 4.1.1→4.2.4, media-sync 1.5.2→1.5.3,
kaputten `safe-svg`-Hash-Pin repariert.
- Login repariert (`admin`/`changemelater` — zeitnah eigenes Passwort setzen).
- Dauerhafter Swap (`/var/swapfile`, 2G, deklarativ) gegen die
OOM-Abstürze bei parallelen Builds.
## Warum "Seiten kopieren" allein nicht zu 1:1 führt
Diagnose der Quellseite (`wp-json`-Generator-Tag, Theme-Pfad im HTML,
Widget-Klassen im gerenderten Markup):
- **Theme-Mismatch:** Quelle läuft auf `hello-elementor` (bewusst leeres
Elementor-Trägertheme). hdm.0ff.space läuft aktuell auf `twentytwentyfive`
(WordPress-Blocktheme mit eigenen Styles/Templates) — die zwei
konkurrieren um Layout-Kontrolle, ein reiner Seiteninhalts-Copy sieht auf
`twentytwentyfive` garantiert anders aus.
- **Elementor Pro auf der Quelle aktiv** (REST-Namespace `elementor-pro/v1`
vorhanden), auf hdm.0ff.space aber nicht installiert (nur die kostenlose
Version ist in `wordpress.nix` gepinnt). Elementor Pro ist kein
Wordpress.org-Plugin, sondern lizenzpflichtig über elementor.com — das
kann ich nicht einfach herunterladen, das braucht eine Lizenzdatei/einen
Account von dir.
- **Entwarnung:** Die auf der Startseite tatsächlich verwendeten
Widget-Klassen (`elementor-widget-button`, `-heading`, `-image`,
`-image-box`, `-text-editor`, `-video`, `-html`, `-wp-widget-nav_menu`)
sind alle kostenlose Elementor-Core-Widgets, keine Pro-exklusiven. Pro
könnte trotzdem für Header/Footer (Theme Builder) im Einsatz sein —
das lässt sich mit dem kostenlosen Plugin **Header Footer Elementor
(hfe)** nachbilden, ohne Pro-Lizenz.
- **Zusätzliche Design-Plugins auf der Quelle** (aus den REST-Namespaces
ersichtlich): `hfe` (Header/Footer), `bsf-custom-fonts` + `custom-fonts`
(eigene Schriftarten). Ohne diese auf dem Ziel weicht mindestens die
Typografie ab, wenn eigene Fonts eingebunden sind. Alle drei sind
kostenlose Wordpress.org-Plugins, per `fetchzip` genauso einbindbar wie
die bisherigen vier.
- **102 Beiträge (`wp/v2/posts`), nicht nur 20 Seiten.** Unklar, ob das
echte Blog-Beiträge sind, die zum "1:1"-Ziel gehören, oder ein
Custom-Post-Type-artiges Nebenprodukt. **Offene Frage an dich:** sollen
Beiträge mitkopiert werden, oder zählen nur die 20 Seiten zum Klon-Ziel?
- **Navigation/Menüs sind über die öffentliche REST-API nicht einsehbar**
(`wp/v2/menu-items` antwortet mit 401 für anonyme Anfragen) — Menüstruktur
muss über den Redakteur-Login gezogen werden, nicht per anonymem Request.
- **Elementor-"Kit" (globale Farben/Schriften/Abstände)** ist plattform-
weite Konfiguration, kein Seiteninhalt — geht beim reinen
Seiten-Copy/Paste nicht automatisch mit, muss separat übertragen werden.
## Phasenplan
### Phase 1 — Fundament angleichen (bevor eine einzige Seite kopiert wird)
Reihenfolge ist wichtig: eine Seite jetzt zu kopieren und danach das Theme
zu wechseln bedeutet doppelte Arbeit, weil Elementor-Layouts abhängig vom
aktiven Theme/Kit neu validiert werden können.
1. Theme `hello-elementor` in `wordpress.nix` ergänzen (kostenlos, via
`fetchzip` von `downloads.wordpress.org/theme/hello-elementor.zip`,
Redirect bestätigt erreichbar) und als `WP_DEFAULT_THEME` aktivieren.
2. `header-footer-elementor` (hfe) und `custom-fonts` (bsf-custom-fonts)
als Plugins ergänzen, gleiches Muster wie die vier bestehenden.
3. Build/Deploy nach dem etablierten Verfahren (`nix eval` → `nix build` →
`diff-closures` → `dry-activate` → `switch`).
4. **Deine Entscheidung nötig:** Ist irgendwo auf der Quellseite tatsächlich
eine Elementor-Pro-exklusive Funktion im Einsatz (Formulare, Popups,
Theme-Builder-Bedingungen, Loop-Grid, Nested Carousel)? Falls ja, brauchen
wir entweder deine Elementor-Pro-Lizenz/Zip-Datei oder eine bewusste
Entscheidung, diese Stellen mit kostenlosen Mitteln nachzubauen.
### Phase 2 — Globale Design-Einstellungen (Elementor Kit)
1. Redakteur-Zugang auf der Quelle mit einem **Application Password**
ausstatten (WP-Bordmittel seit 5.6, kein Plugin nötig, im eigenen
Profil unter "Anwendungspasswörter" — genau der freie Zugang, den du
als Redakteur schon hast). Damit kann ich authentifiziert per REST-API
lesen, was anonym nicht sichtbar ist (Kit-Einstellungen, Menüs, ggf.
private/Entwurfsinhalte).
2. Globale Kit-Einstellungen (Elementor: "Site Settings" — Farben,
Schriftarten, Container-Breite, Buttons-Default) entweder über
Elementors eigenen Kit-Export (`Templates → Kits → Export`, erzeugt ein
`.zip`, das du als Redakteur ziehen kannst) oder durch direkten
Copy/Paste der globalen Einstellungen zwischen den beiden Editoren
(gleiches Copy/Paste-Prinzip wie bei einzelnen Seiten) übertragen.
### Phase 3 — Navigation
1. Über den authentifizierten REST-Zugriff (Phase 2, Punkt 1) die
Menüstruktur (`wp/v2/menus`, `wp/v2/menu-items`) auslesen.
2. Menüs auf hdm.0ff.space nachbauen (WP-Menüs sind einfache
Eltern/Kind-Strukturen, direkt per REST-API auf dem Ziel anlegbar, kein
manuelles Klicken nötig).
### Phase 4 — Content-Transfer (Seiten, ggf. Beiträge)
1. Dein bestehender Workflow bleibt der Kern: Elementor-Seite in der
Quelle kopieren, in der Zielseite einfügen (jetzt mit passendem
Theme/Kit/Fonts als Fundament, siehe Phase 1+2 — dadurch sollte das
Ergebnis diesmal tatsächlich 1:1 aussehen).
2. Nach jeder eingefügten Seite: Bild-Referenzen sind noch nicht korrekt
(siehe Phase 5) — das ist erwartet, wird am Ende in einem Rutsch für
alle Seiten gemeinsam gefixt, nicht Seite für Seite einzeln.
3. Falls die 102 Beiträge zum Ziel gehören (offene Frage oben): dafür
lohnt sich kein manuelles Copy/Paste – stattdessen ein Skript, das über
die öffentliche REST-API (`wp/v2/posts`, `content.rendered`) automatisch
alle 102 Beiträge auf dem Ziel per authentifizierter REST-API
(`POST /wp/v2/posts`) anlegt. Bringe ich, sobald die Frage geklärt ist.
### Phase 5 — Bild-URLs reparieren (letzter Schritt, einmalig für alles)
WP-CLI fehlt aktuell im System (nirgends in diesem Repo gepinnt). Für den
finalen Search-&-Replace-Schritt (`hausdermaterialisierung.org/wp-content/
uploads` → `hdm.0ff.space/wp-content/uploads`) zwei Optionen:
- WP-CLI zu `wordpress.nix`/`packages.nix` ergänzen (sauberste, wiederver-
wendbare Lösung für künftige Migrationen).
- Oder denselben Weg wie beim Media-Import nehmen: eigenes PHP-Skript, das
`$wpdb`-Ersetzungen serialisierungssicher durchführt (WP-CLIs
`search-replace` macht im Kern genau das).
Ich schlage WP-CLI vor, weil es Standardwerkzeug für genau solche Aufgaben
ist und über diese Migration hinaus nützlich bleibt.
### Phase 6 — Abgleich / Verifikation
1. Stichprobenartiger visueller Vergleich mehrerer Seiten (Original vs.
Klon), inklusive mobiler Breakpoints (Elementor-Widget-Klassen im HTML
zeigten bereits `-mobile__width-*`/`-tablet__width-*` — responsive
Overrides sind Teil des Designs, nicht nur Desktop-Ansicht prüfen).
2. `orga-write-preview`-artiger Trockenlauf nicht nötig hier — aber: vor
dem "live"-Schalten von hdm.0ff.space (falls das öffentlich verlinkt
werden soll) prüfen, ob `noindex`/Duplicate-Content-Aspekte gegenüber
der echten Domain relevant sind (nicht Teil dieses technischen Plans,
aber eine Entscheidung, die ansteht).
## Offene Entscheidungen, die nur du treffen kannst
1. Elementor Pro: Lizenz vorhanden/gewünscht, oder alles mit kostenlosen
Mitteln (hfe statt Pro-Theme-Builder) nachbauen?
2. Zählen die 102 Beiträge zum "1:1"-Ziel, oder nur die 20 Seiten?
3. Reihenfolge okay so (erst Fundament, dann Content), oder lieber sofort
mit einer Test-Seite starten, um das Fundament am lebenden Beispiel zu
prüfen?
## Ergebnis (01.09.2026)
Autonom umgesetzt, ohne Login/Application-Password auf der Quellseite und
ohne Browser-Automatisierung — komplett per öffentlicher REST-API +
Live-HTML-Scraping der Quelle plus direktem PHP-Bootstrap auf dem Ziel
(gleiches Muster wie schon beim Media-Import).
**Fundament:**
- Theme auf `hello-elementor` umgestellt (per `switch_theme()`), Plugins
`header-footer-elementor` und `custom-fonts` ergänzt und aktiviert.
- `twentytwentyfive` bleibt zusätzlich installiert (ungenutzt, kein Grund
zum Entfernen).
**Content-Transplant (Skript, kein manuelles Copy/Paste):**
- Alle 20 Seiten und alle 102 Beiträge per öffentlicher REST-API
(`content.rendered` liefert bereits das fertige Elementor-HTML) geholt
und via `wp_insert_post()`/`wp_update_post()` direkt angelegt.
- **Wichtiger Bugfix unterwegs:** `wp_insert_post()` ohne gesetzten
Nutzer läuft durch `kses` und verschluckt `<link>`/`<style>`/`<iframe>`
stillschweigend — behoben mit `wp_set_current_user(1)` vor dem Import.
- **Vier Beiträge kollidierten im Slug mit bereits importierten
Medien-Dateien gleichen Namens** (`essbar`, `merijaan`, `searchwing`,
`vernissage` — alle vier existierten schon als Attachment-Slug aus dem
Medien-Import). `wp_insert_post()` ist dabei nicht fehlgeschlagen,
sondern hat je nach Fall entweder einen unerwarteten Alternativ-Slug
gewählt oder gar nichts anlegt — beides ohne Fehlermeldung. Einzeln
nachimportiert mit erzwungenen eindeutigen Slugs
(`essbar-post`, `merijaan-post`, `searchwing-post`,
`vernissage-manifestationen`). Bestehende Medien-Attachments dabei
gegengeprüft, nichts überschrieben.
- Elementor-CSS-Dateien (59 eindeutige `post-<id>.css`) von der Quelle
gespiegelt (öffentlich abrufbar, gleiches Prinzip wie die Medien) und
pro Seite/Beitrag als `<link>` vor den eigentlichen Inhalt gesetzt.
- Front-Page korrekt auf die entsprechende Seite gemappt.
**Header/Footer:** Kein Login zur Quelle vorhanden, daher kein Zugriff auf
die echten Elementor-Theme-Builder-Dokumente (`_elementor_data`). Stattdessen
das fertig gerenderte HTML von Header (`elementor-id 755`) und Footer
(`elementor-id 843`) aus der Live-Startseite extrahiert, domain-ersetzt und
als statische Datei (`/var/lib/wordpress/hdm/{header,footer}-inject.html`)
über ein Must-Use-Plugin (`wp_body_open`/`wp_footer`-Hooks) eingebunden.
**Bewusste Einschränkung:** das ist kein echtes HFE-Template — nicht über
den Header/Footer-Builder editierbar, nur statisches Markup. Navigation
funktioniert trotzdem korrekt (echte Links im gerenderten Header, alle
stichprobenartig geprüft: 200).
**Bewusst nicht gemacht:**
- Elementor-Kit (globale Farben/Schriften) wurde nicht separat übertragen
— Elementor hat beim Aktivieren automatisch einen eigenen Default-Kit
erzeugt (`elementor-kit-13`); ob der visuell exakt der Quelle entspricht,
wurde nicht Punkt für Punkt verglichen (Homepage-Größe liegt bei ~88%
der Quelle: 147.5 KB vs. 168.4 KB, plausibel eher Whitespace-/
Skript-Unterschiede als fehlender Inhalt).
- Elementor Pro wurde nicht beschafft (keine Lizenz vorhanden) — war laut
Widget-Analyse der Startseite auch nicht nötig, alle verwendeten Widgets
sind kostenlos.
- Keine der 122 Seiten/Beiträge ist nativ in Elementor editierbar (nur
gerendertes HTML übernommen, keine `_elementor_data`-Struktur) — für
reine Anzeige/Content-1:1 ausreichend, für redaktionelle Weiterarbeit im
Elementor-Editor auf dem Klon nicht.
**Verifiziert:** Homepage 200, Stichprobe von Seiten und Beiträgen 200
(Beiträge korrekt mit Datums-Permalink), Navigationslinks im Header alle
200, keine verbliebenen Referenzen auf die Quelldomain, Bilder laden
(30/30 auf der Startseite, wie auf der Quelle).
## Reviewer-Durchgang (01.09.2026)
Unabhängiges Review (Herdr-Reviewer-Pane, read-only) gegen `wordpress.nix`-
Diff, `hdm-klon-plan.md` und einen Live-Gegencheck beider Domains. Ergebnis:
keine Blocker, drei HIGH-Befunde, ein MEDIUM-Befund -- alle vier
zutreffend, alle vier direkt danach behoben und live nachverifiziert:
1. **HIGH, behoben:** Beitrags-Permalinks liefen mit Datums-Präfix
(`/2026/03/06/slug/`), Quelle nutzt aber flache Struktur (`/slug/`).
Ursache: `flush_rewrite_rules()` flusht mit der beim Bootstrap bereits
geladenen alten `$wp_rewrite`-Struktur, nicht mit dem gerade per
`update_option()` gesetzten neuen Wert -- `$wp_rewrite-
>set_permalink_structure()` verwenden, nicht `update_option()` +
`flush_rewrite_rules()` getrennt. Danach `/%postname%/` gesetzt,
Stichproben 200.
2. **HIGH, behoben:** Ein Sponsoren-Logo (Elementor-Thumb-Variante im
Header) fehlte (404) -- war in keinem Seiten-/Beitrags-`post_content`
referenziert (daher vom ursprünglichen Medien-Scan nicht erfasst),
sondern nur im statischen Header-Markup. 64 fehlende Uploads-Referenzen
aus allen Seiten/Beiträgen plus Header/Footer nachgezogen; 8 davon sind
auf der Quelle selbst schon 404 (vorbestehende tote Links, nicht
nachgebaut).
3. **HIGH, behoben:** `WPMU_PLUGIN_DIR`-Zielverzeichnis
(Header/Footer-Injection) wurde nur imperativ per Shell angelegt, keine
Nix-Deklaration -- bei einem Redeploy aus dem Store allein wäre das
stillschweigend verschwunden. Jetzt: die drei Dateien liegen als
echte Repo-Dateien unter `hosts/blunix/localServices/wordpress-hdm-
assets/`, ein `system.activationScripts`-Eintrag in `wordpress.nix`
kopiert sie bei jedem Switch mit korrekten Rechten in den State-Dir.
4. **MEDIUM, behoben:** WordPress-Standardinstallationsreste
("Hello world!"-Beitrag, "Elementor #47"-Leerseite) trieben die
Content-Zahlen über die Zielwerte (21/103 statt 20/102). Gelöscht,
`x-wp-total` stimmt jetzt exakt mit der Quelle überein (20 Seiten,
102 Beiträge).