Zum Inhalt springen
lehrr planrDoku

Dokumentation Entwurf

Entwurf und Begründung

Warum planr so gebaut ist, was dabei verworfen wurde und was offen bleibt. Was es tut, steht in der Nutzer-Doku.


1. Entstehungsgeschichte#

280 Commits zwischen dem 29.06.2026 und dem 26.08.2026, geschrieben neben einem vollen Deputat: 10 im Juni, 46 im Juli, 224 im August - die Sommerferien und die Woche vor Schuljahresbeginn.

Juni/Juli: Grobplanung#

Der erste Gedanke war eine Zeitachse. Ein Schuljahr hat eine feste Zahl von Unterrichtswochen, ein Fachcurriculum eine Liste von Themen mit Stundenbedarf, und dazwischen liegen Ferien, Praktika und Klassenfahrten. Die ersten dreißig Commits bauen genau das: Blöcke, die sich per Drag in der Länge ändern lassen, Meilensteine, die man zwischen Blöcken umhängt, Ferienbänder und ein Pufferzeitraum.

Am 06.07. steht die Wochen-Engine, und mit ihr das Grundmuster: Vorlage (editierbar, klassenunabhängig) und Klasse (Snapshot). Danach kommen die realen Fachcurricula hinein - Mathe 8, Physik 8, Physik 9 nach Rahmenplan MV -, und mit Physik 9 der erste Sonderfall: epochale Fächer, die nur ein Halbjahr laufen.

Ab dem 14.07. die erste Kopplung: selbr, zunächst nur lesend. Am 25.07. wird die Startseite zum Arbeitsbrett und die einzelne Doppelstunde bekommt eine Detailplanung. In derselben Woche entstehen Soll-Ist, die Schnittstelle für die Unterrichtsplanung und die Übungsblätter aus drillr.

11. bis 16. August: aus einem Werkzeug wird ein Programm#

Am 11.08. wird der echte Stundenplan 2026/27 eingepflegt - sechs Lerngruppen, Montag frei, vier davon mit A/B-Rhythmus. Aus einem Wochenschema wird eine blätterbare Kalenderwoche mit Ferien und Sperrzeiten. Am selben Tag kommen die Freigabe-Links für Kollegen und die Seitenleiste.

Am 12.08. die Betriebsgrundlagen, alle an einem Tag: Migrationen statt push, CI über GitHub Actions, Fehlermeldung per Telegram, eigene Fehlerseiten. Danach die checkr-Verknüpfung und die Präsentation je Stunde.

Vom 13. bis 16.08. der Foliensatz - erst als Formular, am 15.08. als Leinwand mit frei ziehbaren Kästen. Am 16.08. wird er wieder abgebaut, siehe Irrwege.

18. bis 21. August: Öffnung#

Am 18.08. entsteht ein Fahrplan mit sechs Etappen, um planr für andere Lehrkräfte zu öffnen. Fünf davon laufen in vier Tagen durch:

EtappeWasWann
AKalender injizierbar - die Engine rechnet mit übergebenem Kalender statt Modulkonstanten18.08.
BKalender in die Datenbank, A/B-Rhythmus als Einstellung18.08.
RDatenbank und Funktionen von Virginia nach Frankfurt19.08.
CKonten statt Hauspasswort, owner_id, API-Schlüssel je Nutzer19.08.
DSchreib-API mit Entwurfsschritt19./20.08.
EMCP-Server, auch aus der Ferne19./20.08.

Die Reihenfolge ist nicht beliebig. R musste vor C liegen: Mit fremden Konten lägen Namen und E-Mail-Adressen anderer Lehrkräfte in den USA. A musste vor B liegen, weil man einen Kalender erst in die Datenbank legen kann, wenn ihn niemand mehr als Konstante importiert.

