Datový Model (Návrh pro Supabase / Postgres)
Tento dokument popisuje databázové schéma, které bude implementováno v Supabase.
1. Uživatelé a Role (Tabulka public.profiles)
Supabase používá tabulku auth.users pro přihlašování. My vytvoříme tabulku public.profiles, která bude propojena přes id.
-
profiles (rozšiřuje
auth.users)id: UUID (Primary Key, FK -> auth.users.id)email: Textfull_name: Textavatar_url: Textroles: Array[Enum] ('admin', 'teacher', 'parent', 'student') - Uživatel může mít více rolí.preferred_language: Enum ('cs', 'en') (default: 'cs') — jazyk UI a AI odpovědí.summary_style: Enum ('narrative', 'bullets') (default: 'narrative') — styl AI souhrnu.hubspot_contact_id: Text (pro synchronizaci s CRM)is_identity_verified: Boolean (Fyzicky ověřeno školou)identity_verified_at: Timestampidentity_verified_by: UUID (FK -> profiles.id - kdo ověřil)created_at: Timestamp
-
student_records (Citlivá data žáků - RLS: Pouze Admin/Ředitel)
id: UUID (PK, FK -> profiles.id)birth_number: Text (Rodné číslo - Šifrováno?)variable_symbol: Integer (Unikátní identifikátor pro platby/evidenci. Formát:YYNNN(např.25011pro 11. žáka v roce 2025).)status: Enum ('active', 'graduated', 'transferred', 'did_not_start', 'interrupted')enrollment_date: Dateend_date: Datenotes: Text (Interní poznámky)
2. Struktura Školy
-
school_years (Školní roky)
id: UUIDname: Text (např. "2025/2026")is_active: Boolean
-
class_groups (Třídy/Triády)
id: UUIDname: Text (např. "Hvězdáři")grade_level: Text (např. "1-3")lead_teacher_id: UUID (FK -> profiles.id)
-
students_classes (Vazba Žák <-> Třída)
student_id: UUID (FK -> profiles.id)class_id: UUID (FK -> class_groups.id)school_year_id: UUID
-
student_guardians (Vazba Žák <-> Zákonný zástupce)
student_id: UUID (FK -> profiles.id)guardian_id: UUID (FK -> profiles.id)relationship_type: Enum ('mother', 'father', 'grandparent', 'other')can_pickup: Boolean (Oprávněn vyzvedávat ze školy)is_legal_guardian: Boolean (Zákonný zástupce - dostává oficiální zprávy)
(Tabulka pickup_persons byla odstraněna — v modelu "AI Podatelna" rodič sdělí vyzvedávající osobu v chatu, AI extrahuje údaje a uloží je přímo do attendance_records.pickup_person_name. Historická data jsou dohledatelná z communication_threads.)
3. Docházka a Omluvenky
-
attendance_records (Denní docházka)
id: UUIDstudent_id: UUIDdate: Datestatus: Enum ('present', 'absent', 'excused', 'late')arrival_time: Timedeparture_time: Timepickup_person_name: Text (Kdo vyzvedl, pokud to nebyl defaultní rodič)
-
attendance_plans (Plán odchodů)
id: UUIDstudent_id: UUIDday_of_week: Int (0-6)regular_departure_time: Timetype: Enum ('regular', 'exception')valid_from: Datevalid_to: Date
-
excuse_notes (Omluvenky)
id: UUIDstudent_id: UUIDauthor_id: UUID (Rodič)content: Textfrom_date: Dateto_date: Datereason: Textstatus: Enum ('pending', 'approved', 'rejected')
-
activities (Kroužky a Akce)
id: UUIDname: Text (např. "Šachy", "Keramika")description: Textteacher_id: UUID (FK -> profiles.id - vedoucí kroužku)schedule: Text (např. "Úterý 14:00-15:00")capacity: Intprice: Decimalis_active: Boolean
-
activity_enrollments (Přihlášky na kroužky)
id: UUIDactivity_id: UUID (FK -> activities.id)student_id: UUID (FK -> profiles.id)status: Enum ('enrolled', 'waitlist', 'cancelled')created_at: Timestamp
-
consents (Definice Souhlasů - GDPR, Výlety)
id: UUIDtitle: Text (např. "Souhlas s focením", "Souhlas s výletem na Šumavu")content: Text (Markdown - právní text)valid_until: Date (kdy vyprší)is_mandatory: Booleancategory: Enum ('gdpr', 'trip', 'photo', 'health')
-
student_consents (Podpisy souhlasů)
id: UUIDconsent_id: UUID (FK -> consents.id)student_id: UUID (FK -> profiles.id)signed_by: UUID (FK -> profiles.id - rodič)signed_at: Timestampstatus: Enum ('granted', 'revoked', 'pending')ip_address: Text (Audit)
4. Evidence Práce
-
subjects (Předměty)
id: UUIDname: Textcolor: Text
-
competencies (Kompetence)
id: UUIDsubject_id: UUID (FK -> subjects.id)name: Textdescription: Text
-
work_items (Práce/Důkazy)
id: UUIDstudent_id: UUID (FK -> profiles.id)created_by: UUID (FK -> profiles.id or NULL for AI agent)title: Textdescription: Text (Markdown support)content: JSONB (Strukturovaný obsah: textové bloky, seznam URL na fotky/soubory, audio poznámky)source: Enum ('upload', 'email', 'api_agent', 'manual')external_reference_id: Text (např. Message-ID emailu pro párování)status: Enum ('draft', 'pending_approval', 'published', 'archived')ai_metadata: JSONB (Analýza od Gemini: navržené kompetence, sentiment, klíčová slova)teacher_feedback: Textcreated_at: Timestamppublished_at: Timestampvisibility: Enum ('private', 'teacher', 'parent', 'public')
-
work_item_tags (Štítky na pracích - Kompetence)
work_item_id: UUIDcompetence_id: UUIDconfidence_score: Float (0.0 - 1.0, pokud navrženo AI)is_approved: Boolean (potvrzeno učitelem)
5. Komunikace (AI Concierge)
-
communication_threads (Konverzace / Tickety)
id: UUIDstudent_id: UUID (FK -> profiles.id, nullable — obecné dotazy nemají žáka)category: Enum ('obecne', 'omluvenka', 'zdravi', 'vyuka', 'incident', 'survey')status: Enum ('open', 'ai_resolved', 'teacher_review', 'closed')assigned_to: UUID (FK -> profiles.id, nullable — pokud řeší AI)created_at: Timestampupdated_at: Timestamp
-
messages (Zprávy ve vlákně)
id: UUIDthread_id: UUID (FK -> communication_threads.id)sender_id: UUID (FK -> profiles.id, nebo NULL pro AI bota)content: Text (Markdown)is_internal: Boolean (pro poznámky učitelů, rodič nevidí)ai_metadata: JSONB (analýza sentimentu, navržené odpovědi, survey response apod.)created_at: Timestamp
6. Ankety a Sběr Dat
-
surveys (Ankety)
id: UUIDtitle: Textdescription: Textauthor_id: UUID (FK -> profiles.id)is_active: Booleandeadline: Timestamptarget_audience: Enum ('all_parents', 'class_group', 'specific_parents')
-
survey_questions (Otázky)
id: UUIDsurvey_id: UUID (FK -> surveys.id)question_text: Textquestion_type: Enum ('yes_no', 'single_choice', 'multiple_choice', 'text')order: Int
-
survey_options (Možnosti odpovědí)
id: UUIDquestion_id: UUID (FK -> survey_questions.id)option_text: Textorder: Int
-
survey_responses (Odpovědi rodičů)
id: UUIDsurvey_id: UUIDquestion_id: UUIDoption_id: UUID (nullable)respondent_id: UUID (FK -> profiles.id)text_answer: Text (nullable)created_at: Timestamp
7. Audit Log
- audit_logs (Auditní stopa — právní pojistka)
id: UUIDuser_id: UUID (FK -> profiles.id)action: Text (např. 'pickup_confirmed', 'excuse_created', 'consent_granted')entity_type: Text (např. 'attendance_records', 'excuse_notes')entity_id: UUIDdetails: JSONB (snapshot dat v okamžiku akce)ip_address: Textuser_agent: Textcreated_at: Timestamp
8. Nastavení Notifikací
- notification_preferences (Preference uživatele)
id: UUIDuser_id: UUID (FK -> profiles.id)channel: Enum ('push', 'email')category: Text (např. 'attendance', 'evidence', 'surveys', 'daily_digest')enabled: Boolean (default: true)summary_frequency: Enum ('daily', 'weekly', 'monthly') (default: 'daily') — jak často posílat souhrn.
9. Knowledge Base & FAQ
-
knowledge_documents (Indexované dokumenty z Google Drive)
id: UUIDdrive_file_id: Text (Google Drive File ID)title: Texttrust_level: Enum ('verified', 'current', 'draft')content_hash: Text (pro detekci změn při syncu)last_synced_at: Timestampcreated_at: Timestamp
-
faq_entries (Ověřené FAQ — samoučící se z dotazů rodičů)
id: UUIDquestion: Textanswer: Textsource_thread_id: UUID (FK -> communication_threads.id — dotaz, který FAQ vytvořil)approved_by: UUID (FK -> profiles.id — ředitel/zástupce)approved_at: Timestampis_published: Booleancategory: Text (např. 'stravování', 'výlety', 'pravidla')usage_count: Integer (kolikrát Sofie tuto FAQ citovala)created_at: Timestamp
10. Bezpečnost (RLS Policies)
Row Level Security (RLS) policies zajistí, že data vidí jen oprávnění uživatelé.
- profiles: Každý může číst své (nebo veřejné profily učitelů). Admin může vše.
- student_records: Pouze admin/ředitel.
- work_items: Učitel vidí svou třídu, rodič vidí své dítě.
- communication_threads: Rodič vidí jen své konverzace. Učitel vidí přiřazené tickety.
- attendance_records: Rodič vidí své dítě. Učitel vidí svou třídu.
- faq_entries: Publikované (
is_published: true) vidí všichni.
[!NOTE] Detailní RLS policies budou implementovány v migraci
0000_init_schema.sql.