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. |
| Supabase Storage | Data v AWS. Gemini Vision v GCP. Cross-cloud transfer = latence + náklady. |
| 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 B as GCP Bucket
participant G as Gemini Vision
participant DB as Supabase
U->>K: Nahraje soubor + vyplní popis
Note over K: Client-side resize fotek (2048px, WebP)
K->>K: Vygeneruje čitelný filename + .meta.json
K->>B: Upload soubor přes signed URL
K->>B: Upload .meta.json přes signed URL
K->>B: Regeneruje manifest.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í)
n8n workflow "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.
n8n workflows
| 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 |
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: GCS infrastruktura + evidenční dokumenty
- GCP: vytvořit bucket sofie-media v europe-west1, CORS, Object Versioning
- Next.js: API routes 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)
- n8n: Work Processing workflow (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 - n8n: Assessment Processing workflow (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 přes n8n. Inspirováno architekturou OpenClaw.
SofieMessage — kanonické schéma zprávy
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ý n8n sub-workflow)
→ 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)
n8n workflow vzor
[Trigger node] → [Normalize node] → [Route node] → [AI node] → [Format node] → [Send node]
(webhook, (→ SofieMessage) (→ správný (Vertex AI) (chunking, (email,
email, sub-workflow) limity kanálu) webhook)
schedule)
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 pro n8n |
| 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 node v n8n 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).