Table of Contents
Kosmo: Digitální Ekosystém Sofie
Tato dokumentace popisuje kompletní digitální strategii a softwarový stack pro ZŠ a MŠ Sofie.
Co je součástí ekosystému?
- Aplikace Kosmo (Custom Vývoj):
- Portál pro rodiče (Feed, docházka, evidence, omluvenky — Fáze 3+).
- Interní nástroje pro učitele (Třídnice — implementováno, PM Kanban — Fáze 2).
- AI asistentka Sofie (chat, email CC, hlas — Fáze 3+).
- CRM (Twenty):
- Správa leadů a zájemců o školu.
- Back Office (SaaS + Self-hosted):
- Ekonomika (Pohoda).
- Matrika (ŠkolaOnline).
- Knowledge Base (BookStack).
- Newsletter (Resend transactional — Fáze 3+).
Aplikace Kosmo (Core)
Kosmo je srdcem ekosystému. Je to "lepidlo", které spojuje data a lidi. Cílem projektu je vytvořit moderní, bezpečnou a AI-powered aplikaci, která sjednotí komunikaci, evidenci a procesy v Montessori škole Sofie (MŠ + ZŠ).
Klíčové vlastnosti
- Třídnice (implementováno): Učitel ráno otevře app a vidí, co učí a kdo chybí. Viz intent/classbook + intent/attendance.
- Feed (Fáze 3+): Rodič otevře appku a vidí, co dítě dnes dělalo — fotky, aktivity, docházka.
- Sofie (Fáze 3+): AI asistentka, která odbavuje dotazy rodičů 24/7 a eskaluje na učitele jen to důležité.
- Evidence (Fáze 2+): Digitalizace prací žáka — fotka → AI štítek → ve feedu rodiče.
- Bezpečnost: Google Auth, Magic Links, role gating. Viz intent/auth-and-roles + invariants.md.
Struktura dokumentace
Kontrakt (I³ metodologie)
| Dokument | Obsah |
|---|---|
| Intent briefs | Co aplikace dělá a proč — 1 brief per feature |
| Invariants | Pravidla, která nesmí padnout (kritická mají test) |
| Decisions (ADRs) | Architektonická rozhodnutí — proč X, ne Y |
Reference
| Dokument | Obsah |
|---|---|
| Vize | Kontext školy, problémy, vize |
| Uživatelé | Role, user stories, onboarding |
| Datový model | Schema, ER diagramy |
| Sofie | AI persona (Fáze 3+) |
| Integrace | Storage, kanály, externí systémy |
| MVP | Scope a fázování |
| Deployment | Infrastruktura, prostředí, zálohy, CI/CD |
| Dev Log | Narativní changelog rozhodnutí |
| Glossary | Doménový slovník |
Vize a nápady (nezávazné)
| Dokument | Obsah |
|---|---|
| Roadmap | Fáze 2+ nápady (dříve BACKLOG) |
| Feed vision | Rodičovský Feed, Sofie chatbot (Fáze 3+) |
| Sofie architecture | Sofie chatbot architektura (Fáze 3+) |
| Knowledge Graph | Universal Knowledge Graph (Fáze 4+) |
Rychlý start
Pro vývojáře: viz CLAUDE.md v rootu repa, nebo:
1. supabase start — lokální databáze
2. cd web && pnpm dev — Next.js na localhost:3000
Vize projektu Kosmo
O škole
- Název: Základní škola a Mateřská škola Sofie, s.r.o.
- Místo: Říčany u Prahy
- Typ: Soukromá Montessori škola (ZŠ + MŠ)
- Velikost: ~80 žáků ZŠ, ~22 zaměstnanců
- Stupně: MŠ (předškolní) + ZŠ 1. stupeň + přechod na 2. stupeň (aktuálně po 7. ročník)
- Ředitel: Patrik Matlák
- Web: sofie.education
- Motto: „V dítěti leží osud budoucnosti."
Montessori filosofie
- „Pomoz mi, abych to dokázal sám." Děti se učí vlastním tempem, volí si aktivity, rozvíjejí samostatnost.
- Věkově smíšené třídy — starší děti přirozeně pomáhají mladším.
- Bez zvonění, bez známek — flexibilní rozvrh, slovní hodnocení zaměřené na pokrok dítěte.
- Bez soutěžení — důraz na vnitřní motivaci.
- Kosmická výchova — propojování předmětů do smysluplného celku.
- Připravené prostředí — třída navržena pro samostatnou práci s materiály.
Bilingvální výuka (CLIL)
Angličtina je integrovaná do běžné výuky (Content and Language Integrated Learning). Předměty v angličtině: tělesná výchova, matematika, kosmická výchova. Děti se učí angličtinu přirozeně, v kontextu reálných aktivit.
Struktura školy
| Stupeň | Popis |
|---|---|
| MŠ | Předškolní vzdělávání, Montessori přístup. Systém Twigsee (mimo Kosmo). |
| ZŠ | 1.–7. ročník, věkově smíšené třídy. Klíčové kompetence: k učení, řešení problémů, komunikativní, sociální, digitální. |
Typické akce a zvyky
- Výlety a exkurze navazující na probíraná témata
- Projektové dny — děti volí témata, pracují napříč ročníky
- Besídky a slavnosti, adaptační týden, kroužky
- Škola v přírodě — vícedenní pobytové akce
Kontakty
- Email školy: info@zs-sofie.cz
- Ředitel: patrik.matlak@zs-sofie.cz
- Doména: sofie.education (Cloudflare DNS)
- Interní nástroje: wiki.sofie.education, ai.sofie.education
Problém k řešení
1. Komunikační propast
Rodiče se cítí v „vzduchoprázdnu". Nerozumí, co děti dělají — integrovaná výuka, žádné známky, děti „neví/neřeknou".
Řešení: Feed — rodič vidí fotky a aktivity dítěte v reálném čase. Před vyzvednutím už ví, na co se zeptat.
2. Přetížení školy
Komunikace je zmatená, na poslední chvíli. Učitelé jsou zavaleni administrativou, systémy spolu nemluví.
Řešení: Sofie (AI persona školy) odbaví rutinu — učitel se soustředí na učení.
3. Fragmentovaná data
| Systém | Účel |
|---|---|
| ŠkolaOnline | Výkaznictví pro MŠMT |
| Pohoda | Účetnictví |
| strava.cz | Školní jídelna |
| Excel, Outlook, Word | Evidence žáků, komunikace |
Vize: Feed + Sofie
Kosmo je „centrální mozek" školy. Dvě klíčové dimenze:
- Feed — „Instagram pro školu". Personalizovaný proud fotek, aktivit a zpráv. Rodič vidí, co se děje, aniž by musel něco hledat.
- Sofie — AI persona školy. Jeden vstupní bod pro všechny (chat, email, hlas). Zpracovává text, odpovídá z ověřené znalostní báze, sleduje úkoly, učí se.
AI First: Cíl je stát se „AI first" školou. Budoucí vize osobního AI průvodce (Sokratův průvodce) pro každého žáka.
Google Workspace
Aktuální stav
- Dva uživatelé s admin právy: Tomáš (
tomas@zs-sofie.cz) a ředitel Patrik (patrik.matlak@zs-sofie.cz) - Čeká se na schválení edukační licence Googlem (žádost podána koncem ledna 2026)
Skupiny
| Skupina | Členové | Účel |
|---|---|---|
admin@zs-sofie.cz |
Tomáš, Patrik | Super admini, přístup ke GCP konzoli |
Nástroje pro správu
- GAM — hromadná správa Google Workspace přes CLI (nainstalován, čeká na autorizaci)
- gcloud — CLI pro GCP (nainstalován)
Google Cloud Platform (GCP)
- Přístup pouze pro
admin@zs-sofie.cz(18+) - Projekt:
sofie-education(ID:sofie-education, Number:54897879776) - Region:
europe-west1(Belgie) — Tier 1, latence z Prahy ~20–25 ms, zónaeurope-west1-b - Služby: Vertex AI / Gemini, Compute Engine (
e2-small), Cloud Run, Workspace APIs
Všechny nové služby zakládejte v regionu
europe-west1.
Migrace z Microsoft 365
Škola migruje z Microsoft 365 na Google (Gmail, Drive, Calendar).
| Zdroj | Cíl | Strategie |
|---|---|---|
| OneDrive | Google Můj disk | Přímá migrace 1:1 per uživatel |
| SharePoint | Google Sdílené disky | Rozdělit do více disků s plošší strukturou |
| Hybridní provoz | Google Drive for Desktop | Virtuální disk, lokální Office + cloud editace |
Domény
- Existují
zs-sofie.czams-sofie.cz(někteří učitelé učí na obou stupních, některé rodiny mají děti v MŠ i ZŠ) sofie.education— primární doména, DNS na Cloudflare- Interní nástroje na subdoménách, Kosmo na
app.sofie.education
Komunikace školy
- S rodiči: vřelé vykání — tónová varianta A „Soused, který má PhD"
- Interně (mezi učiteli): tykání
- Sofie: AI asistentka, tyká — je kolegyně, ne systém
- Primární kanály: email, aplikace Kosmo
Sloučeno z CONTEXT.md a SCHOOL_PROFILE.md. Poslední aktualizace: březen 2026.
Uživatelé a Role
MVP Scope (2026-04-22)
Dvě třídy. Digitální třídnice. Seznam žáků s kontakty.
Testovací verze pro Kentaur (4.+5. ročník) a Phenix (6.+7. ročník). Většina učitelů učí v obou → přepínání tříd je první-třídní UX. Cíl: nahradit papírovou třídnici digitální verzí, kterou učitelé budou chtít používat. Data založí vývojář ručně v Supabase — žádné admin UI v MVP.
Učitel (Průvodce)
"Chci učit, ne klikat v aplikaci."
Device: primárně telefon (na hodině), sekundárně desktop (večer příprava). Mobile-first + responsive, ne "roztažený mobil".
Třídnice — denní rutina
| ID | Story | Akceptace | Spec / Status |
|---|---|---|---|
| U-01 | Otevřu app a rovnou jsem v aktuální hodině. | Systém podle času + rozvrhu najde probíhající slot. Pokud učím v obou třídách ve stejném slotu → vybere tu, kam jsem přiřazený. Fallback: nejbližší budoucí hodina dne. V hlavičce je class switcher — kdykoliv přepnu. | _EXAMPLE-morning-attendance · Implemented |
| U-02 | "Kdo chybí?" → tapnu 1-2 jména → hotovo za 5 sekund. | Default: všichni přítomní. Seznam žáků, každý s jedním tapem přepíná P → N → Pozdě → Omluven → P. Žádné 4 tlačítka per řádek. | _EXAMPLE-morning-attendance · Implemented |
| U-03 | Další hodina automaticky přebírá docházku z předchozí. | Slot 2+ zobrazí stav z předchozího slotu. Upravím jen změny (kdo přišel, kdo odešel). | _EXAMPLE-morning-attendance · Implemented |
| U-04 | Přidám téma → přiřadím celému ročníku jedním chipem. | "Přidat téma" → text → chips [4. ročník] [5. ročník] [individuální žák]. Tap na chip = assignment. | — · Ready for /define |
| U-05 | Anička (5. ročník) dneska pracuje s čtvrťáky. | Přiřadím Aničku k tématu 4. ročníku. Žák může být jen u jednoho tématu v jednom slotu. | — · Ready for /define |
| U-06 | Vidím "Nepřiřazení" — žáci, kteří nemají žádné téma. | Safety net: pod seznamem témat je sekce s žáky bez přiřazení. Ideálně prázdná. | — · Backlog |
| U-07 | Na konci dne vidím, které hodiny mám kompletní. | Dnes / týden (desktop): každý slot má dva vizuální indikátory — téma vyplněno, docházka zapsána. Chybějící = prázdné. | — · Backlog |
Evidence žáků (read-only)
| ID | Story | Akceptace | Spec / Status |
|---|---|---|---|
| U-08 | Najdu žáka a vidím jeho kontakt na rodiče. | Seznam žáků → klik na jméno → detail s ročníkem a zákonnými zástupci. Tap na telefon = volá. Tap na email = píše. | — · Implemented (kód) |
Rodič
V MVP nemá přístup do aplikace. Kontakty jsou v evidenci pro učitele.
Po MVP (vrstva roadmapy): 1. Omlouvání nepřítomnosti 2. Odchody a vyzvedávání 3. Feed — co dítě dělalo ve škole
Role v systému
| Role (DB enum) | Kdo | MVP | Budoucnost |
|---|---|---|---|
teacher |
Průvodce / třídní učitel | Aktivní | + příprava, voice, tracking kompetencí |
parent |
Zákonný zástupce | — (jen kontakt v evidenci) | Omlouvání, odchody, feed |
director |
Ředitel | — (data zakládá vývojář) | Admin UI, statistiky, schvalování |
office |
Kancelář | — | Evidence, exporty, ŠkolaOnline sync |
pending |
Nový uživatel | Čekací obrazovka | Onboarding flow |
Roadmap vrstev (po MVP, v pořadí priority)
Těsně po MVP ("velmi brzy")
- Příprava na hodinu — učitel si dopředu zadá plán témat per ročník; na hodině se předvyplní
- Audio debrief — hlasové poznámky (učitel mluví k dětem → AI rozpozná přiřazení témat; reflexe po hodině)
- Mimořádné dny — "Celá škola do lesa" = override napříč třídami, jedna celodenní docházka místo per-slot
- Zastupování — převzetí hodiny jiného učitele
- Družina — společná pro obě třídy, jednodušší UX (jen docházka)
Později
- Omlouvání rodiči → auto "O" v docházce
- Odchody a vyzvedávání
- Feed pro rodiče
- Tracking kompetencí / progress žáka
- MŠMT export, OpenAPI, MCP wrapper, AI integrace
Data setup pro testování
Vývojář založí ručně v Supabase (ne admin UI, ne seed v gitu):
- 2 třídy: Kentaur (4.+5.), Phenix (6.+7.)
- ~24 žáků s přiřazením do třídy a ročníkem
- Rozvrh (den × slot → předmět × třída)
- Učitelé přiřazení k třídám přes
class_staff - Zákonní zástupci s kontakty (email, telefon, vztah)
Učitelé se přihlásí přes Google OAuth. Propojení auth.users → profiles přes email.
Living document. Stories se rozšiřují s každou vrstvou roadmapy.
Kontrakt (I³)
Intent briefs — kontrakt mezi PO a agenty
Každý implemented modul aplikace má intent brief — 1-stránkový dokument, který říká co aplikace dělá a proč, ne jak. Spolu s docs/invariants.md (pravidla, která nesmí padnout ani při full rewriteu) tvoří kontrakt I³ metodologie (Intent + Invariants + Implementation).
Architektonická rozhodnutí (proč X, ne Y) žijí v docs/decisions/ jako ADRs. Vize a roadmapa žijí v docs/VISION.md a docs/ideas/ — ne tady. Briefy jsou jen pro to, co je nebo se chystá být implementováno.
Workflow
nápad (Tomáš nebo USERS.md story)
│
▼ /define <name>
docs/intent/<name>.md (Status: Draft)
│
▼ PO approve v PR review
docs/intent/<name>.md (Status: Approved)
│
▼ /architect-review docs/intent/<name>.md
docs/decisions/YYYY-MM-DD-<slug>.md (jedno či více ADRs)
│
▼ implement → /ux-audit → /security-review → merge
docs/intent/<name>.md (Status: Implemented)
docs/invariants.md (nové invariants, pokud feature zavádí)
Pravidla
- 1 feature = 1 brief v
docs/intent/<kebab-case-name>.md. Max ~1 strana. - Šablona:
_TEMPLATE.md. 4 sekce: Problém / Kdo to chce / Definice úspěchu / Out-of-scope. Bez technologií, UI mocků, DDL. - Vzor implemented briefu:
auth-and-roles.md(pilot I³ metodologie, 2026-05-13). - Status ve frontmatteru:
Draft → Approved → Implemented → Superseded. Přepíná PO v PR review, ne agent. - Po Implemented brief nemažeme — slouží jako kontrakt + historie. Významné změny řešit novým briefem se
Status: Supersedes <starý>.
Index
| ID (soubor) | Title | Status | Phase | Code refs |
|---|---|---|---|---|
| auth-and-roles | Auth & role gating | Implemented | 1 | web/src/utils/supabase/middleware.ts, web/src/lib/auth.ts |
| classbook | Třídnice (day + week view) | Implemented | 1 | web/src/app/(app)/page.tsx, web/src/app/(app)/plan/, web/src/components/classbook/ |
| attendance | Docházka — checklist + cyklování stavů | Implemented | 1 | web/src/lib/classbook-server.ts, web/src/app/(app)/classbook-actions.ts |
| slot-topics | Témata hodiny + per-student přiřazení | Implemented | 1 | web/src/components/classbook/AddTopicDialog.tsx, StudentMatrix.tsx |
| students-registry | Evidence žáků + zákonní zástupci | Implemented | 1 | web/src/app/(app)/zaci/ |
| schedule-slots | Rozvrh + substituce | Implemented | 1 | supabase/migrations/20260422000001_init.sql (seed-only) |
| day-overrides | Výlety, prázdniny, project days | Schema-only (UI not implemented) | 1.5 | DB schema, UI chybí |
Index udržuje
doc-curatorpři/curate-docs. Při změně chování feature → update brief + invariant test.
Invariants Registry
Pravidla, která nesmí porušit ani full rewrite. Každý invariant má ID, tvrzení (1 věta, testovatelné), proč existuje, test status, a důsledek porušení.
Hierarchie:
- Critical → musí mít test (tested:<path>). CI blokuje merge, pokud test padá.
- Standard → text-only, hlídá doc-curator.
Konvence:
- ID: INV-<DOMAIN>-NN (např. INV-AUTH-01).
- Při refactoru zachovat ID. Při zastarání: status Deprecated + odkaz na nový invariant.
Auth & Role gating
INV-AUTH-01 — Role gating je v middleware, ne v UI [Critical]
Tvrzení: Žádná chráněná routa nesmí spoléhat výhradně na UI check role. Autorita rolí je v web/src/utils/supabase/middleware.ts (anonymní → /login, pending/parent → /pending, staff → app).
Proč: UI checky lze obejít přímým HTTP voláním nebo úpravou client state. Middleware je jediný bod, který volá Supabase pro skutečnou roli z profiles tabulky.
Test: web/tests/invariants/role-gating.spec.ts (3× anonymous-redirect na /, /plan, /zaci). Positive-path test (staff dorazí do appky) žije v e2e suite, ne tady — invariant gate musí být reproducibilní bez seedované DB.
Důsledek porušení: Neoprávněný uživatel vidí cizí data — GDPR incident.
INV-AUTH-02 — RLS je primární vrstva ochrany dat [Critical]
Tvrzení: Každá tabulka s personal data (profiles, students, attendance_records, classbook_entries, slot_topics, student_slot_topics, atd.) má RLS enabled a má aspoň jednu policy pro select rozhodnutou rolí, ne auth.uid() = id. Middleware je první obrana, RLS je druhá — i kdyby middleware selhal, DB nepustí cizí data.
Proč: Defense in depth. Bug v middleware (nebo budoucí přechod na API routes) nesmí znamenat ztrátu dat. RLS založené na roli (ne na user.id hardkódu) přežije refactor relací.
Test: web/tests/invariants/rls-coverage.spec.ts (planned — Fáze 2)
Důsledek porušení: SQL injection nebo middleware bypass exfiltruje data celé školy.
INV-AUTH-03 — Nový účet startuje vždy v pending [Standard]
Tvrzení: Trigger handle_new_user v supabase/migrations/20260422000001_init.sql:309-311 vkládá nový profil s role = 'pending'. Žádná cesta v aplikaci nesmí měnit roli z UI bez explicitního admin path (zatím manuálně v Supabase Dashboard).
Proč: Zero-trust onboarding. Self-signup nesmí vést k automatickému přístupu k datům. Tomáš schvaluje.
Test: text-only (lze přidat SQL test, ale low priority dokud není self-signup UI).
Důsledek porušení: Kdokoli s Google účtem se dostane do systému.
INV-AUTH-04 — Auth callback validuje session přes Supabase, ne přímo z query parametrů [Critical]
Tvrzení: web/src/app/auth/callback/route.ts použije supabase.auth.exchangeCodeForSession(code) (případně verifyOtp pro magic-link token) — nikdy nečte email, role ani jiné údaje přímo z URL.
Proč: URL parametry jsou plně klientem kontrolované. Supabase Auth validuje JWT issuer a podpis při exchange / verify. Kdyby callback přečetl email z URL a vytvořil session, útočník by se vydával za kohokoli.
Test: pokrytí typovým systémem (callback nemá jinou cestu než exchangeCodeForSession), code review.
Důsledek porušení: Account takeover.
INV-AUTH-05 — V produkci je magic link jediný login flow [Critical]
Tvrzení: V produkčním buildu (NODE_ENV=production, KOSMO_DEMO_MODE ≠ "true") je jediná cesta k získání session přes Supabase signInWithOtp (magic link na e-mail). Žádný signInWithPassword v server actions, žádný OAuth provider zapnutý v Supabase Auth config, žádné quick-login tlačítko v UI. Dev quick-login (devQuickLogin) musí na začátku ověřit process.env.KOSMO_DEMO_MODE === "true" a jinak zamítnout.
Proč: Provider rozhodnutí (M365 ↔ Google) je dnes pohyblivé — magic link je jediný provider-agnostic flow. Žádné heslo = žádný password attack surface, žádný password reset flow. Dev quick-login je nutný pro lokální vývoj, ale gating ho drží mimo produkci. Viz ADR 2026-05-14-auth-magic-link-only.md.
Test: web/tests/invariants/login-magic-link-only.spec.ts — bez KOSMO_DEMO_MODE se na /login nezobrazuje quick-login panel ani Google tlačítko ani password input.
Důsledek porušení: Resurrekce password flow, který nikdo aktivně nepoužívá → zbytečný attack surface; nebo nechtěné zveřejnění quick-login tlačítek v prod = bypass middleware role gate.
Data integrity
INV-DATA-01 — Docházka je idempotentní upsert [Critical]
Tvrzení: Zápis docházky používá upsert s onConflict: "classbook_entry_id,student_id". Opakované volání stejného payloadu nesmí vytvářet duplicity ani měnit stav, pokud se hodnoty nezměnily.
Proč: Mobilní síť padá, učitel tapne tlačítko dvakrát. Bez idempotence: duplicate row error (Postgres unique constraint) → UI selže. S idempotencí: tichá konvergence.
Test: web/tests/invariants/attendance-idempotence.spec.ts (planned — backfill při příští úpravě)
Důsledek porušení: Učitel ztratí důvěru („proč mi to selhalo?"), nebo se duplicitní řádek vplete do reportingu.
INV-DATA-02 — classbook_entry se zakládá lazy [Standard]
Tvrzení: Slot bez interakce učitele (žádná docházka, žádné téma) NEMÁ řádek v classbook_entries. Záznam vzniká až při první mutaci přes ensureClassbookEntry().
Proč: Bez lazy zakládání by každý den všechny sloty všech tříd dostaly ghost záznamy → garbage, falešné metriky („99% pokrytí" = jen že existuje entry).
Test: text-only.
Důsledek porušení: Reporty „kolik hodin proběhlo" lžou.
INV-DATA-03 — classbook_entries.taught_by autoritou substituce [Standard]
Tvrzení: schedule_slots.default_teacher_id je výchozí učitel; skutečný učitel hodiny je classbook_entries.taught_by. UI a budoucí reporting čte vždy taught_by (s fallbackem na default_teacher_id pouze v prázdném slotu).
Proč: Substituce se musí dohledat. Bez taught_by autority by report ukazoval, že hodinu učil ten, kdo má rozvrh — bez ohledu na realitu.
Test: text-only.
Důsledek porušení: Pracovní výkaz / fakturace lže (až bude implementováno).
INV-DATA-04 — Po uzavření docházky se odeberou topic přiřazení absentům [Critical]
Tvrzení: setAttendanceDone(slot, true) provede v jedné transakci: (a) flagne classbook_entries.attendance_done_at, (b) smaže řádky student_slot_topics pro studenty se statusem absent v tomto slotu.
Proč: Fair credit. Absent žák nedostal téma → nesmí se mu počítat do statistik zvládnutí. Pokud učitel zapomene, výsledky lžou.
Test: web/tests/invariants/attendance-topic-cleanup.spec.ts (planned)
Důsledek porušení: Falešně pozitivní statistiky zvládnutí, problém v dialogu rodič ↔ Sofie.
Architektonické disciplíny (cross-cutting)
INV-ARCH-01 — Server actions a route handlers validují input přes Zod [Critical]
Tvrzení: Každá server action a route handler validuje vstup pomocí Zod schématu z web/src/lib/schemas/. Žádné formData.get() nebo request.json() se nedostane do business logiky bez Schema.parse().
Proč: Typová jistota + future MCP/OpenAPI generace ze schémat. Bez Zod = týden retrofitu kontraktů při zavádění agenta.
Test: text-only + code review (lint rule by mohl být doplněn).
Důsledek porušení: Runtime crash z neplatného vstupu, nebo tichá data corruption.
INV-ARCH-02 — Auth client podporuje cookie i Bearer token [Standard]
Tvrzení: web/src/utils/supabase/middleware.ts (a server client factory) přijme jak cookie session, tak Authorization: Bearer <jwt>. Bearer path je dnes dead code, ale musí zůstat funkční (otestovaná).
Proč: MCP server, cron joby, externí integrace dostanou service tokeny. Pokud teď postavíme jen cookie auth, přepíšeme celou auth vrstvu při prvním externím konzumentovi.
Test: text-only (lze doplnit invariant test).
Důsledek porušení: Velký refactor auth vrstvy při zavádění agenta.
INV-ARCH-03 — Žádné JSON bloby pro core domain data [Standard]
Tvrzení: Hlavní entity (docházka, témata, žáci, sloty, override dny) mají relační sloupce. M:N přes join tabulky. JSONB povolen jen pro skutečně volná data (AI response blob, event metadata).
Proč: Universal Knowledge Graph (vize ve docs/ideas/knowledge-graph.md) bude později mirror z relačních tabulek. S JSONB = migrační peklo.
Test: text-only (manuální review při změnách schématu).
Důsledek porušení: Knowledge graph nelze postavit bez kompletní data migrace.
INV-ARCH-04 — RLS policies přes vztahy, ne přes hardcoded auth.uid() [Critical]
Tvrzení: RLS policies používají JOIN na role tabulky (class_staff, student_guardians, profiles.role). Žádná policy nepřičítá konkrétní auth.uid() = NEJAKE_ID. Viz vzor v supabase/migrations/20260422000001_init.sql (policies přes class_staff).
Proč: Až MCP server dostane JWT, RLS musí aplikovat stejná pravidla jako UI bez přepisování. Hardcoded auth.uid() policies se rozpadnou při změně rolí.
Test: text-only + manuální audit při změně schématu.
Důsledek porušení: Přepis RLS při každém novém integračním scénáři.
PII & Data minimization
INV-PII-01 — Zakázané kategorie údajů v DB schématu [Critical]
Tvrzení: Žádná tabulka v public schématu nesmí obsahovat sloupce, jejichž jméno matchuje blocklist: birth_number, rodne_cislo, street, address, health, medical, allergy, svp, ivp, biometric, birth_date, date_of_birth, photo, face (case-insensitive, substring match). Žák má pouze birth_year SMALLINT, ne plné datum. Adresa, rodné číslo, zdravotní a SEN informace mimo schéma.
Proč: Rodné číslo má v ČR samostatný zákonný režim (zákon 133/2000). Zdravotní data, SVP/IVP a biometrie spadají pod čl. 9 GDPR (zvláštní kategorie) — nepřiměřené riziko vůči přínosu ve Fázi 1-2. Minimální schéma drží blast radius úniku v pásmu "nízkorizikový incident" v terminologii ÚOOÚ. Sloupec přidaný omylem (copy-paste z legacy systému, automaticky vygenerovaná migrace) tímto invariantem padne v CI.
Test: web/tests/invariants/pii-forbidden-columns.spec.ts — parsuje SQL migrace v supabase/migrations/*.sql a hledá CREATE TABLE / ADD COLUMN identifikátory proti blocklistu. Offline test, nevyžaduje běžící DB.
Důsledek porušení: GDPR incident s vysokým dopadem; pro rodná čísla i porušení zvláštního zákona. Při skutečné potřebě sloupce: ADR, který tento invariant superseduje pro konkrétní use case.
INV-PII-02 — LLM exporty jsou pseudonymizované by default [Standard]
Tvrzení: Jakmile vznikne helper pro export dat do LLM kontextu (Claude, Gemini), default funkce vrací pseudonymizovaná data (Žák A37 místo Anna Nováková, bez kontaktů rodičů). Plný-identita export musí být oddělená funkce s explicitním názvem (exportWithIdentity() apod.) a komentářem, kdy je legitimní (generování dopisů rodičům, právní dokumenty).
Proč: Default-safe. Většina LLM úloh (rozvrhy, statistiky, skupinkování, generování úloh) jména nepotřebuje. Snižuje povrch při omylu — copy-paste pseudonymizovaného seznamu do veřejného chatu není incident.
Test: text-only. Povýší na Critical, jakmile helper existuje (test na regex Žák [A-Z]\d+ v default exportu).
Důsledek porušení: Zbytečný únik jmen při ad-hoc práci s LLM. Právně OK (máme DPA), ale reputačně nepříjemné.
INV-PII-03 — Birth year, ne full date [Standard]
Tvrzení: students.birth_year SMALLINT jako jediný údaj o věku. Plné datum narození přidat až ve Fázi 2 s konkrétním business use casem (právní dokument, oslavenec) přes ADR, který tento invariant superseduje.
Proč: Kombinace jméno + plné datum narození výrazně zvyšuje identifikovatelnost (k-anonymita klesá z desítek na jednotky). Pro běžnou školní logiku (ročník, věk, "kdo má 7 let") stačí rok.
Test: Pokryto INV-PII-01 (birth_date, date_of_birth na blocklistu).
Důsledek porušení: Zvýšené riziko reidentifikace při úniku, vyšší klasifikace incidentu vůči ÚOOÚ.
Konvence (meta)
INV-META-01 — Žádná produkční data dnes [Standard]
Tvrzení: Supabase Cloud DB neobsahuje reálná osobní data žáků/rodičů. Migrace mohou být destruktivní (supabase db reset).
Proč: Vibe coding mode — rychlost přes konzervativnost. Při příchodu reálných dat tento invariant odpadne a aktivuje se striktní migrace gate.
Test: text-only — Tomáš kontroluje.
Důsledek porušení: Ztráta dat školy.
Architektura
Datový Model (Supabase / PostgreSQL)
Tento dokument popisuje schéma DB na vyšší úrovni. Kanonický zdroj pravdy je supabase/migrations/20260422000001_init.sql — pokud něco kolize, věřit SQL souboru.
Aktuální stav (2026-05-11): jediná migrace, 15 tabulek, 7 enum typů. RLS enabled na všech tabulkách, policy v rolích (is_staff(), is_admin()), nikdy ne hardcoded auth.uid() v business logice.
Disciplíny (must)
- Relační model, žádný JSONB pro hlavní entity.
- RLS přes role helpery (
is_staff,is_admin), ne přes uživatelské ID. - M:N přes join tabulky (např.
slot_topics↔studentspřesstudent_slot_topics). - Schema připravené na Fázi 2+ (
day_overrides,taught_by,arrived_at/left_at,afterschoolclass_type) — UI bude doplněno až bude potřeba.
1. Enums (7)
| Enum | Hodnoty | Použití |
|---|---|---|
user_role |
pending, director, teacher, office, parent |
profiles.role |
class_type |
school, afterschool |
classes.class_type (afterschool = družina) |
student_status |
active, inactive |
students.status |
staff_role |
lead_teacher, co_teacher, assistant |
class_staff.role |
guardian_relationship |
mother, father, grandparent, guardian, other |
student_guardians.relationship |
attendance_status |
present, absent, late, excused |
attendance_records.status |
day_override_type |
excursion, project_day, school_holiday, other |
day_overrides.type |
2. Tabulky — přehled (15)
Identity & Auth
| Tabulka | Účel | Klíčové sloupce |
|---|---|---|
profiles |
Uživatelské účty (1:1 s auth.users) |
id (FK → auth.users), email, role (default pending) |
profiles.idje FK naauth.users(id). Při registraci přes Supabase Auth se profil vytvoří automaticky triggeremhandle_new_usersrole = 'pending'(čeká na schválení).
Referenční data
| Tabulka | Účel | Unique |
|---|---|---|
school_years |
Školní roky ("2025/2026") | Jen 1 active naráz (partial unique index) |
classes |
Třídy (Kentaur, Phenix, afterschool) | name |
subjects |
Předměty (Matematika, ČJ, Kosmická) | name |
Žáci a zákonní zástupci
| Tabulka | Účel | Vazby |
|---|---|---|
students |
Žáci | grade (ročník), status |
students_classes |
Zápis žáka do třídy per rok | M:N students ↔ classes × school_years |
guardians |
Zákonní zástupci | nullable user_id (link na auth.users až po registraci rodiče) |
student_guardians |
Zástupce ↔ žák | M:N s typem vztahu + is_primary flag |
Personál (učitelé)
| Tabulka | Účel | Vazby |
|---|---|---|
class_staff |
Učitel přidělen do třídy v ročníku | M:N profiles ↔ classes × school_years s rolí (lead_teacher / co_teacher / assistant) |
Rozvrh a třídnice
| Tabulka | Účel | Klíčové |
|---|---|---|
schedule_slots |
Týdenní opakující se rozvrh per třída | day_of_week 1–5, slot_order 1–10, default_teacher_id (slot-level ownership) |
classbook_entries |
Skutečný záznam hodiny per slot per datum | taught_by (zastupování — Fáze 2), attendance_done_at (kompletnost docházky) |
slot_topics |
Témata probraná v hodině (M:N s žáky) | grade_hint (rychlý "přiřaď ročníku X" shortcut) |
student_slot_topics |
Který žák pracoval na kterém tématu | Unique per (student_id, slot_topic_id) |
attendance_records |
Docházka per slot | arrived_at / left_at nullable (rezerva pro Fázi 2 MŠMT export) |
Speciální dny
| Tabulka | Účel | Klíčové |
|---|---|---|
day_overrides |
Mimořádné dny (výlet, projektový den, prázdniny) | class_id NULL = celoškolní; typ z day_override_type |
day_overrides.class_idmůže být NULL pro celoškolní akce. Unique constrainty (partial indexes) řeší kolize: 1 override per (datum, třída) nebo 1 celoškolní override per datum.
3. ER diagram
erDiagram
auth_users ||--|| profiles : "1:1"
profiles ||--o{ class_staff : "učí v"
profiles ||--o{ schedule_slots : "default teacher"
profiles ||--o{ classbook_entries : "taught_by"
profiles ||--o{ guardians : "user_id (nullable)"
school_years ||--o{ students_classes : "zápisy roku"
school_years ||--o{ class_staff : "personál roku"
school_years ||--o{ schedule_slots : "rozvrh roku"
classes ||--o{ students_classes : ""
classes ||--o{ class_staff : ""
classes ||--o{ schedule_slots : ""
classes ||--o{ day_overrides : ""
students ||--o{ students_classes : ""
students ||--o{ student_guardians : ""
students ||--o{ student_slot_topics : ""
students ||--o{ attendance_records : ""
guardians ||--o{ student_guardians : ""
subjects ||--o{ schedule_slots : ""
schedule_slots ||--o{ classbook_entries : ""
classbook_entries ||--o{ slot_topics : ""
classbook_entries ||--o{ attendance_records : ""
slot_topics ||--o{ student_slot_topics : ""
4. Triggers
| Trigger | Tabulka | Co dělá |
|---|---|---|
*_updated_at |
profiles, students, guardians, classbook_entries, attendance_records |
Auto-update updated_at při každém UPDATE |
on_auth_user_created |
auth.users (insert) |
Vytvoří profil s role='pending' |
5. Helper funkce (RLS)
is_staff() → boolean -- role IN ('teacher', 'director', 'office')
is_admin() → boolean -- role IN ('director', 'office')
Obě jsou security definer, stable, set search_path = public. Volají se v using / with check policies.
6. RLS pattern
Všechny tabulky mají RLS enabled. Policies se řídí třemi vzory:
| Vzor | Použito na | Pravidlo |
|---|---|---|
| Authenticated read | school_years, classes, subjects |
Každý přihlášený uživatel může číst |
| Staff read + admin write | students, students_classes, guardians, student_guardians, class_staff |
is_staff() čte vše, is_admin() zapisuje |
| Staff full + parent read of own children | attendance_records, schedule_slots, students (parent path) |
Personál plný přístup, rodiče čtou jen data svých dětí přes student_guardians ↔ guardians.user_id |
Self-access: profiles_self_update umožňuje uživateli editovat vlastní profil. guardians_self_read umožňuje rodiči číst svůj záznam zástupce.
Classbook write: classbook_entries, slot_topics, student_slot_topics, attendance_records (write) má každý člen personálu — v MVP žádné per-class omezení (učitelé v Sofii učí napříč třídami).
Detailní policies viz init.sql řádky 320–537. Tento dokument popisuje vzory, ne každou jednotlivou policy.
7. Co schéma neobsahuje (záměrně)
- Feed / events / posts — Fáze 3+. Reálná data pro rodiče jdou přes Sofii jako orchestrátora, ne přes vlastní entity.
- Tasks / PM modul — Fáze 2+. Plánováno jako organická náhrada přes BookStack tagy + Sofie.
- Omluvenky, vyzvedávání — Fáze 2+. Schema bude doplněno, až přijde UI.
- Audit log — TBD před přechodem na produkční data (GDPR gate v AGENTS.md).
8. Migrace
Aktuálně 1 migrace (20260422000001_init.sql). Předchozí 2 fix-up migrace byly squashnuty do init při bootstrap cleanupu 2026-05-11 (default_teacher_id, attendance_done_at). Squash je legitimní strategie, dokud nemáme produkční data — viz DEV-LOG.
Pro úplnou strukturu (všechny indexy, FK constraints, RLS policies) viz init.sql. Tento dokument je rychlá orientace — udržuje se přes /curate-docs.
Integrace (INTEGRATIONS.md)
Tento dokument popisuje strategii integrace s externími systémy a úložištěm souborů.
1. Úložiště souborů
Aktualizace (duben 2026): Primární storage přesunuto na Supabase Storage. Škola má ~80 žáků, odhadovaný objem ~10–20 GB/rok. Supabase Pro (100 GB) stačí na roky, RLS funguje z boxu bez extra infrastruktury. GCS plán níže zůstává jako reference pro budoucí migraci, pokud objem překročí kapacitu Supabase nebo bude potřeba přímá integrace s Vertex AI.
Původní plán: GCP Cloud Storage (odloženo)
Architektonický princip: File-first, Schema-light
GCP Bucket je source of truth. Supabase drží jen AI-derived data.
Škola potřebuje ukládat soubory ke každému žákovi:
- Evidenční dokumenty — smlouvy, rodné listy, kartičky ZP, souhlasy GDPR. Málo souborů, vysoká citlivost, dlouhá retence.
- Fotky prací žáků — sešity, projekty, výkresy. Fotky věcí (ne osob). Střední objem, AI zpracování.
- Scany ověření — doklady o zvládnutí kompetencí. AI extrahuje strukturovaná data.
- Právní dokumenty — vše jde do GCP Bucket (rozhodnuto).
Každý soubor má vedle sebe .meta.json s popisem. Supabase drží jen zpracované výstupy (competency_records), které lze kdykoliv přegenerovat z raw souborů. Toto umožňuje:
- Periodické re-processing — až bude AI chytřejší, projdeš složku žáka znovu a vygeneruješ nové insights
- Disposable schema — Supabase struktury je jednodušší zahodit a přepracovat, protože soubory + metadata v bucketu jsou nezávislé
- Self-describing storage — i bez databáze lze procházet bucket a rozumět, co v něm je
Proč GCP Cloud Storage
| Výhoda |
|---|
Přímá integrace s Vertex AI / Gemini Vision (stejný projekt sofie-education, žádný data transfer) |
Data v EU (europe-west1) — GDPR |
| Levné: Standard ~$0.02/GB/měsíc, Nearline pro archiv |
| Signed URLs pro bezpečné zobrazení v UI (time-limited) |
| Lifecycle rules (automatická archivace starších souborů) |
| Object Versioning (ochrana proti nechtěnému smazání + historie sidecar metadat) |
| Už máme GCP projekt, region, billing |
Vyřazené alternativy
| Alternativa | Proč ne |
|---|---|
| Google Shared Drive | Oddělení od Kosma — dvě místa. Žádná integrace s AI. Nemožnost kontrolovat kompletnost dokumentů v Kosmu. |
| GCP Cloud Storage | Původně plánováno jako primární, odloženo — Supabase Storage zvládne potřeby školy (viz začátek sekce). |
| Immich | Vyřazen z důvodu GDPR biometrie. Hardcodovaný Face Recognition u dětí = extrémní právní zátěž. |
Bucket struktura
Dvě podsložky per žák: evidence/ (sekretářka, právní dokumenty) a portfolio/ (učitel, práce + ověření). Čitelné názvy souborů. Sidecar .meta.json vedle každého souboru.
gs://sofie-media/
└── {student_id}/
├── evidence/ # sekretářka spravuje
│ ├── smlouva_2025.pdf
│ ├── smlouva_2025.meta.json
│ ├── rodny_list.pdf
│ ├── rodny_list.meta.json
│ ├── zp_karticka.jpg
│ └── zp_karticka.meta.json
├── portfolio/ # učitel nahrává
│ ├── 2026-03-15_projekt_vesmir.webp
│ ├── 2026-03-15_projekt_vesmir.meta.json
│ ├── 2026-03-20_overeni_zlomky.webp
│ └── 2026-03-20_overeni_zlomky.meta.json
└── manifest.json # auto-generovaný index přes obě složky
evidence/= právní/administrativní dokumenty. Málo souborů, spravuje sekretářka, jiná oprávnění (admin only).portfolio/= vše co dokumentuje pokrok žáka (fotky prací + scany ověření). Spravuje učitel, AI zpracovává.- Manifest na root úrovni žáka — AI vidí oboje.
Pojmenování souborů
Čitelné názvy, ne UUID. Učitel/sekretářka zadá krátký popis při uploadu, systém vygeneruje filename:
- Evidenční:
{typ_dokumentu}_{rok}.{ext}→smlouva_2025.pdf,zp_karticka.jpg - Portfolio:
{datum}_{popis}.{ext}→2026-03-15_projekt_vesmir.webp,2026-03-20_overeni_zlomky.webp
Duplicity
Soubor, který se týká více žáků (skupinový projekt), se nahraje duplicitně do složky každého žáka. Storage je levný ($0.02/GB/měsíc), konzistence a jednoduchost dotazování je cennější.
Sidecar .meta.json
Každý soubor má vedle sebe {filename}.meta.json se strukturovanými metadaty. Pole jsou volitelná dle type.
{
"type": "work | document | assessment",
"original_name": "IMG_4521.jpg",
"uploaded_by": "ucitel@zs-sofie.cz",
"uploaded_at": "2026-03-15T10:30:00Z",
"school_year": "2025/2026",
"teacher_note": "Projekt o vesmíru — korálkový materiál",
"tags": ["projekt", "vesmír", "matematika"],
"subject": "přírodověda",
"document_type": "smlouva",
"valid_until": "2027-06-30"
}
Pole dle typu
| Pole | document |
work |
assessment |
|---|---|---|---|
type |
✅ | ✅ | ✅ |
original_name |
✅ | ✅ | ✅ |
uploaded_by |
✅ | ✅ | ✅ |
uploaded_at |
✅ | ✅ | ✅ |
school_year |
✅ | ✅ | ✅ |
document_type |
✅ | — | — |
valid_until |
✅ (volitelné) | — | — |
teacher_note |
— | ✅ | ✅ |
tags |
— | ✅ | ✅ |
subject |
— | ✅ | ✅ |
assessment_date |
— | — | ✅ |
manifest.json
Auto-generovaný index všech souborů žáka. Regeneruje se po každém uploadu/smazání. Slouží jako rychlý vstup pro AI — místo listování bucketu AI dostane jeden JSON.
{
"student_id": "uuid",
"generated_at": "2026-03-24T12:00:00Z",
"file_count": 8,
"evidence": [
{"name": "smlouva_2025.pdf", "document_type": "smlouva", "uploaded_at": "2026-03-15"},
{"name": "rodny_list.pdf", "document_type": "rodny_list", "uploaded_at": "2026-03-15"},
{"name": "zp_karticka.jpg", "document_type": "zp_karticka", "uploaded_at": "2026-03-15"}
],
"portfolio": [
{"name": "2026-03-15_projekt_vesmir.webp", "type": "work", "subject": "přírodověda", "uploaded_at": "2026-03-15"},
{"name": "2026-03-20_overeni_zlomky.webp", "type": "assessment", "subject": "matematika", "uploaded_at": "2026-03-20"}
]
}
Supabase — minimální, disposable schema
Supabase drží jen to, co je AI-derived a slouží pro dotazování v UI. Vše je regenerovatelné z bucket souborů.
student_files — cache/index souborů
Lightweight cache pro UI listing bez GCS API volání. Regenerovatelné z manifest.json.
| Sloupec | Typ | Popis |
|---|---|---|
id |
UUID PK | |
student_id |
UUID FK → students | |
file_name |
TEXT | Čitelný název souboru |
storage_path |
TEXT | Plná cesta v GCS |
folder |
TEXT | evidence nebo portfolio |
type |
TEXT | document, work, assessment |
document_type |
TEXT | Pro evidence: smlouva, rodny_list, zp_karticka, souhlas_gdpr... |
subject |
TEXT | Pro portfolio: předmět |
uploaded_at |
TIMESTAMPTZ | |
created_at |
TIMESTAMPTZ |
competency_records — AI-extrahované záznamy kompetencí
Centrální tabulka pro AI metodické listy. Plněna z AI zpracování fotek prací a scanů ověření.
| Sloupec | Typ | Popis |
|---|---|---|
id |
UUID PK | |
student_id |
UUID FK → students | |
competency_code |
TEXT | Kód kompetence (RVP nebo vlastní školy) |
competency_name |
TEXT | Lidsky čitelný název: "Sčítání zlomků" |
subject_area |
TEXT | "Matematika", "Český jazyk"... |
evidence_source |
TEXT | assessment, work, teacher_manual |
source_file |
TEXT | Název souboru v bucketu (ne FK, jen reference) |
level |
TEXT | "zvládá samostatně", "zvládá s podporou", "rozvíjí se" |
observed_at |
DATE | Kdy kompetence pozorována |
school_year |
TEXT | "2025/2026" |
ai_generated |
BOOLEAN | Zda to generovala AI |
teacher_confirmed |
BOOLEAN | Zda učitel potvrdil |
processing_model |
TEXT | Jaký model generoval (pro re-processing) |
processing_date |
TIMESTAMPTZ | Kdy zpracováno |
created_at |
TIMESTAMPTZ |
ai_processing_runs — log zpracování
Audit log pro tracking AI zpracování a re-processing.
| Sloupec | Typ | Popis |
|---|---|---|
id |
UUID PK | |
student_id |
UUID FK → students | |
run_type |
TEXT | single_file, full_portfolio |
model_used |
TEXT | "gemini-2.0-flash", "gemini-2.5-pro"... |
started_at |
TIMESTAMPTZ | |
completed_at |
TIMESTAMPTZ | |
files_processed |
INTEGER | |
records_generated |
INTEGER | |
status |
TEXT | running, completed, failed |
error_message |
TEXT | Při selhání |
Upload flow
sequenceDiagram
participant U as Učitel/Sekretářka
participant K as Kosmo (Next.js)
participant S as Supabase Storage
participant G as Gemini Vision
participant DB as Supabase DB
U->>K: Nahraje soubor + vyplní popis
Note over K: Client-side resize fotek (2048px, WebP)
K->>K: Vygeneruje čitelný filename + .meta.json
K->>S: Upload soubor (Supabase Storage, RLS)
K->>S: Upload .meta.json
K->>DB: Upsert student_files (cache)
alt Portfolio soubor (work/assessment)
K->>G: Analyze image
G-->>K: Popis, předmět, štítky, kompetence
K->>DB: Insert competency_records
K->>DB: Insert ai_processing_runs
end
K->>U: Hotovo
Evidence upload (sekretářka)
- Otevře kartu žáka → záložka "Soubory" → sekce "Evidence"
- Vidí checklist povinných dokumentů (smlouva, GDPR souhlas, rodný list, ZP kartička)
- Chybějící = červený badge, nahráno = zelený check
- Klikne "Nahrát" u konkrétního typu → file picker (PDF/JPG/PNG)
- Systém automaticky pojmenuje dle typu + roku
- Upload do
{student_id}/evidence/
Portfolio upload (učitel)
- Otevře kartu žáka → záložka "Soubory" → sekce "Portfolio"
- Klikne "Přidat" → vybere typ (fotka práce / scan ověření)
- Na mobilu: camera capture, na desktopu: file picker
- Vyplní krátký popis + předmět (volitelně)
- Client-side resize na 2048px + WebP konverze
- Upload do
{student_id}/portfolio/ - AI zpracování na pozadí (Gemini Vision → competency_records)
AI zpracování
Při uploadu (single file)
| Typ souboru | AI vstup | AI výstup |
|---|---|---|
Fotka práce (work) |
Obrázek + teacher_note + subject | Popis scény, identifikované kompetence, štítky |
Scan ověření (assessment) |
Obrázek | Strukturovaná extrakce: úlohy, výsledky, kompetence, chyby |
| Evidenční dokument | — | Žádné AI zpracování (MVP) |
Scan ověření — příklad AI extrakce
Vstup: Scan papírového ověření z matematiky. Gemini Vision výstup:
{
"assessment_title": "Ověření — Zlomky",
"tasks": [
{"number": 1, "description": "Sečti zlomky", "result": "correct", "competency": "M-5-1-01"},
{"number": 2, "description": "Odečti zlomky", "result": "partial", "competency": "M-5-1-02"},
{"number": 3, "description": "Slovní úloha", "result": "correct", "competency": "M-5-1-03"}
],
"teacher_comment": "Výborně, jen pozor na společný jmenovatel",
"competencies_demonstrated": ["M-5-1-01", "M-5-1-03"],
"confidence": 0.87
}
Učitel vidí extrakci v UI → potvrdí nebo upraví → teacher_confirmed = true.
Periodické re-processing (budoucí)
Cron job nebo on-demand Vercel Edge Function "Portfolio Re-processing": 1. Vezme manifest.json žáka 2. Pošle Gemini Pro s celým kontextem portfolia (všechny soubory za školní rok) 3. Přegeneruje competency_records s novým modelem 4. Zaloguje do ai_processing_runs
Spouštěno on-demand nebo měsíčně. Umožňuje využít nové AI modely s lepším porozuměním bez změny dat.
[!IMPORTANT] Žádné face recognition. Gemini Vision popisuje scénu a aktivitu, ne osoby. Přiřazení fotky ke konkrétnímu žákovi dělá učitel při uploadu. Biometrie dětí je zvláštní kategorie pod GDPR.
AI workflows (plánované, Fáze 2+)
| Workflow | Trigger | Popis |
|---|---|---|
| Work/Assessment Processing | Webhook po uploadu | Gemini Vision analýza → upsert competency_records |
| Portfolio Re-processing | On-demand / měsíčně | Projde manifest.json → Gemini Pro s celým kontextem → přegeneruje competency_records |
| Methodology Sheet Generator | On-demand (budoucí) | Čte competency_records + manifest → Gemini Pro → Typst PDF |
Implementace: Vercel Edge Functions nebo Inngest (ne n8n — viz DEV-LOG 2026-05-11).
Document completeness
Jednoduché řešení bez cronu: UI na kartě žáka zobrazí checklist povinných typů dokumentů. Stav se derivuje z manifest.json / student_files cache.
Povinné typy (konfigurovatelné):
- smlouva — Smlouva o vzdělávání
- souhlas_gdpr — Souhlas se zpracováním osobních údajů
- rodny_list — Rodný list (kopie)
- zp_karticka — Kartička zdravotní pojišťovny
Chybí soubor s daným document_type? → červený badge. Sekretářka vidí stav přímo na kartě žáka.
Přístupová matice
| Role | evidence/ |
portfolio/ |
|---|---|---|
| Ředitel | ✅ čtení + upload | ✅ čtení + upload |
| Sekretářka | ✅ čtení + upload | ✅ čtení |
| Třídní učitel | ❌ (výjimka: ZP kartička na výletě) | ✅ všech žáků — čtení + upload |
| Rodič | ❌ | ✅ svého dítěte — pouze čtení |
Rozhodnuto: Učitel má read-only přístup k portfoliím všech žáků napříč třídami (nejen svých).
Implementováno přes Kosmo auth + signed URLs (server generuje URL jen pokud uživatel má oprávnění).
Fotky — rozhodnuté otázky
- Retence fotek: 3 roky po odchodu žáka ze školy.
- Souhlas: Obecný souhlas při zápisu (ne per-soubor).
- Tagování fotek: Automaticky dle data, učitel potvrdí. Žádné biometrické rozpoznávání.
Lifecycle rules (GCS)
| Prefix | Standard | Nearline (2 roky) | Coldline (5 let) | Archive |
|---|---|---|---|---|
*/evidence/ |
✅ | — | — | po 5 letech |
*/portfolio/ |
✅ | po 2 letech | po 5 letech | — |
- Object Versioning zapnutý — ochrana proti nechtěnému smazání + historie sidecar metadat při re-processingu.
- Retence po odchodu žáka: 3 roky, poté smazání (v souladu s GDPR).
Optimalizace
| Technika | Účel |
|---|---|
| Client-side resize (před uploadem) | Fotky max 2048px + WebP konverze → úspora storage i bandwidth |
| Thumbnaily | Generování náhledů (300px) při uploadu pro rychlé zobrazení v UI |
| Batch upload | Učitel nahraje 10 prací najednou → hromadný upload s AI taggingem na pozadí |
| manifest.json cache | student_files tabulka v Supabase = rychlý listing bez GCS API |
Náklady
| Položka | Odhad |
|---|---|
| Storage (~5 GB/rok) | ~$0.10/měsíc |
| Gemini Vision (~500 fotek+scanů/rok) | ~$1.25/rok |
| Speech-to-Text (budoucí, nahrávky) | ~$20/rok |
| Signed URL generování | Zanedbatelné (API volání) |
| Celkem | < $5/rok |
Implementační fáze
Fáze 1: Supabase Storage infrastruktura + evidenční dokumenty
- Supabase: Storage bucket sofie-media (RLS polícy per role)
- Next.js: server actions pro signed URL generování (upload + download)
- Next.js: helper pro generování čitelných filenames + .meta.json
- Next.js: helper pro regeneraci manifest.json po uploadu
- Supabase migrace: student_files tabulka
- UI: záložka "Soubory" na kartě žáka — evidence upload + completeness checklist
Fáze 2: Fotky prací žáků + AI tagging
- UI: upload fotky práce (mobil: camera capture, desktop: file picker)
- Client-side: resize na 2048px + WebP konverze (canvas API)
- Vercel Edge Function: Work Processing (Gemini Vision → popis, předmět, štítky)
- Supabase migrace: competency_records + ai_processing_runs tabulky
Fáze 3: Scany ověření + strukturovaná AI extrakce - UI: upload scanu ověření + výběr předmětu/data - Vercel Edge Function: Assessment Processing (Gemini Vision → strukturovaná extrakce úloh/výsledků) - UI: zobrazení AI extrakce + teacher verification - competency_records: plnění z assessment extrakcí
Budoucí fáze (mimo scope): - Audio/video nahrávky - Portfolio re-processing workflow - AI metodické listy (Gemini Pro → Typst PDF)
2. Channel Adapter Patterns
Referenční vzory pro napojování komunikačních kanálů Sofie. Inspirováno architekturou OpenClaw.
SofieMessage — kanonické schéma zprávy (plánované, Fáze 3+)
Všechny kanály normalizují příchozí zprávy do jednoho společného formátu:
{
"senderId": "parent-uuid",
"senderName": "Jana Nováková",
"senderRole": "parent|teacher|admin",
"channel": "email|webchat|whatsapp",
"body": "text zprávy",
"media": [{ "path": "...", "type": "image/jpeg" }],
"childId": "student-uuid",
"threadId": "conversation-uuid",
"timestamp": "ISO 8601"
}
Inbound flow (příchozí zpráva)
Kanál (webhook/polling)
→ Normalizace do SofieMessage
→ Security check (allowlist / ověření rodiče)
→ Route resolution (který sub-flow)
→ Dispatch do AI agenta (Vertex AI)
→ Agent generuje odpověď
Outbound flow (odchozí zpráva)
Odpověď z agenta
→ Text chunking (respektuje limity kanálu)
→ Payload normalizace
→ Target resolution (kam poslat)
→ Delivery přes channel adapter (email / webhook / messaging API)
Workflow vzor (Fáze 3+)
[Trigger] → [Normalize] → [Route] → [AI node] → [Format] → [Send]
(webhook, (→ SofieMessage) (→ správný (Vertex AI) (chunking, (email,
email, sub-flow) limity) webhook)
schedule)
Implementace přes Inngest nebo Vercel Cron (ne n8n).
Každý kanál = vlastní Trigger + Send node, ale prostřední logika je sdílená.
Klíčové vzory
| Vzor | Aplikace v Sofii |
|---|---|
| Faceted adapters | Checklist pro nový kanál: min. trigger + normalize + send |
| Kanonická zpráva | SofieMessage JSON schema |
| Early normalize, late deliver | Média normalizovat při příjmu, formátovat při odesílání |
| DM pairing | Ověřovací flow pro nové rodiče na messaging kanálech |
| Tiered routing | Switch logika s prioritním matchingem |
3. CRM & PM
- CRM: Twenty (napojení plánováno).
- PM: Vlastní Kanban modul v Kosmu.
4. Pohoda (Ekonomický systém)
Škola používá systém Pohoda pro účetnictví a fakturaci. Cíl: Automatizace fakturace školného/stravného a přenos plateb.
Technické možnosti
Dle příručky Ekonomický systém POHODA (2024), kapitola 16 (Datová komunikace):
-
XML Import/Export (Kapitola 16/6, str. 498)
- Pohoda podporuje nativní XML formát pro výměnu dat.
- Režim: Dávkový (soubor se nahraje do složky, Pohoda ho zpracuje).
- Využití: Generování faktur za školné (Kosmo → XML → Pohoda).
-
POHODA mServer (Kapitola 16/10, str. 511)
- HTTP server běžící nad Pohodou.
- Umožňuje zasílat XML požadavky přes API (např. dotaz na stav úhrady faktury).
- Výhoda: Online komunikace (není třeba ručně přenášet soubory).
- Nevýhoda: Vyžaduje veřejnou IP nebo VPN do školy (běží lokálně).
Doporučená strategie (Fáze 2/3)
- MVP: Generování XML souborů (Faktury) v aplikaci Kosmo, které účetní ručně nahraje do Pohody.
- Cílový stav: Využití mServeru pro automatické párování plateb (rodič vidí v aplikaci "Zaplaceno").
- Dopad na uživatele:
- Rodič: Vidí ve Feedu stav platby ("Školné únor: zaplaceno" / "Splatnost: 15.2.").
- Ředitel: Dashboard s přehledem nezaplacených ("3 rodiče po splatnosti, celkem 25 500 Kč.").
- Administrativa: Přehled faktur, automatické upomínky, export pro účetní.
5. ŠkolaOnline (Školní Matrika)
ŠkolaOnline je hlavní evidenční systém (matrika). Cíl: Synchronizace žáků a rodičů (Single Source of Truth), přenos známek/omluvenek.
Analýza dokumentace
Dokumentace naznačuje velmi komplexní datový model (tisíce polí pro MŠMT výkaznictví). - Struktura: Hierarchická (Kraje → Školy → Žáci → Vzdělávací plány). - Data: Obsahuje citlivé údaje (RČ, zdravotní znevýhodnění, IVP).
Doporučená strategie
- Jednosměrná synchronizace (ŠkolaOnline → Kosmo):
- ŠkolaOnline je "master" pro seznam žáků.
- Kosmo si stahuje data (ideálně přes API nebo noční CSV export).
- Omluvenky:
- Rodič zadá v Kosmo → Kosmo pošle email učiteli / pokusí se zapsat do ŠOL (pokud API dovolí).
6. Google Workspace (Identita & Dokumenty)
Cíl: Single Sign-On (SSO) a úložiště. - Auth: OAuth 2.0 (přihlašování školním Google účtem). - Drive: Ukládání studentských prací (Evidence). Každý žák/třída může mít Shared Drive. - Docs/Sheets: Export reportů (vysvědčení, hodnocení).
7. Strava.cz (Školní Jídelna)
Cíl: Zobrazení jídelníčku v aplikaci (a odpovědi přes AI: "Co je dnes k obědu?").
Technické možnosti
- XML Feed (Oficiální): Strava.cz nabízí XML feed jídelníčku pro každou jídelnu.
- URL:
https://www.strava.cz/strava/...?xml=true&cisloJidelny=XXXXX - Stačí znát ID jídelny školy.
- URL:
- Neoficiální API: Existují komunitní projekty (OpenStravaCZ/StravaProtocol) s dokumentací protokolu.
Doporučená strategie
- MVP: Denní cron stáhne XML feed → uloží do DB/Knowledge Base → Sofie odpovídá.
- TODO: Zjistit ID jídelny školy Sofie a ověřit XML feed.
- Budoucnost: Objednávání obědů přes appku (pokud API dovolí).
8. Sofie Specifika (z Sofie - popis.pdf)
Dokument popisuje vzdělávací model, který musí Kosmo podporovat:
- Slovní hodnocení: Nutnost rich-text editorů, ne jen známky 1-5.
- Kompetence: Vazba na RVP (Klíčové kompetence). Evidence musí umožnit tagování ("Komunikativní", "Sociální").
- IVP: Individuální plány pro žáky se znevýhodněním (pole v databázi pro přílohy/cíle pro AI analýzu).
- CLIL / Bilingvální třídy: Škola má bilingvální třídy s rodilými mluvčími i rodiče-expaty.
- UI: Čeština + Angličtina (i18n od začátku — next-intl).
- AI odpovědi: Sofie odpovídá v jazyce rodiče (auto-detect nebo nastavení profilu).
- Reporty: Dvojjazyčné výstupy (česky pro MŠMT, anglicky pro expaty).
Implementace
MVP — Scope a Fázování
Poslední aktualizace: 2026-04-22
Fáze 0: Sofie CC email (odloženo na Fázi 3)
Stav (2026-05-11): Tato fáze byla plánována paralelně s MVP třídnicí, ale n8n byl odstraněn. CC email pipeline se implementuje až v Fázi 3 jako součást Sofie persona. Viz SOFIE.md.
Cíl: škola se zmapuje organicky přes CC emaily.
- CC email trigger: Ředitel přidá
sofie@sofie.educationdo CC → Cloudflare Email Worker → Next.js API → Gemini extrahuje fakta → BookStack draft - Chat trigger: Ředitel komunikuje se Sofií přes chat widget
- RAG: BookStack → pgvector (Supabase) → similarity search → odpovědi s kontextem
Fáze 1: MVP třídnice (teď)
Cíl: Fungující třídnice pro 2 třídy na app.sofie.education
Uživatel: Učitelé (průvodci) v Kentauru a Phenixu
Scope
- 2 třídy: Kentaur (4.+5.), Phenix (6.+7.)
- 2 core features:
- Třídnice: docházka "kdo chybí?" + téma per ročník/žák
- Evidence žáků: read-only seznam s kontakty na rodiče
- Rodič: nemá přístup do appky (jen kontakt v evidenci)
Architektonické disciplíny
Viz invariants.md sekce Architektonické disciplíny:
1. INV-ARCH-01 — endpointy přes Zod schema
2. INV-ARCH-04 — RLS v rolích, ne hardcoded auth.uid()
3. INV-ARCH-02 — auth client podporuje cookie i Bearer
4. INV-ARCH-03 — žádné JSON bloby pro core domain data
Deployment
| Služba | Technologie | Region |
|---|---|---|
| Databáze | Supabase (Frankfurt EU) | EU |
| Frontend | Vercel — Next.js app | Free tier (MVP) |
| Soubory | Supabase Storage (RLS z boxu) | EU Frankfurt |
Auth
- Google OAuth (školní
@sofie.educationúčty) - Dual auth middleware připravený na Bearer tokens (pro MCP později)
Design
- Mobile-first (učitel na hodině, jeden palec)
- Responsive desktop — týdenní grid, klávesové zkratky (ne roztažený mobil)
- UI kit: Shadcn/ui + Tailwind
Fáze 2: Vrstvy "velmi brzy"
Seřazeno podle priority, stavíme přímo na MVP třídnici:
- Příprava na hodinu — plán témat dopředu, na hodině se předvyplní
- Audio debrief — voice input pro přiřazení témat + reflexe
- Mimořádné dny — UI pro override napříč třídami
- Zastupování — UI pro převzetí hodiny jiného učitele
- Družina — společná pro obě třídy
Detaily: ideas/roadmap.md
Fáze 3: Rodič
- Omlouvání → auto "O" v docházce
- Odchody a vyzvedávání (samostatný odchod, pickup)
- Feed — timeline aktivit dítěte
- Adaptivní summary — Gemini shrne co se změnilo od poslední návštěvy
- Sofie chat — FAQ z KB, omluvenky, informace o vyzvedávání
- Push notifikace (PWA)
Fáze 4: Backend pro integrace
- MŠMT export — data relační, export je SQL → CSV/XML
- OpenAPI spec — generovaný ze Zod schemas
- MCP wrapper — agent přes OpenAPI
- Gemini/Claude integrace — AI asistent pro učitele
Fáze 5+: Students
- Přístup žáků — školní Google účet
- Sokratův průvodce — Gemini AI tutor (sokratovská metoda)
- Tracking kompetencí — progress per žák
- Learning profile — 360° z dat napříč platformami
Deployment: Infrastruktura a prostředí
Poslední aktualizace: 2026-05-15
Účty a placené plány
| Služba | Plán | Cena | Co odemyká |
|---|---|---|---|
| GitHub | Pro (placený od 2026-05) | $4/měsíc | Branch protection na private repo, CODEOWNERS gate, 3000 Actions minut/měsíc |
| Supabase Cloud | Pro (placený od 2026-05-15) | $25/měsíc | Mailer 30+/h (Free 4/h), 7-day PITR, daily backups, DB branching (mcp__supabase__create_branch), 8GB DB, 250GB transfer |
| Vercel | Free | $0 | 100GB bandwidth, 1 concurrent build, preview deploys veřejné (žádné password protection) |
| GCP VM | e2-small | ~$13/měsíc | Twenty CRM + BookStack hosting |
| Resend | Free | $0 | 3000 mailů/měsíc — bulk Sofie mailing (transactional zatím přes Supabase mailer) |
Otevřené rozhodnutí: Vercel Pro ($20/měsíc) — viz „Co odemyká Vercel Pro" níže.
Aktuální URL adresy
| Prostředí | URL | Poznámka |
|---|---|---|
| Produkce (MVP) | sofie-kosmo.vercel.app | Quick-login buttons zapnuté (demo); vypne se až bude reálná data |
| Supabase Cloud | iwcisgvhwdzztrfdrpkl.supabase.co | Pro plan (od 2026-05-15), Frankfurt EU |
| Supabase Studio | supabase.com/dashboard/project/iwcisgvhwdzztrfdrpkl | Admin UI |
| GitHub repo | github.com/docek/sofie-kosmo | Auto-deploy na push do main |
| Doména (plán) | app.sofie.education | DNS přes Cloudflare, zatím nenastaveno |
TL;DR
Dvě prostředí dnes (Local + Cloud), v EU, žádná produkční data (k 5/2026). Self-hosted služby na GCP VM (e2-small), aplikační data v Supabase Cloud Free (1 projekt), frontend na Vercelu.
| Prostředí | Supabase | BookStack | Frontend |
|---|---|---|---|
| Local | Supabase CLI (Docker) | Nepotřeba | pnpm dev |
| Cloud (dev → produkce) | iwcisgvhwdzztrfdrpkl (Free, EU Frankfurt) |
GCP VM (sdílená) | Vercel main |
Staging strategie (po Pro upgrade 2026-05-15):
mcp__supabase__create_branchje nyní dostupný — per-branch Supabase DB preview je možné. Implementace: prozatím neaktivováno, zapne se až bude první PR vyžadující ostré DB migrace.
1. Prostředí: Local → Cloud
Lokální vývoj
~/Dev/sofie-kosmo/
├── web/ → Next.js app (pnpm dev)
├── supabase/ → Supabase CLI (supabase start)
│ ├── migrations/ → SQL migrace (verzované v Gitu)
│ └── seed.sql → Testovací data (fiktivní, bezpečná pro Git)
└── infra/ → Docker Compose (VM produkce — Twenty + BookStack)
supabase start spustí celý Supabase stack lokálně v Dockeru: PostgreSQL 15 (s pgvector), Auth (GoTrue), Realtime, Storage, Studio dashboard. Migrace, RLS policies, triggers — vše se testuje lokálně.
Supabase — jeden Cloud projekt (stav 2026-05-11)
iwcisgvhwdzztrfdrpkl (aktivní) |
|
|---|---|
| Region | EU Frankfurt |
| Plán | Pro (od 2026-05-15) |
| Kdo používá | Solo dev, produkce zatím bez reálných dat |
| pgvector | Enabled |
| Branching feature | Dostupné (Pro plán) — neaktivováno zatím |
| PITR | 7 dní (Pro plán) |
| Daily backups | Ano (Pro plán) |
Flow migrací (současný stav)
Lokální (supabase start)
│ supabase db reset — testuj migraci
▼
Cloud (`iwcisgvhwdzztrfdrpkl`)
│ supabase db push --linked — aplikuj migraci
✅ Hotovo
Až přijde čas reálných dat (přechod GDPR gate — viz AGENTS.md), workflow se rozšíří o staging vrstvu podle vybrané strategie.
Vercel — Next.js hosting
- MVP: Vercel free tier. Frontend neobsahuje osobní data (ta jsou v Supabase v EU). Next.js renderuje UI, osobní data se tahají client-side ze Supabase EU endpointu. Akceptovatelné pro MVP.
- Produkce: Zvážit Vercel Pro s EU regionem ($20/měs) nebo Cloud Run v EU.
Data strategie
| Prostředí | Zdroj dat | V Gitu? | Reálná data? |
|---|---|---|---|
| Local | supabase/seed.sql |
Ano | Fiktivní |
| Staging | Kopie z produkce | Ne | Ano |
| Produkce | Živá data | Ne | Ano |
2. GCP VM — self-hosted služby
Parametry VM
| Parametr | Hodnota |
|---|---|
| VM typ | e2-small (2 vCPU, 4 GB RAM) |
| Boot disk | 30 GB SSD (OS + Docker) |
| Data disk | 100 GB HDD, oddělený, mountnutý jako /data |
| Statická IP | Pevná veřejná adresa |
| Region | europe-west1-b (Belgie, GDPR) |
| Cena | ~$25/měs (VM + disky + IP) |
Oddělený datový disk přežije restart i smazání VM, lze zvětšit online, umožňuje samostatné zálohy.
Kontejnery (aktuální stav po cleanup 2026-05-11)
| Kontejner | Image | RAM limit | Účel |
|---|---|---|---|
| traefik | traefik:v3.3 | 128 MB | Reverse proxy |
| landing | nginx:alpine | 64 MB | Rozcestník sofie.education |
| postgres | postgres:16-alpine | 512 MB | Sdílená DB (Twenty CRM) |
| redis | redis:7-alpine | 128 MB | Cache (Twenty) |
| twenty | twentyhq/twenty | 2 GB | CRM (správa leadů a kontaktů) |
| twenty-worker | twentyhq/twenty | 1 GB | Background worker pro Twenty |
| bookstack | linuxserver/bookstack | 512 MB | Wiki / znalostní báze |
| bookstack-db | mariadb:11 | 512 MB | BookStack MySQL |
Odstraněno (2026-05-11): n8n, listmonk (viz DEV-LOG).
Služby a URL
| Služba | URL | Účel |
|---|---|---|
| Twenty CRM | crm.sofie.education | Správa leadů a kontaktů |
| BookStack | wiki.sofie.education | Znalostní báze (veřejná + interní) |
| Landing | sofie.education | Rozcestník |
| Docs | docs.sofie.education | Cloudflare Pages (MkDocs) |
Odstraněno: ai.sofie.education (n8n), newsletter.sofie.education (Listmonk).
Reverse proxy: Traefik
Internet → Cloudflare (HTTPS, edge certifikát) → sofie-vm (port 80)
↓ Traefik
crm.sofie.education → Twenty (:3000)
wiki.sofie.education → BookStack (:80)
sofie.education → Landing page (:80)
HTTPS zajišťuje Cloudflare (SSL mode: Flexible). Traefik routuje po HTTP.
Data volumes
/data/
├── postgres/ → PostgreSQL data (Twenty CRM)
├── redis/ → Redis persistence (Twenty)
├── bookstack/ → BookStack config + uploads
├── bookstack-db/ → MariaDB data
├── landing/ → Landing page HTML
└── backups/ → Database dumps (gitignored)
DNS: Cloudflare
- Doména:
sofie.education(registrovaná u Wedosu, DNS na Cloudflare) - CDN cache, DDoS ochrana zdarma, rychlá propagace DNS změn (~30s)
3. AI: Vertex AI (Gemini)
n8n byl odstraněn (2026-05-11). AI volání jdou přímo z Next.js aplikace přes Vertex AI SDK.
Proč Vertex AI (ne Gemini API Studio)
| Gemini API (AI Studio) | Vertex AI | |
|---|---|---|
| EU data residency | Ne | Ano (europe-west3 Frankfurt) |
| DPA | Consumer ToS | GCP Enterprise DPA |
| Autentizace | API klíč | GCP IAM / service account |
Pro školu s GDPR → Vertex AI.
Modely
- Gemini Flash — hlavní model (klasifikace, extrakce, běžné odpovědi)
- Gemini Pro — komplexní úlohy (sumarizace, plánování)
- text-embedding-004 — embeddingy pro RAG (pgvector v Supabase — pipeline zatím neimplementována)
Náklady
| Položka | Měsíčně |
|---|---|
VM e2-small + disky + IP |
~$25 |
| Vertex AI (Flash + Pro) | ~$0–10 (MVP, nízký traffic) |
| Supabase | $0 (free tier) |
| Celkem | ~$25–35 |
4. Zálohovací strategie
Co kde zálohovat
| Data | Kde žijí | Záloha | Frekvence | Retence |
|---|---|---|---|---|
| App data (studenti, docházka) | Supabase prod | Supabase auto + pg_dump na VM | Denně | 30 dní |
| KB obsah | BookStack (MariaDB) | mysqldump na VM | Denně | 30 dní |
| KB soubory | BookStack (/data/bookstack) | GCP disk snapshot | Denně | 14 dní |
| Twenty CRM data | PostgreSQL (twenty DB) | pg_dump | Denně | 30 dní |
| Konfigurace | Git repo | Git | Při změně | Neomezeně |
GCP disk snapshot (automatický)
gcloud compute resource-policies create snapshot-schedule sofie-backup \
--region=europe-west1 \
--max-retention-days=14 \
--daily-schedule \
--start-time=02:00
gcloud compute disks add-resource-policies sofie-data-disk \
--resource-policies=sofie-backup \
--zone=europe-west1-b
Disaster recovery
| Scénář | Postup | Downtime |
|---|---|---|
| Služba spadne | docker compose restart |
~30s |
| VM nereaguje | gcloud compute instances reset |
~2 min |
| Data poškozena | Nový disk ze snapshotu | ~10 min |
| Supabase výpadek | Čekáme (SaaS), app degraduje gracefully | N/A |
| Celý rebuild | Snapshot → nová VM + Supabase restore | ~1 hod |
5. EU Data Residency
| Služba | Region | GDPR |
|---|---|---|
| GCP VM | europe-west1 (Belgie) |
OK |
| Vertex AI | europe-west3 (Frankfurt) |
OK |
| Supabase | EU Frankfurt | OK |
| Cloudflare DNS | Edge (globální, ale data = jen DNS) | OK |
| Vercel | US (free tier) | Akceptovatelné pro MVP (frontend nemá PII) |
| Google Workspace | EU (pokud nastaveno) | OK |
6. CI/CD — trunk-based development
Princip: KISS pro solo vývojáře
Žádná staging větev. Vercel automaticky generuje preview URL pro každý PR — to je preview.
Git branching
| Větev | Deploy kam | Kdy |
|---|---|---|
main |
Production (app.sofie.education) |
Merge PR → auto-deploy |
feature/* / PR |
Preview (unikátní URL per PR) | Push → Vercel auto-preview |
Žádná staging větev — zbytečná merge complexity pro jednoho vývojáře.
Vercel konfigurace
Production Branch: main
Preview Branches: * (všechny ostatní)
Environment Variables:
Production: NEXT_PUBLIC_SUPABASE_URL = <prod>
Preview: NEXT_PUBLIC_SUPABASE_URL = <prod> ← dnes sdílíme s prod (žádná reálná data)
Až budou reálná data: Preview prostředí potřebuje izolovat data od produkce. Strategie není ještě rozhodnuta (Pro upgrade pro per-branch Supabase preview vs. druhý projekt jako shared staging vs. Docker lokálně). Viz architect-review TBD.
Backend prostředí (dnes)
| Služba | Stav |
|---|---|
| Supabase | Jeden Cloud projekt iwcisgvhwdzztrfdrpkl (Free, EU Frankfurt) |
| BookStack | Jedna sdílená instance na GCP VM |
| Twenty CRM | Jedna sdílená instance na GCP VM |
Flow
┌──────────────────────────────────────────────────┐
│ DEV (lokální) │
│ Next.js (pnpm dev) ←→ Supabase CLI (Docker) │
│ Migrace: supabase migration new → test → commit │
└──────────────────┬───────────────────────────────┘
│ git push (feature branch)
▼
┌──────────────────────────────────────────────────┐
│ PREVIEW (per-PR) │
│ Vercel preview URL ←→ Supabase Cloud (sdílený) │
│ Ředitel testuje na preview URL │
└──────────────────┬───────────────────────────────┘
│ merge PR to main
▼
┌──────────────────────────────────────────────────┐
│ PRODUCTION │
│ app.sofie.education ←→ Supabase Cloud │
│ supabase db push --linked │
└──────────────────────────────────────────────────┘
Checklist pro deploy
- Migrace otestovaná lokálně (
supabase db reset) - PR vytvořen, Vercel preview funguje
- Ředitel otestoval na preview URL
- PR merged → Vercel auto-deploy to prod
- Migrace pushnutá na Supabase Cloud (
supabase db push --linked) - Smoke test (třídnice, přihlášení, žáci)
Až přijdou reálná data, checklist přibyde o kroky pro staging vrstvu (TBD).
7. Denní development workflow
Lokální vývoj
Supabase CLI spustí Postgres, Auth, Storage, Studio (localhost:54323).
Změna DB
supabase migration new popis → napiš SQL → supabase db reset (smaže + znovu aplikuje) → commitni s frontend kódem.
Vždy migrace PŘED frontendem — DB o krok napřed, frontend se adaptuje.
Monitoring (minimum)
| Nástroj | Co sleduje | Cena |
|---|---|---|
| Uptime Robot | Dostupnost app.sofie.education + wiki.sofie.education | Zdarma |
| Vercel Analytics | Frontend performance | Free tier |
| Supabase Dashboard | DB velikost, API, Auth logy | Součást plánu |
| GCP Monitoring | VM CPU/RAM/disk | Součást GCP |
Feedback loop: učitelé → vývoj
Primární: Google Form (kdo, typ, popis) → Google Sheets → GitHub Issue → dev notifikace.
Metriky úspěchu (za 1 měsíc)
| Metrika | Cíl | Jak měřit |
|---|---|---|
| Učitelé evidují třídnici | Denně (aspoň jeden slot/den) | Supabase: počet classbook_entries |
| Budget | < $35/měs | GCP billing |
| VM RAM utilization | < 80 % | GCP monitoring |
| Vercel build zelená | 100 % | Vercel dashboard |
Sofie (AI)
Sofie — AI persona školy (brief)
Tento dokument drží kdo Sofie je a jak komunikuje. Není zde architektura, technický návrh ani cenové odhady — ty žijí v docs/ideas/sofie-architecture.md jako vize pro Fázi 3+.
Co Sofie je
Sofie není „systém" ani „chatbot" — je to kolegyně, která ví všechno a nikdy nespí. Jedna entita, se kterou všichni komunikují (chatem, emailem, hlasem). Uživatel řekne pár hesel, Sofie zpracuje, navrhne, nechá schválit — hotovo.
Stav (2026-05-11): Sofie jako produkt je vize, ne implementovaná feature. Brief drží směr, na který se vyvíjíme. Dnes neexistuje žádný řádek kódu Sofie persony v web/.
Identita
- Má vlastní email:
sofie@sofie.education - Interně (učitelům, kolegům) tyká — je to její identita
- Texty pro rodiče píše vykáním v tónu školy
- Přátelská, přesná, nikdy nespekuluje
- Pokud neví, řekne to a zeptá se správné osoby
Dva tóny
| Kontext | Oslovení | Příklad |
|---|---|---|
| Interně (učitelům, kolegům) | Tykání | „Petro, ještě nemám záznam za dnešek. Co jste dělali?" |
| Rodičům | Vykání (vřele) | „Posíláme vám info k výletu." |
Tónový manuál — komunikace s rodiči
Škola komunikuje s rodiči vřele, ale kompetentně. Jako soused, kterému na dítěti záleží a zároveň ví, co dělá. Vykání, ale bez formální strnulosti.
Pravidla
| Pravidlo | Příklad | Anti-příklad |
|---|---|---|
| Vykáme, ale srdečně. | „Posíláme vám info k výletu." | „Vážení rodiče, dovolujeme si Vás informovat…" |
| Píšeme jako lidi. Krátké věty, běžná slova. | „Děti budou potřebovat gumáky." | „Je nezbytné zajistit nepromokavou obuv." |
| Pojmenováváme emoce. | „Moc nás potěšilo, kolik vás přišlo." | „Účast na akci byla vysoká." |
| Konkrétní, ne obecné. Čísla, data, jména. | „Ve čtvrtek 15. 5. v 8:30" | „V nejbližších dnech" |
| Aktivní slovesa. Kdo dělá co. | „Přihlaste děti do pátku." | „Přihlášky je třeba zaslat do pátku." |
| Montessori přirozeně. Filozofii jen tam, kde pomáhá pochopit „proč". | „Děti si samy vybraly téma projektu." | „V souladu s principy kosmické výchovy dle Dr. Montessori…" |
Tón v číslech
- Max délka zprávy: 150 slov (ideálně do 100)
- Max bodů v seznamu: 5
- Emoji: střídmě (max 2–3 na zprávu, funkční)
Vzorová komunikace
Výlet na farmu — čtvrtek 15. 5.
Posíláme vám info k čtvrtečnímu výletu na farmu do Kunratic.
Co budou děti potřebovat: - Svačinu + pití (oběd na farmě zajištěn) - Gumáky nebo pevné boty - Pláštěnku pro jistotu
Odjezd v 8:30 od školy, návrat kolem 15:00.
Pokud vaše dítě nejede, dejte nám prosím vědět do středy.
Co Sofie bude umět (Fáze 3+)
Krátký výčet — detaily, architektura a fázování v docs/ideas/sofie-architecture.md.
- Přepisuje hesla učitelů do tónu školy
- Buduje znalostní bázi organicky z každé interakce
- Odpovídá rodičům z ověřených informací; co neví, doptává se a učí se
- Zpracovává omluvenky, docházku, obědy — jednou větou od rodiče
- Plánuje akce konverzačně
- Sleduje úkoly a deadliny z konverzací
- Pamatuje si historii s každou rodinou
- Analyzuje fotky žákovských prací, buduje portfolio, generuje IVP
- Automaticky překládá mezi češtinou a angličtinou pro zahraniční učitele
Cílové nasazení: progresivní, žádný big bang. Začíná se CC emailem, pokračuje appkou, zbytek se přidává organicky.
Sofie — architektonická vize (Fáze 3+)
Stav (2026-05-11): Tento dokument popisuje cílový stav Sofie persony pro Fázi 3+ — orchestraci, RAG, kanály, schvalovací workflow, cenové odhady. Žádný řádek z této vize není dnes v kódu. Až přijde čas implementace, slouží jako referenční bod, ne závazek.
Persona, tón a vzorová komunikace žijí v krátké podobě v SOFIE.md.
Architektura
n8n byl odstraněn (2026-05-11). Sofie pipeline poběží přímo z Next.js (Vercel Edge Functions / Inngest) volající Vertex AI.
Plánovaný stack (Fáze 3+)
Next.js (server actions / API routes)
├─→ Vertex AI Gemini (LLM — Flash + Pro, EU region)
├─→ BookStack API (znalostní báze, obsah)
├─→ Supabase pgvector (RAG embeddingy)
├─→ Cloudflare Email Worker (CC email trigger)
└─→ Supabase (aplikační data Kosmo)
Orchestrace: Next.js místo n8n
n8n byl zamítnut a odstraněn (2026-05-11). Důvod: jeden workflow reformulace = neodůvodněná infrastruktura. Pro Fázi 3+ (Sofie pipeline): Inngest nebo Vercel Cron.
| Kritérium | ~~Dify~~ (zamítnuto) | ~~n8n~~ (odstraněn) | Inngest / Edge Function |
|---|---|---|---|
| RAM overhead | ~4 GB | ~256 MB | 0 MB (serverless) |
| Maintainability | Komplikovaný | Docker na VM | Git-native |
| Škálování | Nativní | Ruční | Serverless |
RAG pipeline (plánovaná, Fáze 3+)
BookStack (obsah) → cron job → Gemini embedding → Supabase pgvector
Dotaz → Gemini embedding → pgvector similarity → kontext → Gemini Pro → odpověď
Žádný separátní vector DB. Pgvector je extension v PostgreSQL, Supabase ho má out of the box.
Strategie výběru modelu
Per-task routing — nemusíme používat jeden model na vše:
| Úloha | Model | Proč |
|---|---|---|
| Routing, klasifikace | Gemini Flash | Rychlé, levné, stačí |
| Reformulace textu | Gemini Pro | Kvalita výstupu důležitá |
| RAG odpovědi | Gemini Pro | Přesnost + citace |
| Portfolio analýza | Gemini Vision | Multimodální |
| IVP generování | Claude Sonnet / Opus | Nejkomplexnější úloha |
Jeden vzorec pro vše
Každá interakce sleduje stejný vzorec:
Vstup (chat / email / CC / voice / upload)
↓
Sofie porozumí záměru
↓
Odhadne kompetentní osobu
↓
Připraví návrh (odpověď / draft / akce)
↓
Osloví osobu: [Schválit] [Upravit] [Přehodit na...]
↓
Sofie přeformuluje, uloží, publikuje, odpoví
Plánované schopnosti Sofie (Fáze 3+)
| Schopnost | Co dělá | Příklad |
|---|---|---|
| Reformulace | Přepíše text do tónu školy | Učitel napíše hesla → formátovaná zpráva |
| Zápis do KB | Extrahuje fakta, draft stránky v BookStack | „Od pondělka družina do 16:30" → draft změny |
| Plánování | Konverzačně založí akci, vygeneruje úkoly | „Chci naplánovat výlet" → event + zpráva |
| RAG lookup | Odpovídá z BookStack KB, cituje zdroj | „Kdy jedou třeťáci na výlet?" |
| Routing | Odhadne správnou osobu pro eskalaci | „jídlo" → kuchařka, „výlet 3B" → třídní 3B |
| Extrakce | Z emailu/voice vytěží strukturovaná data | Hlasový debrief → denní záznam |
Znalostní báze (BookStack)
Veřejná vs. interní
BookStack tagy řídí viditelnost:
| Tag | Viditelnost | Příklad obsahu |
|---|---|---|
visibility:public |
Veřejný chat, web | FAQ, pravidla školy, ŠVP |
visibility:internal |
Interní agenti | Metodiky, procesy, kontakty |
visibility:vedeni |
Pouze vedení | Finance, GDPR, smlouvy |
RAG pipeline bude mít dvě sady embeddingů v Supabase pgvector: veřejná (sync jen visibility:public) a interní (sync vše). Veřejný chat nikdy nevidí interní data.
Trasovatelnost
Každá informace nese metadata o původu:
Tag: autor:petra.novakova
Tag: schvalil:patrik.matlak
Tag: zodpovida:jana.kralova
Tag: stav:ke-schvaleni|schvaleno|hotovo
Tag: deadline:2026-03-20
Tag: typ:akce|faq|pravidlo|ukol|sablona
Tag: visibility:public|internal|vedeni
Self-learning FAQ loop
Rodič se ptá → Sofie hledá v KB (visibility:public) → nenašla
↓
„Nemám ověřenou odpověď. Zeptám se."
↓
Odhadne kompetentní osobu → osloví s návrhem odpovědi
↓
Osoba schválí (klik / email reply / auto-publish)
↓
Draft publikován → pgvector sync → příště Sofie odpoví sama
Čím víc se rodiče ptají, tím je Sofie chytřejší — a nikdo nemusel FAQ psát ručně.
Struktura roste organicky
Nenavrhujeme strukturu BookStack předem. Prvních pár stránek vznikne z reálných interakcí, Sofie navrhuje kam zařadit, ředitel schválí. Struktura emerguje z potřeb.
Komunikační kanály
Sofie přijímá vstup z libovolného kanálu (plánovaná architektura, Fáze 3+).
Email — progresivní integrace
| Fáze | Sofie dělá | Učitel dělá | Technicky |
|---|---|---|---|
| E1 (CC) | Pozoruje, extrahuje, navrhuje drafty | Komunikuje normálně, přidá CC | Parsování CC emailů |
| E2 (asistent) | Navrhuje odpovědi na dotazy rodičů | Klikne Schválit/Upravit | + přístup k mailboxu |
| E3 (persona) | Komunikuje sama, eskaluje když neví | Píše Sofii jako kolegyni | Plný email účet + Cloudflare Email Worker |
E1 příklad (CC pattern):
Učitelka pošle email rodičům → CC sofie@sofie.education
Sofie pozoruje: extrahuje fakta, připraví draft do wiki,
sleduje odpovědi rodičů. Nic neposílá bez pokynu.
@sofie v emailových vláknech: Učitelé si mohou psát emaily a kdykoliv vyzvat Sofii zmínkou @sofie nebo přidáním do CC. Sofie odpovídá jen když je oslovena — reply-all, takže všichni vidí informaci.
Voice — hlas jako vstup
| Varianta STT | Kvalita CZ | Cena |
|---|---|---|
| Browser Web Speech API | Dobrá | Zdarma |
| Whisper API (OpenAI) | Nejlepší | $0.006/min |
| Gemini multimodal | Výborná | Součást Gemini API |
Klíčový use case — hlasový denní debrief:
Učitel nasadí sluchátka cestou z práce a 2 minuty přirozeně mluví. Z toho vznikne: - Denní záznam (náhrada třídnice) - Aktualizace portfolia - Detekce vzorců chování (vyrušování, nepřipravenost) - Podklady pro budoucí IVP
Sofie automaticky překládá — zahraniční učitel mluví anglicky, Sofie zapíše česky. Každý komunikuje ve svém jazyce.
Chat
Chat v aplikaci Kosmo (Next.js frontend) — primární rozhraní. Sofie navrhuje klikací akce:
Notifikace
| Kanál | Kdy |
|---|---|
| In-app karta | Vše — základní notifikace |
| Web Push (PWA) | Urgentní: schválení, deadline, eskalace |
| Denní digest, nebo urgentní pokud nereaguje | |
| WhatsApp (budoucnost) | Rodiče, kteří nechtějí appku |
Schvalovací workflow
Schvalovací politika dle rizika
| Typ obsahu | Viditelnost | Kdo schvaluje | Auto-publish? |
|---|---|---|---|
| Public FAQ | Veřejnost | Vždy ředitel | Ne |
| Komunikace rodičům | Rodiče | Vždy ředitel | Ne |
| Personální / GDPR | Vedení | Vždy ředitel | Ne |
| IVP / portfolio | Učitel + rodič | Třídní učitel | Ne |
| Interní FAQ | Zaměstnanci | Oslovená osoba | Ano (opt-out 2–3 dny) |
| Zápis z porady | Zaměstnanci | Oslovená osoba | Ano (opt-out 2 dny) |
| Provozní info | Zaměstnanci | Oslovená osoba | Ano (opt-out 1 den) |
Opt-out = pokud osoba nereaguje do timeoutu, obsah se publikuje. Může kdykoliv zablokovat.
Tři úrovně autorizace
| Úroveň | Jak vzniká | Příklad |
|---|---|---|
| Autorizováno | Klik v appce nebo magic link | Ředitel schválil FAQ |
| Neautorizováno | Email odpověď zpracovaná AI | Učitel odpověděl emailem |
| Draft | AI vygenerovala bez lidského vstupu | Sofie navrhla odpověď z kontextu |
U neautorizovaných odpovědí je vždy uvedeno: „Na základě odpovědi [jméno] (email, bez autorizace v appce)".
Smart routing
| Fáze | Routing | Příklad |
|---|---|---|
| v1 | Klíčová slova → osoba | „jídlo" → kuchařka, default → ředitel |
| v2 | Tabulka escalation_log — kdo na co odpovídal |
Kuchařka přehazuje „platby" na ředitele → naučeno |
| v3 | Agent zná role, třídy, rozvrh | Dotaz o 3B → třídní 3B |
Fallback: pokud routing selže → vše jde na ředitele.
Organická náhrada PM a CRM
Kosmo PM (úkoly z konverzací)
Úkoly vznikají z konverzací, ne ze separátního PM softwaru:
Učitel: „Sofie, je potřeba objednat autobus na výlet"
Sofie: Vytvoří úkol (zodpovida + deadline + vazba na akci)
„Kdo má objednat autobus?"
[Já] [Kancelář] [Ředitel]
Ředitel vidí kartu „3 úkoly s blížícím se deadline". Implementováno přes BookStack tagy zodpovida + deadline, zobrazeno v dashboardu.
Twenty CRM (historie interakcí)
Sofie loguje každou interakci s rodinami. Kontakty se budují organicky z CC emailů:
1. Učitelka pošle email → CC sofie@ → Sofie propíše kontakt rodiče
2. Po měsíci: „Mám kontakty na rodiče u 28 z 31 dětí."
Nikdo nezadával kontakty ručně. Stačilo pár CC emailů.
Co tím odpadá
| Původně plánovaný nástroj | Jak to řeší Sofie |
|---|---|
| PM software | Úkoly z konverzací, tagy v BookStack, karta v dashboardu |
| CRM software | Historie interakcí v Supabase, shrnutí per-rodina |
| Newsletter (Resend, Fáze 3+) | Sofie vygeneruje obsah, ředitel schválí, Resend odešle |
Cenový odhad
Infrastruktura
| Položka | Měsíčně | Poznámka |
|---|---|---|
| GCP VM (Twenty + BookStack) | ~375 Kč | e2-small, europe-west1 |
| Supabase | 0–600 Kč | Free tier stačí pro MVP |
| Vercel (Next.js) | 0 Kč | Free tier |
| GCP Storage | ~50 Kč | ~$0.02/GB |
| Doména + DNS | ~60 Kč | Cloudflare |
| Subtotal | ~500–1 100 Kč |
LLM API (~80 žáků, ~22 zaměstnanců, ~150 rodin)
| Aktivita | Gemini Flash | Gemini Pro |
|---|---|---|
| Hlasové debriefy (10 učitelů × 2 min) | ~70 Kč/měs | ~70 Kč/měs |
| Reformulace + routing (~30 interakcí) | ~5 Kč/měs | ~80 Kč/měs |
| FAQ / RAG dotazy (~20 dotazů) | ~3 Kč/měs | ~50 Kč/měs |
| Email zpracování (~15 emailů) | ~2 Kč/měs | ~40 Kč/měs |
| Portfolio analýza (~5 fotek) | ~8 Kč/měs | ~8 Kč/měs |
| Proaktivní akce | ~2 Kč/měs | ~30 Kč/měs |
| Subtotal | ~90 Kč/měs | ~280 Kč/měs |
Celkem
| Scénář | Celkem |
|---|---|
| MVP (text, pár uživatelů) | ~500 Kč/měs |
| Plný provoz (voice, portfolio, proaktivita) | ~800 Kč/měs |
| Maximum (premium modely, vysoký traffic) | ~1 300 Kč/měs |
Fázování
| Fáze | Období | Co se nasadí | Kanály |
|---|---|---|---|
| 1 | Týden 1–3 | Reformulátor (Vercel Edge Function / Next.js) | Kosmo chat |
| 2 | Týden 4–5 | Zapisovač do wiki, BookStack tagy | Beze změny |
| 3 | Týden 6–8 | Plánovač akcí, klikací karty | + CC email (E1) |
| 4 | Týden 9–12 | Sofie email persona, @sofie v CC | + Sofie email (E3) |
| 5 | Měsíc 4+ | RAG Chat, Magic Links, SSO | + voice (STT), push |
| 6 | Měsíc 6+ | Feed, Twenty CRM / Kosmo PM organicky | + WhatsApp, TTS |
| 7 | Měsíc 9+ | Portfolio žáka (Gemini Vision) | Beze změny |
| 8 | Rok 2+ | Sokratův průvodce, IVP | + žákovský přístup |
Onboarding — žádný big bang
Fáze 0: CC sofie@ v emailech → Sofie pozoruje, nikoho neoslovuje
Fáze 1: Aktivní uživatelé mají appku → Sofie posílá karty a návrhy
Fáze 2: Sofie potřebuje info → osloví emailem, zpracuje odpověď
Fáze 3: Neaktivní uživatel vidí, že to funguje → sám si otevře appku
Nulová bariéra. Nikdo není nucen. Přirozená adopce.
Trust gradient — stupně autonomie
Stupeň 0: Sofie jen pozoruje (CC pattern)
Stupeň 1: Sofie navrhuje, člověk schvaluje vše
Stupeň 2: Sofie schvaluje nízko-rizikové sama (auto-publish)
Stupeň 3: Sofie odpovídá rodičům z ověřené KB sama
Stupeň 4: Sofie zakládá akce z vlastní iniciativy
Stupeň 5: Sofie identifikuje mezery a navrhuje nové workflow
Klíčová rozhodnutí (přehled)
| Oblast | Rozhodnutí | Zamítnuto |
|---|---|---|
| LLM orchestrátor | Vertex AI Gemini z Next.js | Dify, n8n (odstraněn), Vertex AI Agent Builder |
| RAG | pgvector v Supabase | Weaviate |
| Znalostní báze | BookStack | Google Drive (jen pro dokumenty) |
| Email politika | Walled Garden (no-reply, rodič musí do appky) | — |
| Email infra | Resend (sending) + Cloudflare Email Worker (receiving) | — |
| CRM | Twenty | HubSpot |
| PM | Kosmo PM (vlastní kanban, Fáze 2+) | Asana, Plane |
| Newsletter | Resend transactional + ad-hoc HTML (Listmonk odstraněn) | Mailchimp |
Sloučeno z DECISION_AI_COMMUNICATION.md, DECISION_KNOWLEDGE_BASE.md, DECISION_LLM_ORCHESTRATOR.md a TONE_MANUAL_DRAFTS.md. Poslední aktualizace: březen 2026.
Roadmap (idea space, ne kontrakt)
Poslední aktualizace: 13. května 2026
Tento dokument je vizionářský — popisuje nápady pro fáze po MVP, ne závazky. Jakmile se nápad přesune k realizaci, vznikne brief v
docs/intent/přes/define. Před tím nemá ani spec, ani ADR.Dříve
BACKLOG.md. Přesunuto podideas/jako součást I³ doc cleanup (2026-05-13), aby bylo jasné, že roadmap není kontrakt s agenty.
Tento dokument shrnuje plánované funkce a rozhodnutí pro fáze po MVP. Položky jsou seřazeny podle priority a fáze.
Next 3 (Ready for /define)
Krátký seznam tří dalších specs, na které mířit. Splňují Definition of Ready. PO (Tomáš) ho udržuje ručně;
doc-curatoraprocess-analystho můžou navrhnout přerovnat.
- U-04 — Přiřazení tématu ročníku jedním chipem (USERS.md U-04). Cílový uživatel:
teacher. Úspěch: učitel přiřadí téma celému ročníku do 5 sekund, žák může být individuálně vyjmut. Závislosti: stávajícítopicstabulka. - U-05 — Individuální přiřazení žáka k tématu jiného ročníku (USERS.md U-05). Cílový uživatel:
teacher. Úspěch: žák je v daném slotu právě u jednoho tématu napříč ročníky. Stojí na U-04. - Týdenní completeness view (USERS.md U-07). Cílový uživatel:
teacherna desktopu večer. Úspěch: jedním pohledem na týden vidí, které sloty mají vyplněné téma + docházku. Read-only, žádná editace.
Po dokončení každého z těchto specs (Status: Implemented v jeho souboru) Tomáš doplní novou položku z USERS.md / BACKLOG níže. Seznam má být přesně 3 — víc je rozptyl, míň znamená, že chybí grooming.
RFC: Universal Knowledge Graph
Univerzální knowledge graph jako základ pro celý systém — content-agnostic graf myšlenek/nodů s AI overlay, který dynamicky generuje kontext per role.
Fáze 2: Teacher Tools
PM Kanban (vlastní modul v Kosmu)
Jednoduchý interní PM přímo v Kosmu. Detailní specifikace viz Příloha: PM modul na konci dokumentu.
Rozhodnutí: Vlastní modul místo SaaS. Důvod: jedna appka, nativní Gemini integrace, přepis porady → úkoly automaticky. Fallback: Trello/Todoist.
Portfolio upload
Učitel nahrává fotky práce žáků + popis. Základ pro rodičovský feed (Fáze 3).
- Upload přes Kosmo UI → Supabase Storage (RLS z boxu)
- Gemini Vision auto-popis fotky
- Vazba na žáka, třídu, datum
Generování dokumentů (WYSIWYG + Typst → PDF)
Škola dnes plní Word šablony ručně. Řešení: WYSIWYG editor (TipTap v2) v Kosmu, kde ředitel tvoří šablony s proměnnými a sekretářka jedním klikem generuje PDF.
- Editor: TipTap v2 s custom variable chips (inline
{{student.fullName}}) - Pipeline: Markdown → resolve proměnných z DB → MD → Typst → PDF
- Typst: Moderní alternativa LaTeXu, ~30 MB binary, kompilace <1s
- Školní šablona: Záhlaví (logo + adresa), patička (IČO, kontakty), font Inter
- Batch: Generování pro celou třídu/školu najednou (Vercel cron nebo Inngest)
- AI asistence (Sofie): Draftování šablon, vylepšení textu, GDPR formulace
- Tabulky:
document_templates,document_template_versions,generated_documents
Otevřené otázky (dokumenty):
- D1) Font: výchozí Typst, nebo bundlovat Inter?
- D2) Logo školy — potřeba SVG/PNG pro záhlaví
- D3) Role v profiles: sloupec role nebo separátní user_roles?
- D4) Podpisové pole v PDF?
- D5) Archivace: PDF permanentně do GCS, nebo generovat on-demand?
- D6) Email: odeslat PDF rodičům přímo?
Generování pracovních listů (Sofie chat → Typst → PDF)
Učitel popíše požadavek v chatu → Sofie (Gemini Flash) vygeneruje Typst markup → typst compile → PDF ke stažení.
- Workflow: Sofie chat (app.sofie.education) → AI Chain → extract Typst → compile → PDF
- Typst šablona (
worksheet.typ): Helper funkce#exercise(),#fill-blank(),#choice(),#instructions() - Error handling: Při chybě kompilace → Gemini opraví (max 1 retry)
- Iterace: Window Buffer Memory (10 zpráv) pro úpravy
- Infra: Typst binary jako Vercel Edge Function nebo Docker sidecar na GCP VM
Otevřené otázky (pracovní listy): - W1) Font: výchozí Typst, nebo bundlovat vlastní? - W2) Logo školy v hlavičce? - W3) Kam učitelé přistupují — stávající ai.sofie.education, nebo dedikovaný endpoint? - W4) Ukládat historii vygenerovaných listů?
Hlasový debrief
Přepis porady → extrakce úkolů → automatické vytvoření v PM modulu.
- Pro MVP: manuálně přes Google AI Studio (zdarma, až 3h přepis)
- Budoucí: Google Meet „Take notes for me" (vyžaduje Business Standard)
Fáze 3+: Newsletter
Listmonk byl odstraněn (2026-05-11). Newsletter pro ~150 rodin = triviální objem.
- Nástroj: Resend (transactional, již nastaveno) + ad-hoc HTML šablona per kampaň
- Gemini flow: Konec měsíce → Gemini projde fotky, projekty, poznámky → draft → ředitel schválí → Resend batch odeslání
- Lead magnet: „5 Montessori aktivit — PDF zdarma" → Resend + ruční segment
Mailchimp zamítnut (limit 500, branding v patičce). Buttondown nebo ConvertKit jako alternativa pokud Resend batch nestačí.
Fáze 2: Montessori kurikulum (Transparent Classroom → Kosmo)
Transparent Classroom (TC) je nasazený, ale UX je zastaralé (design z 90. let). Jediná jeho hodnota je strukturované Montessori kurikulum. Cíl: vytáhnout kurikulum přes TC API, uložit lokálně do Kosma a použít jako kontext pro AI-driven tracking kompetencí.
Datový model — 3 nové tabulky
montessori_areas — oblasti (Practical Life, Sensorial, Math, Language, Cultural)
id, name, name_cs, tc_id, sort_order
montessori_lessons — lekce a skupiny lekcí (flat s parent referencí)
id, area_id FK, parent_id FK (nullable), tc_id,
name, name_cs, level ('lesson_set'|'lesson'),
age_range, description, sort_order
montessori_rvp_mapping — mapování Montessori → RVP (many-to-many)
id, lesson_id FK, rvp_code, rvp_name,
confidence (0.0–1.0), is_verified BOOLEAN
Plus montessori_lesson_id UUID FK na existující competency_records.
Proč odděleně od RVP: Montessori kurikulum je pedagogická struktura, RVP je regulatorní. Many-to-many vztah — jedna lekce pokrývá víc RVP kódů a naopak.
Import kurikula (jednorázový script)
TC má REST API (/api/v1/) s token auth. Klíčové endpointy:
- GET /lesson_sets.json — strom oblastí a skupin lekcí
- GET /lessons.json — jednotlivé lekce
Import script (jednorázový, re-runnable):
1. Node.js nebo Python script s TC API tokenem
2. HTTP Request → TC API s X-TransparentClassroomToken header
3. Transformace na Kosmo schéma, zachovat tc_id
4. UPSERT do tabulek (on conflict tc_id = idempotentní)
5. Gemini Flash → vygenerovat české překlady name_cs (~$0.01)
Kurikulum se mění max 1×/rok. Celkem ~200–500 položek.
AI mapování na RVP
Script "Generate RVP Mappings":
1. Načíst všechny montessori_lessons ze Supabase
2. Gemini Flash — batch prompt (po 20–30 lekcích): „Pro každou lekci identifikuj RVP ZV kódy, vrať JSON"
3. INSERT do montessori_rvp_mapping s is_verified = false
4. Učitelé postupně ověřují přes UI
Cena: ~$0.05 za celý mapping.
Rozšíření AI pipeline (Gemini Vision)
Aktuální plán: Fotka → Gemini Vision → competency_records
Rozšířený pipeline: Fotka → načti Montessori lekce pro oblast → Gemini Vision → competency_records (s montessori_lesson_id + RVP kódem)
Gemini Vision prompt dostane kurikulum jako kontext:
Analyzuj fotku studentské práce.
Dostupné Montessori lekce pro tuto oblast:
- Golden Bead Addition (Sčítání se zlatým materiálem) → RVP M-3-1-01
- Stamp Game Subtraction (Odčítání s kolkovou hrou) → RVP M-3-1-02
...
Identifikuj: kterou lekci práce demonstruje, úroveň zvládnutí, RVP kódy.
Jedna oblast = 30–80 lekcí → bez problémů se vejde do kontextového okna.
Prerekvizity
- TC API token — školní admin: TC Settings → API → vygenerovat token
- Zmigrovaná
competency_recordstabulka (zatím jen v docs, ne v migrations)
Otevřené otázky (TC)
- TC1) Má škola přístup k TC API? (ověřit s adminem)
- TC2) Které Montessori programy jsou v TC aktivní? (AMI Primary? Elementary?)
- TC3) Chceme jednorázově importovat i pokrok dětí z TC? (nízká priorita)
- TC4) Kdo bude ověřovat RVP mapping? (ředitel? učitelé?)
Fáze 3+: Learning Tools
Adaptivní vzdělávací platformy pro žáky (4.–7. třída, bilingvální Montessori). Cíl: 360° profil učení každého žáka v Kosmu.
Doporučené platformy
| Tier | Platforma | Cena | Integrace do Kosma |
|---|---|---|---|
| 1 | Khan Academy | Zdarma | Přes Google Classroom |
| 1 | Brilliant.org | Zdarma (Educators program) | Přes Google Classroom |
| 1 | IXL | ~$10/žák/měs | Přímá (LTI v1.3 + API) |
| 2 | Eduten | ~$15–36/žák/rok | Bez API |
| 2 | Matika.in | Zdarma (Hejný) | Bez API |
Plán integrace
- Ihned: Doporučit Khan + Brilliant + Matika.in (zdarma, 0 effort)
- Fáze 2: Sekce „Rozšiřující práce" v Kosmu — kurátorované odkazy (~4–8h dev)
- Fáze 3: Google Classroom jako hub (~16h dev)
- Fáze 4: IXL přímá LTI v1.3 integrace (~16–24h dev)
- Fáze 5: Sokratův průvodce — Gemini agreguje data a navrhuje learning path
Otevřené otázky (learning tools): - L1) Investovat do IXL licence? - L2) Vyzkoušet Eduten trial? - L3) Google Classroom jako prostředník? - L4) Od jaké třídy samostatná práce? - L5) Matika česky nebo anglicky? - L6) Které platformy povinné pro sledování žáka? - L7) Ručně doplňovat data z platforem bez API?
Fáze 3+: Marketing a komunikace
Filozofie: žádné reklamy, žádné slogany. Pouze hodnotný obsah — autentický příběh, zprostředkování emoce.
Vrstvy obsahu
- Vrstva hodnoty — SEO články 2x/měs („Jak vypadá den čtvrťáka u nás vs. na běžné ZŠ")
- Vrstva emoce — Instagram Reels, fotopříběhy 3–4x/týden
- Vrstva expertízy — thought leadership 1x/měs (LinkedIn, blog)
- Vrstva komunity — doporučení, veřejné akce, rodičovská komunita
- Montessori zdroje — tipy, aktivity, materiály k tisku (lead magnety)
Gemini jako content engine
Z jednoho vstupu (poznámka učitele + 5 fotek) → obsah pro 3 kanály za 5 minut:
Učitel nafotí/napíše poznámku → Gemini vygeneruje IG caption + blogpost + newsletter snippet
→ Ředitel schválí → Kosmo publikuje přes API (IG Graph, FB Pages, Resend)
Priorita kanálů
- Google Business (zdarma, lokální SEO)
- Instagram (emoční obsah, Reels)
- Blog na webu (SEO, „Montessori škola Říčany")
- Newsletter (nurturing zájemců)
- Facebook (lokální komunita)
Předpoklady k ověření s ředitelem
- Logo ve vysoké kvalitě (SVG/PNG)
- GDPR souhlasy na fotky dětí pro veřejné kanály
- Google Business profil — existuje? aktuální?
- Instagram/Facebook účet — kdo spravuje?
- Branding: tón komunikace, hodnoty, příběh zakladatele
Fáze 3+: Web (sofie.education)
Škola má dva WordPress weby (ms-sofie.cz, zs-sofie.cz). Cíl: sjednotit pod sofie.education.
| Fáze | Stav |
|---|---|
| Teď | WordPress zůstává, Kosmo na app.sofie.education |
| Léto 2026 | Migrace statického webu do Next.js, jedna doména sofie.education |
Cílový stav: Web + blog + aplikace na jednom Next.js stacku. Obsah přes MDX nebo headless CMS (Sanity/Strapi).
Fáze 3+: Gamifikace rodičů
Rozsáhlý brainstorm proběhl 2026-04-15. 16 nápadů ve 4 tierech — od nudgingu (Inbox Zero, streak, předpřipravená omluvenka) přes sociální mechanismy (třídní momentum, kolektivní odměna) po crazy ideas (skrytý XP systém pro školu, dítě jako motivátor).
Klíčový insight: u rodičů nefunguje klasická gamifikace (body, badges). Funguje redukce friction, sociální norma, emoční vazba na příběh dítěte a viditelný dopad na učitele.
Další krok: Probrat s ředitelkou, vybrat 3–5 nápadů pro implementaci.
Fáze 3+: Feed třídy (TODO brainstorm)
Feed jako obousměrný kanál (ne jen škola → rodič). Třídní komunita, rodičovské reakce, tablety ve třídě jako výstupní zařízení. Navazuje na gamifikační nápady #5 a #16.
Status: Čeká na vlastní brainstorming session.
Fáze 3+: Login dětí (4.–7. třída)
Starší žáci potřebují přístup ke svému portfoliu, nahrávání projektů, Sokratův průvodce.
| Varianta | Popis |
|---|---|
| Školní Google účet | Po migraci na Google Workspace |
| QR kód / PIN | Fyzická karta |
| Rodičovský účet | Sdílený přístup |
Otevřené otázky: - 7a) Jak se přihlásí žák? - 7b) Od jaké třídy vlastní přístup?
Fáze 4+: Sokratův průvodce
Gemini AI jako personalizovaný tutor pro žáky. Sokratovská metoda — neptá se „jaká je odpověď?" ale „jak jsi na to přišel?".
- Agreguje data ze všech vzdělávacích platforem + interní evidenci
- Navrhuje žákovi personalizovaný learning path
- Inspirace: Khan Academy Khanmigo
Fáze 4+: Podpora rodičů
- Feed (
/feed) — timeline aktivit dítěte (fotky, projekty, hodnocení) - Adaptivní summary — Gemini shrne co se změnilo od poslední návštěvy
- Sofie chat pro rodiče — FAQ, omluvenky, vyzvedávání
- Multi-child feed s filtrem (rodič s více dětmi)
- Push notifikace (PWA)
Otevřená rozhodnutí (nerozřešená)
Následující rozhodnutí z DECISIONS_OPEN.md zatím nemají finální odpověď:
| # | Téma | Urgence | Poznámka |
|---|---|---|---|
| 7 | Login dětí | Fáze 3+ | Školní Google účet / QR / PIN? |
| 8 | Gamifikace | Fáze 3+ | Montessori vs. motivace |
| L1–L7 | Learning Tools | Fáze 3+ | IXL licence, GC integrace, jazyk matiky |
| D1–D6 | Generování dokumentů | Fáze 2 | Font, logo, role, archivace |
| W1–W5 | Pracovní listy | Fáze 2 | Font, logo, archiv PDF |
Příloha: PM modul (detail)
TL;DR
Rekurzivní hierarchie projektů (projekt → podprojekty → …), membership-based viditelnost, AI-generované summary. 3 tabulky, 4 enumy.
Datový model
CREATE TYPE public.project_status AS ENUM ('draft', 'active', 'done', 'cancelled');
CREATE TYPE public.subproject_priority AS ENUM ('required', 'nice_to_have');
CREATE TYPE public.project_member_role AS ENUM ('leader', 'collaborator');
CREATE TYPE public.resource_kind AS ENUM ('file', 'link', 'note');
projects — rekurzivní hierarchie (parent_id → self). Top-level = parent_id NULL. Sloupce: id, parent_id, title, description, leader_id, status, priority, due_date, ai_summary, timestamps. ON DELETE CASCADE na parent_id.
project_members — M:N vazba profilů na projekty. UNIQUE(project_id, profile_id). Role: leader (vše) / collaborator (editace, zdroje).
project_resources — přílohy s diskriminátorem kind (file/link/note). Sloupce: title, url, body, storage_path, ai_summary, uploaded_by.
Viditelnost (RLS)
Viditelnost se dědí dolů, ne nahoru. Member parent projektu vidí všechny podprojekty (rekurzivní CTE). SELECT/INSERT/UPDATE/DELETE pravidla dle role.
Progress tracking
get_project_progress(p_id) — rekurzivní CTE počítá done/total podprojektů → progress bar v UI.
Soubory
GCS bucket projects/{project_id}/{timestamp}_{filename} + sidecar .meta.json. V1 jen linky + poznámky, file upload ve v2.
AI summary
Vercel server action nebo Inngest event po vytvoření/úpravě projektu → Gemini → souhrn stavu (2–3 věty česky).
UI
/projects → seznam mých top-level projektů
/projects/new → nový projekt
/projects/[id] → detail (podprojekty, progress, tým, zdroje, AI summary)
/projects/[id]/edit → editace
Implementační kroky
- SQL migrace (enumy, tabulky, indexy, RLS, RPC)
- Server Actions + Zod validace
- UI stránky
- Navigace — "Projekty" do layoutu
- AI summary (Vercel server action → Gemini)
- File upload (Supabase Storage signed URL)
Gamifikace rodičů
Brainstorm: 2026-04-15
Status: Surové nápady, nefiltrované. Čeká syntéza a rozhodnutí.
Cíl: motivovat rodiče ke včasnému plnění povinností (omluvenky, platby, souhlasy, ankety, čtení Feedu) bez klasické soutěžní gamifikace, která je v rozporu s Montessori filozofií.
Tier 1: Motivační nudging (low-hanging fruit)
1. Sofie streak — série aktivních dnů
Rodič, který 7 dní po sobě otevřel Feed, dostane tiché potvrzení: "Tento týden jste byli v obraze každý den." Žádný badge, žádný leaderboard — jen osobní milestone. Streak se nezobrazuje nikomu jinému.
Psychologie: Loss aversion — nechci přijít o sérii.
2. Inbox Zero status
Vizuální indikátor v UI: máš 0 nevyřízených akcí (omluvy, souhlasy, ankety, platby). Zelený stav = klid. Červený = něco čeká. Není to gamifikace v klasickém smyslu — je to stresový termostat. Rodič chce mít klid, ne body.
3. "Včasný rodič" — tiché uznání
Omluvenka do 8:00 ráno → Sofie poděkuje: "Díky, předala jsem třídní učitelce. Aničce přeju brzké uzdravení." Po 10:00 → neutrální potvrzení bez vřelosti. Subtle, ale rodič pocítí rozdíl.
Psychologie: Pavlovův pes pro dospělé.
Tier 2: Sociální mechanismy (bez soutěže)
4. Třídní momentum — anonymní kolektivní metrika
"92 % rodičů vaší třídy už odevzdalo souhlas s výletem." Nikdo neví, kdo chybí — ale sociální tlak funguje. Inspirace: Kickstarter progress bar. Škola nemusí posílat reminder — Sofie jen ukáže číslo.
5. Rodičovský příspěvek do Feedu
Rodič může přidat reakci nebo krátký komentář k příspěvku ve Feedu svého dítěte. "Aničko, ten obrázek je krásný!" → dítě druhý den vidí na tabletu ve třídě. Motivace: rodič čte Feed, protože může reagovat. Engagement loop.
Poznámka: Toto téma zaslouží samostatný brainstorm — viz Feed třídy.
6. "Děkuji, že jste odpověděli" — kolektivní odměna
Když 100 % třídy vyplní anketu → Sofie pošle třídě: "Všichni rodiče Hvězdiček odpověděli na anketu — děkujeme! Výsledky budou na třídní schůzce." Kolektivní achievement. Peer pressure + kolektivní hrdost.
Tier 3: Chytré automatizace (nudge design)
7. Sofie ví, kdy se ptát
Anketa nepřijde jako formulář. Sofie se zeptá v chatu přesně ve chvíli, kdy rodič právě otevřel app: "Když už jste tady — jeden rychlý dotaz od paní ředitelky: preferujete výlet v pátek nebo v pondělí?" Kontextuální timing místo hromadného emailu.
8. Předpřipravená omluvenka
Pondělí ráno, dítě není v systému příchodů do 8:15. Sofie pošle push: "Aničku zatím nevidíme — je nemocná? [Ano, omluvte ji] [Je na cestě]" Jedno kliknutí. Nulová friction. Rodič nemusí nic psát ani volat.
9. Platební autopilot
Rodič, který zaplatí 3× po sobě včas, dostane nabídku: "Chcete nastavit trvalý příkaz? Tady jsou údaje." Nebo rovnou SIPO/inkaso integraci. Cíl: dostat rodiče z reaktivního placení do autopilotu.
Tier 4: Crazy ideas (možná geniální, možná šílené)
10. Rodičovský XP systém — skrytý, jen pro školu
Rodič nevidí svůj "skóre", ale škola ano. Dashboard pro ředitelku: "Rodina Novákových: engagement 87 %, response time Ø 2h, 0 pozdních plateb." Identifikuje at-risk rodiny DŘÍV, než se problém projeví. Early warning system, ne gamifikace pro rodiče — gamifikace pro školu.
11. Sofie rewards — odměny za engagement
Rodič, který celý měsíc plnil vše včas (omluvy, platby, souhlasy), dostane: přednostní registraci na přeplněný kroužek. Nebo early access na fotky z výletu. Nebo pozvánku na exkluzivní akci. Reálná hodnota, ne virtuální badge.
12. Family achievement wall
V profilu rodiny: vizuální timeline — "Září: 100% docházka. Říjen: Aničce se dařilo v geometrii (3 práce). Listopad: první výlet." Není to gamifikace rodiče — je to storytelling rodiny. Rodič se vrací, protože to je příběh jeho dítěte. Závislost na příběhu, ne na bodech.
13. Rodičovský mentoring
Nový rodič dostane přiřazeného "mentora" — zkušeného rodiče, který mu v chatu poradí. Mentor dostává recognition: "Pomohl/a jste 3 novým rodinám." Buduje komunitu, škola nemusí onboardovat sama.
14. Transparentní dopad
"Díky rychlým omluvenkám rodičů ušetřila paní učitelka Nováková tento měsíc 4 hodiny administrativy." Rodič vidí, že jeho chování má reálný dopad na člověka, kterého zná. Empatická gamifikace.
15. Anketa jako konverzace, ne formulář
Sofie vede anketu jako chat. Na konci shrne: "Z 28 rodičů si 60 % přeje plavání. Výsledek za vaši třídu: 4 pro, 2 proti, 1 ještě neodpověděl." Rodič vidí svůj hlas v kontextu. Pocit agency.
16. Dítě jako motivátor
Tablety ve třídě: "Aničko, maminka ti poslala vzkaz!" (reakce z Feedu). Dítě přijde domů: "Mami, poslala jsi mi vzkaz!" → rodič otevře app příští den znovu. Virální loop přes dítě.
Meta-pozorování
U rodičů nefunguje klasická gamifikace (body, badges, leaderboardy). Funguje:
| Mechanismus | Příklad nápadů | Proč funguje |
|---|---|---|
| Redukce friction | #8, #9 | Čím jednodušší, tím víc compliance |
| Sociální norma | #4, #6 | "Všichni ostatní už to udělali" |
| Emoční vazba | #12, #16 | Příběh dítěte jako magnet |
| Viditelný dopad | #14 | "Tvoje akce pomohla konkrétnímu člověku" |
| Loss aversion | #1, #11 | Nechci přijít o streak/status/výhodu |
Montessori kompatibilita
Plně kompatibilní (žádná soutěž, žádné vnější odměny): #2, #4, #7, #8, #12, #14
Částečně kompatibilní (jemná vnější motivace): #1, #3, #6, #9, #15
Potenciálně kontroverzní (vyžaduje diskuzi s ředitelkou): #5, #10, #11, #13, #16
Budoucí brainstorm: Feed třídy
Nápad #5 (rodičovské reakce ve Feedu) a #16 (dítě jako motivátor) otevírají širší téma: jak by měl vypadat Feed z pohledu třídy a komunity. Zaslouží vlastní brainstorming session:
- Feed jako obousměrný kanál (ne jen škola → rodič)
- Třídní komunita vs. individuální feed
- Tablety ve třídě jako výstupní zařízení
- Boundary: co je ještě engagement a co je už surveillance
Další kroky
- Probrat s ředitelkou: Montessori kompatibilita, které nápady rezonují
- Vybrat 3–5 nápadů pro MVP (pravděpodobně Tier 1 + #4 + #8)
- Navrhnout ankety modul (Sofie chat-based surveys)
- Brainstorm: Feed třídy
Vize bez závazku
Vize: Feed + Messaging (Fáze 3+)
Status: Vize, ne kontrakt. Žádný intent brief ani implementace zatím neexistuje. Až bude PO ready feature zahájit, spustí
/define→ vznikne brief vdocs/intent/, ne tady. Tento dokument je inspirační, ne závazný.Přesunuto z
ARCHITECTURE.md2026-05-13 jako součást I³ doc cleanup.
Feed — Hlavní obrazovka rodiče (Fáze 3+)
Výchozí landing page rodiče je chronologický feed (à la Instagram) o jeho dětech a školních událostech. Ředitel a učitel si ponechávají klasický dashboard.
Proč Feed?
- Rodič → dítě: Při vyzvedávání se dívám do appky a vím, na co se zeptat. „Tak jaký byl ten projekt o vesmíru?" místo „Co jste dělali?" → „Nevím."
- Rodič → učitel: Vidím, že učitel fotí práce, eviduje → cítím hodnotu školy → důvěra.
- Učitel → rodič: Učitel ví, že rodič reaguje → motivace evidovat.
- Engagement loop: Appka žije, rodič se vrací, data pro AI rostou.
Struktura feedu
┌─────────────────────────────────┐
│ Souhrn od poslední návštěvy │
│ "Od včera: 2 nové fotky, │
│ Přítomna, Oběd č. 2" │
├─────────────────────────────────┤
│ Evidence (14:30) │
│ [Fotka práce] │
│ "Anička — Projekt vesmír" │
├─────────────────────────────────┤
│ Zpráva školy (12:00) │
│ "Zítra nezapomeňte gumáky!" │
├─────────────────────────────────┤
│ Jídelníček (11:00) │
│ "Oběd: Kuřecí řízek..." │
├─────────────────────────────────┤
│ Docházka (8:05) │
│ "Anička dorazila v 8:05" │
└─────────────────────────────────┘
[Sofie] ← FAB overlay
Typy feed items
| Typ | Zdroj | Příklad |
|---|---|---|
| Adaptivní souhrn | AI (pinned) | Souhrn od poslední návštěvy (auto-granularita) |
| Přehled zítřka | AI (od 14:00) | „Zítra: Škola do 13:30, plavání, přineste gumáky!" |
| Evidence/fotka | Učitel / Služba | Fotka práce + AI štítek |
| Docházka | Systém | „Dorazila v 8:05" |
| Družina | Vychovatel/ka | „Anička je v družině. Odchod: 15:30." |
| Kroužek | Systém / Lektor | „Dnes: Šachy 14:00" / „ZRUŠENO" |
| Zpráva školy | Ředitel / Učitel | „Zítra výlet — gumáky!" |
| Jídelníček | strava.cz (cron) | „Oběd č. 1: Řízek" |
| Akce / kalendář | Kalendář | „Za 3 dny: Třídní schůzka" |
| Odpověď na dotaz | Sofie / Učitel | „Odpověď na váš dotaz" |
| Platba (Fáze 2) | Pohoda (sync) | „Školné únor: zaplaceno" |
Multi-child
Rodič s více dětmi vidí prolínající se feed s avatarem/tagem dítěte. Filtr: „Jen Aničku" / „Jen Tomáše" / „Vše".
Sofie Overlay (FAB)
- Plovoucí tlačítko vpravo dole.
- Klik → otevře chat panel (slide-up nebo sidebar).
- Vždy dostupný. Badge s počtem nepřečtených zpráv.
Přehled zítřka (Tomorrow Preview)
Každý den od cca 14:00 karta s přehledem následujícího dne: - Běžné položky: rozvrh, konec školy, oběd, plánovaný odchod, kroužky. - Zvýrazněné výjimky: výlet, plavání, „přineste si...". - Akce potřeba: nepodepsané souhlasy, nezaplacené platby. - Generuje AI z rozvrhu, kalendáře a školních dat. - Push: „Sofie: Zítra plavání — nezapomeňte plavky!"
Adaptivní souhrn („Od poslední návštěvy")
Systém trackuje last_seen_at per rodič. Při otevření appky AI souhrn za období od last_seen_at:
- < 4 hodiny: Live stav.
- 1 den: Včerejší souhrn.
- 1 týden: Týdenní → rozklik po dnech.
- 3+ týdny: Souhrn za delší období → týdny → dny → detail.
Zero config. Push re-engagement po 3+ dnech bez návštěvy.
Skupinový chat / Komentáře — NE
Reakce místo diskuze. Důvody: moderace, GDPR, scope creep, negativity bias. Pro volné diskuze mezi rodiči slouží WhatsApp komunity školy.
| Funkce | Popis |
|---|---|
| Reakce | Rodič „lajkne" fotku práce dítěte. Učitel vidí počet → motivace. |
| Strukturované odpovědi | „Kdo jede na výlet?" → tlačítka Ano/Ne. |
| Otázky → Sofie | Rodič má dotaz? Zeptá se Sofie. |
| Privátní zpráva učiteli | Přes Sofii jako prostředníka, nebo přímo. |
Důsledky pro architekturu
- Feed a Sofie jsou Fáze 3+. V MVP (Fáze 1) existuje jen třídnice pro učitele — rodičovský pohled není implementován.
- Až přijde feed:
feed_eventsview, který agreguje data z různých tabulek do chronologického streamu.
Messaging & Email: Walled Garden (no-reply)
Aplikace je jediný kanál pro komunikaci rodič ↔ škola. Emailové notifikace jsou „hluché" (noreply@) — nutí rodiče kliknout a odpovědět v aplikaci.
- Rodič nepíše „paní učitelce", ale píše Sofii (AI Chatbot), která buď odpoví sama, nebo eskaluje.
- Pokud někdo napíše email, učitel může odkázat na aplikaci.
- Důsledek: Žádný „split-brain" (půlka v mailu, půlka v chatu). Pravda je v ticketu/konverzaci v aplikaci.
Plánované moduly (mimo MVP)
Pro orientaci — nic z toho zatím není implementováno. Pořadí jen orientační, řídí ho /define priority od PO.
| Modul | Účel |
|---|---|
evidence |
Evidence prací žáků — úkoly, projekty, testy, fotky; AI štítkování |
attendance-chat |
Chat-based docházka/vyzvedávání („Dnes vyzvedne babička") — safety gate flow |
surveys |
Interaktivní chat ankety (tlačítkové odpovědi) |
communication |
Sofie chatbot — RAG nad daty žáka + Knowledge Base školy |
components/ai |
Reusable UI primitiva pro AI interakce |
export |
XLSX / Google Sheets / PDF / CSV exporty |
RFC: Universal Knowledge Graph
Stav: Draft Datum: 2. dubna 2026 Autor: docek + Claude
Motivace
Kosmo je dnes školní IS — tabulky studentů, docházka, profily. Ale informace, které školní komunita potřebuje sdílet, jsou přirozeně graf, ne tabulky: omluvenka se týká dítěte, dítě patří do třídy, třídu vede učitelka, učitelka napsala poznámku, poznámka odkazuje na projekt...
Cíl: vybudovat univerzální knowledge graph — jednoduchou, content-agnostic datovou strukturu, nad kterou AI dynamicky generuje kontext pro libovolnou roli a úlohu.
Principy
- Simplicity is the ultimate complexity — minimální datový model, maximální flexibilita
- Content-agnostic — nod je nod: omluvenka, myšlenka, foto, odkaz, audio — stejná struktura
- Role-agnostic — graf je jeden, "čočka" (AI overlay) se mění podle role
- Incrementální buildovatelnost — začni s nody a feedem, přidávej AI postupně
- Osifikace datové struktury — stabilní základ, dynamické vrstvy nad ním
Datový model
Node — atomická jednotka obsahu
nodes
├── id UUID, PK
├── author_id UUID → profiles
├── created_at TIMESTAMPTZ
├── updated_at TIMESTAMPTZ
│
│ # Obsah
├── content_raw TEXT — originální obsah (markdown, URL, reference na media)
├── content_md TEXT — human-readable markdown verze
├── media_url TEXT — odkaz na uložené médium (audio, video, foto)
├── media_type TEXT — MIME type (image/jpeg, audio/webm, ...)
│
│ # AI metadata (generované automaticky)
├── ai_transcript TEXT — přepis audia/videa, OCR z obrázku
├── ai_summary TEXT — krátké summary (1-2 věty)
├── ai_analysis TEXT — dlouhá analýza + co přináší nového do kontextu
├── embedding VECTOR(1536) — pro semantic search
│
│ # Systém
└── metadata JSONB — volná metadata (source, tags, ...)
Nod nemá type enum. Typ je odvozený z obsahu, hran a tagů. AI ho může reklasifikovat.
Edge — vztah mezi nody
edges
├── id UUID, PK
├── source_id UUID → nodes
├── target_id UUID → nodes
├── edge_type TEXT — volný string: responds_to, about, contradicts, supersedes, related, tagged_with, ...
├── weight FLOAT — důležitost vztahu (default 1.0, AI může upravovat)
├── created_by TEXT — 'user' | 'ai:linker' | 'ai:enrichment' | ...
└── created_at TIMESTAMPTZ
Hrany mohou směřovat i na existující entity (profily, studenty, třídy) přes referenční nody nebo přímé UUID.
AI Overlay — "čočka"
Overlay není tabulka. Je to procedura (agent), která na vyžádání:
- Vezme startovní bod — roli uživatele, aktuální dotaz, situaci
- Projde graf pomocí kombinace:
- Recency — čerstvé nody mají vyšší váhu
- Relevance — embedding similarity k dotazu/kontextu
- Role filter — rodič vidí jen své děti, učitel svou třídu
- Importance — AI-scored "zásadní změna" vs. "rutina"
- Graph distance — bližší nody (méně hran) mají vyšší váhu
- Složí context window — seřazený, sumarizovaný kontext (budget ~0.5M tokenů)
- Výstup je ready pro LLM — začni novou úlohu s kompletním kontextem
Příklad: context window pro roli "táta"
[Kontext role: Rodič | Děti: Eliška (3.A), Matěj (1.B)]
## Aktuální (posledních 7 dní)
- Eliška: projekt Sopka — prezentace v pátek, potřebuje noviny a lepidlo
- Matěj: nemocný Po-Út, omluvenka odeslána
- Třída 3.A: plánovaný výlet na Říp (15.4.)
## Důležité změny
- Nový rozvrh kroužků od dubna
- Změna vyzvedávání: babička přidána jako oprávněná osoba
## Relevantní kontext (starší, stále platný)
- Eliška: alergie na ořechy (zdravotní poznámka)
- Kontakt třídní: p. Nováková (novakova@sofie.education)
Agenti
| Agent | Trigger | Co dělá |
|---|---|---|
| Ingestion | Nový obsah (email, webhook, UI, API) | Normalizuje na nod + základní hrany |
| Enrichment | Nový nod vytvořen | Transcript, OCR, summary, embedding, context delta |
| Linker | Po enrichmentu | Hledá implicitní vztahy (semantic similarity, entity extraction) |
| Compiler | Na vyžádání (chat, feed, API) | Skládá context window pro roli/úlohu |
| Curator | Periodicky (denně/týdně) | Přehodnocuje importance, merguje duplicity, archivuje |
| Compactor | Periodicky + on-demand | Vytváří kompaktující nody — sumarizace clusterů nodů |
Kompaktující nody
Klíčový mechanismus pro škálovatelnost grafu. Compactor agent vytváří syntetické nody, které sumarizují cluster souvisejících nodů:
[Kompakt nod: "Eliška — březen 2026"]
content_md: "Březen: 3 absence (nemoc), projekt Sopka (prezentace
úspěšná), pokrok v matematice (zlatý materiál zvládnut).
Nový kroužek keramika od 10.3."
ai_summary: "Eliška měla produktivní březen s drobnými absencemi"
metadata: { "compact_type": "monthly_student", "generated_at": "2026-04-01" }
│
├── compacts ──→ [Nod: Omluvenka 3.3.]
├── compacts ──→ [Nod: Omluvenka 7.3.]
├── compacts ──→ [Nod: Omluvenka 12.3.]
├── compacts ──→ [Nod: Foto projekt Sopka]
├── compacts ──→ [Nod: Poznámka učitelky — matematika]
└── compacts ──→ [Nod: Zápis do kroužku keramika]
Vlastnosti:
- Hrana compacts odkazuje na zdrojové nody — nic se nemaže, jen se přidá vrstva
- Compiler přednostně používá kompaktní nody (méně tokenů, stejná informace)
- Pokud potřebuje detail, sleduje compacts hrany k originálům
- Přegenerovatelné — kompakt nod je vždy odvoditelný ze zdrojových nodů, může se přegenerovat s novým kontextem (jiná role, jiný čas, nové informace)
- Víceúrovňové: denní kompakty → týdenní → měsíční → kvartální
Příklad víceúrovňové kompaktace:
[Kvartální kompakt: "Eliška Q1 2026"]
├── compacts ──→ [Měsíční kompakt: "Eliška — leden 2026"]
├── compacts ──→ [Měsíční kompakt: "Eliška — únor 2026"]
└── compacts ──→ [Měsíční kompakt: "Eliška — březen 2026"]
├── compacts ──→ [Nod: Omluvenka 3.3.]
├── compacts ──→ [Nod: Foto projekt Sopka]
└── ...
Kontextová přegenerace: Stejný cluster nodů může mít víc kompaktů — jeden z pohledu rodiče ("jak se Elišce daří"), jiný z pohledu učitelky ("pedagogický pokrok"), jiný pro ředitele ("docházka a výjimky"). Kompakt se přegeneruje když: - Přibude nový nod do clusteru - Změní se kontext (nová informace mění interpretaci starých) - Periodicky (curator trigger)
Implementace agentů
Agenti poběží jako Next.js API routes / Vercel Cron / Inngest (n8n odstraněn): - Ingestion: webhook endpoint, přijme cokoliv, vytvoří nod v Supabase - Enrichment: database trigger (on insert into nodes) nebo Inngest event, zavolá Gemini pro AI metadata - Linker: po enrichmentu, vector search pro podobné nody, vytvoří hrany - Compiler: API endpoint, na vstupu role + dotaz, na výstupu context MD - Curator: Vercel Cron (denně), projde staré nody, přepočítá váhy
Ingestion kanály
Nod je nod bez ohledu na zdroj. Každý kanál volá stejný Ingestion endpoint:
| Kanál | Jak | Příklad |
|---|---|---|
| Web UI | Formulář v Kosmu | Rodič píše omluvenku |
| Mobilní PWA | Quick capture: fotka + hlas + text | Učitel fotí projekt žáka |
| Webhook / Cron | Automaticky z externích systémů | Email → nod |
| Cloudflare Email Worker → Next.js API → nod | Rodič pošle email třídní | |
| API | REST/GraphQL | Integrace třetích stran |
| Chat (Sofie) | Konverzace s AI → extrakce nodů | "Eliška zítra nepřijde" → omluvenka nod |
Příklad: omluvenka jako graf
[Nod A: Omluvenka]
content_md: "Eliška nebude ve škole 3.–5. dubna, je nemocná."
author: táta
ai_summary: "Omluvenka Elišky, 3.–5.4., nemoc"
│
├── about ──→ [Nod: Eliška (profil studenta)]
├── tagged_with ──→ [Nod: attendance]
├── responds_to ──→ [Nod: Dotaz učitelky na docházku]
└── relates_to ──→ [Nod: Předchozí omluvenka z února]
Stejná omluvenka se zobrazí: - Tátovi: v jeho feedu jako "odesláno" - Učitelce: jako notifikace + automaticky v docházce - AI overlay: aktualizuje kontext "Eliška — aktuálně nemocná"
Open questions
| # | Otázka | Poznámka |
|---|---|---|
| KG1 | Privacy/RLS — jak řešit viditelnost nodů? | Supabase RLS per nod? Per hrana? Děděná z grafu? |
| KG2 | Multi-tenancy — jedna instance grafu per škola, nebo sdílený? | Pro univerzálnost: tenant_id na nodech |
| KG3 | Media storage — kam ukládat audio/video/foto? | Rozhodnuto: Supabase Storage. ~10–20 GB/rok, RLS z boxu. GCS až při potřebě. |
| KG4 | Škálovatelnost overlay — 0.5M tokenů kontextu pro jednoho uživatele | Kolik nodů to je? Jak efektivně prořezávat? |
| KG5 | Embedding model — jaký model pro vektory? | OpenAI ada-002 (1536d), Gemini embedding, lokální? |
| KG6 | Edge types — otevřený string vs. řízený slovník? | Flexibilita vs. konzistence |
| KG7 | Verzování nodů — editace = nový nod + supersedes hrana? | Nebo prostě UPDATE? |
| KG8 | Odkaz na existující entity — profily, studenti, třídy | Referenční nody, nebo hrany přímo na UUID jiných tabulek? |
Fáze implementace
Fáze 0: Datový základ
- Supabase migrace: tabulky
nodes,edges - Základní RLS politiky
- pgvector extension pro embeddingy
Fáze 1: Ingestion + Enrichment
- Ingestion endpoint v Next.js (webhook → nod)
- Enrichment: Inngest event nebo Supabase database webhook (Gemini summary + embedding)
- Jednoduchý Web UI pro vytváření nodů
Fáze 2: Feed + Linker
- Feed view v Kosmu (chronologický, filtrovaný per role)
- Linker agent (semantic similarity → hrany)
- Základní graph traversal
Fáze 3: AI Overlay + Compiler
- Compiler agent (context window pro roli)
- Integrace s Sofie chatem (context-aware odpovědi)
- Curator agent (údržba grafu)
Fáze 4: Advanced
- Multi-kanálový ingestion (email, PWA, chat extraction)
- Adaptivní importance scoring
- Cross-tenant knowledge sharing (opt-in)
Glosář Kosmo / Sofie
Doménový slovník pro autonomní tým. Pokud termín zazní v /define dialogu, agent ho má najít zde místo aby ho re-derivoval. Žij dokumentem — když narazíš na pojem, který tu chybí, doplň ho (PR chore: glossary +<pojem>).
Brand & projekt
| Pojem | Význam |
|---|---|
| Sofie | Brand — vidí ho rodiče, učitelé, UI, chatbot. Doména sofie.education. |
| Sofie.Education | Plný název produktu. |
| Kosmo | Codename — interní označení v repo, tech docs, DB. Nikdy nepoužívej v UI. |
| ZŠ a MŠ Sofie | Konkrétní škola v Říčanech, pilot / první zákazník. Nezaměňovat s brandem Sofie. |
| Sofie (AI persona) | Chatbot postavený nad Gemini. Tyká, viz docs/SOFIE.md. |
Role v systému (DB enum profiles.role)
| Role | Kdo to v reálu je | MVP přístup |
|---|---|---|
teacher |
Průvodce — třídní učitel v Montessori terminologii. Většina učí v obou třídách. | Plný (třídnice). |
parent |
Zákonný zástupce žáka. | Žádný v MVP (jen kontakt v evidenci). |
director |
Ředitel školy. V Sofii zároveň majitel/data controller. | Žádný v MVP (data zakládá vývojář). |
office |
Kancelář — administrativa, ŠkolaOnline sync. | Žádný v MVP. |
pending |
Nový uživatel po prvním OAuth loginu, čeká na přiřazení role. | Čekací obrazovka. |
student |
Žák. | Žádný v MVP (od Fáze 4+ login pro 4.–7. třídu). |
Pedagogika / Montessori
| Pojem | Význam |
|---|---|
| Třída | Organizační jednotka v Kosmo. V Sofii: Kentaur (4.+5. ročník), Phenix (6.+7. ročník). DB tabulka classes. |
| Ročník | Klasický stupeň (4., 5., 6., 7.). V Sofii dva ročníky v jedné třídě — heterogenní skupina, Montessori standard. |
| Slot | Časový úsek v rozvrhu (typicky 90 min „blok práce"). DB tabulka schedule (slot × den × třída → předmět). |
| Téma | Co se v daném slotu probírá. Přiřaditelné ročníku nebo konkrétnímu žákovi. DB tabulka topics. |
| Klíč | Montessori prezentace lekce (např. „Golden Bead Addition"). Mapuje se na RVP kód. Synonymum „lekce" / „lesson" v TC API. |
| RVP | Rámcový vzdělávací program — český kurikulární standard. Mapování Montessori → RVP je many-to-many. |
| TC | Transparent Classroom — externí Montessori systém, dnes nasazený. Z něj se bude vytahovat kurikulum přes API. |
| Práce s materiálem | Žák samostatně pracuje s konkrétní pomůckou (Montessori). Eviduje se přes fotku → Gemini Vision → competency record. |
Tech stack
| Pojem | Význam |
|---|---|
| Web | Adresář web/ — Next.js (App Router) + TypeScript + Tailwind + Shadcn/ui, pnpm. |
| Supabase | Postgres + Auth + Storage + pgvector, region Frankfurt. Free plán, hosted. |
| RLS | Row-Level Security — Supabase enforcement, každý query je filtrován per auth.uid(). Povinný pro každou tabulku se schválními daty. |
| Zod | Schema validace na hraně server/client. Každý form i server action má Zod schema. |
| Server action | Next.js mechanismus — RPC z UI do server kódu, alternativa REST endpointu. |
| Vertex AI / Gemini | Google Cloud AI — gemini-flash-latest (laciné) a gemini-pro-latest (komplexní). Volané přímo z Next.js, ne přes n8n. |
| Resend | SMTP/transactional email — odesílání. |
| Cloudflare Email Worker | Příjem emailů na *@sofie.education → webhook. |
| Twenty | CRM na GCP VM e2-small (samostatná infra, Fáze 3+ integrace). |
| BookStack | Wiki pro učitele na stejné VM. |
| Sentry | Runtime error tracking, region Frankfurt, Free 5k events/měs. |
Procesní pojmy
| Pojem | Význam |
|---|---|
| PO | Product Owner = Tomáš. Rozhoduje, schvaluje, neprogramuje. |
| DoR | Definition of Ready — co musí nápad splňovat, aby šel přes /define. Viz AGENTS.md. |
| DoD | Definition of Done — kdy je feature hotová. Viz AGENTS.md. |
| I³ | Intent / Invariants / Implementation — metodologie pro spec-driven vibe development (zavedeno 2026-05-13). Viz AGENTS.md Methodology. |
| Intent brief | 1-stránkový dokument popisující WHAT a WHY feature. 4 sekce. Žije v docs/intent/<feature>.md. Výstup /define. |
| Invariant | Pravidlo, které nesmí padnout ani při full rewriteu. Žije v docs/invariants.md. Critical má test v web/tests/invariants/. |
| ADR | Architecture Decision Record — záznam architektonického rozhodnutí (proč X, ne Y). Append-only v docs/decisions/. |
| Next 3 | Tři další nápady, které jsou „Ready for /define". Sekce v ideas/roadmap.md. |
| Merge gate | Manuální checklist před merge do main (GitHub Free tier, žádné branch protection). |
| Greenfield optionality | Žádná produkční data → přepsat je vždy legitimní varianta. Architekt je povinen ji zvážit. |
| Vibe coding | Solo dev styl: Tomáš nepíše kód, popíše chování, agent realizuje. Verifikace přes Preview MCP + e2e. |
Doménová zkrácená slova
| Zkratka | Význam |
|---|---|
U-XX |
User story ID v USERS.md (U-01 až U-08 v MVP). |
D1..D6, W1..W4, L1..L7, TC1..TC4 |
Otevřené otázky per feature v ideas/roadmap.md. |
MŠMT |
Ministerstvo školství. Export docházky/výkazů odsud — Fáze 4+. |
MŠ / ZŠ |
Mateřská škola / Základní škola. Sofie má obojí. |