FunOS.
- 01 Testy
- 02 Skutečná Postgres
- 03 Review agenti
- 04 Kontrola driftu
- 05 Záloha
- 06 Nasazení
- 07 Screenshot
- 08 Hlídač
Jeden člověk a Claude Code postavili systém, na kterém běží rodinný zábavní park: rezervace, dárkové poukazy, předplacené karty a obousměrné napojení na pokladnu. Tečou přes něj skutečné peníze zákazníků. Tohle je o disciplíně, díky které se kódu od AI dá věřit i s nimi.
- Místo
- Uherské Hradiště
- Provozovny
- Laser Game · dětský svět · herna · party room
- Termín
- Den otevření, 1. října 2026
Rodinný zábavní park se čtyřmi provozovnami pod jednou střechou. Rezervace, dárkové poukazy, předplacené karty, web i pokladna žily každý zvlášť a o sobě navzájem nevěděly. Pokladna věděla, co se prodalo. Nikdo nevěděl, jestli karta dobitá online bude u pultu opravdu fungovat. Těžká nebyla žádná jednotlivá obrazovka. Těžké bylo, aby se pět systémů shodlo na penězích, každou minutu, zatímco obsluha odbavuje frontu dětí.
Park otevírá k pevnému datu. Od té chvíle je každá chyba rodič u pultu s kartou, na které je špatné číslo, a rodinná firma, která to musí vysvětlovat.
- Pokladna · tržby, kredit, body
- Předplacená karta v kapse zákazníka
- Dobití a platby poukazů online
- Rezervace z webu i od obsluhy
- Back office, ze kterého majitelé řídí den
- Zákaznický účet na webu
„Obrazovka, která vypadá správně, je snadná. Peníze, které sedí v pokladně, v back office i v telefonu zákazníka zároveň, jsou ten skutečný produkt.“
Kód píše AI. Jestli se nasadí, rozhoduje disciplína. Každé pravidlo tady vzniklo z toho, že jednou něco proklouzlo.
Většinu systému napsal Claude Code, a rychle. Rychlost ale nikdy nebyla riziko. Riziko je kód, který se zkompiluje, projde vlastními testy a v penězích se stejně plete. Práce se proto přesunula: méně psaní, víc rozhodování o tom, co musí platit, a stavění strojů, které to pokaždé zkontrolují.
- Co musí platit o penězích a co se nesmí stát nikdy
- Číst incident, ne jen diff
- Z každé uniklé chyby udělat test nebo guard
- Nasazení v pevném pořadí, vždycky nejdřív záloha
- Říct „ještě ne“, když backend není hotový
- Píše kód, migrace i testy
- Pustí celé CI lokálně, než pushnu
- Projde každou změnu čtyřmi až šesti pohledy
- Schválně rozbije vlastní testy, aby dokázal, že kousnou
- Porovná produkci s repem, oběma směry
Čtyři plochy, jedna databáze, jeden zdroj pravdy.
Obě aplikace i všechny integrace čtou a zapisují jednu databázi Postgres. Pravidla přístupu žijí v databázi, ne v UI: schované tlačítko není oprávnění.
- Web37 rout
Veřejný web
Rezervace s živou obsazeností podle provozovny, dárkové poukazy s online platbou, poptávky oslav a zákaznický portál se zůstatkem karty, body a dobitím online. Předrenderovaný, takže se dá číst i bez JavaScriptu.
- FunOS33 obrazovek
Back office
Rezervace, akce, poukazy, evidence karet, zákazníci, směny a výplaty zaměstnanců, tržby z pokladny, zprávy z webu, mapa zákaznických cest a stránka se zdravím systému.
- KartaPokladna + FunOS + web
Předplacená karta StonkyPass
Kredit žije v nativním zákaznickém kreditu pokladny, takže platba je jedno pípnutí u pultu. Body a úrovně zrcadlí FunOS. Ztracená karta se jedním krokem zablokuje v pokladně i ve FunOS a pak vymění za novou i se zůstatkem.
- ProvozBěží beze mě
Provoz
Hlídač, který při poruše pošle e-mail, kanárek, který každou hodinu přečte kontrolní kartu v pokladně, denní šifrované zálohy s vyzkoušenou obnovou a kontrola každé tři hodiny, že na produkci běží to, co je v main.
Všechno se potká v Postgres. Každá šipka má kontrolu.
Dvě React aplikace, jeden projekt Supabase. Pravidla, která sahají na peníze, běží uvnitř databáze, kde zabezpečení na úrovni řádků rozhoduje, kdo smí co číst a zapisovat. Edge funkce mluví s okolním světem, plánované úlohy drží pokladnu a FunOS ve shodě.
- CI se třemi joby: build, peněžní sada na skutečné databázi, web + testy v prohlížeči
- Denní šifrovaná záloha, obnova vyzkoušená
- Kontrola nasazených verzí každé 3 hodiny
- Hlídač provozu + kanárek pokladny, e-mail při poruše
Dobití u pokladny se musí objevit všude. Aniž by ho kdokoli psal dvakrát.
Takhle projde systémem jedna předplacená karta. Zapisují do ní čtyři různé programy. Když se kterýkoli z nich rozejde s ostatními, zákazník vidí špatné číslo.
- 14:02PokladnaDobití u pultu+500 Kč
- 14:04SyncZrcadleno do FunOS500 Kč
- 15:40PokladnaLaser Game, placeno kartou−180 Kč
- 15:42SyncÚtrata zrcadlena, přičteny body+18 b
- 18:10WebZákazník kouká do portálu320 Kč
- 18:10FunOSObsluha vidí stejný zůstatek320 Kč
Stejné číslo v pokladně, v back office i v telefonu zákazníka.
- 01
Pravdu o kreditu drží pokladna. FunOS ji zrcadlí a stejný pohyb nikdy nepošle zpátky dvakrát.
- 02
Kredit je ledger pohybů, nikdy přepsaný zůstatek. Oprava je nový řádek, ne změněný.
- 03
Body vznikají jen z kreditu utraceného za vstupné a hry, podle pravidla parku.
- 04
Každou hodinu kanárek přečte kontrolní kartu v pokladně a porovná ji s FunOS.
Rozhodnutí, která jsou schválně nudná.
- Kreditní ledger je jen pro zápis
- Zůstatek se počítá z pohybů. Nikdo, ani já, zůstatek nepřepisuje. Když je něco špatně, oprava je další řádek a historie zůstane čitelná.
- Platební webhooky jsou idempotentní
- Platební brána zavolá dvakrát, klidně desetkrát. Stejná platba musí připsat přesně jednou. Po opakovaném selhání systém přestane zkoušet sám a zeptá se člověka.
- Nebrat peníze, které nejde doručit
- Než zákazník zaplatí dobití online, systém ověří, že kartu v pokladně opravdu najde. Když ne, na platební bránu ho vůbec nepošle.
- UI nikdy nepředběhne backend
- Když databáze něco ještě nepřijme, obrazovka řekne „připravujeme“, místo aby nechala zákazníka dojít flow, které na posledním kroku spadne. Na produkci jde vždycky nejdřív backend.
- Oprávnění mají dvě strany
- Schovaná záložka není kontrola přístupu. Každá změna rolí se kontroluje v UI i v politikách databáze a test obojí porovnává.
- Souhlas před cookies
- Návštěvy se měří bez cookies, dokud se návštěvník nerozhodne. Odmítnout jde stejně snadno jako povolit, jak čeká ÚOOÚ, a odvolání smaže, co se uložilo.
„Ověřeno“ znamená spuštěno, ne že to někdo přečetl.
Psaní dělá Claude Code. Kolem něj je smyčka, díky které můžou systémem téct skutečné peníze: každý krok buď něco spustí, nebo vyrobí důkaz, a změna je hotová, až když důkaz existuje.
- 01Zadání
Požadavek přijde obyčejnou češtinou od lidí, kteří park provozují. Udělám z něj, co musí platit a co se nesmí stát nikdy.
- 02Stavba
Claude Code pracuje na větvi ve vlastním worktree. Malé fáze, každá ověřitelná sama o sobě.
- 03CI lokálně
Jeden skript pustí přesně to, co CI. Když změna sahá na peníze, odmítne skončit zeleně bez sady na skutečné Postgres.
- 04Review
Čtyři až šest review agentů čte diff různými pohledy: bezpečnost, správnost, okrajové případy a jeden, který vidí jen samotný diff.
- 05Rozbít
Mutační kontrola: rozbiju to, co nový test hlídá. Když test pořád projde, byla to dekorace a píše se znovu.
- 06Nasazení
Kontrola driftu, záloha databáze, migrace, funkce, pak build webu na skryté adrese. Na doménu jde až po kontrole.
- 07Podívat se
Screenshot skutečné produkční obrazovky a hlídač po nasazení. Zelený build nikdy nebyl cíl.
- Privilegované funkce vs. politiky tabulek
- Funkce se zvýšenými právy nesmí pustit víc rolí, než dovolí sama tabulka.
- Shoda napříč vrstvami
- Enumy v databázi vs. mapy v UI, role v UI vs. role v databázi, volané funkce vs. migrace.
- Odkazy, které existují
- Každý odkaz v e-mailu nebo SMS musí vést na skutečnou routu webu.
- Anonymní přístup
- Co smí spustit návštěvník bez přihlášení, je výslovný seznam. Peněžní funkce na něm nejsou.
- Strop přeskočených testů
- Počet tiše přeskočených testů nesmí růst.
- Drift produkce
- Produkce vs. repo oběma směry, včetně toho, jaká verze které funkce je nasazená.
$ node scripts/prod-drift-check.mjsEdge funkce (18 nasazených, 18 v repu)Brána nasazených funkcí sedí s konfiguracíNasazené funkce odpovídají mainu (žádná není starší)Migrace (222 celkem)Konfigurace Auth (SMTP, šablony e-mailů, limity)# exit 1 = drift → nenasazovatRole ořezané jen v UI
Změna snížila počet rolí z osmi na pět v rozhraní. Databáze ale znala staré: zrušený externí účet by propadl do celého back office. Teď test porovnává role v UI s rolemi v databázi.
Blokátor reklam, který by obnovil formulář
Review změny s analytikou zjistilo, že blokátor reklam, který zablokuje soubor analytiky, by spustil obnovu po nasazení a smazal rozepsanou rezervaci. Opraveno před merge, i s testem.
Tabulka, kterou úloha na pozadí nepřečte
Peněžní sada na čisté databázi ukázala, že nová tabulka nemá práva pro servisní účet. Na produkci by úloha na dohánění nikdy nic nedohnala.
Tři incidenty, tři nové stroje.
Každý z nich prošel buildem, testy i lidským okem. Ani jeden se nedal najít čtením. Na každý teď něco běží.
- 15. 8. 202601
Nasazení smazalo živou obrazovku
- Co se stalo
- Registrace karty se nasadila ručně a nikdy nezmergovala. Další nasazení z main ji z produkce odstranilo. Build zelený, testy zelené, funkce pryč.
- Co existuje teď
- Kontrola driftu, která porovná produkci s repem oběma směry. Návratový kód 1 znamená nenasazovat.
- 19. 8. 202602
CI dva dny červené a nikdo si nevšiml
- Co se stalo
- Selhání se schovalo za zeleným krokem s testy. Migrace nešly aplikovat na prázdnou databázi a databáze postavená jen z migrací byla nepoužitelná: práva udělená kdysi ručně se do repa nikdy nedostala.
- Co existuje teď
- Job v CI, který při každé peněžní změně postaví databázi od nuly a pustí proti ní peněžní sadu.
- 9. 10. 202603
Zaplacené dobití, které nedorazilo
- Co se stalo
- Oprava hledání karty v pokladně byla v repu, ale platební funkce na produkci byla starší. Zákazník zaplatil online a kredit nedorazil. Připsal se ručně, až když byly oba systémy ověřené.
- Co existuje teď
- Žádná platba, dokud se karta nenajde, žádné nekonečné automatické pokusy a každé tři hodiny kontrola, že produkce běží to, co je v main.
Od prvního commitu do dne otevření a dál.
- První commit
Přestavba raného prototypu na produkční stack: vlastní databáze, vlastní hosting, testy od prvního dne.
- Zpevněný web, napojené platby
Validace vstupů, platební brána a první CI.
- Pokladna mluví s FunOS
Tržby z pokladny chodí do back office samy.
- Řetěz karty ověřený naživo
Spárování, dobití u pokladny, sync, back office, web — od začátku do konce na skutečné kartě.
- Guardy a peněžní sada
Testy napříč vrstvami a job v CI na skutečné databázi.
- Audit před otevřením
Peněžní cesty, práva v databázi a limity přihlášení prověřené a nasazené.
- Den otevření
Rezervace v provozu, denní šifrované zálohy běží.
- Oči na produkci
Sledování chyb bez osobních údajů, hlídač provozu a kanárek pokladny.
- Ztracené karty a analytika
Blokace a výměna karty v pokladně i ve FunOS najednou; analytika webu se souhlasem.
Jen to, co je změřené.
Spočítáno na hlavní větvi a v jejích CI lozích 19. října 2026. Jen technická čísla: tržby, počty zákazníků a objem kreditu patří parku, ne téhle stránce.
- 1 544
- Unit testů back office
- + 285, které potřebují živé přístupy
- 626
- Unit testů webu
- Vitest
- 131
- Testů v prohlížeči
- Playwright, vč. přístupnosti
- 263
- Peněžních testů na skutečné Postgres
- databáze postavená od nuly
- 190
- Testů edge funkcí
- Deno
- 6
- Automatických guardů
- každý ze skutečného incidentu
- 222
- Migrací databáze
- 24 572 řádků SQL
- 62 711
- Řádků TypeScriptu
- bez testů a generovaných typů
- 194
- Mergnutých pull requestů
- 826 commitů
Co tohle není.
- 01
Není to kód jednoho člověka. Vývojář na straně parku upravuje ve stejném repu obsah webu, provozovny a ceny — asi 18 % commitů. Inženýrství, peněžní cesty a provoz jsou moje.
- 02
Hosting i databáze dnes běží na free tarifech. Zálohy mám vlastní, denní a šifrované, s vyzkoušenou obnovou. Placené tarify jsou na cestě.
- 03
Ani jedna aplikace zatím nejede TypeScript ve strict režimu. Je to zapsaný dluh, ne schovaný; zapnutí je samostatná velká změna.
- 04
Jeden incident k zákazníkovi doputoval dřív, než na něj guard existoval. Peníze se srovnaly, guard přišel potom.
- 05
API pokladny se chová i způsobem, který v dokumentaci není. Kanárek kontroluje odpovědi každou hodinu, ale změna u dodavatele nás pořád může překvapit první.
- 06
Analytika webu běží od 14. října. Data o konverzích zatím nejsou, takže tahle stránka žádná netvrdí.
Kontroly jsou produkt.
Rezervační formulář dnes z modelu dostane kdokoli. Čas zabral seznam věcí, které se penězům zákazníků už nikdy nesmí stát — a stroje, které je kontrolují při každé změně.