AI klon Petra Vojnara · SEBA Academy

Průvodce projektem — zeptej se na specifikaci

Interní AI parťák, který zná kompletní specifikaci platformy (design, API, datové schéma i oba pohledy). Pomůže ti vyznat se v projektu, propojit souvislosti a najít, co ještě doplnit před ultraplanem.

Průvodce projektem zná celou specifikaci platformy
AI

Ahoj! Znám celou specifikaci projektu SEBA AI platforma — design dokument, API kontrakty, datové schéma i oba pohledy. Zeptej se mě na cokoliv: jak něco funguje, proč jsme se tak rozhodli, kde jsou rizika nebo co ještě chybí doplnit. Na čem zrovna pracuješ?

Specifikace platformy · verze 0.10 1. 7. 2026
↓ Níže najdeš kompletní specifikaci platformy ve třech pohledech

Z průměrného chatbota děláme nástroj, který prodává

Existující AI klony — včetně toho prvního od experti.ai i té verze, kterou jsi dostal — kloužou po povrchu. Jsou strohé, běží na starších enginech, mají slabý tah na bránu a lidé se k nim nevracejí. My jsme vzali tu dodanou verzi a pozvedli ji na úplně jiný level. Na téhle stránce ti ukážu, co konkrétně bylo nedotažené, jak jsme to opravili a co všechno s klonem plánujeme dál.

Krátce řečeno

Dosavadní řešení uměla „odpovídat na otázky". To je málo. Chatbot, který jen odpoví a nechá člověka odejít, ti nepřinese ani korunu. My stavíme aktivního obchodníka — který zahřeje zájemce, pozná, co potřebuje, ve správnou chvíli nabídne konkrétní produkt a předá ti připravený kontakt. A to celé tvým hlasem a z tvého know-how.

Srovnání — dosavadní klony vs. ten náš

Co rozhodujeDosavadní klony (např. experti.ai)Náš nový klon
AI engineStarší GPT (verze ~5.2–5.3), případně Gemini 2.5Gemini 3.1 Flash Lite — novější generace, rychlá a nákladově efektivní
Kontextové okno250 tisíc tokenů1 milion tokenů (4× víc) — pojme celé tvé know-how najednou
ČeštinaUmělejší, „přeloženě" působícíPřirozená čeština — Gemini ji zvládá líp než GPT i Claude
Hloubka odpovědíPár strohých vět — člověk si řekne „tohle mi ChatGPT řekne líp"Hluboké strukturované odpovědi z celého tvého know-how — úvod, body s příklady, vizuální diagram, shrnutí, konkrétní úkol
Výběr produktůNeumí — nabízí naslepoVybírá podle profilu zájemce, klidně 2 možnosti k porovnání
Termíny akcíNeumí nabídnout konkrétní termínNabídne nejbližší volný termín workshopu/masterclass
Identita uživatelůVšichni pod jedním účtem — nevíš, kdo co píšeKaždý zájemce má profil — víš s kým mluvíš a co řeší
Tah na bránuStrohé, pasivní — lidé se nevracíVede konverzaci k cíli, kvalifikuje, předává leady

Co bylo nedotažené — a jak jsme to spravili

❌ Bylo Klon odpovídal stroze a tlačil na schůzku hned v první zprávě. To odrazuje — působí to jako vtíravý prodejce a u značky „akademie sebevědomého řečníka" to škodí.
✅ Teď Přepracovali jsme logiku tak, aby klon nejdřív dával hodnotu a konzultaci nabídl až ve chvíli, kdy konverzace dozraje a člověk projeví vážný zájem. Nabídka je navíc navázaná na to, o čem se zrovna baví.
❌ Bylo Běželo to na starším enginu, který klouže po povrchu a v delší konverzaci ztrácí nit.
✅ Teď Přešli jsme na Gemini 3.1 Flash Lite s milionovým kontextovým oknem. Klon udrží mnohem delší a souvislejší rozhovor, pracuje s víc informacemi najednou a odpovídá přirozenou češtinou. Je to novější generace, která navíc umí „přemýšlet" před odpovědí — a přitom je nákladově efektivní, takže provoz nestojí majlant. Vyměnili jsme i způsob, jak hledá ve tvém know-how (novější, přesnější technologie — embeddingy verze 2).
❌ Bylo Klon odpovídal obecnými frázemi z internetu, ne tvým know-how.
✅ Teď Napojili jsme ho na celý obsah tvého kurzu — e-book a všech pět modulů. Když se někdo zeptá na trému nebo na vynucení rozhodnutí, odpoví tvými technikami a tvým stylem. Cestou jsme navíc opravili dvě skryté chyby v původním kódu, které kazily kvalitu a zbytečně pálily náklady.
❌ Bylo Lidé se hlásili pod jedním společným účtem. Nešlo zjistit, kdo co píše — viděl jsi jen počet zpráv za den, ale ne od koho.
✅ Teď (v plánu) Každý zájemce dostane vlastní profil. Budeš vidět, s kým klon mluvil, co ten člověk řeší a jak je „horký". Žádní anonymové — konkrétní lidé s konkrétními potřebami.
Nechali jsme to prověřit — a dotáhli

Než se začne stavět, nechali jsme celý návrh projít nezávislou kontrolou čtyř odborných „kritiků" (každý hlídá něco jiného: skeptik zpochybňuje předpoklady, „pre-mortem" hledá, proč by to mohlo selhat, hlídač nákladů a hlídač architektury). Našli čtyři místa, která by se v běžícím systému draho opravovala — a my je opravili teď, na papíře. Mimo jiné: jak přesně klon pozná tu pravou chvíli nabídnout, aby mu neutekl horký zájemce, a jak nastavit souhlasy se zpracováním dat tak, aby ostré spuštění bylo právně čisté. Radši najít slabiny dřív, než na nich někdo pohoří.

Co s klonem plánujeme — celý plán

1

Hravý vstupní dotazník

Než se s klonem dá člověk do řeči, projde zábavným, gamifikovaným dotazníkem. Zjistíme z něj, kdo to je, co řeší, čeho chce dosáhnout a kolik je ochotný do rozvoje investovat. Navržený tak, aby ho člověka bavilo vyplnit.

Co tím získáš Klon nemluví s anonymem, ale s konkrétním člověkem, kterého zná. A ty získáváš data o cenové citlivosti — využiješ je při ladění ceny tvého chystaného online kurzu.
2

Chytré doporučování produktů — a správné načasování

Klon podle profilu a vývoje rozhovoru vybere z tvého portfolia to pravé — někomu večerní workshop, firmě školení na míru, někomu intenzivní mentoring. Umí porovnat dvě možnosti a nabídnout nejbližší volný termín. Klíčové je, že rozlišuje, jestli člověk řeší rozvoj jen pro sebe, nebo i pro tým / celou firmu — podle toho míří buď na produkty pro jednotlivce, nebo na firemní zakázku (ta je řádově hodnotnější). A hlavně: nikdy netlačí předčasně. Sleduje, jak konverzace „zraje" — jestli člověk popsal vlastní situaci, ptá se na řešení, vrací se k tématu — a nabídne teprve, když pozná vážný zájem. Výjimka je, když někdo sám řekne „kolik to stojí, kde se přihlásím" — tam klon nezdržuje doptáváním a rovnou pomůže.

Co tím získáš Víc uzavřených obchodů a méně otrávených návštěvníků. Lidé dostanou nabídku, která jim dává smysl, ve chvíli, kdy jsou na ni připravení — a firemní zájemce nepropadne sítem jako „další jednotlivec".
3

Připravený obchodní kontakt na stole

Když má někdo zájem, klon si vezme kontakt a celý rozhovor ti shrne do obchodního briefingu: kdo to je, co řeší, o co má zájem, jakou měl námitku, jak je horký. Zachytíme i ty, co řeknou jen „rozmyslím si to" — jako vlažné kontakty k pozdějšímu oslovení.

Co tím získáš Nezvedáš telefon naslepo. Víš přesně, s kým mluvíš a na co navázat — kvalifikace je hotová za tebe. Ty si budeš moct rovnou zavolat tomu správnému člověku ve správnou chvíli.
4

Přehledné rozhraní pro tebe + bezpečnost

V přehledu uvidíš všechny příležitosti, profily, celé konverzace i doporučené další kroky. Klon mezitím pracuje nonstop. Má nastavené limity, takže si z něj nikdo neudělá vlastní hračku na tvůj účet. A osobní data lidí jsou chráněná podle GDPR — souhlasy se sběrem kontaktu jsme navíc nastavili přesně podle českého úřadu (ÚOOÚ), takže ostré spuštění je právně čisté a zároveň bez zbytečného tření (člověka u vstupu neotravuje zaškrtávátky tam, kde nemusí).

Co tím získáš Prodejní asistent, který nikdy neonemocní a zvládne mluvit s desítkami lidí najednou — a ty máš všechno pod kontrolou na jednom místě, bez rizika pokuty za špatně sebraný souhlas.
5

Připraveno na tvůj online kurz — dva klony

Celá platforma je navržená tak, aby až spustíš online kurz, ho klon začal nabízet jako prioritu. A protože jeden klon nesedí všem situacím, počítáme rovnou se dvěma. Warmup klon (děláme teď) je volně přístupný a zdarma — jeho úkol je zahřát zájemce a vést je k nabídce, takže je o něco aktivnější v prodeji; je to lapač na vrcholu trychtýře. Prémiový klon (později, uvnitř kurzu) poběží pro lidi, co si kurz koupí — tam je trpělivější a víc mentor než prodejce, protože platícího zákazníka už neprodáváš, ale provázíš.

Oba mají stejný mozek, liší se jen „povahou" (jak rychle a jak moc nabízí) — tu přepneme jedním nastavením, ne stavbou nového klona.

Co tím získáš Až přijde kurz, máš pro něj připravený prodejní kanál, který se učí na reálných zákaznících už teď — a druhý, prémiový režim, který zákazníkům kurzu dělá osobního průvodce.

Proč zrovna Gemini

Zvolili jsme Gemini záměrně. Má milionové kontextové okno (4× víc než dosavadní řešení), takže udrží dlouhý a souvislý rozhovor a hlavně — pojme celé tvé know-how najednou. Díky tomu klon neodpovídá z pár náhodných úryvků, ale ze všeho, co umíš, propojeně. A mluví nejpřirozenější češtinou ze všech velkých modelů, líp než GPT i Claude. To je u nástroje, který nese tvé jméno, zásadní.

Výsledek poznáš na první odpovědi: místo pár strohých vět dostane člověk promyšlenou odpověď s úvodem, konkrétními body, vizuálním diagramem, shrnutím i úkolem na doma — a to vše tvým stylem a z tvého kurzu. Přesně ten rozdíl, kvůli kterému se lidé budou vracet, místo aby si otevřeli vlastní ChatGPT.

Krátce: z chatbota, co klouže po povrchu, děláme aktivního obchodníka, který nese tvé jméno a maká za tebe.

Jak jsme to vymysleli — pro tým

Tahle stránka je pro vás, co na projektu děláte nebo o něm rozhodujete. Vezmeme to chronologicky: co stavíme, v jakém pořadí, a hlavně proč jsme se u každého kroku rozhodli zrovna takhle. Není to technická dokumentace (ta je v záložce vedle) — je to vyprávění o tom, jak vznikal koncept a jaké úvahy za ním stojí.

Výchozí situace

Začínali jsme s jednoduchým AI chatbotem, kterého připravil kolega přes Gemini. Fungoval, ale byl to jen „chatbot co odpovídá". Naším úkolem bylo přetvořit ho na nástroj, který reálně přináší obchodní hodnotu — kvalifikuje zájemce a vede je k produktům SEBA Academy. Místo záplatování jsme se rozhodli postavit promyšlenou platformu od základu.

Cesta projektu — krok za krokem

1

Nejdřív jsme ověřili a vyladili samotný chat

Rozjeli jsme aplikaci lokálně, sjednotili ji na Gemini 3.1 Flash Lite přes OpenRouter (novější generace, umí reasoning, nákladově efektivní) a předělali způsob, jakým nabízí konzultace. Původní verze tlačila schůzku hned v první zprávě — to odrazuje. Přepracovali jsme to tak, aby AI nabízela pomoc až když konverzace dozraje a člověk projeví vážný zájem.

Proč takhle: Tahle dodaná appka je pro nás throwaway test — ověřili jsme na ní napojení modelu, embeddingů a vyhledávání ve znalostech. Finální platformu stavíme od základu; z téhle verze si bereme jen ověřené stavební kameny (napojení na model, embeddingy, princip vyhledávání). A hned zkraje jsme srovnali přístup: agresivní prodej zabíjí důvěru — u značky „akademie sebevědomého řečníka" by vtíravý bot škodil.
2

Napojili jsme AI na reálný obsah kurzu

Aby „AI Petr" nemluvil obecnými frázemi, naindexovali jsme do něj celý obsah kurzu — e-book a všech pět modulů. Teď odpovídá konkrétními technikami Petra Vojnara. Při tom jsme cestou opravili i dvě skryté chyby v původním kódu, které by jinak kazily kvalitu a zbytečně pálily náklady.

Proč takhle: Hodnota AI dvojčete stojí a padá s tím, jestli zní jako Petr, ne jako generický internet. Reálný obsah kurzu = autentické odpovědi = důvěra zákazníka.
3

Navrhli jsme celý prodejní trychtýř a nechali ho prověřit — dvakrát

Sepsali jsme kompletní plán platformy: gamifikovaný dotazník na vstupu, vlastní databázi zákazníků a leadů, chytré doporučování produktů a rozhraní pro Petra. Pak jsme ten plán nechali projít nezávislou kontrolou — čtyři odborné perspektivy (architektura, data, bezpečnost, prodej) hledaly v návrhu díry. První kolo našlo 51 připomínek, které jsme zapracovali.