Am 20.08. kommen an einem Tag Planungsfreunde, der Zettel, die Zeitschiene, die Einheiten-Ansicht und der Rückweg aus merkr dazu. Am 21.08. der Rahmenplan als eigene Ebene - und damit die Einsicht, dass die Vorlage die Stundenliste tragen muss, nicht nur eine Blocklänge.

22. bis 26. August: Weg herein#

Am 22.08. fällt auf, dass zwei Dinge fehlen, um planr an ein Kollegium zu geben: Man konnte sich nicht anmelden (kontoAnlegen lag hinter dem Proxy), und man konnte seine Lerngruppen nicht anlegen (Stundenpläne gab es nur über die Schnittstelle). Beides kommt dazu.

Am 23.08. der Vertretungsplan, am 25.08. der nächtliche Zettel-Lauf, am 26.08. der Datei-Upload. Dazwischen die ersten drei Meldungen eines zweiten Nutzers - und die betreffen alle dieselbe Lücke: Er hatte Kurse ohne Vorlage angelegt und kam nicht weiter.


2. Architektur-Entscheidungen#

Engine ist rein#

buildPlan bildet die didaktisch geordnete Stundenfolge auf die konkreten Termine ab. Vier Regeln, mehr nicht: Stoff füllt freie Termine der Reihe nach, ausgefallene Termine bekommen keinen Stoff, Klassenarbeiten sind an ihrem Ankerdatum verankert, und wenn nachgeschobener Stoff über eine Arbeit oder aus dem Schuljahr hinausdrückt, gibt es eine Warnung statt einer stillen Verschiebung.

Die Funktion kennt keine Datenbank, kein React, keine Zeitzone. Alles, was die Planung wirklich ausmacht, ist damit ohne Aufbau prüfbar - und dieselbe Rechnung läuft in der Oberfläche, im Skript und über die Schnittstelle.

Die Warnung statt der Verschiebung ist die eigentliche Entscheidung. Eine Engine, die eine Klassenarbeit heimlich um eine Woche schiebt, hat immer recht und hilft nie.

Snapshot statt Live-Join#

Eine Lerngruppe kopiert beim Ausrollen Blöcke, Meilensteine und Anforderungen aus der Vorlage. Weitergeben einer Vorlage kopiert ebenfalls. Es gibt bewusst keinen Rückkanal.

Der Grund ist zuerst didaktisch: Mitten im Schuljahr will niemand, dass sich der Jahresplan der 9d ändert, weil jemand die Fachschaftsvorlage angefasst hat. Er ist aber auch technisch: Wäre eine geteilte Vorlage live sichtbar, bräuchte jede Vorlagen-Abfrage eine zweite Frage ("gehört sie mir, oder darf ich sie nur sehen?"), und der Besitz wäre nicht mehr die eine Antwort, die lib/besitz.ts gibt.

Die Anforderungen waren bis zum 21.08.2026 die Ausnahme - ein Live-Join über classes.template_id und die Positionsnummer. Beide Folgen fielen erst auf, als es zu spät war: Wer seine Vorlage löschte, verlor die Anforderungen aller daraus entstandenen Klassen, und wer Blöcke umsortierte, schob sie stillschweigend an ein anderes Thema.

Warum das Soll beim Vorbereiten entsteht#

Der naheliegende Weg wäre eine Jahres-Baseline: Im August steht der Plan, ab da misst man dagegen. Der Commit 72617f1 vom 25.07.2026 hat sich dagegen entschieden. Der Grund steht im Schema-Kommentar an lesson_plans:

Das Soll entsteht beim Vorbereiten, ein paar Tage vor der Stunde - nicht als Jahres-Baseline. Genau dagegen wird später gemessen; der laufende Plan verschiebt sich bei Ausfällen weiter, das Soll nicht.

Ein Plan vom August misst gegen einen Wunsch. Ein Soll von letzter Woche misst gegen eine Absicht, die jemand mit Kenntnis der Lage gefasst hat. Deshalb stehen festgeschriebenAm und sollDatum an lesson_plans und nicht an curriculum_items: Wer eine Stunde nie vorbereitet hat, hat kein Versprechen abgegeben, gegen das man messen könnte - und taucht weder in "Nachzutragen" noch in der Bilanz auf.

