Von der Konzeption bis zum Deployment: alles aus einer Hand
invoi.app ist meine persönliche Buchhaltungsapp, die ich im Rahmen meiner Selbstständigkeit entwickelt habe. Als ich damals anfing, nach einer Softwarelösung für meine Buchhaltung zu suchen, kam in mir schnell der Gedanke auf, dass ich nicht für etwas bezahlen möchte, was ich auch selber bauen kann. Gedacht, getan. Diese App hat mit den Jahren verschiedene Evolutionsstufen durchlaufen und mir immer wieder Futter zum Lernen gegeben. Dabei ist jede Ebene durch meine Hände gegangen: Anforderungen, Datenmodell, Frontend, Backend, PDF Service und Infrastruktur. Aktuell beschäftige ich mich verstärkt mit der DevOps-Seite der App.
Vom Interface bis zur Infrastruktur
invoi.app ist kein einzelnes Programm, sondern ein kleines verteiltes System. Mir war wichtig, API und PDF-Service voneinander getrennt zu halten. Die API betrachte ich als reine Zugriffsschicht auf die Datenbank, der PDF-Service ist davon komplett unabhängig und ließ sich daher gut abkapseln. Hier ist die ganze Landkarte auf einen Blick — jede Schicht, von der Oberfläche, in der ich Rechnungen anlege, bis runter zum Server, auf dem alles läuft.
Das Interface
Die Oberfläche, in der ich Rechnungen anlege, Kunden verwalte und fertige PDFs herunterlade. Für die Umsetzung habe ich auf ein fertiges Template von nuxt/ui gesetzt, um das Rad nicht neu zu erfinden und ein solides Design zu haben.
Der Datenzugriff
Symfony war ein echter Game Changer. Sobald ich das Datenmodell über Doctrine abgebildet hatte, hat mir API Platform daraus alle grundlegenden CRUD-Operationen generiert. Auch um Authentifizierung oder die Validierung eingehender Requests muss man sich nicht selbst kümmern, das bringt Symfony von Haus aus mit. Die Entwicklung war dadurch sehr reibungsarm.
Das Datenmodell
Ein sauber normalisiertes Schema, über Doctrine abgebildet. In der ersten Version von invoi.app habe ich auf MongoDB gesetzt. Mit der Zeit wurde mir aber klar, dass sich für dieses Datenmodell eine relationale Datenbank besser eignet.
Der PDF-Dienst
Ein eigener kleiner Service mit nur einer Aufgabe: aus Rechnungsdaten ein sauberes PDF rendern. Die Entwicklung mit Hono war reibungslos und erfrischend.
Das Fundament
aktueller FokusContainer, CI/CD und Monitoring. Alles auf meinem eigenen Homelab statt in fremder Cloud. Das ist der Bereich, in dem ich aktuell am liebsten unterwegs bin.
Relational und normalisiert
Wie in der Architekturübersicht bereits erwähnt, bot es sich an, dieses Datenmodell relational umzusetzen. Besonders die Beziehung zwischen User und Organization lässt sich optimal über eine Verbindungstabelle abbilden. Über die Fremdschlüssel kann ich im Frontend gezielt filtern, etwa Rechnungen nach Kunde oder Organisation.
Enough said, show me some screens
In Zukunft werde ich eine Live-Demo zur Verfügung stellen. Für den Moment, müssen Screenshots ausreichen.


Wie eine Rechnung entsteht
Ein Rechnungs-PDF wird immer dann generiert, wenn im Frontend eine neue Rechnung angelegt wird.
Das Frontend schickt die Rechnung an die API. Die speichert sie in Postgres und fragt beim PDF-Dienst ein Dokument an. Der rendert aus einem Handlebars-Template mit Playwright ein PDF und legt es in MinIO ab. Zurück kommt eine Download-URL, die nur eine Weile gültig ist.
Vom Code zum Betrieb
Eine App zu schreiben ist die eine Hälfte. Sie so zu betreiben, dass ich ihr vertraue, ist die andere — und da lerne ich gerade am meisten.
Ehrlich gesagt war der Betrieb lange Murks. Secrets lagen im Image, die Container liefen als root, die Logs waren über drei Dienste verstreut (allein im Frontend über 70 Stück). Solange nur ich die App nutze, geht das. Aber ordentlich ist anders. Das räume ich gerade Schritt für Schritt auf — und aus jedem Schritt wird ein kleines Stück, das ich zeigen kann.
Durchgezogen läuft schon · gestrichelt ist geplant.

