Skip to content

Schul-Alltag Module — Konzept

Fuenf Module die den taeglichen Schulbetrieb digitalisieren. Alle fuenf teilen sich ein gemeinsames Datenmodell und nutzen die bestehende Prilog-Infrastruktur (Spaces, Chat, Kalender, SSE, n8n-Trigger).

Designprinzip: Jedes Feature lebt IN einem Space. Ein Space ist nicht nur ein Chatroom — er ist die digitale Entsprechung einer Schulklasse, eines Teams, einer AG. Alles was in dieser Gruppe passiert (Chat, Aufgaben, Briefe, Abwesenheiten, Umfragen) gehoert in denselben Space.


Architektur-Ueberblick

┌──────────────────────────────────────────────────────────┐
│                    Space "Klasse 4b"                      │
│                                                           │
│  ┌─────┐  ┌────────┐  ┌──────────┐  ┌─────────────────┐ │
│  │Chat │  │Aufgaben│  │ Kalender │  │  Dateien (DMS)   │ │
│  └─────┘  └────────┘  └──────────┘  └─────────────────┘ │
│                                                           │
│  ┌──────────────┐  ┌──────────┐  ┌────────────────────┐  │
│  │Elternbriefe  │  │Umfragen  │  │ Mitteilungsheft    │  │
│  │& Formulare   │  │          │  │ (pro Schueler)     │  │
│  └──────────────┘  └──────────┘  └────────────────────┘  │
│                                                           │
│  ┌──────────────────────────────────────────────────────┐ │
│  │              Abwesenheiten                            │ │
│  │  (Space-uebergreifend, aber pro Space filterbar)     │ │
│  └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────┘

Gemeinsames Datenmodell

Alle fuenf Features nutzen eine zentrale SpacePost-Tabelle als Grundlage. Ein SpacePost ist eine strukturierte Nachricht in einem Space — kein Chat-Bubble, sondern ein formales Objekt mit Typ, Antwortoptionen und Tracking.

SpacePost
├── id, spaceId, tenantId
├── type: 'letter' | 'poll' | 'form' | 'note' | 'absence'
├── title, body (Markdown)
├── authorId
├── visibility: 'all' | 'parents' | 'staff' | 'students'
├── responseType: 'none' | 'acknowledge' | 'yes_no' | 'choice' | 'form_fields'
├── responseDeadline (optional)
├── reminderSent: boolean
├── pinned: boolean
├── attachments: FileItem[]
├── createdAt, updatedAt

├── SpacePostResponse[] (Antworten/Rueckmeldungen)
│   ├── id, postId, userId
│   ├── response: 'yes' | 'no' | 'acknowledged' | JSON (Formular-Felder)
│   ├── comment (optionaler Freitext)
│   ├── createdAt

├── SpacePostReminder[] (automatische Erinnerungen)
│   ├── id, postId, sentAt, targetCount, respondedCount

└── AbsenceEntry[] (nur fuer type='absence')
    ├── id, postId, studentUserId, spaceId, tenantId
    ├── date, endDate (Zeitraum)
    ├── reason: 'sick' | 'family' | 'appointment' | 'other'
    ├── reportedBy (Eltern-UserId)
    ├── attestRequired: boolean (auto ab Tag 3)
    ├── attestReceived: boolean
    ├── acknowledgedBy (Lehrer-UserId)
    ├── createdAt

1. Elternbriefe mit Rueckmeldung

User-Flow: Lehrer

Lehrer oeffnet Space "Klasse 4b" → Tab "Briefe & Umfragen"

    ├── Klick "Neuer Brief"

    ├── Formular:
    │   ├── Titel: "Wandertag am 15. Mai"
    │   ├── Text: (Markdown-Editor, wie Chat aber laenger)
    │   ├── Anhang: Routenplan.pdf (optional)
    │   ├── Rueckmeldung: [Keine | Kenntnisnahme | Ja/Nein | Auswahl]
    │   ├── Frist: 10. Mai (optional)
    │   └── Sichtbarkeit: Nur Eltern

    ├── Klick "Senden"

    └── Brief erscheint im Space als Karte (nicht als Chat-Nachricht)
        ├── Eltern sehen ihn im Feed + als Badge
        ├── Status-Balken: "18 von 24 beantwortet"
        └── Lehrer kann Erinnerung an fehlende senden

