DEV Community

Abid niazi
Abid niazi

Posted on

Building Zero-Data-Retention EU Compliance Utilities in Next.js 14: Peppol XML, IBAN Validation & GDPR

Why European Compliance Belongs on the Client Side

When building B2B applications for European clients, data privacy isn't just a feature—it is a legal requirement. With the rollout of mandatory electronic invoicing across the EU (such as Belgium’s Jan 2026 mandate and France’s Sep 2026 reform) alongside strict GDPR enforcement, developers are faced with a dilemma:

Create Valid Peppol BIS 3.0 Invoices | GDPR Compliant XML Generator

Free client-side Peppol BIS 3.0 XML generator. Create & validate EN16931 compliant UBL 2.1 e-invoices for Belgium 2026, France 2026, Germany 2027 B2B mandates.

favicon freetoolforge.org

How do you validate sensitive financial data (banking details, invoice totals, VAT numbers) without introducing server-side data liability?

The answer is 100% Client-Side Execution. By shifting parsing, XML serialization, and validation algorithms entirely to the browser in Next.js 14, you completely eliminate server logging, database retention, and GDPR payload overhead.

Here is an architectural look at how we built a zero-server EU compliance utility suite on FreeToolForge.


1. Generating Peppol BIS Billing 3.0 UBL 2.1 XML in the Browser

Peppol (Pan-European Public Procurement OnLine) requires invoice data to strictly match the UBL 2.1 XML schema and EN16931 European standards. Sending raw financial payloads to a backend API introduces data security risks.

To solve this, our client component builds the XML document object model locally before rendering:


typescript
// Client-side XML Escaping & Payload Construction
function escapeXml(str: string): string {
  return str.replace(/[<>&'"]/g, (c) => {
    switch (c) {
      case '<': return '&lt;';
      case '>': return '&gt;';
      case '&': return '&amp;';
      case '\'': return '&apos;';
      case '"': return '&quot;';
      default: return c;
    }
  });
}

// Generating compliant UBL 2.1 XML without server roundtrips
export function generatePeppolXml(invoiceData: InvoicePayload): string {
  return `<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2" xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2" xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2">
  <cbc:CustomizationID>urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0</cbc:CustomizationID>
  <cbc:ProfileID>urn:fdc:peppol.eu:2017:poacc:billing:01:1.0</cbc:ProfileID>
  <cbc:ID>${escapeXml(invoiceData.id)}</cbc:ID>
  <cbc:IssueDate>${invoiceData.issueDate}</cbc:IssueDate>
  <cbc:DocumentCurrencyCode>${invoiceData.currency}</cbc:DocumentCurrencyCode>
  <!-- Fully generated client-side -->
</Invoice>`;
}
Enter fullscreen mode Exit fullscreen mode

Top comments (0)