My day job is Finance Ops and accounting. I'm not a software engineer by training.
But in DACH, the gap between "what accountants need" and "what developers build" is real — and expensive. So I closed it myself.
Live demo (local-first, zero tracking): https://me-mateescu.de/tools/xrechnung/
The problem I kept hitting
Germany's E-Rechnungspflicht is no longer theoretical. B2G (Business-to-Government) invoicing has required a valid XRechnung for years, and B2B is rolling out in phases (reception from 2025, issuance for >€800k revenue from 2027, and broadly from 2028).
A PDF — even a perfect one — is not enough.
Every tool I found was one of three things:
- Enterprise ERP (SAP, DATEV): full XRechnung support, hundreds of euros/month, built for teams, not freelancers
- SaaS invoicing (Lexoffice, sevDesk): subscription-based, your invoice data lives on their servers, lock-in by design
-
CLI tools: open-source Java/Python libraries that assume you know what
java -jarmeans
The missing middle: a freelancer who needs to invoice the municipality of Hamburg once a quarter. A one-person consultancy that just won its first public-sector contract. A Kleinunternehmer who needs §19 UStG compliance without paying for DATEV.
That's who I built this for. Also me.
What I shipped
A browser-native XRechnung 3.0 generator. No server. No account. No data leaves your machine.
Validates against KoSIT Validator v1.6.2 (Config v3.0.2) + EN 16931.
Exports: UBL 2.1 and UN/CEFACT CII syntax.
Generates a DIN 5008-style PDF alongside the XML.
Supports Kleinunternehmer (§19 UStG), Standard VAT, and Reverse Charge (§13b UStG).
🔗 Live: https://me-mateescu.de/tools/xrechnung/
📦 Source: https://github.com/Mihai-82Adrian/portfolio-astro (MIT)
Why local-first — and how I proved it
Invoice data is high-signal: client names, project descriptions, amounts, IBANs.
Most SaaS tools solve the trust problem by asking you to trust them. This tool solves it by not touching your data at all.
Everything — XML generation, PDF rendering, pre-validation — runs in the browser.
Your seller defaults persist in localStorage. Nothing else.
The proof isn't marketing copy. It's the DevTools Network tab:
Zero outbound requests. Not "we encrypt everything" — just: nothing leaves.
How I actually built this (the honest version)
My role here is closer to architect and orchestrator than "I code all day."
I work from the compliance constraints down: read the EN 16931 spec, map the domain model in TypeScript types, define the validation rules, then specify the implementation.
Build note (full transparency): parts of the implementation were AI-assisted (Claude Code/Codex), under my architecture, with manual review and validation loops.
This workflow forced me to understand the standard deeply — because you cannot prompt your way past a KoSIT schema validation error you don't understand. When the validator rejects your XML with BT-31 cardinality violation, you need to know what BT-31 is.
The hardest part wasn't the code. It was building a typed domain model that produces both UBL 2.1 and UN/CEFACT CII output from the same Invoice object — without branching logic everywhere:
Same invoice. Two syntax outputs. The domain model is syntax-agnostic.
The deployment: zero backend, Cloudflare edge
Every push to master triggers a GitHub Actions build and deploys straight to Cloudflare Pages. No servers, no containers, no databases.
The static assets are cached at Cloudflare's edge — so latency is basically: "the file is already there."
What I'd do differently
One thing: read the full EN 16931 + CIUS context before touching any code.
I assumed XRechnung was "just XML with some German quirks." It's not. It's layered: EN 16931 Core + CIUS + KoSIT profile requirements. The URN identifiers alone took me two days to get right — and they’re a common cause of validation failures even when invoice data is correct.
Typed constants (TypeScript const values) eliminated an entire class of errors. Worth knowing upfront.
Questions for the community
If you've worked with XRechnung, EN 16931, or Peppol:
- What validation errors do you see most often in production?
- UBL or CII — what do your clients' ERPs actually consume?
- What's the one missing feature before this is useful to you?
Full technical breakdown (architecture, code, domain model):
👉 https://me-mateescu.de/blog/xrechnung-generator-local-first-en16931/




Top comments (1)
🔗 Quick links for those who want to skip straight to it:
→ Live tool: me-mateescu.de/tools/xrechnung/
→ Source (MIT): github.com/Mihai-82Adrian/portfoli...
→ Full technical deep-dive: me-mateescu.de/blog/xrechnung-gene...
A note on the build process: I'm Finance Ops by background, not a
full-time SWE. The architecture and domain model are mine; the code
was implemented with AI assistance (Claude Code) under my direction,
with manual review and KoSIT validation loops throughout.
Happy to discuss any of it — the EN 16931 domain model, the local-first
tradeoffs, or the AI-assisted workflow itself.