B2B SaaS · E-Invoicing & Accounts Receivable
Prodinvoice
Designed & built full-stack by Farivar Zarvandeh
Fail-closed German e-invoicing with a customer portal.
- Fieldswait
- Taxwait
- Totalswait
- ZUGFeRDwait
- KoSITwait
INV-2026-0418
Σ €1,190.00
- Domain library classes
- 63
- HTTP handlers
- 23
- Test files
- 51
- Test assertions
- ~2,250
- Schema migrations
- 20
- Staff roles in access matrix
- 5
Figures counted from the repository; maturity note: The codebase is extensive and heavily tested, with CI against real MariaDB and the KoSIT validator. It is evolving from a single-company invoice portal into a brandless multi-tenant SaaS. External sign-offs (tax adviser review, accountant pilot, B2G test workflow, independent security review) are still open, and the UI is currently German-only.
01
Product introduction
Prodinvoice is a multi-tenant invoicing platform that turns new or legacy PDF invoices into validated ZUGFeRD and XRechnung e-invoices. It then handles everything after issuance — portal delivery, payments, disputes, corrections, supplier invoices and accounting export.
02
The problem
Germany's e-invoicing mandate means a PDF with some XML attached is no longer good enough: invoices must satisfy EN 16931 business rules, public authorities expect plain XRechnung XML with a Leitweg-ID, and issued invoices must never be silently edited. Many businesses still produce PDFs in older systems, track payments and disputes in spreadsheets, and cannot tell whether a generated file would pass the recipient's validator. On top of that, inbound supplier invoices carry real risks such as malicious XML and redirected bank accounts.
03
The solution
Prodinvoice routes every invoice through a single fail-closed gate: mandatory-field preflight, integer-cent tax calculation, totals reconciliation, ZUGFeRD/XRechnung generation, read-back, and validation by the official KoSIT validator running as a version-pinned sidecar. Nothing becomes an e-invoice unless it passes, and every verdict is recorded. Issued invoices are frozen by the application and by database triggers, corrections become separate credit-note documents, and payment status is derived from a ledger instead of stored as a flag. A branded customer portal, a hardened inbound pipeline, retention rules, backups that are tested by restoring them, and a versioned accounting export round out the lifecycle.
04
Core features
Fail-closed e-invoice gate
ImplementedA single sanctioned path from invoice data to an E-Rechnung: preflight, tax, reconciliation, generation, read-back and KoSIT EN 16931 validation. A refusal promotes nothing and keeps its recorded verdict.
Hybrid PDF and XRechnung XML from one builder
ImplementedGenerates ZUGFeRD/Factur-X EN 16931 hybrids and standalone XRechnung 3 XML from the same document model, so the PDF and the XML can never disagree. Public-authority buyers automatically receive XML.
PDF invoice import
ImplementedExtracts text from existing PDFs, detects fields and runs an e-invoice preflight so reviewers see up front whether an invoice can be converted. An optional OCR command handles scanned documents.
Configurable parser templates
PartialPer-tenant, versioned field mappings using anchors, regex, coordinates or table regions. Templates can be created and applied; a visual mapping editor and rollback are still to come.
Native invoice creation and branded letterhead
ImplementedDrafts with catalogue or custom lines stay editable until they are issued, then receive a transactional per-tenant number and a branded letterhead PDF with an optional signature.
Immutable lifecycle and corrections
ImplementedIssued invoices are protected by the service layer, the store and seven database triggers. Storno and partial corrections are new documents, issued as credit notes that reference the original.
Payments, evidence and disputes
ImplementedAn append-only ledger derives open, partial, paid, overpaid, refunded and cancelled states. Customers can upload payment proof for review or raise a dispute.
Inbound supplier invoices
ImplementedByte-level file inspection, a ClamAV scan, an XXE-safe XML parser and a CII/UBL reader feed a review queue with validation, duplicate detection and an alert when a supplier's IBAN changes.
Reports and accounting export
ImplementedRevenue, aging and VAT summaries reconcile against their source invoices. Accounting bundles follow a versioned contract with SHA-256 and replay protection.
Retention, backup and restore drill
ImplementedRetention policies and legal holds per tenant, plus encrypted AES-256-GCM backups that are checked by restoring them into a scratch database.
Multi-tenancy and security
ImplementedSession-derived tenancy, a role matrix stored as data, TOTP MFA, login throttling, browser-bound CSRF tokens, tenant-bound download tokens and tenant suspend/close/export.
Electronic B2G transmission and DATEV connector
PlannedDelivery to ZRE, OZG-RE or Peppol is currently recorded as a manual submission, and the accounting connector to a specific target system has not been built yet.
05
System architecture
A framework-free PHP monolith behind a single front controller serves two separate surfaces: a staff admin and a customer portal. Domain services in lib/ handle tenancy, policy, lifecycle, tax, e-invoice generation and ledgers. MariaDB holds the structured data, while a content-addressed document store keeps every received and issued file immutable by SHA-256. Generated and received e-invoices are validated by an official KoSIT validator sidecar, uploads are scanned by ClamAV, and the whole stack runs in Docker Compose, with CI testing against the real services.
Hover or focus a component to trace its real connections.
12 components · 12 connections, as found in the repository.
06
Technology stack
- frontend
- Server-rendered PHP templatesVanilla JavaScriptCustom CSS design system
- backend
- PHP (framework-free)ComposerApache with front controllerCLI tools for backup, export and tenant ops
- data
- MariaDB 11Content-addressed document store (SHA-256)Database triggers for immutability
- infra
- Docker ComposeGitHub Actions CI against real servicesClamAVMailpit (dev)
- integrations
- ZUGFeRD / Factur-X (EN 16931)XRechnung 3 (CII)UBL inboundKoSIT validatorhorstoeko/zugferdFPDF / FPDIsmalot/pdfparserOptional OCR (e.g. Tesseract)
07
Product experience

