SKIP TO CONTENT
← ALL FILES Fakts · Riga · 2025

CASE FILE

FAKTS

Invoicing that satisfies a bureaucracy

PLATFORMCOMPLIANCEAI INTAKEGO + POSTGRESSVELTEKIT
← → move through nine panels ESC leaves · or swipe

THE ASK

A spreadsheet cannot be an e-invoice.

Latvia is moving every business invoice to a structured, machine-readable format. Public sector already, everyone else by 2028. Most Latvian freelancers and small companies still invoice from a template and a PDF export, which will stop being a legal document. Build the thing they move to, and make it pleasant enough that they move early.

deadlines are the easiest brief to scope against.

THE CONSTRAINTS

2025 · 01 · 01

Structured e-invoicing mandatory for invoices to the state.

2026 · 03 · 30

Business to business opens voluntarily. The window we are building in.

2028 · 01 · 01

Mandatory for everyone, and the data must reach the tax authority within five working days of issue.

Format
Peppol BIS 3.0 over UBL 2.1, to EN 16931
Addressing
9939:LV40003XXXXXX, the Latvian VAT scheme
Numbering
Unique and sequential per series. EU VAT Directive art. 226(2), Cabinet Reg. 877 §28
VAT
Every standard Latvian tier, plus reverse charge and exempt lines

none of this is negotiable. that is what makes it interesting.

THE NUMBER

SERIES FKT-2026 TENANT 01
FKT-2026-0041 ISSUED
FKT-2026-0042 ISSUED
FKT-2026-0043 ROW LOCKED
FKT-2026-0044 NEVER SKIPPED
DRAFT-8c21f UNNUMBERED

A draft holds no number. It gets one at issue, or not at all.

An invoice series may not have a hole in it. Not a convention, a legal requirement, and the first thing an auditor counts. So two people issuing in the same second must not collide, and a request that fails halfway must not burn a number on the way out.

Allocation takes a row lock, SELECT … FOR UPDATE, on the sequence for that tenant, that series, that year. The number is handed out at issue and the document is frozen into an immutable snapshot in the same move.

the counter on this deck runs the same way. it has never skipped either.

THE RECORD

Nobody should retype a company's legal address. Fakts keeps its own nightly mirror of the Latvian Enterprise Register and the state address register, pulled from the open data portal. Type three letters of a client's name and the official record fills the form.

CLIENT kais
Legal name
SIA KAISMA
Reg. no.
40003XXXXXX
VAT
LV40003XXXXXX
Address
Brīvības iela 000, Rīga, LV-1010

FILLED FROM THE REGISTER · SYNCED NIGHTLY

typed data is wrong data, eventually.

THE INTAKE

Invoices you receive arrive as email attachments, which is where bookkeeping goes to die. Connect a mailbox and Fakts polls it, queues the attachments, and extracts each one into a draft with supplier, number, dates, lines and VAT already filled in. A person confirms it. The machine never books anything on its own.

IN

MAILBOX

Polled on a schedule, read only.

QUEUE

ATTACHMENT

Stored, deduped, waiting.

MODEL

EXTRACT

Fields pulled from the document.

STOP

YOU CONFIRM

Nothing is booked until a person says so.

the useful part of an agent is knowing where to make it stop.

THE BUILD

EDGE

CLOUDFLARE

  • SvelteKit on Workers
  • Static assets, global
  • R2 for files, EU routed
  • Presigned uploads
ORIGIN · ONE VPS

GO API

  • net/http, no framework
  • sqlc over raw SQL
  • Caddy terminates TLS
  • Postgres 16 beside it
IN PROCESS

WORKERS

  • Document ingestion
  • Mailbox polling
  • Recurring invoices
  • Register sync, ECB rates

One rule holds the money side together: the server recalculates every financial field before it writes, and returns the record it stored. The interface never decides what a total is, it only shows what the database agreed to.

boring infrastructure, on purpose. it has to still be here in 2028.

THE SPEC

FrontendSvelteKit, TypeScript, Svelte 5 runes, Cloudflare Workers
BackendGo, standard library net/http, sqlc
DatabasePostgreSQL 16, pgxpool, row-locked numbering sequences
DocumentsUBL 2.1 / Peppol BIS 3.0 XML, PDF, EPC QR payment codes
FilesCloudflare R2, presigned uploads, EU data routing
AuthGoogle OAuth, JWT in an HttpOnly SameSite cookie
ExtractionAnthropic API, feature gated, human confirms every result
Open dataEnterprise register and address register mirrored nightly
LanguagesLatvian and English, with a separate per-document language
HostingCloudflare edge, one Oracle VPS, nightly database dumps

every optional piece degrades quietly instead of breaking the app.

WHERE IT STANDS

LIVE

fakts.lv, LV and EN

8

permissioned modules

2028

compliant ahead of the mandate

1

server, deliberately

Outgoing invoices, quotes, incoming documents, royalties, a client book, a calendar and VAT reporting, across multi-company tenants with module-level permissions. The public site prerenders to static HTML in both languages.

that is the file. the agent takes it from here.

FKT-2026-001 / 009
CASE FILE
© 2026 KANEPE · RIGA, LV