Besitz an genau drei Wurzeln#

classes, plan_templates, share_links. Alles andere hängt per Fremdschlüssel mit on delete cascade darunter und erbt ihn. lib/besitz.ts kennt die Wege dorthin und ist die einzige Stelle, die "gehört das mir?" beantwortet.

Kindabfragen brauchen danach keinen eigenen Filter: Wer die classId geprüft hat, darf alles lesen, was daran hängt. Doppelte Filter kosten Latenz und verstecken, wo die Entscheidung wirklich fällt.

Kein Row Level Security. Es wäre ein zweiter Ort für dieselbe Entscheidung - und wenn beide Orte auseinanderlaufen, gewinnt der, den man vergessen hat.

Keine Rollen und Rechte. Es gibt eine Rolle: die Lehrkraft mit ihren eigenen Daten. Alles Weitere sind Freigaben, und die tragen ihre Grenze bei sich.

Proxy ist keine Autorisierung#

proxy.ts prüft nur, ob ein Sitzungs-Cookie vorliegt. Ob die Sitzung gilt und welche Daten sie sehen darf, entscheidet die Datenschicht bei jeder einzelnen Abfrage. So empfiehlt es die Next-Doku ausdrücklich: Der Proxy läuft vor jeder Anfrage und darf nichts Langsames tun.

Geblieben ist eine Regel in die andere Richtung: Fehlen die Auth-Variablen, antwortet er mit 503. Eine vergessene Variable darf nicht bedeuten, dass alles offensteht. Dieselbe Logik gilt seit dem 25.08. für die Registrierung - fehlt PLANR_REGISTRIERCODE in Produktion, ist die Tür zu und nicht auf.

Keine Schülerdaten, und zwar strukturell#

Es gibt keine Schülertabelle. Was aus checkr zurückkommt, sind Klassenwerte je Anforderung. Was in selbr gezählt wird, bleibt in selbr. Namen führt allein merkr, und merkr liegt auf dem iPad.

Der schärfere Schritt kam am 19.08.2026 aus einer Datenschutzprüfung: Drei Felder laden dazu ein, etwas über einzelne Kinder zu schreiben - Klassenprofil, Reflexion und Hausaufgabe. Für den Betreiber selbst ist das seine eigene Planung, für eine fremde Lehrkraft wäre dasselbe Feld eine Auftragsverarbeitung mit AVV je Schule, TOMs und Zustimmung jeder Schulleitung.

Der Denkfehler im ursprünglichen Plan war die Annahme, eine Klausel in den Nutzungsregeln könne das regeln. Die Rollen nach DSGVO folgen der Sachherrschaft, nicht der Vereinbarung. Was hilft, ist, die Daten gar nicht erst zu bekommen - deshalb gibt es die Felder für fremde Konten nicht. Nicht ausgegraut, nicht schreibgeschützt, sondern nicht da (lib/betreiber.ts).

Entwurfsschritt vor jedem großen Schreiben#

Stundenpläne und Vorlagen-Stundenlisten werden zweistufig geschrieben: entwurf gibt in Klartext zurück, was planr verstanden hat, plus eine Prüfsumme; ohne diese Prüfsumme schreibt uebernehmen nicht.

Der Grund ist Erfahrung mit Modellen: Sie liefern plausiblen Unsinn. Aus "9d, Di 1./2." wird ein Mittwoch, und aus "ca. 40 Stunden Terme" werden zwanzig Doppelstunden in einer Reihenfolge, die didaktisch falsch ist. Beides fällt erst im März auf. Dazwischen gehört ein Mensch, der den Klartext liest.

Der heimtückischste Fehler, den pruefeVorlage abfängt, sind zwei verschiedene Namen für dieselbe Einheitsnummer - in der Jahresübersicht später kaum als Fehler zu erkennen.