User-Flow: Eltern

Eltern oeffnen Space "Klasse 4b" → sehen Brief-Karte oben angepinnt

    ├── Klick auf Brief → Detail-Ansicht
    │   ├── Titel + Text + Anhang
    │   ├── Antwort-Buttons: [Ja, mein Kind nimmt teil] [Nein]
    │   ├── Optionaler Kommentar: "Leon braucht Wanderschuhe"
    │   └── Klick "Absenden"

    └── Bestaetigung: "Ihre Rueckmeldung wurde gespeichert"

Lehrer-Dashboard: Rueckmeldungsuebersicht

┌─────────────────────────────────────────────────────┐
│ Wandertag am 15. Mai              Frist: 10. Mai    │
│ ████████████████████░░░░░  18/24 (75%)              │
│                                                      │
│ ✓ Ja (teilnehmen): 16                               │
│ ✗ Nein: 2                                            │
│ ○ Ausstehend: 6                                      │
│                                                      │
│ Ausstehend:                                          │
│   Familie Weber, Familie Schmidt, Familie Klein,     │
│   Familie Braun, Familie Hoffmann, Familie Lang      │
│                                                      │
│ [Erinnerung senden]  [Als PDF exportieren]           │
└─────────────────────────────────────────────────────┘

Automatische Erinnerung

  • Cron-Job prueft taeglich Posts mit responseDeadline
  • 3 Tage vor Frist: Erinnerungs-Nachricht im Chat an alle die noch nicht geantwortet haben
  • Am Tag der Frist: letzte Erinnerung
  • Erinnerung kommt als System-Nachricht im Space-Chat: "Erinnerung: Bitte geben Sie Ihre Rueckmeldung zum Wandertag ab (Frist: 10. Mai)"

2. Schnelle Umfragen / Abstimmungen

Konzept

Umfragen sind SpacePosts mit type: 'poll' und responseType: 'choice'. Die Optionen werden als JSON im Post gespeichert.

SpacePost (type: 'poll')
├── title: "Wann passt der Elternabend?"
├── body: "Bitte waehlen Sie einen Termin."
├── config: {
│     options: ["Dienstag 18:00", "Mittwoch 19:00", "Donnerstag 18:30"],
│     multiSelect: false,
│     anonymous: false,
│     showResultsBeforeVote: false,
│   }
├── responseDeadline: "2026-05-10"
└── SpacePostResponse[]
    └── response: { choice: "Dienstag 18:00" }

User-Flow: Erstellen

Lehrer → Space → Tab "Briefe & Umfragen" → "Neue Umfrage"

    ├── Frage: "Wann passt der Elternabend?"
    ├── Optionen: [+ Option hinzufuegen]
    │   ├── "Dienstag 18:00"
    │   ├── "Mittwoch 19:00"
    │   └── "Donnerstag 18:30"
    ├── Mehrfachauswahl: [Ja / Nein]
    ├── Anonym: [Ja / Nein]
    ├── Ergebnis vor Abstimmung zeigen: [Ja / Nein]
    ├── Frist: (optional)
    └── [Umfrage starten]

Ergebnis-Ansicht (Live-Update via SSE)

┌─────────────────────────────────────────────┐
│ Wann passt der Elternabend?                  │
│                                              │
│ Dienstag 18:00   ████████████░░  12 (50%)   │
│ Mittwoch 19:00   ██████░░░░░░░░   6 (25%)   │
│ Donnerstag 18:30 ██████░░░░░░░░   6 (25%)   │
│                                              │
│ 24 von 24 haben abgestimmt                  │
│                                              │
│ [Umfrage schliessen]                         │
└─────────────────────────────────────────────┘

