Dynamische PDF-Generierung mit Gotenberg, n8n und SeaTable

Dynamische PDF-Generierung mit Gotenberg, n8n und SeaTable. SeaTable wird als Backend für die Konfiguration verwendet und Gotenberg erstellt die PDFs, während n8n alles zusammenbindet.

Bei meinem Vortrag auf den Seadays 2024 habe ich gezeigt, wie ich in einem Projekt SeaTable als Backend genutzt habe, um Daten wie Logo und Fußzeile einer PDF-Vorlage zu konfigurieren — und versprochen, noch mehr dazu zu teilen. Mir ist neulich aufgefallen, dass ich genau das vergessen habe: Setup und Workflow zu teilen. Sorry, ich war etwas nervös und hab’s nicht aufgeschrieben. Hier ist es also, ein paar Monate später.

Was ist Gotenberg?

Bevor wir in den Workflow eintauchen, kurz für alle, die Gotenberg nicht kennen: was das überhaupt ist.

Gotenberg ist eine Docker-basierte, zustandslose API, die HTML, Markdown und Office-Dokumente in PDF umwandelt. Stell es dir als Webservice vor, der dein HTML (mit CSS) nimmt und ein sauber formatiertes PDF ausspuckt — Schluss mit komplexen PDF-Bibliotheken und dem Kampf gegen Formatierungsprobleme.

Warum das nützlich ist? Nun, wenn du schon mal PDFs programmatisch erzeugen wolltest, weißt du, wie schmerzhaft das sein kann. Gotenberg nimmt dir die ganze schwere Arbeit ab. Du schickst dein HTML einfach per HTTP-POST hin, und es kommt ein schönes PDF zurück. Unter der Haube läuft Chrome, also sehen deine PDFs genau so aus wie im Browser — heißt: Dein CSS funktioniert wie erwartet. Das Beste daran? Es ist komplett zustandslos — du kannst es in einem Container laufen lassen, nach Bedarf hoch- und runterskalieren, und es legt nichts auf der Festplatte ab. Perfekt für Automatisierungs-Workflows wie den, den wir hier mit n8n bauen.

Für dieses Tutorial nehme ich die Demo-Installation unter https://demo.gotenberg.dev/, aber ich empfehle dir dringend, für den produktiven Einsatz deine eigene Instanz aufzusetzen. Es ist nur ein einfacher Docker-Container, die Bereitstellung ist also unkompliziert.

SeaTable Setup

Das SeaTable-Setup ist sehr einfach. Du brauchst nur eine einzige Tabelle, nennen wir sie PDF Configuration, und ein paar Spalten. (Oder lad dir die SeaTable Base herunter und importier sie in deine SeaTable-Instanz.)

Das funktioniert wie ein Key/Value-Store: Wir haben den Schlüssel (zum Beispiel Logo) und einen Wert (die Logo-Datei). Es gibt außerdem zwei Arten von Werte-Feldern, Value und Value Long. Warum, zeige ich später genauer — kurz gesagt: Wenn du einen Wert wie einen Firmennamen oder eine Adresse hast, brauchst du höchstwahrscheinlich keine der Formatierungen, die SeaTable bietet (fett, unterstrichen, Zeilenumbrüche etc.), also reicht ein normales Textfeld — in einem Textfeld in SeaTable kannst du sowieso nichts formatieren und keine Zeilenumbrüche setzen.

Wenn du aber mehr Text brauchst und ihn formatieren willst — denk an die Fußzeile einer Rechnung — wo du Zeilenumbrüche, fetten Text etc. brauchst, dann ist das Value Long-Feld perfekt: Da hast du alle Formatierungsoptionen von SeaTable. Man könnte sagen: Nimm einfach Value Long und formatier nichts. Aber: Nutzer sehen das Textfeld und fangen an, formatierten Text einzugeben, und wenn dein Workflow in n8n das nicht behandelt, bekommst du sehr unerwartete Ergebnisse auf dem PDF — aber lass uns nicht vorgreifen und Schritt für Schritt vorgehen.

n8n Workflow

Mit dieser sehr einfachen SeaTable Base gehen wir zum n8n Flow. Fangen wir mit den Grundlagen an. Nehmen wir an, du willst ein Rechnungssystem auf Basis von SeaTable bauen und nutzt n8n + Gotenberg, um das PDF zu erstellen.

Eine Rechnungsvorlage erstellen

Zuerst brauchst du eine Rechnungsvorlage. Für dieses Beispiel kannst du diese einfache Vorlage zum Einstieg nehmen. Es ist nur statisches HTML, kein Logo, keine Platzhalter, nur HTML + CSS.

Ein erstes PDF erstellen

Importier den ersten Workflow aus dem GitHub-Repo, der sieht so aus. Er nutzt die Demo-Installation von Gotenberg. Ich empfehle dir dringend, dein eigenes Gotenberg aufzusetzen, aber zur Demonstration nehmen wir die öffentliche Demo-Installation.

Schlüsseln wir das auf.

HTML zu Binärdaten