Warum überhaupt ein MCP-Server#

Die Zielformulierung des Öffnungs-Fahrplans lautet: "planr ist der Speicher mit Rechenkern, die Oberfläche bleibt optional." Das ist keine Vision, sondern die Beobachtung, wie planr wirklich benutzt wird - Unterrichtsplanung passiert ohnehin im Gespräch mit einem Modell; was fehlte, war die Stelle, an der das Ergebnis landet. Vorher lief das über eine handgeschriebene HTTP-Schnittstelle (045879e, 25.07.2026), und jeder Client baute seine eigenen fetch-Aufrufe.

Zwei Regeln stammen aus einer Messung vom 22.08.2026 und nicht aus der Theorie: Mit allen 22 Werkzeugen im Katalog traf ein 9B-Modell 11 von 12 Alltagssätzen - ein großer Katalog schadet also nicht. Aber Namen erfindet es, Nummern nicht (aus "Statistik und Wahrscheinlichkeit" mit 8 Doppelstunden wurde der Einheitsname "Statistik und Wahrscheinlichkeit 8"), und rechnen kann es nicht, während es Werkzeugergebnisse zuverlässig wiedergibt. Daraus folgen grobplan_lesen mit Nummern, grobplan_aendern ausschließlich über Nummern und ein Systemtext ohne eine einzige Zahl aus der Planung.

Warum Neon und nicht Supabase#

selbr, drillr und checkr laufen auf Supabase. planr nicht, aus zwei Gründen.

Row Level Security wäre ein zweiter Ort für dieselbe Entscheidung. planrs Zugriffsschutz sitzt in lib/besitz.ts, bewacht von einem Test, der den Quelltext von app/actions.ts liest. Dieselbe Regel zusätzlich als Policy zu führen hieße, sie an zwei Stellen richtig halten zu müssen. Der Öffnungs-Fahrplan führt RLS ausdrücklich unter "bewusst nicht dabei".

Neon Auth kam mit der Datenbank. Als das Hauspasswort fiel, war der Weg mit den wenigsten beweglichen Teilen der, der schon dalag: Konten im Schema neon_auth, owner_id als echter Fremdschlüssel darauf, on delete cascade bis in die letzte Phase einer Stunde. Ein Konto zu löschen ist damit eine Datenbankoperation und kein Aufräumskript.

Der Preis steht daneben: Neon Auth ist Beta, deshalb liegt es hinter lib/auth.ts als einziger Berührungsfläche. Und Neons Managed Better Auth lässt keine eigenen Plugins zu - deshalb kann planr nicht ohne Handarbeit zum OAuth-Server werden, und deshalb klemmt Claude Desktop bis heute.

Dazu kommt die Datenbank selbst: planr ist latenzgebunden, nicht weil eine Abfrage langsam wäre, sondern weil es viele kleine stellt. Daraus folgen Promise.all an fast jeder Seite, ein Pool von höchstens fünf Verbindungen (db/index.ts), cache() um aktiverKalender() - und die Entscheidung, beim Regionswechsel die Vercel-Funktionen mitzunehmen statt nur die Daten.

Nichts speichern, was woanders die Wahrheit ist#

Der Vertretungsplan wird bei jedem Aufruf gelesen und nirgends abgelegt. Der Experimente-Katalog wird gefragt, nicht abgeschrieben. An checkr hängt nur die Kennung des Auftrags, keine Ergebnisse. Am Meilenstein hängt nur die Kennung des Experiments.

Eine gepflegte Zuordnungstabelle wäre ein dritter Ort, an dem etwas veralten kann - für einen Vorschlag, den ohnehin ein Mensch prüft. Und ein Ausfall, den planr sich selbst einträgt, wäre eine Behauptung über eine Stunde, bei der niemand war.