Sonderfall: Ja/Nein-Schnellumfrage

Fuer die haeufigste Variante ("Kommt Ihr Kind zum Schulfest?") gibt es einen Shortcut: responseType: 'yes_no' braucht keine Optionen. Zwei grosse Buttons: Ja / Nein.


3. Abwesenheiten / Krankmeldungen

Konzept

Abwesenheiten sind das einzige Feature das Space-uebergreifend funktioniert. Ein Schueler kann in mehreren Spaces sein (Klasse, AG, Foerderunterricht). Eine Krankmeldung gilt fuer alle.

Die Abwesenheit wird von den Eltern gemeldet und ist an den Schueler gebunden (nicht an einen Space). Lehrer sehen sie gefiltert nach ihren Spaces.

Datenmodell

AbsenceEntry
├── id
├── tenantId
├── studentUserId     -- der abwesende Schueler (Matrix-User-ID)
├── studentName       -- Anzeigename (denormalisiert fuer Performance)
├── date              -- Ab-Datum
├── endDate           -- Bis-Datum (null = nur heute)
├── reason            -- 'sick' | 'family' | 'appointment' | 'other'
├── reasonText        -- optionaler Freitext ("Zahnarzt um 10 Uhr")
├── reportedBy        -- Eltern-User-ID
├── reportedAt
├── attestRequired    -- automatisch true wenn Dauer >= 3 Tage
├── attestReceived    -- Lehrer setzt auf true
├── attestFileId      -- optionaler Datei-Anhang (Attest-Scan)
├── acknowledgedBy    -- Lehrer-User-ID (hat zur Kenntnis genommen)
├── acknowledgedAt
├── status            -- 'reported' | 'acknowledged' | 'excused' | 'unexcused'
├── createdAt, updatedAt

Index: (tenantId, date), (studentUserId, date)

User-Flow: Eltern melden Abwesenheit

Eltern oeffnen Prilog → oben rechts: grosser roter Button
"Kind abwesend melden"

    ├── Kind auswaehlen (falls mehrere Kinder)
    │   └── Leon Mueller (Klasse 4b)

    ├── Zeitraum:
    │   ├── [Nur heute]
    │   ├── [Mehrere Tage] → Datepicker: Von ___ Bis ___

    ├── Grund:
    │   ├── [Krank]
    │   ├── [Familiär]
    │   ├── [Arzttermin]
    │   └── [Sonstiges] → Freitext

    └── [Abwesenheit melden]
        └── Bestaetigung: "Abwesenheit fuer Leon am 19.04. gemeldet.
            Die Klassenlehrerin wird benachrichtigt."

User-Flow: Lehrer — Morgen-Uebersicht

Lehrer oeffnet Space "Klasse 4b" → Tab "Anwesenheit"

┌─────────────────────────────────────────────────────┐
│ Heute: Montag, 19. April 2026                        │
│                                                      │
│ ● Anwesend: 22    ○ Abwesend: 2    ? Unbekannt: 0  │
│                                                      │
│ Abwesend:                                            │
│ ┌────────────────────────────────────────────────┐   │
│ │ 🔴 Leon Mueller      Krank     seit heute      │   │
│ │    Gemeldet von: Frau Mueller, 07:12           │   │
│ │    [Zur Kenntnis nehmen]                       │   │
│ ├────────────────────────────────────────────────┤   │
│ │ 🟡 Mia Schmidt       Arzttermin  nur heute    │   │
│ │    Gemeldet von: Herr Schmidt, 07:45           │   │
│ │    Anmerkung: "Ab 11 Uhr wieder da"           │   │
│ │    [Zur Kenntnis nehmen]                       │   │
│ └────────────────────────────────────────────────┘   │
│                                                      │
│ Langzeit-Abwesenheiten:                              │
│ ┌────────────────────────────────────────────────┐   │
│ │ 🔴 Tim Weber    Krank   15.04. - 22.04.       │   │
│ │    ⚠ Attest erforderlich (ab Tag 3)           │   │
│ │    Attest: [Noch nicht eingereicht]            │   │
│ └────────────────────────────────────────────────┘   │
│                                                      │
│ [Abwesenheit manuell eintragen]                      │
│ [Monatsuebersicht]  [Export CSV]                     │
└─────────────────────────────────────────────────────┘

