nullInvoice ist ein Spring Boot Mikroservice für automatisierte Rechnungserstellung und -verwaltung mit vollständig anpassbaren HTML-Vorlagen, entwickelt zur Integration in Webshops und SaaS-Plattformen.
Unternehmen nutzen nullInvoice für die Rechnungserstellung, nachdem Verkäufe abgeschlossen sind. Lieferanten werden einmalig über die Web-UI konfiguriert, danach ruft Ihre Anwendung die REST API auf, um konforme Rechnungen bei Bedarf zu erstellen.
So funktioniert es:
- Setup: Konfigurieren Sie Lieferanten in der UI mit Firmendaten, Locale, Währung, Steuersätzen, individuellem Branding und Rechnungsvorlagen
- Authentifizierung: Generieren Sie API-Schlüssel im Admin-Dashboard für sicheren REST-API-Zugriff
- Integration: Ihr Webshop/SaaS sendet authentifizierte API-Anfragen an
/api/v1/invoices/generateunter Verwendung der Lieferanten-ID - Erstellung: Rechnungen werden aus vollständig anpassbaren HTML-Vorlagen erstellt und als JSON oder PDF mit Metadaten-Headern zurückgegeben
- Zustellung: Ihre Anwendung erhält die Rechnung und kann sie an Kunden weiterleiten oder für die Ablage speichern
┌─────────────────┐
│ Kunde │
│ schließt │
│ Kauf ab │
└────────┬────────┘
│
▼
┌─────────────────────────────────────────┐
│ Ihr Webshop/SaaS-Plattform │
│ ───────────────────────────────────── │
│ 1. Zahlung verarbeiten │
│ 2. Digitale Quittung ausstellen │
│ (erforderlich) │
│ 3. Kunde fordert Rechnung? ─────────┐ │
└──────────────────────────────────────┼──┘
│
│ API-Aufruf
▼
┌──────────────────────────────┐
│ nullInvoice-Service │
│ ────────────────────────── │
│ POST /api/v1/invoices/ │
│ generate │
│ │
│ - Prüft Lieferanten-ID │
│ - Wendet Vorlage an │
│ - Speichert HTML-Snapshot │
│ - Generiert PDF │
│ - Gibt Rechnung zurück │
└──────────────┬───────────────┘
│
│ Antwort (JSON oder PDF)
▼
┌──────────────────────────────────────────┐
│ Ihr Webshop/SaaS-Plattform │
│ ────────────────────────────────────── │
│ - Empfängt JSON-Metadaten ODER PDF-Datei│
│ - Speichert Rechnungsnummer für Ablage │
│ - Sendet PDF per E-Mail an den Kunden │
└──────────────────────────────────────────┘
Vollständig anpassbare Vorlagen
- Rechnungen basieren auf benutzerdefinierten HTML-Vorlagen mit Inline-CSS
- Vorlagen unterstützen 30+ Platzhalter für Lieferanten-, Kunden- und Finanzdaten
- Standardvorlagen pro Lieferant ermöglichen unterschiedliches Branding je Geschäftseinheit
Unveränderlichkeit von Dokumenten
- Jede Rechnung speichert einen Snapshot der geparsten HTML-Vorlage zum Zeitpunkt der Erstellung
- Vorlagenänderungen beeinflussen bereits erstellte Rechnungen nicht
- Rechnungen können konsistent aus dem gespeicherten Snapshot neu erstellt werden
- Datenbankberechtigungen verhindern das Löschen von Rechnungsdatensätzen (finanzielle Compliance)
Multi-Tenant-fähig
- Konfigurieren Sie mehrere Lieferanten mit unabhängigen Einstellungen (Locale, Währung, Nummerierung, Branding)
- API-Aufrufer geben die Lieferanten-ID an, um Rechnungen unter verschiedenen Geschäftseinheiten zu erstellen
Flexible Bereitstellung
- Rückgabe von Rechnungsmetadaten als JSON für die Ablage (
response_type: number) - PDF direkt mit Metadaten in den Headern für sofortige Zustellung (
response_type: pdf) - PDF später abrufen über
/api/v1/invoices/{invoiceNumber}/pdf
Asynchrone Generierungs-Warteschlange
- Alternativer Pfad für Integrationen, die nicht synchron auf die Generierung warten möchten
- Die Anfrage wird in eine Warteschlange geschrieben, ein Hintergrund-Worker erzeugt die Rechnung, Clients fragen den Status per Polling ab
- Gleiche Nummerierungs-Garantien wie der synchrone Pfad (gemeinsame Lieferanten-Sperre)
- Der Worker lässt sich über
QUEUE_ENABLED=falsedeaktivieren (Standardtrue)
OpenAPI-Dokumentation
- Interaktive API-Dokumentation unter
/swagger - OpenAPI-JSON-Spezifikation unter
/openapi - Vollständige Request/Response-Beispiele und Try-it-out-Funktionalität
nullInvoice enthält integrierte Authentifizierung (sitzungsbasiertes UI-Login + API-Schlüssel-Authentifizierung für REST-Endpunkte). Dies bietet standardmäßig Sicherheit, ist jedoch weiterhin für den Einsatz in internen/privaten Netzwerken gedacht.
Empfohlene Bereitstellung:
- Hinter einer Firewall oder einem VPN
- In einem privaten Netzwerk, das nur für Ihre vertrauenswürdigen Anwendungen erreichbar ist
- Mit aktiviertem HTTPS/TLS für alle Verbindungen
- Hinter einem Reverse Proxy mit konfiguriertem Rate Limiting
Für den Produktivbetrieb sind zusätzliche Sicherheitsmaßnahmen erforderlich:
- HTTPS/TLS aktivieren
- Rate Limiting auf Reverse-Proxy-Ebene konfigurieren
- Starke Admin-Passwörter verwenden
- API-Schlüssel regelmäßig rotieren
- API-Schlüssel in sicherem Secret Management speichern (HashiCorp Vault, AWS Secrets Manager usw.)
Siehe Abschnitt Sicherheit & Best Practices für eine vollständige Checkliste.
nullInvoice ist eine Pipeline zur Rechnungserstellung, die Rechnungsdokumente erstellt, speichert und bereitstellt. Es:
- Verfolgt keine Zahlungen oder Zahlungsstatus über einfache "unbezahlt/ausgestellt"-Flags hinaus
- Verwaltet keine Forderungen oder Verbindlichkeiten
- Erstellt keine Finanzberichte oder Bilanzen
- Integriert sich nicht in Buchhaltungssysteme (Hauptbücher, Journale usw.)
- Übernimmt keine Buchhaltung, Abstimmung oder Steuererklärungen
Für umfassendes Finanzmanagement integrieren Sie nullInvoice mit einem dedizierten Buchhaltungssystem. Nutzen Sie diesen Dienst zur Rechnungserstellung und importieren Sie die Rechnungen anschließend in Ihre Buchhaltungssoftware für Nachverfolgung und Compliance.
- Java 21, Spring Boot 3.5.3
- MariaDB + JPA
- Thymeleaf (UI)
- OpenHTMLToPDF (PDFBox)
- OpenAPI unter
/openapi, Swagger UI unter/swagger
Für Docker-Bereitstellung (empfohlen):
- Docker
- Docker Compose
Für lokale Entwicklung:
- Java 21 (JDK - Eclipse Temurin oder OpenJDK)
- Maven 3.9+
- MariaDB 10.5+ (oder MySQL 8.0+)
- Tailwind CSS Standalone-Binary (für den CSS-Build - von GitHub releases)
Datenbank erstellen:
CREATE DATABASE nullinvoice CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Dedizierten Anwendungsnutzer mit eingeschränkten Rechten erstellen:
CREATE USER 'nullinvoice'@'localhost' IDENTIFIED BY 'your_secure_password';
-- Berechtigungen für normale Operationen und Schema-Migrationen
GRANT SELECT, INSERT, UPDATE ON nullinvoice.* TO 'nullinvoice'@'localhost';
GRANT CREATE, ALTER, INDEX, REFERENCES ON nullinvoice.* TO 'nullinvoice'@'localhost';
FLUSH PRIVILEGES;Für Remote-Zugriff den Host anpassen:
CREATE USER 'nullinvoice'@'%' IDENTIFIED BY 'your_secure_password';
GRANT SELECT, INSERT, UPDATE ON nullinvoice.* TO 'nullinvoice'@'%';
GRANT CREATE, ALTER, INDEX, REFERENCES ON nullinvoice.* TO 'nullinvoice'@'%';
FLUSH PRIVILEGES;Wichtig: Warum diese eingeschränkten Rechte?
Rechnungen sind unveränderliche Finanzdokumente und dürfen nach dem Erstellen niemals gelöscht werden. Der Anwendungsnutzer ist bewusst eingeschränkt und darf nicht:
DELETE- kann keine Datensätze löschenDROP- kann keine Tabellen oder Datenbank löschenTRUNCATE- kann keine Tabellen leerenGRANT- kann keine Berechtigungen vergeben
Das stellt Datenintegrität und Compliance mit Anforderungen zur Finanzarchivierung sicher. Das UPDATE-Recht wird für Statusänderungen (z. B. als bezahlt markieren) und Soft Deletes für Parteien-Datensätze benötigt.
- Das Datenbankschema wird durch Flyway-Migrationen verwaltet
- Initiales Schema:
nullInvoice/src/main/resources/db/migration/V1__initial_schema.sql - Das Schema wird beim Start automatisch erstellt/aktualisiert
- Hibernate DDL-Modus ist auf
nonegesetzt (Flyway verwaltet alle Schemaänderungen)
Eine Beispiel-Konfigurationsdatei liegt unter .env.example. Kopieren Sie diese nach .env und passen Sie die Werte an Ihre Umgebung an.
Umgebungsvariablen (Standardwerte in Klammern):
TZ- ERFORDERLICH System-Zeitzone (Europe/Sofia)APP_PORT(8080)DB_HOST(localhost)DB_PORT(3306)DB_USER(nullinvoice)DB_PASSWORD(leer)DB_NAME(nullinvoice)DB_PARAMS- ERFORDERLICH JDBC-Parameter, die an die Verbindungs-URL angehängt werden
Sie MÜSSEN die Zeitzone an ZWEI Stellen setzen:
TZUmgebungsvariable - setzt die System-/AnwendungszeitzoneserverTimezoneParameter inDB_PARAMS- setzt die Zeitzone der Datenbankverbindung
Beide Werte MÜSSEN mit der Zeitzone des Datenbankservers übereinstimmen, damit Datums-/Zeitwerte korrekt interpretiert und gespeichert werden.
Beispielkonfiguration:
TZ=Europe/Sofia
DB_PARAMS=?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Europe/SofiaHäufige Zeitzonenwerte: UTC, Europe/London, America/New_York, Asia/Tokyo. Siehe vollständige Liste.
Nicht übereinstimmende Zeitzonen führen zu falschen Rechnungsdaten und Zeitstempeln.
Beim ersten Start wird die Anwendung auf /setup umleiten, um das initiale Admin-Konto zu erstellen. Dies ist erforderlich, bevor andere Funktionen genutzt werden können.
Zurücksetzen und neues Admin-Konto erstellen (Notfall):
- Anwendung stoppen
- Tabellen
usersundapi_keysin der Datenbank leeren - Anwendung neu starten
- Den
/setup-Flow erneut abschließen
Sicherheitsempfehlungen:
- Starke Passwörter für das Admin-Konto verwenden
- Passwort-Hinweis setzen (optional, aber empfohlen)
- Separate API-Schlüssel für unterschiedliche Umgebungen generieren (dev, staging, prod)
- Nicht verwendete API-Schlüssel widerrufen
Authentifizierungsarchitektur:
- UI-Zugriff: Sitzungsbasierte Authentifizierung mit Form-Login
- API-Zugriff: Stateless Bearer-Token-Authentifizierung (API-Schlüssel)
- Passwörter: BCrypt-Hash mit 10 Runden
- API-Schlüssel: UUID-Format, BCrypt-gehasht, werden nur einmal angezeigt
Sitzungsdauer:
Standardmäßig laufen UI-Sitzungen nach 30 Minuten Inaktivität ab (Spring Boot/Tomcat Standard). Benutzer werden automatisch abgemeldet und zur Anmeldeseite weitergeleitet.
Um die Sitzungsdauer anzupassen, fügen Sie Folgendes zu nullInvoice/src/main/resources/application.yml hinzu:
server:
servlet:
session:
timeout: 60m # Optionen: 15m, 30m, 1h, 2h, usw.Gängige Timeout-Werte:
15m- 15 Minuten (strengere Sicherheit)30m- 30 Minuten (Standard)1h- 1 Stunde (Komfort für aktive Benutzer)8h- 8 Stunden (erweitert für lange Sitzungen)
Checkliste für den Produktivbetrieb:
- HTTPS/TLS für alle Verbindungen aktivieren
- Starke Admin-Passwörter verwenden
- Separate API-Schlüssel pro Anwendung/Umgebung erstellen
- Hinter Firewall oder VPN betreiben
- Rate Limiting auf Reverse-Proxy-Ebene konfigurieren
- Logging und Monitoring einrichten
- API-Schlüssel-Nutzung regelmäßig prüfen (Zeitstempel der letzten Nutzung)
- Nicht verwendete oder kompromittierte API-Schlüssel sofort widerrufen
- API-Schlüssel in Umgebungsvariablen halten, niemals im Code
- Sicheres Secret Management verwenden (HashiCorp Vault, AWS Secrets Manager usw.)
CSRF-Schutz:
- Aktiviert für alle UI-Formulare
- Deaktiviert für API-Endpunkte (stateless Bearer-Token-Auth)
Sicherheit beim ersten Start:
- Die Anwendung ist unbenutzbar, bis ein Admin-Konto über
/setuperstellt wurde - Die Setup-Seite ist nur erreichbar, wenn noch kein Admin existiert
- Nach dem Setup ist Login für alle Funktionen erforderlich
Offizielle Docker-Images: Vorgefertigte Images sind auf Docker Hub verfügbar. Suchen Sie nach dem offiziellen nullInvoice-Image, um den Build-Schritt zu überspringen.
Build ohne Cache:
docker compose build --no-cacheStack starten:
docker compose up -dStack stoppen:
docker compose down-
Stellen Sie sicher, dass eine MariaDB-Instanz läuft und erstellen Sie die Datenbank. Siehe Datenbank einrichten
-
Tailwind CSS bauen (vor dem ersten Start erforderlich):
./build-tailwind.sh
-
Projekt mit Maven bauen:
cd nullInvoice mvn clean package -
Anwendung starten:
java -jar target/nullinvoice-0.0.1-SNAPSHOT.jar
Das Projekt wurde mit NetBeans erstellt und kann als Maven-Projekt mit dem Spring-Boot-Plugin geöffnet werden.
Umgebungsvariablen in NetBeans setzen:
Option 1 - Über die IDE:
- Rechtsklick auf das Projekt >> Properties
- Zu Actions >> Run navigieren
- Umgebungsvariablen setzen:
APP_PORT,DB_NAME,DB_USER,DB_PASSWORD
Option 2 - Direkt bearbeiten:
nbactions.xmlim Projekt-Root anpassen
Beim ersten Zugriff werden Sie zu /setup weitergeleitet, um das initiale Admin-Konto zu erstellen:
http://localhost:8080öffnen (oder Ihre konfigurierte URL)- Sie werden automatisch zu
/setupweitergeleitet - Admin-Konto mit Benutzername, Passwort und optionalem Passwort-Hinweis erstellen
- Nach dem Setup werden Sie zu
/loginweitergeleitet
Anmeldung:
- Anmeldeseite unter
/loginaufrufen - Die erstellten Admin-Zugangsdaten verwenden
- Passwort-Hinweis ist über das Info-Icon verfügbar (falls konfiguriert)
Admin-Dashboard: Nach der Anmeldung finden Sie das Admin-Dashboard im Benutzermenü:
- Admin-Passwort ändern
- API-Schlüssel für REST-API-Zugriff generieren
- API-Schlüssel widerrufen
- API-Schlüssel-Nutzung anzeigen (Zeitstempel der letzten Nutzung)
Voraussetzungen:
- Ersteinrichtung abgeschlossen (Admin-Konto erstellt)
- Mit Admin-Zugangsdaten angemeldet
Bevor Sie Rechnungen über die API erstellen können, müssen Sie mindestens einen Lieferanten über die Web-UI konfigurieren. Lieferanten definieren Firmendaten, Locale, Währung, Steuersätze, individuelles Branding (über Vorlagen) und die Rechnungsnummerierung für die Rechnungserstellung.
-
In die Web-UI unter
http://localhost:8080einloggen (oder Ihren konfigurierten Port) -
Zu Lieferanten navigieren
-
Neuen Lieferanten mit Firmendaten erstellen
-
Locale, Währung und Steuereinstellungen konfigurieren
-
Einstellungen für die Rechnungsnummerierung setzen (Präfix, Stellen)
-
Lieferanten-ID für die API-Integration notieren
-
API-Schlüssel unter Admin > API-Schlüssel für REST-API-Zugriff generieren
Beispiele für die Lieferanteneinrichtung finden Sie unter docs/example-images - en-us für ein US- oder Nicht-EU-Beispiel und eu-de für ein EU-Beispiel.
Nach der Konfiguration können Sie eine XHTML-Vorlage einrichten und die Lieferanten-ID (oben links in der Lieferantenbearbeitung) verwenden, um API-Aufrufe an /api/v1/invoices/generate zu senden.
- Lieferanten und Kunden mit Soft Delete und Eindeutigkeitsprüfungen verwalten.
- Rechnungsvorlagen mit individuellem Branding erstellen und verwalten, mit globalem Standard und Lieferanten-Standard.
- Rechnungen erstellen, wobei HTML-Snapshots im Rechnungseintrag gespeichert werden.
- Rechnungen bei Bedarf als PDF rendern.
- Rechnungen nach Nummer, Datum, Kunde, Lieferant und Status suchen und sortieren.
- Rechnungsstatus als
unpaidoderissued(bezahlt/endgültig) verwalten.
- Statuswerte sind
unpaidundissued.issuedgilt als bezahlt und endgültig. - Die Erstellung einer Rechnung über die API führt immer zu
issued, und die API akzeptiert keine Status-Overrides. - Die Erstellung über die UI kann eine Rechnung nur dann als
unpaidmarkieren, wenn ein Fälligkeitsdatum gesetzt ist. - Unbezahlte Rechnungen können auf der Rechnungsdetailseite als
issuedmarkiert werden. - Ausgestellte Rechnungen können nicht wieder auf unbezahlt zurückgesetzt werden.
/invoices/newerstellt Rechnungen mit dem im Cookie ausgewählten Lieferanten (falls vorhanden).- Der Schalter für
unpaidist deaktiviert, bis ein Fälligkeitsdatum gesetzt ist. /invoicesunterstützt Filterung nach Lieferant (Dropdown) und Suche nach Nummer, Datum oder Kunde. Die Datumssuche akzeptiert ISO (YYYY-MM-DD) oderdd.MM.yyyy.- Die Rechnungsliste kann nach Status sortiert werden; die Sortierung nach Status wechselt die Reihenfolge von
unpaidundissued. /invoices/{invoiceNumber}zeigt Status, Summen, gespeicherte HTML-Vorschau und bietet eine Einweg-Aktion „Als bezahlt markieren“ für unbezahlte Rechnungen.
- Lieferanten: Zuerst Lieferantendaten einrichten. Das Lieferantenprofil bestimmt Locale, Währung, Rechnungsnummerierung und Standardsteuersatz.
- Vorlagen: Vorlage für individuelles Branding erstellen und als Standard festlegen. Globalen Standard verwenden oder einen Lieferanten-Standard setzen, um den globalen Standard zu überschreiben.
- Kunden (optional): Kunden können manuell hinzugefügt werden, aber die Rechnungserstellung legt Kunden auch automatisch an/aktualisiert sie.
- Aktiven Lieferanten auswählen: Standardlieferant in der UI auswählen, wodurch ein Cookie gesetzt wird, der bei der Rechnungserstellung verwendet wird.
- Lieferanten-ID für die API: Lieferanten im Bearbeitungsmodus öffnen und die Lieferanten-ID oben links verwenden.
- Rechnungen: Rechnungen auflisten, suchen und filtern; Rechnung öffnen, um Details zu prüfen und unbezahlte Rechnungen als ausgestellt/bezahlt zu markieren.
- Rechnung erstellen: Kundendaten eingeben oder einen vorhandenen Kunden suchen, Positionen hinzufügen und den Steuersatz pro Position setzen. Fehlt bei einer Position der Steuersatz, gilt der Standardsteuersatz des Lieferanten.
- Rabatte und Notizen: Einen pauschalen Rabatt eingeben oder den Rabatt-%-Rechner verwenden; Notizen hinzufügen und die Rechnung erstellen, um die Übersichtsseite zu sehen.
Die Rechnungserstellung verwendet eine pessimistische Schreibsperre auf dem Lieferanten-Datensatz, um Race Conditions bei der Berechnung der nächsten Rechnungsnummer zu vermeiden. Dies blockiert konkurrierende Anfragen für denselben Lieferanten, bis die Nummer vergeben ist.
Authentifizierung erforderlich: Alle API-Endpunkte erfordern entweder:
- Bearer-Token im
Authorization-Header (empfohlen für Integrationen) - Aktive Sitzung (wenn Sie über die Web-UI eingeloggt sind)
Generieren Sie einen API-Schlüssel im Admin-Dashboard und fügen Sie ihn in den Authorization-Header ein:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoicesWenn Sie über die Web-UI eingeloggt sind, wird Ihre Sitzung automatisch für API-Anfragen genutzt.
API-Schlüssel generieren:
- In die Web-UI einloggen
- Zu Admin (Benutzermenü) navigieren
- Zum Abschnitt "API-Schlüssel" scrollen
- Optional eine Beschreibung eingeben und auf „Schlüssel generieren“ klicken
- Schlüssel sofort kopieren - er wird nicht erneut angezeigt
- Der Schlüssel wird im Format
Authorization: Bearer {key}angezeigt
Sicherheitshinweise:
- API-Schlüssel sind in der Datenbank gehasht (BCrypt)
- Schlüssel können jederzeit im Admin-Dashboard widerrufen werden
- Zeitstempel der letzten Nutzung wird pro Schlüssel erfasst
- Separate Schlüssel für verschiedene Anwendungen/Umgebungen generieren
POST /api/v1/invoices/generate
Authentifizierung erforderlich - Bearer-Token im Authorization-Header angeben.
- Erfordert
supplier_idundclient. response_typeunterstütztnumber(Standard) oderpdf.number: gibt JSON nur mit Rechnungsmetadaten zurückpdf: liefert das PDF direkt mit Metadaten in den Response-Headern
- Status ist immer
issuedfür API-erstellte Rechnungen.
Beispielanfrage (bestehender Kunde per ID):
curl -X POST http://localhost:8080/api/v1/invoices/generate \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"response_type": "number",
"supplier_id": 1,
"client": { "id": 42 },
"items": [
{ "description": "Consulting", "quantity": 1, "unit_price": 1000, "tax_rate": 0.2 }
],
"issue_date": "2026-01-16",
"due_date": "2026-01-30",
"currency_code": "EUR",
"notes": "Thank you"
}'Beispielanfrage (neue Kundendaten):
curl -X POST http://localhost:8080/api/v1/invoices/generate \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"response_type": "number",
"supplier_id": 1,
"client": {
"name": "Client Co",
"addressLine1": "2 Side St",
"city": "Burgas",
"country": "BG",
"taxId": "123",
"vatId": "BG123"
},
"items": [
{ "description": "Consulting", "quantity": 1, "unit_price": 1000, "tax_rate": 0.2 }
]
}'Beispielantwort (response_type: number):
{
"status": "issued",
"message": "invoice generated",
"invoiceNumber": "INV-000001",
"issueDate": "2026-01-16"
}Beispielanfrage (response_type: pdf für direkten PDF-Download):
curl -X POST http://localhost:8080/api/v1/invoices/generate \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"response_type": "pdf",
"supplier_id": 1,
"client": {
"name": "Client Co",
"addressLine1": "2 Side St",
"city": "Plovdiv",
"country": "BG",
"taxId": "123",
"vatId": "BG123"
},
"items": [
{ "description": "Consulting", "quantity": 1, "unit_price": 1000, "tax_rate": 0.2 }
]
}' \
-o invoice.pdf -iBeispielantwort (response_type: pdf):
HTTP/1.1 200 OK
Content-Type: application/pdf
Content-Disposition: attachment; filename="INV-000001.pdf"
X-Invoice-Number: INV-000001
X-Invoice-Status: issued
X-Invoice-Issue-Date: 2026-01-16
[PDF binary data]
Die PDF-Antwort enthält Rechnungsmetadaten in benutzerdefinierten Response-Headern (X-Invoice-Number, X-Invoice-Status, X-Invoice-Issue-Date), sodass Ihre Anwendung die Rechnungsdetails speichern kann, während sie die PDF-Datei direkt erhält.
GET /api/v1/invoices
Authentifizierung erforderlich - Bearer-Token im Authorization-Header angeben.
- Optionaler Filter:
status=unpaidoderstatus=issued
Beispielanfrage:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoices?status=unpaidBeispielantwort (gefiltert):
[
{ "invoiceNumber": "INV-000002", "status": "unpaid" }
]Authentifizierung erforderlich - Bearer-Token im Authorization-Header angeben.
Rechnungsmetadaten abrufen:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoices/INV-000001Rechnung als PDF herunterladen:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoices/INV-000001/pdf \
-o invoice.pdfAlternative zu POST /api/v1/invoices/generate für Aufrufer, die nicht synchron auf die Generierung warten möchten. Die Anfrage wird in einer Warteschlange persistiert, ein Hintergrund-Worker erzeugt die Rechnung, und Clients fragen den Status per Polling ab.
Beide Pfade durchlaufen dieselbe Lieferanten-Zeilensperre, sodass Rechnungsnummern über den synchronen und asynchronen Pfad hinweg fortlaufend bleiben.
POST /api/v1/invoice-requests
Authentifizierung erforderlich - Bearer-Token im Authorization-Header angeben.
Der Request-Body ist identisch mit POST /api/v1/invoices/generate. Das Feld response_type wird ignoriert - asynchrone Anfragen persistieren nur die Warteschlangenzeile; nach Abschluss wird die Rechnung über die Standard-Abrufendpunkte mit der invoiceNumber aus der Statusantwort geladen.
curl -X POST http://localhost:8080/api/v1/invoice-requests \
-H "Authorization: Bearer YOUR_API_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{
"supplier_id": 1,
"client": { "id": 42 },
"items": [
{ "description": "Consulting", "quantity": 1, "unit_price": 1000, "tax_rate": 0.2 }
]
}'Antwort (201 Created):
{
"requestId": 42,
"status": "PENDING",
"message": "invoice generation request queued",
"createdAt": "2026-05-17T10:00:00"
}GET /api/v1/invoice-requests/{requestId}
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/invoice-requests/42Antwort bei COMPLETED:
{
"requestId": 42,
"status": "COMPLETED",
"invoiceId": 107,
"invoiceNumber": "INV-000042",
"attempts": 1,
"createdAt": "2026-05-17T10:00:00",
"completedAt": "2026-05-17T10:00:02"
}neue Anfrage -> PENDING
Worker erfolgreich -> COMPLETED
Worker wirft Fehler -> PENDING (wird erneut versucht)
attempts >= max_attempts -> FAILED (terminal)
PENDING ist der einzige wiederholbare Status. Abstürze während der Verarbeitung werden vollständig zurückgerollt und zählen nicht zum Wiederholungsbudget. Nach COMPLETED die Rechnung über GET /api/v1/invoices/{invoiceNumber} (JSON) oder /api/v1/invoices/{invoiceNumber}/pdf (PDF) abrufen.
Der Worker lässt sich über die Umgebungsvariable QUEUE_ENABLED=false deaktivieren.
Authentifizierung erforderlich - Bearer-Token im Authorization-Header angeben.
GET /api/v1/parties/client?taxId=...&vatId=...(erfordert taxId oder vatId)GET /api/v1/parties/clients/search?q=...(mindestens 2 Zeichen)GET /api/v1/parties/suppliers
Beispiel:
curl -H "Authorization: Bearer YOUR_API_KEY_HERE" \
http://localhost:8080/api/v1/parties/suppliersGET /api/v1/health(keine Authentifizierung erforderlich)
- Vorlagen befinden sich in
invoice_templatesund müssen HTML-Inhalt enthalten. - Die Rechnungserstellung erfordert eine wirksame Standardvorlage (lieferantenspezifisch oder global).
- Lieferanten können den globalen Standard mit einer lieferantenspezifischen Vorlage überschreiben.
- Erstellte Rechnungen speichern einen HTML-Snapshot für konsistentes Re-Rendering.
- PDFs werden aus dem gespeicherten HTML-Snapshot gerendert, sofern vorhanden.
Vorlagen müssen im XHTML-Format vorliegen, damit PDFs korrekt gerendert werden:
- XML-Deklaration hinzufügen:
<?xml version="1.0" encoding="UTF-8"?> - XHTML-Namespace verwenden:
<html xmlns="http://www.w3.org/1999/xhtml"> - Sämtliches CSS muss inline in einem
<style>-Tag im<head>stehen - Externe Stylesheets werden für die PDF-Erstellung nicht unterstützt
Beispielvorlagen sind im Verzeichnis templates/ in 6 Sprachen verfügbar (EN, BG, IT, ES, DE, RU).
Vorlagen verwenden {{placeholder}}-Variablen. Wenn ein Platzhalter in der Vorlage fehlt, werden diese Daten in der finalen Rechnung nicht gerendert. Der Dienst validiert nicht, welche Platzhalter vorhanden oder fehlend sind.
Unterstützte Platzhalter:
{{invoiceNumber}}{{issueDate}}{{dueDateRow}}(komplette<div>-Zeile oder leer){{supplierName}}{{supplierAddressLine1}}{{supplierAddressLine2Row}}(komplette<div>-Zeile oder leer){{supplierCityRegionPostal}}{{supplierCountry}}{{supplierTaxIdRow}}(komplette<div>-Zeile oder leer){{supplierVatIdRow}}(komplette<div>-Zeile oder leer){{supplierEmailRow}}(komplette<div>-Zeile oder leer){{supplierPhoneRow}}(komplette<div>-Zeile oder leer){{clientName}}{{clientAddressLine1}}{{clientAddressLine2Row}}(komplette<div>-Zeile oder leer){{clientCityRegionPostal}}{{clientCountry}}{{clientTaxIdRow}}(komplette<div>-Zeile oder leer){{clientVatIdRow}}(komplette<div>-Zeile oder leer){{clientEmailRow}}(komplette<div>-Zeile oder leer){{clientPhoneRow}}(komplette<div>-Zeile oder leer){{itemsRows}}(gerenderte<tr>-Zeilen){{subtotal}}{{discountTotal}}{{taxTotal}}{{total}}{{notesSection}}(kompletter<div>-Abschnitt oder leer)
PDFs werden mit OpenHTMLToPDF gerendert. Die Anwendung bündelt die Schriftfamilie DejaVu, die Latein, Kyrillisch, Griechisch und andere Unicode-Zeichen unterstützt.
Verwendung der gebündelten Schriften:
body {
font-family: "DejaVu Sans", sans-serif;
}Verwendung benutzerdefinierter Webfonts:
Vorlagen können externe Fonts über @font-face im Inline-<style>-Abschnitt laden. Stellen Sie sicher, dass der Webfont Ihre Sprache unterstützt (z. B. Kyrillisch für Russisch/Bulgarisch, Griechisch usw.). Gebündelte DejaVu-Schriften dienen als Fallback, falls der Webfont nicht geladen werden kann.
@font-face {
font-family: 'Roboto';
font-style: normal;
font-weight: 400;
src: url('https://fonts.gstatic.com/s/roboto/v30/KFOmCnqEu92Fr1Me5WZLCzYlKw.ttf') format('truetype');
}
body {
font-family: 'Roboto', 'DejaVu Sans', sans-serif;
}Verfügbare gebündelte Schriften:
| Font Family | Weights | Styles |
|---|---|---|
DejaVu Sans |
200 (extra-light), 400 (normal), 700 (bold) | normal, oblique |
DejaVu Sans Condensed |
400 (normal), 700 (bold) | normal, oblique |
DejaVu Sans Mono |
400 (normal), 700 (bold) | normal, oblique |
DejaVu Serif |
400 (normal), 700 (bold) | normal, italic |
DejaVu Serif Condensed |
400 (normal), 700 (bold) | normal, italic |
- Lieferanten und Kunden teilen sich die Tabelle
partiesund werden überroleunterschieden. - Soft Delete blendet Parteien aus Listen aus, während die Rechnungshistorie erhalten bleibt.
- Lieferanteneinstellungen können Locale, Währung, Datumsformat, Rechnungspräfix und Stellenzahl überschreiben.
- Der Lieferantenwert
default_tax_ratewird auf Positionen ohne Steuersatz angewendet.
- Rechnungsnummern sind lieferantenspezifisch und verwenden
max(invoice_number_int) + 1. - Optionales Präfix und Stellenzahl werden aus den Lieferanteneinstellungen angewendet.
- Währungscodes werden gegen ISO 4217 validiert.
Ein Skript ist enthalten, um die API zur Rechnungserstellung mit parallelen Anfragen zu belasten.
Verwendung:
API_KEY=your_api_key ./integration-tests/gen-test.sh [SUPPLIER_ID] [COUNT] [BASE_URL]Oder den API-Schlüssel als 4. Argument übergeben:
./integration-tests/gen-test.sh [SUPPLIER_ID] [COUNT] [BASE_URL] [API_KEY]Parameter:
SUPPLIER_ID- Lieferanten-ID für Testrechnungen (Standard: 1)COUNT- Anzahl paralleler Anfragen für die Rechnungserstellung (Standard: 20)BASE_URL- Basis-URL der Anwendung (Standard: http://localhost:8080)API_KEY- Ihr API-Schlüssel (erforderlich, kann als Umgebungsvariable gesetzt werden)
Beispiel:
API_KEY=abc123-your-key ./integration-tests/gen-test.sh 1 50 http://localhost:8080Dies sendet parallele Anfragen zur Rechnungserstellung, um die pessimistische Sperre und die Gesamtleistung der API unter Last zu testen.
Die UI verwendet Tailwind CSS, das bei Änderungen am CSS neu gebaut werden muss.
-
Tailwind CSS Standalone-Binary von GitHub releases herunterladen
-
Binary in das Verzeichnis
twbin/legen (z. B.twbin/tailwindcss-linux-x64) -
Build-Skript ausführen:
./build-tailwind.sh
Dies baut nullInvoice/src/main/resources/static/css/tailwind.css aus der Quelldatei tailwind-src.css.
Für schnelle Entwicklung ohne Rebuild kommentieren Sie das CDN-Skript in nullInvoice/src/main/resources/templates/fragments/head.html aus:
<script src="https://cdn.tailwindcss.com"></script>Denken Sie daran, Tailwind CSS vor dem Produktiv-Deployment neu zu bauen.
nullInvoice/src/main/java- AnwendungscodenullInvoice/src/main/resources/templates- UI-Vorlagen (Thymeleaf)nullInvoice/src/main/resources/static- JS/CSS-AssetsnullInvoice/src/main/resources/db/migration- Flyway-Migrationentemplates/- Beispiel-Rechnungsvorlagen in 6 Sprachen (EN, BG, IT, ES, DE, RU)integration-tests/- Lasttest-Skripte für die Rechnungserstellungbuild-tailwind.sh- Hilfsskript zum Bauen von Tailwind CSStwbin/- Tailwind CSS Standalone-Binary (separat herunterladen)
Interaktive API-Dokumentation:
- OpenAPI-JSON-Spezifikation:
/openapi - Swagger UI:
/swagger
Zugriff auf Swagger UI:
- In die Web-UI einloggen
- Benutzermenü > "API Docs" klicken
- Oder direkt
/swaggeraufrufen (Login erforderlich)
Endpunkte in Swagger testen:
- Auf den "Authorize"-Button (Schlosssymbol) oben rechts klicken
- API-Schlüssel eingeben (bei Bedarf unter Admin > API-Schlüssel erzeugen)
- "Authorize" klicken
- Alle Anfragen enthalten nun automatisch den Bearer-Token
- "Try it out" verwenden, um Endpunkte interaktiv zu testen
Hinweis: Die Swagger UI erfordert Authentifizierung und ist nur für eingeloggte Admin-Nutzer verfügbar.
Unterstützte UI-Sprachen: Die Anwendung ist vollständig internationalisiert mit Message Bundles:
- Englisch (EN) ✅
- Deutsch (DE) ✅
- Bulgarisch (BG) ✅
- Spanisch (ES) ✅
- Italienisch (IT) ✅
- Russisch (RU) ✅
README-Übersetzungen: Dieses README.md ist auch verfügbar in:
Maschinelle Übersetzung bereitgestellt von Google Gemini.
Rechnungsvorlagen: Beispielvorlagen sind für alle 6 Sprachen oben enthalten (im Verzeichnis templates/)
Technische Unterstützung für weitere Sprachen: Die Anwendung kann Rechnungen in jeder Sprache mit passender Schriftunterstützung erzeugen:
- Arabisch (VAE, Saudi-Arabien usw.) - RTL-Unterstützung per CSS, benötigt Vorlagen & UI-Übersetzungen
- Ostasiatische Sprachen (Chinesisch, Japanisch, Koreanisch) - Unicode-Schriften unterstützt, benötigt Vorlagen & UI-Übersetzungen
- Hebräisch - RTL-Unterstützung per CSS, benötigt Vorlagen & UI-Übersetzungen
- Jede andere Unicode-basierte Sprache
Wir freuen uns über Beiträge zu:
- 🌍 UI-Übersetzungen (
messages_{lang}.propertiesinnullInvoice/src/main/resources/) - 📄 Beispiel-Rechnungsvorlagen für Ihre Sprache/Region (
templates/{lang}/) - 🎨 Schrift-Empfehlungen für optimales PDF-Rendering in Ihrer Sprache
- 📝 Dokumentationsverbesserungen und Übersetzungen
Die gebündelte Schriftfamilie DejaVu unterstützt umfangreiche Unicode-Abdeckung. Für Sprachen, die spezielle Schriften benötigen, verwenden Sie @font-face in Rechnungsvorlagen, um Webfonts zu laden und mit DejaVu als Fallback abzusichern.
Dieses Projekt ist unter der Elastic License 2.0 lizenziert - siehe Datei LICENSE für Details.
Copyright 2026 nullata
- Font Awesome Free:
nullInvoice/src/main/resources/static/fontawesome-free-7.1.0-web/LICENSE.txt - DejaVu Fonts:
nullInvoice/src/main/resources/fonts/LICENSE.txt