Die eine Ausnahme ist gut begründet: Sagt der Vertretungsplan dauerhaft etwas anderes als der eigene Stundenplan (kein "Geändert!"-Vermerk), zieht planr Raum und Block selbst nach - und protokolliert jede solche Änderung. Ein Stundenplan, der sich unbemerkt ändert, wäre schlimmer als einer, der veraltet.

Zwei Rechnungen sind eine zu viel#

Wo eine Regel an zwei Stellen stünde, wird sie an eine gezogen und die andere ruft sie auf.

  • lib/sequenz.ts wird vom Knopf in der Oberfläche und vom Skript benutzt.
  • lib/stundenplan-raster.ts übersetzt geklickte Kästchen in genau den Text, den die Schnittstelle ohnehin prüft - danach läuft dieselbe Prüfung, dieselbe Terminerzeugung, dieselben Meldungen.
  • mcp/routen.ts wird vom MCP-Endpunkt und vom Chat der Kursseite benutzt.
  • lib/leistungsarten.ts entstand, weil dieselbe Zuordnung als KIND_LABEL in neun Dateien stand, mal lang, mal kurz.
  • lib/farben.ts entstand, weil die Seitenleiste ihre eigene Farbtabelle hatte.

Drei Tests lesen den Quelltext, nicht die Rückgabewerte#

lib/freigabe.test.ts, lib/planungsfreunde.test.ts und lib/mehrbenutzer.test.ts prüfen nicht, was eine Funktion zurückgibt, sondern was in ihrem Quelltext steht. Das ist selbst eine Architekturentscheidung: Ein Verhaltenstest prüft nur, woran jemand gedacht hat. Ein Feld, das morgen jemand zur Freigabe-Abfrage hinzufügt, hätte keinen Test, der es kennt - die Quelltext-Wache schlägt trotzdem an.

Zustand ohne React, wo React zu spät kommt#

Klappbereiche, der Fein/Grob-Umschalter, die Position des Zettel-Knopfs und seine Marke lesen ihren Zustand aus localStorage, bevor das erste Bild steht - über ein kurzes Skript hinter dem Markup, nicht über useEffect. Mit einem Effekt stünde bei jedem Aufruf erst der Standard da und spränge sichtbar um.

Der Preis: suppressHydrationWarning an den betroffenen Elementen, und die Skripte stehen als Zeichenketten in eigenen Dateien (lib/zettel-marke.ts), damit sie testbar sind. Zusammengebautes JavaScript fällt sonst erst im Browser auf die Nase, und dort sieht man nur ein stummes Nichts.


3. Irrwege#

Folieneditor (13.-16.08.2026, drei Tage)#

Erst als Formular, dann als Leinwand: Kästen frei ziehen, Größe ändern, direkt tippen, Folienleiste, automatisches Speichern. Er funktionierte.

Abgebaut am 16.08. Gegen Canva gewinnt er nicht - dort sind die Bilder, die Vorlagen und die Übung. Geblieben ist die Rollenteilung: planr liefert das Gerüst, weil es als einziges die Planung kennt; Canva gestaltet. Mit dem Editor fielen die Druckansicht (das PDF kommt aus Canva und ist dort vollständig) und das Tafelbild.

Die Spalte lesson_slides.tafel steht bis heute in der Datenbank: Sie stört nicht, und eine Migration für ein totes Feld wäre Risiko ohne Gegenwert.

Tagesansicht "Heute" (20.08.2026)#

Sie beantwortete dieselbe Frage wie die Arbeitsliste auf der Übersicht, nur für einen einzigen Tag, und wurde nicht benutzt. Ersatzlos entfernt. lib/heute.ts blieb - es ist die Datenquelle der Arbeitsliste.

Klassenkarten auf der Startseite (19.08.2026)#

Seit die Seitenleiste dieselben Lerngruppen führte, stand jede Klasse zweimal auf demselben Bildschirm. Mit den Karten fielen drei Rechnungen samt Tests weg, und DashboardKlasse schrumpfte von siebzehn Feldern auf sechs.