Monats-Uebersicht (Klassenbuch-Ersatz)

                    April 2026
Schueler       01 02 03 04 05 ... 19 20 21 22
─────────────────────────────────────────────
Leon Mueller    ·  ·  ·  ·  ·     K  ·  ·  ·
Mia Schmidt     ·  ·  ·  ·  ·     A  ·  ·  ·
Tim Weber       ·  ·  ·  ·  ·     K  K  K  K
Emma Braun      ·  ·  F  ·  ·     ·  ·  ·  ·
─────────────────────────────────────────────
K = Krank, A = Arzttermin, F = Familiaer, · = Anwesend

Attest-Automatik

  • Cron-Job prueft taeglich alle offenen Abwesenheiten
  • Wenn endDate - date >= 3 TageattestRequired = true
  • Wenn attestRequired und kein Attest nach 5 Tagen → Erinnerung an Eltern
  • Eltern koennen Attest als Foto/PDF hochladen → attestFileId gesetzt

Benachrichtigungen

  • Eltern meldet Abwesenheit → System-Nachricht im Klassen-Space: "Leon Mueller wurde fuer heute als krank gemeldet."
  • Lehrer nimmt zur Kenntnis → Eltern erhalten Bestaetigung
  • Attest-Erinnerung → Chat-Nachricht an Eltern

Sekretariats-Ansicht (Space-uebergreifend)

Schulleitung / Sekretariat sieht eine Gesamtuebersicht aller Klassen:

┌─────────────────────────────────────────────┐
│ Abwesenheiten heute — Gesamtschule          │
│                                              │
│ Klasse 1a:  1 abwesend (Sophie K.)          │
│ Klasse 2b:  0 abwesend                      │
│ Klasse 3a:  3 abwesend                      │
│ Klasse 4b:  2 abwesend (Leon M., Mia S.)   │
│                                              │
│ Gesamt: 6 von 312 Schuelern (1,9%)          │
└─────────────────────────────────────────────┘

4. Digitales Mitteilungsheft

Konzept

Das Mitteilungsheft ist ein privater Kanal zwischen Klassenlehrer und Eltern eines bestimmten Schuelers. Es ersetzt das gelbe Heft.

Technisch ist es ein SpacePost mit type: 'note' und einer Referenz auf den Schueler. Nur der Klassenlehrer und die Eltern des Schuelers sehen die Eintraege.

MitteilungsheftEntry
├── id
├── tenantId
├── spaceId           -- Klassen-Space
├── studentUserId     -- der betroffene Schueler
├── authorId          -- Lehrer oder Eltern
├── direction         -- 'school_to_home' | 'home_to_school'
├── content           -- Text (kurz, max 1000 Zeichen)
├── category          -- 'info' | 'request' | 'praise' | 'concern'
├── acknowledgedAt    -- Gegenseite hat gelesen
├── acknowledgedBy
├── createdAt

User-Flow: Lehrer schreibt Mitteilung

