Die Startseite log nicht -- sie war nur alt. Und Protokolle lassen sich loeschen

Drei Meldungen aus einer Nachricht.

1. "WIRD IMMER NOCH ANGEZEIGT"
   Ein Protokoll war geschrieben, die Startseite meldete trotzdem weiter
   "1 Gespraech hat noch kein Protokoll".

   NACHGESTELLT statt vermutet: Der Server lag die ganze Zeit richtig.
   Der Hinweis erscheint, sobald ein vergangenes Gespraech kein Protokoll
   hat, und verschwindet in dem Moment, in dem eines geschrieben ist --
   nachgemessen, beides.

   Falsch war der BILDSCHIRM. Browser legen eine verlassene Seite
   vollstaendig beiseite (bfcache) und holen sie beim Zurueckgehen
   unveraendert hervor, mitsamt allen Zahlen vom ersten Laden. Kein
   Skript laeuft dabei erneut. Wer ein Protokoll schreibt und dann auf
   "Zurueck" tippt, sieht zwangslaeufig den Stand von vorher.

   Das ist kein Schoenheitsfehler: Eine Zahl, die etwas Falsches
   behauptet, ist schlimmer als gar keine -- man glaubt ihr ja. Und sie
   kostet danach Vertrauen in ALLE Zahlen.

   kopf.js laedt eine zurueckgeholte Seite jetzt neu. Nur dann
   (`event.persisted`), nicht bei jedem Anzeigen -- sonst waere es eine
   Endlosschleife. Gilt fuer jede Workspace-Seite, nicht nur die
   Startseite.

2. PROTOKOLLE LOESCHEN -- NUR DOGFATHER
   Bewusst istDogFather und nicht istLeitung: Ein Manager hat sonst
   ueberall dieselben Rechte, hier ausdruecklich nicht. Wer ein Protokoll
   entfernen darf, kann nachtraeglich bestimmen, was besprochen wurde.

   Geloescht wird NUR das Protokoll. Das Gespraech bleibt im Kalender und
   rutscht wieder zu "Protokoll fehlt" -- die Handlung ist damit
   umkehrbar: neu schreiben, fertig. Die daraus entstandenen AUFGABEN
   bleiben ebenfalls stehen; sie sind echte Arbeit, die jemand uebernommen
   hat, und mit einem Klick auf ein Protokoll zu verschwinden waere ein
   stiller Datenverlust an ganz anderer Stelle.

   Der Knopf steht nur bei DogFather. Ein Knopf, der bei anderen
   erscheint und dann abgewiesen wird, ist eine Einladung zum Aergernis.

3. IMMER NUR EINS OFFEN
   Vorher liessen sich beliebig viele Protokolle gleichzeitig aufklappen
   -- die Seite wurde so lang, dass die Liste darunter aus dem Blick
   geriet. Ein neu geoeffnetes Gespraech schliesst jetzt das vorherige.
   Beim Laden ist alles zu.

GEPRUEFT: server/pruef-protokoll-loeschen.mjs, 20 Pruefungen. Die
Zurueck-Pruefung misst an EINZAHL gegen MEHRZAHL ("1 Gespraech HAT" gegen
"2 Gespraeche HABEN") -- die Zahl selbst steht in einem eigenen Feld und
taucht im Fliesstext nicht auf. Drei Gegenproben: dass der Hinweis nach
dem Reparieren ueberhaupt noch anschlaegt (sonst waere "verschwunden"
auch bei kaputtem Hinweis gruen), dass eine Managerin 403 bekommt und das
Protokoll danach unveraendert dasteht, und dass der Loeschknopf bei ihr
gar nicht erst gezeichnet wird. Bestehende Laeufe gruen: Startansicht 133,
Rollen 97, Kalender 84, Serien 67, Protokoll-Klappe 52, Handy 50, Ampel
47, Freie Namen 32, Code 17.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-02 23:45:45 +02:00
co-authored by Claude Opus 5
parent fc26597083
commit e7b277b7fc
33 changed files with 531 additions and 137 deletions
+53 -1
View File
@@ -18,7 +18,7 @@
import express from "express";
import {
db, protokolliere, echteIp, sitzungLesen, einstellung, einstellungSetzen, istLeitung,
db, protokolliere, echteIp, sitzungLesen, einstellung, einstellungSetzen, istLeitung, istDogFather,
} from "./workspace.js";
import { sichtbar } from "./workspace-kalender.js";
@@ -182,6 +182,58 @@ callRouter.put("/workspace/api/call-link", gleicheHerkunft, (req, res) => {
}
});
/* ---------- Protokoll löschen -------------------------------------------
NUR DogFather (Wunsch 02.09.2026: "ich will auch dass ich die löschen
kann. und nur ich kann die löschen sonst keiner").
Bewusst istDogFather und nicht istLeitung: Ein Manager hat sonst
überall dieselben Rechte, hier ausdrücklich nicht. Ein Protokoll ist
die Gedächtnisstütze eines Gesprächs -- wer es entfernen darf, kann
nachträglich bestimmen, was besprochen wurde.
Gelöscht wird NUR das Protokoll, nicht das Gespräch. Der Termin bleibt
im Kalender und erscheint danach wieder unter "Protokoll fehlt" -- die
Handlung ist damit umkehrbar: neu schreiben, und alles ist wie vorher.
Die daraus entstandenen AUFGABEN bleiben ebenfalls stehen. Sie sind
echte Arbeit, die jemand übernommen hat; sie mit einem Klick auf ein
Protokoll verschwinden zu lassen wäre ein stiller Datenverlust an
einer ganz anderen Stelle. Die Verknüpfung fällt weg (ON DELETE
CASCADE auf der Zwischentabelle), die Aufgaben selbst nicht. */
callRouter.delete("/workspace/api/calls/:id/protokoll", gleicheHerkunft, (req, res) => {
try {
if (!istDogFather(req.person)) {
return res.status(403).json({ fehler: "Nur DogFather darf ein Protokoll löschen." });
}
const id = Number(req.params.id);
if (!Number.isInteger(id)) return res.status(400).json({ fehler: "ungueltig" });
/* Auch DogFather kommt nur an Gespräche, die er sehen darf -- die
Sichtbarkeitsregel gilt hier wie überall. Bei ihm ist das "alles",
aber die Abfrage steht trotzdem da: Ändert sich die Regel einmal,
ändert sie sich hier mit. */
const { wo, werte } = sichtbar(req.person);
const call = db().prepare(
`SELECT t.id, t.titel, pr.id AS protokoll_id
FROM termine t LEFT JOIN protokolle pr ON pr.termin_id = t.id
WHERE ${wo} AND t.id = ?`).get(...werte, id);
if (!call) return res.status(404).json({ fehler: "nicht_gefunden" });
if (!call.protokoll_id) return res.status(404).json({ fehler: "kein_protokoll" });
db().prepare("DELETE FROM protokolle WHERE id = ?").run(call.protokoll_id);
protokolliere("protokoll_geloescht", {
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
detail: `Call #${id} ${call.titel}`.slice(0, 120),
});
res.json({ ok: true });
} catch (fehler) {
console.error("[workspace] Protokoll löschen:", fehler?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
callRouter.post("/workspace/api/calls/:id/protokoll", gleicheHerkunft, (req, res) => {
const d = db();
try {