SaaS

Jak jsem vytvořil SaaS s 100 000+ uživateli – case study fakturujzdarma.cz

· 12 min čtení
Jak jsem vytvořil SaaS s 100 000+ uživateli – case study fakturujzdarma.cz

Tohle není článek o tom, jak vytvořit SaaS za víkend. Je to příběh systému, který dnes zpracovává faktury pro více než 100 000 uživatelů — a co všechno muselo fungovat, aby se to povedlo.

Jmenuju se Jakub Dostál a fakturujzdarma.cz je jeden z projektů, na kterém pracuji jako fullstack vývojář a technický architekt. V tomhle článku rozeberu celý projekt od začátku — jaký byl problém, jak jsem přistoupil k řešení, jaké technologie jsem zvolil a proč, a co jsem se naučil z provozu systému v produkci.

Výchozí situace — co a proč

Fakturujzdarma.cz je online fakturační systém. Uživatelé v něm vystavují faktury, spravují klienty, sledují platby a řeší základní účetní agendu. To zní jednoduše — ale realita je složitější.

Klíčové požadavky na systém od začátku:

  • Nulová bariéra vstupu — registrace zdarma, bez kreditky, okamžité použití
  • Spolehlivost — faktura musí odejít včas, data nesmí zmizet
  • Výkon — systém musí zvládat tisíce současných uživatelů bez degradace
  • Mobilní přístup — podnikatelé fakturují z telefonu, ne jen z desktopu
  • Automatizace — upomínky, pravidelné faktury, notifikace po splatnosti

Z pohledu vývoje na míru šlo o typický případ, kdy hotová řešení na trhu buď nestačila funkčně, nebo měla nevyhovující cenový model.

Volba technologického stacku

Tohle je rozhodnutí, které ovlivní všechno další. U SaaS systému, kde očekáváte desítky tisíc uživatelů, nemůžete sáhnout po čemkoli.

Backend: Go (Golang) + Fiber

Go jsem zvolil z několika konkrétních důvodů:

  • Výkon — Go je kompilovaný jazyk. Jeden API server zvládne tisíce requestů za sekundu s minimální spotřebou paměti. U fakturačního systému, kde se generují PDF, počítají DPH a odesílají emaily, je to zásadní.
  • Jednoduchost — Go nemá dědičnost, generika přišla pozdě, a to je vlastně výhoda. Kód je čitelný i po dvou letech. Žádná magie, žádné frameworkové obskurity.
  • Concurrency — Goroutiny a channels. Když potřebujete odeslat 500 upomínek najednou, nemusíte řešit thread pool management.
  • Deployment — Výstup je jeden binární soubor. Žádné runtime závislosti, žádný node_modules.

Jako HTTP framework jsem použil Fiber v2 — výkonný, s dobrou middleware podporou a Express-like API, které zrychluje vývoj.

Frontend: SvelteKit

SvelteKit jsem zvolil proto, že:

  • Rychlost renderingu — Svelte generuje vanilla JavaScript, žádný virtual DOM overhead. Pro SaaS aplikaci, kde uživatel tráví hodiny, je rychlost UI kritická.
  • SSR + SPA hybrid — Server-side rendering pro SEO stránek (landing pages, nápověda), SPA režim pro samotnou aplikaci.
  • Bundle size — SvelteKit produkuje výrazně menší bundles než React nebo Vue. To se projeví hlavně na mobilu.
  • Developer experience — Reaktivita je přirozená, ne přilepená. Méně boilerplate = rychlejší iterace.

Databáze: PostgreSQL + Redis

PostgreSQL jako primární databáze. U finančních dat není prostor pro experimenty s NoSQL — potřebujete ACID transakce, foreign keys a spolehlivé zálohy.

Redis pro:

  • Session management
  • Rate limiting
  • Cache frekventovaných dotazů (seznamy klientů, šablony faktur)
  • Job queue pro asynchronní úlohy (odesílání emailů, generování PDF)

Mobilní aplikace: Capacitor

Nativní iOS a Android aplikace přes Capacitor. SvelteKit frontend zabalený do nativního shellu s přístupem k systémovým API (push notifikace, kamera pro sken dokladů). Jeden codebase pro web i mobil.

Architektura systému

Architektura je navržená pro horizontální škálovatelnost a oddělení zodpovědností:

┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│  SvelteKit   │────▶│   Go / Fiber  │────▶│  PostgreSQL  │
│  Frontend    │     │   REST API    │     │             │
└─────────────┘     └──────┬───────┘     └─────────────┘
                           │
                    ┌──────┴───────┐
                    │    Redis     │
                    │ Cache + Jobs │
                    └──────────────┘

API design

REST API s konzistentní strukturou. Každý endpoint vrací standardní formát:

{
  "data": { ... },
  "meta": { "page": 1, "total": 342 }
}

Autentizace přes HTTP-only cookies s tokenem. Žádné JWT v localStorage — bezpečnost je u finančních dat priorita.

Klíčové moduly

Systém je rozdělen do modulů, které spolu komunikují přes interní API:

ModulZodpovědnost
UsersRegistrace, autentizace, profily, nastavení
InvoicingVytváření, editace, odesílání a správa faktur
ClientsDatabáze klientů, IČO lookup, automatické doplňování
PaymentsSledování plateb, párování s fakturami
NotificationsEmail notifikace, upomínky po splatnosti, push
PDF EngineGenerování PDF faktur z šablon
AdminSpráva uživatelů, audit log, monitoring, ban systém
SchedulerPravidelné faktury, automatické upomínky, cron úlohy