Lehrer → Space "Klasse 4b" → Tab "Mitteilungsheft"

    ├── Schueler-Liste mit Badges (ungelesene Antworten)
    │   ├── Leon Mueller          (1 neue Antwort)
    │   ├── Mia Schmidt
    │   ├── Tim Weber             (Attest ausstehend)
    │   └── ...

    ├── Klick auf "Leon Mueller"

    └── Chat-aehnliche Ansicht (aber formal):
        ┌─────────────────────────────────────────────┐
        │ Leon Mueller — Mitteilungsheft               │
        │                                              │
        │ 📤 14.04. (Schule → Eltern)                │
        │ Leon hat heute seine Sportsachen vergessen.  │
        │ Bitte morgen mitbringen.                     │
        │ Kategorie: Hinweis                           │
        │ ✓ Gelesen am 14.04. um 18:23                │
        │                                              │
        │ 📥 15.04. (Eltern → Schule)                │
        │ Danke fuer den Hinweis, Sportsachen sind     │
        │ eingepackt.                                  │
        │ ✓ Gelesen am 15.04. um 07:45                │
        │                                              │
        │ ┌──────────────────────────────────────────┐ │
        │ │ Neue Mitteilung...                       │ │
        │ │ Kategorie: [Hinweis ▾]                   │ │
        │ │                         [Senden]         │ │
        │ └──────────────────────────────────────────┘ │
        └─────────────────────────────────────────────┘

User-Flow: Eltern

Eltern oeffnen Prilog → sehen Badge am Space "Klasse 4b"

    ├── Tab "Mitteilungsheft"
    │   └── Nur Eintraege fuer das eigene Kind sichtbar

    ├── Neue Mitteilung von der Schule:
    │   "Leon hat seine Sportsachen vergessen"
    │   [Gelesen ✓]  ← 1-Klick-Bestaetigung

    └── Antwort schreiben (optional)

Datenschutz

  • Eltern sehen NUR die Eintraege ihres eigenen Kindes
  • Lehrer sehen alle Eintraege ihrer Klasse
  • Eintraege werden nach Schuljahresende archiviert
  • Kein anderer Schueler, kein anderer Elternteil sieht fremde Eintraege

Kategorien mit Icons

KategorieIconBeispiel
infoℹ️"Morgen unterrichtsfrei"
request📋"Bitte Sportsachen mitbringen"
praise"Leon hat heute toll mitgemacht"
concern⚠️"Leon war heute sehr unruhig"

5. Formulare / Einverstaendniserklaerungen

Konzept

Formulare sind SpacePosts mit type: 'form' und strukturierten Feldern. Der Lehrer erstellt ein Formular aus einer Vorlage oder frei, die Eltern fuellen es digital aus — das ersetzt die Zettelwirtschaft.

SpacePost (type: 'form')
├── title: "Einverstaendnis Schwimmunterricht"
├── body: "Hiermit erklaere ich, dass mein Kind..."
├── config: {
│     fields: [
│       { key: "childCanSwim", type: "yes_no", label: "Kann Ihr Kind schwimmen?", required: true },
│       { key: "healthNotes", type: "text", label: "Gesundheitliche Hinweise", required: false },
│       { key: "emergencyPhone", type: "phone", label: "Notfall-Telefon", required: true },
│       { key: "consent", type: "checkbox", label: "Ich bin einverstanden", required: true },
│     ],
│     requireSignature: true,   -- digitale "Unterschrift" (Name + Datum)
│     template: "swimming",     -- Vorlage-ID (fuer Wiederverwendung)
│   }
├── responseDeadline: "2026-05-01"
└── SpacePostResponse[]
    └── response: {
          "childCanSwim": "yes",
          "healthNotes": "Keine",
          "emergencyPhone": "0151-12345678",
          "consent": true,
          "signature": { "name": "Maria Mueller", "date": "2026-04-22" }
        }

Feld-Typen

TypDarstellungValidierung
textEinzeilige TexteingabeOptional min/max Laenge
textareaMehrzeiliges TextfeldOptional max Laenge
yes_noZwei Buttons: Ja / NeinRequired
checkboxCheckbox mit LabelMuss angehakt sein wenn required
choiceDropdown oder Radio-ButtonsEine Option muss gewaehlt sein
dateDatepickerGueltiges Datum
phoneTelefon-EingabeTelefonnummer-Format
numberZahleneingabeOptional min/max
signatureName + Datum (auto-generiert)Pflichtfeld