Die Rechnungsvorlage nimmt einfach das HTML aus der Rechnungsvorlage und reicht es ohne Änderungen an den nächsten Node weiter, der es in eine Datei umwandelt. Du musst das tun, weil Gotenberg in einer POST-Anfrage eine Binärdatei als Formulardaten erwartet, um das HTML in PDF zu konvertieren. Das Ganze nimmt nur das HTML aus dem html-Eingabefeld und speichert es als Binärdaten im data-Feld mit dem Dateinamen index.html.

HTML in PDF konvertieren

Jetzt werden diese Binärdaten an den HTTP-Request-Node weitergegeben, der eine HTTP-POST-Anfrage an Gotenberg schickt. Hier musst du die URL https://demo.gotenberg.dev/forms/chromium/convert/html definieren und den Body als Form-Data mit den zuvor erstellten Binärdaten senden.

Gotenberg gibt dann ein PDF zurück, das du auch aus n8n herunterladen könntest. Soweit so gut, aber … das ist etwas langweilig und nicht ganz das Ziel dieses Beitrags. Babyschritte … einer nach dem anderen, ich komme dahin.

Das Logo hinzufügen

Bevor du das Logo wirklich hinzufügen kannst, musst du n8n mit SeaTable verbinden — und dafür brauchst du einen API-Schlüssel von SeaTable.

Die API vorbereiten

Einen API-Schlüssel in SeaTable erstellen

Für einen API-Schlüssel gehst du in die Base → Erweitert → API Token

Gib ihm einen Namen und klick auf Submit. Wenn du nichts nach SeaTable schreiben willst, kannst du die Berechtigung auch auf Read-Only setzen.

Nimm jetzt den API-Schlüssel; wir fügen ihn n8n hinzu, sobald wir zum SeaTable-Node kommen.

Den Schlüssel zu n8n hinzufügen

Füge einen SeaTable-Node in deinen n8n-Workflow ein, mit der Zeilen-Aktion Search a row by keyword

Erstell eine neue Berechtigung

Füg hier deinen SeaTable-API-Schlüssel ein

Das sollte nach dem Speichern bestätigen, dass alles einwandfrei läuft.

Nach dem Logo suchen

Sag deinem SeaTable-Such-Node, dass er nach einem Schlüssel namens logo in der Tabelle PDF Configuration suchen soll. Wenn du ihn ausführst, siehst du so etwas wie hier — inklusive einer URL fürs Logo. Großartig!

Naja … fast, denn diese URL funktioniert nur, wenn du bei SeaTable angemeldet bist — öffentlich erreichbar ist sie nicht, heißt: Gotenberg kommt auch nicht dran.

Eine öffentliche URL für das Logo erstellen

Damit Gotenberg (oder jede andere öffentliche Ressource) ans Logo kommt, musst du den SeaTable-Node Get the public URL from asset path ausführen.

Beachte bitte: Sobald du eine öffentliche URL erstellt hast, ist sie öffentlich. Heißt: JEDER, der die URL kennt, kommt dran, und es gibt keinen n8n-Node, um einen öffentlichen Link wieder zu entfernen! Behalt das im Hinterkopf.

Ruf diesen Node mit dem path vom Such-Node auf; du musst den Pfad nehmen und nicht die URL! Nach dem Ausführen bekommst du eine Download-URL, mit der du — und Gotenberg übrigens auch — ans Logo kommst.

Das kannst du jetzt in der HTML-Vorlage nutzen, um das Logo einzufügen. Also los.

Das Logo zum HTML hinzufügen

Hol dir die neue Vorlage aus dem HTML-Repo, die im Grunde nur die Zeile fürs Logo zusätzlich zur vorherigen Vorlage enthält — inklusive ein bisschen hässlichem Inline-Styling, damit das Logo nicht die ganze Seite füllt.

<img src="{{ $json.download_link }}" style="width: 100%; max-width: 300px">

damit das aus dem Weg ist, erstellen wir das PDF und schauen uns den kompletten Workflow an.

Das PDF enthält jetzt das Logo

Der Rahmen drum herum ist unschön, aber das ist kein Tutorial übers Design schöner Rechnungen, also reicht das für dieses Beispiel.

Der vollständige Logo-Workflow

Der “vollständige Workflow” klingt, als wäre es etwas richtig Komplexes, aber wenn du dir den Workflow ansiehst, siehst du, wie einfach er ist — und warum n8n dafür so großartig ist.

Geändert wurde in diesem Workflow nur der Inhalt der Rechnungsvorlage und die zwei Nodes, um Logo und öffentliche URL fürs Logo zu holen.

Wie wär’s mit etwas Text?

Warum nicht mit dieser Vorlage weitermachen? Ich zeige dir, wie du auch die Value- und Value Long-Felder nutzt. Zur Demonstration nehmen wir einfach an, die E-Mail deines Unternehmens soll konfigurierbar sein.

Neue Konfiguration in SeaTable hinzufügen

Geh in die PDF-Konfiguration in SeaTable und füge eine neue Zeile mit der E-Mail hinzu.

Deine Konfiguration sollte jetzt so aussehen:

Diese Konfiguration aus n8n abrufen

Alles, was du dafür brauchst, ist ein neuer Such-Node und die Suche nach dem email-Schlüssel.

Aktualisier deine Vorlage so, dass sie die E-Mail enthält

und du bist fertig 🎉. Du hast erfolgreich die E-Mail aus der SeaTable-Konfiguration ins PDF eingefügt.

Du kannst dir die neue Rechnungs-HTML aus dem Repo holen sowie den neuen Workflow, der jetzt so aussieht:

Schön. Immer noch einfach und unkompliziert, und es ist schon konfigurierbar und erweiterbar. Was ist mit den Value Long-Werten?

Formatierten Text hinzufügen

Jetzt zum letzten Teil dieses Tutorials: formatierten Text in die Vorlage bringen. Für dieses Beispiel nehmen wir uns die Bankdaten vor und machen sie in SeaTable konfigurierbar:

Bank-Konfiguration zu SeaTable hinzufügen

Zuerst korrigieren wir einen Fehler in der SeaTable-Tabelle. Das Value Long-Feld wurde versehentlich als Text-Feld statt als Long Text angelegt

Geh zur Spaltenkonfiguration → Spaltentyp anpassen

Und änder es auf Long Text

Jetzt kannst du den formatierten Text zu SeaTable hinzufügen

Warum jemand den Banknamen kursiv schreiben würde, ist mir ein Rätsel, aber hey, ich urteile nicht.

Die neue Konfiguration abrufen

Jetzt wieder: Füg einen Such-Node hinzu und such nach dem Schlüssel bank_details. Das gibt dir die formatierten Daten fürs PDF — diese Formatierung ist allerdings in Markdown, und wir brauchen HTML.

Markdown zu HTML konvertieren

Glück gehabt: n8n bringt einen Markdown-zu-HTML-Node mit

Eine Sache mag ich noch nicht ganz, etwas, womit ich früher schon Probleme hatte. Ich mag die doppelten Zeilenumbrüche nicht, die von SeaTable kommen, und hatte auch Probleme mit unsichtbaren Leerzeichen oder escapten @-Zeichen. Das löst man leicht mit ein bisschen JavaScript. Statt {{ $json['Value Long'] }} nimmst du also {{ $json['Value Long'].replaceAll(/&#x20;/g, ' ').replaceAll(/\n\n/g, '\n').replaceAll(/\\@/g, '@') }}, was sich um das Ersetzen dieser Stellen kümmert.

Es zur HTML-Vorlage hinzufügen

Jetzt musst du nur noch diesen formatierten Text in die HTML-Vorlage bringen. Entfern den statischen Text aus der HTML-Vorlage und füg die Daten aus dem Markdown-Konvertierungs-Node ein. (oder lad dir einfach das neue HTML aus dem Repo herunter)

Und schau dir das an — die formatierten Daten sind auf dem PDF.

Abschließende Gedanken

Bevor du losziehst und das in Produktion einsetzt, lass mich ein paar Dinge ansprechen. Dieser Workflow ist absichtlich einfach gehalten, um die Kernfunktion zu zeigen: SeaTable mit n8n und Gotenberg zu verbinden. In einem echten Szenario würdest du wahrscheinlich ein paar Verbesserungen einbauen. Zum einen: Wenn du viele Konfigurationselemente hast, kann ein separater Such-Node pro Element deinen Workflow schnell wie ein verworrenes Durcheinander aussehen lassen. Du könntest das optimieren, indem du alle Konfigurationsdaten in einem einzigen Aufruf holst und dann verarbeitest, oder ein ausgefeilteres Lookup-System baust. Aber für dieses Tutorial machen mehrere Such-Nodes es leichter zu verstehen, was bei jedem Schritt passiert. Außerdem hat dieses Beispiel absolut keine Fehlerbehandlung. Was passiert, wenn der Logo-Schlüssel in SeaTable nicht existiert? Was, wenn die API down ist? Was, wenn die Bilddatei beschädigt ist? In einem Produktions-Workflow würdest du ordentliche Fehlerbehandlung, Fallback-Werte und vielleicht etwas Validierung einbauen, damit deine PDFs nicht kaputtgehen, wenn etwas schiefläuft. Das Ziel war hier nicht, ein kugelsicheres Produktionssystem zu bauen, sondern dir zu zeigen, wie diese drei Tools zusammenspielen — und dir eine Grundlage zum Weiterbauen zu geben. Wenn du die Grundlagen verstanden hast, kannst du allen Schnickschnack hinzufügen, den dein konkreter Anwendungsfall braucht. Nimm das also als Ausgangspunkt, nicht als Ziellinie. Frohes Automatisieren! 🚀

Brauchst du Hilfe mit n8n?

Wenn du dein Automatisierungs-Game heben willst oder Hilfe brauchst, Workflows wie diese in deinem Unternehmen umzusetzen:

Meld dich, wenn du diese repetitiven Aufgaben in automatisierte Workflows verwandeln willst, die rund um die Uhr laufen!


Der komplette Workflow

Download

essential