Skip to content
All projects

eRechnung Studio

A web app for small businesses to create, receive, validate and archive XRechnung and ZUGFeRD e-invoices, with official KoSIT validation, plain-language errors and a tamper-evident archive.

Type
Side project
Tech stack
  • NestJS
  • React
  • PostgreSQL
  • BullMQ
  • XRechnung
  • ZUGFeRD
Illustration of eRechnung Studio

Background

Since 1 January 2025, every business in Germany must be able to receive structured e-invoices based on the European standard EN 16931. Issuing them becomes mandatory in stages over the next few years. For a small business, that raises four practical questions: How do I create a valid XRechnung? What do I do with the XML file a supplier just sent me? Is it even valid? And how do I archive it?

eRechnung Studio handles all four in one web app, built as a multi-tenant SaaS for small and mid-sized businesses.

Writing invoices

The editor covers customers, products and the usual German tax cases: 19 % and 7 % VAT, reverse charge (§13b UStG), intra-EU supply and the small-business exemption (§19 UStG). Invoices export as XRechnung (UBL 2.1 or UN/CEFACT CII) or as ZUGFeRD, a PDF/A-3 that people can read, with the XML embedded for software.

Invoice numbers like RE-2026-00042 must not have gaps. A number is only assigned when an invoice is finalized, inside a transaction that locks the tenant's counter, so drafts never use one up. A test sends 100 parallel finalize requests and expects 100 unique, consecutive numbers. Amounts are stored in cents, with rounding per line and per VAT group following the EN 16931 calculation rules (BR-CO-*).

Receiving and checking

Incoming invoices can be uploaded as XML or ZUGFeRD PDF, or forwarded to an inbox address per tenant. The app detects the format and shows the raw XML as a readable invoice.

Validation runs through the official KoSIT validator instead of a re-implementation of hundreds of Schematron rules. Its rule IDs map to an error catalogue in German and English, and the affected field is highlighted. So this:

BR-DE-15: Buyer reference (Leitweg-ID) is missing

becomes "The customer requires a buyer reference. Add it under Customer → Invoicing."

In practice, most of the work in e-invoicing is data quality. Writing the XML is easy; getting every required field right before export is not.

Under the hood

  1. React appeditor · inbox · archive
  2. NestJS APIREST · API keys
  3. BullMQ workersgenerate · validate · parse
  4. KoSIT validatorXSD + Schematron
  5. PostgreSQL + S3RLS per tenant
The API stays fast because PDF/A-3 generation, validation and parsing run as background jobs.

Every format converts to and from one internal model based on the EN 16931 semantic model (Business Terms BT-*, Groups BG-*). A new output format means one new mapper and no changes to business logic. Round-trip tests against the official XRechnung test suite catch mapping errors that unit tests miss.

The archive follows GoBD. Finalized invoices can't be updated at the database level, so corrections become new records that reference the original. Each document gets a SHA-256 hash chained to the previous one, and an audit log records who did what and when. Tenants are separated with PostgreSQL Row-Level Security, so a forgotten WHERE clause can't expose another company's invoices.

A REST API and webhooks let online shops, ERP systems and n8n workflows create and receive e-invoices automatically.

This is a portfolio project based on published technical standards. It isn't tax or legal advice.