Vorlagen-Bibliothek

Vordefinierte Formulare pro Einrichtungstyp (wie bei Notfallplaenen):

Schule:

  • Einverstaendnis Schwimmunterricht
  • Einverstaendnis Ausflug/Klassenfahrt
  • Einverstaendnis Foto-/Videoaufnahmen
  • Medikamentengabe-Erlaubnis
  • Abmeldung vom Religionsunterricht
  • Einverstaendnis Mediennutzung

Kita:

  • Einverstaendnis Sonnencreme-Auftrag
  • Abholberechtigung (Personen-Liste)
  • Allergien und Unvertraeglichkeiten
  • Einverstaendnis Waldtag
  • Schlafzeiten-Vereinbarung

Altersheim:

  • Einverstaendnis Medikamenten-Aenderung
  • Einverstaendnis Aktivitaeten-Teilnahme
  • Kontaktdaten Angehoerige aktualisieren

User-Flow: Formular erstellen

Lehrer → Space → Tab "Briefe & Umfragen" → "Neues Formular"

    ├── Vorlage waehlen:
    │   ├── "Einverstaendnis Schwimmunterricht" (vorgefuellt)
    │   ├── "Einverstaendnis Ausflug" (vorgefuellt)
    │   └── "Leer — eigenes Formular"

    ├── Formular anpassen:
    │   ├── Titel aendern
    │   ├── Text anpassen
    │   ├── Felder hinzufuegen/entfernen/umordnen
    │   ├── Digitale Unterschrift: [Ja / Nein]
    │   └── Frist setzen

    └── [Formular senden]

User-Flow: Eltern fuellen aus

Eltern → Space → sehen Formular-Karte

    ├── Klick → Formular oeffnet sich
    │   ├── Ueberschrift + Erklaerungstext
    │   ├── Felder ausfuellen
    │   ├── Unterschrift: "Maria Mueller" (auto-Datum)
    │   └── [Absenden]

    └── Bestaetigung: "Formular eingereicht"

Lehrer-Uebersicht

┌─────────────────────────────────────────────────────┐
│ Einverstaendnis Schwimmunterricht   Frist: 01.05.   │
│ ████████████████░░░░░░░░  16/24 eingereicht (67%)   │
│                                                      │
│ Ergebnisse:                                          │
│ ├── Kind kann schwimmen:  Ja: 14, Nein: 2           │
│ ├── Gesundl. Hinweise:    3 Eintraege                │
│ └── Alle Unterschriften:  16 vorhanden               │
│                                                      │
│ Ausstehend: 8 Familien                               │
│ [Erinnerung senden]  [Alle Antworten als PDF]        │
└─────────────────────────────────────────────────────┘

Gemeinsame Infrastruktur

Tab-Struktur im Space

Der Space bekommt neben Chat, Aufgaben, Kalender, Dateien einen neuen Tab: "Briefe & Umfragen". Dieser Tab zeigt alle SpacePosts (Elternbriefe, Umfragen, Formulare) in einer chronologischen Liste mit Filter.

Abwesenheiten bekommen einen eigenen Tab: "Anwesenheit".

Mitteilungsheft bekommt einen eigenen Tab: "Mitteilungsheft" (nur fuer Mitarbeiter sichtbar; Eltern sehen es als separate Ansicht fuer ihr Kind).

SSE Events

EventTrigger
post.createdNeuer Brief/Umfrage/Formular
post.responseJemand antwortet/stimmt ab
post.reminderErinnerung gesendet
absence.reportedEltern melden Abwesenheit
absence.acknowledgedLehrer bestaetigt
note.createdNeue Mitteilung im Heft
note.acknowledgedGelesen-Bestaetigung

Berechtigungen

