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
14 KiB
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.spacesuploads-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 auftwentytwentyfive(WordPress-Blocktheme mit eigenen Styles/Templates) — die zwei konkurrieren um Layout-Kontrolle, ein reiner Seiteninhalts-Copy sieht auftwentytwentyfivegarantiert anders aus. - Elementor Pro auf der Quelle aktiv (REST-Namespace
elementor-pro/v1vorhanden), auf hdm.0ff.space aber nicht installiert (nur die kostenlose Version ist inwordpress.nixgepinnt). 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.
- Entwarnung: Die auf der Startseite tatsächlich verwendeten
Widget-Klassen (
- 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, perfetchzipgenauso 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-itemsantwortet 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.
- Theme
hello-elementorinwordpress.nixergänzen (kostenlos, viafetchzipvondownloads.wordpress.org/theme/hello-elementor.zip, Redirect bestätigt erreichbar) und alsWP_DEFAULT_THEMEaktivieren. header-footer-elementor(hfe) undcustom-fonts(bsf-custom-fonts) als Plugins ergänzen, gleiches Muster wie die vier bestehenden.- Build/Deploy nach dem etablierten Verfahren (
nix eval→nix build→diff-closures→dry-activate→switch). - 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)
- 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).
- 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
- Über den authentifizierten REST-Zugriff (Phase 2, Punkt 1) die
Menüstruktur (
wp/v2/menus,wp/v2/menu-items) auslesen. - 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)
- 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).
- 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.
- 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.nixergä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-CLIssearch-replacemacht 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
- 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). 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, obnoindex/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
- Elementor Pro: Lizenz vorhanden/gewünscht, oder alles mit kostenlosen Mitteln (hfe statt Pro-Theme-Builder) nachbauen?
- Zählen die 102 Beiträge zum "1:1"-Ziel, oder nur die 20 Seiten?
- 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-elementorumgestellt (perswitch_theme()), Pluginsheader-footer-elementorundcustom-fontsergänzt und aktiviert. twentytwentyfivebleibt 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.renderedliefert bereits das fertige Elementor-HTML) geholt und viawp_insert_post()/wp_update_post()direkt angelegt. - Wichtiger Bugfix unterwegs:
wp_insert_post()ohne gesetzten Nutzer läuft durchksesund verschluckt<link>/<style>/<iframe>stillschweigend — behoben mitwp_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:
- 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 perupdate_option()gesetzten neuen Wert -- `$wp_rewrite-set_permalink_structure()
verwenden, nichtupdate_option()+flush_rewrite_rules()getrennt. Danach/%postname%/` gesetzt, Stichproben 200. - HIGH, behoben: Ein Sponsoren-Logo (Elementor-Thumb-Variante im
Header) fehlte (404) -- war in keinem Seiten-/Beitrags-
post_contentreferenziert (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). - 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 unterhosts/blunix/localServices/wordpress-hdm- assets/, einsystem.activationScripts-Eintrag inwordpress.nixkopiert sie bei jedem Switch mit korrekten Rechten in den State-Dir. - 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-totalstimmt jetzt exakt mit der Quelle überein (20 Seiten, 102 Beiträge).