From 12d4d489757e809ea4e8feacdb579e5d4f80d3d9 Mon Sep 17 00:00:00 2001 From: Dogfather Date: Wed, 16 Sep 2026 18:03:50 +0200 Subject: [PATCH] pruef-struktur: von zehn Fehlern auf null -- vier davon waren keine Die dritte und letzte rote Pruefung. Sie meldete zehn Fehler, und sechs davon waren Fehlalarm. 1. SECHS SEITEN "VON NIRGENDWO VERLINKT" Gemeldet wurden crew-index, entwicklung, rechte, talente, teamlage und treff-moderation. Keine davon war verwaist -- man kommt auf jede, indem man eine KACHEL antippt. Die Kacheln stehen im Server (`ziel: "talente.html"`), und der wurde nie durchsucht. Der blinde Fleck lag in der Pruefung. Abgeleitet statt nachgetragen: Statt die sechs von Hand auszunehmen, kommen workspace.js und crew-adresse.js als Quellen dazu. Wer morgen eine Kachel anlegt, ist damit automatisch abgedeckt. 2. FALSCHE ZEILENNUMMERN Die Ortszeit-Pruefung schnitt Blockkommentare heraus und ersetzte sie durch EIN Leerzeichen -- ab da zaehlte split("\n") falsch. Gemeldet wurde "pruef-eskalation.mjs:43", dort steht eine Zeile ueber Kekse. Wer dem nachgeht, findet nichts, haelt die Pruefung fuer kaputt und sieht beim naechsten Mal nicht mehr nach. Mit richtigen Zeilen waren sechs der sieben Funde echt: Sie bauen ihr Tagesdatum aus toISOString(), also aus UTC. Zwischen Mitternacht und zwei Uhr liefert das den Vortag -- die Pruefungen waeren tagsueber gruen und nachts rot gewesen. Der siebte (pruef-eskalation.mjs:70) rechnet von einem FESTEN Mittag aus und ist damit sicher; das Muster kann es nur nicht unterscheiden. Auch umgestellt, damit es nicht beim naechsten Lesen wieder auffaellt. Neu: server/helfer-tag.mjs -- heuteLokal, tagLokal, tagVon. Nicht aus workspace.js importiert, weil eine Pruefung, die nur ein Datum braucht, dafuer keinen Server hochfahren soll. pruef-backstage-import hatte die Rechnung sogar schon richtig stehen -- und benutzte sie 1270 Zeilen weiter unten trotzdem nicht. 3. TOTES CSS `.rolle__zeichen .nase` war tot. Beim Nachsehen: `.auge` und `.hell` daneben auch -- sie wurden nur davon verdeckt, dass die Pruefung den Klassennamen als TEILZEICHENKETTE gegen den Quelltext haelt, und "auge" steckt in "Auge", "hell" in "hell". Dutzende Treffer im Fliesstext deutscher Kommentare. `.fuell` bleibt, die wird benutzt. Die Schwaeche der Suche steht jetzt an der Stelle notiert. 4. start.css MIT 347 KB Die Grenze soll verhindern, "dass eine Seite unnoetig viel laedt". Auf der echten Seite nachgemessen: start.css auf der Platte 346 KB uebertragen 110 KB (br) chat.css 59 KB 16 KB entwicklung.css 33 KB 8 KB Caddy packt unterwegs. Von start.css sind ausserdem 227 KB KOMMENTAR (64 %) -- die Pruefung bestrafte genau das, was dieses Haus absichtlich tut, und haette eine Datei mit 199 KB dichtem CSS durchgewunken. Dasselbe Argument steht drei Absaetze hoeher schon fuer gestufte Bilder. Jetzt zwei Zahlen, weil es zwei Fragen sind: was der BESUCHER laedt (brotli Stufe 4 -- bei 4 liefert node 111 KB, Caddy 110, jede andere Stufe waere eine erfundene Zahl) und was ein MENSCH pflegen muss (ohne Kommentare). Sonst koennte man die erste Zahl klein halten, indem man immer mehr Prosa schreibt. MIT GEGENPROBE, in drei Faellen: 281 KB dichtes CSS faellt durch, 404 KB Kommentar gehen durch, und 246 KB sich WIEDERHOLENDES CSS faellt ebenfalls durch -- sonst koennte man die erste Grenze mit Wiederholung unterlaufen. pruef-struktur 0 Fehler (vorher 10) pruef-eskalation 40, pruef-modi-livecheck 16, pruef-treff-werkzeuge 70, pruef-backstage-import 160, pruef-css-klassen, pruef-crew-adresse 132 -- alle 0 Fehler Damit sind alle drei roten Pruefungen gruen. Co-Authored-By: Claude Opus 5 --- server/helfer-tag.mjs | 57 +++++++++++++ server/pruef-backstage-import.mjs | 14 ++-- server/pruef-eskalation.mjs | 9 ++- server/pruef-modi-livecheck.mjs | 3 +- server/pruef-struktur.mjs | 129 +++++++++++++++++++++++++++++- server/pruef-treff-werkzeuge.mjs | 3 +- workspace/app.webmanifest | 8 +- workspace/assets/css/gate.css | 32 +++++--- workspace/aufgaben.html | 24 +++--- workspace/automation.html | 26 +++--- workspace/befinden.html | 24 +++--- workspace/bereich.html | 34 ++++---- workspace/calls.html | 28 +++---- workspace/chat.html | 26 +++--- workspace/content.html | 30 +++---- workspace/crew-index.html | 10 +-- workspace/crew.webmanifest | 8 +- workspace/dateien.html | 26 +++--- workspace/entwicklung.html | 24 +++--- workspace/index.html | 8 +- workspace/kalender.html | 28 +++---- workspace/leistung.html | 26 +++--- workspace/personen.html | 26 +++--- workspace/profil.html | 28 +++---- workspace/rechte.html | 24 +++--- workspace/report.html | 28 +++---- workspace/scouting.html | 26 +++--- workspace/start.html | 24 +++--- workspace/startcheck.html | 28 +++---- workspace/steckbrief.html | 28 +++---- workspace/talente.html | 24 +++--- workspace/team.html | 26 +++--- workspace/teamlage.html | 24 +++--- workspace/treff-moderation.html | 24 +++--- workspace/treff-regeln.html | 26 +++--- workspace/uebersicht.html | 26 +++--- workspace/wissen.html | 26 +++--- 37 files changed, 580 insertions(+), 385 deletions(-) create mode 100644 server/helfer-tag.mjs diff --git a/server/helfer-tag.mjs b/server/helfer-tag.mjs new file mode 100644 index 00000000..524dc113 --- /dev/null +++ b/server/helfer-tag.mjs @@ -0,0 +1,57 @@ +/* ===================================================================== + EIN TAGESDATUM IN ORTSZEIT — für Prüfungen (16.09.2026) + + `new Date().toISOString().slice(0, 10)` ist der bequemste Weg zu + einem Datum und der falsche. toISOString rechnet in UTC; Server und + Menschen stehen hier auf Europe/Berlin. Zwischen Mitternacht und + zwei Uhr morgens liefert die Rechnung deshalb den VORTAG. + + In einer Prüfung heißt das: Sie ist tagsüber grün und nachts rot, + ohne dass irgendetwas kaputt ist. Ein Fehlalarm, den man nicht + nachstellen kann, ist der sicherste Weg, eine Prüfung abzuschalten. + + --------------------------------------------------------------------- + WARUM NICHT AUS workspace.js + + Dort stehen `heuteLokal()` und `tagLokal()` schon, mit demselben + Kommentar — aber wer sie importiert, zieht das ganze Haus mit: die + Datenbank, die Umstellungen, die Zeitgeber. Eine Prüfung, die nur ein + Datum braucht, soll dafür keinen Server hochfahren. + + Dieselbe Rechnung an zwei Stellen ist hier also Absicht, und es ist + die Ausnahme, nicht die Regel: Es sind vier Zeilen ohne + Verzweigung, sie können nicht auseinanderlaufen, ohne dass + pruef-struktur es meldet. + + --------------------------------------------------------------------- + UND WANN toISOString RICHTIG IST + + Wenn die Uhrzeit fest auf Mittag steht. `Date.parse("…T12:00:00Z")` + plus oder minus ganze Tage bleibt in jeder Zeitzone am selben + Kalendertag — deshalb rechnet der Server mit UTC-Mittag, wenn er + Fristen VERGLEICHT. Nur beim ANZEIGEN und beim Erzeugen eines + Tagesdatums gilt die Ortszeit. + ===================================================================== */ + +const zwei = (n) => String(n).padStart(2, "0"); + +/** Der heutige Tag in Ortszeit, als `JJJJ-MM-TT`. */ +export function heuteLokal() { + const d = new Date(); + return `${d.getFullYear()}-${zwei(d.getMonth() + 1)}-${zwei(d.getDate())}`; +} + +/** Derselbe Tag, um `versatz` Tage verschoben. Negativ heißt zurück. */ +export function tagLokal(versatz = 0) { + const d = new Date(Date.now() + versatz * 86400_000); + return `${d.getFullYear()}-${zwei(d.getMonth() + 1)}-${zwei(d.getDate())}`; +} + +/** Ein beliebiger Zeitpunkt als Tagesdatum in Ortszeit. + * + * Für Prüfungen, die von einem FESTEN Zeitpunkt aus rechnen statt von + * jetzt — dort ist die Zeitzone genauso entscheidend. */ +export function tagVon(zeitpunkt, versatz = 0) { + const d = new Date(zeitpunkt + versatz * 86400_000); + return `${d.getFullYear()}-${zwei(d.getMonth() + 1)}-${zwei(d.getDate())}`; +} diff --git a/server/pruef-backstage-import.mjs b/server/pruef-backstage-import.mjs index e0acff0e..eb0dd951 100644 --- a/server/pruef-backstage-import.mjs +++ b/server/pruef-backstage-import.mjs @@ -26,6 +26,7 @@ import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join, dirname } from "node:path"; import { fileURLToPath } from "node:url"; +import { tagLokal } from "./helfer-tag.mjs"; import { spawn } from "node:child_process"; import { DatabaseSync } from "node:sqlite"; import { scryptSync, randomBytes } from "node:crypto"; @@ -52,11 +53,12 @@ const jetzt = new Date().toISOString(); (Shop, 06.09.2026): Die Wanduhr darf Eingabe sein, nie Annahme. ALLE DREI WERDEN AUS EINER STELLE ABGELEITET -- drei eigene Rechnungen waeren drei Gelegenheiten, wieder auseinanderzulaufen. */ -const tagLokal = (versatz) => { - const d = new Date(Date.now() + versatz * 86400000); - const p2 = (n) => String(n).padStart(2, "0"); - return `${d.getFullYear()}-${p2(d.getMonth() + 1)}-${p2(d.getDate())}`; -}; +/* SEIT DEM 16.09.2026 AUS helfer-tag.mjs. Die Rechnung stand hier + richtig -- und wurde 1270 Zeilen weiter unten trotzdem nicht + benutzt: Dort stand wieder `toISOString().slice(0, 10)`. Ein Helfer, + den man beim naechsten Mal vergisst, ist eine halbe Loesung. Jetzt + gibt es ihn einmal fuer alle Pruefungen, und pruef-struktur meldet, + wer ihn nicht benutzt. */ const heute = tagLokal(0); const gestern = tagLokal(-1); const morgen = tagLokal(1); @@ -1324,7 +1326,7 @@ console.log("\n=== Die Seite ==="); /* EINE Person, ZWEI Tage -- dafuer ist dieser Weg da. Der erste Entwurf hatte hier zwei verschiedene Creator; dass die neue Sperre ihn abgewiesen hat, war ihr erster echter Treffer. */ - const vortag = new Date(Date.now() - 2 * 86400000).toISOString().slice(0, 10); + const vortag = tagLokal(-2); const xlsxDatei = xlsxBauen([ ["Datum", "Creator", "Diamanten", "LIVE-Dauer"], [gestern, "@Nova_Live", "12.480", "3Std. 4Min."], diff --git a/server/pruef-eskalation.mjs b/server/pruef-eskalation.mjs index 48b564a5..4fd0171c 100644 --- a/server/pruef-eskalation.mjs +++ b/server/pruef-eskalation.mjs @@ -30,6 +30,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { request as httpAnfrage } from "node:http"; import { portMussFreiSein } from "./helfer-port.mjs"; +import { heuteLokal, tagLokal, tagVon } from "./helfer-tag.mjs"; const PORT = await portMussFreiSein(4417, "pruef-eskalation"); @@ -67,7 +68,7 @@ const jetzt = new Date().toISOString(); als Annahme benutzt, misst irgendwann das Gegenteil -- der Kalender holt sie ein. Hier wird die Zeit uebergeben, also ist sie Eingabe. */ const NUN = Date.parse("2026-09-15T12:00:00+02:00"); -const tagVor = (n) => new Date(NUN - n * 86400000).toISOString().slice(0, 10); +const tagVor = (n) => tagVon(NUN, -n); let idDogi; { @@ -219,12 +220,12 @@ melde("=== 5. Über die Leitung ==="); const d = oeffne(); const rein = d.prepare(`INSERT INTO aufgaben (titel, status, prioritaet, frist, erstellt, erstellt_von) VALUES (?,?,'mittel',?,?,?)`); - const heute = new Date().toISOString().slice(0, 10); - const vor = (n) => new Date(Date.now() - n * 86400000).toISOString().slice(0, 10); + const heute = heuteLokal(); + const vor = (n) => tagLokal(-n); rein.run("Seit gestern faellig", "offen", vor(1), jetzt, idDogi); rein.run("Liegt seit fuenf Tagen", "offen", vor(5), jetzt, idDogi); rein.run("Haengt seit zwanzig", "offen", vor(20), jetzt, idDogi); - rein.run("Erst naechste Woche", "offen", new Date(Date.now() + 7 * 86400000).toISOString().slice(0, 10), jetzt, idDogi); + rein.run("Erst naechste Woche", "offen", tagLokal(7), jetzt, idDogi); rein.run("Heute faellig", "offen", heute, jetzt, idDogi); d.close(); diff --git a/server/pruef-modi-livecheck.mjs b/server/pruef-modi-livecheck.mjs index 75580f1f..521b215a 100644 --- a/server/pruef-modi-livecheck.mjs +++ b/server/pruef-modi-livecheck.mjs @@ -23,6 +23,7 @@ import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; +import { tagLokal } from "./helfer-tag.mjs"; const ordner = mkdtempSync(join(tmpdir(), "ws-live-")); process.env.WORKSPACE_DB = join(ordner, "workspace.db"); @@ -75,7 +76,7 @@ void idMan; liegt in der Zukunft und wird RELATIV gerechnet -- ein festes Datum holt der Kalender irgendwann ein, und dann ist die Pruefung rot, ohne dass etwas kaputt waere. */ -const inTagen = (n) => new Date(Date.now() + n * 86400_000).toISOString().slice(0, 10); +const inTagen = (n) => tagLokal(n); const TAG1 = inTagen(3); const TAG2 = inTagen(10); diff --git a/server/pruef-struktur.mjs b/server/pruef-struktur.mjs index c2839fe7..42abb072 100644 --- a/server/pruef-struktur.mjs +++ b/server/pruef-struktur.mjs @@ -30,6 +30,7 @@ import { readFileSync, readdirSync, existsSync, statSync } from "node:fs"; import { join, dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; +import { brotliCompressSync, constants } from "node:zlib"; const __dirname = dirname(fileURLToPath(import.meta.url)); const REPO = join(__dirname, ".."); @@ -183,8 +184,33 @@ ok(nurPraefix > 0, `${nurPraefix} zusammengesetzte Aufrufe: nur Praefix pruefbar /* ---------- 4. Jede Seite ist erreichbar --------------------------------- */ console.log(`\n=== Erreichbarkeit ===`); +/* WER AUF EINE SEITE ZEIGT, IST NICHT NUR EIN href (16.09.2026). + + Diese Zeile meldete sechs Seiten als "von nirgendwo verlinkt": + crew-index, entwicklung, rechte, talente, teamlage und + treff-moderation. Keine davon war verwaist -- man kommt auf jede, + indem man eine KACHEL antippt. Die Kacheln stehen aber im Server + (`ziel: "talente.html"`), und der wurde hier nie durchsucht. + + Eine Pruefung, die seit Wochen sechs Fehler meldet, die keine sind, + ist schlimmer als keine: Man liest sie nicht mehr, und dann uebersieht + man die siebte, die echt ist. Der blinde Fleck lag in der Pruefung, + nicht im Haus. + + ABGELEITET, NICHT NACHGETRAGEN: Statt die sechs von Hand + auszunehmen, kommen die Dateien dazu, in denen die Ziele wirklich + stehen. Wer morgen eine Kachel anlegt, ist damit automatisch + abgedeckt -- und wer eine Seite anlegt, auf die nichts zeigt, faellt + weiterhin auf. */ +const zeigerQuellen = [ + ...quellenMitLinks, + /* Die Kachellisten -- dort steht `ziel: "talente.html"`. */ + { name: "server/workspace.js", pfad: join(SERVER, "workspace.js") }, + /* Die Zugangswaende -- crew-index.html wird dort ausgeliefert. */ + { name: "server/crew-adresse.js", pfad: join(SERVER, "crew-adresse.js") }, +]; const verlinkt = new Set(["index.html", "start.html"]); -for (const { pfad: quelle } of quellenMitLinks) { +for (const { pfad: quelle } of zeigerQuellen) { const text = readFileSync(quelle, "utf8"); for (const m of text.matchAll(/["'`](?:\/workspace\/)?([a-z0-9-]+\.html)/g)) { verlinkt.add(m[1]); @@ -239,6 +265,23 @@ ok(reste.length === 0, reste.length ? reste.join(" · ") : "keine Entwicklungsre /* ---------- 7. Groesse der Assets ---------------------------------------- */ console.log(`\n=== Dateigroessen ===`); +/** Ist diese Text-Datei zu schwer? Gibt den Grund oder `null`. + * + * ALS EIGENE FUNKTION, damit die Gegenprobe sie mit erfundenem Inhalt + * aufrufen kann. Eine Messung, die nur ueber die echten Dateien + * laeuft, ist genau so lange gruen, wie zufaellig keine zu gross ist + * -- und beweist nie, dass sie ueberhaupt anschlagen kann. */ +function textZuSchwer(roh) { + const gepackt = Math.round(brotliCompressSync(roh, { + params: { [constants.BROTLI_PARAM_QUALITY]: 4 }, + }).length / 1024); + if (gepackt > 200) return `${gepackt} KB uebertragen`; + const ohneKommentar = Math.round( + roh.toString("utf8").replace(/\/\*[\s\S]*?\*\//g, "").length / 1024); + if (ohneKommentar > 200) return `${ohneKommentar} KB ohne Kommentare`; + return null; +} + let schwer = []; for (const unter of ["assets/js", "assets/css", "assets/img"]) { const ordner = join(WS, unter); @@ -300,11 +343,81 @@ for (const unter of ["assets/js", "assets/css", "assets/img"]) { } continue; } + /* BEI TEXT MISST DIE ROHE GROESSE DAS FALSCHE (16.09.2026). + + Die Grenze soll verhindern, "dass eine Seite unnoetig viel + laedt" -- so steht es oben. Fuer Bilder ist die Datei genau das, + was geladen wird. Fuer CSS und JS nicht: Caddy komprimiert sie + unterwegs. Nachgemessen auf der echten Seite am 16.09.: + + start.css auf der Platte 346 KB uebertragen 110 KB (br) + chat.css 59 KB 16 KB + entwicklung.css 33 KB 8 KB + + Die Pruefung meldete start.css mit 347 KB -- davon sind 227 KB + KOMMENTAR (64 %). Sie bestrafte damit genau das, was dieses Haus + absichtlich tut: jede Entscheidung danebenschreiben. Und sie + haette eine Datei mit 199 KB dichtem, unkommentiertem CSS + durchgewunken. + + Dasselbe Argument steht drei Absaetze weiter oben schon einmal, + fuer die gestuften Bilder: "Bei einem Bild, das in mehreren + Groessen vorliegt, misst sie das Falsche." + + JETZT ZWEI ZAHLEN, weil es zwei verschiedene Fragen sind: + + 1. WAS DER BESUCHER LAEDT -- brotli, Stufe 4. Die Stufe ist + nicht geraten: Bei 4 liefert node 111 KB, Caddy liefert + 110. Jede andere Stufe waere eine Zahl, die mit der + Wirklichkeit nichts zu tun hat. + 2. WAS EIN MENSCH PFLEGEN MUSS -- die Datei ohne Kommentare. + Sonst koennte man die erste Zahl klein halten, indem man + immer mehr Prosa schreibt, und niemand merkt, dass das CSS + selbst ausgeufert ist. */ + if (/\.(css|js)$/.test(n)) { + const grund = textZuSchwer(readFileSync(p)); + if (grund) schwer.push(`${unter}/${n} ${grund}`); + continue; + } if (kb > 200) schwer.push(`${unter}/${n} ${kb} KB`); } } ok(schwer.length === 0, schwer.length ? `ueber 200 KB: ${schwer.join(", ")}` : "keine Datei ueber 200 KB"); +/* GEGENPROBE ZUR GROESSENMESSUNG. Sie ist seit dem 16.09.2026 kein + blosser Blick auf die Dateigroesse mehr, sondern packt den Inhalt + zusammen -- und eine Messung, die niemand je hat anschlagen sehen, + ist eine Behauptung. Drei Faelle, und jeder muss anders ausgehen. */ +{ + /* 1. Viel echtes CSS, das sich nicht wegpacken laesst. */ + let dicht = ""; + for (let i = 0; i < 9000; i++) { + dicht += `.k${i.toString(36)}-${(i * 7919).toString(36)} { color: #${ + (i * 2654435761 % 16777215).toString(16).padStart(6, "0")}; }\n`; + } + ok(textZuSchwer(Buffer.from(dicht)) !== null, + `dichtes CSS von ${Math.round(dicht.length / 1024)} KB faellt durch ` + + `(${textZuSchwer(Buffer.from(dicht))})`); + + /* 2. Dieselbe Menge Text, aber als Prosa im Kommentar -- die packt + sich auf ein Zehntel und darf durchgehen. Das ist der ganze + Grund fuer die Umstellung. */ + const prosa = "/* " + "Jede Entscheidung gehoert danebengeschrieben. ".repeat(9000) + " */\n" + + ".a { color: #fff; }\n"; + ok(textZuSchwer(Buffer.from(prosa)) === null, + `${Math.round(prosa.length / 1024)} KB Kommentar gehen durch — sie kosten ` + + "den Besucher fast nichts"); + + /* 3. UND DIE ZWEITE ZAHL MUSS AUCH ANSCHLAGEN: viel echtes CSS, das + sich zwar gut packt (weil es sich wiederholt), aber trotzdem + niemand mehr pflegen kann. Ohne diesen Fall koennte man die + erste Grenze mit Wiederholung unterlaufen. */ + const wiederholt = ".gleich { color: #ffffff; padding: 4px; }\n".repeat(6000); + ok(textZuSchwer(Buffer.from(wiederholt)) !== null, + `${Math.round(wiederholt.length / 1024)} KB sich wiederholendes CSS faellt ` + + `ebenfalls durch (${textZuSchwer(Buffer.from(wiederholt))})`); +} + /* ---------- 8. Totes CSS ------------------------------------------------- */ /* start.css wird auf JEDER Seite geladen und ist 126 KB gross. Was darin @@ -611,7 +724,19 @@ console.log(`\n=== Rechnen die Pruefungen mit Ortszeit? ===`); anzeigen -- eine Warnung, die immer kommt, und die liest bald niemand mehr. */ if (datei === "pruef-struktur.mjs") continue; - const text = readFileSync(join(SERVER, datei), "utf8").replace(/\/\*[\s\S]*?\*\//g, " "); + /* KOMMENTARE RAUS, ZEILEN BEHALTEN (16.09.2026). + + Hier stand `replace(…, " ")` -- ein Blockkommentar ueber zwanzig + Zeilen wurde also zu einem Leerzeichen, und ab da zaehlte + `split("\n").length` falsch. Gemeldet wurden Zeilennummern, die + auf voellig anderen Code zeigten: pruef-eskalation.mjs:43 ist + eine Zeile ueber Kekse. + + Wer einer solchen Meldung nachgeht, findet dort nichts, haelt + die Pruefung fuer kaputt und sieht beim naechsten Mal gar nicht + mehr nach. Jetzt bleibt je Zeile eine Zeile stehen. */ + const text = readFileSync(join(SERVER, datei), "utf8") + .replace(/\/\*[\s\S]*?\*\//g, (m) => m.replace(/[^\n]/g, " ")); /* Das Muster ist eng gefasst: NUR toISOString() gefolgt von einem Schnitt auf zehn Zeichen -- also genau die Bildung eines Tagesdatums. `new Date().toISOString()` allein (ein voller diff --git a/server/pruef-treff-werkzeuge.mjs b/server/pruef-treff-werkzeuge.mjs index dad8dca9..ffd870db 100644 --- a/server/pruef-treff-werkzeuge.mjs +++ b/server/pruef-treff-werkzeuge.mjs @@ -39,6 +39,7 @@ import { mkdtempSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { request as httpAnfrage } from "node:http"; +import { heuteLokal } from "./helfer-tag.mjs"; import { portMussFreiSein } from "./helfer-port.mjs"; const PORT = await portMussFreiSein(4402, "pruef-treff-werkzeuge"); @@ -75,7 +76,7 @@ const { BEREICHE } = await import("./workspace-bereiche.js"); const d = new DatabaseSync(process.env.WORKSPACE_DB); const jetzt = new Date().toISOString(); -const heute = jetzt.slice(0, 10); +const heute = heuteLokal(); const schluessel = randomBytes(32).toString("hex"); d.prepare("INSERT INTO einstellungen (schluessel, wert, geaendert, von)" + " VALUES (?,?,?,NULL) ON CONFLICT(schluessel) DO NOTHING") diff --git a/workspace/app.webmanifest b/workspace/app.webmanifest index 5f48b5da..dffcaf8c 100644 --- a/workspace/app.webmanifest +++ b/workspace/app.webmanifest @@ -13,25 +13,25 @@ "theme_color": "#06090f", "icons": [ { - "src": "/assets/img/app-symbole/workspace-192.png?v=202609161723", + "src": "/assets/img/app-symbole/workspace-192.png?v=202609161803", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-512.png?v=202609161723", + "src": "/assets/img/app-symbole/workspace-512.png?v=202609161803", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609161723", + "src": "/assets/img/app-symbole/workspace-192-maskable.png?v=202609161803", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609161723", + "src": "/assets/img/app-symbole/workspace-512-maskable.png?v=202609161803", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/assets/css/gate.css b/workspace/assets/css/gate.css index a8c460e4..26a7e13c 100644 --- a/workspace/assets/css/gate.css +++ b/workspace/assets/css/gate.css @@ -654,18 +654,26 @@ body.gate { stroke: none; fill: color-mix(in srgb, var(--rf) 52%, transparent); } -.rolle__zeichen .auge { - stroke: none; - fill: color-mix(in srgb, var(--rf) 26%, #ffffff); -} -.rolle__zeichen .nase { - stroke: none; - fill: color-mix(in srgb, var(--rf) 45%, #06090f); -} -.rolle__zeichen .hell { - stroke: color-mix(in srgb, var(--rf) 16%, #ffffff); - stroke-width: 2; -} +/* HIER STANDEN DREI REGELN FUER EIN ZEICHEN, DAS ES NICHT MEHR GIBT + (16.09.2026). + + `.auge`, `.nase` und `.hell` gehoerten zu einem Rollenzeichen, das + aus SVG-Pfaden gezeichnet war. Heute ist es ein Bild plus drei + Kreise mit festen Farben (`#r-husky`) -- kein Element im Haus traegt + diese Klassen noch. Nachgemessen ueber alle HTML- und JS-Dateien: + als Klasse null Vorkommen. + + `.fuell` BLEIBT: die wird an einer Stelle wirklich benutzt. + + WARUM NUR EINE DAVON GEMELDET WURDE: Die Suche nach totem CSS + vergleicht den Klassennamen als Teilzeichenkette gegen den gesamten + Quelltext. „auge" steckt in „Auge", „hell" in „hell" und + „hellster" -- beide kamen im Fliesstext deutscher Kommentare + dutzendfach vor und galten damit als benutzt. Nur „nase" kam + nirgends vor. Die beiden anderen waren genauso tot, nur unsichtbar. + + Das ist eine offene Schwaeche der Pruefung, kein Befund gegen das + Haus -- sie steht hier notiert, damit sie nicht wieder verlorengeht. */ /* Gewaehlt: mehr Licht auf demselben Gegenstand -- kein anderer Gegenstand. */ .rolle[aria-checked="true"] .rolle__zeichen { diff --git a/workspace/aufgaben.html b/workspace/aufgaben.html index 79c417a1..01360d3d 100644 --- a/workspace/aufgaben.html +++ b/workspace/aufgaben.html @@ -12,19 +12,19 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - + + + + + + - + @@ -282,10 +282,10 @@ - - - - - + + + + + diff --git a/workspace/automation.html b/workspace/automation.html index 0de3f6a2..b5b244e6 100644 --- a/workspace/automation.html +++ b/workspace/automation.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -168,10 +168,10 @@ - - - - - + + + + + diff --git a/workspace/befinden.html b/workspace/befinden.html index 5d971f90..7c21d721 100644 --- a/workspace/befinden.html +++ b/workspace/befinden.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -105,9 +105,9 @@ - - - - + + + + diff --git a/workspace/bereich.html b/workspace/bereich.html index 6fdf62d6..245c11c2 100644 --- a/workspace/bereich.html +++ b/workspace/bereich.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -181,14 +181,14 @@ - - - - - - - - - + + + + + + + + + diff --git a/workspace/calls.html b/workspace/calls.html index 650c4e60..dee63653 100644 --- a/workspace/calls.html +++ b/workspace/calls.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -89,11 +89,11 @@ - - - - - - + + + + + + diff --git a/workspace/chat.html b/workspace/chat.html index 37fd921b..51f08443 100644 --- a/workspace/chat.html +++ b/workspace/chat.html @@ -12,26 +12,26 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -341,10 +341,10 @@ - - - - - + + + + + diff --git a/workspace/content.html b/workspace/content.html index 4af332c8..f602ebf5 100644 --- a/workspace/content.html +++ b/workspace/content.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -179,12 +179,12 @@ - - - - - - - + + + + + + + diff --git a/workspace/crew-index.html b/workspace/crew-index.html index 682c6544..560eb003 100644 --- a/workspace/crew-index.html +++ b/workspace/crew-index.html @@ -36,15 +36,15 @@ - - - + + + - + @@ -339,6 +339,6 @@ - + diff --git a/workspace/crew.webmanifest b/workspace/crew.webmanifest index 293b42f7..e02758ad 100644 --- a/workspace/crew.webmanifest +++ b/workspace/crew.webmanifest @@ -13,25 +13,25 @@ "theme_color": "#06090f", "icons": [ { - "src": "/assets/img/app-symbole/crew-192.png?v=202609161723", + "src": "/assets/img/app-symbole/crew-192.png?v=202609161803", "sizes": "192x192", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-512.png?v=202609161723", + "src": "/assets/img/app-symbole/crew-512.png?v=202609161803", "sizes": "512x512", "type": "image/png", "purpose": "any" }, { - "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609161723", + "src": "/assets/img/app-symbole/crew-192-maskable.png?v=202609161803", "sizes": "192x192", "type": "image/png", "purpose": "maskable" }, { - "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609161723", + "src": "/assets/img/app-symbole/crew-512-maskable.png?v=202609161803", "sizes": "512x512", "type": "image/png", "purpose": "maskable" diff --git a/workspace/dateien.html b/workspace/dateien.html index bb60a816..312c9e31 100644 --- a/workspace/dateien.html +++ b/workspace/dateien.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -108,10 +108,10 @@ - - - - - + + + + + diff --git a/workspace/entwicklung.html b/workspace/entwicklung.html index 2c800fca..01302f4b 100644 --- a/workspace/entwicklung.html +++ b/workspace/entwicklung.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -102,9 +102,9 @@ - - - - + + + + diff --git a/workspace/index.html b/workspace/index.html index 4892d36d..62ee6852 100644 --- a/workspace/index.html +++ b/workspace/index.html @@ -30,9 +30,9 @@ - - - + + + @@ -401,6 +401,6 @@ - + diff --git a/workspace/kalender.html b/workspace/kalender.html index 31fac49f..e5b8590e 100644 --- a/workspace/kalender.html +++ b/workspace/kalender.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -377,11 +377,11 @@ - - - - - - + + + + + + diff --git a/workspace/leistung.html b/workspace/leistung.html index be29a92f..872774a3 100644 --- a/workspace/leistung.html +++ b/workspace/leistung.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -444,10 +444,10 @@ - - - - - + + + + + diff --git a/workspace/personen.html b/workspace/personen.html index 3a4d2a67..d65473b8 100644 --- a/workspace/personen.html +++ b/workspace/personen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -423,10 +423,10 @@ - - - - - + + + + + diff --git a/workspace/profil.html b/workspace/profil.html index 32b25eb2..f4057bda 100644 --- a/workspace/profil.html +++ b/workspace/profil.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -214,11 +214,11 @@ - - - - - - + + + + + + diff --git a/workspace/rechte.html b/workspace/rechte.html index 538cf305..211e16b8 100644 --- a/workspace/rechte.html +++ b/workspace/rechte.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -134,9 +134,9 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - + + + + diff --git a/workspace/report.html b/workspace/report.html index e04a6f6a..42f5bc3c 100644 --- a/workspace/report.html +++ b/workspace/report.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -106,11 +106,11 @@ - - - - - - + + + + + + diff --git a/workspace/scouting.html b/workspace/scouting.html index ee64a4fa..e2d52e33 100644 --- a/workspace/scouting.html +++ b/workspace/scouting.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -173,10 +173,10 @@ - - - - - + + + + + diff --git a/workspace/start.html b/workspace/start.html index d0fe9af7..4e1cbd4a 100644 --- a/workspace/start.html +++ b/workspace/start.html @@ -12,21 +12,21 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - + + - + @@ -674,10 +674,10 @@

- - - - - + + + + + diff --git a/workspace/startcheck.html b/workspace/startcheck.html index 4a5934b2..c13cc8cb 100644 --- a/workspace/startcheck.html +++ b/workspace/startcheck.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -85,11 +85,11 @@ - - - - - - + + + + + + diff --git a/workspace/steckbrief.html b/workspace/steckbrief.html index 27f86304..97d0b19e 100644 --- a/workspace/steckbrief.html +++ b/workspace/steckbrief.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -146,11 +146,11 @@ - - - - - - + + + + + + diff --git a/workspace/talente.html b/workspace/talente.html index 3a83564c..e54973bb 100644 --- a/workspace/talente.html +++ b/workspace/talente.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -94,9 +94,9 @@ - - - - + + + + diff --git a/workspace/team.html b/workspace/team.html index aeedb77a..0d55b9c5 100644 --- a/workspace/team.html +++ b/workspace/team.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + @@ -110,10 +110,10 @@ - - - - - + + + + + diff --git a/workspace/teamlage.html b/workspace/teamlage.html index f6784389..56adee86 100644 --- a/workspace/teamlage.html +++ b/workspace/teamlage.html @@ -7,20 +7,20 @@ - - - - - - - + + + + + + + - + - - - - + + + + diff --git a/workspace/treff-moderation.html b/workspace/treff-moderation.html index 9fbffe2b..4e81fedc 100644 --- a/workspace/treff-moderation.html +++ b/workspace/treff-moderation.html @@ -7,14 +7,14 @@ - - - - - - - - + + + + + + + + @@ -110,9 +110,9 @@ - - - - + + + + diff --git a/workspace/treff-regeln.html b/workspace/treff-regeln.html index 9a413ac8..10c5fb12 100644 --- a/workspace/treff-regeln.html +++ b/workspace/treff-regeln.html @@ -7,18 +7,18 @@ - - - - - - - + + + + + + + - + @@ -211,10 +211,10 @@ Beim ersten Anlauf fehlte die Zeile auf genau diesen beiden neuen Seiten. Gefunden hat das nicht das Auge, sondern pruef-css-klassen, die seit dem 07.09. jede Seite danach absucht. --> - - - - - + + + + + diff --git a/workspace/uebersicht.html b/workspace/uebersicht.html index 625735b2..c2d4dc5d 100644 --- a/workspace/uebersicht.html +++ b/workspace/uebersicht.html @@ -12,22 +12,22 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - + + + + - - - + + + - + @@ -149,11 +149,11 @@ - + - - - - + + + + diff --git a/workspace/wissen.html b/workspace/wissen.html index 7f91ec87..47b99f7d 100644 --- a/workspace/wissen.html +++ b/workspace/wissen.html @@ -12,20 +12,20 @@ Ton wie die Kopfleiste darunter (#06090f), damit Leiste und Seite eine Flaeche sind statt zweier. --> - - - - - - - + + + + + + + - + @@ -190,10 +190,10 @@ - - - - - + + + + +