Manager sehen nur noch ihre zugeteilten Scouts -- und deren Creator
Wunsch vom 01.09.2026: "er soll nur die Scouts sehen, die ihm zugeteilt sind." Dazu entschieden: Ein Manager sieht dann AUCH die Creator dieser Scouts, und zuteilen darf NUR DogFather. WAS VORHER WAR. Ein Manager sah die gesamte Scout-Pipeline -- alle Leads aller Scouts, dazu dieselben in der Suche und in "Was ist dran". Das war die letzte Stelle, an der "nur DogFather sieht alles" noch nicht galt. EINE EIGENE TABELLE, KEIN ZWEITER EINTRAG IN `betreuung`. Dort heisst die Spalte creator_id, und der ganze uebrige Code liest sie als "das ist ein Creator". Ein Scout darin waere technisch moeglich und fachlich eine Luege gewesen: betreuteIds() gaebe Scout-Nummern zurueck, die anderswo als Creator behandelt wuerden. Solche Abkuerzungen raechen sich genau dann, wenn niemand mehr weiss, dass sie getroffen wurden. DIE KETTE steht an EINER Stelle (betreuteIds in workspace.js): Manager -> seine Scouts -> deren Creator. Ohne sie muesste jeder Creator einem Manager einzeln zugewiesen werden, und beim ersten vergessenen faende er ein Loch in seiner Uebersicht, ohne zu merken, dass es eines ist. Dieselbe Regel gilt fuer Leads in Pipeline, Suche und Hinweisen -- aus einer Quelle (pipelineIds), nicht dreimal abgeschrieben. ZUTEILEN DARF NUR DOGFATHER, und das ist keine Foermlichkeit: Diese Zuteilung ERWEITERT die Sicht eines Managers. Duerfte er sie selbst setzen, koennte er sich seine eigene Sichtbarkeit vergeben -- eine Grenze, die der Begrenzte selbst verschieben kann, ist keine. Deshalb istDogFather und ausdruecklich NICHT istLeitung. In der Personenliste steht bei jedem Scout "Gehoert zu", sichtbar nur fuer DogFather. Der Leerwert heisst "— direkt bei DogFather —" und nicht "— niemand —": Ein Scout ohne Manager ist nicht unbetreut, er haengt an DogFather. Das ist ein Zustand, kein Mangel. NEBENBEI KORRIGIERT: In der Zustaendigkeits-Route stand als Kommentar noch "ein Eintrag auf DogFather oder Manager aendert an den Rechten nichts, die Leitung sieht ohnehin jeden Creator". Das gilt seit heute nicht mehr -- fuer einen Manager entscheidet dieser Eintrag jetzt sehr wohl ueber die Sichtbarkeit. Ein falscher Kommentar ist schlimmer als keiner: Er wird geglaubt. DIE PRUEFUNG STELLT DEN MISSBRAUCH AN DEN ANFANG. Diese Aenderung erweitert Sichtbarkeit -- alles andere heute hat sie eingeschraenkt. Ein Fehler dort zeigt jemandem zu wenig und faellt auf; ein Fehler hier zeigt zu viel und faellt niemandem auf. Geprueft wird deshalb: Manager und Scout duerfen nicht zuteilen (404, und es wird auch wirklich nichts geschrieben), Scout an Scout und Scout an DogFather werden abgewiesen, ein Creator laesst sich nicht zuteilen. Danach die Kette in beide Richtungen, das Zuruecknehmen, und dass ein Scout zu genau einem Manager gehoert. Ein lehrreicher Fehlschlag in der Pruefung selbst: Sie meldete, die Auswahl fehle in der Oberflaeche. Sie fehlte nicht -- die Personenliste ist nach Rollen ZUGEKLAPPT, und die Pruefung hatte nicht aufgeklappt. Sah aus wie ein Produktfehler, war einer der Pruefung. Sie klappt jetzt auf und stellt vorher fest, dass wirklich alle sieben Zeilen dastehen. Gesamtlauf: 30 von 30 Dateien, 1210 von 1210 Einzelpunkten. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+91
-1
@@ -553,6 +553,34 @@ export function db() {
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_betreuung_betreuer ON betreuung (betreuer_id);
|
||||
|
||||
/* Welcher Scout gehoert zu welchem Manager (01.09.2026).
|
||||
|
||||
"er soll nur die Scouts sehen, die ihm zugeteilt sind."
|
||||
|
||||
WARUM EINE EIGENE TABELLE und nicht ein zweiter Eintrag in
|
||||
betreuung: Dort heisst die Spalte creator_id, und der ganze
|
||||
uebrige Code liest sie als "das ist ein Creator". Ein Scout in
|
||||
dieser Spalte waere technisch moeglich und fachlich eine Luege --
|
||||
betreuteIds() gaebe dann Scout-Nummern zurueck, die anderswo als
|
||||
Creator behandelt wuerden. Solche Abkuerzungen raechen sich
|
||||
genau dann, wenn niemand mehr weiss, dass sie getroffen wurden.
|
||||
|
||||
Ein Scout gehoert zu hoechstens EINEM Manager -- deshalb ist
|
||||
scout_id der Schluessel. Eine Zuteilung an mehrere waere die
|
||||
Frage "wer ist zustaendig?" ohne Antwort.
|
||||
|
||||
ON DELETE CASCADE auf beiden Seiten: Verschwindet der Scout oder
|
||||
der Manager, ist die Zuteilung gegenstandslos. Sie stehenzulassen
|
||||
hiesse, dass eine geloeschte Person weiter Sichtbarkeit steuert. */
|
||||
CREATE TABLE IF NOT EXISTS scout_zuteilung (
|
||||
scout_id INTEGER PRIMARY KEY REFERENCES personen(id) ON DELETE CASCADE,
|
||||
manager_id INTEGER NOT NULL REFERENCES personen(id) ON DELETE CASCADE,
|
||||
seit TEXT NOT NULL,
|
||||
gesetzt_von INTEGER REFERENCES personen(id) ON DELETE SET NULL
|
||||
);
|
||||
CREATE INDEX IF NOT EXISTS idx_scout_zuteilung_manager
|
||||
ON scout_zuteilung (manager_id);
|
||||
|
||||
/* Meeting-Protokoll zu einem Termin (Konzept, Seite 13).
|
||||
Bewusst eine eigene Tabelle statt neuer Spalten in termine: Es
|
||||
gibt hier keine Migrationen, und ein Protokoll gehoert ohnehin
|
||||
@@ -909,13 +937,75 @@ export function codeErzeugen(gruppen = 4, laenge = 4) {
|
||||
export function betreuteIds(person) {
|
||||
if (!person || (person.rolle !== "scout" && person.rolle !== "manager")) return [];
|
||||
try {
|
||||
return db().prepare("SELECT creator_id FROM betreuung WHERE betreuer_id = ?")
|
||||
const eigene = db().prepare("SELECT creator_id FROM betreuung WHERE betreuer_id = ?")
|
||||
.all(person.id).map((z) => z.creator_id);
|
||||
if (person.rolle !== "manager") return eigene;
|
||||
|
||||
/* DIE KETTE: Manager -> seine Scouts -> deren Creator (01.09.2026).
|
||||
|
||||
Entschieden auf die Frage "sieht er dann auch die Creator dieser
|
||||
Scouts?" -- "ja, alles seiner Scouts". Das ist die uebliche
|
||||
Ordnung: Wer einen Scout fuehrt, muss sehen, woran der arbeitet.
|
||||
Ohne das muesste jeder Creator einem Manager EINZELN zugewiesen
|
||||
werden, und beim ersten vergessenen faende er ein Loch in seiner
|
||||
Uebersicht, ohne zu merken, dass es eines ist.
|
||||
|
||||
Ein Set, weil ein Creator auf beiden Wegen kommen kann: direkt
|
||||
zugeteilt UND ueber seinen Scout. Doppelte Nummern wuerden in den
|
||||
IN-Listen zu doppelten Fragezeichen -- fachlich harmlos, aber
|
||||
jede Abfrage unnoetig laenger. */
|
||||
const scouts = scoutsVon(person.id);
|
||||
if (!scouts.length) return eigene;
|
||||
const ueberScouts = db().prepare(
|
||||
`SELECT creator_id FROM betreuung
|
||||
WHERE betreuer_id IN (${scouts.map(() => "?").join(",")})`)
|
||||
.all(...scouts).map((z) => z.creator_id);
|
||||
return [...new Set([...eigene, ...ueberScouts])];
|
||||
} catch {
|
||||
return []; // im Zweifel nichts sehen, nie mehr
|
||||
}
|
||||
}
|
||||
|
||||
/** Die Scouts, die diesem Manager zugeteilt sind. Fuer alle anderen
|
||||
* leer -- ein Scout fuehrt keine Scouts, ein Creator schon gar nicht.
|
||||
* DogFather braucht sie nicht: Er sieht ohnehin alles. */
|
||||
export function scoutsVon(managerId) {
|
||||
if (!managerId) return [];
|
||||
try {
|
||||
return db().prepare("SELECT scout_id FROM scout_zuteilung WHERE manager_id = ?")
|
||||
.all(managerId).map((z) => z.scout_id);
|
||||
} catch {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
/** Wessen Leads darf diese Person sehen? Gibt die Personennummern
|
||||
* zurueck, deren Pipeline sichtbar ist -- der eigene immer dabei.
|
||||
* Ein Scout sieht nur sich, ein Manager sich und seine Scouts. */
|
||||
export function pipelineIds(person) {
|
||||
if (!person) return [];
|
||||
if (person.rolle !== "manager") return [person.id];
|
||||
return [...new Set([person.id, ...scoutsVon(person.id)])];
|
||||
}
|
||||
|
||||
/** Zuteilung setzen oder loesen (null loest sie).
|
||||
* Wer das DARF, entscheidet die Route -- hier steht nur, WIE. */
|
||||
export function scoutZuteilungSetzen(scoutId, managerId, akteur = null) {
|
||||
const d = db();
|
||||
if (managerId === null) {
|
||||
d.prepare("DELETE FROM scout_zuteilung WHERE scout_id = ?").run(scoutId);
|
||||
return;
|
||||
}
|
||||
d.prepare(`
|
||||
INSERT INTO scout_zuteilung (scout_id, manager_id, seit, gesetzt_von)
|
||||
VALUES (?,?,?,?)
|
||||
ON CONFLICT(scout_id) DO UPDATE SET
|
||||
manager_id = excluded.manager_id,
|
||||
seit = excluded.seit,
|
||||
gesetzt_von = excluded.gesetzt_von`)
|
||||
.run(scoutId, managerId, new Date().toISOString(), akteur);
|
||||
}
|
||||
|
||||
/* SQL-Baustein "diese Spalte gehoert zu einem meiner Creator".
|
||||
Gibt null zurueck, wenn es nichts zu ergaenzen gibt -- eine leere
|
||||
IN-Liste waere ungueltiges SQL. */
|
||||
|
||||
Reference in New Issue
Block a user