The problem
Before an agency pays the media suppliers of a campaign, someone has to collect each supplier's invoice and declarations and check that its tax and labor certificates (federal, state, municipal, FGTS and labor debts) are valid. Done by hand, that means chasing PDFs, opening government sites one by one and comparing numbers across documents.
FaturaDoc was built to automate this, but I inherited it as an AI product that was not ready for production: the data it showed could not be trusted, and the code carried a lot of dead weight.
What I built
- Data correctness first. I fixed how documents, certificates and statuses were stored and shown, so each supplier's situation on screen matches the facts behind it.
- OCR for scanned PDFs. Suppliers often send photographed or scanned invoices with no text layer. Those files now go through OCR, so the invoice number, supplier ID, period and amount can be read and checked like any other document.
- Government certificate lookups. Once a supplier's documents are complete, the system queries the issuing agencies for the certificates and records the result of each one: valid, irregular, lookup failed, or needs manual review.
- LLM risk reports. Gemini on Vertex AI cross-checks the documents against the certificate results and writes a report with a verdict, the findings that block payment, warnings such as certificates close to expiry, a risk level and recommendations for the agency.
- Integration with the campaign platform. FaturaDoc is connected to Metrike's campaign platform (web-metrike), so checks start from the campaign flow instead of being set up by hand.
The stack is FastAPI and Celery workers on PostgreSQL, with a React front end.
Key decisions
- Fix the data before adding features. A compliance tool that shows a wrong status is worse than no tool, so correctness came before OCR or AI.
- OCR only where it is needed. Pages with a text layer are read directly; only scanned pages go through OCR, so both kinds of upload end up in the same checks.
- Delete what isn't used. I removed about 10k lines of dead code, which made the codebase smaller and easier to change safely.
- Track cost per campaign, internally. Processing cost is tracked per campaign for the team that runs the product. The agency sees compliance results, not infrastructure cost.
Results
- The inherited product is in production and I operate it.
- Servers are hardened: secrets rotated, SSH by key only, firewall in place.
- Prometheus alerts are in place, and backups come with restore checks.
- Each campaign's processing cost is tracked.
- About 10k lines of dead code were removed.
- Compliance checks start directly from Metrike's campaign platform.




