Das Verlassen eines unveränderten Punktefelds löste Autosave aus; leere Zellen
wurden als 0 gespeichert und ergaben Note 6. Zellen melden nur noch echte
Änderungen, Zeilen ohne Werte werden nicht angelegt und haben keine Note.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
GroupMembership.IsSupportStudent markiert Förderschüler unabhängig von der
Niveaudifferenzierung (Checkbox-Spalte in der Schülerliste; in differenzierten
Gruppen zählt das Förderniveau). Punkteeingabe und Deckblätter einer
Förderarbeit zeigen nur Förderschüler und Schüler mit vorhandenem Ergebnis.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Neben Wiederholung und Nachschreibarbeit gibt es im Arbeitsdialog die Art
Förderarbeit (Exam.IsSupportWork). Sie darf am Tag der ersten Arbeit liegen,
übernimmt dessen Datum als Vorschlag und ersetzt wie eine Nachschreibarbeit
nur fehlende Noten.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ein Klassensatz dauert spürbar und fror den Dialog ein. GenerateAsync
setzt jetzt per Task.Run, RenderBatchToPdf meldet jeden gesetzten
Datensatz über ein optionales IProgress<int>. Das abschließende
Document.Merge meldet nichts, dort läuft der Balken unbestimmt.
Währenddessen sind die Schaltflächen gesperrt und der Dialog bleibt
offen. Ein einzelnes Deckblatt wird nicht mehr doppelt gesetzt.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der interne Klausurtitel passt nicht immer aufs Deckblatt. Das neue Feld
ist mit ihm vorbelegt, ändert nur Exam.Title für diesen Druck und fällt
leer gelassen auf den internen Titel zurück.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Der Container wurde horizontal auf die Textbreite geschrumpft, sodass die
Ausrichtung wirkungslos blieb. Der Auswahlrahmen für TEXT im Designer folgt
jetzt w= bzw. der Zeilenbreite bei align=center/right.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Platzhalterkatalog und Tabellen-Zeichner liegen jetzt in LehrerApp.Templating,
damit Designer und Hauptapp dieselbe Tabelle zeichnen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neuer Dialog "Deckblätter…" bei Klausuren, Punktetabelle als Drawing mit
festen Spaltenbreiten, FLOWDRAWBOX-Attribut fit=content, Stapel-Rendering
mit Seitenzahl je Datensatz, Kursbezeichnung und konfigurierbares Kürzel.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ein Zwischenstand ist ein Durchgang aus Stichtag, Anlass und
Schülerauswahl (ganze Gruppe, Teilgruppe oder Einzelfall, mit
Schnellfilter für gefährdete Schüler). Der Zeugnisnoten-Assistent geht
die gewählten Schüler im Zwischenstand-Modus durch und notiert
vorläufige schriftliche, mündliche und Gesamtnote samt Notiz.
Gespeichert wird das als eigenes Modell InterimGrade, getrennt von der
Zeugnisnote. Die Berechnung endet am Stichtag und rechnet den laufenden
Mitarbeits-Abschnitt mit ein. Zwischenstände erscheinen im Assistenten
als Liste und Marker im Verlauf sowie als graue Spalte in der
Notenübersicht (nicht in "Gesamt", nicht im PDF).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neuer Assistent (Einstieg im Zeugnisnoten-Dialog) geht die Lerngruppe
Schüler für Schüler durch: berechnete Note mit ungerundetem Wert und
Teilbereichen, Mitarbeitsgraph abschnittsweise oder als Verlauf, Arbeiten
und Einzelnoten. Das 1. Halbjahr erscheint im 2. Halbjahr nur als Kontext.
Die Endjahresnote wird jetzt in Dialog und Assistent aus den
Halbjahresnoten verrechnet (gemeinsamer ReportGradeCalculator). In Klasse 10
kommen Projektprüfung, schriftliche/mündliche Abschlussprüfung und
zusätzliche mündliche Prüfung hinzu, gewichtet nach Oberschulverordnung und
PrüfV Sek. I; gerundet wird dabei bewusst nicht automatisch.
Die Zeitleisten-Erzeugung des Mitarbeits-Assistenten liegt dafür im
gemeinsamen ParticipationTimelineBuilder.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Neuer Dialog ExamRevealDialog: zeigt zunächst nur den Namen eines Schülers,
erst nach „Aufdecken“ Note, Punktzahl und Punkte je Aufgabe. Blättern und
gezielte Auswahl oben; jeder Schülerwechsel deckt wieder zu. Erreichbar über
„Einzelansicht“ im Klausuren-Tab und auf der Klausuren-Hauptseite.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Nachschreibarbeiten nutzen die Wiederholungs-Verknüpfung, ersetzen aber nur
fehlende Noten; mehrere Folgearbeiten je erster Arbeit sind möglich.
Exam.Kind trennt Klausuren (schriftlich) von Tests u. Ä. (Sonstige).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- "Enter springt: Schüler für Schüler / Aufgabe für Aufgabe" im Dialog wählbar und gemerkt;
Umschalt+Enter zurück, Pfeiltasten springen direkt und öffnen das Eingabefeld
- Tasten per Tunnel-Handler abgefangen, bevor DataGrid/TextBox sie auswerten
- Abwesende Schüler und Aufgaben der anderen Fassung werden übersprungen
- Zellen lesen ihre Zeile aus dem DataContext (recycelte Zeilen schreiben nicht mehr falsch)
- Bonusaufgaben zählen bei der angezeigten Nummerierung nicht mit
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entschärfte Warnungen (zurückgestellt oder Vorgang in Bearbeitung) liefen
bisher grau am Ende ihrer Art-Gruppe mit und zählten weiter zu den offenen
Punkten. Sie stehen jetzt in einer eingeklappten "Zurückgestellt"-Gruppe
ganz unten, mit dem Grund als Untertitel, und zählen nicht mehr mit. Nach
Fristablauf kehren sie automatisch in ihre Gruppe und die Zählung zurück.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Eine auf einem Gerät zurückgestellte Warnung stand auf den anderen weiter
rot oben, weil DashboardWarningSnooze bewusst lokal gehalten war. Save löst
jetzt db.OnChange aus, EventApplier übernimmt den Typ. Die Id wird aus
(StudentId, WarningTag) abgeleitet, damit zwei Geräte denselben Datensatz
beschreiben statt am Unique-Index ux_student_tag zu kollidieren;
Schema-Migration 7 schlüsselt bestehende lokale Einträge um.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ein Dokumentationseintrag kann jetzt weitere Schüler*innen betreffen
(Documentation.AdditionalStudentIds, StudentId bleibt Hauptperson). Der
Eintrag existiert nur einmal, erscheint aber im Dokumentations-Tab jeder
beteiligten Person. Der Dokumentations-Dialog bietet in beiden
Vorgänge-Tabs "Betrifft außerdem" mit den Beteiligten des Vorgangs an.
Klassenlehrer-Listen, WebUntis-Abgleich, Löschfristen und
Referenzzählung berücksichtigen die weiteren Beteiligten.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Dashboard warnings (attendance, homework, lateness) get a "Details" flyout
with key figures, a list of dates and the compact month calendar from the
class teacher overview, now extracted as a shared control. The calendar
now aligns days under their weekday (Mo-So header, blank leading cells).
Creating Vorgänge and documentation is supported by quick blocks with the
current figures, dated standard phrases (e.g. "Klassenleitung informiert")
and documentation templates (status snapshot, conversation, informing the
class/subject teachers, parent call, parent letter). The class teacher
Vorgänge tab uses WebUntis figures (absences across all subjects, class
register) for the same blocks and templates.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Cross-class warnings (attendance, homework backlog, lateness) stayed red
and at the top even after being acted on. A warning now turns gray and
sorts to the bottom of its group once a recently-updated open Vorgang
with a matching tag exists, or once explicitly snoozed for 1/2/4 weeks.
Both are time-limited: once the grace period lapses without the
underlying number actually improving, the warning goes active again on
the next dashboard load - no background job needed since it's just
recomputed on every RebuildAttention.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Dashboard warnings (attendance, and now homework backlog and lateness) apply
across all classes, but the existing Vorgänge case-file tab only works for
the teacher's own class since it resolves the WebUntis classbook roster.
Instead of loosening that coupling, students get their own narrower
Vorgänge tab, and all three cross-class warnings now jump straight there,
offering to open a matching case or create a new one.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
ai_backend_call_and_charge (db.php) hob PHPs eigenes max_execution_time
nie an, obwohl AnthropicProvider dem curl-Aufruf bis zu 180s erlaubt.
Auf vielen Hosts liegt PHPs Default bei nur 30s - sobald ein Aufruf
laenger brauchte, killte PHP das Skript mitten in curl_exec() mit einem
unabfangbaren Fatal Error statt einer sauberen {"error": "..."}-Antwort.
Der Desktop-Client zeigte dadurch nur die pauschale Fallback-Meldung
ohne Grund - sah wie ein kompletter Ausfall der Einzelstunden-KI-Planung
aus, war aber ein request-Dauer-abhaengiger Timeout, der jeden der fuenf
ai_backend_call_and_charge-Endpunkte treffen konnte.
Fix zentral in ai_backend_call_and_charge (set_time_limit(200)) statt in
jedem Endpunkt einzeln - nach Deployment vom Nutzer verifiziert. Zusaetzlich
dauerhaftes Diagnose-Logging in AiPlanningService (Statuscode/Dauer/
Antwort-Body bei Fehlern ohne auswertbaren Grund) fuer kuenftige Faelle.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Klassenstufe (90px) + Bildungsplan-Version (160px) + die drei Buttons (JSON
importieren/exportieren, Kopieren) allein verlangten schon mehr Breite als die
MaxWidth (640) des umgebenden Panels her gab, da sie mit der Fach-Combobox in
derselben Grid-Zeile standen. Die "*"-breite Fach-Combobox wurde dadurch auf 0px
gequetscht - im Kompetenzen-Tab sichtbar war nur die (leere) Versions-Combobox,
die Fach-Auswahl selbst nicht erreichbar.
Fach/Klassenstufe/Version stehen jetzt in einer eigenen Zeile, die drei
Aktionsbuttons darunter.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Ein Sync-Ausfall (offline/Fehler) war bisher nur als blasser Text in der Statuszeile
sichtbar und konnte so stundenlang unbemerkt bleiben, bis auf einem anderen Gerät
Daten fehlten. SyncStatusViewModel meldet neue Ausfälle jetzt einmalig aktiv per Toast
(nicht bei jedem automatischen Retry erneut).
DatabaseEncryptionService.IsEncrypted/VerifyPassword öffneten die Datenbankdatei mit
einer zweiten, exklusiven (Direct) LiteDB-Verbindung, während LiteDbContext dieselbe
Datei bereits im Shared-Modus offen hält - jeder Aufruf (z.B. beim Öffnen der
Einstellungen) crashte reproduzierbar mit IOException. Beide öffnen jetzt ebenfalls im
Shared-Modus und erzwingen einen tatsächlichen Lesezugriff, da Shared-Verbindungen die
Datei lazy öffnen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Die Server-API cached users.db im laufenden Prozess; ein externer Schreib-
zugriff der CLI wird erst nach einem Container-Neustart wirksam.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Manuelle Einzelerfassung je Kompetenz war im Alltag zu aufwendig (Nutzer-Feedback). Neue
ParticipationCompetencyEstimate mittelt die bereits erfassten Aspekt-Bewertungen der Sitzung
(normiert auf dieselbe -2..+2-Achse) und rundet auf den nächsten Schritt; die Tagesflagge wirkt
symmetrisch (Spitzentag hebt, Schlaftag/Schlechter Tag senken gleichermaßen).
Die Schätzung wird nie automatisch gespeichert - sie erscheint nur als abgeschwächt dargestellter
Zellenwert (RatingCell.IsEstimated), solange keine explizite Bewertung existiert. Ein Klick setzt
den Wert bewusst und persistiert ihn wie bisher.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Mitarbeit-Sitzungen waren bisher komplett MCP-unerreichbar. Neue ParticipationTools-Klasse
exponiert get_participation_sessions (Datum, Kommentar, zugeordnete Kompetenzen) sowie
add_session_competency/remove_session_competency, nach demselben Einzel-Zuordnung-Muster wie
LessonPlanTools. Bewusst ohne die einzelnen Schülerbewertungen (ParticipationEntry) - die bleiben
personenbezogen und MCP-unerreichbar.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Unit/Lesson/ExamTask/ParticipationSession referenzierten Kompetenzen bisher per Freitext-Code,
case-insensitiv gegen den Katalog gematcht - fragil bei Umbenennungen und seit der
Bildungsplan-Versionierung nicht mehr eindeutig (zwei Versionen können denselben Code vergeben).
Neuer Werttyp CompetencyReference (ItemId + Code/Description-Momentaufnahme) löst das: solange die
Id noch im Katalog auflösbar ist, zählt die live Fassung (Rename wirkt sofort), sonst bleibt die
gespeicherte historische Fassung sichtbar statt spurlos zu verschwinden.
Migration (Schema-Version 6) löst bestehende Codes gegen den Katalog auf; die zuvor dreifach
duplizierte Kompetenz-Tag-UI ist jetzt in CompetencyTagGroupBuilder konsolidiert.
add_lesson_competency/remove_lesson_competency nehmen jetzt itemId statt code und validieren gegen
den Katalog (vorher ungeprüft).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue Bildungspläne wachsen je Fach klassenstufenweise hoch, sodass Kurse abhängig vom
Einschulungsjahr entweder dem alten oder dem neuen Bildungsplan folgen. CompetencyCatalogVersion
(Fach + Name + IsDefault) macht das abbildbar: CompetencyDomain bekommt eine VersionId, Kurse
wählen über LearningGroup.CompetencyCatalogVersionId (null = Standardversion des Fachs) welche
Version gilt. Migration legt für bestehende Kataloge automatisch eine Standardversion an, damit
alte Datenbanken unverändert weiterlaufen.
MCP: neue Tools für Versions-CRUD (get/create/update/delete_competency_plan_version,
update_group_competency_version), get_competency_catalog/create_competency_domain um optionalen
versionId-Parameter erweitert.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Samstage/Sonntage sind normalerweise keine Schultage - "keine Fehlzeit" dort
ist keine Leistung und soll nicht optisch gleichwertig neben echten
Schultag-Einträgen stehen. Tageskacheln für Sa/So ohne Signal bekommen jetzt
einen helleren Rahmen/Hintergrund und blasseren Text; ein tatsächlicher
Eintrag an einem Wochenendtag bleibt unverändert farbig, da er echte
Information trägt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Chronologische Liste splittet ab 4 Zeilen in zwei Spalten (erste Hälfte
links, Rest rechts), sofern die Box mindestens zwei komfortable Spalten
zulässt (>= 2x Referenzbreite + Zwischenraum) - sonst blieben Datum/Umfang/
Status pro Hälfte zu schmal. Halbiert die benötigte Höhe bei längeren Listen
etwa, was der vom Nutzer beobachteten unerklärlichen Leerseite bei einer sehr
langen einspaltigen FLOWDRAWBOX entgegenwirken sollte.
Bei der Gelegenheit einen Bug aus dem vorherigen Commit gefixt: der
Refactor auf die gemeinsame DrawRows()-Hilfsfunktion hatte eine doppelte,
inzwischen tote Kopfzeilen-Zeichnung übrig gelassen (sichtbar als
doppeltes "Datum" in den Draw-Befehlen).
Hinweis: die reale Vorlage dieses Nutzers deklariert die FLOWDRAWBOX für
Student.AbsenceDays aktuell nur mit 170 statt z.B. 400+ Einheiten Breite -
dort bleibt es also weiterhin bewusst einspaltig, bis die Box verbreitert
wird.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Die Spaltenpositionen/-breiten wurden fälschlich zusätzlich mit
millimeterScale multipliziert, so als wären es eigene mm-Maße - bei einer in
"pt" deklarierten Vorlage (millimeterScale ≈ 2.83) lag z.B. die Status-Spalte
dadurch bei x≈323 in einer nur 170 Einheiten breiten Box, weit außerhalb des
sichtbaren Bereichs. Das erklärt die "zerschossene" Tabelle.
Spalten sind jetzt Anteile von contentWidth (das bereits die reale, korrekte
Boxbreite in der Koordinaten-Einheit der Vorlage ist) statt eigener,
zusätzlich umzurechnender mm-Werte - nur echte Y-Maße (Zeilenhöhe, Abstände)
brauchen weiterhin millimeterScale.
Zusätzlich wie beim Anwesenheitskalender: kein eigener "Fehltage"-Titel mehr,
der Name bleibt klein/hellgrau nur zur Kontrolle - reduziert den Höhen-
Overhead pro Seite etwas, hilft aber nur begrenzt gegen mehr benötigte Seiten
bei vielen Fehltagen, da Zeilen jetzt korrekt physisch groß (statt vorher zu
klein) gerendert werden.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
"Anwesenheit" als eigene Überschrift entfernt - die Monatsnamen im Raster
machen bereits klar, worum es geht. Trailing-Gap vor der Legende von 4mm auf
2mm, Abstand nach dem Schülernamen von 1mm auf 0.5mm reduziert.
Der Höhen-Overhead im Referenzentwurf sinkt dadurch von 45mm auf 36.5mm (vor
den Wochenzeilen) und vergrößert entsprechend den gemeinsamen Skalierungs-
faktor k, wenn die Boxhöhe der begrenzende Faktor ist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Titel ("Anwesenheit") und Schülername dienen nur der Kontrolle, dass der
Kalender zum richtigen Kind gehört - nicht als gestalterischer Blickfang.
Beide jetzt klein und hellgrau statt groß/fett/dunkel, dazu ein eigener
(kleinerer) Y-Abstand vor der Legende statt der bisherigen Wiederverwendung
von monthGapX.
Der dadurch eingesparte Höhen-Overhead im Referenzentwurf (61mm -> 45mm vor
den Wochenzeilen) erhöht direkt den gemeinsamen Skalierungsfaktor k, wenn die
Boxhöhe der begrenzende Faktor ist - die Tageskacheln werden dadurch bei
gleicher Vorlagenbox spürbar größer.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Breite und Höhe wurden bisher getrennt behandelt (Breite = volle reale
Boxbreite, Höhe = Größenwahl*Einheitenfaktor) - bei einer Box, deren
Seitenverhältnis vom Referenzentwurf abweicht, verzerrte das die Tageskacheln
sichtbar.
Das Raster wird jetzt komplett in einem festen 170mm-Referenzentwurf
berechnet und erst am Ende mit einem einzigen Faktor k = min(a_x, a_y,
Größenwahl) * millimeterScale in die Koordinaten der Vorlage skaliert - a_x/
a_y sind die Verhältnisse von realer Boxbreite/-höhe zum Referenzentwurf.
Dadurch bleiben die Kacheln immer proportional, auf Kosten von ungenutztem
Rand auf der Achse, die nicht der begrenzende Faktor ist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nachdem die Kalender-Breite jetzt an die reale DRAWBOX/FLOWDRAWBOX-Breite
gekoppelt ist, konnte das (korrekt größer werdende) Raster die von der
Vorlage deklarierte Höhe überschreiten - eine DRAWBOX bricht anders als eine
FLOWDRAWBOX nicht automatisch auf Folgeseiten um, überschüssiger Inhalt wird
von QuestTemplateRenderer stillschweigend am unteren Rand abgeschnitten.
StudentAttendanceCalendarDrawingBuilder ermittelt jetzt vorab, wie viele
Wochen die gewählten Monate brauchen, und verkleinert "Größe" automatisch so
weit, dass der Kalender innerhalb der deklarierten Höhe bleibt (nur bei
DRAWBOX/IsFixed - eine FLOWDRAWBOX darf weiterhin frei wachsen, da sie bei
Bedarf auf weitere Seiten fließt statt abzuschneiden).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Die DrawingValue-Builder gingen bisher immer von einer festen Breite (170)
aus, unabhängig davon, wie breit die DRAWBOX/FLOWDRAWBOX in der jeweiligen
Vorlage tatsächlich deklariert ist. Bei einer breiteren Box (oder einer in
"pt" statt "mm" deklarierten Seite, wie im echten Fehlzeitenbrief-Template)
blieb dadurch ein Großteil der eigentlich verfügbaren Fläche ungenutzt leer
- sichtbar als "Luft" rechts und unterhalb des Kalenders im generierten PDF.
CreateLetterDialogViewModel/LetterTemplateTools ermitteln jetzt die real
deklarierte Boxbreite samt Maßeinheit aus dem geladenen Template
(LetterPlaceholderBuilder.FindDeclaredDrawingBox) und reichen sie an die
Builder durch, die ihr mm-entworfenes Raster entsprechend skalieren.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue DrawingCommand-Primitives DrawCircle und DrawRoundedRectangle (SVG-Rendering
plus FLOWDRAWBOX-Paginierung). Anwesenheitskalender nutzt RoundedRectangle für die
Tageskacheln und verkleinert Monatsabstand/Kachel-Innenabstand, damit die Kacheln
den Rasterplatz sichtbar besser ausfüllen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SizeToContent="Height" ohne Begrenzung ließ das Fenster beim Typ
"Elternbrief" (drei zusätzliche Felder) so hoch werden, dass der
Speichern-Button auf kleineren Bildschirmen (z.B. MacBook) nicht mehr
erreichbar war. ScrollViewer bekommt eine MaxHeight, ab der intern
gescrollt wird - analog zum bestehenden Muster in McpConfirmDialog.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Datum-Spalte in der Fehltage-Tabelle war für "dd.MM.yyyy" zu schmal
bemessen (an der kurzen Kopfzeile "Datum" orientiert) und wurde
abgeschnitten. RenderFlow erzwang außerdem zwischen den Ausschnitten
einer zu hohen Zeichenbox einen harten Seitenumbruch unabhängig vom
tatsächlich verbleibenden Platz auf der Seite - dadurch begann z.B.
der zweite Monat auf Seite 3, obwohl Seite 2 noch reichlich Platz
hatte.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Lesson bekommt ein neues Freitextfeld PlanningIdeas fuer grobe Ideen vor der
Feinplanung, sichtbar im LessonDialog und als Kontext an die KI-Planung
(Backend + MCP) durchgereicht. LessonPhaseStep.MaterialPrompt speichert den
beim Uebernehmen einer KI-Stunde erzeugten Materialerstellungs-Prompt dauerhaft,
statt ihn nur einmalig im AiAssistDialog anzuzeigen - im Verlaufsplan-Editor
ueber einen neuen Kopieren-Button je Phase erneut nutzbar, auch ueber MCP
lesbar/schreibbar.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
UntisHubJobState (Faelligkeits-Zeitstempel des Untis-Hubs) lief bisher
ausserhalb des Sync - jedes Geraet fuehrte seine eigene Buchhaltung, wodurch
auf allen Instanzen dieselben Punkte offen blieben und ein bereits erledigter
Abgleich anderswo erneut WebUntis-Traffic ausgeloest haette (Nutzer-Feedback).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
LehrerApp.Desktop und LehrerApp.McpBridge emulieren die Named Pipe unter
macOS/Linux über eine Socket-Datei unter TMPDIR. Von Finder/Dock
gestartet bekommt Desktop das reguläre Session-TMPDIR unter
/var/folders/.../T, während die Bridge als Kindprozess von Claude
Desktop oft eine reduzierte Umgebung mit TMPDIR=/tmp erbt - beide
suchten die Pipe-Datei dann an unterschiedlichen Orten und fanden sich
nie ("MCP nicht erreichbar", obwohl beide Prozesse liefen). TMPDIR wird
jetzt in beiden Prozessen vor der ersten Pipe-Instanz hart auf denselben,
von ApplicationData abgeleiteten Ordner gesetzt.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nutzer-Feedback aus echtem Live-Test der neuen Untis-MCP-Tools: groupId ist ueberall
Pflichtparameter (get_grades, get_schedule, get_lesson_plans, get_untis_absence_rows, ...), war
aber nirgends ueber MCP auflösbar - ein KI-Client kannte bestenfalls den Klarnamen einer
Lerngruppe, nie ihre Id.
- Neues GroupTools.cs mit get_groups (Read): listet Lerngruppen mit Id/Name/Typ/Schuljahr/
Klassenstufe/SubjectId/IsActive, optional nach Schuljahr gefiltert.
- UntisHubStatusRowDto liefert zusaetzlich GroupId mit (null bei den drei dashboard-weiten
Zeilen), damit fuer eine dort gelistete Gruppe nicht zusaetzlich get_groups noetig ist.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue Menü-Kategorie "Formulare" in der Menüleiste: "Elternbrief erzeugen..." öffnet
jetzt einen Schüler-Picker statt nur aus der Schülerdetailansicht erreichbar zu sein,
"Arbeitsblatt personalisieren..." ist aktiv, sobald eine einzelne Lerngruppe geöffnet
ist, und erzeugt aus einer in TemplateDesigner gebauten .lavorlage-Vorlage ein PDF je
aktivem Gruppenmitglied - über eine von den Elternbrief-Vorlagen getrennte
WorksheetTemplateStore-Bibliothek.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- UntisHubService.RecordRun: ein abgeschlossener Langzeit-Fehlzeitenabgleich schliesst die
kurzfristige Kadenz derselben Gruppe automatisch mit ab (nicht umgekehrt).
- Fehlzeitenabgleich-Dialog: neue "Uebernahme als"-ComboBox statt starrem Zielstatus, vorbelegt
mit dem berechneten Vorschlag, aber frei aenderbar.
- Neuer ai-backend-Endpunkt untis-status.php + AiPlanningService.RequestUntisStatusSuggestionsAsync:
gebuendelter, anonymisierter KI-Statusvorschlag (nur Positions-Id + Rohsignale, nie Name/Klasse/
Datum), mit hartem Id-Mengen-Abgleich gegen Verwechslung.
- Neue MCP-Tools (UntisComparisonTools): get_untis_hub_status, get_untis_absence_rows/
apply_untis_absence_status (anonymer Weg ueber ENr-Zuordnung) sowie
get_named_untis_absence_pattern als bewusste, eng begrenzte Ausnahme (Name+Fehlzeiten fuer
explizit angegebene Schueler-IDs, mit Bestaetigung ohne Sitzungsfreigabe - dafuer
IMcpConfirmationService.ConfirmAsync um allowSessionTrust erweitert).
- MapStatus/ENr-Zuordnung aus dem ViewModel in das neue, geteilte UntisLessonAbsenceHelper
gezogen, damit Dialog und MCP-Tool nie unterschiedliche Statusvorschlaege berechnen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude Desktop deaktivierte den ganzen MCP-Server, sobald der Initialize-Handshake beim
Bridge-Start fehlschlug - der Regelfall, wenn LehrerApp.Desktop (z.B. nach Windows-Autostart
von Claude Desktop) noch nicht läuft. Die Bridge ist jetzt selbst ein MCP-Server gegenüber
Claude Desktop und gleichzeitig ein MCP-Client gegenüber dem echten Server in LehrerApp.Desktop:
der Handshake gelingt dadurch immer.
Verbunden spiegelt sie die echte Werkzeugliste 1:1; ohne Verbindung bietet sie nur ein
lehrerapp_status-Werkzeug an, das den Grund erklärt und erneut verbindet. Ein Hintergrund-Loop
versucht unabhängig davon alle 5s zu reconnecten und schaltet per notifications/tools/list_changed
automatisch auf die echten Werkzeuge um, sobald LehrerApp erreichbar ist. Bricht die Verbindung
während eines laufenden Aufrufs ab, kommt ein normales Tool-Fehlerergebnis statt eines
Prozessabsturzes zurück.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue CompetencyTools.cs: create/update/delete_subject, create/update/delete_competency_domain,
add/update/remove_competency_item, get_subjects, get_competency_catalog. delete_subject und
delete_competency_domain als weitere Destructive-Ausnahmen neben delete_lesson (kein Papierkorb).
Lesson bekommt ein neues Competencies-Feld (analog zu Unit.Competencies) sowie
add_lesson_competency/remove_lesson_competency in LessonPlanTools.cs.
ICompetencyDomainRepository um GetBySubject() erweitert, um den Katalog eines Fachs ohne
bekannte Klassenstufe abzufragen.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sitzungsfreigabe: McpConfirmDialog bietet zwei Checkboxen ("diese Art
von Aktion" / "alle KI-Aktionen für den Rest der Sitzung nicht mehr
nachfragen"), nur beim Bestätigen wirksam. IMcpConfirmationService.
ConfirmAsync bekommt einen per [CallerMemberName] automatisch
befüllten operationKey - kein bestehender Aufruf musste geändert
werden. Freigaben leben als In-Memory-Bookkeeping auf der
Confirmation-Service-Instanz, gelten bis App-Ende, werden aber trotzdem
geloggt, damit stillschweigende Bestätigungen nicht spurlos bleiben.
Grund: 17 identische Bestätigungen in Folge für eine neu generierte
Unterrichtseinheit sind unzumutbar.
LessonStatus.Cancelled ("Ausgefallen") als Alternative zu
delete_lesson für Stunden, die nur ausgefallen sind (Exkursion,
Feiertag), aber als Ereignis dokumentiert bleiben sollen. Als
Cancelled=4 angehängt (bestehende LiteDB-Werte 0/1 sind fix). Konsistent
wie "bereits durchgeführt" behandelt an allen Stellen, die bisher nur
auf Conducted prüften: Terminverschiebung, Fortschrittsanzeige,
Hausaufgabe-kontrollieren-Erinnerung, "nächste Stunde"-Vorschlag.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Nach dem ersten Live-Test mit echtem Bridge-Prozess: der bisherige
ConfirmDialog fiel zu wenig auf, wenn LehrerApp im Hintergrund lief
(Normalfall, da der Anstoß vom KI-Client in einem anderen Fenster
kommt). Neuer, eigenständiger McpConfirmDialog statt Änderung am
geteilten ConfirmDialog (hätte alle anderen Aufrufer mitbetroffen):
breiter, auffälliger Kopfbereich, Topmost. AvaloniaMcpConfirmationService
holt das Hauptfenster zusätzlich aus einer möglichen Minimierung und
aktiviert es vor dem Anzeigen.
move_lesson kapselt die bereits vorhandene LessonSchedulingService.Move
(shiftFollowingLessons öffnet eine Lücke für eine neue Stunde, indem
spätere Stunden derselben Einheit mitverschoben werden) - keine neue
Terminlogik, nur Wiederverwendung.
delete_lesson ist eine bewusste, gezielte Ausnahme von "v1 ohne
Lösch-Tools" auf expliziten Nutzerwunsch: eigene
AllowedDestructiveWriteTools-Liste, Destructive=true-Annotation,
Bestätigungstext betont ausdrücklich die fehlende Papierkorb-Deckung
für Lessons.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
download_lesson_attachment deckte bisher nur die Leserichtung ab, der
Nutzer legt Arbeitsblätter aber tatsächlich über die Anhang-Funktion an
Einzelstunden ab. Neues Write-Tool nimmt Dateiname + Base64-Inhalt
entgegen, validiert vor der Bestätigungsnachfrage (leer/ungültig/zu
groß) und lädt erst nach Bestätigung hoch.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Schließt die MCP-Server-Spec ab. "Worksheets" aus der Spec entsprechen
im tatsächlichen Datenmodell den .lavorlage-Elternbrief-Vorlagen
(LehrerApp.Templating) - es gibt kein separates Arbeitsblatt-Konzept mit
Fach/Klassenstufe-Metadaten. Neue Tools list_letter_templates (Read) und
render_letter (Read, liefert Base64-PDF, kein DB-Schreibzugriff).
upload_worksheet/update_worksheet bewusst nicht umgesetzt: das
Seitenlayout ist eine eigene positionsbasierte DSL mit eigenem
visuellen Editor (LehrerApp.TemplateDesigner) - ein LLM müsste sie
blind erzeugen, mit hohem Risiko für kaputte Layouts. Platzhalter-Logik
aus CreateLetterDialogViewModel nach LetterPlaceholderBuilder extrahiert,
damit Dialog und MCP-Tool nicht auseinanderdriften.
Neuer McpClientRegistrationService trägt den Bridge-Pfad in Claude
Desktops claude_desktop_config.json ein (Button in den Einstellungen,
nie automatisch), ohne bestehende Fremdeinträge zu verlieren und ohne
eine nicht lesbare Konfigurationsdatei zu überschreiben.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Statt eines "update_lesson", das die ganze Stunde inkl. Verlaufsplan als
ein großes JSON-Objekt tauscht, gezielte kleine Tools je Teiloperation
(Nutzervorschlag): create/update_unit, create/update_lesson (Metadaten
ohne Phasen), add/update/remove_lesson_phase (je eine Phase),
download_lesson_attachment (Base64, auf 3 MB gedeckelt). Verkürzt das
Lesen-Schreiben-Zeitfenster je Operation und liefert lesbare Diffs für
den Bestätigungsdialog statt eines Objekt-Dumps.
ILessonRepository um GetById ergänzt (fehlte bisher, war aber
Voraussetzung für jedes der neuen Tools). get_lesson_plans liefert jetzt
zusätzlich Phase-IDs und Attachment-Metadaten, damit ein Client sie
gezielt referenzieren kann.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
build-macos-app.sh publiziert und platziert jetzt zusätzlich zur
Hauptapp die MCP-Bridge-Binary (Contents/MacOS/LehrerApp.McpBridge),
inklusive Universal-Binary-Handling und eigenständiger Ad-hoc-Signierung
vor dem Bundle-weiten codesign --deep-Schritt. Publish/Lipo/Kopier-Logik
dafür in eine wiederverwendbare place_binary()-Funktion extrahiert.
Nur auf Bash-Syntax geprüft (kein macOS in dieser Session verfügbar) -
noch nicht auf echtem macOS gebaut/verifiziert, siehe TODO.md 4.5.27.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Neue Write-Tools create_time_entry, create_grade_entry und
update_student_group_assignment schreiben nie direkt: jeder Aufruf zeigt
zuerst einen menschenlesbaren Bestätigungsdialog (bestehender
ConfirmDialog, über Dispatcher.UIThread aus dem Pipe-Session-Thread
angezeigt) und schreibt erst nach Bestätigung, mit 2-Minuten-Timeout
gegen eine hängende Session. Zusätzliches Read-Tool get_lesson_plans.
create_note bewusst nicht umgesetzt (kollidiert mit dem bestehenden
Dokumentations-Ausschluss aus Phase 1), create_lesson_plan/
update_lesson_plan wegen der Modellkomplexität von Lesson zurückgestellt
(siehe TODO.md 4.5.26).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Erlaubt einem lokalen KI-Client (z.B. Claude Desktop) strukturierten
Lesezugriff auf Schüler, Klausuren, Noten, Stundenplan und Zeiterfassung.
Neuer LehrerApp.McpBridge-Prozess reicht stdio-JSON-RPC über eine Named
Pipe an einen In-Process-MCP-Server im Avalonia-Hauptprozess durch
(ModelContextProtocol.Core, StreamServerTransport direkt auf der Pipe).
Standardmäßig deaktiviert, Opt-in über neuen Einstellungen-Tab.
Dokumentationstypen (Gesprächsnotizen/Vorfälle/Förderpläne) sind auf
Code-Ebene nie erreichbar (McpToolScope, analog PlainEventStore.Allowed).
Write-Tools, Bestätigungsdialog-UI, Worksheets/Lesson-Plans-Tools und
macOS-Packaging folgen in späteren Phasen (siehe TODO.md 4.5.25).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
TimeOnly.FromDateTime(DateTime.Now).AddHours(+-2) wickelt bei Mitternacht um (TimeOnly hat
keinen Datumsanteil) - je nach Ausfuehrungsuhrzeit (ca. 22:00-02:00) landete "+2 Stunden"
zeitlich vor statt nach "jetzt" oder umgekehrt, wodurch zwei Tests zufaellig rot wurden statt
das eigentliche Verhalten (Wartezeit nach Unterrichtsende) zu pruefen. Per Gegenprobe auf
unveraendertem main bestaetigt: dieselbe Flakiness besteht dort bereits.
DashboardViewModel erhaelt einen optionalen Func<DateTime>? now-Konstruktorparameter (Default
DateTime.Now, gleiches Muster wie die bereits bestehenden optionalen annualPlanEvents/
schoolWeather-Parameter) und nutzt ihn statt direkter DateTime.Now-Aufrufe in Load() und
LoadMissingTeachingTime. Die beiden betroffenen Tests injizieren jetzt einen festen
Referenzzeitpunkt (ein Feiertags-freier Dienstag im September) und sind damit unabhaengig
von der tatsaechlichen Ausfuehrungsuhrzeit deterministisch gruen.
Details siehe TODO.md, Abschnitt 9 (Dashboard).
Fasst die sieben Kacheln, die tatsaechlich "wo muss ich reagieren" beantworten
(Entschuldigungen, Fehlzeiten-Warnung, Foerderplan-Wiedervorlage, Korrekturen,
ungeplante Stunden, Auffaelligkeiten, Unterrichtszeit-Nacherfassung), zu einer
Karte "Handlungsbedarf" mit Filter-Chips zusammen statt sieben eigener
Sichtbarkeits-Schalter.
Neues gemeinsames Modell AttentionItem/AttentionGroup/AttentionAction traegt nur
Anzeigedaten - die Datenbeschaffung bleibt unveraendert in den jeweiligen
DashboardViewModel.LoadXxx-Methoden, die am Ende ein AttentionItem statt ihrer
eigenen Item-Klasse erzeugen. RebuildAttention() gruppiert nach Art (feste
Reihenfolge) und wendet Filter an, ohne die Repos erneut abzufragen.
SupportPlanDueItem, CorrectionProgressItem, UnplannedLessonItem und
DashboardAlertItem entfallen (nur dashboard-intern verwendet); OpenExcuseItem
und AttendanceWarningItem bleiben bestehen, da GroupOverviewViewModel sie
weiterhin nutzt. Fuenf Navigations-Commands wurden durch ein einziges
OpenAttentionItemCommand ersetzt.
Bewusste Verhaltensaenderung: LoadAlerts dupliziert Fehlzeiten-Ueberschreitungen
nicht mehr in die Auffaelligkeiten-Gruppe, da dieselbe Zahl sonst zweimal in
derselben Karte erschiene (vorher durch zwei getrennte Kacheln nicht sichtbar).
Details und Testanpassungen siehe TODO.md, Abschnitt 9 (Dashboard).
ApplyCardLayout() zaehlte bisher IsVisible statt EffectiveIsVisible, wodurch eine
eingeschaltete aber leere HideWhenEmpty-Kachel weiterhin einen Rasterplatz belegte.
Da im Alltag meist mehrere der sieben HideWhenEmpty-Kacheln leer sind, war das der
Normalfall, nicht die Ausnahme. UpdateDashboardSummary() setzte zudem alle IsEmpty-
Werte, ohne das Layout danach neu zu berechnen.
Zusaetzlich hatte jede Kachel ihren Grid-Margin fest im XAML verdrahtet (links/rechts),
obwohl Spalte und Zeile erst zur Laufzeit aus Sichtbarkeit und Reihenfolge berechnet
werden - beim Ausblenden einer Kachel wanderten die Nachbarn in die andere Spalte,
der Rinnstein sass dann auf der falschen Seite. DashboardCardOption.Margin leitet den
Wert jetzt aus Column ab; das XAML bindet darauf statt fixer Werte.
Drei Regressionstests decken beide Faelle ab.