Browser sollte den MacMini fragen (22./23.08.2026)#

Der Chat auf der Kursseite sollte direkt mit der Modellbrücke im Heimnetz reden. In Produktion ging das nicht: Chrome lässt eine Seite im offenen Netz nicht auf eine Adresse im privaten Bereich zugreifen, und Tailscale vergibt 100.64/10. Die Anfrage kam nie an, ohne Fehlermeldung, der fetch hing.

Aus localhost:3000 fiel das nicht auf - Loopback darf. Ein Test aus einer Browser-Erweiterung täuschte kurz Erfolg vor, weil die in einer isolierten Welt läuft, in der die Regel nicht gilt.

Der Umbau war der bessere Schnitt: planr ruft die Brücke jetzt selbst, das Zugangswort bleibt auf dem Server, und der Chat läuft auf jedem Gerät - auch ohne Tailscale, also am Schul-iPad.

Grenze des Behandelten war zu grob (20.08.2026)#

Damit die Übung zur ersten Mathestunde der 9d nicht Scheitelpunkte und tan(45°) enthält, bekommt drillr eine Liste dessen, was die Klasse schon hatte. Die erste Fassung arbeitete auf Themengebiets-Ebene - und hatte zwei Löcher:

  • Ein Gebiet trägt die Klassenstufe seines Schwerpunkts, die Aufgaben darin ihre eigene. Meldete eine Neunte "Wahrscheinlichkeitsrechnung" als behandelt, kamen die Aufgaben der Stufe 10 mit.
  • Ein Themenblock ist feiner als ein Gebiet. Mit dem Beginn des ersten von drei Blöcken am Gebiet "Quadratische Gleichungen" waren alle 26 Aufgaben frei.

Behoben über die Klassenstufe der einzelnen Aufgabe und über Unterthemen als Schlüssel. Die Bedingung dafür - ein Unterthema darf in keinem anderen Gebiet vorkommen - gehört vor jeder weiteren Pflege geprüft.

Marke am Zettel-Knopf zählte das Falsche (20.08.2026)#

Zuerst stand dort die Zahl der offenen Einträge. Eine Zahl im farbigen Kreis auf einem Knopf verspricht aber "jemand hat dir geschrieben", nicht "so viele Punkte sind offen" - und beim eigenen Eintrag sprang sie hoch. Sie zählt jetzt Einträge und Antworten der anderen, die man noch nicht gesehen hat.

drizzle-kit push (bis 12.08.2026)#

Es änderte die Produktionsdatenbank sofort, ohne Datei und ohne Spur. Ein spaltenentfernender Push vor dem Deploy brach die laufende App. Ersetzt durch Migrationen mit nummerierten Dateien im Repository.

Zettel als Artifact (20.08.2026)#

Die Vorstufe des Beta-Zettels war eine selbstspeichernde Seite auf claude.ai, die sich beim Eintrag selbst neu veröffentlicht. Verworfen, weil der Freigabe-Dialog dort nur "nur ich" und "jeder mit dem Link" kennt und offen ist, ob ein Link-Gast schreiben darf. In planr hat der Kollege ohnehin ein Konto.

Dieser Irrweg hinterlässt keinen Commit - er endete vor dem ersten. Belegt ist er in der Session-Notiz Leben/Software/Sessions/2026-08-20 planr Zettel.md.

Hauspasswort, und die Lehre zweimal (11.-19.08. und 25.08.2026)#

Acht Tage lang lag ein einzelnes Passwort vor der Planung (PLANR_PASSWORT, gleichLang()). Es fiel mit Etappe C. Geblieben ist die 503-Regel: Fehlt die Konfiguration, ist in Produktion zu und nicht auf.

