PeterPapp.sk
definícia kompilátor ×9

Prekompiluj, nerefaktoruj. Ako staviam produkčný softvér s AI, nie appku, ale systém, ktorý ju kompiluje

AI Building·22. septembra 2026·
Zhrnutie článkuAI
  1. Nestavaj appku, stavaj systém, ktorý ju kompiluje. Skutočný prompt je coding harness: pravidlá kódu, design systém, roadmapa so špecifikáciami a dátový model. Jediný prompt, ktorý som napísal, bol „Naprogramuj celú aplikáciu podľa roadmapy".
  2. Appka je na zahodenie. Feedback aj zmena scopu idú do harnessu, nie do kódu, a ďalší build ich v sebe. Appka sa pregenerovala desaťkrát nanovo, do kódu som nesiahol ani raz.
  3. Veľký feedback stojí rovnako málo ako malý. Cena zmeny nie je úmerná kódu, ktorý existuje, ale riadkom, ktoré pribudnú v harnesse. Keď modul druhej fázy rozbil dátový model, oprava trvala deň a potom bežal nový build.
  4. Klient testuje od prvého týždňa. Prvá verzia appky je vždy len frontend, na nerozoznanie od produkčnej. Šesť iterácií overilo produkt, scope aj dátový model skôr, než vznikol backend. Kód z tejto fázy bol vedľajší produkt.
  5. Knižnica komponentov namiesto dokumentu tokenov. Dokument s tokenmi agent nikdy nedodržal. Vibe-coding slúži len na hľadanie vizuálu, z neho agent vyextrahoval knižnicu a cez pravidlo 80 percent, derivačné recepty a design audit si ju udržiava sám.
  6. Desať hodín, jeden prompt, nula otázok. Orchestrátor riadi agentov epic po epicu cez verifikačnú bránu a dva audity a nikdy neverí, že „testy prešli". Výsledok: 64 stránok, 947 testov, päťdesiat vyklikaných journeys bez blockeru.
  7. Choď o level vyššie. Mesiac namiesto troch, jeden človek namiesto tímu. Rebuild si zaslúži len chyba, ktorej chýba pravidlo. Odmena nie je kus kódu, ktorý funguje, ale systém, ktorý generuje správne. A aj tento harness je na zahodenie.

Zhrnutie vygenerovala AI z celého článku, autor ho skontroloval.

Už neprogramujem. Mením definíciu produktu na vrchu a coding agenti ju za pár hodín prekompilujú na čistý kód aplikácie, znova a znova, bez technického dlhu. O tom, ako pre klientov budujem produkčné appky, od nuly, vytvorené iba s AI.

Štyri dni pred termínom som mal v rukách len systém, ktorý kompiluje. Žiadnu appku. V starom mindsete v tomto bode appku už pár týždňov testuješ a ladíš. Tu bol návrh hotový, ale kód appky neexistoval. Spustil som desaťhodinový produkčný build s AI a večer sme mali hotovú produkčnú appku pre klienta. Bol to zážitok: život na hrane technológie, kde veríš systému, ktorý si postavil, a nie kódu, ktorý vidíš.

Vyše pätnásť rokov navrhujem, dizajnujem a programujem appky so zakladateľmi firiem. Po štyroch rokoch práce v tíme na budovaní appiek som sa dostal späť do delivery role: znova som mohol sám uchopiť end-to-end proces, zamyslieť sa nad AI a reinventnúť, ako appka vzniká. Toto je článok o tom, ako vytváram úplne nové produkčné appky na greenfielde pre klientov, vytvorené iba s AI: jeden klientsky projekt od deviatich workshopov po desaťhodinový produkčný run.

#Tri veci, ktoré sa zmenili

Nešiel som cestou vibe-codingu, kde appku buduješ postupným promptovaním a každá zmena je ďalšia záplata. Bez architektúry rozhodnutej na začiatku sa z toho v istom bode stane chaos a technický dlh, ktorý ťa v projekte zastaví. Namiesto toho som si postavil systém, ktorý reinventuje tri veci, na ktorých stál vývoj softvéru pätnásť rokov, a ktoré sú v tomto procese gamechanger.

+1 +1 +1 kód = zdroj pravdy 30 zmien neskôr: súčet náhod, chaos vs harness = zdroj pravdy · appka vždy nanovo +1 +1 +1 kód = zdroj pravdy 30 zmien neskôr: súčet náhod, chaos vs harness = zdroj pravdy appka sa vždy postaví nanovo
  • Appka je na zahodenie. Neprogramujem nič. Mením definíciu produktu na vrchu a agenti ju za pár hodín prekompilujú na čistý kód nanovo, bez technického dlhu, so všetkými úpravami. Na tomto projekte appka vznikla desaťkrát nanovo a do kódu som nesiahol ani raz. Zmena scopu, ktorá rozbila dátový model a v kóde by stála týždeň refaktoringu, tu stála deň a jeden build.

  • Klient testuje od prvého týždňa, nie na konci. Najväčšie riziko klasického vývoja: produkt je takmer hotový a klient až pri testovaní zistí, že niečo chýba alebo je zle navrhnuté. Tu mal od prvého týždňa v rukách appku na nerozoznanie od produkčnej, v takmer plnom scope, dával feedback a na druhý deň videl novú verziu. Šesťkrát. Kým vznikla skutočná produkčná appka, produkt, scope aj dátový model už boli overené.

  • Jeden človek, jeden prompt, desať hodín. Celú produkčnú appku naprogramoval jeden autonómny agentic run na mojom počítači, z jedného promptu, bez jedinej otázky. Exekúcia celého projektu trvala mesiac. Pred érou agentov by rovnaký rozsah trval tri mesiace a potreboval produktového manažéra, dizajnéra a dvoch až troch inžinierov.

O akú appku ide: klient, firma v automotive na Slovensku s vyše 50 zamestnancami, si u mňa objednal appku na správu interných procesov a k nej customer-facing modul, kde si firemní zákazníci spravujú vlastné flotily. Zákazky, vozidlá, termíny, servisná história, notifikácie. Štyri používateľské role, každá s vlastným rozhraním, osem modulov, dve fázy.

Ako som to celé postavil, je zvyšok článku.

#Pred prvým buildom

##Deväť workshopov

Samotnej stavbe predchádzalo deväť product discovery workshopov s klientom, každý na 60 až 90 minút. Cieľ bol pochopiť požiadavky, preskúmať biznis procesy firmy a jasne pomenovať problémy, ktoré má vlastný softvér vyriešiť. Riešili sme dve vetvy: návrh nových interných procesov a softvéru, ktorý ich ponesie, a zákaznícky modul toho istého softvéru, lebo firme záleží na dlhodobej spokojnosti svojich zákazníkov. Po workshopoch som vedel, čo stavať.

Už od prvého workshopu mi AI pomáhala informácie ukladať a dávať im jasnú štruktúru. Tá bola počas celého projektu hlavným zdrojom pravdy pri rozhodovaní o návrhu systému.

##Dva harnessy

Tu je dobré miesto na zavedenie dvoch pojmov, ktoré sa budú v článku opakovať. V projekte totiž existujú dva harnessy a každý robí niečo iné.

Knowledge harness je môj vlastný systém na usporiadanie informácií zo všetkých workshopov s klientom a na ich syntézu do finálnych výstupov: roadmapy a feature špecifikácií. Zároveň je to operačný systém projektu: zápisy zo stretnutí, rozhodnutia aj s dôvodmi, mapa ľudí u klienta, celá komunikácia. Z toho istého stavu mi pripraví podklady na stretnutie, e-mail klientovi, ponuku aj zmluvu, a na otázku „prečo sme sa rozhodli takto" odpovie s odkazom na konkrétny zápis. Ako funguje zvnútra, si nechám na samostatný článok.

Coding harness je súbor textových dokumentov v repozitári aplikácie, ktoré definujú pravidlá pre coding agenta: ako programovať frontend, ako backend, aká je architektúra, ako sa testuje a ako sa nasadzuje. Je to prompt, ktorý agent dostane namiesto zadania. Práve o ňom je zvyšok tohto článku. Keď ďalej píšem len „harness", myslím tento coding harness.

Vzťah medzi nimi je jednosmerný: workshopy idú do knowledge harnessu, z neho vypadne roadmapa, špecifikácie a dátový model, a tie vstupujú do coding harnessu ako zadanie, čo sa má postaviť.

9 workshopov knowledge harness scope roadmapa · specy · model coding harness kompilátor appka disposable artefakt 9 workshopov knowledge harness scope roadmapa · specy · model coding harness kompilátor appka disposable artefakt

##Tech stack

Poďme sa pozrieť na môj tech stack:

  • Agent – Claude Code, rozšírený o vlastné skills pre každú fázu projektu na syntetizovanie a management: discovery, roadmapa, spec, build, design/code audit.
  • Frontend – React 19 s TypeScriptom a Tailwindom v4, buildovaný cez Vite, bez UI knižnice: každý komponent je vlastný a prečo, vysvetlím pri design systéme. V návrhovej fáze bežal sám, bez backendu, s IndexedDB ako lokálnou databázou.
  • Backend – Laravel 13. Frontend naň sedí cez Inertiu, takže appka je monolit bez API vrstvy: controller pošle dáta stránke ako props a formulár ich pošle späť.
  • Komunikácia a integrácie – E-maily cez Laravel Mail a Notifications (aktivácia účtov, mesačné reporty, pripomienky), v produkcii cez Resend. SMS cez BulkGate, bez balíka, len tenký vlastný kanál nad HTTP klientom. PDF cez dompdf na generovanie interných dokumentov. Plánovač na mesačné uzávierky a pripomienky termínov. Napojenie na SoftApp, systém servisu na sklad a fakturáciu, so servisnými záznamami párovanými cez ŠPZ.
  • Infraštruktúra – PostgreSQL, Redis s Horizonom na fronty, Fortify na autentifikáciu, privátny objektový storage na faktúry a výpisy, monitoring cez Pulse a Nightwatch, testy v Peste, hosting Laravel Cloud.

Jedno pravidlo v harnesse stojí za zmienku: každý problém sa rieši first-party balíkom od Laravelu, nič iné sa bez môjho súhlasu a záznamu v decision logu neinštaluje. Agent tak nemá kde improvizovať s knižnicami.

#V číslach

#Ako generovať appku desaťkrát tak, aby vyzerala a fungovala vždy rovnako?

A navyše zakaždým aj s úpravami z klientovho feedbacku. Bez odpovede na túto otázku sa takto iterovať nedá. Nechceš dať klientovi desiatykrát do ruky appku, ktorá vyzerá vždy inak.

Odpoveďou je coding harness, náš kompilátor. Na jeho úrovni je definované všetko, čo musí medzi buildmi ostať stabilné. Design systém: ako aplikácia vizuálne vyzerá, aké má interakčné patterny a pravidlá a ako derivovať nové komponenty, ktoré v ňom ešte nie sú. Pravidlá kódu: ako presne programovať frontend, ako backend, aká je architektúra, aká je testovacia stratégia, ako sa píšu testy a ako sa nasadzuje. A nakoniec chrbtica aplikácie: celý scope funkcionalít a špecifikácia každej z nich. Všetko podstatné je raz definované na úrovni harnessu.

„Naprogramuj celú aplikáciu podľa roadmapy." 5 slov pravidlá FE · BE · design kontrakt testy · smoke · deploy stratégia audit pravidiel a kvality dátový model · entity roadmapa + 64 specov harness = skutočný prompt · 196 000 slov appka = artefakt · 10 h „Naprogramuj celú aplikáciu podľa roadmapy." 5 slov pravidlá FE · BE · design kontrakt testy · smoke · deploy stratégia audit pravidiel a kvality dátový model · entity roadmapa + 64 specov harness = skutočný prompt · 196 000 slov appka = artefakt · 10 h

Ďalšie tri kapitoly idú po týchto vrstvách: design systém, pravidlá frontendu a roadmapa so špecifikáciami.

#Design systém aplikácie

Chcel som reinventnúť, ako vzniká úplne nový produkt, od prvého nápadu po produkciu. Tak začnime na začiatku: ako som vytvoril design systém bez toho, aby som otvoril Figmu a začal kresliť obrazovky.

##Vibe-coding ako hľadanie vizuálu

Predstavu som už mal: aký dashboard firma potrebuje a akým vizuálnym štýlom má hovoriť. Zameriaval som sa na funkčný dizajn, nie na estetiku, a na tomto základe som začal vibe-codovať dashboard pre majiteľa firmy. (Ukážky nižšie sú preskinované UI a katalóg komponentov z reálneho projektu, prefarbené na fiktívnu firmu, aby som ich mohol ukázať.)

Vibe-coding má v mojom procese presne toto miesto: hľadanie vizuálu, nie stavba produktu. Nebolo to nič zložité a netreba pri tom premýšľať nad best practices pre frontendový stack. Nový priečinok, otvorený Claude Code a prompt, nech vytvorí základný React projekt a v ňom stránku dashboardu majiteľa s farbami, fontami a dizajnovým smerom, ktoré som mu určil. Chcel som admin dashboard s navigačným sidebarom vľavo a typickým adminovským obsahom vpravo: tabuľky, taby, vyhľadávanie, pár štatistík.

Od prvého vibe-codeného prototypu cez vybraný vizuál po finálny prototyp dashboardu.

Prvú verziu som potom viackrát iteroval a ladil, kým sa mi výsledok vizuálne páčil. Základný dashboard bol možno 15 až 20 promptov. A bol interaktívny: komponenty reagovali na kliknutie, nebola to statická obrazovka.

Takto vznikli celkom štyri varianty dashboardu s rôznym typom vizuálu. Vybral som ten, ktorý sa mi na projektové účely páčil najviac, a z neho derivoval tri ďalšie stránky: detail entity s informáciami, tabuľkami a akčnými tlačidlami, zoznam entít v tabuľke a formulár na vytvorenie novej entity. Tieto štyri stránky obsahovali väčšinu interakčných prvkov, ktoré sa v aplikácii opakujú ako základné stavebné prvky. A dali sa ukázať klientovi a pýtať si feedback na vizuál aj interakčné patterny skôr, než existovala jediná reálna funkcionalita.

Štyri stránky z demo appky: dashboard, zoznam, detail a formulár. Väčšina interakčných prvkov appky je v nich.

##Zo štyroch stránok UI knižnica komponentov

Bola to ručná práca na dva dni explorácie a stavby základu dizajnu aplikácie. Ďalší krok bol kľúčový: nechal som Claude, nech z tých štyroch vibe-codených stránok vyextrahuje všetky UI komponenty a spraví z nich plnohodnotnú UI knižnicu komponentov pre aplikáciu. Aby sa dali vidieť a testovať, vytvoril som zároveň stránku Showcase, kde sa dajú všetky prelistovať, spolu s popisom: fonty, farby, whitespace a na čo ktorý komponent slúži a ako ho použiť.