AktionMitarbeiterElternSchueler
Brief/Umfrage/Formular erstellenJaNeinNein
Auf Brief/Umfrage/Formular antwortenJaJaNein
Abwesenheit meldenNeinJaNein
Abwesenheit einsehen (eigene Klasse)JaNur eigenes KindNein
Mitteilung schreibenJaJa (Antwort)Nein
Mitteilung lesenJa (alle Schueler)Nur eigenes KindNein

n8n-Integration (Pro)

Jeder Event kann als n8n-Trigger genutzt werden:

  • "Wenn Krankmeldung eingeht → Email an Sekretariat"
  • "Wenn Formular-Frist ablaeuft und < 80% → Erinnerung an Eltern"
  • "Wenn Abwesenheit > 5 Tage → Schulleitung informieren"
  • "Wenn neuer Brief → Push-Notification (wenn PWA installiert)"

Kalender-Integration

  • Abwesenheiten erscheinen im Klassen-Kalender
  • Formular-Fristen erscheinen als Kalender-Event
  • Elternabend-Umfrage → Gewinner-Termin wird automatisch als Event angelegt

Chat-Integration

  • Briefe/Umfragen werden als System-Nachricht im Space-Chat angezeigt (nicht als voller Text, sondern als Link-Vorschau mit Titel + Status)
  • Erinnerungen werden als Chat-Nachricht gesendet
  • Abwesenheits-Meldungen erscheinen als kurze Info im Klassen-Chat

Datenbank-Schema (SQL)

sql
-- ═══════════════════════════════════════════════════════════
-- SpacePosts: Elternbriefe, Umfragen, Formulare
-- ═══════════════════════════════════════════════════════════

CREATE TABLE space_posts (
    id              VARCHAR(50)  PRIMARY KEY,
    space_id        VARCHAR(50)  NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
    tenant_id       VARCHAR(64)  NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    type            VARCHAR(20)  NOT NULL,  -- 'letter' | 'poll' | 'form'
    title           VARCHAR(500) NOT NULL,
    body            TEXT,
    config          JSONB        NOT NULL DEFAULT '{}',
    author_id       VARCHAR(255) NOT NULL,
    visibility      VARCHAR(20)  NOT NULL DEFAULT 'all',
    response_type   VARCHAR(20)  NOT NULL DEFAULT 'none',
    response_deadline TIMESTAMP(3),
    reminder_sent   BOOLEAN      NOT NULL DEFAULT false,
    pinned          BOOLEAN      NOT NULL DEFAULT false,
    closed          BOOLEAN      NOT NULL DEFAULT false,
    created_at      TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at      TIMESTAMP(3) NOT NULL
);

CREATE INDEX space_posts_space_id_idx ON space_posts(space_id, created_at DESC);
CREATE INDEX space_posts_tenant_id_idx ON space_posts(tenant_id, type);

CREATE TABLE space_post_responses (
    id          VARCHAR(50)  PRIMARY KEY,
    post_id     VARCHAR(50)  NOT NULL REFERENCES space_posts(id) ON DELETE CASCADE,
    user_id     VARCHAR(255) NOT NULL,
    response    JSONB        NOT NULL,  -- { choice: "Ja" } oder { field1: "wert", ... }
    comment     TEXT,
    created_at  TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,

    UNIQUE(post_id, user_id)
);

CREATE INDEX space_post_responses_post_id_idx ON space_post_responses(post_id);

-- ═══════════════════════════════════════════════════════════
-- SpacePost-Templates: Wiederverwendbare Vorlagen
-- ═══════════════════════════════════════════════════════════

CREATE TABLE space_post_templates (
    id              VARCHAR(50)  PRIMARY KEY,
    tenant_id       VARCHAR(64)  NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    type            VARCHAR(20)  NOT NULL,
    title           VARCHAR(500) NOT NULL,
    body            TEXT,
    config          JSONB        NOT NULL DEFAULT '{}',
    facility_type   VARCHAR(50),  -- 'schule', 'kita', etc. — NULL = alle
    is_system       BOOLEAN      NOT NULL DEFAULT false,
    created_at      TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);