Dieselbe Umkehrung musste ein zweites Mal gelernt werden. Bis zum 25.08.2026 galt für PLANR_REGISTRIERCODE "nicht gesetzt heißt offen" - eine vergessene Zeile in Vercel hätte bedeutet, dass jeder im Internet ein Konto anlegen kann, ohne dass etwas kaputt aussieht. Behoben hat das ausgerechnet der erste nächtliche Zettel-Lauf (c07398a, 0107ffd).

Zwei Rechnungen, die noch nebeneinanderlaufen#

buildWeekPlan (Wochen, Meilenstein-Fenster) und lib/abschnitte.ts (Ferienabschnitte) rechnen beide über dasselbe Jahr. Das endet erst, wenn afterBlockSeq fällt - siehe Offene Fragen.


4. Philosophie#

Konkret vor allgemein#

planr ist an einem einzigen Fall geschärft worden: Mathematik und Physik am Gymnasium in MV, Doppelstunden, A/B-Wochen. Vieles davon ist inzwischen verallgemeinert, aber immer erst, nachdem der konkrete Fall funktionierte.

Der Vorteil zeigt sich an Details, die man sich nicht ausdenkt: dass ein Merkheft nie auf iServ wartet. Dass eine Klassenarbeit in einer Woche liegt und nicht an einem Tag. Dass am Mittwoch die 8d in der 5./6. Stunde vor der 9a in der 1./2. stehen muss - alphabetisch sortiert war die Tagesansicht monatelang falsch, ohne dass es jemandem auffiel.

Software soll wissen, was sie nicht weiß#

Der Unterschied zwischen "nichts offen" und "nichts erfasst", zwischen "nicht konfiguriert" und "nicht erreichbar", zwischen "kein Rückstand" und "keine Rückmeldung". Diese Unterscheidungen kosten jedes Mal Arbeit und sind jedes Mal der Punkt, an dem eine Anzeige entweder hilft oder täuscht.

Die Lehre daraus ist teuer bezahlt: Der checkr-Rückkanal sah ein Jahr lang aus wie leer, während nur ein Token fehlte. Das ist die Kehrseite von "gibt bei jedem Fehler null zurück".

Nichts behaupten, was ein Mensch entscheiden muss#

planr trägt keinen Ausfall selbst ein, verteilt keine Ferienabschnitte um und schiebt keine Klassenarbeit heimlich. Es rechnet, zeigt den Befund und legt einen Knopf daneben.

Dieselbe Linie gilt gegenüber Modellen: Lesen läuft durch, Schreiben wird gefragt, und die großen Schreibvorgänge gehen über einen Entwurf, den ein Mensch liest.

Weg zurück#

planr sagte lange vor der Stunde, was auf der Übung steht, und erfuhr danach nie, ob es getragen hat. Vier kleine Teile haben das geschlossen: Was auf einem Blatt stand, wird festgehalten; merkr bekommt die Themen zum Antippen; was gewackelt hat, wird als Signal abgelegt; die nächste Übung zieht es vor.

Dasselbe Muster beim Zettel: Der Rückkanal ("umgesetzt in Commit x") ist das Eigentliche. Ohne ihn endet jeder Eintrag im Nichts, bis jemand nachfragt.

Kommentare erklären das Warum#

planr hat ungewöhnlich lange Kommentare. Sie beschreiben nicht, was der Code tut, sondern welche Alternative aus welchem Grund verworfen wurde - und ziemlich oft, welcher Fehler dahintersteckt, der einmal wirklich passiert ist. Wer eine Stelle ändern will, findet dort meistens schon, warum die naheliegende Lösung nicht funktioniert hat.

Viele kleine Programme statt eines großen#

planr plant und steuert, drillr macht Papier, selbr ist die Schülerfläche, checkr korrigiert, merkr ist das Klassenbuch, prüfr baut die Arbeiten. Der Schnitt läuft nach Nutzer, nicht nach Lernphase: Deshalb liegen die Namen der Kinder allein in merkr, und deshalb liegt merkr auf dem Gerät.


5. Offene Fragen#

Strukturell#

