Termine, die von allein weiterlaufen -- bis man sie abstellt
Wunsch: "ich will dass ich da im kalender auch sachen machen die jede
woche jeden monat automatisiert immer weiter laufen so wie ich es
auswaehle bis ich es selber deaktiviere. aktiviere diese option fuer
jeden."
Acht Rhythmen (taeglich, werktags, woechentlich, alle zwei Wochen,
monatlich am Datum, am Monatsletzten, am n-ten Wochentag, jaehrlich),
wahlweise mit Enddatum oder ohne Ende. Fuer JEDE Rolle -- Creator und
Scouts legen sie fuer sich selbst an, mit denselben Grenzen wie beim
einzelnen Termin.
WARUM ECHTE TERMINE UND KEINE GERECHNETEN AUSPRAEGUNGEN
Der naheliegende Weg waere gewesen, die Wiederholung nur beim Anzeigen
auszurechnen. Das waere ein stiller Ausfall geworden: ACHT andere Stellen
lesen die Tabelle termine direkt -- Calls, Protokolle, Berichte,
Hinweise/Ampel, Suche, Aufgaben ("naechster Termin"), Uebersicht und die
Startseite. In all diesen Ansichten haette schlicht nichts gestanden, und
aufgefallen waere es erst Monate spaeter. Stattdessen macht ein
Nachfueller aus der Regel echte Zeilen (Horizont 180 Tage) -- jedes andere
Modul sieht sie mit, ohne dass dort eine Zeile geaendert werden musste.
Beim geplanten ICS-Abo gilt dasselbe.
KEIN ZEITGEBER. Der Nachfueller laeuft beim Serverstart, beim Anlegen und
Aendern und beim Oeffnen des Kalenders (dort hoechstens alle fuenf
Minuten). Er ist idempotent. Ein Cron waere eine weitere Sache gewesen,
die stillschweigend ausfallen kann.
WAS BEIM ABSTELLEN PASSIERT: Vergangene Termine und alles, was jemand von
Hand angefasst hat (verschoben, umbenannt, abgehakt), bleibt stehen. Nur
die unberuehrte Zukunft wird aus dem Kalender genommen. Wer einen
einzelnen Tag loescht, streicht nur diesen einen -- der Tag wird als
Ausnahme vermerkt, sonst legte der Nachfueller ihn wieder an.
ZEITUMSTELLUNG: Gerechnet wird auf reinen Datumstexten in UTC-Mittag, die
Uhrzeit wird als Text angehaengt. 18:00 bleibt dadurch 18:00 und wandert
im Oktober nicht auf 17:00.
DIE SICHTBARKEITSREGEL STEHT JETZT NUR NOCH EINMAL (workspace.js,
termineSichtbar) statt zweimal fast gleich. Zwei Fassungen waeren
auseinandergelaufen -- und dann haette eine Wiederholung jemandem etwas
gezeigt, was der einzelne Termin ihm verbirgt.
IN DER OBERFLAECHE beschriften sich die Rhythmen nach dem gewaehlten
Datum ("jeden Dienstag", "jeden Monat am letzten Dienstag") statt
abstrakt ("woechentlich"), inklusive des ehrlichen Hinweises, dass "jeden
31." den Februar auslaesst. Darunter steht der ganze Satz in Worten. Eine
neue Leiste "Laeuft von allein" zeigt alle laufenden Wiederholungen mit
Abstell-Schalter -- was von selbst weiterlaeuft, muss man sehen koennen.
GEPRUEFT: 67 Pruefungen (server/pruef-serien.mjs), darunter von Hand
nachgeschlagene Datumsangaben fuer jeden Takt (der letzte Dienstag im
Dezember 2026 ist der 29., nicht der 22.; der 29. Februar nur in
Schaltjahren) und vier GEGENPROBEN, die beweisen, dass die Pruefungen
auch "nicht in Ordnung" sagen koennen. Die Anzahl der Pruefungen steht in
der Bedingung, nicht nur im Meldetext. Bestehende Pruefungen unveraendert
gruen: Kalender 84, Sicht 48, Startansicht 133, Protokoll 52, Ampel 47,
Handy 50, Aufgabenbrett 44, Sprung 43, Personen-Loeschen 40, Uebersicht
33, Workspace-Seiten 32, Formulare 19, Betreuung 18, Grosscheck 15,
Lesbarkeit 14.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -179,6 +179,21 @@ function umstellungen(d) {
|
||||
["personen", "instagram", "TEXT"],
|
||||
["personen", "youtube", "TEXT"],
|
||||
["personen", "twitch", "TEXT"],
|
||||
|
||||
/* ---- Wiederkehrende Termine (02.09.2026) ----
|
||||
Drei Spalten an `termine`, damit eine Ausprägung weiss, woher sie
|
||||
stammt:
|
||||
serie_id die Regel, aus der sie entstanden ist
|
||||
serie_tag der geplante Tag -- daran erkennt der Nachfüller,
|
||||
dass es diese Ausprägung schon gibt, und legt sie
|
||||
kein zweites Mal an
|
||||
serie_beruehrt jemand hat sie von Hand angefasst (verschoben,
|
||||
umbenannt, abgehakt). Solche Termine bleiben beim
|
||||
Abstellen der Serie stehen -- was jemand
|
||||
bearbeitet hat, wird ihm nicht weggeräumt. */
|
||||
["termine", "serie_id", "INTEGER REFERENCES termin_serien(id) ON DELETE SET NULL"],
|
||||
["termine", "serie_tag", "TEXT"],
|
||||
["termine", "serie_beruehrt", "INTEGER NOT NULL DEFAULT 0"],
|
||||
]) {
|
||||
try {
|
||||
const vorhanden = d.prepare(`PRAGMA table_info(${tabelle})`).all().map((s) => s.name);
|
||||
@@ -191,6 +206,17 @@ function umstellungen(d) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Der Nachfüller fragt bei jedem Lauf "welche Ausprägungen dieser
|
||||
Serie gibt es schon?". Ohne diesen Verbund-Index liest SQLite dafür
|
||||
die ganze Termintabelle. Er steht hier unten und nicht oben im
|
||||
Bauplan, weil die beiden Spalten erst durch die Schleife darüber
|
||||
entstehen -- oben gäbe es sie beim ersten Start noch nicht. */
|
||||
try {
|
||||
d.exec("CREATE INDEX IF NOT EXISTS idx_termine_serie ON termine (serie_id, serie_tag)");
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Index idx_termine_serie:", fehler?.message);
|
||||
}
|
||||
|
||||
/* Content-Saeulen: die drei bis fuenf Themen, aus denen der Kanal
|
||||
besteht. Aus der Recherche: 3-5 Saeulen nach der 70/20/10-Regel
|
||||
(70 % Wert, 20 % Community, 10 % Eigenwerbung); eine Saeule wird
|
||||
@@ -435,6 +461,61 @@ export function db() {
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_termine_beginn ON termine (beginn);
|
||||
|
||||
/* Wiederkehrende Termine (02.09.2026) --------------------------------
|
||||
|
||||
Eine Serie ist eine REGEL, kein Termin: "jeden Dienstag um 18:00
|
||||
Uhr, bis ich es abstelle". Aus ihr entstehen echte Zeilen in
|
||||
der Tabelle termine.
|
||||
|
||||
Warum echte Zeilen und nicht bloss gerechnete Ausprägungen:
|
||||
ACHT andere Stellen lesen termine direkt -- Calls, Protokolle,
|
||||
Berichte, Hinweise/Ampel, Suche, Aufgaben ("nächster Termin"),
|
||||
Übersicht, Startseite. Eine nur im Kalender gerechnete
|
||||
Wiederholung wäre in all diesen Ansichten unsichtbar gewesen,
|
||||
ohne dass es jemandem auffällt, und beim geplanten ICS-Abo
|
||||
ebenfalls. Der Nachfüller hält stattdessen einen Horizont echt
|
||||
gefüllt -- damit sieht jedes Modul die Wiederholung, ohne dass
|
||||
dort eine einzige Zeile geändert werden musste.
|
||||
|
||||
uhrzeit statt beginn: Eine Regel kennt keinen Zeitpunkt, nur
|
||||
eine Uhrzeit und einen Takt. Gerechnet wird auf reinen
|
||||
Datumstexten -- deshalb bleibt 18:00 auch über die
|
||||
Zeitumstellung hinweg 18:00 und wandert nicht auf 17:00. */
|
||||
CREATE TABLE IF NOT EXISTS termin_serien (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
titel TEXT NOT NULL,
|
||||
beschreibung TEXT,
|
||||
art TEXT NOT NULL DEFAULT 'termin'
|
||||
CHECK (art IN ('termin','call','review')),
|
||||
takt TEXT NOT NULL
|
||||
CHECK (takt IN ('taeglich','werktags','woechentlich',
|
||||
'zweiwoechentlich','monatlich_datum',
|
||||
'monatlich_letzter','monatlich_wochentag',
|
||||
'jaehrlich')),
|
||||
start_tag TEXT NOT NULL,
|
||||
uhrzeit TEXT NOT NULL,
|
||||
ende_tag TEXT,
|
||||
dauer_min INTEGER NOT NULL DEFAULT 30,
|
||||
ort TEXT,
|
||||
creator_id INTEGER REFERENCES personen(id) ON DELETE SET NULL,
|
||||
teilnehmer_id INTEGER REFERENCES personen(id) ON DELETE SET NULL,
|
||||
aktiv INTEGER NOT NULL DEFAULT 1,
|
||||
erstellt TEXT NOT NULL,
|
||||
erstellt_von INTEGER REFERENCES personen(id) ON DELETE SET NULL,
|
||||
geaendert TEXT
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_serien_aktiv ON termin_serien (aktiv);
|
||||
|
||||
/* Ausgelassene Tage einer Serie. Wer eine einzelne Ausprägung
|
||||
löscht, meint "dieses eine Mal nicht" -- ohne diese Tabelle
|
||||
legte der Nachfüller sie beim nächsten Aufruf wieder an, und der
|
||||
gelöschte Termin wäre kommentarlos zurück. */
|
||||
CREATE TABLE IF NOT EXISTS termin_serien_aus (
|
||||
serie_id INTEGER NOT NULL REFERENCES termin_serien(id) ON DELETE CASCADE,
|
||||
tag TEXT NOT NULL,
|
||||
PRIMARY KEY (serie_id, tag)
|
||||
);
|
||||
|
||||
/* Dateiablage. Auf der Platte traegt jede Datei einen erzeugten
|
||||
Zufallsnamen (name_datei), der Originalname steht nur hier.
|
||||
Dadurch kann ein Dateiname weder Pfade verlassen noch etwas
|
||||
@@ -1069,6 +1150,34 @@ export function betreutWo(person, spalte) {
|
||||
return { wo: `${spalte} IN (${ids.map(() => "?").join(",")})`, werte: ids };
|
||||
}
|
||||
|
||||
/* Wer sieht welchen Termin -- und damit auch: welche Wiederholung.
|
||||
|
||||
NUR DogFather sieht alles (01.09.2026). Vorher stand hier istLeitung()
|
||||
-- damit sah auch jeder Manager jeden Creator. Ein Manager faellt
|
||||
jetzt in dieselbe Regel wie ein Scout: nur die Creator, die ihm
|
||||
zugeteilt sind. Ausdruecklicher Wunsch: "NUR DIE ROLLE DOGFATHER SOLL
|
||||
WIRKLICH ALLEINE ALLES SEHEN."
|
||||
|
||||
Geaendert wird ausschliesslich, wer was SIEHT. Was ein Manager DARF
|
||||
(freigeben, aendern, Personen verwalten), haengt weiterhin an
|
||||
istLeitung und bleibt unveraendert -- sonst haette dieser eine Wunsch
|
||||
stillschweigend seine halben Rechte mitgenommen.
|
||||
|
||||
Der Praefix ist der Tabellenname im jeweiligen SQL: "t" fuer termine,
|
||||
"s" fuer termin_serien. Diese Regel steht bewusst nur EINMAL: Eine
|
||||
zweite, fast gleiche Fassung fuer die Serien waere frueher oder
|
||||
spaeter auseinandergelaufen -- und dann haette eine Wiederholung
|
||||
jemandem etwas gezeigt, was der einzelne Termin ihm verbirgt. */
|
||||
export function termineSichtbar(person, praefix = "t") {
|
||||
if (istDogFather(person)) return { wo: "1=1", werte: [] };
|
||||
const p = praefix;
|
||||
const eigen = `(${p}.creator_id = ? OR ${p}.teilnehmer_id = ? OR ${p}.erstellt_von = ?)`;
|
||||
const werte = [person.id, person.id, person.id];
|
||||
const b = betreutWo(person, `${p}.creator_id`);
|
||||
if (!b) return { wo: eigen, werte };
|
||||
return { wo: `(${eigen} OR ${b.wo})`, werte: [...werte, ...b.werte] };
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DIE SICHT EINES ANDEREN — nur fuer DogFather.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user