Legacy PDF to validated e-invoice
- 1Upload PDF
- 2Inspect, virus-scan and archive the original
- 3Extract fields and run preflight
- 4Review and assign a customer
- 5Render branded letterhead
- 6Gate: tax, totals, ZUGFeRD and KoSIT
- 7Issue, freeze and publish to the portal
Create and issue an invoice
- 1Select customer
- 2Add catalogue or custom lines
- 3Save editable draft
- 4Issue with transactional numbering
- 5Produce hybrid PDF and, for authorities, XRechnung XML
- 6Queue delivery
Get paid
- 1Customer uploads payment proof in portal
- 2Staff accepts or rejects with a reason
- 3Allocate payment to invoice
- 4Settlement state derived
- 5Aging and revenue reports update
Review a supplier invoice
- 1Receive XML or hybrid
- 2Safe parse and virus scan
- 3Read CII/UBL and check arithmetic
- 4Validate and detect duplicates
- 5Flag IBAN changes
- 6Assign, approve and export to accounting
08
Engineering challenges
- 01
Keeping refusal evidence through a rollback
Issuance runs in one transaction that rolls back when the gate refuses, which used to erase the record of why. Validation verdicts are now written on a second database connection, so the reason survives.
- 02
Immutability vs. tenant purge
Seven triggers freeze issued invoices, but DROP TRIGGER is DDL and commits implicitly in MariaDB. Purge lifts the triggers before the transaction opens and is refused while retention or legal holds apply.
- 03
Proving tenant isolation over HTTP
An end-to-end test logs in as one tenant and sends every admin route the other tenant's real IDs. It detects leaks with unique markers instead of status codes and uses positive controls so that empty pages cannot make it pass.
- 04
PDF and XML that cannot disagree
The hybrid PDF and the standalone XRechnung come from a single CII builder. Seller identity and letterhead are passed in per document, never read from the logged-in session, so batch and CLI runs cannot stamp one tenant's identity onto another's invoice.
- 05
Hostile inbound files
External XML goes through a parser that rejects DOCTYPE, ENTITY and XInclude on the raw bytes before libxml reads them. Files are classified by magic number, scanned, and preserved even when refused.
- 06
Backups that are proven
The restore drill checks three independent hashes: the archive, the restored bytes and the restored database. Tests tamper with each one and assert that the drill refuses.
09
Technical differentiators
Official-validator gate
Uses the same KoSIT EN 16931/XRechnung verdict the recipient will get, with version and checksum pins, instead of only checking that the generator ran.
Recipient-aware output
Public authorities automatically get XRechnung XML with a Leitweg-ID check, while businesses get a readable hybrid PDF.
Ledger, not flags
Payment and dispute states are derived from append-only records, so screens, reports and exports always agree.
Fraud-aware inbound
A known supplier arriving with a new IBAN triggers a visible alert on the review screen, not just a log entry.
Compliance-grade data handling
Content-addressed immutable storage, retention policies, legal holds, an append-only audit trail and encrypted, drill-tested backups.
10
Explore further
The source repository is private. A live walkthrough is available on request.