# Skrift Auto Article Zwei n8n-Workflows fuer die Ratgeber-Produktion von skrift.de. ``` artikel-index.json Redaktionsplan, eine Zeile je Artikel | v Workflow 1: brief-vorbereiten briefe/brief-.json NeuronWriter-Brief als Schreibvorlage | v Cowork schreibt den Artikel artikel/artikel-.json fertiger Artikel | v Workflow 2: pruefen-und-importieren WordPress-Entwurf + nachbessern/nachbessern-.json bei zu niedrigem Score ``` --- ## 1. Einmalige Einrichtung ### 1.1 Credentials in n8n Die Workflows referenzieren drei Credentials, die bereits im n8n-Credential-Store angelegt sind. In den Node-Parametern steht kein einziges Geheimnis. | Credential | Typ | Inhalt | |---|---|---| | `NeuronWriter API` | HTTP Header Auth | Name `X-API-KEY`, Wert = NeuronWriter-Key | | `Gitea Skrift Auto Article` | HTTP Header Auth | Name `Authorization`, Wert = `token ` | | `WP skrift.de Redakteur` | HTTP Basic Auth | Benutzer `ai-agent`, Passwort = Application Password | Wird ein Key ausgetauscht, nur das Credential in n8n bearbeiten. Die Workflow-Dateien bleiben unveraendert. **Gitea-Token:** braucht den Scope `write:repository`. Mit `read:repository` allein scheitert jeder Schreibvorgang mit HTTP 403 und der Meldung `token does not have at least one of required scope(s)`. **WordPress-Benutzer:** eigener Benutzer mit Rolle Redakteur, kein Administrator. Die Rolle Redakteur darf technisch auch veroeffentlichen. Der Workflow setzt `status: draft` hart und bricht ab, falls WordPress etwas anderes zurueckmeldet. Wer das zusaetzlich absichern will, nimmt die Rolle Autor und entzieht per Code-Snippet `publish_posts`. Dann kann der Benutzer aber keine fremden Beitraege mehr aktualisieren, was die Idempotenz bricht. ### 1.2 Mu-Plugin auf skrift.de `wordpress/skrift-ratgeber-felder.php` nach `wp-content/mu-plugins/` kopieren. Es registriert vier Meta-Felder REST-schreibbar: | Feld | Typ | Inhalt | |---|---|---| | `kurzantwort` | string | Ein Absatz, der die Suchfrage sofort beantwortet | | `cta_ziel` | string (URL) | Zieladresse des Call-to-Action | | `stand_datum` | string | Format `YYYY-MM-DD` | | `faq` | array | `[{frage, antwort}]` | Ohne dieses Plugin nimmt die WordPress-REST-API die Felder stillschweigend nicht an. Der Workflow erkennt das und schreibt eine Warnung in die Benachrichtigung. Ausgabe der FAQ im Beitrag ueber den Shortcode `[skrift_faq titel="Haeufige Fragen"]`, zum Beispiel in einem Elementor-Shortcode-Widget. Die drei einfachen Felder lassen sich in Elementor Pro direkt als Dynamic Tag "Post Custom Field" einbinden. ### 1.3 SMTP fuer die Benachrichtigung Beide Workflows enden auf einem Node `Benachrichtigung`, der **deaktiviert** ist. Zum Aktivieren: SMTP-Credential zuweisen, Absenderadresse eintragen, Node aktivieren. Die Meldung wird vom Node davor fertig formuliert, am Text selbst muss nichts geaendert werden. --- ## 2. Workflow 1: brief-vorbereiten ### Start - Manuell in der n8n-Oberflaeche - Zeitplan Montag 07:00 (Node ist deaktiviert, bei Bedarf aktivieren) - Webhook: `POST https://n8n.lucas-orth.de/webhook/brief-vorbereiten` ### Ablauf 1. `artikel-index.json` ueber die Gitea-API lesen 2. Alle Zeilen mit `status: "offen"` herausfiltern, Pflichtfelder pruefen 3. Je Artikel `POST /new-query` an NeuronWriter 4. `POST /get-query` pollen, alle 20 Sekunden, maximal 30 Versuche 5. Antwort auf die benoetigten Felder reduzieren 6. `briefe/brief-.json` committen 7. Status auf `brief_bereit` setzen, `query_id` in die Zeile schreiben 8. Benachrichtigung ### Pflichtfelder in artikel-index.json Die Datei ist ein Array. Jede Zeile braucht: ```json { "slug": "handgeschriebene-werbebriefe", "titel": "Handgeschriebene Werbebriefe: Wann sie wirken und wann nicht", "keyword": "handgeschriebene werbebriefe", "kategorie": "Direktmarketing", "cta_ziel": "https://skrift.de/muster-anfordern", "status": "offen" } ``` Fehlt eines der Felder in einer Zeile mit `status: "offen"`, bricht der Workflow mit Angabe von Zeilennummer und fehlenden Feldern ab. Zeilen mit anderem Status werden nicht geprueft. Statuswerte: `offen` -> `brief_bereit` (durch Workflow 1) -> danach frei nutzbar. ### Was im Brief steht Die im Auftrag geforderten Felder liegen auf oberster Ebene: `query_id`, `keyword`, `begriffe_pflicht`, `begriffe_erweitert`, `fragen`, `wortzahl_ziel`. `begriffe_pflicht` und `begriffe_erweitert` enthalten je Begriff die von NeuronWriter empfohlene Spanne: ```json {"begriff": "handschriftlich", "min": 1, "max": 17, "bei_wettbewerbern_pc": 70} ``` `fragen` fasst vier NeuronWriter-Quellen zusammen, dedupliziert und nach Wichtigkeit sortiert. Fragen aus der `topic_matrix` tragen ein `gewicht` von 1 bis 10. Darunter steht `artikel` mit slug, titel, kategorie und cta_ziel aus der Tabelle, sowie ein Block `zusatz` mit Material, das beim Schreiben hilft: Ueberschriften-Begriffe, Entitaeten, Suchintention, Zielwortzahl-Median und die vollstaendigen Gliederungen der fuenf bestplatzierten Wettbewerber. --- ## 3. Workflow 2: pruefen-und-importieren ### Start - Manuell - Webhook: `POST https://n8n.lucas-orth.de/webhook/pruefen-und-importieren` ### Vertrag Cowork -> Workflow 2 Cowork legt je Artikel eine Datei `artikel/artikel-.json` an: ```json { "slug": "handgeschriebene-werbebriefe", "titel": "Handgeschriebene Werbebriefe: Wann sie wirken und wann nicht", "query_id": "565abcca58f65e52", "keyword": "handgeschriebene werbebriefe", "kategorie": "Direktmarketing", "cta_ziel": "https://skrift.de/muster-anfordern", "content_html": "