-- ═══════════════════════════════════════════════════════════
-- Abwesenheiten
-- ═══════════════════════════════════════════════════════════

CREATE TABLE absence_entries (
    id                VARCHAR(50)  PRIMARY KEY,
    tenant_id         VARCHAR(64)  NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    student_user_id   VARCHAR(255) NOT NULL,
    student_name      VARCHAR(255) NOT NULL,
    date              DATE         NOT NULL,
    end_date          DATE,
    reason            VARCHAR(30)  NOT NULL DEFAULT 'sick',
    reason_text       TEXT,
    reported_by       VARCHAR(255) NOT NULL,
    reported_at       TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    attest_required   BOOLEAN      NOT NULL DEFAULT false,
    attest_received   BOOLEAN      NOT NULL DEFAULT false,
    attest_file_id    VARCHAR(50)  REFERENCES file_items(id),
    acknowledged_by   VARCHAR(255),
    acknowledged_at   TIMESTAMP(3),
    status            VARCHAR(20)  NOT NULL DEFAULT 'reported',
    created_at        TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at        TIMESTAMP(3) NOT NULL
);

CREATE INDEX absence_entries_tenant_date_idx ON absence_entries(tenant_id, date);
CREATE INDEX absence_entries_student_idx ON absence_entries(student_user_id, date);

-- ═══════════════════════════════════════════════════════════
-- Mitteilungsheft
-- ═══════════════════════════════════════════════════════════

CREATE TABLE mitteilungsheft_entries (
    id               VARCHAR(50)  PRIMARY KEY,
    tenant_id        VARCHAR(64)  NOT NULL REFERENCES tenants(id) ON DELETE CASCADE,
    space_id         VARCHAR(50)  NOT NULL REFERENCES spaces(id) ON DELETE CASCADE,
    student_user_id  VARCHAR(255) NOT NULL,
    author_id        VARCHAR(255) NOT NULL,
    direction        VARCHAR(20)  NOT NULL,  -- 'school_to_home' | 'home_to_school'
    content          TEXT         NOT NULL,
    category         VARCHAR(20)  NOT NULL DEFAULT 'info',
    acknowledged_at  TIMESTAMP(3),
    acknowledged_by  VARCHAR(255),
    created_at       TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX mitteilungsheft_space_student_idx
    ON mitteilungsheft_entries(space_id, student_user_id, created_at DESC);

Umsetzungs-Reihenfolge

PhaseModulAufwandErgebnis
ASpacePost-Grundgeruest + Elternbriefe~5-6 TageBriefe mit Rueckmeldung + Fortschrittsbalken
BUmfragen (Erweiterung SpacePost)~3-4 TageJa/Nein + Mehrfachauswahl + Live-Ergebnis
CAbwesenheiten~5-6 TageEltern-Meldung + Lehrer-Uebersicht + Monatsansicht
DMitteilungsheft~4-5 TageSchueler-bezogener Lehrer-Eltern-Kanal
EFormulare~5-6 TageFormular-Builder + Vorlagen + digitale Unterschrift
FVorlagen-Bibliothek + Erinnerungs-Cron~2-3 TageSystem-Vorlagen + automatische Erinnerungen

Gesamt: ~24-30 Arbeitstage (~5-6 Wochen)

Empfohlene Reihenfolge: A → B → C → D → E → F

Phase A und B teilen sich das SpacePost-Modell und koennen schnell hintereinander gebaut werden. Phase C (Abwesenheiten) ist eigenstaendig. Phase D (Mitteilungsheft) baut auf dem Space-Kontext auf. Phase E (Formulare) erweitert SpacePost um den Formular-Builder. Phase F (Vorlagen) ist Polish.