Stránka Showcase: každý komponent na jednom mieste, s popisom, na čo slúži.

Knižnica má jeden účel: aby coding agent staval frontend konzistentne naprieč celou aplikáciou a ja som mal plnú kontrolu nad jej vizuálom. Skúšal som aj jednoduchšiu cestu, jeden design.md dokument s tokenmi: farby, fonty, paddingy. Nefungovalo to. Agent sa vizuálu nikdy nedržal a v každom rune derivoval iný typ aplikácie, nikdy nie konzistentný. Vlastná knižnica komponentov, hotová ešte pred prvým buildom, sa ukázala ako jediný spoľahlivý spôsob, ako mať rovnaký frontend naprieč desiatimi runmi.

design.md tokeny v texte → 5 variantov jedného modalu vs <DesignSystem /> komponenty v kóde → jeden modal, dookola design.md tokeny v texte → 5 variantov jedného modalu vs <DesignSystem /> komponenty v kóde → jeden modal, dookola

Pár čísel, nech je to hmatateľné. Z tých štyroch vibe-codených stránok Claude vyextrahoval 46 komponentov. Dnes, po produkčnom rune, ich má katalóg 83: 63 primitívov (tlačidlá, polia, pilulky, karty, tabuľky, drawer, modal), 4 kompozity (app shell, sidebar, hlavička stránky, formulárová karta) a 16 doménových komponentov ako časová os zákazky alebo tabuľka servisnej histórie. Ani jeden z tých 37 nových som nenapísal ja, všetky derivoval agent počas buildov.

##Prečo žiadna cudzia UI knižnica

Tu je namieste povedať, prečo v projekte nie je žiadna cudzia UI knižnica. Nikdy som ich nepoužíval, vždy som si radšej dizajnoval a programoval vlastné komponenty. UI knižnice sú pre mňa z estetického aj funkčného hľadiska limitujúce: zanášajú do kódu chaos a skrytú komplexitu a tlačia ti vlastný opinionated smer, ako má rozhranie vyzerať. Mám rád čisté riešenia na mieru. A dnes to už nie je trade-off medzi rýchlosťou a čistotou: coding agent nakóduje komponent so všetkým, čo potrebujeme, na počkanie a bez záťaže, ktorú by so sebou priniesla knižnica.

cudzia UI knižnica Uložiť balast chaos, skrytá komplexita, ich opinionated smer komponent na mieru Uložiť presne to, čo treba, agent · na počkanie · bez záťaže cudzia UI knižnica Uložiť balast chaos, skrytá komplexita, ich opinionated smer komponent na mieru Uložiť presne to, čo treba, agent · na počkanie · bez záťaže

##Dizajn kontrakt: ako sa systém používa

Keď boli komponenty nakódované, spísal som do harnessu dizajn kontrakt. Nie je to popis vzhľadu, ten už žije v kóde a na stránke Showcase. Je to návod, ako sa systém používa a kde sú jeho hranice. Má sedem častí:

  • Kontrakt agenta – šesť krokov v pevnom poradí, ktoré agent prejde pri každej obrazovke: vyber šablónu stránky, vyber komponenty podľa účelu, derivuj len keď nič nesedí, nikdy nevymýšľaj tokeny, každý nový komponent daj do Showcase, drž lokalizáciu.
  • App shell a plátno – jeden kanonický shell pre všetky role, žiadny top bar, biele plátno, sépia len v draweroch, pevné rozmery sidebaru, obsah cez celú šírku. Tri šablóny stránok (dashboard, zoznam s detailom, centrovaný formulár), z ktorých sa každá nová obrazovka odvodí. Drawer len na dashboarde na rýchly náhľad, modal na jednu sústredenú otázku. Jediný breakpoint, kde sa shell prepne do mobilného režimu.
  • Výber komponentov – tabuľka zámer → komponent: hlavná akcia, sekundárna, stavový štítok, vyhľadávanie, formulárové pole, KPI dlaždica, prázdny stav, chyba. Agent najprv pomenuje, čo chce, a až potom siahne po komponente. Plus pravidlá pre tabuľky: poradie stĺpcov, akcie v riadku, radenie na serveri.
  • Recepty na deriváciu – osem tvarov (tlačidlo, pole, prepínač, pilulka, dlaždica, plocha, overlay, kompozit) a pre každý postup, z čoho a ako odvodiť nový variant.
  • Kontrakt ikon – veľkosť a hrúbka ťahu podľa kontextu, farby, dvojtónové aktívne ikony v navigácii.
  • Anti-patterny – zoznam vecí, ktoré sa v tomto alebo v sesterskom projekte aspoň raz dostali do kódu: žiadny raw hex, žiadne nové akcentové farby, žiadne oranžové tlačidlá, žiadne ťažké tiene, žiadny font-bold, žiadna cudzia UI knižnica, žiadne vymyslené varianty.
  • Keď je dokument zle – ak pravidlá bránia rozumnému riešeniu, je to signál na eskaláciu, nie povolenie ich porušiť.
