Vorlagenbrett: Modis bewerben sich, DogFather und die rechte Hand entscheiden

Filipe: "die modis sollen bei all diesen voschlaegen auch nur bewerben
koennen. die aufgaben aus der vorlage, da sollen die modis sich nur
bewerben koennen und nur dogfather und die rechte hand sollen annehmen
oder ablehnen koennen, mit einem text als notiz."

WAS SICH AENDERT
----------------
Auf dem Vorlagenbrett steht fuer einen Modi jetzt "Bewerben" statt
"Uebernehmen". Wer sich beworben hat, sieht das an der Karte -- samt
dem Satz, WER antwortet, und einem Weg zurueck. DogFather und die
rechte Hand sehen die Bewerbung an derselben Karte, mit Namen und dem
Wort dazu, und daneben "Annehmen" und "Ablehnen". Beide fragen nach
einer Notiz.

"ALSO NUR" GILT AUCH AM SERVER, nicht nur im Browser: Die alte Tuer
antwortet einem Modi mit 403 und dem Satz, was stattdessen geht. Ein
ausgeblendeter Knopf ist eine Bitte, abgelehnt wird in der Route.

DIE LINKE HAND STEHT ABSICHTLICH NICHT BEI DEN ENTSCHEIDERN
------------------------------------------------------------
Sie gehoert seit dem 22.09. ueberall dazu ("ich will dass die linke
hand auch ueberall zu sehen ist"). Hier hat Filipe genau zwei genannt.
Das ist keine Vergesslichkeit von mir, sondern seine Aufzaehlung -- und
dieselbe Grenze zieht das Haus schon bei den Aufgaben-Bewerbungen
(entscheidetUeberAufgaben). Sie darf weiter VERTEILEN; das hat er nicht
angefasst.

Sie ist deshalb die schaerfste Probe in der Pruefung: Wer statt "darf
entscheiden" nur "darf verteilen" abfragt, laesst sie mitentscheiden --
und niemandem faellt es auf, weil alles funktioniert.

DIE AUFGABE ENTSTEHT ERST MIT DER ZUSAGE
----------------------------------------
Der naheliegende Weg waere gewesen, beim Bewerben gleich die Aufgabe
anzulegen und die vorhandene Bewerbung aus aufgaben_zuteilung
daranzuhaengen. Dann stuende nach zwoelf Absagen zwoelfmal Arbeit auf
dem Brett, die niemand bestellt hat -- und um das einzufangen, muesste
das Ablehnen Aufgaben LOESCHEN. Loeschen als Nebenwirkung einer Absage
ist genau die Sorte Regel, die irgendwann das Falsche trifft.

Also eine eigene, kleine Tabelle (vorlagen_bewerbungen). Bis jemand ja
sagt, gibt es nur eine Zeile. Die Woerter sind dieselben wie drueben
(zustand, entscheid_text, entschieden_von) -- zwei Namen fuer dieselbe
Sache waeren zwei Sprachen im selben Haus.

Und die Zusage legt die Aufgabe ueber DIESELBE Funktion an wie das
Uebernehmen (katalogAufgabeAnlegen, neu, aus dem Katalog-Zweig
herausgeloest). Damit sieht eine erbetene Aufgabe aus wie eine
verteilte: gleiche Frist, gleiche Kategorie, gleiche Kennung. Ein
zweiter Weg waere ein zweiter Satz Regeln.

KLEINIGKEITEN, DIE SONST WEHTUN
-------------------------------
  * "Alle 12 uebernehmen" gibt es nur fuer die, die verteilen. Ein
    "Alle bewerben" waere der schnellste Weg, zwoelf Bitten auf einmal
    loszuschicken -- und damit zwoelf Entscheidungen fuer jemand anderen.
  * Wer eine Aufgabe schon hat, bekommt keinen Bewerben-Knopf. Der
    Server lehnt das ohnehin ab; ein Knopf, der eine Absage holt, ist
    schlimmer als keiner.
  * Nach einer Absage darf man sich wieder bewerben. Der eindeutige
    Index gilt deshalb nur fuer OFFENE Bewerbungen -- ueber alle
    Zustaende waere eine Absage ein Bann.
  * Gesucht wird ueber den SCHLUESSEL der Vorlage, nicht ueber die
    Nummer in der Liste. Die Nummer verschiebt sich, sobald jemand eine
    Vorlage einfuegt -- genau dieser Fehler ist am 16.09. schon einmal
    passiert.

GEPRUEFT
--------
pruef-modi-katalog: 95 Pruefungen, 0 Fehler (vorher 49).

Die Pruefung ist beim Umbau ROT geworden -- 9 Zeilen, alle dort, wo ein
Modi sich selbst etwas nahm. Richtig so, sie hat die Aenderung bemerkt.
Sie steht jetzt auf dem neuen Weg und misst ihn ganz:

  * der Modi kommt an die alte Tuer nicht mehr heran (403, erst_bewerben)
  * die Bewerbung legt NOCH KEINE Aufgabe an
  * die linke Hand darf verteilen, aber nicht entscheiden (403)
  * der Bewerber selbst erst recht nicht (403)
  * die Zusage erzeugt die Aufgabe -- mit Kategorie, Frist, Besitzer
  * die Notizen stehen in der Datenbank, samt WER entschieden hat
    (direkt gelesen: ein Feld, das der Server annimmt und nirgends
    speichert, saehe von aussen genauso aus)
  * nach einer Absage geht es wieder
  * am Bildschirm: alle Knoepfe heissen "Bewerben", kein einziger
    "Uebernehmen" mehr, die wartende Karte nennt, wer antwortet --
    und DogFather klickt sich durch Annehmen samt Notizfeld, bis die
    Aufgabe auf dem Brett steht

Die Gegenprobe in Abschnitt 7 lief mit dem Zugang des Modis und haette
ab heute nur noch bewiesen, dass die Rechtepruefung greift -- sie
benutzt jetzt DogFather. Genau so verliert eine Pruefung still ihren
Sinn.

pruef-aufgaben-vorlagen: unveraendert gruen.

ZWEI FUNDE NEBENHER, BEIDE AELTER ALS DIESE AENDERUNG -- gemessen, nicht
vermutet (mit gestashten Aenderungen gegengeprueft):
  * pruef-modi-wortleck ist seit dem 22.09. rot: Der Rollenname steht
    in team.css und teamlage.js, also in Dateien, die jeder bekommt.
  * pruef-zuteilung stuerzt seit laengerem ab (#neu-oeffnen ist
    verborgen). Beides kommt als naechstes, getrennt.

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-23 10:59:51 +02:00
co-authored by Claude Opus 5
parent 256ea6f7c0
commit e736a12cff
45 changed files with 1652 additions and 649 deletions
+300 -16
View File
@@ -36,8 +36,18 @@
import express from "express";
import {
db, sitzungLesen, istLeitung, darfCreator, protokolliere, echteIp, kategorienFuer,
termineSichtbar, MODI_KATEGORIEN, MODI_STUFEN,
db,
sitzungLesen,
istLeitung,
darfCreator,
protokolliere,
echteIp,
kategorienFuer,
termineSichtbar,
MODI_KATEGORIEN,
MODI_STUFEN,
entscheidetUeberAufgaben,
darfAufgabenVerteilen,
} from "./workspace.js";
export const vorlagenRouter = express.Router();
@@ -1431,6 +1441,26 @@ vorlagenRouter.get("/workspace/api/vorlagen", (req, res) => {
aufbauplan: kategorienFuer(req.person).length
? { gruppen: MODI_GRUPPEN, aufgaben: MODI_KATALOG }
: null,
/* ==== DIE BEWERBUNGEN KOMMEN MIT (23.09.2026) =================
Sie stehen in DERSELBEN Antwort wie der Katalog und nicht in
einer zweiten Abfrage. Das Brett zeichnet sich bei jedem
Kategoriewechsel neu; eine eigene Abfrage daneben waere ein
zweiter Weg, auf dem die beiden auseinanderlaufen koennen --
und man saehe eine Karte als "beworben", die es nicht mehr ist.
WER WAS SIEHT, entscheidet vorlagenBewerbungenFuer(): Wer
entscheidet, bekommt alle offenen; alle anderen nur ihre
eigenen. Im Browser zu filtern hiesse, die fremden Namen
trotzdem auszuliefern.
UND OB ICH ENTSCHEIDEN DARF, sagt ebenfalls der Server. Die
Oberflaeche vergleicht keine Rollennamen -- assets/js/aufgaben.js
bekommt jeder, der die Seite oeffnet. */
bewerbungen: kategorienFuer(req.person).length
? vorlagenBewerbungenFuer(req.person) : null,
darf_entscheiden: entscheidetUeberAufgaben(req.person),
darf_verteilen: darfAufgabenVerteilen(req.person),
});
});
@@ -1454,6 +1484,253 @@ function gleicheHerkunft(req, res, next) {
next();
}
/* =====================================================================
AUS EINER VORLAGE WIRD EINE AUFGABE -- an EINER Stelle (23.09.2026)
Dieselben acht Zeilen standen im Zweig "katalog" der Uebernehmen-
Route. Seit eine Zusage auf eine Bewerbung dasselbe tut, braucht es
sie zweimal -- und zwei Fassungen desselben INSERT sind zwei
Gelegenheiten, dass eine davon beim naechsten Feld nicht mitgeht.
DIE FRIST WIRD IN ORTSZEIT GERECHNET. Ueber toISOString kaeme
zwischen Mitternacht und zwei Uhr der Vortag heraus -- derselbe
Fehler, der im Haus schon einmal eine Pruefung falsch rot gemacht
hat.
DIE KENNUNG DER VORLAGE WANDERT MIT. Nur so kann das Brett spaeter
zeigen, was schon uebernommen ist -- der Titel taugt dafuer nicht,
er darf geaendert werden. */
function katalogAufgabeAnlegen(v, zielId, vonId) {
const d = new Date(Date.now() + (v.tage || 7) * 86400_000);
const frist = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`
+ `-${String(d.getDate()).padStart(2, "0")}`;
db().prepare(`INSERT INTO aufgaben
(titel, beschreibung, status, prioritaet, verantwortlich_id, frist,
kategorie, vorlage, erstellt, erstellt_von)
VALUES (?,?,'offen',?,?,?,?,?,?,?)`)
.run(v.titel, v.text, v.tage <= 1 ? "hoch" : "mittel",
zielId, frist, v.kategorie, v.schluessel, jetzt(), vonId);
return db().prepare("SELECT last_insert_rowid() AS id").get().id;
}
/* Wie lang darf ein Wort zu einer Bewerbung sein? Dieselbe Groesse wie
drueben bei den Aufgaben -- ein Satz, kein Aufsatz. */
const BEWERBUNG_TEXT_MAX = 600;
/** Die offenen Bewerbungen, so wie sie die Seite braucht.
*
* WER WAS SIEHT, ENTSCHEIDET HIER DER SERVER: Wer entscheidet, sieht
* alle offenen; alle anderen sehen nur die eigenen. Im Browser zu
* filtern hiesse, die fremden Namen trotzdem auszuliefern -- und
* assets/js/aufgaben.js bekommt jeder, der die Seite oeffnet.
*/
function vorlagenBewerbungenFuer(person) {
const darf = entscheidetUeberAufgaben(person);
const zeilen = db().prepare(`
SELECT b.id, b.vorlage, b.kategorie, b.person_id, b.text, b.zustand,
b.entscheid_text, b.entschieden_am, b.erstellt, p.name AS person_name
FROM vorlagen_bewerbungen b
LEFT JOIN personen p ON p.id = b.person_id
WHERE b.zustand = 'beworben' ${darf ? "" : "AND b.person_id = ?"}
ORDER BY b.id`).all(...(darf ? [] : [person.id]));
return zeilen.map((z) => ({
id: z.id, vorlage: z.vorlage, kategorie: z.kategorie,
person_id: z.person_id, person_name: z.person_name || "Jemand",
text: z.text || null, erstellt: z.erstellt,
selbst: z.person_id === person.id,
}));
}
/* =====================================================================
SICH AUF EINE VORLAGE BEWERBEN (23.09.2026)
Filipe: "die modis sollen bei all diesen voschlaegen auch nur
bewerben koennen. die aufgaben aus der vorlage, da sollen die modis
sich nur bewerben koennen und nur dogfather und die rechte hand
sollen annehmen oder ablehnen koennen, mit einem text als notiz."
WER DARF WAS -- und die zweite Zeile ist die, die er ausdruecklich
gesagt hat:
bewerben wer NICHT verteilen darf (die Modis)
entscheiden DogFather und die rechte Hand
uebernehmen wer verteilen darf, wie bisher
DIE LINKE HAND STEHT ABSICHTLICH NICHT BEI DEN ENTSCHEIDERN. Sie
gehoert sonst ueberall dazu (Auftrag vom 22.09.: "ich will dass die
linke hand auch ueberall zu sehen ist"), hier hat Filipe genau zwei
genannt. Das ist keine Vergesslichkeit von mir, sondern seine
Aufzaehlung -- und dieselbe Grenze zieht das Haus schon bei den
Aufgaben-Bewerbungen (entscheidetUeberAufgaben).
DER TEXT IST FREIWILLIG BEIM BEWERBEN und freiwillig beim
Entscheiden. Beim ABLEHNEN einer zugeteilten Aufgabe ist eine
Begruendung Pflicht -- dort sagt jemand ab, der gefragt wurde. Hier
bittet jemand; ein "bitte" braucht keine Begruendung. Filipes Wort
ist "mit einem text als notiz", also eine Moeglichkeit, keine Huerde.
===================================================================== */
/** Die Vorlage zu einer Kennung -- oder null.
* Gesucht wird ueber den SCHLUESSEL und nicht ueber die Nummer in der
* Liste: Die Nummer verschiebt sich, sobald jemand eine Vorlage
* einfuegt, und dann bewirbt man sich auf etwas anderes, als man
* gesehen hat. Genau dieser Fehler ist am 16.09. schon einmal
* passiert. */
function vorlageZuSchluessel(schluessel) {
return MODI_AUFGABEN_FLACH.find((v) => v.schluessel === schluessel) || null;
}
vorlagenRouter.post("/workspace/api/vorlagen/bewerben", gleicheHerkunft,
express.json({ limit: "4kb" }), (req, res) => {
try {
if (!kategorienFuer(req.person).length) {
/* Wortgleich mit einer erfundenen Vorlage -- wer den Katalog
nicht bekommt, soll nicht erfahren, dass es ihn gibt. */
return res.status(400).json({ fehler: "Unbekannte Vorlage." });
}
/* WER VERTEILEN DARF, BEWIRBT SICH NICHT. Er traegt sich ein --
eine Bitte an sich selbst waere ein Vorgang ohne Gegenueber,
und im schlimmsten Fall entscheidet jemand ueber die eigene
Bewerbung. */
if (darfAufgabenVerteilen(req.person)) {
return res.status(403).json({ fehler: "du_entscheidest_selbst" });
}
const v = vorlageZuSchluessel(String(req.body?.vorlage || ""));
if (!v) return res.status(400).json({ fehler: "Unbekannte Vorlage." });
const text = String(req.body?.text ?? "").trim().slice(0, BEWERBUNG_TEXT_MAX) || null;
const d = db();
/* SCHON BEWORBEN? Die Datenbank sagt es ohnehin (der Index ist
eindeutig) -- aber eine saubere Antwort ist besser als ein
Fehler aus der Tiefe. */
const schon = d.prepare(`SELECT id FROM vorlagen_bewerbungen
WHERE vorlage = ? AND person_id = ? AND zustand = 'beworben'`)
.get(v.schluessel, req.person.id);
if (schon) return res.status(409).json({ fehler: "schon_beworben" });
/* UND LIEGT SIE SCHON AUF DEM BRETT? Sich auf etwas zu bewerben,
das man bereits hat, ist eine Bitte ins Leere. */
const liegtSchon = d.prepare(`SELECT id FROM aufgaben
WHERE vorlage = ? AND verantwortlich_id = ? AND status <> 'erledigt'`)
.get(v.schluessel, req.person.id);
if (liegtSchon) return res.status(409).json({ fehler: "liegt_schon_bei_dir" });
d.prepare(`INSERT INTO vorlagen_bewerbungen
(vorlage, kategorie, person_id, text, zustand, erstellt)
VALUES (?,?,?,?,'beworben',?)`)
.run(v.schluessel, v.kategorie, req.person.id, text, jetzt());
protokolliere("vorlage_beworben", {
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
detail: `${v.schluessel} ${v.titel}`.slice(0, 120),
});
res.status(201).json({ ok: true, bewerbungen: vorlagenBewerbungenFuer(req.person) });
} catch (f) {
console.error("[vorlagen] bewerben:", f?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
/* ---- Die eigene Bewerbung zuruecknehmen ------------------------------
Sie wird GELOESCHT und nicht auf "zurueckgezogen" gesetzt: Wer sich
nicht mehr bewirbt, hat nichts getan, was jemand nachlesen muesste --
und eine Zeile, die nur noch sagt "hier stand mal eine Bewerbung",
waere in der Liste der Leitung Laerm. Dieselbe Entscheidung wie bei
den Aufgaben-Bewerbungen. */
vorlagenRouter.post("/workspace/api/vorlagen/bewerbung-zurueck", gleicheHerkunft,
express.json({ limit: "2kb" }), (req, res) => {
try {
const id = Number(req.body?.id);
if (!Number.isInteger(id)) return res.status(400).json({ fehler: "ungueltig" });
const b = db().prepare("SELECT * FROM vorlagen_bewerbungen WHERE id = ?").get(id);
/* NICHT MEINE = GIBT ES NICHT. Ein 403 verriete, dass es sie
gibt und wem sie gehoert. */
if (!b || b.person_id !== req.person.id || b.zustand !== "beworben") {
return res.status(404).json({ fehler: "nicht_gefunden" });
}
db().prepare("DELETE FROM vorlagen_bewerbungen WHERE id = ?").run(id);
protokolliere("vorlage_bewerbung_zurueck", {
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
detail: String(b.vorlage).slice(0, 120),
});
res.json({ ok: true, bewerbungen: vorlagenBewerbungenFuer(req.person) });
} catch (f) {
console.error("[vorlagen] bewerbung-zurueck:", f?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
/* ---- Entscheiden: annehmen oder ablehnen ------------------------------
EINE SCHLEIFE FUER BEIDE WEGE. Zwei fast gleiche Routen waeren zwei
Gelegenheiten, dass eine die Rechtepruefung oder das Protokoll
vergisst -- und es ist immer die zweite.
BEI DER ZUSAGE ENTSTEHT DIE AUFGABE, und zwar ueber dieselbe
Funktion wie beim Uebernehmen (katalogAufgabeAnlegen). Damit sieht
eine erbetene Aufgabe genauso aus wie eine verteilte: gleiche Frist,
gleiche Kategorie, gleiche Kennung. Ein zweiter Weg waere ein
zweiter Satz Regeln. */
for (const [weg, ja] of [["annehmen", true], ["ablehnen", false]]) {
vorlagenRouter.post(`/workspace/api/vorlagen/bewerbung/${weg}`, gleicheHerkunft,
express.json({ limit: "4kb" }), (req, res) => {
try {
/* NUR DOGFATHER UND DIE RECHTE HAND -- woertlich nach Filipes
Aufzaehlung, und dieselbe Schranke wie bei den
Aufgaben-Bewerbungen. */
if (!entscheidetUeberAufgaben(req.person)) {
return res.status(403).json({ fehler: "nicht_erlaubt" });
}
const id = Number(req.body?.id);
if (!Number.isInteger(id)) return res.status(400).json({ fehler: "ungueltig" });
const d = db();
const b = d.prepare("SELECT * FROM vorlagen_bewerbungen WHERE id = ?").get(id);
if (!b || b.zustand !== "beworben") {
return res.status(409).json({ fehler: "keine_bewerbung" });
}
const v = vorlageZuSchluessel(b.vorlage);
if (!v) return res.status(409).json({ fehler: "vorlage_weg" });
/* GIBT ES DIE PERSON NOCH? Zwischen Bewerbung und Antwort
koennen Tage liegen. Eine Aufgabe an einen abgeschalteten
Zugang waere Arbeit, die nie jemand sieht. */
const wer = d.prepare(
"SELECT id, name FROM personen WHERE id = ? AND aktiv = 1").get(b.person_id);
if (!wer) return res.status(409).json({ fehler: "person_weg" });
const kommentar = String(req.body?.kommentar ?? "").trim()
.slice(0, BEWERBUNG_TEXT_MAX) || null;
const nun = jetzt();
let aufgabeId = null;
if (ja) {
aufgabeId = katalogAufgabeAnlegen(v, wer.id, req.person.id);
}
d.prepare(`UPDATE vorlagen_bewerbungen
SET zustand = ?, entscheid_text = ?, entschieden_von = ?,
entschieden_am = ?, aufgabe_id = ?
WHERE id = ?`)
.run(ja ? "angenommen" : "abgelehnt", kommentar, req.person.id,
nun, aufgabeId, id);
protokolliere(ja ? "vorlage_bewerbung_angenommen" : "vorlage_bewerbung_abgelehnt", {
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
detail: `${b.vorlage} fuer ${wer.name}`.slice(0, 120),
});
res.json({
ok: true, zustand: ja ? "angenommen" : "abgelehnt",
aufgabe_id: aufgabeId,
bewerbungen: vorlagenBewerbungenFuer(req.person),
});
} catch (f) {
console.error(`[vorlagen] bewerbung/${weg}:`, f?.message);
res.status(503).json({ fehler: "nicht_verfuegbar" });
}
});
}
vorlagenRouter.post("/workspace/api/vorlagen/uebernehmen", gleicheHerkunft,
express.json({ limit: "16kb" }), (req, res) => {
try {
@@ -1572,9 +1849,26 @@ vorlagenRouter.post("/workspace/api/vorlagen/uebernehmen", gleicheHerkunft,
bekommt, soll nicht erfahren, dass es ihn gibt. */
return res.status(400).json({ fehler: "Unbekannte Art." });
}
const zielId = req.person.rolle === "modi"
? req.person.id
: Number(req.body.person_id) || null;
/* ==== WER SICH HIER SELBST ETWAS NIMMT (23.09.2026) ======
Filipe: "die modis sollen bei all diesen voschlaegen auch
nur bewerben koennen."
Bis heute stand hier: Ein Modi nimmt sich die Aufgabe
selbst. Jetzt geht das ueber eine Bewerbung -- und zwar
HIER abgelehnt und nicht nur im Browser ausgeblendet. Ein
ausgeblendeter Knopf ist eine Bitte; abgelehnt wird an
dieser Stelle.
GEPRUEFT WIRD "DARF VERTEILEN" UND NICHT "IST MODI": Die
Frage ist nicht, wer jemand IST, sondern was er darf. So
gilt die Regel auch fuer jede Rolle, die morgen dazukommt --
und in dieser Datei steht kein Rollenname, der nicht
hineingehoert. */
if (!darfAufgabenVerteilen(req.person)) {
return res.status(403).json({ fehler: "erst_bewerben" });
}
const zielId = Number(req.body.person_id) || null;
if (!zielId) return res.status(400).json({ fehler: "Bitte zuerst eine Person wählen." });
/* Nur an jemanden, fuer den die Kategorien ueberhaupt gelten --
sonst landete eine Modi-Aufgabe samt Kategorie an einem
@@ -1607,17 +1901,7 @@ vorlagenRouter.post("/workspace/api/vorlagen/uebernehmen", gleicheHerkunft,
return res.status(400).json({ fehler: "Unbekannte Vorlage." });
}
for (const v of auswahl) {
/* Frist in ORTSZEIT gerechnet. Ueber toISOString kaeme
zwischen Mitternacht und zwei Uhr der Vortag heraus. */
const d = new Date(Date.now() + (v.tage || 7) * 86400_000);
const frist = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}`
+ `-${String(d.getDate()).padStart(2, "0")}`;
db().prepare(`INSERT INTO aufgaben
(titel, beschreibung, status, prioritaet, verantwortlich_id, frist,
kategorie, vorlage, erstellt, erstellt_von)
VALUES (?,?,'offen',?,?,?,?,?,?,?)`)
.run(v.titel, v.text, v.tage <= 1 ? "hoch" : "mittel",
zielPerson.id, frist, v.kategorie, v.schluessel, jetzt(), req.person.id);
katalogAufgabeAnlegen(v, zielPerson.id, req.person.id);
angelegt.push(v.titel);
}