afterBlockSeq muss fallen. Blöcke und Meilensteine hängen über eine Positionsnummer zusammen, die zugleich die Wochenverteilung trägt. Solange sie steht, laufen zwei Rechnungen nebeneinander, und ein Einschieben in der Mitte eines Kurses ist gefährlich (aus "KA nach Terme" wird "KA nach Brüche"). Sie zu entfernen heißt, die Termine der Arbeiten allein aus der Stundenliste zu nehmen und buildWeekPlan für Klassen abzuschalten.

Die Vorlagen sind noch nicht auf Stundenlisten umgestellt. template_items gibt es seit dem 21.08.2026, aber erzeugeSequenz rechnet weiter aus den Klassen-Blöcken, wenn keine Liste da ist. Der Umstieg ist idempotent vorbereitet (stelleVorlageUm) und läuft nur einmal - ein zweiter Lauf überschriebe die Titel, für die es die Liste gibt.

PLANR_API_TOKEN soll ersatzlos verschwinden, sobald die eigenen Skills und Jobs auf persönliche Schlüssel umgestellt sind.

Betrieb#

Der Mailversand ist gebaut, aber nicht scharf. Bestätigungs- und Passwort-Mails kommen englisch und im Junk-Ordner an. Der Webhook-Weg (app/api/auth-mail/route.ts) ist fertig und absichtlich nicht aktiviert: Ist er an, verschickt Neon selbst nichts mehr - eine Fehlkonfiguration hieße also gar keine Mails. Für ein ganzes Kollegium ist "Passwort vergessen" damit noch nicht tragbar.

Konto sperren geht nur per SQL. Bei einem Betreiber und einer Handvoll Nutzer lohnt eine Oberfläche dafür nicht.

Die Modellbrücke steht im offenen Netz, ihr ganzer Schutz ist ein Token, und ein Rate-Limit gibt es nicht.

Claude Desktop bindet den MCP-Endpunkt noch nicht ein. Ein Custom Connector erwartet OAuth 2.1 mit Dynamic Client Registration; ein fester Schlüssel als Kopfzeile steckt bei Anthropic in einer Beta. Der Ausbau zum eigenen OAuth-Server wäre Handarbeit - Neons Managed Better Auth lässt keine eigenen Plugins zu. Bei zwei Nutzern lohnt das nicht.

Inhaltlich#

Physik hat keine Übungen. drillr führt 21 Themengebiete, alle Mathematik. Eine Physik-Übung ist dort nicht ungemappt, sondern unmöglich.

Der Experimente-Katalog hat für die zweite Jahreshälfte der 9a kein einziges Experiment (Geradlinige Bewegung, E-Bike: 8 Doppelstunden). Entweder fehlt es in der Sammlung, oder es ist dort noch nicht erfasst.

Zwei Physikkurse sind in selbr nicht erreichbar, weil es dort keine Zugänge dieser Kohorte gibt. Ein Tag ohne Zugänge wäre schlimmer als keiner - planr böte Hausaufgaben an, die niemand sieht.

Nicht gebaut, und zwar mit Absicht#

  • Geteilte Fachschafts-Vorlagen mit Live-Bezug. Der Unterbau stünde bereit, aber weitergeben heißt kopieren - siehe oben.
  • Ein Werkzeug, mit dem ein Modell selbst auf den Zettel schreibt. Notiert wird beim Benutzen, mit dem Knopf. Was ein Modell sich notiert, hat niemand bemerkt.
  • Ein Nachtlauf über die offenen Wünsche. Ein Wunsch ist eine Produktentscheidung, keine Aufgabe. Der nächtliche Lauf nimmt sich nur Fehlerberichte vor.
  • Mehrere Bundesländer. LAND = "MV" bleibt vorerst Konstante.
  • Eine eigenständige Timer-Seite. Der Timer läuft in planr, präsentiert wird in Canva - solange das so ist, sieht man ihn nur, wenn planr nebenher offen steht.