Efectiback
An electronic invoicing SaaS for Peru: issues invoices, receipts and notes straight to SUNAT, with a REST API, a client portal and an operator panel.



The problem
Small businesses need to issue invoices that SUNAT accepts without relying on an accountant or a slow portal, and the systems they already use (POS, ERP, online store) must be able to integrate by API.
What I built
I built the platform end to end: a Java library with UBL 2.1, XAdES signing and a SOAP client; a Spring Boot API with hexagonal architecture; a client portal and a back office in Angular; and the landing page in Astro.
Outcome
In use by real clients. More than 350 automated backend tests, and issuing verified against SUNAT’s beta environment with an accepted CDR.
Decisions that mattered
- 01
The queue lives in Postgres
Sending to SUNAT uses a queue table with FOR UPDATE SKIP LOCKED and exponential-backoff retries: no RabbitMQ, no extra infrastructure.
- 02
One validator per document type
Invoices, receipts and notes validate with their own rules, extracted from SUNAT’s official spreadsheet. An error is rejected with HTTP 422 before queuing.
- 03
Modular monolith, not microservices
A single deployment with bounded contexts (issuing, identity, subscriptions). The engine is a library without Spring, tested on its own.
- 04
Encrypted secrets
Each company’s digital certificates and SOL key are stored encrypted with a master key, and the session uses an HttpOnly cookie.
- 05
Minimal running cost
Backend on Cloud Run, database on Supabase, files on Cloudflare R2 and front ends on Cloudflare Pages.
Technologies
- Java 21
- Spring Boot
- PostgreSQL
- Angular
- Cloud Run
- Cloudflare R2
- Astro
C4 model. The pulsing line is the main path of a request.
Level 1 · who uses the system and what it connects to
Level 2 · the applications and data stores it is made of
Level 3 · the components inside the API
- Person
- System
- Container
- Database
- External
- Main path
- 01Portal or ERP
- 02REST API
- 03Postgres queue
- 04XAdES signing
- 05SUNAT
- 06CDR in R2