...

...

", "kurzantwort": "Ein Absatz, der die Hauptfrage direkt beantwortet.", "faq": [{"frage": "...", "antwort": "..."}], "seo_titel": "max. 60 Zeichen", "seo_beschreibung": "max. 155 Zeichen", "stand_datum": "2026-09-20" } ``` Pflicht sind `slug`, `titel`, `query_id`, `kategorie`, `content_html`. Der Slug im Dateinamen muss mit dem Slug im JSON uebereinstimmen, sonst bricht der Workflow fuer diesen Artikel ab. `query_id` stammt aus dem Brief, Workflow 1 schreibt sie zusaetzlich in `artikel-index.json`. Fehlt `stand_datum`, setzt der Workflow das heutige Datum. Fehlt `seo_titel`, wird `titel` verwendet. ### Ablauf 1. Ordner `artikel/` auflisten, alle `artikel-*.json` einsammeln 2. Je Artikel: Datei laden, zugehoerigen Brief laden 3. `POST /evaluate-content` an NeuronWriter, `content_score` auslesen 4. Score unter Zielwert: - fehlende Begriffe gegen den Brief berechnen - `nachbessern/nachbessern-.json` committen - naechster Artikel 5. Score ab Zielwert: - `POST /import-content` speichert die Revision in NeuronWriter - `GET /wp-json/wp/v2/posts?slug=` prueft auf vorhandenen Beitrag - Kategorie suchen, bei Bedarf anlegen - Beitrag anlegen oder aktualisieren, immer `status: draft` - Meta-Felder und SEOPress-Felder im selben Request - Cache leeren - Zeile in `status-importe.json` 6. Benachrichtigung mit Vorschaulinks ### Zielwert anpassen Im Node **Konfiguration**, Feld `score_ziel`. Standard ist 72. Der Wert gilt fuer alle Artikel eines Laufs. Alle anderen Stellschrauben liegen im selben Node: Basis-URLs, Ordnernamen, Pause zwischen Artikeln, Empfaengeradresse. ### Nachbesserungsbericht `/evaluate-content` liefert ausschliesslich `{status, content_score}`, also keine Liste fehlender Begriffe. Der Workflow berechnet sie deshalb selbst, indem er den Artikeltext gegen `begriffe_pflicht` und `begriffe_erweitert` aus dem Brief zaehlt. ```json { "score": 44, "score_ziel": 72, "wortzahl": {"ist": 96, "ziel": 1178, "differenz": -1082}, "fehlende_pflichtbegriffe": [{"begriff": "empfänger", "soll_min": 1, "soll_max": 9, "ist": 0, "luecke": 1}], "fehlende_zusatzbegriffe": [], "unbeantwortete_fragen": [{"frage": "...", "gewicht": 10}] } ``` Die Zaehlung arbeitet als Teilstring auf kleingeschriebenem Text. Komposita zaehlen mit: `brief` wird auch in `Werbebriefe` gefunden. Umlaute werden **nicht** normalisiert. Steht im Artikel `Empfaenger` statt `Empfänger`, gilt der Begriff als fehlend. Das ist gewollt, weil NeuronWriter genauso zaehlt. --- ## 4. Fehlerverhalten Jeder HTTP-Node hat einen eigenen Fehlerausgang mit einer Meldung, die die wahrscheinliche Ursache benennt statt nur den Statuscode. Ein Artikel darf uebersprungen werden bei: Analyse-Start, Status-Abfrage, Poll-Timeout, Artikel-Datei laden, Score-Ermittlung, Nachbesserungs-Commit. Der Lauf geht dann mit dem naechsten Artikel weiter, der Fehler landet in der Benachrichtigung. Ein Artikel darf **nicht** uebersprungen werden beim Schreiben nach WordPress. Der Node `Beitrag anlegen oder aktualisieren` hat bewusst kein Continue On Fail. Schlaegt er fehl, stoppt der gesamte Lauf, damit kein halb importierter Zustand unbemerkt bleibt. Dasselbe gilt fuer das Zurueckschreiben des Status in Workflow 1: bleibt die Tabelle auf `offen`, wuerden beim naechsten Lauf Analysen doppelt erzeugt und Kontingent verbraucht. HTTP-Nodes wiederholen bei technischen Fehlern dreimal mit drei Sekunden Abstand. Zwischen zwei Artikeln liegt eine Pause von fuenf Sekunden. --- ## 5. Aufbau des Repos ``` artikel-index.json Redaktionsplan artikel/ fertige Artikel aus Cowork briefe/ NeuronWriter-Briefe aus Workflow 1 nachbessern/ Berichte zu Artikeln unter Zielwert status-importe.json was wann als Entwurf nach WordPress ging workflows/ die beiden importfertigen n8n-Dateien build/ Generatorskripte, die die Workflow-JSONs erzeugen wordpress/ Mu-Plugin fuer die Meta-Felder docs/ Feldnachweis und Rohbelege der API-Antworten .env Zugangsdaten, nicht versioniert .env.example Vorlage ohne Werte ``` Die Workflow-JSONs werden nicht von Hand bearbeitet, sondern aus `build/gen_wf1.py` und `build/gen_wf2.py` erzeugt: ``` python3 build/gen_wf1.py python3 build/gen_wf2.py ``` Danach in n8n importieren oder per API aktualisieren. Wer lieber direkt in der n8n-Oberflaeche arbeitet, exportiert den Workflow anschliessend wieder nach `workflows/` und laesst die Generatoren liegen. --- ## 6. Belege `docs/feldnachweis.md` listet jede Stelle, an der ein Feldname aus einer echten API-Antwort ermittelt wurde, mit Beispielantwort. Die Rohantworten liegen als `docs/beleg-*.json` daneben.