Aus einer Idee wird Arbeit -- mit einem Knopf statt mit Abtippen

Stufe 9 aus dem Plan zur Perfektion: "Idee -> Aufgabe/Termin".

WARUM DAS MEHR IST ALS EINE BEQUEMLICHKEIT

Das ganze Haus steht auf einem Satz: "Was hier nicht steht, passiert
nicht." Ein Ideenbrett, aus dem keine Aufgabe werden kann, ist der eine
Ort, an dem dieser Satz nicht gilt -- dort steht etwas, und passieren
tut es trotzdem nicht. Wer eine Idee umsetzen wollte, tippte sie ein
zweites Mal ab. Und was man abtippt, tippt man irgendwann nicht mehr ab.

DREI ENTSCHEIDUNGEN

  GENAU EINMAL. Ein zweiter Versuch fuehrt nicht zu einer zweiten
  Aufgabe, sondern zum Verweis auf die vorhandene (409). Gefragt wird
  an der AUFGABE, nicht an der Idee: Dort steht die Tatsache, und sie
  kann nicht auseinanderlaufen.

  DIE IDEE BLEIBT STEHEN. Sie wird nicht verschoben und nicht geloescht
  -- wer nachsieht, was aus einem Gedanken geworden ist, soll den
  Gedanken noch finden, und daneben die Antwort.

  DIE AUFGABE WEISS, WOHER SIE KAM. `aus_eintrag_id` mit echtem
  Fremdschluessel, nicht als Text im Beschreibungsfeld. Ein Verweis, den
  nur ein Mensch lesen kann, ist kein Verweis. ON DELETE SET NULL, nicht
  CASCADE: Wird die Idee geloescht, bleibt die Arbeit.

NICHT AUS JEDEM BRETT

Aus einem Beitrag im Treff wird keine Aufgabe. Was jemand aus der
Community schreibt, gehoert ihm; daraus stillschweigend Arbeit zu
machen waere eine Verwendung, mit der er nicht rechnet. Welche Bretter
es sind, entscheidet der Server -- die Oberflaeche fragt nach, statt
eine zweite Liste zu fuehren.

WAS ABSICHTLICH NICHT MITWANDERT: die Frist. Eine Idee hat keinen
Termin; wer ihr beim Uebernehmen automatisch einen gaebe, erfaende ihn.
Die Dringlichkeit wandert dagegen mit -- dieselben drei Stufen.

ZUSTAENDIG IST, WER UEBERNIMMT, nicht wer die Idee aufgeschrieben hat.
Eine Aufgabe, die jemandem ohne sein Zutun zugeteilt wird, wird nicht
angefangen.

ZWEIMAL AM FALSCHEN ORT GELANDET

Der Knopf stand erst in `if (lage.team)`, dann immer noch innerhalb von
`if (treffBrett && lage)` -- also beide Male ausgerechnet am Treff und
an keinem Arbeitsbrett. Gefunden hat das beide Male die Pruefung im
Browser ("0 Knoepfe auf dem Ideenbrett"), nicht das Lesen. Jetzt steht
er in der allgemeinen Knopfreihe, hinter `darfEintragen()` -- eine
Uebernahme ist ein Schreibvorgang.

Und die Gegenprobe zur Brettliste lief anfangs ins Leere: Sie fragte
nach `BEREICHE[b].treff`, ein Merkmal, das es nicht gibt, und fand null
Treff-Bretter -- eine Gegenprobe, die nichts gegenprueft. TREFF_BRETTER
steht in workspace.js.

PRUEFUNGEN: pruef-uebernahme neu mit 39, davon 4 im Browser (der Klick
muss eine Aufgabe in der DATENBANK erzeugen, nicht nur eine Meldung).

Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
2026-09-15 12:25:36 +02:00
co-authored by Claude Opus 5
parent b9f261bbac
commit d76d9aa5da
35 changed files with 995 additions and 372 deletions
+58
View File
@@ -426,6 +426,43 @@
if (!a.ok) { melde('Ändern hat nicht geklappt.'); return; }
await laden();
}));
/* AUS EINER IDEE WIRD ARBEIT (15.09.2026, Stufe 9).
HIER und nicht in der Treff-Knopfreihe: Die gehoert ganz zum
Treff (`if (treffBrett && lage)`), und dort waere der Knopf
genau am falschen Ort -- an den Beitraegen der Community, und an
keinem Arbeitsbrett. Zweimal hintereinander dort gelandet;
gefunden hat es beide Male die Pruefung im Browser mit "null
Knoepfe auf dem Ideenbrett", nicht das Lesen.
Welche Bretter Uebernahmen kennen, entscheidet der Server. Eine
zweite Liste hier waere die, die veraltet.
IST ES SCHON GESCHEHEN, steht statt des Knopfes der Verweis. Ein
Knopf, der beim zweiten Druecken "gibt es schon" sagt, laedt zum
zweiten Druecken ein. */
const schon = uebernahmen[e.id];
if (schon) {
const v = el('a', 'eintrag__aufgabe', 'Aufgabe · ' + schon.status);
v.href = 'aufgaben.html#a' + schon.aufgabe_id;
v.title = 'Aus diesem Eintrag ist eine Aufgabe geworden.';
knoepfe.append(v);
} else if (uebernahmeMoeglich) {
knoepfe.append(tuKnopf('zur Aufgabe', async () => {
const a = await hole('/workspace/api/eintrag/' + e.id + '/zur-aufgabe',
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' });
const j = await a.json().catch(() => ({}));
if (!a.ok) {
melde(j.fehler === 'schon_uebernommen'
? 'Daraus gibt es schon eine Aufgabe.'
: (j.fehler || 'Ging nicht.'));
return;
}
melde('Steht jetzt im Aufgabenbrett – bei dir.');
await laden();
}));
}
if (LEITUNG.has(ich.rolle) || e.erstellt_von === ich.id) {
knoepfe.append(tuKnopf('löschen', async () => {
if (!confirm(`„${e.titel}" wirklich löschen?`)) return;
@@ -491,8 +528,29 @@
for (const [wert, name] of Object.entries(einstellung.arten)) ziel.append(knopf(wert, name));
}
/* WAS AUS DEN EINTRAEGEN GEWORDEN IST -- einmal fuer das ganze Brett.
Bei zwanzig Ideen waeren einzelne Abfragen zwanzig Anfragen, und die
Liste stuende zwanzigmal kurz falsch da, bevor sie stimmt. */
let uebernahmen = {};
let uebernahmeMoeglich = false;
async function uebernahmenLaden() {
try {
const a = await fetch(`/workspace/api/bereich/${encodeURIComponent(bereich)}/uebernahmen`,
{ credentials: 'same-origin' });
if (!a.ok) { uebernahmen = {}; uebernahmeMoeglich = false; return; }
const d = await a.json();
uebernahmen = d.uebernahmen || {};
/* OB DER KNOPF HINGEHOERT, ENTSCHEIDET DER SERVER. Eine zweite
Liste der Bretter hier im Browser waere die, die veraltet --
derselbe Fehler wie bei der Rollenreihenfolge am 11.09. */
uebernahmeMoeglich = d.moeglich === true;
} catch { uebernahmen = {}; uebernahmeMoeglich = false; }
}
async function laden() {
try {
await uebernahmenLaden();
const a = await hole(`/workspace/api/bereich/${bereich}`);
if (!a.ok) { melde('Einträge konnten nicht geladen werden.'); return; }
const daten = await a.json();