Problémy, které jsem musel vyřešit

Žádný projekt v produkci nejde hladce. Tady jsou problémy, které jsem řešil — a jak.

1. Generování PDF ve velkém

Tisíce faktur denně potřebuje robustní PDF engine. První verze používala HTML-to-PDF konverzi přes headless Chrome. Fungovalo to — ale bylo to pomalé a paměťově náročné.

Řešení: Přepsal jsem generování na nativní Go knihovnu, která staví PDF přímo z dat. Žádný browser, žádný rendering engine. Výsledek: 10× rychlejší generování, 5× menší paměťová stopa.

2. Upomínky a automatizace po splatnosti

Systém automaticky odesílá upomínky, když faktura není zaplacena po splatnosti. Zní to jednoduše, ale:

  • Co když je email nedoručitelný?
  • Co když uživatel mezitím fakturu zrušil?
  • Co když server restartuje uprostřed odesílání 200 upomínek?

Řešení: Redis-based job queue s at-least-once delivery. Každá upomínka je idempotentní úloha — i kdyby se spustila dvakrát, výsledek je stejný. Stav se zapisuje do PostgreSQL jako audit trail.

3. Vyhledávání a filtrování

100 000+ uživatelů, miliony faktur. Full-text search přes PostgreSQL tsvector s GIN indexy. Pro seznamy klientů a faktur jsem implementoval cursor-based pagination místo OFFSET — s rostoucím datasetem je to řádově rychlejší.

4. Multi-tenant bezpečnost

Každý uživatel vidí jen svá data. Zní to samozřejmě, ale u SaaS na míru je to nejkritičtější aspekt celého systému. Každý databázový dotaz prochází middleware, který automaticky přidává WHERE user_id = ?. Žádný endpoint nemůže vrátit data jiného uživatele.

5. Rate limiting a ochrana proti zneužití

Veřejně přístupný SaaS systém přitahuje boty, scrapery a brute-force útoky. Redis-based rate limiter na úrovni IP i uživatele. Admin dashboard s přehledem podezřelých loginů, IP blacklist a možností blokace účtů.

Admin dashboard

Backend admin systém jsem navrhl jako samostatný modul s vlastní autentizací. Klíčové funkce:

  • Dashboard se statistikami — počty uživatelů, faktur, denní grafy aktivity
  • Správa uživatelů — vyhledávání, detail, historie aktivity, ban/unban
  • Audit log — kdo co kdy udělal, veškeré administrátorské akce
  • Monitoring loginů — neúspěšné pokusy, locked účty, IP analýza
  • Impersonace — možnost přihlásit se jako uživatel pro debugging (s audit logem)

Admin autentizace je oddělená od běžných uživatelů — vlastní session cookie s 24h expirací, sledování neúspěšných pokusů a automatický lock po opakovaném selhání.

Výsledky a čísla

Po několika měsících provozu systém dosáhl:

MetrikaHodnota
Registrovaní uživatelé100 000+
Dostupnost99.9%+
Průměrná odezva APIpod 50 ms
Generování PDFpod 200 ms / faktura
Velikost frontendupod 150 kB gzip (initial load)

Infrastruktura běží na VPS s Dockerem. Žádný Kubernetes, žádné over-engineering. Pro aktuální zátěž je to dostatečné a provozní náklady zůstávají nízké.

Co jsem se naučil

Několik lekcí z vývoje a provozu production SaaS systému:

1. Začněte jednoduše, škálujte až musíte. Původní architektura byla jednoduchá — jeden Go server, jeden PostgreSQL, jeden Redis. Microservices by v počáteční fázi přidaly komplexitu bez benefitu.

2. Automatizace šetří čas vám i uživatelům. Automatické upomínky, pravidelné faktury, IČO lookup — každá automatizovaná funkce snižuje support tikety a zvyšuje retenci. Investice do automatizace se vždy vrátí.

3. Bezpečnost není feature, je to základ. U finančních dat nemůžete řešit bezpečnost „potom”. HTTP-only cookies, rate limiting, audit log, oddělená admin autentizace — to všechno musí být od první verze.

4. Monitoring > testování. Testy zachytí známé problémy. Monitoring zachytí neznámé. V produkci s 100 000 uživateli se dějí věci, které jste nepředpokládali. Logování, metriky a alerting jsou důležitější než 100% code coverage.

5. Výběr technologií rozhoduje. Go + SvelteKit + PostgreSQL je stack, který škáluje bez bolesti. Kdybych začínal dnes, zvolil bych to znovu. Důvody jsem popsal v článku Jak vybrat technologie pro startup.

Pro koho má smysl podobný přístup

Vývoj SaaS na míru není pro každého. Má smysl, pokud:

  • Máte validovaný produkt nebo silný trh
  • Potřebujete plnou kontrolu nad daty a funkcemi
  • Hotová řešení vás omezují (funkčně nebo cenově)
  • Plánujete růst a potřebujete škálovatelnou architekturu

Pokud zvažujete vlastní SaaS projekt a chcete si promluvit o architektuře, technologiích nebo celkovém přístupu — ozvěte se mi. Rád proberu vaši situaci a řeknu, jestli vývoj na míru dává smysl, nebo jestli existuje jednodušší cesta.