Když jsme později dotáhli jádro produktu (viz krok 6 níže), pustili jsme druhé, ostřejší kolo kontroly — opět čtyři kritici, každý s jiným zaměřením (skeptik na předpoklady, „pre-mortem" na scénáře selhání, hlídač nákladů, hlídač architektury). Našli čtyři kritická místa, která by se v běžícím systému opravovala draho, a my je opravili rovnou v zadání. Jedno z nich jsme si navíc ověřili přímo u pravidel českého úřadu pro ochranu údajů.

Proč takhle: Lepší najít slabiny na papíře než až v běžícím systému s reálnými daty lidí. Druhá kontrola po dotažení detailů odhalila věci, které v prvním, hrubším kole ještě nebyly vidět — třeba jak přesně poznat tu pravou chvíli nabídnout, aby neutekl horký zájemce.
4

Vyřešili jsme bezpečnost a ochranu osobních dat

Protože platforma bude pracovat se skutečnými osobními údaji — jména, kontakty, popisy situací lidí — věnovali jsme velkou pozornost GDPR a zabezpečení. Navrhli jsme, jak data chránit v databázi, jak řešit souhlas, jak bezpečně předávat informace AI a jak zařídit, aby se uživatelé nemohli vzájemně „prokliknout" k cizím profilům.

Proč takhle: Únik dat zákazníků by byl katastrofa pro značku i právně. Raději jsme to vyřešili pořádně hned v návrhu, než to lepit dodatečně.
5

Připravili jsme detailní podklad pro implementaci

Z plánu jsme vytvořili kompletní zadání pro vývoj — včetně přesného databázového schématu a popisu, jak spolu jednotlivé části komunikují. Stavět se bude po vrstvách: nejdřív datový a bezpečnostní základ, pak chat s napojením, pak rozhraní pro Petra, nakonec dotazník. Každá vrstva je samostatně otestovatelná.

Proč takhle: Velké systémy se nestaví „velkým třeskem". Po vrstvách máme po každém kroku něco funkčního a otestovaného, místo abychom čekali na konec a doufali, že to spolu zapadne.
6

Dotáhli jsme „mozek" prodeje do detailu

Tady je jádro celé práce. Aby klon opravdu prodával (a ne jen odpovídal), musí umět tři věci spolehlivě a předvídatelně, ne náhodně:

1. Poznat, kdy je čas nabídnout. Místo „odhadu od oka" jsme sestavili jasná pravidla — klon sčítá konkrétní signály (popsal člověk vlastní situaci? ptá se na řešení? vrací se k tématu?), a teprve když to dosáhne určité hranice, považuje konverzaci za „zralou". Pro warmup klon je laťka níž (chceme spíš prodat), pro budoucí prémiový výš (trpělivost). A když někdo rovnou napíše „kolik to stojí", klon to zachytí okamžitě a nezdržuje.

2. Vybrat správný produkt. Klon rozlišuje, jestli člověk řeší rozvoj pro sebe, nebo nakupuje pro tým/firmu — to rozhoduje, jestli mu nabídnout produkt pro jednotlivce, nebo firemní zakázku. Výběr dělá logika v kódu, ne náhodný nápad AI — takže klon nikdy nedoporučí produkt, který neexistuje, a rozhodování se dá testovat a ladit.

3. Zvládnout návraty a „rozmyslím si to". Vyřešili jsme, co se stane, když se člověk vrátí za týden (klon naváže tam, kde skončil), a jak naložit s lidmi, co dotazník vyplnili, ale do chatu se nepustili (zůstávají jako vlažné kontakty — pokud k tomu dali souhlas).

Proč takhle: „Chytrý prodejní bot" zní hezky, ale bez konkrétních pravidel je to jen marketing. My jsme ta pravidla skutečně napsali a necháme je projít druhou kontrolou (krok 3) — proto víme, že klon bude fungovat stejně dnes i za půl roku, ne podle nálady modelu.

Co nás vede

Celou dobu nás vede jedna myšlenka: tahle AI není cíl, je to warmup nástroj na vrcholu trychtýře. Zahřívá zájemce a vede je k produktům — a až bude hotový Petrův online kurz, stane se jeho hlavním prodejním kanálem. Proto je architektura od začátku navržená tak, aby kurz mohla kdykoli přidat jako prioritu.

Z toho vyplynulo i rozhodnutí stavět dva klony, ne jeden: warmup (volně přístupný, zdarma, o něco aktivnější v prodeji — ten děláme teď) a později prémiový uvnitř placeného kurzu (trpělivější, víc průvodce než prodejce). Mají stejný základ; liší se jen „povahou", kterou přepneme nastavením — žádný druhý systém se nestaví. Díky tomu jeden a tentýž návrh poslouží dvěma různým fázím zákazníkova vztahu k SEBA.

A druhá zásada: kvalita před rychlostí. Raději jsme strávili čas pořádným návrhem, nezávislou kontrolou a promyšlením rizik, než abychom rychle slepili něco, co by se za měsíc muselo předělávat. Čím obsáhlejší a promyšlenější specifikaci připravíme teď, tím spolehlivější bude implementace. Tady je prostor na vaše připomínky a brainstorming — proto je nahoře na téhle stránce průvodce specifikací: pomocný AI chat, který zná celou tuhle dokumentaci a odpoví vám na detaily, souvislosti i otevřené otázky. (Pozor: to je interní pomůcka k dokumentaci, ne ten prodejní AI klon — o tom je celá tahle specifikace.)

Stavíme to tak, jak bychom chtěli, aby to někdo postavil nám.

Dotazník na vstupu — co jsme zjistili a proč je teď lepší

Vstupní branou do celého nástroje je gamifikovaný dotazník — člověk vyplní pár otázek a z jeho odpovědí se poskládá „první zpráva pro AI klona", který s ním pak mluví na míru. Dotazník ale dělá tři práce najednou: nastaví klona, kvalifikuje zájemce pro pozdější nabídku a sbírá data o cílovce pro plánovaný online kurz. Tahle záložka shrnuje, co jsme na něm vylepšili, proč zrovna takhle, a co z toho má tým mít.

Výchozí situace

Funkční dotazník nám dodal marketér — dobře napsaný, s gamifikací a citem pro copy. Naším úkolem nebylo ho přepsat, ale ověřit a doladit. Klíčové rozhodnutí: než jsme sáhli do jeho práce, nechali jsme dotazník nezávisle posoudit třemi špičkovými AI modely (Claude, GPT-5.5, Gemini) proti tomu, co víme o cílovce z předchozího výzkumu. Cíl: potvrdit, co funguje, a najít jen to, co jde podložit daty — ne měnit od boku.

Co audit ukázal — krok za krokem

1

Základ je dobrý — nepřepisovat

Všechny tři modely se nezávisle shodly, že kostra dotazníku je solidní: gamifikace, jedna otázka na obrazovku, živý „Profil klona", který se plní, i timing (kontakt až na konci) jsou správně. To všechno zůstává.

Proč takhle: Když se tři nezávisle trénované modely shodnou, je to silný signál. Marketérova práce prošla — dolaďujeme, neboříme.
2

Našli jsme jednu otázku, která mátla — a opravili ji

Nejsilnější nález (opět shoda všech tří modelů): otázka „co chceš zlepšit" míchala dvě různé věci dohromady — bolístku („neumím se prosadit") a odměnu („chci vyšší plat"). Člověk pak nevěděl, podle čeho vybrat. A hlavně jí chyběl ten nejsilnější, nejkonkrétnější moment, který cílovku pálí.

Přepsali jsme volby na čtyři jasné bolístky jazykem, kterým cílovka reálně mluví: „Na poradě ze mě nevypadne ani půlka toho, co chci — a pak to za mě řekne někdo jiný", „Neumím si říct o cenu, radši cuknu", „Zamrznu, když je tlak — stáhne se mi krk, mám okno", „Chci mluvit sebejistě a s autoritou".

Proč takhle: V předchozím výzkumu jsme zjistili, že tohle jsou přesně věty, kterými se cílovka popisuje. Když se v otázce pozná („to je přesně můj případ"), odpoví upřímněji a klon ji líp trefí. Odměnu jsme přesunuli do jiné otázky, kam patří.
3

Přidali jsme otázku „proč to řešíš zrovna teď?"

Podle auditu nejcennější nová otázka. Rozlišuje totiž, jak moc to člověku „hoří": někdo má velkou prezentaci za dva týdny (horký zájemce, spěchá), někdo to řeší dlouhodobě (v klidu). Klon i pozdější komunikace s tím naloží úplně jinak.

Proč takhle: „Čeká mě prezentace za pár týdnů" je nejsilnější signál, že je člověk připravený něco udělat hned. Zároveň nám to dává mapu spouštěčů, podle které se dá načasovat marketing kurzu. Otázka je nepovinná a má i únikovou volbu „řeším to dlouhodobě", aby nikoho netlačila.
4

Doladili jsme, komu klon co nabídne

Přidali jsme otázku, jestli člověk řeší komunikaci za sebe, nebo i za tým/firmu. To rozhoduje, jestli mu klon doporučí individuální produkt, nebo firemní školení. A přemapovali jsme cenová pásma tak, aby odpovídala reálné nabídce SEBA (od kurzu za pár tisíc po mentoring za desítky tisíc).

Proč takhle: Bez téhle informace klon nemůže poznat, jestli mluví s jednotlivcem nebo s někým, kdo rozhoduje o vzdělávání celého týmu — a to jsou úplně jiné nabídky i argumenty.
5

Ošetřili jsme soukromí a souhlasy správně

Na konec, k e-mailu, jsme přidali větu, která cílí na nejsilnější důvod, proč lidé volí online formát: „Odpovědi jsou jen mezi tebou, Petrem a AI. Tvůj šéf ani kolegové se nic nedozví." A vyřešili jsme souhlasy tak, jak to vyžaduje zákon — informace o zpracování AI zvlášť (nutná pro chod), marketingový souhlas zvlášť jako dobrovolné, nepředzaškrtnuté políčko.

Proč takhle: Z výzkumu vyšlo, že experti a manažeři nechtějí přiznat slabinu před kolegy — diskrétnost je pro ně silnější motiv než cena. A správně oddělený souhlas je jednak zákonná povinnost (ověřeno u úřadu pro ochranu údajů), jednak nám dá čistou, důvěryhodnou databázi kontaktů.

Dvě verze, abychom věděli, co funguje líp

Dotazník máme ve dvou verzích a testujeme, která funguje líp. Verze 1 je klikací (rychlé odpovědi z nabídky) — čekáme, že ji dokončí víc lidí. Verze 2 má víc otázek otevřených (člověk píše vlastními slovy) — dá nám autentičtější jazyk cílovky pro pozdější texty na kurz. Návštěvníkům se verze přiděluje náhodně a měříme, jak si obě vedou.

Jak zabráníme slepé verzi Aby se nestalo, že by nám jedna verze tiše nefungovala a my o tom nevěděli, dotazník si zaznamenává průběh — kterou verzi člověk dostal, kde případně odešel, jestli dokončil, jestli dal souhlas. Zatím se to sbírá lokálně; jakmile bude hotová serverová část, statistiky se budou vyhodnocovat centrálně a půjde přepnout na verzi, která vyhrává.

Dotazník načisto — postaveno a běží živě

Aktuální stav (2. 7. 2026)

Všechno níže popsané je hotové a nasazené — dotazník běží na ai.sebacademy.cz. Otázky se načítají z databáze (žádné „zadrátování" v kódu), tým je spravuje v administraci bez programátora, funguje A/B porovnání dvou verzí, živý profil klona i zrcadlo na konci. Vizuál jede v barvách a písmu SEBA Academy a používá profesionální sadu ikon. Právě teď začíná další krok: prémiový redesign — stejná data a logika, ale zážitek dotažený na úroveň špičkových aplikací (koupili jsme k tomu profesionální knihovnu Untitled UI, ze které se skládá nové rozhraní).

Nejdřív jsme vyřešili obsah otázek — že se ptáme na správné věci správným jazykem. Pak druhou půlku: formu a zážitek. Dotazník už nestojí na „zadrátovaných" otázkách v kódu — postavili jsme ho načisto jako hravý, mobilní zážitek, u kterého má člověk pocit, že vyplňováním něco získává. A Petr (a tým) má plnou kontrolu nad otázkami bez programátora. Takhle jsme to postavili:

A

Nejdřív mobil — protože odtud přijde 9 z 10 lidí

Drtivá většina lidí přijde z telefonu, ne z počítače. Proto se celý dotazník navrhuje od mobilu — žádný zbytečný balast okolo, každý prvek musí dávat smysl na malé obrazovce. Inspiraci bereme z nejlepších mobilních aplikací dneška. Cíl je jediný: aby co nejvíc lidí dotazník dokončilo.

Proč takhle: Hezký dotazník, který se rozpadne na mobilu, je k ničemu. Když 90 % provozu je z telefonu, mobil není „taky verze" — je to hlavní verze, a všechno ostatní se mu podřizuje.
B

Silná gamifikace — vyplňování má bavit a odměňovat

Dotazník nemá být formulář, ale malá hra. Ukazatel postupu, který jde vidět. Živý „Profil klona", který se před očima skládá, jak člověk odpovídá. Drobné pochvaly mezi kroky, usmívající se panáček, který se rozzáří, jak se blíží konci, animace a konfety v důležitých momentech. U každé otázky navíc krátké „proč se ptáme a co ti to přinese" — aby člověk nevyplňoval do prázdna, ale věděl, co z toho má.

Proč takhle: Lidi nevyplňují dotazníky rádi. Když ale vidí, že jim odpovědi něco stavějí (jejich vlastního klona) a cesta je příjemná, dojdou až na konec. Každá otázka, u které je jasné „proč", snižuje počet lidí, co to vzdají.
C

Zrcadlo na konci — „takhle tě zatím vidím, sedí to?"

Když člověk dojde na konec, dotazník mu shrne, jak ho na základě odpovědí vnímá — a dá mu možnost si to potvrdit nebo doladit. Je to silný moment („aha, oni mě fakt poslouchali") a zároveň nám to dá přesnější podklad pro klona: člověk sám řekne, jestli jsme ho pochopili správně.

Proč takhle: Shrnutí zrcadlí to, co člověk řekl (jeho situaci a cíl), ne soudy o jeho povaze — pozitivně a bez definitivních nálepek. Působí to hezky, nikoho to neurazí a klon pak navazuje na to, co si člověk sám odsouhlasil.
D

Otázky pod kontrolou — bez programátora

Otázky se přesunou z kódu do administrace. Petr (nebo tým) tak bude moct upravit znění, pořadí, doprovodné texty i nabízené odpovědi sám, kdykoliv — bez čekání na vývojáře. K tomu přehled, odkud lidé chodí (z jaké reklamy, videa, odkazu), statistiky odpovědí a srovnání obou verzí na jednom místě.

Proč takhle: Znění otázek je po auditu odladěné, ale copy se vždycky ladí za provozu. Když je editace v adminu, drobná úprava textu je otázka minuty, ne úkol pro programátora. Vše pod jednou střechou (leady, katalog, dotazník), jedno přihlášení.

Jaký má být výsledek

Dotazník má být nízkoprahová brána, která si získá důvěru — ne výslech. Pár otázek, ze kterých se člověku „skládá jeho AI klon", a přitom nám každá odpověď dává trojí užitek:

1. Nastaví klona na míru — klon pak mluví ke konkrétní situaci člověka, ne obecně.
2. Kvalifikuje zájemce — víme, kdo to je, co řeší, jak moc to spěchá a co mu nabídnout.
3. Sbírá data o cílovce — první systematický zdroj informací pro plánovaný online kurz (kdo jsou lidé, jakým jazykem mluví, co je spouští, kolik jsou ochotni investovat).

Obsah otázek je hotový a doložený tvrdými daty — a forma taky: dotazník načisto stojí a běží živě na ai.sebacademy.cz, včetně serverové části (ukládání odpovědí, statistiky, administrace) a A/B porovnání dvou verzí. Další krok: prémiový redesign — projít celý zážitek krok za krokem a dotáhnout ho na úroveň nejlepších aplikací, aby dotazník dokončilo co nejvíc lidí. Až se doladí, napojí se sběr kontaktů do e-mailingu a spustí se první kampaň.

SEO & obsah — kompletní podklad pro tým

Pracovní dokument pro Petra a marketing. Všechna data jsou z reálného výzkumu (níže zdroje), ne odhady. Čísla = měsíční hledanost v Česku (kolikrát lidé daný výraz zadají do Googlu). U každého bloku je syrová tabulka i lidské „co to znamená". Cílem je, aby se podle toho dalo rovnou pracovat — psát obsah, plánovat kampaně, rozhodovat o prioritách.

Zdroje dat (4 vrstvy): (1) Marketing Miner — oficiální napojení, hledanost klíčových slov, sezónnost, konkurence v SERPu, content gap, top stránky konkurence; (2) scraping sebacademy.cz — co web reálně obsahuje a na co cílí; (3) Meta/Facebook Ads — velikost cílového publika v ČR; (4) deep research přes 3 AI modely (Claude + GPT-5.5 + Gemini) — persony, pain points, jazyk cílovky. Datum sběru: 30. 6. 2026. Plné interní dokumenty: research-cilovka-kurzu-2026-06.md + research-keywords-marketing-miner-2026-06.md.
Tři věci, které musíme pochopit jako první

1. Máme silnou značku, ale mrtvý web. Jméno „Petr Vojnar" hledá 2 900 lidí měsíčně, ale web sebacademy.cz má jen ~29 organických návštěv měsíčně. Poptávka existuje, jen ji nezachytáváme.

2. Lidé hledají jinými slovy, než jak o problému mluví. „Jak se prosadit" prakticky nikdo nehledá (10/měs), zato „asertivita" 6 200×. To rozhoduje, jaká slova dáme na web.

3. V našich tématech je konkurence slabá. Velké portály táhne Excel a angličtina, ne komunikace. Klíčová témata jako asertivita nikdo pořádně neobsadil — je tam volno.

1 · Klíčová slova — na co je poptávka

Co cílovka reálně zadává do Googlu, seřazeno podle objemu. Vysoký objem = velká poptávka. „Peak" = měsíc, kdy se to hledá nejvíc (důležité pro načasování). Zeleně zvýrazněné řádky = největší příležitosti (vysoká poptávka, zvládnutelná konkurence).

A) Velká témata (vrch trychtýře — sem míří obsah a budování značky):

Klíčové slovoHledanost/měsPeakPozn.
asertivita6 200ledenpilíř nikdo neobsadil
prokrastinace4 900gap jen blog konkurence
introvert4 500zářípozor: vztahový záměr (viz sekce 5)
úzkost3 600leden (6 400)klinické — citlivá hranice
asertivní3 300pilíř
petr vojnar2 900kvě/zářznačka! web netěží
sociální fobie1 800říjenklinické
rétorika980 (MM: 1 800)zářívlastní Škola rétoriky
charisma1 700říjenvysoká hodnota (CPC 77 Kč)
leadership1 500manažerská cílovka
soft skills1 400zářízastřešující kategorie
public speaking1 100listopadraketově roste (+2046 % r/r)
emoční inteligence1 200gap
storytelling1 000srpenroste
manipulace810–930listopadobranná stránka komunikace
řeč těla510záříneverbální komunikace
vliv / autorita380 / 360říj / ledbrand témata SEBA
elevator pitch330SEBA to učí

B) Produktové / nákupní dotazy (spodek trychtýře — člověk už chce koupit kurz):

Klíčové slovoHledanost/měsTrend r/rHodnota (CPC)
mentoring1 100−18 %15,42 Kč
masterclass990−19 %27,96 Kč (vysoká)
kurz komunikace190−11 %8,31 Kč
kurz rétoriky140−17 %9,19 Kč
zbraně vlivu120−8 %2,98 Kč — náš produkt!
manažerské dovednosti110−52 %9,48 Kč
obchodní dovednosti100−48 %9,54 Kč
b2b prodej60+1 %56,74 Kč (extrémní!)
leadership kurz60−32 %20,82 Kč
škola rétoriky60+35 %10,96 Kč — konkurent
kurz rétoriky praha50+36 %5,62 Kč — roste, lokální
prezentační dovednosti kurz20−13 %14,26 Kč
Pro Petra: čím vyšší „CPC" (cena za proklik v reklamě), tím cennější slovo — inzerenti za něj platí, protože vede k prodeji. „b2b prodej" za 56 Kč/proklik ukazuje, že firemní segment je lukrativní. „zbraně vlivu" je přímo název našeho produktu a lidé ho hledají — musíme na něj na webu rankovat.

2 · Klíčové zjištění: lidé hledají jinak, než mluví

Nejdůležitější princip pro copywriting i SEO. Cílovka má konkrétní bolesti, ale do Googlu je píše úplně jinými slovy. Ověřeno tvrdě:

Jak o problému MLUVÍ (do dotazníku, do copy)HledanostJak ho HLEDÁ (na web, do reklam)Hledanost
„jak se prosadit na poradě“10asertivita6 200
„neumím si říct o cenu“10vyjednávání310
„strach mluvit před lidmi“10tréma / nervozita190 / 170
„jak si říct o víc peněz“10sebevědomí (cluster)180+
„třesou se mi ruce“20úzkost / tréma3 600 / 190
❌ Kdyby web mluvil jen jazykem cílovkyStránka „Jak se prosadit na poradě" — krásně rezonuje, ale hledá ji 10 lidí měsíčně. Z Googlu nepřijde skoro nikdo.
✓ Co fungujeStránka „Asertivita: jak se prosadit bez agrese" — titulek na vyhledávaný pojem (6 200×), ale uvnitř mluví jazykem cílovky. Z Googlu chodí lidé, text je chytí.
Praktický důsledek: do dotazníku a do textu patří emoční jazyk („ze mě na poradě nevypadne ani půlka") — rezonuje, člověk se pozná. Do titulků, nadpisů a reklam patří vyhledávané pojmy (asertivita, tréma, rétorika). Most mezi nimi = článek s SEO titulkem a lidským obsahem.

3 · Content gap — co psát (témata, kde konkurence boduje a my chybíme)

Tohle je hotová obsahová roadmapa. Marketing Miner našel slova, na která se konkurence v Googlu umisťuje a sebacademy.cz na ně nemá vůbec nic. „Pozice" = na kolikáté pozici v Googlu konkurent je (1 = první místo; 20+ = druhá stránka a dál, kam skoro nikdo nedojde — tzn. i konkurence je tam slabá a jde je předehnat).

Téma (klíčové slovo)Hledanost/měsNejlepší konkurent (pozice)Příležitost
asertivita6 200Seduo (21.) · Top Vision (47.)obří nikdo v TOP 10
prokrastinace4 900Seduo (17.)velká
emoční inteligence1 200Mindtrix (8.)střední
manipulace810Seduo (13.)střední
empatie3 600Top Vision (14.)střední
typologie osobnosti540Seduo (10.)střední
prezentace online480Top Vision (12.) · Seduo (20.)střední
storytelling480Seduo (18.) · Top Vision (19.)střední
small talk420Top Vision (1.)obsazené, ale dá se
námitka (v prodeji)300Seduo (10.)sales pain
win-win vyjednávání450Top Vision (6.)střední
manipulátoři390Top Vision (14.)střední
jak překonat strach140Mindtrix (29.)slabá konkurence
vystupování / „jak být slyšet“380 / 360Top Vision (69. / 26.)slabá konkurence
Jak to číst: čím vyšší číslo pozice u konkurenta (47., 69.), tím hůř je na tom konkurence — takové téma „leží na zemi", stačí napsat lepší článek. „asertivita" má obojí: obrovskou poptávku (6 200) i slabou konkurenci (nikdo v první desítce). Proto je to jednička.

4 · Asertivita do detailu — proč je to jednička

Marketing Miner rozebral i konkrétní otázky kolem asertivity. „Obtížnost" = jak těžké je se na slovo dostat (0–100; nízká = snadné). „Pozice nula" = vyznačená odpověď nad výsledky Googlu (nejlepší možné umístění).

OtázkaHledanost/měsObtížnostBonus v Googlu
co je asertivita38012 (nízká)pozice nula + knowledge panel
asertivita co to je39012 (nízká)
co je to asertivita16012 (nízká)pozice nula + knowledge panel
co znamená asertivita80
Konkrétní akceNapsat pilířový obsah o asertivitě (definice + jak ji rozvíjet + vztah ke komunikaci/sebeprosazení) s autoritou Petra Vojnara. Definiční část cílí na „pozici nula" (obtížnost 12 = reálné). Odsud vést návštěvníky na dotazník → kurz. Vysoká poptávka × slabá konkurence × snadný vstup = nejlepší poměr námahy a výsledku.

5 · Konkurence — kdo je v naší oblasti a jak na tom jsme

Organická návštěvnost = kolik lidí měsíčně přijde na web z Googlu (zdarma, ne z reklam). Ukazuje reálnou sílu v SEO.

WebNávštěv/měs z GoogluProfilCo to znamená pro nás
seduo.cz33 000obří portál (Canva, Excel, angličtina)v komunikaci slabý → nesoupeřit obecně
topvision.cz~ tisíceobsahový stroj na komunikaci (blog)vzor k napodobení
mindtrix.cz1 340online soft-skills kurzyrealistická liga
digiskills.cz1 720online kurzy, roste (+74 % r/r)realistická liga, vzor růstu
skolaretoriky.cz420rétorika (vlastní to slovo)„rétoriku" jim nevezmeme snadno
dalecarnegie.cz~0 organickyprémiový brand, jede na jménoi bez SEO se dá žít na značce
sebacademy.cz29silná značka, mrtvé SEOstartujeme od nuly = velký prostor

Jak vydělává Seduo (a kde je naše mezera): jejich nejnavštěvovanější stránky NEjsou komunikace, ale nástroje — „Canva" (16 570 návštěv/měs!), Excel, Office, angličtina. Jejich stránka o komunikaci/asertivitě se umisťuje až na 58. pozici. To potvrzuje: v komunikaci je velký hráč slabý a je tam pro nás díra.

Přímí konkurenti pod vlastním jménem (osobní brandy podobné Vojnarovi) — modely zmínily: Daniel Šmíd (etiketa), Martin Vasquez (prezentace), René Nekuda, Olga Medlíková. ověřit — jména jsou z AI, je třeba potvrdit, kdo reálně prodává online produkt.

6 · Velikost publika pro reklamy (Facebook / Instagram)

Z Meta Ads — kolik lidí v ČR se dá oslovit placenou reklamou podle zájmů a věku. Reálná čísla z reklamního účtu.

SegmentCíleníVelikost v ČR
Široký28–55 let · osobní rozvoj + podnikání + leadership + motivace1,4–1,6 mil.
Úzký kvalitní30–50 let · leadership development + business networking + sales management269–316 tis.
Pozn. pro markétera: úzké zájmy typu „public speaking" nebo „rétorika" v ČR na Facebooku jako samostatné zájmy neexistují (nejde na ně cílit). Cesta = široké byznys zájmy + pozice (job titles) + hlavně lookalike z e-mailové databáze a z lidí, co projdou dotazníkem/klonem. To je další důvod, proč je dotazník na vstupu klíčový — vyrábí podklad pro přesné cílení reklam.

7 · Načasování — kdy se co hledá

Hledanost kolísá podle roku. Obsah i kampaně má smysl nasazovat s předstihem před vlnou, ne náhodně.

OknoCo rosteProč
Září (nejsilnější)rétorika, řeč těla, soft skills, sociální fobie, zbraně vlivu„restart" po létě, řešení kariéry, firemní rozpočty na Q4 — launch kurzu v září sedí
Leden (druhé)asertivita, úzkost (6 400!), autorita, kurz onlinenovoroční předsevzetí, „letos na sobě zapracuju"
Listopadpublic speaking, manipulaceBlack Friday — okno pro slevovou akci
Červenec–srpen, prosinec(útlum)dovolené, svátky — slabá období

8 · Kde NEtlačit (ať neplýtváme rozpočtem)

!

Dvě upřímná upozornění

Nesoupeřit se Seduem obecně. Mají 33 000 návštěv měsíčně, ale na nástrojích (Canva, Excel). V komunikaci jsou slabí — tam buďme lepší, ne je dohánět všude.

Pozor na téma „introvert“ (4 500/měs). Zní lákavě, ale Marketing Miner ukázal, že lidé u něj řeší vztahy a osobnost, ne kariéru („kdo je introvert", „jak milovat introverta", „zamilovaný introvert"). Pro prodej kurzu slepá ulička. V dotazníku ho ale využijeme — jako způsob, jak se cílovka sama zařadí.

Klinická témata (úzkost 3 600, sociální fobie 1 800) mají obří objem, ale ti lidé hledají terapii, ne kurz. SEBA není terapeut — nesmíme slibovat léčbu. Můžeme empaticky oslovit přes „tréma není nemoc, je to dovednost", ale neklinicky.

9 · Akční plán — co dělat (podle priority)

#AkceProč / dopad
1Zachytit vlastní značku„petr vojnar" 2 900/měs + názvy produktů → nejrychlejší a nejjistější zisk, web teď netěží ani jméno
2Pilíř „asertivita"6 200/měs, slabá konkurence, pozice nula na dosah → vstupní brána do komunikačních témat
3Obsahová roadmapa dle Top Visionprokrastinace, emoční inteligence, manipulace, small talk, storytelling — ověřená poptávka
4Most obsah → dotazník → kurzkaždý článek vede k dotazníku/klonu → z návštěvníka zájemce
5Reklamy: lookalike z databáze + dotazníkupřesnější cílení než zájmy; dotazník vyrábí podklad
6Načasovat na září + ledennasadit obsah s předstihem před vlnami
7Dvě roviny jazyka všudeSEO titulky = vyhledávané pojmy; text uvnitř = jazyk cílovky

Shrnutí pro rozhodnutí

Máme silnou značku, slabou konkurenci v klíčových tématech a hotovou mapu, kam mířit. Web startuje od nuly, takže i základní práce přinese velký skok. Největší a nejrychlejší zisky: (1) zachytit vlastní jméno a produkty, (2) obsadit asertivitu, (3) jet obsahovou roadmapu podle toho, co konkurenci funguje — vždy s autoritou Petra Vojnara a s mostem do prodejního trychtýře.

Tahle stránka je výtah. Plná data (všech ~260 klíčových slov, kompletní content gap, top stránky konkurence) jsou v interních research dokumentech — k dispozici, když budeme něco rozhodovat do hloubky.

SEBA Academy — AI klon Petra Vojnara: Platforma pro kvalifikaci a prodej

Verze: 0.10 (jádro produktu hotové v0.9 + předběžný market research cílovky kurzu jako podklad pro úpravy dotazníku — fáze A) Datum: 2026-06-30 Autor: Honza Gronka + Claude (Opus 4.8) Status: Návrh ke schválení — připraveno jako zadání pro ultraplan Přílohy: schema.sql (CREATE TABLE + RLS + indexy), api-contracts.md (rozhraní mezi subsystémy), HANDOFF-2026-06-30.md (shrnutí stavu) Review: v0.1 prošla adversariálním panelem (architekt, datový model, security/GDPR, produkt/sales) — 51 nálezů (12 critical, 15 high), v0.2 je zapracovala. v0.3 vyřešila 3 sporné body (cenové pásmo, Gemini tier, metriky) + ukotvila strategický kontext (warmup ke kurzu). v0.4 doplnila §10b: identita přes účet, limity volání. v0.5 aktualizovala §0b (reálný stav: OpenRouter embeddingy, RAG hotový) + přidala SQL a API přílohy. v0.7 (audit): sjednocen chat model napříč dokumentem na gemini-3.1-flash-lite přes OpenRouter; přerámován §0b na „co z legacy přebíráme vs. stavíme od nuly”. v0.8–0.9 (2026-06-30): dotaženo jádro produktu — matching rubrika (§6.5: matchProducts(), buyer_role B2B/B2C, dvě vrstvy), maturity rubrika (§6.4: maturityEval(), signály, práh, keyword override), gamifikovaný dotazník (§5.5: gap-analýza reálného kódu marketéra + plán úprav + market research vrstva), životní cyklus konverzace (§6.9: re-entry, cold lead, anon merge), rozhodnutí o dvou klonech (warmup zdarma + budoucí prémiový v kurzu). Druhý nezávislý audit (council — 4 kritici: skeptik/pre-mortem/budget-hawk/skills-engineer) → 4 must-fix opraveny (trigger klasifikátoru + keyword override, cold lead jen se souhlasem, sjednocení identity na magic-link + events tabulka, raw_answers vs. výmaz). GDPR model souhlasů ověřen u ÚOOÚ (§5.5/§9.4: titul podle účelu — AI zpracování = nutnost služby, kontakt/marketing = aktivní souhlas; „pokračováním souhlasíte” je neplatné). v0.10 (2026-06-30): předběžný market research cílovky zářijového kurzu (fáze A, jako podklad pro úpravy dotazníku §5.5) — deep research přes 3 modely (research-cilovka-kurzu-2026-06.md) + keyword/SEO/audience data z Marketing Mineru, scrapingu SEBA a FB Ads (research-keywords-marketing-miner-2026-06.md). Klíčový princip pro dotazník: dvě roviny jazyka (emoční pain fráze do dotazníku, vyhledávané termíny do SEO). Nemění logiku produktu, jen podkládá §5.5 daty.

Jak číst tento spec (důležité pro ultraplan): Toto je zadání pro přestavbu od základu, ne popis stávajícího kódu. Existující appka v AI-clon/ byla throwaway test napojení na OpenRouter (autor: brigádník přes Antigravity) — ověřila, že chat model, embeddingy a RAG fungují. Na téhle appce se NESTAVÍ. Z legacy se přenese jen několik izolovaných, ověřených kusů (viz §0b „CO PŘEBÍRÁME”); zbytek je greenfield. Když spec píše „funguje” nebo „implementováno”, myslí tím princip ověřený v testu, ne hotový modul nové platformy.


0. Co se změnilo proti v0.1 (shrnutí reworku)

Pozn. k „stávajícímu”: legacy appka (brigádník, Antigravity) byla throwaway test napojení — viz §0b. Tam, kde tato sekce mluví o „kódu” / „rozšíření stávajícího”, jde o stav toho testu; platforma se staví od základu, ne jako jeho rozšíření.

Review odhalilo, že v0.1 popisovala jako „rozšíření stávajícího” tři vrstvy, které v legacy testu neexistují a postaví se od nuly: 1. Perzistence stavu — legacy chat nic neukládá (bezstavový route.ts, stav v localStorage). Doplněn jako samostatný subsystém (E). 2. Strukturované signály — model produkuje jen prózu; matching/lead/banner potřebují strojově čitelný výstup. Doplněna architektura klasifikátoru (§6.4). 3. Bezpečnostní vrstva — v DB žádná RLS; plánovaný anon-zápis z WP = únik CRM. Přepracováno (§3.6, §9). Dále opraveno: identita (handoff token místo user_id v URL), datový model (cenové varianty + měna), GDPR (výmaz, souhlas, přenos do Gemini), sales logika (rozpočet jako signál ne strop, warm leady), metriky, fázování.


0b. VZTAH K LEGACY APPCE — co přebíráme vs. co stavíme od nuly (pro ultraplan klíčové)

Stav k 2026-06-28. Existující appka v AI-clon/ je throwaway test (brigádník, Antigravity) — sloužila k ověření napojení na OpenRouter a funkčnosti modelů/RAG. Na ní se NESTAVÍ. Platforma se staví od základu; z legacy se přenese jen několik izolovaných ověřených kusů. Tahle sekce říká, co přesně recyklovat a co psát greenfield.

Posouzení znovupoužitelnosti provedeno čtením reálného kódu (2026-06-28). Závěr: legacy není slepá ulička ani základ — je to svazek 2 kvalitních modulů + infrastruktura, kolem nichž je throwaway frontend a bezstavový endpoint k zahození.

♻️ CO PŘEBÍRÁME Z LEGACY (ověřené, znovupoužitelné — kopírovat, ne psát znovu)

  • OpenRouter chat modulsrc/lib/chat.ts. Completions přes OpenRouter (OpenAI-kompatibilní /chat/completions), implicit caching (cache_control: ephemeral), reasoning (effort), usage tracking (cached/reasoning tokens, cost). Čistý izolovaný modul, kvalitní error handling. Přenést jak je, jen vyměnit system prompt (nový pro sales/orchestraci). Model: gemini-3.1-flash-lite přes OpenRouter (ověřeno funkční).
  • OpenRouter embedding modulsrc/lib/embeddings.ts (embedText). google/gemini-embedding-2, 768-dim, validace dimenzí, timeout. Přenést jak je. KRITICKÉ: ingest i chat MUSÍ stejný embedding model, jinak vektory nesedí.
  • Infrastruktura — Dockerfile (multi-stage, node:24-alpine, standalone), docker-compose, next.config, tsconfig. Přenést jak je, rozšířit env o nové klíče (auth, CRM).
  • RAG základ — Supabase pgvector, tabulka documents (768-dim), funkce match_documents. Migrace 00000000000001_schema_documents.sql + 00000000000002_grants_documents.sql. Přenést + rozšířit (metadata/filtr §13, CRM tabulky §3). 208 chunků z knowledge/ je naindexováno — RAG princip ověřen funkční.
  • Chunking logikascripts/ingest.mjs (deterministický sliding-window, ~5 chunků/soubor). Přenést princip; file→DB pipeline se upraví podle nového zdroje obsahu.
  • Markdown + mermaid renderer + styling — z src/app/page.tsx (MarkdownMessage) a globals.css (glass panel, gradients, Tailwind). Vykopírovat komponentu a styly do nového frontendu (chat fáze je bude potřebovat).

🔨 CO STAVÍME OD NULY (greenfield — throwaway legacy se zahazuje)

  • (C) Chat endpoint + orchestrace — legacy route.ts je bezstavový throwaway (request→reply, žádný DB zápis kromě čtení). Nový /api/chat (§6, api-contracts §3): perzistence zpráv, čtení profilu ze session, klasifikátor signálů, matching. Z legacy se recykluje jen volání chat.ts/embeddings.ts.
  • System prompt — legacy src/lib/prompt.ts je hyperspecifický pro „AI Petr mentor” → přepsat pro sales/lead-gen tone + orchestrační logiku (maturity, produktové doporučení). Princip „strukturovaný cachovatelný prompt s kostrou” zůstává (§6.7).
  • (A) Gamifikovaný dotazník — neexistuje (jen prototyp marketéra protocol-dotaznik.pages.dev). Custom React embed do WP/Elementor.
  • (B) CRM / datová vrstva — neexistuje. Tabulky user_profiles, conversations, messages, leads, products, product_variants, product_terms, consents, usage_limits (viz schema.sql).
  • (D) Admin — neexistuje (legacy má jen tlačítko „Přihlásit se” = alert placeholder, k zahození).
  • (E) Orchestrace stavu + klasifikátor — neexistuje. Perzistence konverzací serverově, strukturované signály (JSON).
  • Frontend (dotazník→chat→lead flow) — legacy page.tsx je chat-only s localStorage sidebar session managementem. Zahodit (kromě markdown rendereru + stylů výše); nový UI flow se píše od nuly.
  • Identita/účet — neexistuje (Supabase Auth je v legacy vypnutý). Perzistence konverzace v legacy je jen localStorage (brain_sessions) → nahradí DB.
  • Limity volání, matching, sales briefing — neexistuje.

⚙️ KLÍČOVÉ TECHNICKÉ FAKTY pro implementaci

  • Vše přes OpenRouter (chat i embeddingy, jeden klíč OPENROUTER_API_KEY). NE přímý Google (@google/genai) — free tier nemá caching (limit=0). Chat model gemini-3.1-flash-lite, embedding google/gemini-embedding-2, oba s prefixem google/ v plném názvu. Sjednoceno napříč specem (dřív §0b/§6.1 uváděly zastaralý gemini-3.5-flash — opraveno v v0.7).
  • Embedding + chat model v .env (jeden zdroj pravdy). Ingest i chat MUSÍ stejný embedding model.
  • Chat běží v kontejneru, na Supabase sahá přes host.docker.internal:54321.
  • Nasazování (od 2026-07-01): „nic ven / dev jen lokálně” ZRUŠENO — jedeme normální pipeline (Docker lokální test → push → Supabase cloud + server). Hlídat jen osobní data (Gemini přes OpenRouter = prod vypnutý logging/trénink) a nikdy neodeslat reálný mail/webhook subjektům při testu. Veškerá AI komunikace jde na OpenRouter.
  • Mandát: pro tento projekt NEPLATÍ „nezasahuj do cizího kódu” — cíl je prémiová appka stavěná od základu, legacy je throwaway.

1. Účel a vize

1.0 Strategický kontext (čti první — určuje priority)

AI klon NENÍ konečný cíl — je to warmup nástroj na vrcholu trychtýře k plánovanému online kurzu Petra Vojnara (budoucí vlajková loď SEBA Academy). Důsledky pro celou platformu: - Teď: klon zahřívá zájemce, dává hodnotu a doporučuje stávající produkty (mentoring/workshopy/masterclass). - Až bude kurz: stane se prioritním produktem; matching ho upřednostní, klon povede primárně k němu. - Architektura na to musí být připravená (kurz jako budoucí prioritní produkt v katalogu + matchingu), ale sám kurz se nedefinuje, dokud neexistuje. - Cenové pásmo v dotazníku slouží i jako price research pro kurz (kolik je publikum ochotné investovat) — viz §5.3.

1.1 Co stavíme

Z existujícího AI chatbota „AI Petr” (digitální dvojče Petra Vojnara) děláme platformu pro kvalifikaci zájemců a prodej vzdělávacích produktů SEBA Academy — lead-generation a sales nástroj, který: 1. Pozná zájemce už při vstupu (gamifikovaný dotazník → profil). 2. Vede hodnotnou konverzaci v Petrově stylu (čerpá z knowledge kurzu, perzistentně si pamatuje stav). 3. V pravou chvíli (kontextová zralost) doporučí vhodný produkt z portfolia podle profilu a vývoje konverzace. 4. Posbírá/doplní lead (včetně „warm” leadů) a uloží do vlastního CRM. 5. Petrovi dá v zabezpečeném admin rozhraní sales briefing ke každému leadu.

1.2 Mimo rozsah verze 1 (YAGNI)

  • Online platba v chatu (zájemce se objedná přes web/kontakt; chat kvalifikuje a předá lead).
  • Automatické plánování do kalendáře (Petr kontaktuje sám; termín = preference).
  • Online vzdělávací program (zatím neexistuje; doplní se do katalogu).
  • Plnohodnotný e-mailing (CRM nachystá strukturu pro notifikaci; mailing nástroj se nestaví).
  • (Pozn.: identita v1 = magic-link účet, ne handoff token — viz §5.2/§10b, sjednoceno council fixem. Cross-device návrat magic linkem je tedy součást v1, ne odložený plán.)

1.3 Úspěšná kritéria

  • Zájemce projde dotazníkem a vpadne do chatu s předvyplněným profilem (Petr se neptá na to, co zná).
  • Vazba profil↔︎konverzace je bezpečná (žádná krádež identity, žádný IDOR).
  • Chat při zralé konverzaci doporučí 1–2 relevantní produkty podle segmentu a situace (rozpočet jako signál, ne strop).
  • Vznikne strukturovaný lead v CRM (i „warm” bez explicitního „chci”), Petr ho vidí jako sales briefing.
  • Dev: vše lokálně, jediná externí komunikace Gemini, jen syntetická data. Prod: osobní data jen na placeném Gemini tieru (viz §9.5).

2. Architektura platformy

2.1 Subsystémy (5)

┌─────────────────────────┐         ┌─────────────────────────┐
│  (A) Gamifikovaný        │         │  (C) AI chat „AI Petr"   │
│      dotazník            │         │      Next.js / Docker    │
│  custom React embed      │         │  - čte profil (přes      │
│  na WP stránce (Elementor)│        │    session, ne URL)      │
│  sebacademy.cz           │         │  - doporučuje produkty   │
│                          │         │  - sbírá/doplňuje lead   │
└───────────┬─────────────┘         └───────────┬─────────────┘
            │ POST profil                        │ čte/píše přes
            │ (server endpoint,                  │ server endpoint
            │  ne anon z browseru)               │
            ▼                                     ▼
┌───────────────────────────────────────────────────────────────┐
│  (B) Datová vrstva / CRM (Supabase, RLS default-deny)           │
│  profily · konverzace+zprávy · leady · katalog · variants ·    │
│  termíny · consent log · knowledge (RAG pgvector)              │
└───────────────────────────┬───────────────────────────────────┘
              ┌─────────────┴──────────────┐
              ▼                            ▼
┌─────────────────────────┐   ┌─────────────────────────┐
│  (E) Orchestrace stavu    │   │  (D) Admin pro Petra      │
│      + klasifikátor       │   │  (auth, server-side)      │
│  - perzistence konverzace │   │  - leady + sales briefing │
│  - maturity/segment/lead  │   │  - správa katalogu/termínů│
│    jako strukturovaný JSON│   │  - audit přístupů         │
└─────────────────────────┘   └─────────────────────────┘

(E) je nový subsystém odhalený review — bez perzistence stavu a strukturovaných signálů nemůže fungovat matching, lead ani admin.

2.2 Princip: DB je jediná autorita

Supabase je centrální mozek i zdroj pravdy o stavu. Frontend (chat UI) přestává být zdrojem pravdy — konverzace se ukládá serverově po každém tahu. Subsystémy komunikují přes Supabase, ne mezi sebou. Identita subjektu se řeší přes server-side session, ne přes URL.

2.3 Technický stack (základ z legacy testu, viz §0b)

  • Chat: Next.js 16.1.6, React 19.2.3. AI přes OpenRouter (OpenAI-kompatibilní /chat/completions i /embeddings, jeden klíč) — NE @google/genai přímo (free tier bez caching). @supabase/supabase-js. (Legacy má @google/genai v deps jako pozůstatek testu — v přestavbě se nepoužívá, lze odstranit.)
  • DB: Supabase, pgvector. Dev = lokální (CLI). Prod = Supabase Cloud EU + DPA (viz §9.5).
  • Dotazník: custom React appka embedovaná do WP/Elementor (iframe/script — viz §11/1), sdílí design s chatem.
  • Admin + server endpointy: součást Next.js appky, service_role pouze v server-only modulech.

Hosting architektura (ROZHODNUTO 2026-06-30) — tři vrstvy, každá kde má:

Vrstva Kde běží Pozn.
WordPress (web + promo kurzu) NextHosting PRO (hlavní doména sebacademy.cz) PHP/MySQL, stávající. Odkazuje/embeduje appku.
Next.js appka (dotazník + chat + admin) NextHosting PRO, subdoména ai.sebacademy.cz (SSL funguje), prod root /home3/uqwbayti/ai.sebacademy.cz Node 20/22 přes Passenger (CloudLinux Node App Manager). Bez Dockeru — NextHosting Docker nemá → next start (standalone build), za LiteSpeed reverse proxy.
Supabase (PostgreSQL + pgvector + Auth) Supabase Cloud, EU region (externě), Free tarif Nutně externí — NextHosting má jen MariaDB/MySQL, ne PostgreSQL, ani pgvector (potřebný pro RAG). DPA podepsat. Tarif viz níže.

Supabase tarif (ROZHODNUTO 2026-06-30): Free + vlastní zálohování. Odhad provozu (peak ~4 000 lidí/měsíc, pár dotazů, jen text) je hluboko pod Free limity (50k MAU, 500 MB DB, 5 GB egress) — kapacitně Free stačí ~12×. Projekt je zatím nejistý → neplatit Pro ($25) předem. Dvě slabiny Free (uspání po týdnu nečinnosti + žádné zálohy) řeší denní cron na NextHostingu: - pg_dump proti prod Supabase → záloha-<datum>.sql na disk exonu (120 GB; data jsou KB–MB, vejdou se tisíce záloh). Rotace 30 dní. - Tentýž běh drží projekt naživu (dotaz na DB = reset 7denní inaktivity) → appka nespadne kvůli uspání. - Robustnost (povinné): cron po dumpu ověří, že soubor existuje a NENÍ prázdný; při selhání pošle alert (mail). Jinak tichý výpadek = ani záloha, ani keep-alive. - Restore otestovat jednou ručně (psql < záloha.sql do čistého projektu) — neověřená záloha je jen pocit. - Upgrade na Pro ($25) zvážit, až (a) poroste provoz nad pohodlí Free, nebo (b) bude vadit závislost na vlastním cronu místo managed záloh. Není to teď nutné.

  • „Vše na exonu kromě DB”: appka i web na NextHostingu (jednotná značka, subdoména), Supabase externě (technická nutnost, ne volba).
  • Sdílení dat s WordPressem (pokud bude potřeba — produkty/objednávky): přes WP REST API, NE sdílená DB (WP=MySQL, klon=Supabase=PostgreSQL, různé databáze).
  • Pozn. pro ultraplan / vrstvu 1: ověřit Next.js 16 přes Passenger bez Dockeru (standalone výstup, port binding, env proměnné na CloudLinux). NextHosting nepodporuje dlouhoběžící daemony nad rámec app procesu — klasifikátor/async úlohy řešit v rámci request lifecycle nebo přes cron (min. interval 1 min), ne jako samostatný worker.

3. Datový model (Supabase)

documents (RAG, pgvector 768) už existuje. Níže nové/upravené. Všechny tabulky s osobními údaji: RLS ON, default-deny (§3.6). Všude created_at + updated_at (+ trigger), FK indexy, soft delete deleted_at kde jsou osobní data.

3.1 user_profiles — profil zájemce

sloupec typ popis
id uuid PK
created_at / updated_at timestamptz
deleted_at timestamptz NULL soft delete (GDPR)
name / email / phone text / text / text NULL kontakt (phone volitelný)
profession / comm_goal / situation / desired_outcome text z dotazníku
previous_attempts / prior_experience text NULL
perceived_value text NULL cenové pásmo — jen signál, ne strop (§6.5)
has_company boolean NULL firma/tým (sekundární/legacy signál — matching řídí buyer_role)
buyer_role text NULL CHECK in (self/team_lead/org_decision) kdo kupuje — řídí B2B vs. B2C větev matchingu (§6.5.2, A4). Z dotazníku C2.1 nebo doplněno v chatu.
raw_answers jsonb immutable archiv odpovědí (+ questionnaire_version)
questionnaire_version text verze dotazníku (interpretace raw)
  • Partial UNIQUE na email WHERE deleted_at IS NULL + upsert podle e-mailu → jeden subjekt místo N duplicit (mobil/desktop/návrat). Alternativa: povolit duplicity + merge v adminu (rozhodnout — §11/8).
  • Souhlas NENÍ boolean zde — řešen samostatně v consents (§3.7).
  • raw_answers (immutable) vs. strukturovaná pole (řeší D7 contact_delta): raw_answers = nedotknutelný archiv odpovědí dotazníku (pro research, nikdy se nepřepisuje). Strukturovaná sloupce (profession, situation, buyer_role, has_company…) jsou odvozená/obohatitelná — klasifikátorový contact_delta (co se nově zjistilo v chatu, §6.4) aktualizuje tyto sloupce, ne raw_answers. Tím se profil obohacuje konverzací, ale původní odpovědi zůstávají auditovatelné.
  • Vazba na účet (§10b): auth_user_id uuid NULL FK → Supabase Auth (když si zájemce nastaví účet/heslo). Identita pro limity + návrat. Dokud nemá účet, profil žije jen přes magic-link session.

3.1b usage_limits — počítadlo zpráv (§10b.3)

sloupec typ popis
id uuid PK
subject_key text identita: account:<id> / session:<id> / ip:<hash> (vrstvený limit)
window_start timestamptz začátek počítaného okna (denní/klouzavé)
message_count int počet zpráv v okně
updated_at timestamptz

Index na (subject_key, window_start). Server inkrementuje atomicky při každém tahu, kontroluje měkký/tvrdý práh. IP ukládat jako hash (GDPR minimalizace).

3.2 conversations — konverzace (hlavička)

sloupec typ popis
id uuid PK
user_id uuid FK → user_profiles NULL NULL = anonymní (přímý vstup)
created_at / updated_at / last_message_at timestamptz last_message_at pro řazení
deleted_at timestamptz NULL
state jsonb orchestrační stav (§6.4): maturity, segment_guess, offered_products[], known_fields, last_classified_at

3.3 messages — zprávy (append-only)

sloupec typ popis
id uuid PK
conversation_id uuid FK → conversations
created_at timestamptz
role text CHECK (user/model/system)
content text

Samostatná tabulka (ne messages jsonb v conversations) — append-only, stránkovatelné, bez race při read-modify-write blobu. Stav „jak daleko jsme” žije v conversations.state, NE v ořezané historii.

3.4 leads — kvalifikovaný lead (i warm)

sloupec typ popis
id uuid PK
user_id uuid FK → user_profiles NULL NULL povoleno (lead z anon konverzace) NEBO se nejdřív založí lazy profil
conversation_id uuid FK → conversations
created_at / updated_at / contacted_at / status_changed_at timestamptz
status text CHECK new / warm / contacted / won / lost
temperature text CHECK hot / warm / cold (pro řazení Petrem)
source text CHECK questionnaire / direct (atribuce)
recommended_product_ids jsonb co systém nabídl
selected_variant_id uuid FK → product_variants NULL co zájemce vybral
preferred_term_id uuid FK → product_terms NULL preferovaný termín (ne volný text)
contact_name / contact_email / contact_phone text immutable snapshot v okamžiku vzniku (dokumentováno)
sales_briefing text viz §6.6 — ne profil, ale předávací briefing

3.5 products + product_variants + product_terms

products (evergreen identita produktu): | id | slug (UNIQUE) | name | category (ENUM/CHECK: mentoring/firemni/workshop_open/masterclass) | segment (CHECK: individual_low/individual_high/company) | description | url | active |

product_variants (řeší cenové varianty + měnu — klíčová oprava): | id | product_id FK | term_id FK NULL | variant_name (NULL/‘Standard’/‘Premium’) | currency (CHECK ‘CZK’/‘EUR’) | price_minor int (haléře/centy) | vat_included bool | price_from int NULL | is_custom_quote bool | active | > Masterclass = 2 varianty na termín (Standard/Premium). Otevřený workshop = CZK i EUR varianta. Firemní = is_custom_quote=true + price_from. DPH přes vat_included, ne volný text.

product_terms (jen kapacita/místo/datum — BEZ ceny, ta je ve variants): | id | product_id FK | date | location | capacity | spots_left CHECK(0..capacity) | active |

3.6 RLS (Row Level Security) — kritická vrstva

  • Default-deny na všech tabulkách s osobními daty (user_profiles, conversations, messages, leads, consents).
  • Anon klíč (client-side): POUZE čtení katalogu (products/product_variants/product_terms WHERE active) — nic víc, žádný přístup k osobním datům.
  • Veškerý zápis osobních dat jen přes server endpointy se service_role (validace, rate-limit, consent check).
  • Pravidlo do specu: každá nová tabulka s osobními údaji = RLS ON + default deny, policy testovat adversariálně (pokus o čtení cizího řádku). RLS i lokálně (dev/prod parita — §9.6).

3.7 consents — granulární souhlas (GDPR čl. 7)

id | user_id FK | created_at | purpose (CHECK: qualification_contact / ai_processing_google / marketing) | granted bool | consent_version text | consent_text_snapshot text | source text |

Jeden boolean nestačí: souhlas musí být per účel + doložitelný (kdy, jaké znění, verze). Viz §9.4.

3.8 GDPR výmaz (mechanismus)

  • Výmaz = anonymizace (name/email/phone/situation → NULL/‘[smazáno]’, raw_answers → NULL — není trvale immutable, GDPR > archiv), zachová strukturální záznam pro účetnictví.
  • FK leads.user_id / conversations.user_id: ON DELETE SET NULL (ne CASCADE — netiše nemazat historii).
  • messages.conversation_id: ON DELETE RESTRICT (council fix) — konverzaci s historií NELZE tvrdě smazat, chrání audit stopu. Konverzace se ruší jen soft (deleted_at); messages se při výmazu anonymizují UPDATE, ne DELETE. Doporučeno revoke DELETE i pro service_role.
  • gdpr_deletion_log (kdo/kdy/jaký subjekt) pro doložitelnost.
  • Retence per status (např. lost lead anonymizace po X měsících).
  • Pozor: náš výmaz nesmaže, co už prošlo přes OpenRouter/Gemini → proto na prod vypnutý trénink/logging na OpenRouteru + jen relevantní data (§9.5).

4. Produktový katalog — obsah

Ceny ověřené z webu 2026-06-27. Před nasazením znovu ověřit. Detail v memory seba-produktove-portfolio. Cenová pásma dotazníku synchronizovat s tímto ceníkem (§5.3).

Produkt Segment Varianty / ceny
Mentoring — konzultace 90 min individual_high 7 990 Kč
Mentoring — 1 měsíc (5×75 min) individual_high 44 990 Kč
Mentoring — 2 měsíce (8×75 min) individual_high 67 990 Kč
Firemní workshop company 34 990 / 49 990 / 59 990 / 79 990 Kč (custom quote, price_from)
Zbraně vlivu company od 34 990 Kč (custom quote)
Otevřený workshop individual_low 5 990 Kč / 269 € (2 měnové varianty), termíny rotují
Masterclass říjen (1.10.2026) individual_low Standard 9 990 / Premium 15 990 Kč
Masterclass listopad (12.11.2026) individual_low Standard 9 990 / Premium 15 990 Kč

5. Subsystém A — Gamifikovaný dotazník

5.1 Účel a princip

Před vstupem do chatu posbírat profil zábavnou, motivující formou. Marketér dodal funkční kód (AI-clon/dotaznik-web/index.html, self-contained vanilla JS) — rozvíjíme ho, ne stavíme od nuly. Gap-analýza + plán úprav: §5.5. Brutální gamifikace — u každého pole proč to chceme vědět + jak pomůže, prokládat tipy/infografikou, ukazovat co získají. Telefon volitelný; povinné jen jméno + e-mail.

Dvojí účel dotazníku (klíčové): (1) háček „nastav si AI klona na míru” — zero bariér, gamifikace, příjemné vyplňování; (2) hlavní zdroj dat pro matching/chat (bloky A+B) ZÁROVEŇ market research pro zářijový online kurz. Těžiště dat je v dotazníku (ne v chatu) — většina lidí chat nezapne nebo skončí po 1 zprávě, takže vyplněný dotazník = jediná jistá data. Každá otázka má dvojí výnos (matching signál + research datapoint). Vše rámováno jako „aby tě klon pochopil” → pravdivost dat plyne z motivace mít lepšího klona, ne z donucení.

5.2 Výstup a identita (přepracováno — bezpečnost)

  • Dotazník NEzapisuje z browseru přes anon klíč. POSTuje na serverový endpoint platformy (service_role), který: validuje, rate-limituje (anti-spam + Turnstile/hCaptcha), ověří souhlas, zapíše user_profiles + consents.
  • Identita přes účet (§10b — nahrazuje samotný handoff token): dotazník vytvoří lehký účet (Supabase Auth) a pošle magic link na e-mail. Vstup do chatu rovnou (bez tření); magic link je záloha pro návrat. V chatu měkká výzva nastavit heslo. Session = httpOnly cookie z magic-link/hesla. user_id NIKDY není v URL (IDOR/krádež identity).
  • Magic link / token jednorázový, TTL omezený, single-use, neuhodnutelný.

5.3 Otázky a cenová pásma

Otázky (V1 radio / V2 text, plná parita — viz §5.5): jméno, role, buyer_role (NOVÁ), zájem, situace, spouštěč „proč teď” (NOVÁ), cíl, zkusil, historie, cena, e-mail+GDPR, telefon. Detailní mapování otázka→matching→research v §5.5.

  • buyer_role (NOVÁ, P0): „Řešíš to sám za sebe, nebo i za tým?” → radio self/team_lead/org_decision. Řídí B2B/B2C větev matchingu (§6.5.2). Mapuje na user_profiles.buyer_role.
  • Spouštěč „proč teď” (NOVÁ): „Co tě k tomu přivádí zrovna teď?” → naléhavost pro warm/hot (§6.4.5) + nejcennější marketing datapoint (trigger events pro načasování kampaní kurzu).
  • Cenové pásmo — ROZHODNUTO (zůstává, dvojí role):
    1. Price research pro budoucí online kurz (§1.0) — cenová citlivost publika pro pricing kurzu. Ukládá se vždy (i do raw_answers), nezávisle na matchingu.
    2. Vedlejší signál pro matching (slabý tie-breaker, §6.5.3) — rozhoduje jen mezi cenově odlišnými rovnocennými kandidáty.
  • NENÍ source of truth. Pásmo jen přispívá, nikdy nevylučuje dražší produkt (§6.5 — signál, ne strop).
  • Přemapovaná pásma (rozhodnuto 2026-06-30, korekce hranice 2026-07-01 auditem) — kopírují portfolio + jemnější rozlišení dole kvůli pricingu kurzu:
    • do_3k „Do 3 000 Kč” (očekávaná hladina online kurzu — klíčové pro pricing)
    • 3_10k „3 000 – 10 000 Kč” (workshop/konzultace/masterclass)
    • 10_40k „10 000 – 40 000 Kč” (prémiové/hybridní pásmo, mezikrok k mentoringu)
    • 40k_plus „40 000 Kč a víc / firemní rozpočet” (mentoring 44–68k padne CELÝ sem)
    • nevim „Nevím / nechci teď řešit” (úniková volba — snižuje drop-off na citlivé otázce; audit 2026-07)
    • Horní hranice 40k, NE 45k (audit-korekce): mentoring začíná na 44 990 → hranice musí být POD ním, jinak se produkt rozpůlí přes dvě pásma. Zachovat rámec „hodnota řešení ≠ rozpočet” (framing „kdyby se ti to fakt posunulo”, bez „jednou provždy” = overpromise). Až bude backend, pásma odvozovat z products (jeden zdroj pravdy). Nahrazuje beta-pásma do5k/5-15k/15-30k/30k+.

5.4 Napojení z WP (embed překonán — rozhodnuto §11/1)

Dotazník NENÍ iframe/script embed do WP (překonáno §11/1, 2026-06-30). Běží jako součást samostatné Next.js appky na ai.sebacademy.cz; z WordPressu (sebacademy.cz) vede jen odkaz/tlačítko na appku. Odpadá cross-origin embed → žádný iframe/CSRF problém z Elementoru. Marketérův dotaznik-web/index.html (vanilla JS, self-contained) se portuje do appky (vrstva 4 ultraplanu), ne embeduje do WP.

CORS /api/profile — K OVĚŘENÍ ve vrstvě 1 (změna proti dřívějšímu „allow-list jen sebacademy.cz”): když dotazník i endpoint běží na stejné subdoméně ai.sebacademy.cz (jedna appka), je to same-origin → cross-origin CORS allow-list není potřeba. Allow-list sebacademy.cz by měl smysl jen kdyby dotazník volal API z jiné domény (WP embed). Model potvrdit při stavbě endpointu (§9.3, api-contracts §Pravidla). Anti-bot (Turnstile/hCaptcha) + rate-limit platí nezávisle na CORS.

5.5 Marketérův kód — gap-analýza, plán úprav, research vrstva (NOVÉ 2026-06-30)

Marketér dodal funkční AI-clon/dotaznik-web/index.html (1492 ř.): dva <form> (V1 #quiz radio, V2 #quizV2 text), přepínač verzí, otázky řízené data-* atributy (rozšiřitelné), boční „Profil tvého AI klona” s živým %, personalizace + 5. pád. Handoff = buildPrompt() (1. osoba) → sendData() na webhook → launchKlon() redirect s promptem v URL. Silné NEMĚNIT: brand UI, gamifikace, % ukazatel, mikrotexty „proč to chceme vědět”, personalizace, hybrid radio+reveal text, dvě verze (rozšiřujeme).

Mezery vs. potřeby (bloky A+B + spec):

# Mezera Důsledek Zdroj
C-1 Chybí buyer_role Matching B2B/B2C větev nefunguje §6.5.2
C-2 Chybí spouštěč „proč teď” Žádná naléhavost (warm/hot) + chybí marketing trigger §6.4.5
C-3 Handoff = prompt v URL Křehké, profil se neukládá server-side, žádná session §5.2
C-4 Sběr až na konci Kdo odpadne v půlce = data ztracena §12 drop-off
C-5 Žádný GDPR souhlas Blokuje ostré spuštění §9.7
C-6 Cenová pásma nesedí Beta-pásma neodpovídají portfoliu/kurzu §5.3
C-7 V2 zahodila historii+cenu Slabší kvalifikace ve V2 §5.3

Plán úprav (pořadí pro ultraplan): 1. Frontend (hned, bez backendu): přidat buyer_role + spouštěč do V1 i V2; dofázovat historii+cenu do V2 (parita); přemapovat cenová pásma (§5.3); GDPR souhlasy podle účelu (viz níže — NE „pokračováním souhlasíš”); přidat nové otázky do PROFILE_FIELDS (živé skládání klona).

✅ FÁZE B HOTOVÁ (2026-07-01) — frontend úpravy hotové po 3-modelovém auditu. Před editací proběhl deep research audit dotazníku (Claude+Codex+Gemini) → research-dotaznik-audit-2026-07.md. Audit potvrdil kostru (nepřepisovat) a našel věcný problém navíc: otázka zajem míchala pain a outcome + chyběl moment porady a tréma (přemapováno na čisté pain pointy). Hotovo v dotaznik-web/index.html: (A) přemapovaný zajem, nová spoustec „proč teď”, přemapovaná cenová pásma (do_3k/3_10k/10_40k/40k+/nevím — horní hranice 40k, ne 45k, ať mentoring padne celý do nejvyššího pásma), zostřený cil, GDPR (info o AI bez checkboxu + oddělený NEpředzaškrtnutý marketingový checkbox → answers.consent_contact), microcopy diskrétnosti nad e-mailem, jméno předvyplněné z intra, změkčený telefon; (B) nová buyer_role, nová format/diskrétnost, doladěný role, historie + „jen sleduju obsah”. C2.4 parita vyřešena třetí cestou: signálové otázky (role/buyer_role/spoustec/historie/cena/format) = radio v OBOU verzích, lišit jen otevřené (situace/cil/zkusil/zajem) → parita I izolace jedné proměnné. Přidán A/B split (náhodný 50/50 + ruční override) + tracking (localStorage/console, připraveno na FORM_ENDPOINT). Engine: PROFILE_FIELDS, generateLead, buildPrompt, captureAnswer napojeny. Ověřeno v prohlížeči (obě verze projdou, GDPR default NEzaškrtnutý). Backend (FORM_ENDPOINT/KLON_URL) = vrstva 1 ultraplanu, zatím prázdné.

📋 Finální znění všech otázek (V1/V2, GDPR texty, split/tracking stav, co čeká na backend) = dotaznik-verze-B-2026-07.md — zdroj pravdy vytažený z kódu, podklad pro ultraplan. A/B split + tracking: frontend hotový (náhodný 50/50 + ruční override + lokální tracking), ale admin vynucená verze/poměr + síťový sběr statistik + vyhodnocení = ultraplan (backend)pickVersion() a track() jsou na to připravené, aktivují se s FORM_ENDPOINT.

GDPR souhlasy — model podle účelu (council fix, ověřeno ÚOOÚ/EDPB 2026-06-30): „pokračováním souhlasíte” je pro GDPR souhlas neplatné — souhlas musí být oddělený, aktivní, jednoznačný projev vůle (ÚOOÚ: implicitní souhlas skrytý v textu ani nečinnost neplatí; předzaškrtnuté pole zakázáno — Planet49). Řešení rozlišuje právní titul podle účelu:

Účel Právní titul UI na contact screen
ai_processing_google (klon zpracuje text přes Gemini/OpenRouter) Plnění služby (čl. 6/1/b) — bez toho klon nefunguje, NENÍ souhlas Jen informace + odkaz na zásady: „Tvé zprávy zpracovává AI (Google Gemini přes OpenRouter).” Žádný checkbox → klon funguje bez tření.
qualification_contact (Petr osloví s nabídkou) Souhlas (čl. 6/1/a) — oslovení není nutné pro funkci Aktivní NEpředzaškrtnutý checkbox, oddělený, volitelný: „Souhlasím, aby mě SEBA kontaktovala s nabídkou na míru.”
marketing (newsletter) Souhlas Aktivní checkbox, volitelný, oddělený.
  • Checkbox je jen u dvou volitelných účelů (kontakt, marketing) — ne podmínka vstupu do chatu. Klon i sběr research dat běží bez nich (ai_processing = nutnost služby; research data agregovaně z raw_answers).
  • Cold lead vzniká JEN při qualification_contact.granted=true (§6.9.2). Bez něj profil + research, žádný kontaktovatelný lead.
  • Povinný checkbox pro ai_processing by byl CHYBA (ÚOOÚ: povinný checkbox pro zpracování nutné ke službě nesplňuje svobodnost). Proto je to informace, ne souhlas.
  • Zapsat do consents (§3.7) granulárně per účel + consent_text_snapshot. Sladí C1.3 (TODO) i §9.4.
  1. Backend (vrstva 1 ultraplanu): průběžné ukládání po každém kroku (POST patch → /api/profile, draft podle session id, upsert podle e-mailu) — řeší C-4; server-side handoff (FORM_ENDPOINT=/api/profile, KLON_URL=/chat BEZ promptu v URL) — řeší C-3; session cookie / magic link (§5.2). buildPrompt() zůstává jako copy-paste fallback.

Market research vrstva (marketing kurzu): dotazník = první systematický zdroj dat o cílovce (žádná persona/ICP zatím neexistuje). Každý datapoint slouží i analytice:

Datapoint Výstup pro kurz
role distribuce kdo je cílovka → cílení reklam
buyer_role poměr B2B vs B2C trh → produktová strategie
situace+zajem (text) pain points vlastními slovy → headliny, copy, jazyk LP
spoustec distribuce trigger events → načasování + messaging kampaní
zkusil (text) konkurence → vymezení + kde inzerovat
cena distribuce cenová citlivost → pricing + segmentace

Research data → raw_answers (immutable, §3.1), nezávisle na matchingu. A/B test V1 (radio, strukturované) vs V2 (text, pravdivější jazyk) přímo měří, co dá kvalitnější research. 4 dimenze (pain/spouštěč/konkurence/cena) jsou rozšiřitelné.

⚠️ PŘEDBĚŽNÝ market research HOTOVÝ (2026-06-30, fáze A před úpravou dotazníku). Než dotazník nasbírá vlastní data, máme externí research cílovky zářijového kurzu — slouží jako podklad pro formulace otázek jazykem cílovky a pro spouštěčovou otázku na reálných triggerech: - research-cilovka-kurzu-2026-06.md — deep research přes 3 modely (Claude+Codex+Gemini) + syntéza. Persony, pain points, spouštěče, konkurence, cena, kanály. Má sekci „PRO DOTAZNÍK” s autentickými českými formulacemi pain points/spouštěčů použitelnými 1:1 jako znění otázek/odpovědí. - research-keywords-marketing-miner-2026-06.md — keyword/SEO/audience data (Marketing Miner oficiální MCP + scraping SEBA + FB Ads). Klíčové pro dotazník: DVĚ ROVINY JAZYKA — pain fráze („jak se prosadit” 10/měs) se NEgooglí, ale cílovka jimi mluví → do dotazníku patří emoční jazyk (rezonuje), do SEO vyhledávané termíny (asertivita 6200). introvert (4500) má vztahový/definiční záměr → pro dotazník jako self-identifikace OK, pro SEO ne. - Surové výstupy 3 modelů: research-raw-2026-06/. Brand jazyk SEBA: memory seba-brand-jazyk-web.


6. Subsystém C+E — AI chat + orchestrace stavu

6.1 Co je z legacy ověřené (a co se z toho přebírá)

Legacy test ověřil funkční jádro chatu: model gemini-3.1-flash-lite přes OpenRouter (s caching + reasoning), RAG na documents (208 chunků), kontextová logika nabízení (zralost), banner. Přebíráme z toho moduly chat.ts + embeddings.ts + RAG základ (viz §0b „CO PŘEBÍRÁME”). Samotný chat endpoint a prompt se přepisují kvůli perzistenci a orchestraci (§6.2–6.6). System prompt v legacy je hyperspecifický pro mentor case → nahradí se sales/orchestrační verzí.

6.2 Perzistence konverzace (NOVÉ — subsystém E)

  • Server endpoint po každém tahu (user i model) zapíše messages + aktualizuje conversations.last_message_at. DB = autorita (frontend přestane být zdroj pravdy).
  • Admin pak čte konverzaci z DB, ne z prohlížeče zájemce.

6.3 Načtení profilu (přes session)

Chat načte profil z user_profiles přes server-side session (httpOnly cookie z magic-link účtu, §5.2 — ne handoff token). Profil → system prompt → Petr ví, s kým mluví, neptá se na známé. Fallback (přímý anonymní vstup bez účtu): anonymní režim + úvodní disclosure „tvé zprávy zpracovává Google Gemini” (§9.4), případný merge po vyplnění dotazníku (§6.9.3).

6.4 Strukturované signály + rubrika ZRALOSTI (maturity)

Model produkuje jen prózu. Pro maturity/segment/recommended/lead potřebujeme strojově čitelný výstup. Tato sekce definuje co klasifikátor vrací a jak z toho vznikne maturity — spínač, který spouští nabídku produktu (§6.5), banner (§6.8), most na Petra (§6.7), vznik leadu (§6.6) a event maturity_reached (§12). Bez operacionalizace zralosti je celý lead-gen nereprodukovatelný — proto rubrika níže.

6.4.1 Klasifikátor — co vrací

Druhé levné volání (gemini-3.1-flash-lite přes OpenRouter, function-calling / responseSchema) vracející striktní JSON. Mezi spuštěními platí poslední uložený stav.

Spouštěč klasifikátoru — KONKRÉTNÍ (rozhodnuto 2026-06-30, council fix): dřívější vágní „levná textová podmínka” byla díra — při 1 zprávě (= většina uživatelů) by klasifikátor nikdy neproběhl a warmup klon by nezachytil lead. Pevná pravidla: 1. Vždy po 2. user zprávě a pak po každé další (do té doby není dost kontextu na zralost; první zpráva = pozdrav/dotaz). 2. Okamžitě (mimo pořadí) při lokálním keyword scanu buy_intent — levný regex/keyword test BĚŽÍ BEZ LLM po KAŽDÉ zprávě (i té první) na markery koupěchtivosti: chci, kolik (to) stojí, cena, kdy (můžu/začín), faktur, přihlás, koup, jdu do toho, objedna, zaplat. Hit → vynutí klasifikaci hned (i po 1. zprávě) → zachytí horký lead v okně nejvyššího zájmu. 3. Cena vs. hodnota: §9.5 sám říká, že jedno levné volání je zanedbatelné proti hodnotě obchodu (44–68k mentoring). Šetřit na teplé konverzaci = špatný trade-off. Klasifikátor proto NEomezovat kvótou na úkor záchytu leadu; kvótu řešit cache (§6.7) a tím, že běží od 2. zprávy, ne každou.

Klasifikátor vrací surové signály, NE hotové maturity ani recommended_slugs. maturity dopočítá maturityEval() (§6.4.3), výběr produktů matchProducts() (§6.5).

Klasifikátor nevrací hotové maturity — vrací surové signály, ze kterých maturity dopočítá aplikační kód (maturityEval()). Důvod: stejně jako u matchingu (§6.5) — reprodukovatelnost, laditelnost, testovatelnost. Práh i váhy jsou konstanty, ne věty v promptu. Výjimka: explicitní koupěchtivost (buy_intent) funguje jako override (viz 6.4.3). Klasifikátor nevrací recommended_slugs — výběr produktů dělá matchProducts() v kódu (§6.5).

Výstupní schéma (vynucené):

{
  "signals": {
    "shared_own_situation": true,   // popsal VLASTNÍ konkrétní situaci (ne obecný dotaz)
    "asked_about_solution": true,   // ptá se na řešení/postup, ne jen edukaci/teorii
    "engagement_depth": 2,          // 0-3: smysluplné výměny na vlastní téma
    "emotional_signal": false,      // frustrace/naléhavost/aspirace vlastními slovy
    "repeated_probing": false,      // opakovaně se doptává do hloubky téhož problému
    "explicit_interest": true,      // zájem o ŘEŠENÍ jako téma (ještě ne "chci koupit")
    "buy_intent": false             // EXPLICITNÍ koupěchtivost → override + hot lead
  },
  "segment": "individual_high",     // odvozeno z buyer_role (§6.5.2)
  "contact_delta": { "buyer_role": "self" }   // co se nově zjistilo z konverzace
}

Rozšiřitelnost (ZÁMĚR — 6+1 signálů je odrazový bod, ne strop): seznam signálů poroste, jak budeme pokrývat víc use-casů. Proto jsou signály data, ne kód — definované v konfiguračním seznamu { signal, type, weight }, přes který maturityEval() iteruje. Přidat signál = (1) přidat řádek do configu, (2) naučit klasifikátor ho vracet, (3) případně zvážit váhu per preset. Skóre, práh ani logika se nemění. Nové klíče v JSON staré konverzace nerozbijí (chybějící signál = default 0/false). Kandidáti na rozšíření: named_concrete_event (jmenoval konkrétní termín „za 14 dní prezentuju představenstvu”), compared_options (ptá se na rozdíl mezi produkty), budget_disclosed, objection_raised (řeší §6.5.5).

Error-handling klasifikátoru (řeší D5): klasifikátor je LLM → může vrátit nevalidní JSON, chybět klíč, nebo dát hodnotu mimo rozsah. Pravidla odolnosti: - Vynucené schéma (function-calling / responseSchema) sníží riziko; přesto vždy validovat výstup proti očekávanému tvaru (typy, enum hodnoty segment). - Nevalidní/parse error → fallback na předchozí state (poslední platná klasifikace zůstává) + retry jednou. Klasifikátor běží jen občas (§6.4.1), takže výpadek jednoho běhu = jen odložená re-klasifikace, ne chyba pro uživatele. - Chybějící signál = default (0/false) — neblokuje (viz rozšiřitelnost výše). - segment mimo enum → zahodit (segment_guess zůstane předchozí), logovat. - Halucinace produktu nehrozí — klasifikátor produkty nevrací, výběr dělá matchProducts() v kódu s validací proti katalogu (§6.5 Příloha 6.5-A). Toto je hlavní pojistka D5. - Nikdy nespadnout celý tah kvůli klasifikátoru — chat odpověď (hlavní model) jde uživateli i bez úspěšné klasifikace; signály se doženou příště.

6.4.2 Stav ve conversations.state

Stav se ukládá do conversations.state (jsonb), neodvozuje z ořezané historie (10 zpráv, po nich model ztrácí začátek). Tvar:

{
  "maturity": {
    "reached": false,            // výsledek rubriky (score >= práh ∨ buy_intent)
    "score": 4,                  // poslední spočtené skóre (ladění/telemetrie)
    "offered": false,            // padla už konkrétní nabídka produktu?
    "offered_at": null,
    "declined": false,           // uživatel odmítl/odložil po nabídce?
    "reminded": false,           // proběhlo už jedno jemné připomenutí po cooldownu?
    "last_classified_at": "..."  // kdy klasifikátor naposled běžel
  },
  "segment_guess": "individual_high",
  "offered_products": [],        // slug[] — co už klon nabídl (i pro matching §6.5)
  "known_fields": ["buyer_role", "situation"]
}

Názvosloví segment vs segment_guess (sjednoceno, řeší D7): klasifikátor (§6.4.1) vrací pole segment = jeho aktuální odhad pro tento běh. Ten se ukládá do conversations.state.segment_guess = uložený (poslední) odhad napříč konverzací. Jde o totéž věcně, jen _guess zdůrazňuje, že je to odhad LLM, ne potvrzená pravda (matching/banner pracují s „potvrzeným” segmentem až po doptání). API kontrakt i state používají tento vztah konzistentně.

6.4.3 Rubrika zralosti — skórování (P0-1)

Princip: ne LLM odhad „je to zralé?“, ale deterministické skóre nad signály + práh dle presetu. Hybrid: silný explicitní signál práh přebije.

score = Σ ( weight[preset][signal] × value[signal] )    // iterace přes config, ne if-strom
maturity_reached = (score >= THRESHOLD[preset]) ∨ buy_intent    // override gate

Váhy a práh — preset warmup (zdarma klon, STŘEDNÍ práh — víc prodává):

Signál Hodnota Váha (warmup)
shared_own_situation bool (0/1) 3
asked_about_solution bool (0/1) 3
engagement_depth int 0–3 1 × stupeň
emotional_signal bool (0/1) 2
repeated_probing bool (0/1) 2
explicit_interest bool (0/1) 2
  • THRESHOLD[warmup] = 5. Význam: zralost nastane zhruba při „vlastní situace (3) + jeden další signál (2)” nebo „ptá se na řešení (3) + 2 výměny (2)“. = střední poloha (rozhodnuto): nabídne po pár výměnách + vlastní situaci, nečeká na explicitní zájem. Maximalizuje záchyt leadů u zdarma nástroje, override jistí horké.
  • THRESHOLD[premium] = 8 (budoucí prémiový klon uvnitř placeného kurzu — viz pozn. níže): vyžaduje vlastní situaci i zájem o řešení i hloubku → trpělivý, nedotěrný. Mění se jen tato konstanta + váhy, ne logika.
  • Override: buy_intent=truematurity_reached=true bez ohledu na skóre. Chytí horký lead, co řekne „chci to / kdy začínáme / pošlete fakturu” po 2 zprávách. Override zároveň nastaví temperature=hot (6.4.5).
  • Guard: maturity se přepočítá jen po běhu klasifikátoru (levná podmínka §6.4.1); jinak platí state.maturity.reached.

Dva klony (rozhodnuto 2026-06-29): stavíme nejdřív warmup klon — bude zdarma, lead-gen ke kurzu, proto víc prodává (warmup preset, práh 5). Budoucí prémiový klon poběží uvnitř placeného kurzu, bude trpělivější (premium preset, práh 8). Preset = sada konstant (váhy + práh), ne větev v kódu. maturityEval() je identická pro oba.

6.4.4 Re-trigger po odmítnutí (cooldown + 1 připomenutí)

Po nabídce, kterou uživatel odmítl/odložil („teď ne”, „rozmyslím si”), se nabídka utlumí — klon se vrátí k edukaci (fázové chování §6.7: closing → zpět do edukační fáze). Druhá nabídka smí padnout maximálně jednou a jen při novém silném signálu.

canOffer =
   maturity_reached ∧ ¬offered                  // ještě nenabídnuto → první nabídka
   ∨ ( declined ∧ ¬reminded ∧ newStrongSignal ) // cooldown prošel + nový impuls → 1 připomenutí
newStrongSignal = buy_intent ∨ posun situace (nový shared_own_situation k jinému tématu)
                  ∨ explicitní návrat k nabídce ("ještě k tomu mentoringu...")
  • První nabídka: offered=true, offered_at=now.
  • Odmítnutí: klasifikátor zachytí → declined=true. Banner i textová nabídka se stáhnou.
  • Připomenutí (max 1): při newStrongSignal → jemně, jeden next step (§6.7 closing = stručně), reminded=true. Pak už klon nikdy aktivně nenabízí (jen edukuje), lead zůstává v CRM.
  • Lead nezaniká: odmítnutí ≠ ztracený zájem (§6.6) — warm lead zůstává pro Petra bez ohledu na cooldown.

6.4.5 Teplota leadu (hot / warm / cold)

leads.temperature určuje rubrika podle kvality zájmu (pro priorizaci Petra):

temperature Podmínka Význam pro Petra
hot buy_intent=true (explicitní „chci / kdy / faktura / jak zaplatit”) Volat první. Chce koupit.
warm maturity_reached=trueoffered=true ∧ ¬buy_intent Zralý zájem o téma, nabídka padla, ještě neřekl „chci”. Nurturovat.
cold vyplněný dotazník bez (zralé) konverzace Lead z dotazníku (§6.9.2) — má profil, kontaktovatelný, ale studený.

Pozor na dvojí „warm” (oprava nekonzistence P3): leads.status='warm' (procesní stav v CRM pipeline: new→warm→contacted→won/lost) je ortogonální k leads.temperature='warm' (kvalita zájmu). Status = „kde lead je v pipeline”, temperature = „jak je horký”. Mohou se lišit (status=contacted + temperature=hot). V adminu i kódu rozlišovat názvem pole, nikdy nezaměňovat.

6.4.6 Few-shot příklady (kalibrace klasifikátoru)

Kalibrační sada pro klasifikátor (symetrická s worked příklady matchingu §6.5.4). Slouží jako few-shot v promptu klasifikátoru + jako test fixtury pro maturityEval().

ZRALÁ (maturity_reached=true): 1. „Já na poradách prostě ztichnu, i když mám co říct. Minulý týden mi zase přebrali nápad. Jak se to dá natrénovat?“* → shared_own_situation, asked_about_solution, emotional_signal. Skóre 3+3+2=8 ≥ 5 → zralé (warm, nabídnout). 2. (po 3 výměnách o trémě) „A tohle funguje i na velký publikum? Já mluvím na konferencích.” → engagement_depth=3, shared_own_situation, explicit_interest. Skóre 3+3+2=8 → zralé. 3. „Zní to dobře. Co to stojí a jak se přihlásím?“* → buy_intent=trueoverride, hot lead (i kdyby skóre bylo nízké).

NEZRALÁ (maturity_reached=false — nenabízet): 4. *„Co je to aktivní naslouchání?“* → jen asked_about_solution (obecná edukace, žádná vlastní situace). Skóre 3 < 5 → nezralé (edukovat dál, budovat autoritu). 5. „Dík, to dává smysl 👍” → žádný signál. Skóre 0 → nezralé. 6. „A Petr dělá i workshopy pro firmy?” (bez vlastního kontextu, jen zvědavost) → explicit_interest samotný. Skóre 2 < 5 → nezralé, ale doptat se na kontext (organicky zjistit buyer_role/situaci — §6.5.2). Pozn.: kdyby pak přidal „my máme v týmu problém s prezentacemi”, skočí shared_own_situation → zralé.

6.4.7 Provázání s ostatními subsystémy

maturity_reached=true je spínač: - Matching (§6.5): odblokuje guard matchProducts() (if (!state.maturity) return null). Maturity předá matchingu: segment_guess, known_fields, offered_products. - Lead (§6.6): maturity ∧ offered → vždy warm lead (i bez „chci”). buy_intent → hot. - Banner (§6.8): zobrazit až při maturity, dle potvrzeného segmentu. - Most na Petra (§6.7): „při zralosti” = maturity_reached. - Event (§12): maturity_reached se loguje jednou při prvním přechodu false→true; product_offered při offered=true.

Příloha 6.4-A — Specifikace maturityEval() (pro ultraplan)

Čistá funkce, symetrická s matchProducts() (Příloha 6.5-A):

maturityEval(signals, state, preset) -> { reached, score, temperature, canOffer }
// config: signály jako DATA (rozšiřitelné — viz 6.4.1)
WEIGHTS = {
  warmup:  { shared_own_situation:3, asked_about_solution:3, engagement_depth:1,
             emotional_signal:2, repeated_probing:2, explicit_interest:2 },
  premium: { /* přísnější — doladí tým až vznikne 2. klon (TBD-by-design) */ }
}
THRESHOLD = { warmup: 5, premium: 8 }

function maturityEval(signals, state, preset='warmup') {
  score = Σ over WEIGHTS[preset]: weight × (signals[signal] ?? 0)   // chybějící = 0
  reached = (score >= THRESHOLD[preset]) || signals.buy_intent      // override gate
  temperature = signals.buy_intent ? 'hot'
              : (reached && state.maturity.offered) ? 'warm'
              : 'cold'
  canOffer = (reached && !state.maturity.offered)
          || (state.maturity.declined && !state.maturity.reminded && newStrongSignal(signals, state))
  return { reached, score, temperature, canOffer }
}

Pravidla: - Volá se po běhu klasifikátoru; výsledek zapsat do state.maturity (reached, score, last_classified_at). - canOffer=true → orchestrace pustí nabídku (matching §6.5) + nastaví offered=true, offered_at. - Idempotence: maturity_reached event jen na první přechod false→true (porovnat s předchozím state). - Testovatelnost: čistá funkce → unit testy nad 6 fixturami z 6.4.6 (signály → očekávané reached/temperature). Změna agresivity klonu = změna WEIGHTS/THRESHOLD, ne logiky. - Preset zdroj: konfigurace klona (env/DB), ne hardcode — warmup teď, premium až vznikne druhý klon.

6.5 Doporučovač produktů (matching — rubrika)

Příprava na kurz (§1.0): matching je navržen tak, aby šel online kurz snadno přidat jako prioritní produkt (products.priority, category='course'). Do té doby se nabízejí stávající produkty. Žádný hardcoded strom, který by přidání kurzu bránil. Pravidlo „kurz vs. ostatní” viz 6.5.6.

Matching je deterministická aplikační logika (čistá funkce nad strukturovaným profilem + signály z konverzace), ne věty v promptu a ne volba LLM. LLM (klasifikátor §6.4) jen dodává vstupní signály (segment, buyer_role, zralostní signály); výběr produktu dělá kód matchProducts(). Důvod: reprodukovatelnost, laditelnost, testovatelnost, žádná halucinace produktu mimo katalog. Klasifikátor nevrací seznam produktů — výběr je výhradně v kódu.

Sekce má dvě vrstvy: Vrstva 1 — principy a pravidla (6.5.1–6.5.6, pro čtení) a Vrstva 2 — skórovací specifikace (Příloha 6.5-A, pro ultraplan/implementaci: vstupy, váhy, prahy, pseudokód, validace).

6.5.1 Vstupní signály (A2)

Signál Zdroj Pole Role v matchingu
role / profese dotazník profession Hrubý segment a téma. Manažer/OSVČ/zaměstnanec ≠ stejná nabídka.
zájem / cíl dotazník comm_goal, desired_outcome Téma (prezentace / vyjednávání / brand / prodej) — k formulaci, ne k výběru produktu (produkty jsou tematicky univerzální).
situace dotazník + chat situation Hloubka potřeby. Akutní konkrétní problém → intenzivnější formát (mentoring). Obecný rozvoj → workshop/masterclass.
buyer_role (NOVÉ, A4) dotazník C2.1 + chat nové pole, viz 6.5.2 Rozhoduje B2B vs. B2C větev. Kupuju za sebe / vedu tým / rozhoduju o vzdělávání ve firmě.
historie dotazník prior_experience (+ returning flag) Byl už na akci Petra? → ne znovu vstupní workshop, ale upsell do hloubky (mentoring/masterclass).
cenové pásmo dotazník perceived_value Slabý tie-breaker (signál, ne strop). Rozhoduje jen mezi jinak rovnocennými kandidáty. NIKDY nesráží skóre mentoringu, když situace sedí. Druhá role: price research pro kurz (§5.3).
maturity klasifikátor state.maturity Brána, ne vstup výběru. Matching se spustí, až maturity=true (§6.4/BLOK B).

Pozn.: comm_goal/desired_outcome určují jak se produkt prodá (jaké benefity zdůraznit), ne který — celé portfolio řeší komunikační dovednosti napříč tématy. Výjimka: brand/prodej téma → mírně preferovat masterclass listopad „Brand, komunikace a prodej” a Zbraně vlivu, když jsou jinak rovnocenné.

6.5.2 Detekce company segmentu (A4 — P0)

Problém: boolean has_company nestačí. Zaměstnanec velké korporace („mám firmu” = ano) ≠ manažer s rozpočtem na vzdělávání týmu. První je B2C (koupí workshop sám), druhý je B2B zakázka (35–80k). has_company=true splní oba → špatný matching.

Řešení — nové pole buyer_role (3 hodnoty), nahrazuje has_company jako matching signál:

buyer_role Význam Segment Typická nabídka
self Kupuju za sebe, vlastní rozvoj individual_* workshop / masterclass / mentoring
team_lead Vedu tým, řeším i dovednosti lidí pod sebou company (slabě) firemní workshop NEBO mentoring pro sebe — doptat se
org_decision Rozhoduju/spolurozhoduju o vzdělávání ve firmě, mám/seženu rozpočet company firemní workshop / Zbraně vlivu

Jak se získá: (1) dotazník — nová otázka C2.1 „Řešíš to sám za sebe, nebo i za tým?” → radio sám za sebe / vedu tým / rozhoduju o vzdělávání ve firmě, mapuje 1:1 na buyer_role. (2) chat — když dotazník chybí nebo je signál slabý, klasifikátor doplní z konverzace PŘED doporučením. Nehádat — doptat se organicky.

Schema dopad (ultraplan): přidat user_profiles.buyer_role text check (buyer_role in ('self','team_lead','org_decision')). has_company ponechat (sekundární/legacy), ale matching řídí buyer_role. Klasifikátorový segment_guess (§6.4) z buyer_role odvozovat.

Hraniční případ team_lead: vědomě nejednoznačný. Default = nabídnout obojí k porovnání (mentoring 1:1 pro sebe + firemní workshop pro tým), nechat konverzaci rozhodnout. Nepřiřazovat natvrdo do company.

6.5.3 Rozhodovací rubrika — skórování (A3)

Ne tvrdý strom, ale skóre na produkt: vstupy → váhy → seřazení → entry offer → 1–2 produkty.

Krok 1 — segmentová větev (buyer_role → kandidáti): - org_decisioncompany (firemní workshop, Zbraně vlivu). Entry: bezplatná konzultace k obsahu. - team_leadcompany + individual_high (firemní workshop a mentoring, porovnání). - selfindividual_low + individual_high (workshop open, masterclass, mentoring).

Krok 2 — skóre uvnitř větve (výchozí = products.priority, modifikátory):

Signál Podmínka Efekt
situace akutní/konkrétní problém, deadline, vysoká frekvence řečnění +mentoring, +Premium masterclass (vč. konzultace)
situace obecný rozvoj „chci se zlepšit” +workshop open, +masterclass standard
historie byl už na akci Petra −vstupní workshop, +mentoring/masterclass (upsell, ne opakovat vstup)
historie úplný začátečník +workshop open / masterclass standard (nízkoprahový první krok)
cena (tie-breaker) nízké pásmo jen mezi rovnocennými: workshop open (5 990) > masterclass (9 990). Nemaže mentoring, dá ho jako aspirační.
cena (tie-breaker) horní pásmo / firemní jen mezi rovnocennými: potvrzuje, že mentoring/firemní je v komfortní zóně.
téma brand / prodej / vyjednávání jemně +Zbraně vlivu (company), +masterclass listopad (self)

Pásma = přemapovaný ceník dle §5.3/C2.2 (horní „45 000+ / firemní rozpočet”), ne současná beta-pásma (do5k/5-15k/15-30k/30k+). Hranice z products (jeden zdroj pravdy).

Pravidlo ceny — slabý tie-breaker (rozhodnuto): perceived_value se uplatní POUZE když dva kandidáti mají po krocích 1–2 ~rovné skóre. Nikdy nesnižuje skóre dražšího produktu pod levnější, pokud situace dražší produkt podporuje. Aspirační produkt se vždy aspoň zmíní. Cena se řeší až ve framingu (6.5.5), ne ve výběru.

Krok 3 — entry offer + počet produktů (A5): - Vždy aspoň jeden nízkoprahový vstup vedle aspiračního: konzultace 7 990 (individual_high vstup) / workshop open 5 990 (individual_low) / bezplatná firemní konzultace (company). - 2 produkty (default) = nízkoprahový + aspirační k porovnání. Když: profil nejednoznačný, team_lead, žádný silný 1:1 signál, cena nejistá. - 1 produkt + přímý CTA jen při silném signálu a jasném produktu: explicitní „chci 1:1” ∨ jasná akutní situace + rozpočet sedí ∨ returning s konkrétní poptávkou. Signál „chce 1:1” se získává z konverzace.

Krok 4 — neúplný profil: chybí-li klíčové pole pro matching (buyer_role — větev, situation — intenzita) → doplnit organicky v chatu PŘED doporučením, ne hádat. Bez nich matching nespouštět, i kdyby maturity=true.

VÝJIMKA pro buy_intent (council fix — sladění bran): když uživatel projeví explicitní koupěchtivost (buy_intent=true — „chci to / kolik / kdy / faktura”), guard NESMÍ blokovat doptáváním. Horký lead, který se ptá „kolik to stojí”, nesmí dostat „a řešíš to sám, nebo za tým?“. Místo toho: nabídnout rovnou bezpečný default (workshop open 5 990 jako univerzální nízkoprahový vstup, nebo konzultace 7 990) + adresovat cenu (§6.5.5) + buyer_role/situation doplnit AŽ POTÉ, organicky („abych ti řekl přesně to nej, je to spíš pro tebe, nebo i pro tým?”). Princip: u buy_intent je horší ztratit moment než netrefit přesný produkt. Tím je override sladěný napříč maturitou (§6.4.3) i matchingem — obě brány buy_intent propouští.

6.5.4 Worked příklady (kalibrace)

  1. Freelancer, začátečník, nízké pásmo, „zlepšit prezentace”. self, začátečník, obecná situace. → workshop open 5 990 (entry, nejbližší termín) + masterclass standard 9 990 (aspirační). Mentoring zmínit jen jako „když budeš chtít do hloubky 1:1”. 2 produkty.
  2. Manažer, rozhoduje o vzdělávání týmu, 8 lidí, firemní rozpočet. org_decision. → firemní workshop (délka dle hloubky, custom quote) + bezplatná konzultace k obsahu. Zbraně vlivu jako tematická alternativa. 2 produkty, jeden CTA = konzultace.
  3. Obchodník, akutně řeší konkrétní vyjednávání, „natrénovat 1:1”, střední pásmo. self, akutní+frekventní, explicitní 1:1. → mentoring 1měsíční 44 990 (1 produkt + CTA). Cena nad pásmem → framing ROI/cena za sezení (6.5.5), neustupovat na workshop. Konzultace 7 990 jako „nezávazný první krok”, když zaváhá.
  4. Byl loni na otevřeném workshopu, vrací se, „jít hlouběji”. self, returning. → mentoring nebo masterclass premium (upsell). NE znovu otevřený workshop. 2 produkty k porovnání.
  5. Vedoucí menšího týmu, „nevím jestli pro sebe nebo pro lidi”. team_lead. → mentoring 1:1 (pro sebe) + firemní workshop (pro tým). Doptat se na velikost týmu a kdo má rozpočet. 2 produkty.

6.5.5 Handling první ceny v chatu (A6)

Ceny mentoringu (44–68k) a firemních (35–80k) nejsou na webu → chat je první místo s číslem. Špatný timing/framing odpálí lead.

Kdy uvést:po vybudování hodnoty (nejdřív co řešení obnáší → pak cena jako vyústění). Když se zeptá hned („kolik to stojí?“): neodmítat, krátce rámovat — „Záleží na formátu, řeknu ti rozsah. Než hodím číslo — kde teď nejvíc tlačí bota?” → 1–2 signály → cena s kontextem. Nikdy holé „44990”.

Jak zarámovat: ROI / cena za sezení (mentoring 1měsíční = 5 sezení + neomezená podpora → „~9 000 za sezení s podporou mezi nimi”). Hodnota vs. cena vázaná na konkrétní situaci z konverzace. Kotva odshora (zmínit dražší první → konzultace 7 990 pak vypadá jako nízkoprahový vstup).

Reakce na cenový šok: nevycouvat hned na nejlevnější — nejdřív reframe (cena/sezení, ROI), pak nabídnout nižší vstup (konzultace 7 990 / workshop 5 990) jako „první krok nezávazně”. Fakturace/splátky: v katalogu pro to ZATÍM není pole — klon je nesmí slibovat, dokud Petr nepotvrdí; max. „na fakturu se domluvíme” → předat na Petra (otevřený bod k §6.6). Closing fáze = stručně (§6.7): jeden next step, ne zeď textu.

6.5.6 Placeholder „kurz vs. ostatní” (A7)

Až vznikne online kurz (category='course'): dostane priority vyšší než ostatní jen pro profily, kde dává smysl — NE tlačit všem. - Vhodný profil: self, začátečník/mírně pokročilý, nízké–střední pásmo, chce samostudium/flexibilitu, není akutní 1:1 potřeba (= překryv s dnešním „workshop open / masterclass standard”). - Nevhodný (priorita kurzu NEpřebíjí): org_decision/team_lead (chtějí živé školení), akutní 1:1 (mentoring), returning chtějící hloubku. - Implementace: priority = výchozí skóre v Kroku 2, ale segmentová větev (Krok 1) ho ohraničí — kurz se nedostane do company větve, nemůže přebít firemní workshop. Tím je „kurz se přidá bez přepisu stromu” splněno bezpečně.

Ostatní matching signály v §3.4/§6.4/§6.6: recommended_product_ids → leads (§3.4); urgence spots_left jen pravdivě a jen u termínových produktů, NIKDY evergreen mentoring/firemní; ceny/místa z product_variants/product_terms (aktuální, ne natvrdo v promptu). Handling námitek viz 6.5.5 + §6.6.

Příloha 6.5-A — Skórovací specifikace (pro ultraplan)

Vstup: matchProducts(profile, state, catalog) -> { primary, secondary?, entryOffer, count, reasoning } - profile: { buyer_role, profession, situation, comm_goal, desired_outcome, prior_experience, perceived_value, has_company } - state: { maturity, segment_guess, offered_products[], known_fields[] } (z conversations.state, §6.4) - catalog: products(active=true) + variants + terms (live z DB — nikdy natvrdo v promptu)

Guard:

if (!state.maturity) return null                         // brána §6.4
// VÝJIMKA buy_intent (council fix): horký lead se neblokuje doptáváním
if (signals.buy_intent)
    return { primary: SAFE_DEFAULT, entryOffer: SAFE_DEFAULT, count: 1, askAfter: missingFields }
    // SAFE_DEFAULT = workshop open 5990 / konzultace 7990; buyer_role+situation doplnit AŽ POTÉ (§6.5.3 Krok 4)
if (missing(profile.buyer_role) || missing(profile.situation))
    return { action: 'ask', field: firstMissing }        // doplnit v chatu, nehádat

Krok 1 — větev (kandidáti C):

org_decision → C = bySegment('company')
team_lead    → C = bySegment('company') ∪ bySegment('individual_high')
self         → C = bySegment('individual_low') ∪ bySegment('individual_high')

Krok 2 — skóre s(p) pro p ∈ C:

s(p) = p.priority                                        // kurz = vysoká až vznikne
     + W_situation * fSituation(profile.situation, p)
     + W_history   * fHistory(profile.prior_experience, p)
     + W_theme     * fTheme(profile.comm_goal, p)

Váhy (laditelné konstanty): W_situation=3, W_history=2, W_theme=1. Priorita kurzu řádově +5 jen v individual_low překryvu.

Krok 2b — cena jako slabý tie-breaker:

if (abs(s(a)-s(b)) <= TIE_EPS)                            // jen rovnocenní kandidáti
    preferCheaperWithinBudget(a, b, profile.perceived_value)
// NIKDY s(p) -= cena. Cena nesnižuje skóre, jen rozhoduje remízy. TIE_EPS ~ 1.
// Aspirační (dražší) kandidát zůstává v nabídce vždy → secondary.

Krok 3 — výběr + entry offer:

ranked = sortDesc(C, s); primary = ranked[0]
entryOffer = lowestThresholdEntry(branch)   // self→workshop 5990 / konzultace 7990; company→bezplatná konzultace
count = strongSingleSignal(profile, state) ? 1 : 2
secondary = count==2 ? pickComplement(ranked, primary, entryOffer) : null
// pokud primary == aspirační a entryOffer ho nepokrývá → secondary = entryOffer

strongSingleSignal = explicitní „chci 1:1” ∨ (akutní situace ∧ rozpočet sedí) ∨ (returning ∧ konkrétní poptávka).

Krok 4 — výstup + validace:

recommended_product_ids = [primary.id, secondary?.id].filter(Boolean)   // → leads (§3.4)
// validace: každý id ∈ catalog & active (řeší D5 halucinaci slugu)
reasoning = humanExplain(...)   // pro sales_briefing + ladění

Framování ceny (6.5.5) se aplikuje až ve formulaci odpovědi (prompt dostane vybraný produkt + variants + pravidlo „cena v kontextu hodnoty / cena za sezení”), ne v matchProducts(). Testovatelnost: čistá funkce → unit testy nad 5 fixturami z 6.5.4 (profil → očekávaný primary/secondary); změna vah = změna konstant, ne logiky.

6.6 Sběr leadu + sales briefing

  • Kombinace: organické doptávání v hovoru + krátké strukturované potvrzení na konci (vybraný produkt + termín; kontakt z profilu, jen potvrdit „Mám tě jako Honza, honza@x — sedí?“).
  • Warm leady (NOVÉ): pokud maturity=true a padla nabídka, VŽDY založit lead (status warm) i bez explicitního „chci” — zavřené okno ≠ ztracený zájem.
  • sales_briefing (ne profil): nabídnutý produkt + reakce (zájem/váhání/námitka), konkrétní námitka, teplota, citát zájemce vlastními slovy, deadline/urgence, doporučený next step. Generovat jako „předávací briefing pro obchodníka”. Minimalizace (§9.4): shrnovat jen obchodní kontext, nespekulovat o osobních charakteristikách; Petr může opravit/smazat.

6.7 Hluboké strukturované odpovědi — PRINCIP OVĚŘEN V LEGACY TESTU (2026-06-28)

Cíl: pryč od strohých „5 řádků basic” (kde si uživatel řekne „tohle mi ChatGPT řekne líp”) → NotebookLM-style hluboké, strukturované, vizualizované odpovědi s reálnou přidanou hodnotou. Princip ověřen naživo v legacy testu a podložen researchem (viz níže). V přestavbě se znovupostaví nad přebíranými moduly (chat.ts/knowledge.ts) s novým, sales/orchestrace-aware promptem — technika (celá KB + caching + reasoning + kostra) zůstává, obsah promptu je nový.

Klíčový poznatek z researche: Problém mělkých odpovědí NEBYL retrieval, ale prompting + málo kontextu. Celá KB má jen ~49k tokenů = 5 % okna Gemini. „Lost in the middle” při 49k neexistuje (ověřeno Google studií arXiv 2511.05850). Gemini je defaultně stručný — hloubku nutno vynutit.

Architektura (ověřená technika, přenáší se do přestavby): - Vše přes OpenRouter (/chat/completions, OpenAI-kompatibilní) — sjednoceno s embeddingy, jeden klíč, nabité kredity. NE přímý Google (free tier nemá caching, limit=0). - Model gemini-3.1-flash-lite — novější generace, nastavitelné reasoning, levný (0,25 $/1M vstup). POZN: gemini-3.5-flash je prémiový (1,50 $/9 $ = 5× dráž), nepoužívat pro warmup chat. (Toto je jediný platný chat model napříč specem — §0b/§6.1 dřív omylem uváděly 3.5-flash jako primární, opraveno v0.7.) - CELÁ KB v kontextu (ne top-5 chunků) — src/lib/knowledge.ts načte všech 208 chunků z documents, pošle do system promptu. Model odpovídá nad celkem, ne nad fragmenty. - Implicit caching — KB + system prompt jdou s cache_control: ephemeral → OpenRouter cachuje statický prefix (90% sleva). Ověřeno: cache HIT ~75k tokenů, ~$0,011/zpráva. - Reasoningreasoning: {effort: "medium"} → model „přemýšlí” před odpovědí (~800 reasoning tokenů). Konfigurovatelné přes REASONING_EFFORT.

Struktura odpovědi (kostra v src/lib/prompt.ts): Pro věcné dotazy z oboru: úvod (háček) → 3–6 bodů s vysvětlením a příkladem → mermaid diagram (když dává smysl) → shrnutí → konkrétní úkol → most na Petra (při zralosti). Verbosity HIGH + měřitelná minima per sekce. Kostra na KONCI promptu (Gemini brzké instrukce v dlouhém promptu dropuje). Few-shot příklad hloubky.

Mermaid diagramy — model generuje ```mermaid bloky, frontend (page.tsx + mermaid.js z CDN) je vykresluje jako SVG. Ověřeno naživo (vyjednávací flowchart s Petrovými pojmy). Pravidla syntaxe v promptu (uvozovky u textu se závorkami, jen -->, ID bez mezer).

Fázové chování (pravidlo v promptu): - Edukační fáze: bohaté, strukturované, s příklady a diagramem (buduje autoritu). - Closing fáze (po nabídce, při námitce): stručně, jeden next step — zeď textu oddaluje rozhodnutí. - Mimo téma / pozdrav / krátká upřesňující otázka: přirozeně a stručně, BEZ kostry.

Soubory (legacy zdroje k přebrání): src/lib/chat.ts (OpenRouter completions + caching + reasoning) a knowledge.ts (celá KB) se přebírají (§0b); prompt.ts (kostra) se přepisuje pro sales/orchestraci. Config zůstává: CHAT_MODEL, REASONING_EFFORT, MAX_OUTPUT_TOKENS.

Budoucí rozšíření (Honzova vize „druhý mozek”): až KB poroste, zvážit hierarchický summary (RAPTOR-style) jako navigační mapu nad KB + RAG na detaily. Při 49k zatím netřeba — celá KB se vejde. Cache na prod přes placený tier (garantovaná, ne jen implicit).

Zobrazit až při maturity (ne od začátku — stálý prodejní banner sráží důvěru mentora), měnit jen podle potvrzeného segmentu, sladit s tím co Petr právě nabídl. Pozor na dvě konkurenční CTA (banner + nabídka v textu). A/B testovat.

6.9 Životní cyklus konverzace, re-entry, lead bez maturity, merge (NOVÉ — řeší D2/D3/D4)

6.9.1 Stavový model konverzace + re-entry (D2 / P0-5)

conversations.status (NOVÉ, schema): active (běží) / dormant (pauza) / closed (ukončeno). Trigger přechodů: - active → dormant: poslední zpráva starší než TTL (návrh 7 dní; konfigurovatelné). Nastaví batch/cron nebo lazy při dalším čtení. - dormant → active: uživatel se vrátí (viz níže). - * → closed: lead won/lost, nebo GDPR výmaz, nebo uživatel explicitně ukončí.

Re-entry (ROZHODNUTO 2026-06-30): navázat na poslední konverzaci. - Při vstupu do chatu (přes session) najít poslední active/dormant konverzaci profilu (index idx_conversations_user_status). Pokud existuje → pokračovat v ní (dormant → active), ne zakládat novou. - Klon zná kontext — system prompt dostane profil + posledních N zpráv + state (maturity/segment/offered_products zůstávají). Přivítá zpět („Minule jsme řešili…“). - Maturity se NEresetuje, ale re-klasifikuje při dalším tahu (signály se přepočtou; pokud mezitím „vychladl”, skóre to zachytí). offered/declined/reminded zůstávají → cooldown (§6.4.4) platí napříč návštěvami. - Jedna konverzace = jeden lead pro Petra → čistá data, žádné duplicity. Pokud výjimečně vznikne víc konverzací na profil, „ta správná” pro briefing = poslední s nejvyšší state.maturity.score.

6.9.2 Lead bez maturity — cold lead z dotazníku (D3 / P1)

Problém: kdo si jen povídá a nedozraje (nebo chat vůbec nezapne) → bez maturity nevznikne lead, i když dal kontakt. Ale dotazník dal plný profil (§5). Spor s tab-petr slibem „každý zájemce má profil/je kontaktovatelný”.

Pravidlo: každý dokončený dotazník SE SOUHLASEM = cold lead (council fix — GDPR). - Cold lead vzniká jen když consents[qualification_contact].granted=true (souhlas s kontaktováním za účelem kvalifikace/nabídky). Bez něj se uloží profil + research data (na základě ai_processing_google souhlasu, který je nutný pro funkci klona), ale žádný kontaktovatelný lead — Petr nesmí kontaktovat člověka bez právního titulu. Research data (raw_answers) slouží jen agregované analýze cílovky, ne adresnému oslovení. - Při server-side zápisu profilu (§5.2, POST /api/profile na dokončení) vzniká (při souhlasu) lead se status='new', temperature='cold', source='questionnaire', recommended_product_ids=NULL (matching ještě neproběhl — chybí konverzace). - Cold lead nemá sales_briefing (není o čem — nebyla konverzace), jen profil + kontakt. Petr ho vidí v adminu jako „vyplnil dotazník, ještě nekonverzoval”. - Když pak konverzace dozraje → stejný lead se povýší (cold → warm/hot, doplní se briefing + produkty), nezakládá se druhý. Vazba přes user_id. - Partial dotazník (odpadl v půlce): díky průběžnému ukládání (§5.5 C-4) existuje profil-draft, ale lead nevzniká dokud není dotazník dokončen (jinak by Petr dostal nekompletní leady). Draft je jen pro retenci kontaktu + drop-off metriku.

6.9.3 Anon → identita merge (D4 / P1)

Scénář: přijdu anonymně do chatu (bez dotazníku — conversations.user_id=NULL), povídám si, pak vyplním dotazník → jak spojit anon konverzaci s novým profilem?

Mechanismus: - Anon konverzace běží na session id (httpOnly cookie, bez user_id). state se plní normálně. - Když uživatel v průběhu/po chatu vyplní dotazník (nebo nastaví účet) → server zná session id (cookie) i nový user_profiles.id. - Merge: UPDATE conversations SET user_id = <profile> WHERE id = <anon session conv> AND user_id IS NULL. Konverzace se „adoptuje” pod profil, historie zpráv zůstává (FK messages.conversation_id se nemění). - Kolize (profil už má jinou konverzaci): platí re-entry pravidlo 6.9.1 — necháme obě, „ta správná” = nejvyšší maturity. Anon konverzaci nepřepisujeme, jen připojíme. - Pozor (bezpečnost): merge jen pro konverzaci z téže session (cookie), nikdy podle hádaného id → zabrání adopci cizí konverzace (IDOR). user_id nikdy z URL/body (§5.2).


7. Subsystém D — Admin pro Petra

7.1 Funkce (v1)

Seznam leadů (filtr status, řazení dle data/teploty), detail = profil + konverzace + sales briefing + nabídnutý/vybraný produkt + kontakt, změna statusu, správa katalogu (produkty, varianty, termíny + volná místa).

7.2 Autentizace (přepracováno — blocker, ne TBD)

  • Supabase Auth (magic link) s povoleným účtem Petra NEBO basic auth za reverse proxy + 2FA. Vždy rate-limit + HTTPS.
  • Kontrola role na serveru u každého /admin a /api/admin (ne jen skrytí UI).
  • service_role jen v admin-only server modulech, nikdy do klientského bundlu.
  • Audit log přístupů k detailu leadu (kdo/kdy).
  • Bez vyřešené auth NENASAZOVAT admin nad reálná data.

8. Klíčové datové toky

8.1 Happy path (s dotazníkem)

  1. Web → gamifikovaný dotazník (WP).
  2. Dotazník → POST na server endpoint → zápis profilu + consent → lehký účet (Supabase Auth) + session cookie → redirect na /chat (BEZ tokenu/user_id v URL). Magic link na e-mail jako záloha pro návrat.
  3. Chat čte profil ze session → konverzace přizpůsobená profilu (perzistovaná po tazích).
  4. Klasifikátor průběžně → maturity → aplikační matching → 1–2 produkty kontextově.
  5. Zájemce projeví zájem (nebo konverzace dozraje bez „chci”) → zápis leads (new/warm) + sales briefing.
  6. (volitelně, vědomě) notifikace Petrovi → admin → kontaktuje.

8.2 Fallback (bez dotazníku)

Anonymní konverzace (user_id NULL), úvodní disclosure o Gemini. Při maturity stejný matching bez profilu (méně přesné). Lead z anon konverzace: leads.user_id NULL nebo lazy profil.


9. Bezpečnost, GDPR a nasazování

9.1 Nasazování (od 2026-07-01 — „nic ven / local only” ZRUŠENO)

Dřívější pravidlo „při dev/testu nic neopustí Mac kromě Gemini” je překonané. Jedeme normální pipeline: Docker jen lokální test → push na main → migrace do Supabase Cloud EU + deploy appky na server. Co zůstává jako opatrnost (ne blok): (a) osobní data subjektů jdou do Gemini přes OpenRouter — na prod nastavit vypnutý logging/trénink + placené kredity (§D1); (b) nikdy neodeslat reálný e-mail/webhook subjektům při testu (notifikace jen Petrovi = vlastník dat). Lokální Supabase e-maily → Mailpit past (dev). (Memory ai-clon-local-only = přepsaná na tuhle realitu.)

9.2 Prod kanály (vědomě, schváleně)

Na prod legitimně vzniká: dotazník → prod Supabase; CRM → notifikace Petrovi (jen hot leady); chat → Gemini přes OpenRouter. Každý kanál schválen, žádný potají. Deploy appky/serveru = na výslovný pokyn Honzy.

9.3 Bezpečnostní jádro (z review)

  • RLS default-deny (§3.6); anon klíč jen čtení katalogu; zápis osobních dat jen server+service_role.
  • Identita: magic-link účet + httpOnly session cookie, user_id NIKDY v URL/body (§5.2). Handoff token v URL zrušen (council fix — Referer/historie leak).
  • Admin auth jako blocker (§7.2).
  • CORS: dotazník i /api/profile na téže subdoméně ai.sebacademy.cz = same-origin → cross-origin allow-list není potřeba (K OVĚŘENÍ ve vrstvě 1, §5.4). Anti-bot (Turnstile/hCaptcha) + rate-limit na endpointu dotazníku platí nezávisle.

9.4 GDPR (ČR/EU)

  • Granulární souhlas per účel (consents, §3.7), doložitelný (verze, znění, čas). Poučení/souhlas PŘED odesláním citlivých dat.
  • Právní titul per účel (council fix, ověřeno ÚOOÚ — viz §5.5): AI zpracování (Gemini/OpenRouter) = plnění služby (čl. 6/1/b, jen informace, ne souhlas — bez něj klon nefunguje); kontakt s nabídkou = aktivní souhlas (nepředzaškrtnutý oddělený checkbox, ne „pokračováním souhlasíš”); marketing = samostatný opt-in. Cold lead jen při kontakt-souhlasu (§6.9.2).
  • Výmaz = anonymizace + log (§3.8). Retenční lhůty per status.
  • Minimalizace (čl. 5/1/c): zvážit neukládat raw_answers trvale; AI briefing nespekuluje o osobních charakteristikách.
  • I anonymní chat: úvodní disclosure o zpracování Googlem.

9.5 Přenos do Gemini/Google (KRITICKÉ)

Chat posílá obsah konverzace + profil = osobní údaje na US endpoint. - Celá AI komunikace jde přes OpenRouter (rozhodnuto — jeden konzistentní stack, žádné přímé napojení na model mimo OpenRouter). Osobní data zájemců tedy tečou: appka → OpenRouter → upstream model (Gemini). OpenRouter i Google jsou příjemci/zpracovatelé (US) — viz §9.7. - Zákaz trénování na datech (klíčové): na PRODUKCI vypnout logging a trénink dat. OpenRouter to umožňuje — v nastavení účtu / hlavičkou požadavku (data-collection off), aby se obsah konverzací NEpoužíval k tréninku. To je produkční must (default režim může data logovat). ROZHODNUTO: prod = OpenRouter s vypnutým tréninkem + placené kredity. - Dev: na testování jen syntetická data (nikdy reálné údaje lidí), ať na režimu logování nezáleží. - Náklady (řádový odhad — ověřit aktuální ceník před prod): Flash modely jsou levné. 1 konverzace ~20–60k tokenů (vstup dominuje kvůli RAG+historii) → řádově 0,30–1,50 Kč/konverzace. Při 100 konv./měsíc ~30–150 Kč, při 1000 ~300–1500 Kč/měsíc. Zanedbatelné proti hodnotě jednoho uzavřeného obchodu. Hlavní nákladový faktor = počet volání na tah (chat+embedding+klasifikátor) → proto optimalizace v §6.4. Free vs. placený se v ceně za token téměř neliší — přechod je kvůli GDPR, ne ceně. - Před ostrým spuštěním (než do appky vstoupí reální lidé): ověřit, že je na OpenRouteru vypnutý trénink/logging dat, a přejít na placené kredity. - Nová sekce do privacy policy: OpenRouter (zprostředkovatel AI volání) + Google (Gemini) (upstream model) + Supabase (databáze) jako příjemci/zpracovatelé — účel, region (US), právní titul (EU-US DPF / SCC), DPA u každého.

9.6 dev→prod parita, secrets a zálohy

  • Stejné RLS i lokálně (parita). Oddělené dev/prod klíče, rotace, prod secrets přes runtime (ne do image). Ověřit .dockerignore že .env.local není v image.
  • Prod auth flagy: enable_signup=false, enable_confirmations=true (dnes dev defaulty = prod mina). Endpointy přes env, žádné hardcoded hosty v kódu mimo compose.
  • Zálohy (Free tarif nemá managed backup — §2.3): denní pg_dump cron na NextHostingu → záloha na disk exonu (rotace 30 dní) + ověření neprázdnosti + alert při selhání + jednou otestovaný restore. Drží zároveň projekt naživu (anti-uspání). Osobní data (GDPR) = ztráta bez zálohy je katastrofa, proto povinné už od ostrého spuštění.
  • Dev: lokální Supabase přes CLI (Docker), Git workflow. Prod: Supabase Cloud EU (Free). Migrace verzované, aplikované na prod kontrolovaně.

9.7 Procesní GDPR (doplnit před spuštěním dotazníku)

Definovat správce (SEBA Academy / Petr Vojnar) a zpracovatele (Google, Supabase). ROPA (čl. 30), aktualizace privacy policy na sebacademy.cz, posouzení DPIA (čl. 35 — systematické profilování + matching ji pravděpodobně opodstatňuje).


10. Fáze stavby (vrstvy — opraveno)

Vrstva 1 NENÍ jen „schéma” — obsahuje bezpečnostní a integrační základ, jinak se vrstva 2 zadrhne nebo se schéma přepisuje zpětně.

  1. Datový + bezpečnostní + integrační základ:
    • Schéma (§3) vč. variants/terms, consents, soft delete, indexy, ENUM/CHECK.
    • RLS policies (default-deny) + adversariální test.
    • Serverový zápisový endpoint pro profil + konverzace/leady + jeho kontrakt.
    • Magic-link účet (Supabase Auth) + session cookie (ne handoff token) — viz §5.2, api-contracts §1/§2.
    • Events tabulka (funnel metriky §12) — viz schema.sql.
    • Kontrakt dotazník→chat (jaká pole, jak identita) zafixovat jako rozhraní HNED.
    • Naplnit katalog.
  2. Chat + orchestrace (E) + matching: perzistence konverzací, klasifikátor (JSON signály), aplikační matching, sběr leadu (vč. warm), sales briefing, fázové odpovědi. Test: scénáře (profil reálný z DB, ne mock — kontrakt už existuje z vrstvy 1).
  3. Admin (D): auth (blocker), leady + briefing, správa katalogu, audit. Test: CRUD + auth.
  4. Dotazník (A): gamifikovaný React + embed do WP + POST přes server endpoint + handoff. Test: vyplnění → profil v DB → vstup do chatu přes token.
  5. End-to-end: celý happy path + warm lead + GDPR výmaz.

Každá vrstva = vlastní implementační plán (writing-plans).


10b. Identita, účet a limity volání (NOVÉ — abuse ochrana + CX)

Proč: bez limitu si někdo udělá z chatu vlastní ChatGPT a SEBA platí jeho Gemini tokeny. Limit je nutný. ALE klon je sales nástroj — limit nesmí useknout legitimní zralou konverzaci (= nejteplejší lead). Řešení = limit + chytré přepnutí na osobní kontakt. Detaily k dořešení s týmem; níže rozhodnutý směr + CX nápady.

10b.1 Dva oddělené problémy (neplést)

  1. Cost abuse („vlastní ChatGPT”) → řeší limit zpráv (níže).
  2. Bot/spam abuse (skripty, DoS, scraping) → řeší anti-bot (Turnstile/hCaptcha) + rate-limit na server endpointech (§5.4, §9.3). Limit zpráv na tohle NESTAČÍ.

10b.2 Progressive commitment — identita a účet (Honzův návrh, CX-first)

Postupné zvyšování závazku podle rostoucí hodnoty — nízká bariéra na vstupu, větší závazek později: 1. Vstup bez tření: dotazník vyplněn → rovnou do chatu. Žádná bariéra, člověk hned mluví s Petrem. Na e-mail přijde magic link jako záloha pro návrat. 2. Měkká výzva v chatu: jakmile je uvnitř a vidí hodnotu → nenásilná výzva „Nastav si heslo, ať se sem kdykoli pohodlně vrátíš.” Dobrovolné, motivované pohodlím. 3. Fallback magic link: když heslo nezadá, návrat jen přes magic link z mailu (musí ho mít uložený / hledat v historii) = jemné tření, které motivuje k nastavení hesla.

Login z dotazníku NAHRAZUJE křehký handoff token z v0.2. Identita vázaná na účet (e-mail) řeší tři věci najednou: (a) bezpečný most dotazník→chat, (b) limit vázaný na člověka, ne na obejitelnou IP/cookie, (c) personalizaci profilu napříč zařízeními. - Technicky: Supabase Auth (magic link, je dnes vypnutý, jen zapnout). Heslo volitelně doplnitelné. Profil + pokyny pro AI (personalizace „na míru”) vázané na účet → konverzace se ubírá správným směrem.

10b.3 Limit zpráv — rozhodnutý směr (čísla doladí tým)

Kombinace měkkého a tvrdého limitu + chytré chování (Honza zvolil možnosti 1+3): - Měkký práh (návrh ~30 zpráv/den, doladit): varování, ne useknutí. Chytí náhodné/lehké nadužití. - Tvrdý strop (vyšší denní/měsíční na účet): proti cílenému zneužití. - Vrstvení metrik: měkký na IP+session (chytne anonymní), tvrdý na účet (chytne cílené). Žádná metoda není neprůstřelná sama — i nedokonalý limit odradí drtivou většinu. - Chytré přepnutí po dosažení (KLÍČOVÉ pro CX i konverzi): Petr NEUSEKNE zeď „limit vyčerpán”. Místo toho přepne: „Hele, dneska jsme toho probrali pořádný kus — pojďme to dotáhnout naživo, ať ti to ušiju na míru.” + nabídne kontakt/konzultaci/produkt. Limit se stává konverzním momentem, ne frustrací. (U zralé konverzace = ideální chvíle na předání leadu.)

10b.4 CX nápady a otevřené body (brainstorm pro tým)

  • Rozlišit limit pro nepřihlášeného (přísnější — anonymní, riziko abuse) vs. přihlášeného s profilem (volnější — known lead, chceme ho nechat mluvit).
  • Limit komunikovat dopředu a lidsky (ne až náraz): např. jemný indikátor / Petrova hláška „ještě pár otázek a pak to dotáhneme osobně”.
  • Reset limitu: denně o půlnoci? Klouzavé okno 24h? (Doladit.)
  • Zvýhodnit „warm” leady: kdo dal kontakt / projevil zájem o produkt → vyšší limit (odměna za závazek).
  • Anti-abuse bez poškození UX: captcha jen při podezření (ne na každého), ne otravovat skutečné zájemce.
  • Vše k finální diskuzi s týmem — konkrétní čísla, mechanika resetu, tone of voice hlášek.

11. Otevřené otázky (tvrdé brány před příslušnou vrstvou)

Stav 2026-06-30: všechny technické otázky ROZHODNUTY (před spuštěním ultraplanu). Zbývá jen doladit čísla limitů s týmem (mechaniku ultraplan postaví) a externí milník (kurz, čeká na Petra).

Rozhodnuté 2026-06-30

  1. Embed dotazníku — VYŘEŠENO: odkaz/tlačítko z WP na samostatnou appku ai.sebacademy.cz (NE iframe/script). Odpadá CORS/CSRF problém, appka běží nativně na vlastní subdoméně, plná kontrola UX. (Nahrazuje dřívější „iframe vs. script”.)
  2. Admin auth — VYŘEŠENO: Supabase Auth (magic link), jen Petrův účet + role check na serveru u každého /admin a /api/admin (§7.2). Stejná technologie jako identita zájemce — žádný nový mechanismus.
  3. Notifikace Petrovi — VYŘEŠENO: ano, transakční mail jen u HORKÝCH leadů (temperature=hot, §6.4.5) — obsahuje odkaz do adminu, NE celý profil v mailu (minimalizace). U warm/cold ne (záplava). Interní notifikace správci = GDPR-čisté (Petr je vlastník dat). Kanál: SMTP/transakční služba ze serveru appky.
  4. Aktualizace cen/termínů — VYŘEŠENO: Petr v adminu (§7.1) + měsíční cron připomínka aktualizovat termíny/spots_left před akcemi (ať klon nelže o dostupnosti).
  5. Prod Supabase / hosting — VYŘEŠENO (§2.3): appka na NextHosting PRO (Node/Passenger, subdoména), Supabase Cloud EU, Free tarif + DPA externě (NextHosting nemá PostgreSQL/pgvector). Free slabiny (uspání + zálohy) řeší denní pg_dump cron na exonu (záloha + keep-alive). WP na hlavní doméně, sdílení dat přes REST API. Upgrade na Pro ($25) až s provozem.
  6. Identita cross-device — VYŘEŠENO (§5.2/§10b): účet z dotazníku + magic link → heslo. Handoff token v URL zrušen (council fix).
  7. Duplicitní profily — VYŘEŠENO: UNIQUE+upsert dle e-mailu (partial unique, §3.1). Pro sdílené/firemní e-maily ověřit vlastnictví (magic-link klik) před merge anon konverzace. Lead = 1:1 s user_id, vždy UPSERT.
  8. Cenové pásmo — VYŘEŠENO (§5.3): price research + signál (slabý tie-breaker), ne strop.
  9. Metriky — VYŘEŠENO (§12): obojí (Clarity + CRM eventy, events tabulka).

Zbývá (neblokuje start ultraplanu)

  1. Limity volání (§10b) — DEFAULT zapsán, čísla doladit s týmem před vrstvou 2: výchozí ~20 zpráv/den měkký práh (varování), ~30/den tvrdý (stop milým tónem — „dneonemocní” brand), denní reset (date_trunc bucket, atomicky triviální — ne klouzavé okno), nepřihlášený nižší limit než přihlášený. Mechaniku postaví ultraplan; čísla jsou konstanty, mění se bez přepisu logiky. Vrstvený limit: account tvrdý → session měkký → IP jen anti-bot (ne tvrdý blok kvůli NAT/firmám).
  2. Online kurz Petra Vojnara (EXTERNÍ, čeká na Petra): kdy bude a jaké parametry → pak do katalogu jako prioritní produkt (§1.0). Hlavní budoucí milník.

12. Metriky konverzního trychtýře — ROZHODNUTO: OBOJÍ

„Sales nástroj” se nedá ladit bez měření. Sbírat: dotazníky → chaty → nabídky → leady → won; drop-off per krok (zejména na potvrzení kontaktu §6.6); atribuce zdroje (questionnaire vs direct). Umožní A/B test (banner při zralosti vs. stálý, 1 vs. 2 produkty, value vs. budget framing). - Microsoft Clarity (už napojený na sebacademy.cz — memory clarity-sebacademy): chování na webu — heatmapy, nahrávky dotazníku i chatu, kde lidé odpadají, jak scrollují. Rozšířit Clarity i na chat appku. - Vlastní eventy v Supabase CRM: obchodní funnel — přesné napojení na konkrétní leady/produkty/výsledek (dotazník dokončen, chat zahájen, dosažena zralost, produkt nabídnut, lead vznikl, status změněn). Vidět v adminu. - Rozdělení rolí: Clarity = jak se chovají, CRM eventy = obchodní výsledek. Dohromady kompletní obraz trychtýře (i ke kurzu, až bude).


13. RAG knowledge — připravit na rozšíření (z review)

documents nemá metadata/filtr (ověřeno: bigserial PK, match_documents bez filtru). Až přibude víc produktů/online program, RAG nemá jak filtrovat podle kontextu. Přidat sloupec metadata/source/product_slug + filtr do match_documents PŘED ingestem víc obsahu (re-embedding 1000+ chunků je drahý, projekt na kvótu právě čeká).


14. Shrnutí klíčových rozhodnutí

  • Celý flow jeden spec, stavba po vrstvách; vrstva 1 = data+bezpečnost+integrace. ✔
  • 5 subsystémů (přibyla orchestrace stavu E). ✔
  • DB = jediná autorita; perzistence konverzací serverově. ✔
  • Identita: magic-link účet + httpOnly session cookie, user_id NIKDY v URL/body (token v URL zrušen). ✔
  • RLS default-deny; zápis osobních dat jen server+service_role; anon jen čtení katalogu. ✔
  • GDPR: granulární souhlas, výmaz=anonymizace, prod = OpenRouter s vypnutým tréninkem dat + placené kredity, dev=syntetická data. ✔
  • Strukturované signály přes klasifikátor (JSON), matching v aplikační logice. ✔
  • Sales: rozpočet = signál ne strop; entry offer vedle aspiračního; warm leady; sales briefing; handling námitek; fázové odpovědi. ✔
  • Datový model: product_variants (Standard/Premium + měna, price_minor), termíny bez ceny, CHECK/ENUM, indexy. ✔
  • Metriky trychtýře + RAG metadata jako součást rozsahu. ✔
  • Dotazník = custom React embed do WP, brutální gamifikace, telefon volitelný, zápis přes server endpoint. ✔