Die zwei Häuser sind getrennt -- und die Tür geht in beide Richtungen
Filipe: "ich will dass du zuerst die komplette site vn der workspace
seite trennst. da soll nichts verknüpft sein. wenn ich bei der einen
was mache soll nichts bei der anderen passieren. … es soll nur für
dogfather eine kachel geben wo er mit einem einfachen klick von der
einen auf die anderen seite kommt aber sonst garnichts."
Das kehrt die Entscheidung vom 10.09.2026 um ("getrennt wird das
AUSSEHEN, nicht der Bestand"). Wer den alten Kommentar liest, liest
einen überholten Stand -- das steht jetzt an jeder betroffenen Stelle.
WAS GEMESSEN WAR, BEVOR ETWAS GEBAUT WURDE
* Nur drei Module trennten nach Haus (Aufgaben, Bereiche, Dateien).
Chat, Kalender, Wissen, Material, Personenlisten und der Rest nicht.
* Die Trennung war EINSEITIG: nurHaus() griff nur auf crew.
* siehtModis() hebelte sie für DogFather auf der Agenturseite aus --
in seiner Gesprächsliste standen dort beide Häuser nebeneinander.
* Keine haus-Spalte in der Datenbank.
* Der Bestand kreuzte aber kaum: 0 von 86 Terminen gemischt, 0 von 7
Zweier-/Gruppengesprächen, genau EIN Kanal.
WAS JETZT DASTEHT
* Drei Rollenmengen in crew-adresse.js (crew / agentur / beide) und
hausVonRolle(); eine unbekannte Rolle bekommt null, kein Haus.
* Spalte `haus` an acht Wurzeltabellen, nachgetragen aus Belegen:
238 Zeilen eindeutig, die Wissensablage geschlossen der Agentur,
vier Restzeilen namentlich, der gemischte Kanal aufgelöst
(die zwei Scouts gehen heraus, die 7 Nachrichten sind alle vom
Team). Offen bleiben: null.
* nurHaus, hausBedingung und darfAnlegen gelten in BEIDE Richtungen.
* Der siehtModis-Durchgriff ist weg -- aber in DREI Fällen, nicht
zwei: Prüfadressen bekommen gar kein Haus und verhalten sich exakt
wie vorher. Die erste Fassung hatte das übersehen und 19 Prüfungen
umgeworfen, an denen nichts kaputt war.
* Kalender: getrennt, aber "belegt" bleibt (Filipes Entscheidung).
Die Blöcke tragen NUR Beginn und Dauer -- kein Titel, keine Person.
Gebaut als Gegenstück zur Liste (meine Termine MINUS die sichtbaren),
damit beide nicht auseinanderlaufen können.
* Die Wissens-Kachel ist auf der Team-Adresse weg UND die Route
antwortet dort mit 404 -- eine fehlende Kachel ist nur eine Bitte.
* Die Wechsel-Kachel für DogFather geht jetzt in beide Richtungen.
GEPRÜFT: pruef-haus-trennung 97 statt 81, 0 Fehler (vorher 7, alle
haben die alte Regel behauptet). Die neuen Abschnitte sind DORT
eingezogen statt in eine zweite Datei -- `pruef-haustrennung.mjs` hätte
sich von `pruef-haus-trennung.mjs` um einen Bindestrich unterschieden.
Dazu grün: haus-seiten, crew-adresse, chat, chat-kanaele,
kanal-besetzung, kalender, serien, treffchat, wissen-neu,
modi-checkliste, modi-katalog, rechtetafel, personen-liste, sicht,
verborgen, fremde-sicht, alle-wege.
NICHT VON MIR: pruef-treff (3) und pruef-kachel-universum (2) waren
schon vorher rot -- beim Treff auf dem Stand 40b48e89 nachgemessen,
bei den Farben steht dieselbe Zahl im Kopf der Prüfung selbst.
Co-Authored-By: Claude Opus 5 <[email protected]>
This commit is contained in:
+512
-26
@@ -36,10 +36,12 @@ import { hilfeTabellen } from "./hilfe-tabellen.js";
|
||||
import { supportTabellen } from "./support-tabellen.js";
|
||||
import { unterstuetzungTabellen } from "./unterstuetzung-tabellen.js";
|
||||
import { sitzungPasstZurAdresse, istOhneModiAdresse, istCrewAdresse, istPruefAdresse, AUSSEN_ROLLEN,
|
||||
TEAM_DOGI_ROLLEN, CREW_ADRESSE } from "./crew-adresse.js";
|
||||
TEAM_DOGI_ROLLEN, CREW_ADRESSE, WORKSPACE_ADRESSE, AGENTUR_ROLLEN, BEIDE_HAEUSER_ROLLEN,
|
||||
hausVonRolle, rollenImHaus, nurAnderesHaus } from "./crew-adresse.js";
|
||||
/* Weitergereicht, damit die Fachmodule sie wie alles andere aus
|
||||
workspace.js beziehen und nicht wissen muessen, wo sie wohnt. */
|
||||
export { TEAM_DOGI_ROLLEN };
|
||||
export { TEAM_DOGI_ROLLEN, AGENTUR_ROLLEN, BEIDE_HAEUSER_ROLLEN,
|
||||
hausVonRolle, rollenImHaus, nurAnderesHaus };
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
@@ -580,8 +582,16 @@ export function darfAnlegen(person) {
|
||||
Quelle sowohl fuer die Pruefung in der Route als auch fuer die
|
||||
Auswahl in der Oberflaeche -- deshalb verschwinden die anderen
|
||||
Rollen dort von selbst, statt eine Absage zu bringen. */
|
||||
if (person.haus !== "crew") return alle;
|
||||
return alle.filter((r) => HAUS_TEAM_ROLLEN.has(r));
|
||||
/* UND SEIT 24.09.2026 GILT DASSELBE ANDERSHERUM. Bis dahin stand
|
||||
hier „auf der Agenturadresse alles" -- DogFather konnte dort also
|
||||
einen Modi anlegen, der danach im Team-Haus auftauchte, ohne dass
|
||||
er die Seite je gesehen haette. Ein Umbau auf der einen Seite darf
|
||||
auf der anderen nichts bewirken; das Anlegen einer Person ist
|
||||
genau so ein Umbau. */
|
||||
const haus = person.haus;
|
||||
if (haus !== "crew" && haus !== "agentur") return alle;
|
||||
const hier = rollenImHaus(haus);
|
||||
return alle.filter((r) => hier.has(r));
|
||||
}
|
||||
|
||||
/** Wer darf die Rolle einer Person aendern, die schon da ist?
|
||||
@@ -744,8 +754,19 @@ export function ohneDogFather(praefix, spalten = ["creator_id", "erstellt_von"])
|
||||
Dogi": Kaeme morgen eine sechste Rolle dazu, waere sie mit einem
|
||||
`ausser` automatisch in der Agentur, ohne dass jemand darueber
|
||||
nachgedacht hat. Eine Aufzaehlung zwingt zur Entscheidung -- dieselbe
|
||||
Ueberlegung wie bei OHNE_MODI_HOSTS in crew-adresse.js. */
|
||||
const AGENTUR_ROLLEN = new Set(["spicy", "manager", "scout", "creator"]);
|
||||
Ueberlegung wie bei OHNE_MODI_HOSTS in crew-adresse.js.
|
||||
|
||||
SEIT 24.09.2026 STEHT SIE IN crew-adresse.js, nicht mehr hier.
|
||||
Beim Bau der Haustrennung habe ich dort eine zweite, wortgleiche
|
||||
Menge angelegt und es erst gemerkt, als Node den Doppelnamen
|
||||
ablehnte -- also nur, weil zufaellig derselbe Name gewaehlt war.
|
||||
Haette ich sie `AGENTUR` genannt, staenden jetzt zwei Listen da, die
|
||||
beim naechsten Rollenwechsel auseinanderlaufen. Genau die Bauart,
|
||||
die in diesem Haus schon viermal Daten gekostet hat.
|
||||
|
||||
Sie wohnt jetzt bei TEAM_DOGI_ROLLEN und AUSSEN_ROLLEN, wo die
|
||||
anderen beiden Haus-Mengen stehen -- crew-adresse.js hat keine
|
||||
eigenen Importe und ist damit der einzige Ort ohne Kreisgefahr. */
|
||||
|
||||
/* Die gemeinsame Bauweise beider Filter. Sie stand bis zum 10.09.2026
|
||||
nur einmal da, in ohneTeamDogi -- und beim zweiten Haus waere sie
|
||||
@@ -992,9 +1013,21 @@ const MODI_BEREICHE = [
|
||||
{ gruppe: "Für dich", gruppeUnter: "Deine Seite im Team",
|
||||
name: "Mein Steckbrief", unter: "Dein Bild und deine Kanäle", zeichen: "steckbrief",
|
||||
ton: 10, ziel: "steckbrief.html", szene: "halle" },
|
||||
{ gruppe: "Für dich", gruppeUnter: "Deine Seite im Team",
|
||||
name: "Wissen", unter: "Nachschlagen statt nachfragen", zeichen: "wissen",
|
||||
ton: 9, ziel: "wissen.html", szene: "arena" },
|
||||
/* ==== DIE WISSENS-KACHEL IST HIER RAUS (24.09.2026) =============
|
||||
|
||||
Filipe, zur Frage, wohin die neun Dokumente gehören: „diese
|
||||
komplette kachel soll nur im workspace sein."
|
||||
|
||||
NICHT NUR DIE DOKUMENTE, DIE KACHEL. Die Ablage enthält die
|
||||
Schulungen von Spicy Media („SPICY MEDIA 01–04"), OBS, TikTok
|
||||
LIVE Studio — Material für Creator, nicht für die Moderation.
|
||||
Eine Kachel stehenzulassen, hinter der nichts mehr liegt, wäre
|
||||
eine Tür in einen leeren Raum: Man drückt sie jeden Tag einmal
|
||||
und lernt nur, dass sie nichts tut.
|
||||
|
||||
UND DIE ROUTE IST MITGESICHERT (`wissenNurAgentur` weiter unten).
|
||||
Eine fehlende Kachel ist eine Bitte, keine Schranke — die Adresse
|
||||
`wissen.html` kann jeder tippen, der sie einmal gesehen hat. */
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -2698,11 +2731,6 @@ const TEAM_GRUPPE = {
|
||||
die sie ersetzt.
|
||||
===================================================================== */
|
||||
export function zusatzBereicheFuer(person) {
|
||||
/* Auf der Team-Adresse liefert bereicheFuer() ohnehin die Kacheln des
|
||||
Teams. Eine Tuer zu dem Haus, in dem man schon steht, waere ein
|
||||
Knopf, der nichts tut. */
|
||||
if (person?.haus === "crew") return [];
|
||||
|
||||
/* NUR DOGFATHER UND VANVAN -- also `admin`.
|
||||
|
||||
Der erste Entwurf gab die Tuer auch an TEAM_DOGI_ROLLEN (die
|
||||
@@ -2719,15 +2747,46 @@ export function zusatzBereicheFuer(person) {
|
||||
`admin` ist der einzige Fall, der wirklich zwei Haeuser hat. */
|
||||
if (person?.rolle !== "admin") return [];
|
||||
|
||||
/* ==== DIE TUER GEHT JETZT IN BEIDE RICHTUNGEN (24.09.2026) ========
|
||||
|
||||
Filipe: "es soll nur fuer dogfather eine kachel geben wo er mit
|
||||
einem einfachen klick von der einen auf die anderen seite kommt
|
||||
aber sonst garnichts."
|
||||
|
||||
Bis heute stand oben `if (person?.haus === "crew") return [];` --
|
||||
die Tuer gab es also nur im Agenturhaus. Auf der Team-Adresse gab
|
||||
es keinen Weg zurueck; man musste die Adresse tippen. Am 21.09.
|
||||
war das richtig, weil von dort aus ohnehin alles zusammenhing.
|
||||
Seit die Haeuser hart getrennt sind, ist es eine Sackgasse -- und
|
||||
zwar genau die Sorte, die derselbe Absatz weiter oben fuer die
|
||||
andere Richtung schon als Fehler benennt.
|
||||
|
||||
EINE KACHEL, NICHT ZWEI LISTEN: Welches Haus gerade gemeint ist,
|
||||
entscheidet `person.haus`; Name, Ziel und Unterzeile leiten sich
|
||||
daraus ab. Zwei getrennte Bloecke waeren zwei Fassungen desselben
|
||||
Gedankens, und die naechste Aenderung ginge in nur eine davon.
|
||||
|
||||
ZUR ANMELDUNG: Die beiden Adressen haben getrennte Sitzungen (der
|
||||
Keks ist hostgebunden, `path=/workspace`, ohne `domain`). Beim
|
||||
ERSTEN Klick meldet man sich drueben einmal an -- danach haelt es
|
||||
180 Tage. Den Keks auf `.dogfather-universe.com` zu setzen, um das
|
||||
zu sparen, waere falsch: Dann ginge der Team-Keks bei jedem Aufruf
|
||||
an die Agenturadresse mit, also genau die Verbindung, die hier
|
||||
gerade getrennt wird -- und die verborgene Adresse haette eine
|
||||
zweite Spur. */
|
||||
const nachCrew = person.haus !== "crew";
|
||||
|
||||
return [{
|
||||
gruppe: "Team Dogi",
|
||||
gruppe: nachCrew ? "Team Dogi" : "Creator Workspace",
|
||||
gruppeUnter: "Das andere Haus \u2014 eigene Seite, eigene Daten",
|
||||
name: "Zu Team Dogi",
|
||||
unter: "Das Rudel, das Team und die Moderation \u2014 auf ihrer eigenen Adresse",
|
||||
name: nachCrew ? "Zu Team Dogi" : "Zum Creator Workspace",
|
||||
unter: nachCrew
|
||||
? "Das Rudel, das Team und die Moderation \u2014 auf ihrer eigenen Adresse"
|
||||
: "Creator, Scouts und die Agentur \u2014 auf ihrer eigenen Adresse",
|
||||
zeichen: "hinaus",
|
||||
ton: 40,
|
||||
szene: "portal",
|
||||
ziel: CREW_ADRESSE + "/workspace/start.html",
|
||||
ziel: (nachCrew ? CREW_ADRESSE : WORKSPACE_ADRESSE) + "/workspace/start.html",
|
||||
/* AUSSEN heisst: Diese Kachel fuehrt aus dem Haus hinaus. Ohne das
|
||||
Merkmal wuerde nurOffeneKacheln() sie wegfiltern -- es baut aus
|
||||
dem Ziel einen Pfad ("/workspace/" + ziel) und fragt die
|
||||
@@ -2938,6 +2997,262 @@ function checkListeErweitern(d, tabelle, spalte, marker, werte, jetztStempel) {
|
||||
}
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DAS HAUS DER ALTEN ZEILEN NACHTRAGEN (24.09.2026)
|
||||
=====================================================================
|
||||
|
||||
Alles, was vor der Trennung entstanden ist, hat kein Haus. Diese
|
||||
Funktion trägt es nach -- EINMAL, und danach findet sie nichts mehr
|
||||
zu tun (sie fragt nur nach `haus IS NULL`).
|
||||
|
||||
SIE LEITET AB, SIE RÄT NICHT. Für jede Zeile wird gesammelt, welche
|
||||
MENSCHEN daran hängen, und aus deren Rollen das Haus bestimmt:
|
||||
|
||||
* genau ein Haus unter den Beteiligten -> das ist es
|
||||
* beide Häuser unter den Beteiligten -> KONFLIKT, bleibt leer
|
||||
* nur DogFather (oder niemand) -> unbestimmbar, bleibt leer
|
||||
|
||||
DOGFATHER ZÄHLT BEI DER BESTIMMUNG NICHT MIT, und das ist der ganze
|
||||
Trick: Er wohnt in beiden Häusern. Zählte er mit, wäre jede zweite
|
||||
Zeile ein "Konflikt". Er ist kein Beleg -- die anderen sind es.
|
||||
|
||||
WAS LEER BLEIBT, WIRD GENANNT -- mit Tabelle, Nummer und Titel. Eine
|
||||
Nachtragung, die schweigend eine Voreinstellung setzt, verschiebt
|
||||
Termine zwischen Häusern, ohne dass es jemand merkt. Gemessen am
|
||||
echten Stand sind es genau ZWEI Termine; die kann man von Hand
|
||||
entscheiden. Eine Voreinstellung wäre für die 87 anderen richtig und
|
||||
für diese zwei geraten -- und man wüsste nicht, welche zwei.
|
||||
|
||||
BEI DEN EINTRÄGEN ENTSCHEIDET DER BEREICH und nicht der Ersteller.
|
||||
`regeln`, `anschlag`, `highlight` sind Bretter von Team Dogi,
|
||||
`agentur` gehört der Agentur -- das steht fest, unabhängig davon,
|
||||
wer gerade etwas hineingeschrieben hat. Der Ersteller ist bei 20 von
|
||||
26 Einträgen DogFather und damit kein Beleg; der Bereich ist einer.
|
||||
===================================================================== */
|
||||
export function haeuserNachtragen(d) {
|
||||
const meldung = { gesetzt: 0, konflikt: [], offen: [] };
|
||||
try {
|
||||
/* Wer gehört wohin -- einmal gelesen, nicht je Zeile. Bei 19
|
||||
Personen und 250 Zeilen wären das sonst 250 Abfragen für eine
|
||||
Antwort, die sich während des Laufs nicht ändert. */
|
||||
const hausJePerson = new Map();
|
||||
for (const p of d.prepare("SELECT id, rolle FROM personen").all()) {
|
||||
hausJePerson.set(p.id, hausVonRolle(p.rolle));
|
||||
}
|
||||
/* Aus einer Liste von Personennummern das Haus -- oder warum nicht.
|
||||
"beide" (DogFather) und unbekannte Nummern zählen nicht mit. */
|
||||
const hausAus = (ids) => {
|
||||
const gefunden = new Set();
|
||||
for (const i of ids) {
|
||||
const h = hausJePerson.get(i);
|
||||
if (h === "crew" || h === "agentur") gefunden.add(h);
|
||||
}
|
||||
if (gefunden.size === 1) return [...gefunden][0];
|
||||
return gefunden.size > 1 ? "konflikt" : null;
|
||||
};
|
||||
|
||||
/* Je Tabelle: wie komme ich an die beteiligten Menschen?
|
||||
Als Tafel und nicht als sieben Blöcke -- ein achter Eintrag ist
|
||||
dann eine Zeile und keine Kopie. */
|
||||
const TAFEL = [
|
||||
["chat_raeume", (r) => d.prepare(
|
||||
"SELECT person_id AS p FROM chat_teilnehmer WHERE raum_id = ?")
|
||||
.all(r.id).map((z) => z.p), "name"],
|
||||
["termine", (r) => [
|
||||
...d.prepare("SELECT person_id AS p FROM termin_teilnehmer WHERE termin_id = ?")
|
||||
.all(r.id).map((z) => z.p),
|
||||
r.creator_id, r.teilnehmer_id, r.erstellt_von,
|
||||
].filter((x) => x != null), "titel"],
|
||||
["aufgaben", (r) => [r.creator_id, r.verantwortlich_id, r.erstellt_von]
|
||||
.filter((x) => x != null), "titel"],
|
||||
/* DIE DATEI ERBT VON DEM, WORAN SIE HAENGT. Ein Titelbild, das
|
||||
DogFather an einen Eintrag von Team Dogi gehaengt hat, hat
|
||||
ueber die Personen keinen Beleg -- ueber den Eintrag sehr
|
||||
wohl. Gemessen: drei von acht Dateien waeren sonst offen
|
||||
geblieben, obwohl ihr Haus eindeutig feststeht.
|
||||
Die Eintraege werden WEITER UNTEN gesetzt; deshalb liest diese
|
||||
Zeile `eintraege.haus` erst, wenn es schon dasteht -- die
|
||||
Reihenfolge in dieser Funktion ist Absicht, nicht Zufall. */
|
||||
["dateien", (r) => [r.creator_id, r.hochgeladen_von]
|
||||
.filter((x) => x != null), "name_original",
|
||||
(r) => hausVomEltern(d, r)],
|
||||
/* DIE WISSENSABLAGE GEHOERT GANZ DER AGENTUR (24.09.2026,
|
||||
Entscheidung Filipe). Deshalb steht hier ein fester Rückfall
|
||||
und keine Ableitung: Alle neun Dokumente sind von DogFather
|
||||
hochgeladen, an ihnen hängt kein zweiter Mensch — über die
|
||||
Personen gäbe es NIE einen Beleg, und die Zeilen blieben auf
|
||||
Dauer offen. Der Rückfall beantwortet das ein für alle Mal.
|
||||
Käme morgen ein Dokument von einem Creator, zeigte die
|
||||
Ableitung darüber ohnehin schon auf die Agentur. */
|
||||
["wissen", (r) => [r.erstellt_von].filter((x) => x != null), "titel",
|
||||
() => "agentur"],
|
||||
["material", (r) => [r.von_id].filter((x) => x != null), "dateiname"],
|
||||
["termin_serien", (r) => [r.creator_id, r.teilnehmer_id, r.erstellt_von]
|
||||
.filter((x) => x != null), "titel"],
|
||||
];
|
||||
|
||||
/* DIE EINTRAEGE ZUERST -- die Dateien erben von ihnen. Stuenden
|
||||
sie wie vorher danach, liefe die Vererbung ins Leere, und drei
|
||||
Dateien blieben offen, obwohl der Beleg dagewesen waere. Eine
|
||||
Reihenfolge, die man einer Schleife nicht ansieht: deshalb steht
|
||||
sie hier als Satz und nicht nur als Position. */
|
||||
eintraegeNachHaus(d, meldung);
|
||||
restzeilenZuordnen(d, meldung);
|
||||
|
||||
for (const [tabelle, leute, titelSpalte, ausEltern] of TAFEL) {
|
||||
let spalten;
|
||||
try {
|
||||
spalten = d.prepare(`PRAGMA table_info(${tabelle})`).all().map((x) => x.name);
|
||||
} catch { continue; }
|
||||
if (!spalten.includes("haus")) continue;
|
||||
const schreib = d.prepare(`UPDATE ${tabelle} SET haus = ? WHERE id = ?`);
|
||||
for (const zeile of d.prepare(
|
||||
`SELECT * FROM ${tabelle} WHERE haus IS NULL`).all()) {
|
||||
/* ZUERST DIE MENSCHEN, DANN DIE ELTERN. Ein Mensch ist der
|
||||
unmittelbarere Beleg; erst wenn keiner etwas sagt, wird
|
||||
gefragt, woran die Zeile haengt. */
|
||||
const h = hausAus(leute(zeile)) || (ausEltern ? ausEltern(zeile) : null);
|
||||
const wer = `${tabelle}#${zeile.id} „${zeile[titelSpalte] || "ohne Titel"}"`;
|
||||
if (h === "crew" || h === "agentur") { schreib.run(h, zeile.id); meldung.gesetzt++; }
|
||||
else if (h === "konflikt") meldung.konflikt.push(wer);
|
||||
else meldung.offen.push(wer);
|
||||
}
|
||||
}
|
||||
|
||||
if (meldung.gesetzt) {
|
||||
console.log(`[workspace] Haus nachgetragen: ${meldung.gesetzt} Zeilen.`);
|
||||
}
|
||||
/* DER DRITTE AUSGANG. Nicht "in Ordnung", nicht "kaputt", sondern
|
||||
"konnte nicht nachsehen" -- mit Grund und mit Namen, damit ein
|
||||
Mensch entscheiden kann. Eine Zeile ohne Haus verschwindet nicht:
|
||||
Sie ist weiterhin für DogFather sichtbar und für sonst niemanden
|
||||
(siehe hausWo). */
|
||||
for (const x of meldung.konflikt) {
|
||||
console.log(`[workspace] Haus UNKLAR (beide Häuser beteiligt): ${x}`);
|
||||
}
|
||||
for (const x of meldung.offen) {
|
||||
console.log(`[workspace] Haus OFFEN (nur DogFather beteiligt): ${x}`);
|
||||
}
|
||||
} catch (fehler) {
|
||||
console.error("[workspace] Häuser nachtragen:", fehler?.message);
|
||||
}
|
||||
return meldung;
|
||||
}
|
||||
|
||||
/** Das Haus eines Eintrags -- aus seinem BEREICH, nicht aus dem
|
||||
* Ersteller. `regeln`, `anschlag`, `highlight` sind Bretter von Team
|
||||
* Dogi, `agentur` gehoert der Agentur; das steht fest, unabhaengig
|
||||
* davon, wer gerade hineingeschrieben hat. Bei 20 von 26 Eintraegen
|
||||
* ist der Ersteller DogFather und damit kein Beleg. */
|
||||
function eintraegeNachHaus(d, meldung) {
|
||||
try {
|
||||
const spalten = d.prepare("PRAGMA table_info(eintraege)").all().map((x) => x.name);
|
||||
if (!spalten.includes("haus")) return;
|
||||
const schreib = d.prepare("UPDATE eintraege SET haus = ? WHERE id = ?");
|
||||
for (const zeile of d.prepare(
|
||||
"SELECT id, bereich FROM eintraege WHERE haus IS NULL").all()) {
|
||||
schreib.run(MODI_BEREICHE_ERLAUBT.has(zeile.bereich) ? "crew" : "agentur", zeile.id);
|
||||
meldung.gesetzt++;
|
||||
}
|
||||
} catch (f) { console.error("[workspace] Häuser (Einträge):", f?.message); }
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DIE VIER ZEILEN, DIE KEIN BELEG ERREICHT (24.09.2026)
|
||||
=====================================================================
|
||||
|
||||
Nach allen Ableitungen blieben am echten Stand genau vier Zeilen
|
||||
ohne Haus: drei Termine und ein Bild. An ihnen hängt nur DogFather,
|
||||
und er wohnt in beiden Häusern — es GIBT dort nichts abzuleiten.
|
||||
|
||||
WARUM SIE NAMENTLICH DASTEHEN UND NICHT ÜBER EINE REGEL LAUFEN.
|
||||
Eine Regel bräuchte eine Annahme („was DogFather allein einträgt,
|
||||
ist Team Dogi"), und die wäre für „Manager Meeting" und „Call mit
|
||||
Cigdem" (Cigdem ist Spicy Media) falsch. Eine falsche Annahme, die
|
||||
auf 250 Zeilen läuft, verschiebt Dinge, die niemand sucht. Vier
|
||||
benannte Zeilen kann man nachlesen und widerrufen.
|
||||
|
||||
UND SIE SIND DOPPELT GESICHERT: Nummer UND Titel müssen passen.
|
||||
Trifft eine Datenbank die Nummer mit einem anderen Titel (eine
|
||||
Kopie, ein anderer Stand), passiert nichts — statt dass ein
|
||||
fremder Termin stillschweigend das Haus wechselt.
|
||||
|
||||
Läuft genau einmal: danach ist `haus` gesetzt und die Bedingung
|
||||
`haus IS NULL` findet nichts mehr.
|
||||
===================================================================== */
|
||||
function restzeilenZuordnen(d, meldung) {
|
||||
/* ==== DER EINE KANAL, IN DEM BEIDE HAEUSER SASSEN (24.09.2026) ====
|
||||
|
||||
„Chat-Moderation": DogFather, die rechte und die linke Hand, vier
|
||||
Modis -- und zwei Scouts. Der einzige Raum im ganzen Haus, der
|
||||
ueber die Grenze ging (0 von 86 Terminen, 0 von 7 uebrigen
|
||||
Raeumen taten das).
|
||||
|
||||
Filipes Entscheidung: „Scouts raus, Kanal bleibt Team Dogi."
|
||||
|
||||
GEMESSEN, BEVOR ENTSCHIEDEN WURDE: Die sieben Nachrichten in
|
||||
diesem Kanal sind ALLE vom Team (VanVan 4x, Marina 2x, Diene 1x).
|
||||
Die beiden Scouts haben dort nie geschrieben; sie kamen am
|
||||
11.09.2026 in derselben Sekunde hinein wie DogFather und VanVan,
|
||||
also beim automatischen Anlegen -- bevor KANAL_ROLLEN auf die
|
||||
Team-Rollen eingeschraenkt wurde. Es geht damit nichts verloren.
|
||||
|
||||
`raus_am` UND NICHT LOESCHEN: Die Zeile bleibt stehen und traegt
|
||||
ein Datum. Wer spaeter fragt, warum jemand nicht mehr im Kanal
|
||||
ist, findet eine Antwort statt einer Luecke. */
|
||||
try {
|
||||
const raum = d.prepare(
|
||||
"SELECT id, haus FROM chat_raeume WHERE id = 3 AND name = 'Chat-Moderation'").get();
|
||||
if (raum && !raum.haus) {
|
||||
const fremd = [...nurAnderesHaus("crew")].map((r) => `'${r}'`).join(", ");
|
||||
const n = d.prepare(
|
||||
`UPDATE chat_teilnehmer SET raus_am = ?
|
||||
WHERE raum_id = 3 AND raus_am IS NULL
|
||||
AND person_id IN (SELECT id FROM personen WHERE rolle IN (${fremd}))`)
|
||||
.run(new Date().toISOString()).changes;
|
||||
d.prepare("UPDATE chat_raeume SET haus = 'crew' WHERE id = 3").run();
|
||||
meldung.gesetzt++;
|
||||
console.log(`[workspace] Kanal „Chat-Moderation" -> Team Dogi, ${n} aus dem anderen Haus herausgenommen.`);
|
||||
}
|
||||
} catch (f) { console.error("[workspace] Kanal 3:", f?.message); }
|
||||
|
||||
const ZUORDNUNG = [
|
||||
["termine", 3, "Manager Meeting", "agentur"],
|
||||
["termine", 5, "GrundRegeln-Schulung", "crew"],
|
||||
["termine", 179, "Call mit Cigdem", "agentur"],
|
||||
["material", 1, "community.png", "crew"],
|
||||
];
|
||||
for (const [tabelle, id, titel, haus] of ZUORDNUNG) {
|
||||
try {
|
||||
const spalte = tabelle === "material" ? "dateiname" : "titel";
|
||||
const n = d.prepare(
|
||||
`UPDATE ${tabelle} SET haus = ? WHERE id = ? AND ${spalte} = ? AND haus IS NULL`)
|
||||
.run(haus, id, titel).changes;
|
||||
if (n) {
|
||||
meldung.gesetzt += n;
|
||||
console.log(`[workspace] Haus von Hand gesetzt: ${tabelle}#${id} „${titel}" -> ${haus}`);
|
||||
}
|
||||
} catch (f) {
|
||||
console.error(`[workspace] Restzeile ${tabelle}#${id}:`, f?.message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Woran haengt diese Datei -- und welches Haus hat das? */
|
||||
function hausVomEltern(d, zeile) {
|
||||
try {
|
||||
if (zeile.eintrag_id) {
|
||||
const e = d.prepare("SELECT haus FROM eintraege WHERE id = ?").get(zeile.eintrag_id);
|
||||
if (e?.haus) return e.haus;
|
||||
}
|
||||
if (zeile.aufgabe_id) {
|
||||
const a = d.prepare("SELECT haus FROM aufgaben WHERE id = ?").get(zeile.aufgabe_id);
|
||||
if (a?.haus) return a.haus;
|
||||
}
|
||||
} catch { /* kein Beleg ist kein Fehler -- dann bleibt es offen */ }
|
||||
return null;
|
||||
}
|
||||
|
||||
function umstellungen(d) {
|
||||
/* MIT SEKUNDEN, nicht nur mit Minuten (07.09.2026).
|
||||
|
||||
@@ -3719,6 +4034,46 @@ function umstellungen(d) {
|
||||
einer Tabelle. Ein REFERENCES darauf gaebe es nicht; geprueft wird
|
||||
beim Schreiben, an der Stelle, die den Katalog kennt. */
|
||||
["aufgaben", "aus_punkt", "TEXT"],
|
||||
|
||||
/* ==== ZU WELCHEM HAUS GEHOERT DIESE ZEILE? (24.09.2026) ==========
|
||||
|
||||
Filipe: „wenn ich bei der einen was mache soll nichts bei der
|
||||
anderen passieren."
|
||||
|
||||
WARUM EINE SPALTE UND NICHT EINE RECHNUNG. Bis heute wurde das
|
||||
Haus aus den beteiligten Personen ABGELEITET (ohneAgentur /
|
||||
ohneTeamDogi). Das trägt für jede Zeile, an der mindestens ein
|
||||
Mensch aus genau einem Haus hängt -- und es trägt NICHT für die
|
||||
Zeilen, an denen nur DogFather hängt. Er wohnt in beiden Häusern;
|
||||
seine Zeilen standen deshalb in beiden. Gemessen am echten Stand:
|
||||
57 von 89 Terminen sind von ihm, 20 von 26 Einträgen.
|
||||
|
||||
Eine Rechnung, die in 30 % der Fälle zwei Antworten gibt, ist
|
||||
keine Grenze. Deshalb steht das Haus jetzt DA, geschrieben in dem
|
||||
Moment, in dem die Zeile entsteht -- und zwar aus `person.haus`,
|
||||
also aus der Adresse, auf der gearbeitet wurde.
|
||||
|
||||
NULL IST ERLAUBT und heisst „noch nicht nachgetragen". Die
|
||||
Nachtragung (haeuserNachtragen) füllt es aus dem vorhandenen
|
||||
Bestand; was sie nicht eindeutig bestimmen kann, sagt sie laut,
|
||||
statt zu raten.
|
||||
|
||||
ALTER TABLE ADD COLUMN UND KEIN TABELLENUMBAU: Am 11.09.2026 hat
|
||||
ein Neubau der Tabelle `eintraege` drei Spalten samt Inhalt
|
||||
verschluckt, ohne Fehlermeldung. ADD COLUMN kann das nicht. */
|
||||
["chat_raeume", "haus", "TEXT"],
|
||||
["termine", "haus", "TEXT"],
|
||||
["aufgaben", "haus", "TEXT"],
|
||||
["eintraege", "haus", "TEXT"],
|
||||
["dateien", "haus", "TEXT"],
|
||||
["wissen", "haus", "TEXT"],
|
||||
["material", "haus", "TEXT"],
|
||||
/* Die WIEDERHOLUNGSREGEL braucht es auch: Der Nachfueller erzeugt
|
||||
daraus Termine, und die muessen wissen, wohin sie gehoeren. Ohne
|
||||
sie erbten sie `null` -- und ein `null` ist in beiden Haeusern
|
||||
sichtbar (siehe hausWo). Eine woechentliche Serie haette die
|
||||
Trennung damit Woche fuer Woche neu unterlaufen. */
|
||||
["termin_serien", "haus", "TEXT"],
|
||||
]) {
|
||||
try {
|
||||
const vorhanden = d.prepare(`PRAGMA table_info(${tabelle})`).all().map((s) => s.name);
|
||||
@@ -3731,6 +4086,11 @@ function umstellungen(d) {
|
||||
}
|
||||
}
|
||||
|
||||
/* Die Häuser nachtragen -- direkt nachdem die Spalte da ist. Steht
|
||||
der Aufruf weiter unten, läuft er beim allerersten Start auf eine
|
||||
Tabelle ohne Spalte und meldet einen Fehler, den niemand braucht. */
|
||||
haeuserNachtragen(d);
|
||||
|
||||
/* Der Nachfüller fragt bei jedem Lauf "welche Ausprägungen dieser
|
||||
Serie gibt es schon?". Ohne diesen Verbund-Index liest SQLite dafür
|
||||
die ganze Termintabelle. Er steht hier unten und nicht oben im
|
||||
@@ -5651,8 +6011,38 @@ export function sitzungLesen(req) {
|
||||
nicht, was er darf -- genau wie die Sicht eines anderen
|
||||
(sichtPerson) das auch nicht tut. Wer hier etwas anderes einbaut,
|
||||
macht aus einer Anzeigefrage eine Rechtefrage. */
|
||||
/* ==== PRUEFADRESSEN BEKOMMEN KEIN HAUS (24.09.2026) ===========
|
||||
|
||||
Hier stand `istCrewAdresse(...) ? "crew" : "agentur"` -- also
|
||||
bekam auch `127.0.0.1` ein Haus, naemlich "agentur". Das war
|
||||
harmlos, solange auf der Agenturseite ohnehin nicht gefiltert
|
||||
wurde. Seit die Grenze in BEIDE Richtungen gilt, ist es das
|
||||
Gegenteil von harmlos:
|
||||
|
||||
GEMESSEN am selben Nachmittag: `pruef-chat-kanaele` fiel mit 13
|
||||
Fehlschlaegen um. Nicht weil etwas kaputt war, sondern weil
|
||||
DogFather auf 127.0.0.1 ploetzlich im Agenturhaus sass und
|
||||
deshalb keinen Modi mehr in einen Kanal einladen durfte. Die
|
||||
naechsten Pruefungen waeren still gruen geblieben und haetten
|
||||
nichts mehr gemessen.
|
||||
|
||||
GENAU DAVOR WARNT crew-adresse.js DREIMAL (Falle 2 in ihrem
|
||||
Kopf): "Ein gruener Lauf, der nichts mehr prueft, ist schlimmer
|
||||
als ein roter." Ich bin trotzdem hineingelaufen -- der Kommentar
|
||||
stand da, gelesen habe ich ihn erst, als es rot wurde.
|
||||
|
||||
`null` IST DER DRITTE WERT, und alle Hausfunktionen kennen ihn
|
||||
schon: nurHaus, hausBedingung, hausWo und ohneAnderesHaus
|
||||
filtern nur bei "crew" oder "agentur". Eine Pruefadresse
|
||||
verhaelt sich damit exakt wie vor dem Umbau.
|
||||
|
||||
EINE ERFUNDENE ADRESSE BLEIBT AGENTUR. istPruefAdresse zaehlt
|
||||
localhost und 127.* auf -- nicht "alles, was nicht crew ist".
|
||||
`crew.boese.de` faellt also weiterhin ins Agenturhaus und
|
||||
oeffnet nichts Drittes. */
|
||||
const haus = istCrewAdresse(req.get?.("host")) ? "crew"
|
||||
: "agentur";
|
||||
: istPruefAdresse(req.get?.("host")) ? null
|
||||
: "agentur";
|
||||
|
||||
/* DER AUSSCHLUSS WIRKT HIER -- an derselben Stelle wie alles andere
|
||||
(11.09.2026).
|
||||
@@ -7275,9 +7665,44 @@ export function termineSichtbar(person, praefix = "t") {
|
||||
Adresse mit dem Team, und die Termine der Agentur gehen sie dort
|
||||
nichts an. Geprueft wird die ROLLE und nicht der Name -- ein Name
|
||||
waere die Stelle, an der es beim naechsten Menschen bricht. */
|
||||
if (person.haus === "crew" && person.rolle !== "admin") {
|
||||
/* ==== DIE AUSNAHME FUER DOGFATHER IST UMGEBAUT (24.09.2026) =======
|
||||
|
||||
Hier stand `person.rolle !== "admin"` -- also: Jeder auf der
|
||||
Team-Adresse sieht nur Team-Termine, DogFather aber ALLE, quer
|
||||
ueber beide Haeuser. Das war sein Wunsch vom 11.09.2026, mit
|
||||
einer Begruendung, die weiterhin richtig ist: Wer die Haelfte
|
||||
seines Tages nicht sieht, legt einen Call auf eine Zeit, in der
|
||||
er schon woanders sitzt.
|
||||
|
||||
Am 24.09.2026 hat er die Trennung verlangt -- und auf die
|
||||
Nachfrage, was mit dieser Ausnahme geschieht, entschieden:
|
||||
„Getrennt, aber ‚belegt' bleibt sichtbar."
|
||||
|
||||
DAS IST NICHT DERSELBE WUNSCH ZWEIMAL, SONDERN ZWEI VERSCHIEDENE
|
||||
ANSPRUECHE AN DIESELBE ANZEIGE: Der INHALT gehoert getrennt (kein
|
||||
fremder Titel, kein fremder Teilnehmer auf der falschen Seite),
|
||||
die ZEIT nicht (sonst doppelt man sich). Beides geht: Hier wird
|
||||
hart getrennt, und die Kalenderroute legt die fremden Zeiten
|
||||
zusaetzlich als titellose „belegt"-Bloecke daneben. Nur fuer die
|
||||
DogFather-Rolle, wie 2026-09-11 festgelegt -- VanVan sieht
|
||||
weiterhin nichts von der anderen Seite.
|
||||
|
||||
ZWEI BEDINGUNGEN UND NICHT EINE: `hausWo` fragt die Spalte (sie
|
||||
weiss es auch bei einem Termin, an dem nur DogFather haengt --
|
||||
gemessen 57 von 89), `ohneAnderesHaus` fragt die Beteiligten (sie
|
||||
greift auch dort, wo noch kein Haus eingetragen ist). Wer nur eine
|
||||
nimmt, hat je nach Zeile eine Luecke.
|
||||
|
||||
SERIEN HABEN KEINE HAUS-SPALTE (`praefix === "s"` zeigt auf
|
||||
termin_serien). Dort bleibt es bei der Ableitung ueber die
|
||||
Beteiligten -- eine Bedingung auf eine Spalte, die es nicht gibt,
|
||||
waere ein SQL-Fehler und damit eine leere Seite. */
|
||||
const haus = person.haus;
|
||||
if (haus === "crew" || haus === "agentur") {
|
||||
const spalten = ["creator_id", "teilnehmer_id", "erstellt_von"];
|
||||
const ausSpalte = p === "t" ? ` AND ${hausWo(person, p)}` : "";
|
||||
return {
|
||||
wo: `(${eigen}) AND ${ohneAgentur(p, ["creator_id", "teilnehmer_id", "erstellt_von"])}`,
|
||||
wo: `(${eigen})${ausSpalte} AND ${ohneAnderesHaus(p, person, spalten)}`,
|
||||
werte,
|
||||
};
|
||||
}
|
||||
@@ -7627,12 +8052,36 @@ export function protokollLesen(anzahl = 20) {
|
||||
* -- und das sagt bei der Community ueberall Nein. Zwei verschiedene
|
||||
* Fragen, zwei verschiedene Funktionen; wer sie in eine legt, kann
|
||||
* spaeter nicht mehr sagen, welche gerade zugeschlagen hat. */
|
||||
const HAUS_TEAM_ROLLEN = new Set(["admin", "hand", "linke", "modi", "gast"]);
|
||||
/* BIS ZUM 24.09.2026 STAND HIER EINE EIGENE MENGE
|
||||
(`admin, hand, linke, modi, gast`). Sie war wortgleich mit dem, was
|
||||
`rollenImHaus("crew")` liefert -- und damit die zweite Liste, die
|
||||
beim naechsten Rollenwechsel haette nachgezogen werden muessen. Sie
|
||||
ist weg; gefragt wird jetzt die eine Menge in crew-adresse.js. */
|
||||
|
||||
/* =====================================================================
|
||||
DIE GRENZE GILT IN BEIDE RICHTUNGEN (24.09.2026)
|
||||
|
||||
Bis heute stand hier `if (person?.haus !== "crew") return ids;` --
|
||||
also: Auf der Team-Adresse wird gefiltert, auf der Agenturadresse
|
||||
NICHT. Das war richtig, solange „getrennt wird das Aussehen, nicht
|
||||
der Bestand" galt. Filipe hat das am 24.09.2026 umgedreht: „wenn ich
|
||||
bei der einen was mache soll nichts bei der anderen passieren."
|
||||
|
||||
WAS DIE EINSEITIGKEIT KONKRET BEDEUTET HAT: DogFather arbeitet in
|
||||
beiden Haeusern. Auf crew. sah er nur Team Dogi -- auf
|
||||
workspace.dogfather-universe.com aber ALLES, Team Dogi eingerechnet.
|
||||
In seiner Gespraechsliste standen dort die Raeume beider Haeuser
|
||||
nebeneinander, ohne dass etwas sie unterschieden haette.
|
||||
|
||||
EIN UNBEKANNTES HAUS FILTERT NICHT, und das ist Absicht: Auf einer
|
||||
Pruefadresse setzt sitzungLesen() „agentur"; ein drittes Haus gibt
|
||||
es nicht. Stuende hier ein `else` mit einer Annahme, waere die
|
||||
naechste Adresse stillschweigend einem Haus zugeschlagen. */
|
||||
function nurHaus(ids, person) {
|
||||
if (person?.haus !== "crew") return ids;
|
||||
const haus = person?.haus;
|
||||
if (haus !== "crew" && haus !== "agentur") return ids;
|
||||
try {
|
||||
const liste = [...HAUS_TEAM_ROLLEN].map((r) => `'${r}'`).join(", ");
|
||||
const liste = [...rollenImHaus(haus)].map((r) => `'${r}'`).join(", ");
|
||||
const erlaubt = db().prepare(
|
||||
`SELECT id FROM personen WHERE rolle IN (${liste})`).all().map((z) => z.id);
|
||||
/* `null` heisst bei diesen Funktionen "alle". Sobald das Haus
|
||||
@@ -7664,11 +8113,48 @@ function nurHaus(ids, person) {
|
||||
EINE FUNKTION UND KEINE ZWEITE ROLLENLISTE: Wer den Ausdruck
|
||||
abschreibt, hat beim naechsten Rollenwechsel zwei Wahrheiten. */
|
||||
export function hausBedingung(person, spalte = "rolle") {
|
||||
if (person?.haus !== "crew") return "";
|
||||
const liste = [...HAUS_TEAM_ROLLEN].map((r) => `'${r}'`).join(", ");
|
||||
const haus = person?.haus;
|
||||
if (haus !== "crew" && haus !== "agentur") return "";
|
||||
const liste = [...rollenImHaus(haus)].map((r) => `'${r}'`).join(", ");
|
||||
return ` AND ${spalte} IN (${liste})`;
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
DAS HAUS EINER ZEILE -- ALS SQL-BEDINGUNG (24.09.2026)
|
||||
|
||||
Fuer die sieben Tabellen mit eigener `haus`-Spalte (chat_raeume,
|
||||
termine, aufgaben, eintraege, dateien, wissen, material).
|
||||
|
||||
WARUM DIE SPALTE UND NICHT DIE PERSONEN. Die Ableitung ueber die
|
||||
Beteiligten (ohneAgentur / ohneTeamDogi) traegt fuer jede Zeile, an
|
||||
der mindestens ein Mensch aus genau einem Haus haengt -- und sie
|
||||
traegt NICHT fuer die Zeilen, an denen nur DogFather haengt. Gemessen
|
||||
am echten Stand: 57 von 89 Terminen. Die standen in beiden Haeusern.
|
||||
|
||||
`haus IS NULL` KOMMT MIT, und das ist eine bewusste Uebergangsregel:
|
||||
Beim Nachtragen bleiben Zeilen offen, deren Haus sich aus dem
|
||||
Bestand nicht belegen laesst (gemessen: 14 von 252). Wuerden sie
|
||||
herausfallen, verschwaende die halbe Wissensablage, ohne dass jemand
|
||||
einen Fehler saehe -- die unangenehmste Sorte Datenverlust. Sie
|
||||
bleiben deshalb sichtbar, und `haeuserNachtragen` nennt jede einzeln
|
||||
beim Namen, damit sie zugeordnet werden koennen. Ist die Liste leer,
|
||||
hat diese Zeile keine Wirkung mehr.
|
||||
|
||||
@param {string} praefix Tabellenkuerzel im SQL, z.B. "t" fuer termine
|
||||
===================================================================== */
|
||||
export function ohneAnderesHaus(praefix, person, spalten) {
|
||||
const haus = person?.haus;
|
||||
if (haus !== "crew" && haus !== "agentur") return "1=1";
|
||||
return ohneRollen(praefix, spalten, nurAnderesHaus(haus));
|
||||
}
|
||||
|
||||
export function hausWo(person, praefix) {
|
||||
const haus = person?.haus;
|
||||
if (haus !== "crew" && haus !== "agentur") return "1=1";
|
||||
const p = praefix ? `${praefix}.` : "";
|
||||
return `(${p}haus = '${haus}' OR ${p}haus IS NULL)`;
|
||||
}
|
||||
|
||||
/* EINE LISTE VON CREATOR-NUMMERN DARF NUR CREATOR ENTHALTEN (11.09.2026).
|
||||
|
||||
Klingt selbstverstaendlich, war es nicht. `ohneVerborgene` schreibt
|
||||
|
||||
Reference in New Issue
Block a user