Scouting: links die normalen Creator, rechts die Premium
Filipe: "ich will dass es da in der mitte eine trennung gibt. links sollen normale creator sein und rechts premium creator. es gibt bei tiktok naemlich diese zwei optionen von streamer ... auch dass wenn man die eintraegt soll man aussuchen koennen." Jede Stufe der Pipeline hat jetzt zwei Spalten mit einer Trennlinie dazwischen. Die Trennung sitzt IN der Stufe, nicht einmal ueber der ganzen Seite: Zwei komplette Pipelines nebeneinander haetten jede Stufenueberschrift verdoppelt und die beiden Seiten waeren nie auf gleicher Hoehe gewesen. GENAU ZWEI WERTE, kein "weiss nicht". Anders als bei `netzwerk`, wo "noch nicht gefragt" eine eigene gueltige Antwort ist: Dort wird eine fremde Tatsache festgehalten, hier eine eigene Absicht -- und deren Normalfall ist "normal". NULL wird als "normal" gelesen, der eine vorhandene Lead steht damit links, ohne dass ihm etwas unterstellt wird. DIE ART UEBERLEBT DIE UEBERGABE. Beim Creator-Onboarding wandert sie auf die Person und ist in der Personenverwaltung aenderbar. Ohne das endet die Angabe genau dort, wo sie zum ersten Mal vertraglich zaehlt. Die Schwelle misst den STUFENKASTEN (@container), nicht das Fenster -- der Fehler vom 06.09.2026 im selben Haus. Auf dem Handy liegen die Spalten untereinander, die senkrechte Linie faellt weg. ZWEI FUNDE BEIM BAUEN, beide von Hauswachen: * `pruef-fingermass` fand, dass meine neue Handy-Messung mit `setViewportSize` statt eigenem Kontext lief -- ohne `hasTouch` greift keine einzige Regel aus `@media (pointer: coarse)`. * Die Klassen hiessen zuerst `.spalte__*` -- die gehoeren `aufgaben.css`, und scouting.html laedt die VOR scouting.css. `margin-left: auto` aus dem Aufgabenbrett zog die Zahl 560 px von ihrem Wort weg, ohne dass eine Pruefung rot wurde. Jetzt `.art-spalte__*`, und der Abstand wird gemessen. pruef-scouting-felder: 28 -> 64 Pruefungen, gruen. Zwei Gegenproben gefahren (Trennung deaktiviert, Spaltenreihenfolge gedreht) -- beide schlugen an. Dazu gruen: haus-trennung, css-klassen, personen-liste, personen-kachel, hand-personen, schranke, formulare, lesbarkeit, agentur, deutsche-texte, tippziele, leerzustand, fingermass. Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
@@ -22,6 +22,11 @@ import {
|
||||
db, protokolliere, echteIp, sitzungLesen, personAnlegen, codeNeu, sitzungToken, personSperren, betreuungSetzen, scoutZuteilungSetzen, istLeitung, istDogFather, siehtModis, siehtAlles, ROLLEN_SORTIERUNG, ROLLEN_REIHE, istSpicy, verborgeneIds, TEAM_DOGI_ROLLEN, darfAnlegen, darfRollenWechseln, darfRolleAendern, rollenZumAendern, hausBedingung, istHand, fuehrtDieZugaenge,
|
||||
} from "./workspace.js";
|
||||
import { sicherungJetzt } from "./workspace-sicherung.js";
|
||||
/* Normal und Premium stehen bei der Scout-Pipeline, weil sie dort
|
||||
entstehen. Hier wird dieselbe Liste benutzt und keine zweite
|
||||
angelegt -- sonst koennte eine Seite einen Wert anbieten, den die
|
||||
andere ablehnt. */
|
||||
import { ARTEN, ART_NAME, artVon } from "./workspace-scouts.js";
|
||||
|
||||
export const personenRouter = express.Router();
|
||||
|
||||
@@ -343,6 +348,12 @@ personenRouter.get("/workspace/api/verwaltung/personen", (req, res) => {
|
||||
res.json({
|
||||
personen: db().prepare(`
|
||||
SELECT p.id, p.name, p.rolle, p.aktiv, p.erstellt, p.letzter_login,
|
||||
/* Normal oder Premium (06.10.2026). Sie kommt beim
|
||||
Creator-Onboarding aus der Scout-Pipeline mit und wird
|
||||
ab da hier gepflegt. Bei allen anderen Rollen ist sie
|
||||
leer und bedeutet nichts -- die Oberflaeche fragt
|
||||
deshalb vorher nach der Rolle, nicht nach dem Wert. */
|
||||
p.creator_art,
|
||||
(SELECT COUNT(*) FROM sitzungen s WHERE s.person_id = p.id) AS sitzungen,
|
||||
(SELECT COUNT(*) FROM aufgaben a
|
||||
WHERE (a.creator_id = p.id OR a.verantwortlich_id = p.id)
|
||||
@@ -383,7 +394,13 @@ personenRouter.get("/workspace/api/verwaltung/personen", (req, res) => {
|
||||
LEFT JOIN scout_zuteilung sz ON sz.scout_id = p.id
|
||||
WHERE 1=1${hausBedingung(req.person, "p.rolle")}
|
||||
ORDER BY ${ROLLEN_SORTIERUNG.replace("rolle", "p.rolle")}, p.aktiv DESC, p.name`)
|
||||
.all().filter((z) => !weg.has(z.id)),
|
||||
.all().filter((z) => !weg.has(z.id))
|
||||
/* NULL heisst "normal" -- aufgeloest wird das hier und nicht in
|
||||
der Oberflaeche, damit es nicht zwei Meinungen darueber gibt.
|
||||
Nur bei Creatorn: Bei allen anderen Rollen bleibt das Feld
|
||||
leer, und "leer" ist dort die richtige Antwort. */
|
||||
.map((z) => (z.rolle === "creator"
|
||||
? { ...z, creator_art: artVon(z.creator_art) } : z)),
|
||||
/* Wer ueberhaupt als zustaendig eingetragen werden kann.
|
||||
|
||||
Bis zum 31.08.2026 waren das nur Scouts. In der Auswahl stand
|
||||
@@ -401,6 +418,14 @@ personenRouter.get("/workspace/api/verwaltung/personen", (req, res) => {
|
||||
WHERE rolle IN ('admin', 'manager', 'scout') AND aktiv = 1
|
||||
ORDER BY ${ROLLEN_SORTIERUNG}, name`).all().filter((z) => !weg.has(z.id)),
|
||||
|
||||
/* Normal und Premium kommen MIT -- aus derselben Liste wie in der
|
||||
Scout-Pipeline. Die Oberflaeche fuehrt keine eigene: Sonst
|
||||
stuenden die beiden Arten an drei Stellen im Haus (Server,
|
||||
Pipeline-Seite, Personenseite), und die dritte waere die, die
|
||||
beim naechsten Mal vergessen wird. Genau so ist es am 10.09.
|
||||
schon einmal mit der Rollenwahl passiert. */
|
||||
arten: ARTEN, art_name: ART_NAME,
|
||||
|
||||
/* =============================================================
|
||||
ROLLEN, DIE NICHT IM BROWSER STEHEN DUERFEN (09.09.2026)
|
||||
|
||||
@@ -601,6 +626,46 @@ personenRouter.put("/workspace/api/verwaltung/betreuung/:id", gleicheHerkunft, (
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- Normal oder Premium (06.10.2026) -----------------------------
|
||||
|
||||
Die Art kommt beim Creator-Onboarding aus der Scout-Pipeline mit. Ab
|
||||
hier haengt sie an der PERSON und laeuft dem Lead nicht mehr
|
||||
hinterher: Ein Lead kann geloescht werden, ein Vertrag kann wechseln,
|
||||
und die Pipeline ist ein Arbeitsstand, kein Register.
|
||||
|
||||
DESHALB MUSS SIE HIER AENDERBAR SEIN. Ein Wert, den man einmal setzt
|
||||
und danach nie wieder -- genau das war Filipes Befund vom 11.09.2026
|
||||
ueber die Pipeline ("man kan da nichts machen"), und ihn hier noch
|
||||
einmal zu bauen waere derselbe Fehler mit einer anderen Spalte. */
|
||||
|
||||
personenRouter.put("/workspace/api/verwaltung/personen/:id/creator-art", gleicheHerkunft, (req, res) => {
|
||||
try {
|
||||
const id = Number(req.params.id);
|
||||
if (!Number.isInteger(id)) return res.status(400).json({ fehler: "ungueltig" });
|
||||
|
||||
const creator = db().prepare("SELECT id, name, rolle FROM personen WHERE id = ?").get(id);
|
||||
/* NUR an Creatorn. Ein Manager mit der Art "Premium" waere eine
|
||||
Angabe, die nirgends etwas bedeutet -- und sie stuende dann in
|
||||
der Liste, als haette jemand sie gemeint. */
|
||||
if (!creator || creator.rolle !== "creator") {
|
||||
return res.status(404).json({ fehler: "nicht_gefunden" });
|
||||
}
|
||||
|
||||
const w = String(req.body?.creator_art ?? "").trim();
|
||||
if (!ARTEN.includes(w)) return res.status(400).json({ fehler: "Unbekannte Creator-Art." });
|
||||
|
||||
db().prepare("UPDATE personen SET creator_art = ? WHERE id = ?").run(w, id);
|
||||
protokolliere("creator_art_gesetzt", {
|
||||
personId: req.person.id, rolle: req.person.rolle, ip: echteIp(req),
|
||||
detail: `#${id} ${creator.name} -> ${ART_NAME[w] || w}`.slice(0, 120),
|
||||
});
|
||||
res.json({ ok: true, creator_art: w });
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Creator-Art setzen:", fehler?.message);
|
||||
res.status(503).json({ fehler: "nicht_verfuegbar" });
|
||||
}
|
||||
});
|
||||
|
||||
/* ---------- Welcher Scout gehoert zu welchem Manager --------------------
|
||||
|
||||
"er soll nur die Scouts sehen, die ihm zugeteilt sind." (01.09.2026)
|
||||
|
||||
Reference in New Issue
Block a user