Design System — Agent Operating Manual
This document is the contract for any agent (or human) generating UI in this codebase. It does not restate colors, typography, or component APIs — those have a single source of truth elsewhere:
Looking for…Go to…
Color, radii, shadow, typography tokenssrc/index.css (@theme block)
Live, runnable showcase of every primitivesrc/pages/DesignSystem.tsx (route /design-system)
One-line catalog of every component + propsdocs/COMPONENTS.md
Layer boundaries / import rulesdocs/BOUNDARIES.md
Project architecture, hooks, servicesdocs/ARCHITECTURE.md
Routes & navigationdocs/ROUTES.md
Error UX patterndocs/ERRORS.md
This file owns: how to use the system, when to derive new components, and what's forbidden.
1. Agent contract
When you are asked to generate or modify UI, run this loop in order. Do not skip steps.
1.Pick a page template. Open src/pages/DesignSystem.tsxPageTemplatesSection. Three canonical layouts exist: dashboard, list+detail, centered form. Start from the one whose shape matches the screen.
2.Pick primitives by purpose, not by name. Walk the showcase from top to bottom. For each piece of the screen, find the closest existing component in src/components/ (catalog in docs/COMPONENTS.md). If something fits within ~80%, use it and pass props — don't fork it.
3.Only derive when no primitive fits. If you can't find a match, follow §4 Derivation recipes below before writing anything new. Composing existing primitives is always preferred over building a new one.
4.Never invent tokens. Colors, radii, shadows, motion durations all come from src/index.css. If a value seems missing, you are almost certainly trying to do something the system rejects — re-read §6 Anti-patterns.
5.Showcase what you build. Any new primitive added to src/components/ must also appear in src/pages/DesignSystem.tsx with a Showpiece and get a row in docs/COMPONENTS.md. No exceptions — the showcase is the system's source of truth.
6.Match the locale. App copy is Slovak, informal-direct register, no exclamation marks. Reuse phrasing from the showcase or existing pages.
2. App shell, canvas & locale
The contract in §1 covers individual components. This section covers the things the agent loses control of when it improvises chrome — and where past builds have shipped the wrong answer most often.
2.1 App shell is one canonical component
The chrome that wraps every authenticated screen (sidebar + main canvas + create menu + user footer) lives in one file: src/components/AppShell.tsx. It is composed from Sidebar + NavSection + NavItem + CreateMenu exactly as SidebarShellDemo in src/pages/DesignSystem.tsx shows.
Pages render only their content inside <Outlet />. Shell concerns — nav, create menu, user footer, canvas color, container padding — belong to AppShell, never to route files.
Different portals (partner vs admin, Owner vs Ops) are modes of the same shell, expressed through props or conditional nav arrays. Do not create a parallel shell implementation per portal.
If SidebarShellDemo lives only inside the showcase, extract it to src/components/AppShell.tsx first and import it from both the showcase and production. Two implementations of the same chrome are never allowed.
There is no top bar. The showcase templates have none. Page titles belong to PageHeader, not the chrome.
2.2 Where the CreateMenu lives
CreateMenu is the dark "Vytvoriť" button. It belongs inside the sidebar via <Sidebar topSlot={<CreateMenu … />}>, directly below the logo. It is never placed in a topbar, header, or floating in the page body. The showcase demonstrates this in SidebarShellDemo.
2.3 Main canvas color
The main canvas (everywhere outside drawers and modals) is bg-bg-surface — white. Light grey (bg-bg-base) is reserved for drawer shells only — and drawers appear only on the Dashboard (see §2.6). Its purpose there is to make the inner white DetailCards lift visually. Using grey on the main canvas erodes that signal.
The showcase's PageTemplatesSection description states the same rule: the main canvas is white, bg-bg-base belongs to drawer shells.
The palette is neutral: white canvas, light-grey bg-bg-base, ink text (#171717, never pure black), one orange accent (primary) and a muted red used for danger only. The accent-red and accent-lime tokens both resolve to ink — they name a role (structure, toggles/focus), not a hue. Fonts: Ubuntu (sans) and Ubuntu Mono (mono). All values live in src/index.css.
2.4 Sidebar dimensions
Sidebar expanded width: 260px. Collapsed: 76px. These are the values SidebarShellDemo uses. Do not improvise narrower or wider sidebars per page — the rest of the layout grid is calibrated to these numbers.
2.5 Page templates
The showcase's PageTemplatesSection defines three layouts. Every route-level page must match one of them:
Dashboard — KPI tile row + content cards, sidebar + main canvas, no extra topbar. This is the only screen that opens a Drawer — see §2.6.
List + detail — table on the main canvas; selecting a row navigates to a full-page detail route (BackLink + DetailPageHeader + a column of DetailCards on the white canvas). The detail is its own page — never a drawer. Used for cases, partners, clients.
Centered formmax-w-[560px] mx-auto, BackLink above PageHeader, single FormCard. Used for invites, settings sub-pages, two-step flows. Wider or left-aligned form pages are a deviation.
If a screen doesn't fit any of the three, stop and surface the conflict before improvising — adding a fourth template is an owner-approval moment, not an in-flight decision.
2.6 Drawers are Dashboard-only
The Drawer (right-aligned overlay, light-grey inner shell) appears on one screen — the Dashboard. It has exactly two jobs there:
Quick preview — clicking a record in a dashboard widget opens a read-only glance. The drawer's action row carries an open-full-detail control (e.g. „Otvoriť poruchu") that navigates to the full-page detail route. You do not edit inside the drawer — it is a glance, not a workspace.
Aktivita panel — the activity feed (TimelineFeed), opened from the bell.
Every other screen resolves record detail and activity as a full page, never a drawer:
A list page (Poruchy, Klienti, Partneri) opens a row as a full-page detail route — BackLink + DetailPageHeader + DetailCards on the white canvas.
Activity reached outside the Dashboard is a full page, not the Aktivita drawer.
If you are building a non-Dashboard screen and reach for Drawer, stop — the system wants a full-page detail (template §2.5) instead.
2.7 Locale
App copy is Slovak, informal-direct register, no exclamation marks. When in doubt about phrasing, lift it from the showcase or an existing page rather than translating freshly. Mixing English UI strings or formal address ("Vy"/"Vám" outside of explicit legal copy) breaks the voice.
2.8 Main content spans the full canvas width
The content area — everything to the right of the sidebar — fills 100% of the remaining width. It is a fluid 1fr column, never a fixed pixel width and never a centered max-w-* wrapper at the canvas level.
The shell grid is [sidebar] [1fr]. The content column stretches and shrinks with the viewport; only the sidebar carries fixed widths (§2.4).
Width constraints belong to inner elements, not the canvas. The centered-form template (§2.5) caps its FormCard at max-w-[560px] — but that cap lives on the card, while the canvas underneath still spans the full column.
Do not wrap a page's content in a fixed-width or max-w-* container to "keep it tidy". Tables, dashboards, and detail pages use the whole width.
The PageTemplatesSection templates already encode this — their main column is 1fr. Copy that, never reintroduce a fixed shell width.
3. Component selection rules
Map the intent → primitive before writing JSX. Use this table as a decision tree:
IntentPrimitive
Hero action on a pagePrimaryCTA (dark fill). Never orange.
Cancel / secondary actionSecondaryButton
Toolbar action with icon + labelGhostButton
Icon-only button (with aria-label)IconButton
Status labelPill (semantic tones) — or StatePill for case lifecycle
Hero search bar (Dashboard)HeroSearch — live result list inside the card
In-table / compact searchTableSearch (inside TablePanel)
Form fieldTextField (mono / prefix / suffix / error all built-in)
Two/three-option choice in a formSegmentField
Yes/no settingSwitch (ink default; orange only for attribution/network-level)
Card list of options where one is selectedRadioGroup
KPI numbers above a tableStatTile (only one highlight tile per row)
Container with elevationCard
Container without elevationSurface (tints: surface, base, subtle)
Filterable listTablePanel + DataTable + TableRow + TableCell
Empty listEmptyState
Inline noticeAlertBanner (tones: danger, warn, info)
Record detail opened from a list pageFull-page detail route — BackLink + DetailPageHeader + DetailCards. Never a drawer (see §2.6)
Quick record preview or the activity panel — Dashboard onlyDrawer (right-aligned overlay) — see §2.6
Single-question editModal (centered, ~480px)
Numeric ± edit inside a modalStepper + DiffStrip
Inner-page title blockPageHeader + BackLink (list / form pages); DetailPageHeader + BackLink (entity profile pages)
Section divider with accentSectionAccent + SectionLabel, or SectionHeader for the full block
Activity feed grouped by dayTimelineFeed
ID / serial number / installation number / contract number / shortcodewrap in <Mono>
Loading stateSkeleton (shape-matched) for surface fills, Spinner for inline, PrimaryCTA loading for buttons
Failure stateErrorDialog (centered modal — never inline error rows; see docs/ERRORS.md)
Anti-rule. Reaching for a third-party UI library (Headless UI, Radix, MUI, shadcn) is forbidden without explicit owner approval. Every primitive listed above is already implemented locally.
3.1 Table column order
Every DataTable orders its columns by a fixed priority. Do not reorder per screen — a consistent skeleton lets the operator scan any table the same way.
1.ID — the entity's identifier (C-2026-1144, partner code, client ID), wrapped in <Mono>. Include this column only when the entity has an ID; skip the slot entirely when it doesn't.
2.Entity name — the human label: client name, partner name, case title.
3.Labels — status and category Pills / StatePills (case state, type, tags). All label-style columns group here, directly after the name.
4.Everything else — remaining data columns (serial number, installation number, amounts, dates, owner), in whatever order best fits the screen.
5.Actions — the row-action column, always last (§3.2).
So a case table reads: Porucha (ID) · Klient · Typ · Stav · Sériové číslo · Partner · Cena opravy · Akcie. TableSection in src/pages/DesignSystem.tsx is the reference — mirror it.
3.2 Table row actions are icon-only
Row-action buttons never carry a text label. Each action is a single clickable symbol — a ghost IconButton with a required aria-label (and a matching title for the hover tooltip). This holds for every row action: open, edit, delete, download.
Use IconButton variant="ghost" size="sm"; the action column is the last one and its column field is sortable: false.
A text-labelled button (PrimaryCTA, SecondaryButton, or GhostButton with children) inside a table row is a deviation — see §6.
Page-level actions that do need a label live in the PageHeader or the TablePanel controls row, never in the row itself.
3.3 Cross-link partner / client / case references
Anywhere an entity — a partner, a client, or a case — is named, that name is a navigable link to the entity's detail route, not plain text. This applies everywhere the reference appears: table cells, DetailCard values, drawer previews, timeline items, activity feeds, modal copy.
Render the reference as a link to the entity's full-page detail route (List + detail template, §2.5). The operator can always pivot from one record to a related one in a single click.
In a table, both the ID column and the name column link to the same detail route.
Plain, non-clickable text for a partner/client/case name is a deviation. If a reference genuinely has no detail route to point at, that is a gap to surface — not a reason to drop the link.
If a shared link primitive is needed for this, derive it per §4 — keep the styling calm (inherit text color; underline or color shift on hover only).
4. Derivation recipes
If §3 has no fit, follow the closest recipe below. Every new component:
Goes in src/components/<Name>.tsx, named export, functional only, no any.
Uses only token utility classes from src/index.css (bg-bg-surface, text-text-primary, border-border-strong, shadow-card, …). No raw hex anywhere.
Inherits API conventions from its closest sibling primitive (see recipes).
Gets a Showpiece in DesignSystem.tsx and a row in docs/COMPONENTS.md in the same PR.
4.1 New button shape
Copy the API surface of PrimaryCTA: { children, icon?, trailingIcon?, size?, loading?, ...buttonProps }. Pass ...rest through to <button> so consumers retain disabled, onClick, aria-*. Pick the existing fill family — dark, light-with-strong-border, or ghost — don't invent a fourth.
4.2 New form field
Mirror TextField's outer envelope: label row (12px medium text-text-secondary, ink * for required) → bordered input shell (border-border-strong resting, border-accent-lime — ink — on focus) → optional hint or errorMessage (11.8px, text-text-muted or text-danger-text). All form fields must accept label, required, hint, errorMessage. If the control is intrinsically wide (textarea, file dropper), keep the same envelope but swap the inner element.
4.3 New toggle / boolean
Choose between Switch (continuous setting) and Checkbox (acknowledgement / multi-select). If you must introduce a new toggle pattern (e.g., tri-state), still keep the props: { checked / value, onChange, label, hint?, disabled?, tone? }. Tones are lime (default, renders as ink) and orange (attribution/network) — do not invent a new tone.
4.4 New pill / chip
Use Pill first with one of its tones. Only create a new chip component when the shape differs (e.g., a chip with a leading avatar, or a removable chip with an ×). Reuse the same radii (rounded-full for chips, rounded-md for square pills) and the soft/strong background pair from the existing tones.
4.5 New stat / tile
Use StatTile with a custom tile payload before forking it. If you need a different shape (e.g., a sparkline tile), keep StatTile's outer card shell (border, radius, padding, hover lift) and only change the inner block. Maintain the one-highlight-tile-per-row rule.
4.6 New surface
Card (elevated) vs Surface (flat). Do not create a third surface treatment. If you need a tinted surface, use Surface with tint="subtle" | "base".
4.7 New overlay
Two kinds exist and that is final:
Drawer — right-aligned, full-height. Dashboard-only (see §2.6): a quick read-only record preview, or the Aktivita panel. Always uses Drawer + DrawerHeader + DrawerBody. Record detail on any non-Dashboard screen is a full-page route, not a drawer.
Modal — centered, fixed width, single focused question. Always uses Modal.
Anything else (popovers, command palettes) requires owner approval before you start.
Sanctioned exception — success toast. The bottom-right success toast (ToastProvider + useToast, src/components/Toast.tsx) is an owner-approved non-blocking confirmation surface for completed actions (partner created, client registered, case opened, invoice uploaded). It is success-only: errors still go through ErrorDialog per docs/ERRORS.md. Do not stretch the toast into warnings, info banners, or destructive confirmations — those have their own primitives (AlertBanner, Modal).
Sanctioned exception — Lead console (Akvizícia, F043). The lead call-workflow (/admin/leads, src/components/LeadConsolePanel.tsx) uses a right-side editable, auto-saving side panel off the leads list. This is a deliberate Akvizícia-scoped exception to "drawers are Dashboard-only" and "you don't edit inside the drawer" (§2.6 / §4.7), approved in the roadmap (§7) and the F043 spec for the operator's high-volume calling console. It does not generalize: every other record-detail surface is still a full-page route, and the Dashboard drawer stays read-only.
4.8 New composite (multi-primitive)
Composites that bind primitives to a domain (InvoiceUploadModal, PartnerInviteForm) live under src/components/ only if they are reused across ≥2 pages. Single-use compositions stay inside their pages/<feature>/ folder. Always compose from primitives — never duplicate token classes.
5. Icon contract
The icon library is lucide-react. There are exactly three rules.
5.1 Size & stroke
ContextSizeStroke
Nav rail / sidebar item202
Inline with text / list rows161.75
Ghost button leading icon141.75
Hero search / page-level181.75
Big empty/error state22–241.5
Use these exact pairs. Avoid strokeWidth={1} (too thin) and strokeWidth={2.25+} (too punchy).
5.2 Color
Icons follow text color unless they carry semantics. Defaults:
Calm / structural: text-text-muted or text-text-secondary.
Inside a tone container (alert/pill): inherit the container's text-*-text.
Inside a PrimaryCTA / cta-dark: white (text-text-inverse).
Never set an icon's stroke directly via style. If you need a custom color, wrap it in a span with text-* — the icon inherits.
5.3 Bi-tone active treatment (sidebar nav)
When an icon needs the brand bi-tone treatment (ink structure, orange accent on a secondary path), wrap it in .mc-bitone[data-active="true|false"]. See src/pages/DesignSystem.tsxBiToneIconsSection for the live demo.
To add a new icon to the bi-tone set, append a CSS rule to src/index.css under the mc-bitone block:
.mc-bitone[data-active="true"] svg.lucide-<icon-name> > *:nth-child(N) { stroke: var(--color-primary); }
Steps:
1.Inspect the icon's lucide SVG to count children (path, rect, circle, …). Lucide exposes them in source order.
2.Decide which child is the accent — typically a secondary, visually smaller element: a dot, a notch, a chart bar, an inner shape. The rest stays ink.
3.Add the rule (use nth-child(N) for a single accent, nth-child(n+M) to accent everything from index M onwards).
4.Add the icon to BiToneIconsSection's icons list in DesignSystem.tsx so the showcase covers it.
5.The default (no rule) is "all paths ink on active" — that is acceptable for icons with one strong silhouette.
Do not bi-tone icons that don't appear in the sidebar nav. Other locations (buttons, alerts, empty states) use the standard mono-color behaviour from §5.2.
6. Anti-patterns
Each item below has shipped at least once in this codebase or a sibling — that's why it's here.
No raw hex anywhere. Not in style={{ color: '#…' }}, not in CSS, not in Tailwind arbitrary values like text-[#171717]. Always a token class.
No pure black / pure white text. Use text-text-primary (#171717) and text-text-inverse.
No new accent colors. Nothing beyond orange, ink, the greys and the muted danger red. accent-red / accent-lime resolve to ink; adding blue/teal/purple/green for "info" or "success" is forbidden; use the existing semantic tones (info is grey-family, success is dark text on light grey, warn is orange-family, danger is the muted red — the only red in the system).
No orange-filled buttons. Orange is for state, focus rings, and attribution chips. Primary fill is cta-dark.
No heavy shadows. shadow-card is the deepest non-drawer elevation. No shadow-2xl, no custom box-shadow with high alpha.
No borders thicker than 1px. For more contrast, switch from border-border to border-border-strong.
No tracking-tight. Use tracking-[-0.01em] / tracking-[-0.015em] exactly as shown in the typography showcase. tracking-tight is too aggressive.
No font-bold. Use font-medium / font-semibold only. Bold reads as shouting in this system.
No inline error rows. Failures surface through ErrorDialog (centered modal). See docs/ERRORS.md.
No springs / bouncy motion. Ease-out / cubic-bezier only. See MotionList in DesignSystem.tsx.
No style={{}} for colors, radii, shadows, motion. Token classes only. The one gradient in the system is the monochrome bloom — .mc-bloom / .mc-bloom-page in src/index.css (soft ink halos, no hue), used by GradientCallout, AuthBackground and the highlight StatTile. Reuse the classes; never re-declare radial-gradient values inline.
No third-party UI libraries. See §3 anti-rule.
No invented Pill tone, Switch tone, IconButton variant, etc. If a new variant feels needed, take the question to the owner before adding it.
No fixed-width or `max-w- main canvas.** The content column right of the sidebar is a fluid 1fr` — see §2.8.
No text-labelled buttons in table rows. Row actions are icon-only ghost IconButtons — see §3.2.
No plain-text partner/client/case names. Every entity reference is a link to its detail route — see §3.3.
7. When this document is wrong
If you are working on a real screen and the rules above prevent a sensible solution, that is a signal — not permission to break the rules. Open a discussion (or, in agent mode, surface the conflict in your reply) before adding a new token, accent, or primitive. The system is intentionally narrow; every exception erodes consistency for the next agent.
Dizajn kontrakt v harnesse

##Auto-audit: agent si dizajn kontroluje sám

Kontrakt sám o sebe nestačí. Coding agenti driftujú: keď stavajú kus frontendu alebo celú appku, po pár obrazovkách začnú syntetizovať z pamäte namiesto toho, aby čítali Showcase. Tlačidlo „Vytvoriť" sa objaví v top bare, ktorý neexistuje, plátno dostane sépiu namiesto bielej, formulár si vymyslí vlastnú šírku. Každá z týchto vecí sa reálne stala. Preto má harness audit skill.

Your Role
You are a design-system reviewer. You compare the implementation against the binding contract in docs/DESIGN_SYSTEM.md and the canonical patterns in src/pages/DesignSystem.tsx. You report concrete, citation-backed deviations. You do not fix them — your output is the audit report. Fixing is a separate pass (Step 5), so that the agent grading the work is never the agent that did it.
This skill exists because past builds shipped wrong chrome (CreateMenu in a topbar instead of the sidebar), wrong canvas color (bg-bg-base instead of bg-bg-surface), wrong form widths (max-w-[820px] instead of the templated max-w-[560px]), and freehand user footers that diverged from SidebarShellDemo. The build agent didn't catch these because it was synthesizing from memory instead of reading the showcase. Your job is to catch them after the fact.
Process
Step 1: Read the contract
1.docs/DESIGN_SYSTEM.md — §1 Agent contract, §2 App shell, canvas & locale, §3 Component selection rules, §5 Icon contract, §6 Anti-patterns. Internalize the rules — these are what you'll grade against.
2.src/pages/DesignSystem.tsx — walk it top to bottom. Pay special attention to:
PageTemplatesSection — the three canonical layouts with exact widths, paddings, canvas color.
SidebarShellDemo — the canonical app shell composition (CreateMenu in topSlot, user footer pattern, sidebar widths 260/76).
CompositionSection — concrete reference patterns for detail page headers, KPI strips, form sections.
3.docs/COMPONENTS.md — the catalog of allowed primitives.
4.CLAUDE.md — the UI Build — Pre-flight section (the index that points at everything above).
5.src/index.css — the @theme block. This is the only source of color, radius, shadow, and font tokens.
Step 2: Pick the audit scope
Resolve the requested scope to a concrete file list:
Feature ID → read knowledge/features/F{ID}-*.md, then git log --diff-filter=A --name-only or list the files mentioned in the spec to find what that feature added.
Route path → trace from src/App.tsx to the page component(s).
Glob → expand it.
all / empty → every .tsx under src/pages/ (except DesignSystem.tsx) plus everything under src/components/ — the showcase-coverage check (§H) needs them in scope.
Print the resolved file list back to the user before reading them — short confirmation step.
Step 3: Run the audit
For each file in scope, check against this rubric. Cite specific line numbers when reporting a finding.
A. App shell & chrome (DESIGN_SYSTEM.md §2.1, §2.2, §2.4)
Verify against the rules in §2 of docs/DESIGN_SYSTEM.md and the canonical SidebarShellDemo in the showcase:
One canonical AppShell exists; no freehand chrome in route files; no parallel shell implementations per portal.
CreateMenu sits inside the sidebar topSlot; no topbar / header / floating create button.
User footer matches the SidebarShellDemo pattern exactly (compare to the demo code).
Sidebar widths match the demo (expanded / collapsed).
B. Page templates (DESIGN_SYSTEM.md §2.5)
For every route-level page, identify which PageTemplatesSection template it should follow (Dashboard / List + detail / Centered form). Flag pages that don't match a template, mix templates, or improvise a fourth shape without escalation.
C. Canvas color (DESIGN_SYSTEM.md §2.3)
Main page canvas is bg-bg-surface (white). bg-bg-base (light grey) is allowed only inside drawer shells.
No raw hex values anywhere. Grep for bg-\[ / text-\[ / border-\[ / style={{ with color values — these are anti-pattern per §6.
D. Tokens & anti-patterns (from §6)
No font-bold (use font-medium / font-semibold).
No tracking-tight (use tracking-[-0.01em] / tracking-[-0.015em]).
No new accent colors — orange, ink, the greys and the muted danger red only (accent-red / accent-lime resolve to ink).
No orange-filled buttons (orange is for state/focus, primary fill is cta-dark).
No shadows heavier than shadow-card outside drawers.
No borders thicker than 1px.
No inline error rows — failures go through ErrorDialog.
No third-party UI libraries (Headless UI, Radix, MUI, shadcn).
No invented Pill tone, Switch tone, IconButton variant.
E. Component selection (from §3)
Every JSX element should map to a primitive from docs/COMPONENTS.md or be composed from primitives. Flag freehand <div className="bg-bg-surface border ..."> that should be a Card or Surface.
Every form field should be TextField or SegmentField, not a raw <input> styled by hand.
Every status indicator should be Pill or StatePill, not a freehand pill-shaped div.
Every section title should use PageHeader or SectionHeader, not a raw <h2 className="...">.
F. Icon contract (§5)
Every icon's size / strokeWidth pair matches the table in DESIGN_SYSTEM.md §5.1 exactly — read the table, don't audit these from memory.
No strokeWidth={1} (too thin) or strokeWidth={2.25}+ (too punchy).
Icon color comes from a text-* class, never from style (§5.2).
G. Locale (DESIGN_SYSTEM.md §2.7)
Slovak, informal-direct register, no exclamation marks. Flag English copy, formal address ("Vy"/"Vám" outside of explicit legal copy), or exclamation marks.
H. Showcase coverage (only if scope includes src/components/)
Every primitive in src/components/ has a Showpiece in src/pages/DesignSystem.tsx and a row in docs/COMPONENTS.md. Flag any new primitive missing from either.
Step 4: Emit the audit report
Produce a markdown report in this exact shape:
# Design audit — {scope} **Date**: {YYYY-MM-DD} **Scope**: {what was audited} **Files checked**: {N} ## Summary - {N} blocking issues - {N} should-fix issues - {N} nits ## Blocking (chrome / template / canvas — affects every page) ### B-1: {short title} - **File**: `src/components/AppShell.tsx:42` - **Rule**: DESIGN_SYSTEM.md §2.1 *App shell is one canonical component* - **Found**: {what the code does} - **Expected**: {what the showcase / docs say} - **Fix**: {one-sentence concrete fix} ### B-2: ... ## Should-fix (per-page deviations) ### S-1: {short title} ... ## Nits (cosmetic, low impact) ### N-1: ... ## Files audited - `src/components/AppShell.tsx` - `src/pages/partner/PartnerDashboard.tsx` - ...
Severity rules:
Blocking = wrong chrome/shell, wrong canvas color, wrong page template, missing AppShell extraction, third-party UI library, raw hex, invented tokens. These break the system itself.
Should-fix = wrong icon size, wrong heading element, freehand div where a primitive exists, form not centered when template requires centered, wrong sidebar width.
Nit = inconsistent spacing within tolerance, slightly off copy register, missing showcase row for a primitive that already exists in production.
Step 5: Hand off, don't fix
This pass never edits code. The report is the deliverable — an auditor that fixes its own findings stops reporting them.
In an autonomous run the orchestrator takes it from here without asking: it opens a fresh pass, applies every Blocking and Should-fix finding, re-runs this audit on the same scope to confirm they are gone, and commits. Nits are applied only when that pass is already touching the file. The run does not continue to the next epic with Blocking findings open.
When a human is driving, the report stops here and they decide what gets applied.
Rules
Cite line numbers for every finding. A finding without a citation is rejected.
Reference the rule for every finding (which section of which doc). "Just feels off" is not a finding.
No auto-fix in the audit pass. Even a one-character fix belongs to the follow-up pass (Step 5) — this pass reads, it never writes.
Do NOT suggest creating new primitives to absorb deviations. The contract says "compose existing primitives" — if a deviation can't be expressed with existing primitives, that's an escalation, not a fix.
Read the actual showcase for every check — don't audit from memory. The showcase is the source of truth; this file (CLAUDE.md, COMPONENTS.md) is the index.
Keep the report under ~80 findings. If there are more, group by file and report top 10 per file with a note that more exist.
Skill design auditu: čo číta, podľa akej rubriky hodnotí a v akom tvare reportuje. Neopravuje, len hlási.

Na konci každého epicu beží design audit ako samostatný subagent. Načíta dizajn kontrakt, tokeny design systému a stránku Showcase, potom prejde postavené obrazovky a porovná ich s nimi: shell a navigácia, šablóny stránok, farba plátna, tokeny a anti-patterny, výber komponentov, ikony, lokalizácia a či má každý nový komponent ukážku v Showcase a riadok v katalógu. Každý nález má súbor, riadok a pravidlo, ktoré porušil, bez citácie sa nález neuznáva. Audit sám neopravuje, len hlási v troch stupňoch: blokujúce, opraviť, drobnosť. Oprava ide v ďalšom kroku a epic nie je hotový, kým nemá nula blokujúcich nálezov.

claude — ~/calora
~/calora (main) $ claude
> /sprint.design-audit F022
Scope: F022 — Case detail (Admin) · knowledge/product/features/F022-case-detail.md
Reading contract: docs/DESIGN_SYSTEM.md · src/pages/DesignSystem.tsx · docs/COMPONENTS.md · src/index.css
Resolved 4 files:
src/pages/admin/cases/CaseDetail.tsx
src/pages/admin/cases/CaseTimeline.tsx
src/components/CaseCloseModal.tsx
src/components/ServiceHistoryTable.tsx
# Design audit — F022 Case detail (Admin)
Date: 2026-07-14 · Files checked: 4
Summary: 1 blocking · 3 should-fix · 2 nits
## Blocking
B-1 Detail canvas uses sepia
src/pages/admin/cases/CaseDetail.tsx:38 rule DESIGN_SYSTEM.md §2.3
found <main className="bg-bg-base px-8 py-8">
expected bg-bg-surface — sepia is reserved for drawer shells
fix drop the wrapper; AppShell already owns canvas color and padding
## Should-fix
S-1 Freehand status pill
src/pages/admin/cases/CaseDetail.tsx:112 rule DESIGN_SYSTEM.md §3 · COMPONENTS.md
found <span className="rounded-full bg-lime-soft px-2 text-[11px]">Otvorená</span>
expected <StatePill state="open" />
S-2 Raw <h2> section title
src/pages/admin/cases/CaseTimeline.tsx:21 rule DESIGN_SYSTEM.md §3
found <h2 className="text-[15px] font-semibold">Časová os</h2>
expected <SectionHeader title="Časová os" />
S-3 Icon stroke off-contract
src/components/ServiceHistoryTable.tsx:64 rule DESIGN_SYSTEM.md §5.1
found <Wrench size={18} strokeWidth={2} /> inside a table row
expected size 16 · strokeWidth 1.75 for inline rows
## Nits
N-1 Exclamation mark in copy
src/components/CaseCloseModal.tsx:47 rule DESIGN_SYSTEM.md §2.7
found „Zákazka uzavretá!“
expected „Zákazka uzavretá“ — informal-direct, no exclamation marks
N-2 Missing catalog row
src/components/ServiceHistoryTable.tsx rule DESIGN_SYSTEM.md §1.5
found Showpiece exists in the showcase, no row in docs/COMPONENTS.md
expected every primitive gets a showcase entry and a catalog row in the same commit
Report only — no files changed.
Say „fix blocking“ to apply B-1 in a separate pass.
Takto vyzerá výsledok auditu jedného epicu (ukážka). Každý nález má súbor, riadok a pravidlo, ktoré porušil.

##Aktualizácia Design Systému

A odpoveď na otázku, kto udržiava design systém a showcase: agent, lebo mu to vynucujú tri pravidlá a audit ich kontroluje.

  • Pravidlo 80 percent – Pre každý kúsok UI musí nájsť najbližší existujúci komponent, a ak sedí aspoň na 80 percent, použije ho a doladí cez props. Nesmie ho forknúť.
  • Derivačné recepty – Keď nič nesedí, ide podľa receptu pre daný tvar: od ktorého súrodenca zdedí API, ktoré tokeny smie použiť, kam súbor uložiť. Nový overlay môže byť len drawer alebo modal, tretí druh neexistuje.
  • „Ukáž, čo si postavil" – Každý nový komponent dostane v tom istom commite ukážku v Showcase a riadok v katalógu COMPONENTS.md. Audit nahlási každý, ktorému to chýba, takže katalóg sa nikdy nerozíde s kódom.
COMPONENTS.md 80 % „ukáž, čo si postavil" Showcase audit 80 % sedí → použi · nesedí → derivuj podľa receptu · nový → Showcase + COMPONENTS.md, inak audit COMPONENTS.md 80 % „ukáž, čo si postavil" Showcase audit 80 % sedí → použi · nesedí → derivuj podľa receptu nový → Showcase + COMPONENTS.md, inak audit

Sekcia anti-patternov v kontrakte vznikla práve z týchto auditov: každý riadok v nej je chyba z kalibračných buildov, ktorú agent reálne vyprodukoval a ktorá sa už nezopakovala.

Výsledok: keď agent staval layout alebo UI, vždy vedel, ako na to. Ani raz nešiel tvoriť UI podľa vlastného uváženia, vždy podľa vopred definovaných pravidiel.

Design systém máme. Teraz sa pozrime, ako definovať harness tak, aby generoval konzistentný frontend.

#Frontend aplikácie

##Aplikácia bez backendu

S hotovým design systémom sa môžeme pustiť do definície frontendu. Backend nechajme zatiaľ bokom. Chceme čo najskôr dostať aplikáciu do rúk, vyskúšať si ju a iterovať na tom, čo vidíme. Backend v tomto bode len pridáva komplexitu a čas, ktorý by sme my museli definovať a agent strávil jeho stavbou.

Ale ako dostať do ruky funkčnú aplikáciu bez backendu? Trik je nasimulovať backend na frontende, to coding agenti zvládnu hravo. Prvá verzia každej mojej aplikácie je preto vždy bez backendu: obsahuje iba frontend a ako databáza jej slúži lokálna pamäť prehliadača, pre web je to IndexedDB. Všetka funkcionalita, ktorá by inak žila na backende, je zatiaľ na frontende. Netrápi nás, že to raz bude treba preniesť: keď si po X iteráciách schválime finálnu podobu aplikácie, pridáme do harnessu pravidlá pre písanie backendu, starú appku zahodíme a spustíme nový build s backendom - jednoduché, ako vymeniť cartridge v tlačiarni.

lokálna DB klient vidí FE build · 4 hodiny backend prod DB testy · audit klient nevidí ešte nestaviame lokálna DB klient vidí FE build · 4 hodiny backend prod DB testy · audit klient nevidí ešte nestaviame

##Harness súbor po súbore

Ako to celé vyzerá v coding harnesse? Pozrime sa naň súbor po súbore. V ranej fáze projektu, keď sme stavali len frontend, obsahoval priečinok docs/ tieto dokumenty s vopred definovanými pravidlami:

  • ARCHITECTURE.md – Popisuje, z akých častí sa aplikácia skladá a ako spolu komunikujú: čo je obrazovka, čo je logika a kde sa ukladajú dáta. Zároveň funguje ako živý zoznam všetkého, čo sa v aplikácii postupne vytvorí, aby agent aj človek vždy videli aktuálny stav.
  • BOUNDARIES.md – Určuje hranice medzi jednotlivými časťami aplikácie – čo s čím smie súvisieť a čo nie, aby sa kód nezamotal. Obsahuje aj zoznam technológií a prístupov, ktoré v projekte zámerne nepoužívame, aby ich agent ani nezačal pridávať.
  • COMPONENTS.md – Katalóg všetkých stavebných prvkov rozhrania (tlačidlá, karty, tabuľky, formulárové polia) s popisom, na čo každý slúži. Agent má z týchto prvkov skladať nové obrazovky ako zo stavebnice, namiesto toho, aby zakaždým vymýšľal niečo nové.
  • DECISIONS.md – Denník dôležitých rozhodnutí: čo sme sa rozhodli a prečo. Vďaka nemu nikto neskôr nespochybní ani omylom nezvráti voľbu, ktorá mala svoj dôvod.
  • DESIGN_SYSTEM.md – Záväzný manuál pre tvorbu vzhľadu aplikácie: ako postupovať pri návrhu novej obrazovky, ktoré vizuálne pravidlá sú nemenné a čo je zakázané. Zabezpečuje, aby každá obrazovka vyzerala, akoby ju nakreslil ten istý dizajnér.
  • ROUTES.md – Mapa všetkých obrazoviek aplikácie a navigácie medzi nimi, vrátane toho, ktorá rola používateľa čo vidí. Agent podľa nej vie, kam novú obrazovku zaradiť a komu ju sprístupniť.
  • ERRORS.md – Jednotné pravidlo, ako aplikácia komunikuje chyby používateľovi: vždy rovnakým spôsobom, zrozumiteľne a bez prekvapení. Používateľ tak pri každom probléme dostane rovnakú, predvídateľnú skúsenosť.

Zoznam ber ako inšpiráciu, nie predpis. Každý projekt potrebuje iné pravidlá a iné veci, ktoré treba agentovi vynútiť.

Toto je alfa a omega pravidiel, ktoré agent musí dodržiavať, keď autonómne stavia aplikáciu. Nikdy ich nedávam do hlavného súboru pravidiel agenta, ako je CLAUDE.md, aby som ho nezahltil. Lepšia prax je mať v CLAUDE.md alebo AGENTS.md len index súborov: agent si prečíta ten, ktorý sa týka problému, ktorý práve rieši, či už je to architektúra, nové UI alebo niečo iné.

Calora
Quick Reference
Stack: React 19 + Vite + Tailwind CSS v4 + Dexie (IndexedDB)
Knowledge base: knowledge/ (roadmap, feature specs, data model)
Code docs: docs/ (design system, architecture, boundaries, components, decisions)
Critical Architecture Rules
No backend — Everything runs locally. No server.
Simulated auth — Login resolves a local UserAccount from IndexedDB; no server, no tokens, no password hashing. Roles gate the UI, not the data.
IndexedDB via Dexie — Single source of truth. Include id, createdAt, updatedAt on every table.
Local-first — App must work fully locally without backend.
Code Conventions
TypeScript strict mode, no any
Functional components + hooks only, no class components
Custom hooks for all reusable logic (src/hooks/)
Mobile-first, responsive design
Tailwind v4 (CSS-first config, @import "tailwindcss") — Tailwind classes only, no CSS modules or CSS-in-JS
Lucide React for icons
Path alias: @/* maps to src/*
UI Build — Pre-flight
Before writing JSX for any route-level page, run this loop in order. Do not skip.
1.Read the contract. Open docs/DESIGN_SYSTEM.md — it is the binding contract, not background reading. The concrete rules (templates, canvas color, app shell, anti-patterns) live there.
2.Read the showcase. Open src/pages/DesignSystem.tsx and locate the section that matches what you're building (page templates, shell, composition examples). Mirror its structure verbatim — don't translate from memory.
3.Compose, don't fork. For each piece of the screen, pick the closest primitive from docs/COMPONENTS.md. If something fits within ~80%, pass props — don't write a new variant.
4.Never invent tokens. Colors, radii, shadows, motion durations come from src/index.css. If a value seems missing, you're trying to do something the system rejects — re-read the anti-patterns section of DESIGN_SYSTEM.md.
5.Audit before "done". Run /sprint.design-audit at the end of every build session. It is a hard gate, not optional polish.
When in doubt: docs/DESIGN_SYSTEM.md + src/pages/DesignSystem.tsx are the source of truth, not memory.
Commands
npm test && npm run lint
Project Structure
knowledge/ # Product knowledge base roadmap/ # The roadmap — epics, each split into features features/ # One spec per feature (F001, F002, ...) — goal, acceptance criteria, layout entities.md # Data model — every entity with its attributes, lifecycle and relations docs/ # Code documentation DESIGN_SYSTEM.md # The binding visual contract — read before any UI work ARCHITECTURE.md # System overview, data layer, state mgmt, hooks/services registry BOUNDARIES.md # Dependency flow + import rules per layer, hook & component rules COMPONENTS.md # Catalog of primitives, composites, and domain components DECISIONS.md # Technical decision log (Dxxx entries with rationale) ERRORS.md # Error handling pattern (centered ErrorDialog; toasts are success-only) ROUTES.md # Route table, navigation structure, deep-linking rules src/ # Source code components/ # Reusable UI components pages/ # Route-level page components hooks/ # Custom React hooks db/ # Dexie database schema and operations types/ # TypeScript interfaces services/ # Business logic data/ # Static data lib/ # Utilities test/ # Test setup
CLAUDE.md ako index a za ním priečinok docs/ z harnessu, dlhšie súbory skrátené na ukážku. Agent si prečíta len ten, ktorý sa týka jeho problému.

##Simulovaný backend a šev pod hookmi

Teraz späť k simulácii backendu. Dôležité je, ako vyzerá zvnútra. Nie je to hromada mock dát v komponentoch. Je to plnohodnotná databáza v prehliadači, napísaná presne tak, ako by vyzerala na backende. Tabuľky v IndexedDB sú jedna k jednej kópiou dátového modelu z harnessu: rovnaké entity, rovnaké názvy, každý záznam má UUID ako primárny kľúč, vzťahy idú cez cudzie kľúče. Aj to, čo v prehliadači reálne nejde, ako odoslanie e-mailu alebo SMS, sa nasimuluje. Každé takéto odoslanie sa zapíše ako záznam do tabuľky notifikácií a odkaz, ktorý by inak prišiel mailom, sa ukáže rovno na obrazovke. Napríklad taká časová os zákazky funguje rovnako, ako bude fungovať naostro, a budúci backend má pripravený šev, kam sa napojí (reálne sa to celé prepíše, ale kto vie..., skúška dobrého dizajnu architektúry).

nad zipsom sa nešije nič šev komponenty · stránky · hooky rovnaké v oboch fázach služby · IndexedDB simulovaný backend v prehliadači fáza 1 · lokálna appka služby v Laraveli · Postgres rovnaké entity, rovnaké názvy produkcia · prizipsuje sa namiesto IndexedDB nad zipsom sa nešije nič šev komponenty · stránky · hooky rovnaké v oboch fázach služby · IndexedDB simulovaný backend v prehliadači fáza 1 · lokálna appka služby v Laraveli · Postgres rovnaké entity, rovnaké názvy produkcia · prizipsuje sa namiesto IndexedDB

Aby simulácia nepresiakla do UI, harness drží vrstvy oddelené a BOUNDARIES.md to vynucuje ako pravidlo importov: typy, potom databáza, nad ňou služby s biznis logikou, nad nimi hooky, a až nad tým komponenty a stránky. Komponent ani stránka nikdy nesmie importovať databázu ani službu, všetky dáta tečú cez hooky. Toto bolo v rozhodnutiach harnessu zapísané od prvého dňa s jediným dôvodom: keď príde backend, mení sa vrstva pod hookmi, nie obrazovky.

#Definovanie, čo sa bude stavať

##Roadmapa a epicy

Design systém a pravidlá pre frontend máme. Ostáva to najpodstatnejšie: čo staviame. Na to slúži roadmapa a jej špecifikácie funkcionalít. Roadmapa sa pozerá na aplikáciu zvrchu a definuje moduly (a teda epicy), ktoré treba postaviť, aby vznikla funkčná aplikácia. Každý modul sa rozpadá na niekoľko funkcionalít a každá má popísané, ako funguje.

roadmapa.md epicy 64 specov feature spec cieľ interakcia AC × 2–3 krátky, o produkte, nie o kóde roadmapa.md epicy 64 specov feature spec cieľ interakcia AC × 2–3 krátky, o produkte, nie o kóde

Scope vznikol z deviatich discovery workshopov z úvodu. Roadmapa z neho má osem epicov so 64 špecifikáciami funkcionalít. Sedem epicov patrilo prvej fáze. Ôsmy, flotily, prišiel v druhej fáze, ale jeho scope bol vyskúmaný v tých istých workshopoch, žiadne ďalšie sa nekonali.

##Špecifikácie: krátke a o produkte

Každá funkcionalita má vlastný .md dokument, ktorý popisuje, ako má fungovať. Nie je to klasická špecifikácia, ako ju poznáš z raných spec-driven frameworkov. Moja má tri časti: Goal na tri až päť riadkov, dve až tri acceptance kritériá a sekciu Layout & Design, ako má byť zložené UI. Pri čisto backendovej funkcionalite tá tretia časť chýba. Do feature specov sa zvyknú písať aj ďalšie veci: dátová entita, jej vstupy a výstupy, technická špecifikácia, ako to celé naprogramovať. Ja to nerobím. Všetky pravidlá, ako niečo implementovať, sú raz a všeobecne zapísané v harnesse, netreba ich opakovať pri každej funkcionalite. Dnešné jazykové modely sú dosť inteligentné na to, aby funkcionalitu implementovali samy. Tvoja úloha je dať agentovi dobré pravidlá na úrovni coding harnessu, zvyšok nechaj na neho.

Špecifikácie tak ostávajú čo najjednoduchšie, aby sa reviewovali ľahko, bez zbytočných detailov. Jedna vec v nich ale chýbať nesmie: pri každej funkcionalite aj obrazovke je uvedené, ktorej používateľskej roly sa týka. Agent si to sám nedomyslí a v aplikácii so štyrmi rolami je „kto čo smie vidieť a urobiť" najčastejší zdroj chýb. Z tej jednej vety neskôr vyrastú testy autorizácie aj user journeys.

Roadmap: Calora
Status: Active · Data model: entities.md
Overview
React-based build of the partner portal, the admin portal and the customer portal. Eight epics, journey-ordered: Foundation → Partner Onboarding → Client Registration → Fault Intake → Case Lifecycle → Reporting → Acquisition → Customer Portal. Role says who owns a feature — Admin, Partner, Customer, or Tech for platform work and background jobs with no user role.
<!-- Trimmed for the article — the earlier epics stand here in the real doc (and in yours). -->
5. Case Lifecycle
How a case moves from start to done. A case is born at the fault call (epic 4) and opened at intake, once the device is on the bench. Ops manages it through the repair, then closes it with the final price and a short repair summary. That accrues the partner's commission and triggers the close email. The partner can see their own cases the whole way.
Features
IDFeatureRoleDescriptionStatus
F021All cases listAdminEvery case in one place. Filter by status and type.Built
F022Case detailAdminFull view of one case with its timeline; everything editable while open, including swapping the case type mid-flight.Built
F023Mark case doneAdminClosing dialog that captures the total repair price and a short repair summary, then flips the case to done.Built
F024Commission accrualTechWhen a case closes, the partner's commission is recorded automatically.Built
F025Partner close notificationTechOn close, an email goes to the attributed partner letting them know the case is finished.Built
F026My casesPartnerPartner's own case list — the commission-earning ones and the self-pay rows (visible, zero commission).Built
F027Case detailPartnerRead-only view of one of their own cases: device, dates, status, repair total, commission earned, summary.Built
Screens
RouteScreenPortal
/admin/casesAll cases listAdmin
/admin/cases/:idCase detail; the mark-done dialog opens from hereAdmin
/partner/casesMy casesPartner
/partner/cases/:idCase detail (partner)Partner
<!-- Trimmed for the article — the remaining epics follow, one section each. -->
Epic z roadmapy a jeden z jeho specov, presne ako ich číta agent.

##Dátový model ako hotový vstup

K týmto súborom patrí ešte jeden dokument, ktorý nepatrí k pravidlám kódu, ale k produktu: dátový model. Je to jeden súbor, entities.md, ktorý popisuje všetky entity aplikácie aj s ich typmi. Má vyše tisíc riadkov a vznikal už počas workshopov v knowledge harnesse, dávno pred prvým buildom. Rovnako ako roadmapa a špecifikácie prešiel do coding harnessu ako hotový vstup, nie ako niečo, čo by agent vymýšľal pri builde.

roadmapa · 64 specov coding harness zadanie: čo postaviť dátový model entities.md · vyše 1000 riadkov vznikol vo workshopoch, dávno pred prvým buildom roadmapa · 64 specov coding harness zadanie: čo postaviť dátový model entities.md · vyše 1000 riadkov vznikol vo workshopoch, dávno pred prvým buildom

Každá entita v ňom má rovnakú štruktúru. Napríklad zákazka:

  • Účel – jedna veta, načo entita v systéme je.
  • Atribúty – tabuľka polí, pri každom typ, či je povinné, z ktorého workshopu alebo rozhodnutia pochádza a poznámka, čo znamená.
  • Životný cyklus – stavy a prechody medzi nimi: čaká na príjem → otvorená → hotová.
  • Vzťahy – jedna zákazka patrí jednému vozidlu a jednému klientovi.

Práve z tohto dokumentu agent odvodil tabuľky v IndexedDB a neskôr migrácie v Postgrese pre backend.

Data Entities
Status: review · Sources: 9 client workshops + decisions + roadmap + specs
<!-- Trimmed for the article — the earlier entities stand here in the real doc (and in yours). -->
3.6 Case
Layer: PARTNER module. Purpose: A reported fault and its repair job. The unit that triggers partner commission and the central object on the monthly statement.
Attributes
FieldTypeRequiredSourceNotes
case_iduuidyessystemPK
device_iduuid (FK)yes
client_iduuid (FK)yesResolved via device
partner_iduuid (FK)optionalD008, D012Snapshot from the active Attribution when the case is created
case_typeenum: attributed / incentivized_self_payyes (at intake)D011Determined at intake (F019)
coverage_pathenum: warranty / service_plan / out_of_warranty / otheryes (at intake)D011, D050Coverage alone decides it (D050)
case_statusenum: pending_intake / start / doneyesD015pending_intake = created at the fault call, waiting for intake · start = device on the bench · done = client can pick up
fault_reported_attimestampyesD006, D050First-call time ≈ fault. Inline-editable while open
total_repair_eurdecimal(10,2)yes (at done)D014Entered by Ops when closing. Drives the commission base
case_open_time · case_done_time · termis_job_id · repair_summary_comment · commission_percentage_snapshot · notes
Lifecycle
pending_intake ──▶ start ──▶ done │ └─ created at the fault call (F018); waits for the intake, which opens it. case_type may flip mid-flight — must remain editable.
Partner email notifications fire when the case opens (→ start) and when it closes (→ done) — no email on creation.
Relationships
1 Case → 1 Device, 1 Client
1 Case → 0..1 Partner (the attributed partner)
1 Case → 0..1 Commission (for the attributed partner)
Zákazka v entities.md: účel, atribúty, životný cyklus, vzťahy.

#Kalibrácia: dva buildy, kým sa z promptu stal kompilátor

##Harness je prompt

Keď je definovaný design systém, pravidlá kódu a roadmapa so špecifikáciami, môže bežať prvý testovací build. To je moment, keď sa práca zhmotní. Ak je všetko správne, uvidíš funkčnú aplikáciu so všetkými UI prvkami, interakciami a funkciami z roadmapy: plne klikateľnú a na oko hotovú, postavenú v jednom autonómnom rune coding agenta. Jediný prompt, ktorý som napísal, bol „Naprogramuj celú aplikáciu podľa roadmapy". Harness je tvoj prompt. Toto bol len spúšťač.

claude — ~/calora ~/calora (main) $ claude > Naprogramuj celú aplikáciu podľa roadmapy ● Čítam harness: CLAUDE.md · DESIGN_SYSTEM.md · roadmap.md ● Roadmapa: 8 epicov · 64 špecifikácií · dátový model ● Staviam appku, epic po epicu ✓ 1 Foundation ✓ 2 Partner Onboarding 3 Client Registration · 4 Fault Intake · 5 Case Lifecycle · 6 Reporting · 7 Acquisition · 8 Customer Portal ~4 h · choď medzitým do fitka claude — ~/calora ~/calora (main) $ claude > Naprogramuj celú aplikáciu podľa roadmapy ● Čítam harness: CLAUDE.md · DESIGN_SYSTEM.md · roadmap.md ● Roadmapa: 8 epicov · 64 špecifikácií · dátový model ● Staviam appku, epic po epicu ✓ 1 Foundation ✓ 2 Partner Onboarding 3 Client Registration · 4 Fault Intake · 5 Case Lifecycle · 6 Reporting · 7 Acquisition · 8 Customer Portal ~4 h · choď medzitým do fitka

##Prvý run je kalibračný

Prvý run býva kalibračný. Ukáže, ako dobre máš definovaný design systém, pravidlá kódu a hlavne roadmapu so špecifikáciami. Celú aplikáciu si preklikaj, všímaj si odchýlky od svojho zámeru a každú nezrovnalosť si vystopuj späť do harnessu. Ak je niečo zvláštne, s vysokou pravdepodobnosťou to opravíš pridaním pravidla, jeho úpravou alebo dodefinovaním. To isté platí pre špecifikácie produktu: keď niečo nefunguje alebo nevyzerá, ako má, väčšinou ťa od toho delí jedna či dve úpravy pravidiel v harnesse.

U mňa to boli drobnosti: dôležité komponenty, ktoré som zabudol pridať do katalógu a do všeobecných pravidiel (napríklad toastre), špecifické rozloženie sidebaru pre rôzne persony alebo detaily v tom, ako sa skladajú formulárové stránky.

build 1 build 2 build 3 oprav spec oprav harness ~95 % rovnaká z toho istého specu prvé dva buildy neboli o appke — boli o harnesse build 1 build 2 build 3 oprav spec oprav harness ~95 % rovnaká z toho istého specu prvé dva buildy neboli o appke — boli o harnesse

##Master harness: čo agent domyslel, prenes späť

Kalibračné runy majú ešte jeden dôvod. Pri prvom builde vidíš aplikáciu prvýkrát naozaj celú, a agent pri stavbe zaplnil aj diery, ktoré ti v harnesse chýbali: doplnil komponenty, ktoré v katalógu neboli, dopísal pravidlá, urobil rozhodnutia. Niektoré z nich sú podstatné. Pre teba ako architekta a orchestrátora je preto po každom kalibračnom rune povinný review toho, čo agent do harnessu a design systému pridal. Všetko dôležité alebo zabudnuté prenes do počiatočného stavu coding harnessu, do master verzie, z ktorej štartuje každý ďalší build. Harness sa tak nekalibruje len tvojimi opravami, ale aj tým, čo si agent sám domyslel.

master harness počiatočný stav každého buildu build + + kalibračný build agent doplnil, čo chýbalo review čo ide späť do mastera toastre do katalógu sidebar podľa persony skladanie formulárov jednorazový hack len to podstatné zvyšok zahodíš spolu s appkou čo agent domyslel, ide do mastera kalibrácia nie je len oprava chýb — aj zber toho, čo agent domyslel čo agent domyslel, ide do mastera master harness počiatočný stav každého buildu build + + kalibračný build agent doplnil, čo chýbalo review čo ide späť do mastera toastre do katalógu sidebar podľa persony skladanie formulárov jednorazový hack len to podstatné zvyšok zahodíš spolu s appkou kalibrácia nie je len oprava chýb — aj zber toho, čo agent domyslel

Potom celú aplikáciu zahodíš a spustíš run znovu. Nestojí ťa to takmer nič, len trochu času a tokenov z predplatného. A sám uvidíš: ak máš pravidlá dobre definované, aplikácia bude na 95 percent vždy rovnaká.

Jeden takýto build, ktorý staval iba frontend, trval štyri hodiny. Odporúčam naplánovať ho ako task na pozadí a ísť medzitým do fitka alebo von.

##Iterácia s klientom

Gratulujem, máš systém, kde vstup je spec, výstup je appka, a appka je disposable: zahodiť ju je lacnejšie než ju opravovať. Teraz môžeš ísť za klientom, hrať sa s appkou, pýtať si feedback a iterovať, kým nie ste obaja spokojní. Na tomto projekte som spustil šesť frontend buildov: prvé dva boli kalibračné, ďalšie štyri priniesli zásadný feedback od klienta.

Najväčšie čaro je v tom, že feedback som neimplementoval vibe-codingom priamo v kóde, ale na úrovni harnessu a špecifikácií. Starú appku som zahodil a novú vygeneroval už s feedbackom, bez toho, aby som rozbil existujúci kód.

V praxi to vyzeralo takto: klient si preklikal appku a zistil, že v tabuľkách mu chýba triedenie podľa stĺpcov. Do design systému som dopísal, že každá tabuľka musí mať interaktívne triedenie podľa stĺpcov. Ďalší build ho už obsahoval.

tabuľky sa nedajú triediť 1 · klient si preklikal appku feedback DESIGN_SYSTEM.md + 2 · jeden riadok do harnessu build 3 · ďalší build ho už mal tabuľky sa nedajú triediť 1 · klient si preklikal appku feedback DESIGN_SYSTEM.md + 2 · jeden riadok do harnessu build 3 · ďalší build ho už mal

Triedenie tabuliek je zámerne triviálny príklad. Feedback od klienta býva väčšinou oveľa ďalekosiahlejší: inak poskladaný tok obrazoviek, iné rozdelenie práce medzi rolami, celý kus funkcionality, ktorý na workshopoch nikoho nenapadol. Cesta je ale vždy tá istá. Zmena ide do harnessu a špecifikácií, nie do kódu, a ďalší build ju už má v sebe. A práve toto je najväčšia hodnota celého systému: veľký feedback stojí rovnako málo ako malý. Klasický vývoj má cenu zmeny úmernú tomu, koľko kódu už existuje. Tu je úmerná tomu, koľko riadkov pribudne v harnesse. Že to platí aj pre zmenu, ktorá rozbije dátový model, ukáže ďalšia kapitola.

#Keď nový modul rozbije návrh: zmena bez bolesti

Jedna z najväčších nočných môr pri greenfield projekte: produkt je takmer hotový a zistíš, že musíš prekopať jeho časť. Stalo sa to aj mne. Nie preto, že by klient chcel novú funkcionalitu, ale preto, že projekt mal dve fázy a pri plánovaní prvej som nedomyslel, ako do riešenia zapadne modul druhej. Prišiel nový scope a rozbil aktuálny návrh aplikácie.

##Čo sa stalo

Druhá fáza pridala modul flotíl: portál, kde si firemný zákazník sám spravuje svoje autá, termíny a servisnú históriu. Vozidlo, kľúčová entita celého systému, zrazu potrebovalo patriť dvom svetom naraz, interným procesom aj flotile, a dátový model prvej fázy s tým nepočítal. Niektoré väzby bolo treba prekopať. A s novým modulom prišiel do adminu nový svet funkcionalít, takže doterajšie delenie obrazoviek prestalo dávať zmysel. Presne ten stav, ktorý poznáš z bežných produktov: pridá sa nová funkcionalita bez refaktoru existujúcej a rozhranie začne pôsobiť chaoticky.

pred interné procesy vozidlo flotily praská nový modul nalepený vozidlo si ťahajú dva svety, UI je chaos po interné procesy flotily + nový modul nepoznajú sa spoločné jadro vozidlo · termíny · notifikácie · účty nový modul zapadol jedno jadro, dva moduly, čisté UI pred interné procesy vozidlo flotily praská nový modul nalepený vozidlo si ťahajú dva svety, UI je chaos po interné procesy flotily + nový modul nepoznajú sa spoločné jadro vozidlo · termíny · notifikácie · účty nový modul zapadol jedno jadro, dva moduly, čisté UI

##Oprava na úrovni architekta, nie kódu

V klasickom vývoji by táto zmena stála týždeň až dva: niekto musí zmapovať, čoho všetkého sa dotkne, prerobiť dátový model, migrácie, obrazovky a všetko, čo na nich stojí. My sme nič z toho nerobili v kóde. Celá oprava sa odohrala v harnesse, na najvyššej úrovni, kde rozhoduje architekt:

  • Impact assessment. Agent prešiel roadmapu, všetky špecifikácie a dátový model a zmapoval, čo nový modul rozbije a ktorých špecifikácií sa dotkne.
  • Návrh zmeny. Spolu sme navrhli nové jadro modelu: vozidlo ako spoločnú entitu a nad ňou dva moduly, interné procesy a flotily, ktoré sa navzájom nepoznajú. Agent zmenu premietol do celej roadmapy a všetkých dotknutých špecifikácií naraz, aby nič z toho, čo sme už dôsledne definovali, neostalo nekonzistentné.
  • Upratanie UI. Admin navigácia sa pregrupovala do nových celkov tak, aby nový modul zapadol, nie aby sa nalepil.

Všetko za jeden deň. Na druhý deň sme starú appku zahodili a nový build už mal v sebe portál pre flotily.

zmena portál pre flotily impact assessment vozidlo má vlastníka v sebe admin navigácia už nesedí specy, ktoré sa rozbijú agent zmapuje, čo sa rozbije navrhne roadmap.md + ôsmy epic · nová admin navigácia entities.md · dátový model +400 riadkov · jadro + 2 moduly dotknuté specy + poznámky · decision log +3 1 deň v harnesse · na druhý deň build s flotilami zmena portál pre flotily impact assessment vozidlo má vlastníka v sebe admin navigácia už nesedí specy, ktoré sa rozbijú agent zmapuje, čo sa rozbije navrhne roadmap.md + ôsmy epic · nová admin navigácia entities.md · dátový model +400 riadkov · jadro + 2 moduly dotknuté specy + poznámky · decision log +3 1 deň v harnesse · na druhý deň build s flotilami

Toto nie je príbeh o chybe v návrhu a jej oprave. Je to feature systému. Zmenu scopu, ktorá inde znamená týždne bolesti, si tu môžeme dovoliť, lebo appku nedržíme v kóde, ale v definícii. Sme architekti: zmenu robíme na najvyššej úrovni a kód sa z nej prekompiluje. Pomohlo aj to, že sa to dialo vo frontend fáze, backend sa v mojom procese píše vždy až na konci. Nemali sme kód, na ktorom by sme si zakladali. Mali sme definíciu, ktorú sme opravili, a appku, ktorú sme zahodili a nechali postaviť znova.

#Pridajme backend a spustime produkčný run

##Prepnutie harnessu na backend

Keď je celý návrh aplikácie hotový, so všetkými funkcionalitami, klient je spokojný a nič nechýba, je čas prepnúť coding harness z režimu „len frontend" na plnohodnotnú aplikáciu s backendom a produkčným nasadením. Toto je zásadný checkpoint. Musí byť dobre definovaný, aby jeden autonómny run zvládol celú aplikáciu: frontend, backend, aj testovanie aplikácie. Pre klienta sa navonok nič nemení, appka vyzerá rovnako ako tá, ktorú si preklikával. Len hladina klesla a pod ňou sa stavia všetko ostatné.

lokálna DB → migrácie klient vidí to isté ako predtým hladina vo fáze 1 backend · Laravel Postgres testy · audit deploy hladina klesla staviame všetko lokálna DB → migrácie klient vidí to isté ako predtým hladina vo fáze 1 backend · Laravel Postgres testy · audit deploy hladina klesla staviame všetko

Znamená to prejsť náš coding harness v priečinku docs/ a predefinovať súbory, kde je popísaná architektúra, hranice a ostatné pravidlá, z lokálnej aplikácie na aplikáciu s backendom. Backendy píšem v Laraveli.

Je to backendový framework s najucelenejším ekosystémom, aký poznám: jeden tím vyvíja jadro aj oficiálne balíky na všetko, čo produkčná appka potrebuje. Autentifikáciu a účty (Fortify), fronty a plánované úlohy (Horizon), e-maily a notifikácie, súbory, monitoring (Pulse, Nightwatch), testovanie (Pest), prepojenie s Reactom bez API vrstvy (Inertia) a hosting, kde sa to celé nasadí jedným pushom (Laravel Cloud). Pre agenta je to ideálne: každý problém má jedno kanonické, dobre zdokumentované riešenie, takže nemá kde improvizovať. Mne ostáva definovať pravidlá: ako servírovať frontend, ako riešiť autentifikáciu a zabezpečenie, ako aplikáciu testovať.

##Čo prežilo z lokálnej appky

Nič, nič sa nemigrovalo. Frontend sa napísal nanovo spolu s backendom, v jednom rune, z tých istých špecifikácií. Z lokálnej verzie prežil len design system, komponenty sa preniesli do nového projektu ako hotová stavebnica. Schéma z IndexedDB sa stala migráciami v Postgrese, hooky sa stali controllermi, ktoré posielajú stránkam dáta cez Inertia props. Každý build, lokálny aj produkčný, žil na vlastnej git branchi a starý sa nikdy neupravoval, len sa vytvoril nový. Úlohou dizajn fázy nebolo vyprodukovať kód, ktorý si necháme. Jej úlohou bolo overiť návrh aplikácie a dátový model s klientom skôr, než sa dotkneme backendu a finálneho odovzdania projektu. Kód bol vedľajší produkt a bol na zahodenie.

lokálna appka · fáza 1 overené s klientom produkt ✓ · dátový model ✓ design system · komponenty jediné, čo sa sťahuje IndexedDB schéma hooky stránky kód: vedľajší produkt specy design system · komponenty Postgres migrácie · nové controllery · Inertia props · nové stránky · nové produkčná appka · nanovo zo specov lokálna appka · fáza 1 overené s klientom produkt ✓ · dátový model ✓ design system · komponenty jediné, čo sa sťahuje IndexedDB schéma hooky stránky kód: vedľajší produkt specy design system · komponenty Postgres migrácie · nové controllery · Inertia props · nové stránky · nové produkčná appka · nanovo zo specov

##Dva nové dokumenty

Oproti frontendovej fáze pribudli do harnessu dva nové dokumenty:

  • SERVICES.md – Záväzná mapa „problém → balík": každá potreba aplikácie (autentifikácia, fronty, e-maily, PDF, vyhľadávanie, súbory) má priradený jeden oficiálny Laravel balík alebo samotný framework. Je to pravidlo o first-party balíkoch zo sekcie o stacku, zapísané tak, aby si ho agent nemusel vykladať sám.
  • USER_JOURNEYS.md – Katalóg všetkých ciest používateľa naprieč rolami a portálmi, každá s krokmi a očakávaným výsledkom. Je to checklist, podľa ktorého sa dá celá aplikácia preklikať v prehliadači, rola po role. Ako sa použil, ukážem na konci kapitoly.

##Testovacia stratégia a verifikačná brána

Testovacia stratégia si pokojne zaslúži vlastný dokument v harnesse. Ja som ju dal ako všeobecné pravidlo rovno do CLAUDE.md, ako jedinú výnimku z pravidla, že CLAUDE.md je len index: je príliš dôležitá na to, aby si ju agent musel ísť hľadať. Pravidlo je krátke: každá funkcionalita sa odovzdáva aj s testami v Peste, minimálne happy path a autorizácia pre každú rolu. Kto čo smie vidieť a robiť je v aplikácii so štyrmi rolami najčastejší zdroj chýb, preto je to povinné.

K tomu patrí verifikačná brána, šesť príkazov, ktoré musia prejsť, kým sa čokoľvek vyhlási za hotové:

  • testy na SQLite, pre rýchlosť,
  • tie isté testy ešte raz na Postgrese, pre zhodu s produkciou,
  • formát backend kódu,
  • typová kontrola TypeScriptu,
  • lint,
  • produkčný build.

A jedna veta, ktorá sa ukázala ako najdôležitejšia: orchestrátor bránu spúšťa sám a nikdy neverí subagentovi, že „testy prešli". Kto je orchestrátor, vysvetlím hneď.

##Orchestrátor a dva audity

Produkčný run spúšťa ten istý prompt ako každý predchádzajúci: „Naprogramuj celú aplikáciu podľa roadmapy". Rozdiel je v tom, koľko toho agent musí udržať naraz: pravidlá pre frontend, backend, UI, UX, testy a nasadenie, desať hodín v kuse. Pri takýchto veľkých runoch sa mi osvedčilo nespúšťať jedného agenta, ale orchestrátora, ktorý dozerá na celý proces implementácie. Na každý epic z roadmapy spustí implementačných agentov, čaká na ich reporty, skontroluje ich prácu, spustí testovacích a audit agentov, a až keď je epic zelený a commitnutý, ide na ďalší. Sám nič neprogramuje, koordinuje a validuje.

orchestrátor Claude agent · 1M tokenov kontextu spúšťa reporty agent · implementácia kód aj testy k epicu agent · testy Pest · SQLite aj Postgres agenti · audit coding audit · design audit bránu spúšťa sám, subagentovi neverí verifikačná brána · 6 príkazov commit → ďalší epic epic po epicu, kým nie je roadmapa hotová orchestrátor Claude agent · 1M tokenov kontextu spúšťa reporty agent · implementácia kód aj testy k epicu agent · testy Pest · SQLite aj Postgres agenti · audit coding audit · design audit bránu spúšťa sám, subagentovi neverí verifikačná brána · 6 príkazov commit → ďalší epic epic po epicu, kým nie je roadmapa hotová

Audity sú dva, lebo vieme, že agenti pravidlá nedodržia vždy na sto percent. Design audit už poznáš z kapitoly o design systéme: kontroluje, či obrazovky držia dizajn kontrakt, či má každý nový komponent ukážku v Showcase a záznam v katalógu. Coding audit je nový a robí to isté pre kód: prejde frontend aj backend epicu a porovná ho s pravidlami v našom coding harnesse. Oba bežia ako subagenti po dokončení každého epicu, nálezy sa opravia a commitnú, a až potom ide run ďalej. Takto pokryješ väčšinu problémov s nedodržiavaním pravidiel. Ako si taký audit skill vytvoriť? Buď ho napíšeš ručne, alebo necháš agenta zanalyzovať tvoj coding harness a skill ti napíše sám. To isté platí pre testovaciu stratégiu.

##Desať hodín bez jedinej otázky

Produkčný run trval desať hodín. Bola to jedna session, ktorá bežala autonómne na mojom počítači, bez prerušenia a bez jedinej otázky od orchestrátora: všetko, čo potreboval vedieť, mal v harnesse. Výsledok: 30 migrácií, 19 modelov, 33 controllerov, 64 stránok, 947 testov so 7 468 asserciami, štyri používateľské role a rozhrania. Úctyhodný rozsah aplikácie.

jedna session, desať hodín otázky: 0 · reštarty: 0 · pády: 0 0 h 5 h 10 h jediné výchylky: commit po každom epicu a vypadlo z toho 30 migrácií 19 modelov 33 controllerov 64 stránok 947 testov · 7 468 assercií 4 role a rozhrania jedna session, desať hodín otázky: 0 · reštarty: 0 · pády: 0 0 h 5 h 10 h jediné výchylky: commit po každom epicu a vypadlo z toho 30 migrácií 19 modelov 33 controllerov 64 stránok 947 testov · 7 468 assercií 4 role a rozhrania

Nešiel som do toho naslepo. Za sebou sme mali šesť frontend runov, takže sme vedeli, že harness drží. Pred ostrým produkčným runom pribudli ešte dva testovacie runy backendu a jeden produkčný run v plnom rozsahu, len aby sme videli, kde sú hranice agentov v takomto meradle a či takto dlhý autonómny task zvládnu. Nebol to experiment, ale kalkulovaná voľba: z predchádzajúcich projektov som mal dosť skúseností s tým, čo agenti utiahnu. Dokopy tak aplikácia vznikla desaťkrát a ani raz nič nepadlo ani sa nereštartovalo. Žiadne extra náklady na agentov: celý run bežal na mojom bežnom predplatnom Anthropicu za 200 eur mesačne.

appka vznikla desaťkrát každý run na vlastnej git branchi, starý sa nikdy neupravoval 200 € mesačne · bežné predplatné 6 × frontend 2 × backend test skúšobný ostrý deväť nájazdov, jeden ostrý run · 10 h appka vznikla desaťkrát každý run na vlastnej git branchi, starý sa nikdy neupravoval 200 € mesačne · bežné predplatné 6 × frontend 2 × backend test skúšobný ostrý deväť nájazdov, jeden ostrý run · 10 h

##Audity v akcii

Audity si svoju úlohu odpracovali. Coding audit zachytil napríklad porušenú konvenciu písania backendových controllerov. Design audit našiel stránku, kde si agent vymyslel vlastnú hlavičku namiesto existujúceho komponentu PageHeader, a nové komponenty bez záznamu v katalógu. Nálezy sa opravili, commitli a run išiel ďalej.

implementačný agent driftuje od pravidiel kurz = pravidlá v harnesse audit audit audit konvencia controllerov vlastné usporiadanie namiesto šablóny komponent bez záznamu v katalógu audit ho po každom epicu stiahne späť, ešte počas runu implementačný agent driftuje od pravidiel kurz = pravidlá v harnesse audit audit audit konvencia controllerov vlastné usporiadanie namiesto šablóny komponent bez záznamu v katalógu audit ho po každom epicu stiahne späť, ešte počas runu

##Testy a päťdesiat vyklikaných journeys

Testy písal agent spolu s každou funkcionalitou, tak ako to káže pravidlo v CLAUDE.md. Počet testov sám o sebe hovorí málo, počet assercií hovorí, koľko vecí každý test reálne overuje, a necelých osem na test znamená, že testy nie sú len kontrola, či stránka nespadla.

Lenže testy sa dajú napísať aj zle a agent, ktorý testuje vlastný kód, má sklon testovať to, čo napísal, nie to, čo mal napísať. Preto sme po dokončení produkčného runu spustili ešte jeden samostatný run: agent dostal USER_JOURNEYS.md, otvoril prehliadač a appku reálne vyklikával rolu po role. Ten dokument nevznikol po rune, ale pred ním: agent ho vygeneroval z roadmapy a špecifikácií, ja som ho skontroloval a od tej chvíle zrkadlí všetko, čo sa v appke dá robiť, rola po role. Agent mal navyše inštrukciu správať sa ako neposlušný používateľ: skúšať appku rozbiť, zadávať nezmysly, klikať tam, kam nemá. Tá istá technika sa neskôr hodí pri security review.

Prihlásil sa, prešiel každý flow, otvoril stiahnuté prílohy, skontroloval odoslané e-maily. Nič neopravoval, len zapisoval každú nezrovnalosť. Výsledok po päťdesiatich journeys: žiadny blocker, žiadna funkčná chyba v logike aplikácie. Našiel dve drobné chyby, dve nekonzistencie v demo dátach a jednu odchýlku dokumentácie od kódu. Všetko sme potom opravili dodatočne.

staviteľ si kontroluje vlastnú stenu 947 testov · 7 468 assercií testuje to, čo napísal a potom kolaudácia: nezávislý run, iba prehliadač 50 user journeys · každá rola prihlásiť, prejsť každý flow prílohy, odoslané e-maily nič neopravovať, len zapisovať blockery 0 · chyby v logike 0 bezpečnosť 1 · drobné 2 demo dáta 2 · dokumentácia 1 niekto zvonku, kto kód nepísal staviteľ si kontroluje vlastnú stenu 947 testov · 7 468 assercií testuje to, čo napísal a potom kolaudácia: nezávislý run, iba prehliadač 50 user journeys · každá rola prihlásiť, prejsť každý flow prílohy, odoslané e-maily nič neopravovať, len zapisovať blockery 0 · chyby v logike 0 bezpečnosť 1 · drobné 2 demo dáta 2 · dokumentácia 1 niekto zvonku, kto kód nepísal
User Journeys — browser smoke test plan
Kompletný katalóg user journeys naprieč všetkými portálmi. Slúži ako opakovateľný checklist pre per-role browser smoke. Pred behom: sail artisan migrate:fresh --seed (demo personas, heslo password pre všetky: owner@ / ops@ / technik@ / registry@ / firma@ / zakaznik@calora.test).
Konvencia ID: PUB (pre-auth/public) · OWN (admin ako Owner) · OPS (Operations Manager) · TECH (Servisný technik) · FRM (B2B firemný zákazník, portfólio zariadení) · B2C (individuálny zákazník) · X (cross-cutting).
OWN-12 — Firmy & zákazníci (admin ako Owner, owner@calora.test)
KrokAkciaOčakávané
1Otvoriť /admin/portfoliosZoznam portálových zákazníkov (Customer): firmy aj jednotlivci
2Prepnúť filter Firmy / Jednotlivci (B2C)Zoznam sa prefiltruje podľa typu zákazníka
3Pridať firmuFirma vznikne v stave invited, flash ukáže aktivačný link
4Otvoriť detail firmyZariadenia, servisné záznamy a požiadavky firmy na jednej stránke
5Pridať zariadenie: najprv voľné sériové číslo, potom obsadenéVoľné prejde; obsadené ukáže checkbox prevodu a uloží sa až po potvrdení (confirm_transfer)
6Upraviť Termíny (dátum + pripomienka)Edit modal uloží dátum a prepne pripomienku; termín bez dátumu ostáva „nezadané“
7Pridať manuálny servisný záznamZáznam sa objaví v Histórii zariadenia
8Poslať aktiváciuModal potvrdí odoslanie a ukáže jednorazový aktivačný link, použiteľný v PUB-5
<!-- Skrátené pre článok — medzi týmito dvoma stoja journeys ostatných rolí. -->
B2C-3 — Objednanie servisu (individuálny zákazník, zakaznik@calora.test)
KrokAkciaOčakávané
1Prihlásiť sa a otvoriť /portalPrehľad jedného zariadenia: najbližší termín a CTA „Objednať servis“; bez zariadenia sa ukáže EmptyState
2Otvoriť detail zariadeniaTermíny so stavom (zelená / oranžová / červená) a História servisu; história sa ukáže len pri overenom prepojení zákazník ↔ zariadenie
3Objednať servis: typ, dva preferované termíny, popis poruchy, Náhradné kúreniePožiadavka sa odošle; platforma neukladá konkrétny čas, len preferencie
4Otvoriť /portal/bookingsNová požiadavka je v stave „Čaká“
5Otvoriť jej detail a zrušiť jurequested → cancelled; z filtra „Čaká“ zmizne, vo „Zrušené“ pribudne
6Skúsiť otvoriť detail cudzieho zariadenia priamym URLNa detail sa nedostane — prepojenie zákazník ↔ zariadenie nie je overené, portál ho vráti na svoj zoznam
7Odhlásiť sa a otvoriť /portal/bookings priamym odkazomRedirect na prihlásenie; po prihlásení pristane na požiadavkách
<!-- Skrátené pre článok — v reálnom dokumente (aj v tvojom) je každá journey, rola po role. -->
Dve z user journeys, ktoré agent po produkčnom rune preklikal v prehliadači: kroky a očakávaný výsledok.

#Bola appka hotová po produkčnom rune?

Funkčne áno, každý flow prešiel, každá rola sa dostala tam, kam mala. Odovzdateľne ešte nie: zostali drobnosti, ktoré si všimne moje odborné oko, nie test.

##Chyby, ktoré si rebuild nezaslúžia

Produkčný run dopadol lepšie, než som po revízii kódu a testovaní aplikácie čakal. Samozrejme, pár drobných chýb sa našlo. Pri spätnej analýze to boli prevažne chýbajúce usmernenia technickej implementácie, nie logické chyby v kóde. Napríklad ukladanie súborov na lokálny disk namiesto externého úložiska: po ďalšom deploymente by sa všetky súbory zmazali.

Ďalšie chyby boli z rovnakej kategórie, vyberám ich priamo z commit správ v gite:

  • Tlačidlo „späť" vo formulári, ktoré formulár omylom odosielalo, lebo nemalo nastavený typ.
  • Jedna prihlasovacia karta bez vnútorného odsadenia, kým všetky ostatné ho mali.
  • Modal, ktorý sa na nízkych obrazovkách nedal odscrollovať.
  • Pole na percento provízie, ktoré neprijalo desatinnú čiarku, len bodku.
  • Šablóna textu, ktorá pridala bodku za hodnotu, ktorá už bodkou končila.
  • Nejednoznačné pomenovanie súborov.

Kozmetika, setup, drobné konvencie. Ani jedna z nich nebola architektonická a to je dôležité usmernenie pre celý tento prístup. Rebuild s upravenými pravidlami si zaslúži chyba, ktorá nesie zásadný problém v architektúre a bez pravidla sa zopakuje v každej ďalšej obrazovke.

Príklad z nášho kontextu: keby agent riešil oprávnenia na frontende, skrytím tlačidiel a položiek menu podľa role, namiesto na serveri cez policies. Každá obrazovka by to zdedila, každá by sa dala obísť priamou URL a oprava v kóde by znamenala prejsť všetkých 64 stránok. To je chyba do pravidla a do rebuildu. Chyba, ktorá je jedinečná a lokálna, si rebuild nezaslúži, bola by to drahá odpoveď na lacný problém.

chyba opakuje sa v každej obrazovke chýba pravidlo → harness rebuild s upravenými pravidlami jedinečná a lokálna oprava v kóde rebuild by bol drahá odpoveď na lacný problém chyba opakuje sa v každej obrazovke chýba pravidlo → harness rebuild s upravenými pravidlami jedinečná a lokálna oprava v kóde rebuild by bol drahá odpoveď na lacný problém

##Ukazuješ na chybu, nie na riešenie

Takže ako sa opravovali? Nie vibe-codingom, kde agentovi diktuješ, čo má kde prepísať. Agent dostal zoznam nálezov, tak ako ich zapísal browser run a moja vlastná revízia, a spracoval ich autonómne: pri každom sám navrhol riešenie, implementoval ho podľa pravidiel harnessu a pustil verifikačnú bránu. Ja som každú opravu overil a uložili sme to. Ukazuješ na chybu, nie na riešenie.

Osobne si myslím, že dnes je kód napísaný lepšie než na vrchole mojej aktívnej engineering kariéry, keď som denne vyvíjal aplikácie.

##Posledný ľudský dotyk

Agenti sa držali dizajn kontraktu z pravidiel v repozitári a UI mi prišlo solídne. Ako vyslúžilý UI/UX dizajnér a perfekcionista som však strávil ešte zhruba dva dni dolaďovaním UI a flowu, aby aj najmenší detail a najmenšia operácia v aplikácii pôsobili príjemne a prirodzene. Na toto už žiadny premyslený proces nemám, len starý dobrý vibe-coding: Claude, toto urob takto, tamto urob hentak. Je to dolaďovanie drobných detailov, nie vibe-codovanie nových funkcionalít. Trocha ľudského dotyku, ktorý produkčná verzia potrebovala. Bol to posledný ľudský dotyk pred odovzdaním projektu: naleštenie, nie prestavba.

vibe-coding funkcionality „pridaj portál pre flotily" „sprav export zákazky do PDF" „prerob tok príjmu vozidla" „pridaj notifikácie cez SMS" to nerobíme: zmena ide do harnessu a specov, potom rebuild vibe-coding detailov „späť nech neodosiela formulár" „karta: odsadenie ako ostatné" „modal na mobile nech sa dá scrollovať" „percento nech prijme aj čiarku" priamo v kóde: „Claude, toto urob takto", ~2 dni pred odovzdaním dolaďovanie drobných detailov, nie nové funkcionality vibe-coding funkcionality „pridaj portál pre flotily" „sprav export zákazky do PDF" „prerob tok príjmu vozidla" „pridaj notifikácie cez SMS" to nerobíme: zmena ide do harnessu a specov, potom rebuild vibe-coding detailov „späť nech neodosiela formulár" „karta: odsadenie ako ostatné" „modal na mobile nech sa dá scrollovať" „percento nech prijme aj čiarku" priamo v kóde: „Claude, toto urob takto", ~2 dni pred odovzdaním dolaďovanie drobných detailov, nie nové funkcionality

Z jedného autonómneho runu dostaneš aplikáciu, ktorá funguje, drží dizajn a dá sa odovzdať po dvoch dňoch dolaďovania. Tá kvalita nevzniká v rune, ale pred ním: v harnesse s jasnými pravidlami, ako má aplikácia vyzerať, aký má interakčný pattern a ako sa má stavať. Posledné percentá sú už len otázka tvojho zmyslu pre detail. A tie sa doladia v kóde, nie v ďalšom rune.

#Čo ostalo po produkčnom rune

Kód. Zatiaľ. V mojom procese existuje bod, v ktorom sa prepnem: aplikácia sa stane jediným zdrojom pravdy a od tej chvíle iterujeme na nej, svojpomocne, ak je vývoj kontinuálny a klient prináša ďalšie biznis požiadavky. Špecifikácie a harness ostávajú ako dokumentácia toho, prečo appka vyzerá tak, ako vyzerá, ale už sa z nich nekompiluje.

##Mesiac namiesto troch

Celá exekučná časť projektu trvala mesiac. Pred érou coding agentov trval rovnaký rozsah podľa mojich skúseností dva až tri mesiace a potreboval produktového manažéra, dizajnéra a dvoch až troch inžinierov. Dnes to vie zorchestrovať jeden človek, ktorý má ako taký presah do produktu, dizajnu a engineeringu. A k tomu získaš niečo, čo sme pred AI nemali: klient má appku v rukách v ranej fáze návrhu riešenia, feedback sa vracia v hodinách a každý build je celý produkt - nie prototyp z Figmy, nie časť aplikácie, nie okresané MVP. Kód už nestaviaš. Tvoje úlohy sú len dve: naarchitektovať správne riešenie a zorchestrovať agentov, aby ho postavili.

predtým: PM · dizajnér · 2–3 inžinieri 2–3 mesiace architektúra 1 mesiac · jeden človek FE BE QA agenti stavajú celý produkt klient · feedback v hodinách partitúra = architektúra · dirigent = ty · orchester = agenti · každý build je celý produkt predtým: PM · dizajnér 2–3 inžinieri 2–3 mesiace architektúra 1 mesiac · jeden človek FE BE QA agenti stavajú celý produkt klient · feedback v hodinách partitúra = architektúra · dirigent = ty orchester = agenti · každý build je celý produkt

#Čo bolo ťažké

##Manažovanie špecifikácií

Najnáročnejšie na celom procese je manažovať špecifikácie všetkých features v roadmape. Keď ich máš napríklad sto a pracuješ s nimi celý deň, je to naozaj vyčerpávajúce a musíš si sám určiť, či ti ten trade-off stojí za to. Tu treba využiť plnú silu agentov, nech ti ich pomôžu spravovať. A drž ich lean a jednoduché aby ťa to neskôr nezomlelo: dnešní agenti hlúpi nie sú a aj z minima informácií pochopia, čo potrebuješ. Hlavné informácie drž vždy na úrovni harnessu, aby si do špecifikácií zaniesol čo najmenej duplicitných inštrukcií.

#12#48#97#64 sto specov, celý deň… manažovať sto specov je vyčerpávajúce: nechaj si ich spravovať agentmi a drž ich lean #12#48#97#64 sto specov, celý deň… manažovať sto specov je vyčerpávajúce: nechaj si ich spravovať agentmi a drž ich lean

##Komplexný UX flow ako prototyp

Druhá náročná vec je opísať v špecifikácii komplexnejší UX flow, povedzme desaťkrokový proces, ktorým musí používateľ prejsť. Popísať ho tak dobre, aby ho agent zreplikoval podľa tvojich predstáv, je ťažké. Hlavne keď aplikáciu v iteratívnej fáze rekompiluješ znova a znova. Mne sa osvedčilo vziať design systém a vyiterovať (áno, vibe-codingom) samostatný prototyp s UI, ktoré presne robí ten náročný flow. Uložil som ho do harnessu do docs/prototypes a špecifikácia danej funkcionality obsahuje len referenciu: agent sa naň pozrie a implementuje ho do produkčného kódu čisto a podľa produkčných pravidiel. Tak máš to najlepšie z oboch svetov, vibe-codingu aj spec as code.

prototyp flowu vibe-coding z design systému 12345 109876 desať krokov, ktoré sa slovami opísať nedajú uložený v harnesse: docs/prototypes/ referencia spec funkcionality Goal Acceptance Layout & Design → pozri docs/prototypes/ agent produkčný kód čisto, podľa pravidiel harnessu prototyp ukazuje ako, spec naň odkáže, agent to postaví podľa produkčných pravidiel prototyp flowu vibe-coding z design systému 12345 109876 desať krokov, ktoré sa slovami opísať nedajú uložený v harnesse: docs/prototypes/ referencia spec funkcionality Goal Acceptance Layout & Design → pozri docs/prototypes/ agent produkčný kód čisto, podľa pravidiel harnessu prototyp ukazuje ako, spec naň odkáže, agent to postaví podľa produkčných pravidiel

#O level vyššie

##Slučka prompt, čakanie, kontrola

Všímam si, že veľa engineerov kvôli AI agentom prichádza o svoju doterajšiu radosť z práce. Programovanie bolo ich každodenná práca a AI im z nej berie radosť. Typický deň inžiniera vyzeral tak, že ráno vstaneš, uvaríš si kávu, zapneš IDE a na osem hodín sa ponoríš do problému: rozbiješ ho na časti, postavíš riešenie a večer to funguje. Niečo si vytvoril, niečo vyriešil, a to bola tvoja odmena. Dnes ten istý človek sedí celý deň v slučke prompt, čakanie, kontrola, prompt. Robí jedno drobné rozhodnutie za druhým, prácu medzi nimi urobí agent, a večer je vyčerpaný z rozhodovania bez pocitu, že niečo postavil.

predtým: osem hodín v probléme ráno večer večer: funguje, niečo si postavil dnes: v slučke celý deň prompt čakanie kontrola večer: vyčerpaný, nič si nepostavil predtým: osem hodín v probléme ráno večer večer: funguje, niečo si postavil dnes: v slučke celý deň prompt čakanie kontrola večer: vyčerpaný, nič si nepostavil

##Podstata práce sa zmenila, aj odmena je inde

Ja to vnímam inak: treba ísť o level vyššie. Aplikáciu už nestaviame na úrovni kódu. Staviame harness: znalosti, ktoré agenta nasmerujú, design systém, testy a audit, aby agent postavil appku od nuly v jednom autonómnom rune. Je to iná práca a úsudok sa presúva vyššie: akými technológiami stavať, ako má vyzerať UX a UI, ako sa má systém zachovať, keď mu niečo chýba. A dá sa s tým hrať a iterovať rovnako ako s kódom. Odmena je len inde. Nie funkcia, ktorá funguje, ale systém, ktorý funguje. A to, čo z neho vyjde, je trikrát väčšie, než čo sme doteraz stavali.

Otázka už nie je, ako dobre postaviť kus kódu. Otázka je, o koľko zdvihnúť ambície. Aby tá odmena nezmizla, musí rásť scope toho, čo dokážeme. Kedysi sme ulovili zver, potom zasiali pole, potom napísali kód, ktorý automatizoval jednu vec. Dnes vieme navrhnúť celý systém, ktorý rastie a mení sa s tým, čo od neho svet okolo chce. To je teraz v našich rukách: navrhnúť ho a zorchestrovať.

ambície → ↑ odmena ulovíš zver úlovok zaseješ pole úroda napíšeš kus kódu jedna vec funguje postavíš appku produkt funguje postavíš harness systém funguje: appka desaťkrát systém, ktorý rastie adaptuje sa sám ty dnes odmena ostáva, keď rastie scope: nie funkcia, ktorá funguje, ale systém, ktorý funguje ambície → ↑ odmena ulovíš zver úlovok zaseješ pole úroda napíšeš kus kódu jedna vec funguje postavíš appku produkt funguje postavíš harness systém funguje: appka desaťkrát systém, ktorý rastie adaptuje sa sám ty dnes odmena ostáva, keď rastie scope: nie funkcia, ktorá funguje, ale systém, ktorý funguje

#Kam to smeruje

##Harness je tiež na zahodenie

Tento článok je viac o mentálnom modeli než o presnom postupe. Ukazuje, že sa to dá aj takto, nie že sa to má robiť presne takto. Nekopíruj moje harness dokumenty. Inšpiruj sa a skúšaj, čo sedí tebe: každý človek aj každý projekt má vlastné postupy a vlastnú fázu. A harness, ktorý postavíš dnes, nebude o pol roka relevantný. Je nezmysel veriť, že bude.

Pre harness platí to isté, čo pre appku: je na zahodenie. Ostať musí jediné: ochota zahodiť starý mentálny model, keď sa svet zmení, a postaviť si nový. Harness ti dnes postaví samotná AI. Čo ti nepostaví, je pružné uvažovanie a odvaha experimentovať.

začni tu svet sa zmení nový model, nový nástroj mentálny model ohne sa, nepretrhne nový harness napíše ti ho AI starý harness zahodiť spec build appka zahodiť mesiace · keď sa zmení model, nástroj alebo ambícia hodiny · desaťkrát za projekt prekompiluj, nerefaktoruj platí aj o level vyššie: harness je pre mentálny model to, čo appka pre harness začni tu svet sa zmení nový model, nový nástroj mentálny model ohne sa, nepretrhne nový harness napíše ti ho AI starý harness zahodiť spec build appka zahodiť mesiace · keď sa zmení model, nástroj alebo ambícia hodiny · desaťkrát za projekt prekompiluj, nerefaktoruj platí aj o level vyššie: harness je pre mentálny model to, čo appka pre harness

##Product builder v teréne

Ten môj smeruje k tomuto. Rýchle stavanie greenfield projektov, kde chyba v návrhu nie je katastrofa, ale lacná oprava. Kde nová funkcia pridaná za behu nie je prekliatie, ale feature. Kde som ako product builder viac v teréne a bavím sa so zákazníkom a používateľmi, než sedím pri rysovacom plátne a coding obrazovkách. A kde sa vízia riešenia dá naplniť o dosť skôr a lacnejšie, než to bolo doteraz možné. Nie okresané MVP, ale hotový produkt.

pri rysovacom plátne a coding obrazovkách sám, s kódom čas sa presunul sem v teréne, so zákazníkom a používateľmi ty zákazník a používatelia „toto by sme potrebovali inak" product builder v teréne: chyba v návrhu je lacná oprava, nová funkcia za behu je feature pri rysovacom plátne a coding obrazovkách sám, s kódom čas sa presunul sem v teréne, so zákazníkom a používateľmi ty zákazník a používatelia „toto by sme potrebovali inak" product builder v teréne: chyba v návrhu je lacná oprava, nová funkcia za behu je feature

##Ďalší experiment: fixné dáta, nahraditeľná appka

A jedna vec, ktorú chcem skúsiť nabudúce. Je finálny produkčný kód naozaj zdroj pravdy, alebo ním ostáva špecifikácia produktu? Pohrávam sa s myšlienkou oddeliť produkčnú databázu ako statický prvok a aplikáciu nechať ako prvok dynamický, ktorý sa aj pri ďalších veľkých iteráciách môže znova a znova rekompilovať. Pridáš funkcionalitu alebo ju odstrániš, aplikáciu vždy prekompiluješ. Nabral si obrovské množstvo používateľov a aplikácia to nestíha? Prekompiluješ backend s inou architektúrou, prípadne v inom jazyku alebo prostredí. Produkčné dáta, ktoré vygenerovali tvoji zákazníci a tvoja firma, sú fixné, všetko nad nimi je nahraditeľné. To si nechám na budúce experimenty, možno na budúci článok.

spec appka dáta spec v1 spec v2 · + nová funkcionalita spec v3 · desaťkrát viac používateľov prekompiluj prekompiluj prekompiluj appka v1 zahodená appka v2 · + funkcionalita zahodená appka v3 · iný jazyk iná architektúra, keď nestíha produkčné dáta · fixný artefakt · len rastú, nikdy sa nezahadzujú kód nie je zdroj pravdy: hore spec, dole dáta, medzi nimi appka na výmenu spec appka dáta spec v1 spec v2 · + nová funkcionalita spec v3 · desaťkrát viac používateľov prekompiluj prekompiluj prekompiluj appka v1 zahodená appka v2 + funkcionalita zahodená appka v3 iný jazyk iná architektúra, keď nestíha produkčné dáta · fixný artefakt len rastú, nikdy sa nezahadzujú kód nie je zdroj pravdy: hore spec, dole dáta, medzi nimi appka na výmenu

A to je len jeden nápad. Keď o tom píšem, napadá mi obrovské množstvo problémov a príležitostí, ktoré sa dajú takto reinventnúť. Tebe pri čítaní určite napadlo aspoň desať vecí na ďalších desať článkov. Nebojím sa, že kvôli AI nebudeme mať čo robiť. Naopak, práce bude o dosť viac. Len bude iná.

Ak staviaš niečo podobné, vlastný harness, spec ako zdroj pravdy, appku na zahodenie, ozvi sa. Rád porovnám postrehy.

Zdieľať článokLinkedInX
Peter Papp
Peter Papp

Misionár éry AI. Ukazujem, čo dnes dokáže jeden človek: staviam generatívne AI riešenia a zdieľam, čo som sa pri tom naučil. Inšpiruj sa, vezmi si, čo sa dá, a buduj aj ty. Ak riešiš niečo podobné, napíš mi.

Buď ten jeden človek

Staviaš niečo s AI, alebo rozmýšľaš, kde by ti vo firme pomohla? Rád sa o tom pobavím.

Najrýchlejšie ma zastihneš na LinkedInNapíš mi

alebo mi

© 2026 Peter Papp · Postavené s ☕ a Claude CodeLinkedInX