8a2943df3581b9376c300b448ee02decb4f65f5b
30
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
1c3b3808ba |
Express 5: geprueft, aber noch nicht umgestellt
Der Sprung 4 auf 5 entfernt Methoden, aendert die Pfadsyntax
grundlegend (path-to-regexp 8) und stellt Standardwerte um. Vieles
davon faellt nicht beim Start auf, sondern erst, wenn eine bestimmte
Adresse aufgerufen wird -- also im Betrieb, bei einem Kunden. Deshalb
zuerst pruefen statt installieren.
ZWEI PRUEFUNGEN, DIE SICH ERGAENZEN
pruef-express5.mjs durchsucht 89 Dateien nach den Bruchstellen aus dem
offiziellen Migrationsleitfaden: entfernte Aufrufe (res.send(zahl),
req.param, app.del, res.sendfile), die UMGEDREHTE Reihenfolge bei
res.redirect, geaenderte Pfadsyntax ("/*" ohne Namen, ":a?"),
schreibgeschuetztes req.query, entfernte static-Optionen.
server/test-express5.mjs startet einen echten Server mit genau unserem
Aufbau: Middleware-Kette mit eigenen Kopfzeilen, cookieParser,
express.json, eine umleitende Schranke, express.static, ein Router mit
Parameter, 404- und Fehlerbehandlung.
ERGEBNIS
15 von 15 Kategorien unbedenklich, 10 von 10 Laufpruefungen bestanden
gegen express 5.2.1. Der Umstieg waere ohne Codeaenderung moeglich.
Ein Fehlalarm lag dabei im Pruefer selbst: Er meldete drei
req.body-Zugriffe als ungesichert, die in Wahrheit innerhalb eines
"if (typeof req.body?.feld === 'boolean')" stehen -- der Rueckblick war
mit 60 Zeichen zu kurz fuer den Block. Ein Pruefer, der abgesicherte
Stellen anmahnt, kostet die Zeit, die er sparen soll, und beim
naechsten Mal glaubt man ihm auch die echten Funde nicht mehr.
NICHT UMGESTELLT
Bewusst. Der Bestand ist sicherheitstechnisch sauber (npm audit: 0),
express 4.22.2 wird weiter gepflegt, und der Nutzen waere gering
gegenueber dem Risiko, zwei laufende Dienste anzufassen. Die Vorarbeit
liegt vor -- wenn umgestellt wird, dann als eigener Vorgang mit
anschliessendem Live-Test, nicht nebenbei.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
f64403aea8 |
package-lock.json wird versioniert (server/)
Ohne Lock-Datei darf jede Installation andere Fassungen ziehen: "^4.21.2" erlaubt alles unter 5.0. Auf dem Server laeuft deshalb express 4.22.2, waehrend in der package.json 4.21.2 steht -- geprueft wird also nie genau das, was ausgeliefert wird. Solche Unterschiede fallen nicht beim Deploy auf, sondern im Betrieb, und dann sucht man den Fehler im eigenen Code. WARUM SIE AUSGESCHLOSSEN WAR Ein "git pull" auf dem Server scheiterte daran: Git ueberschreibt keine unverfolgte Datei -- unabhaengig davon, ob ihr Inhalt derselbe ist. Der Ausschluss hat den Deploy repariert und dabei den Zweck der Datei beseitigt. Nachgemessen statt vermutet: Die Datei hier und die auf dem Server sind Byte fuer Byte identisch (SHA-256 a50b028d…). Es gab also nie einen inhaltlichen Konflikt, nur einen formalen. Er loest sich, indem die Datei einmal vom Server entfernt und danach aus dem Repo geholt wird. DEPLOY.md ergaenzt: auf dem Server "npm ci" statt "npm install". ci loescht node_modules vorher und baut streng nach der Lock-Datei; es schreibt sie nie um und bricht ab, wenn sie nicht zur package.json passt -- statt still etwas anderes zu installieren. server-internal/ folgt, sobald die dortige Lock-Datei vorliegt. Dieses Verzeichnis liegt unter /home/dogiintern mit Rechten 700. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
62cbd724e2 |
Manifest der Verwaltungs-App an der Zugangswand freigeben
Beim ersten Live-Test war die App nicht installierbar: Symbole 200, Manifest 302. Die Zugangswand hat eine Ausnahmeliste fuer App-Bausteine -- sw.js und app.webmanifest stehen ausdruecklich darin, mit einer ausfuehrlichen Begruendung aus dem Universe. Das neue Manifest fehlte schlicht. Der Grund gilt hier sogar staerker als bei der oeffentlichen App: Die Verwaltung liegt IMMER hinter der Schranke. Ohne Freigabe bekommt der Browser statt des Manifests eine Umleitung auf zugang.html, also HTML statt JSON -- und bietet "App installieren" gar nicht erst an. Unbedenklich: Das Manifest enthaelt Name, Farben, Symbolpfade und drei Verknuepfungen. Keine Kunden-, Projekt- oder Preisdaten. Wer es liest, erfaehrt, dass es eine Verwaltung gibt -- was die Zugangswand ohnehin verraet. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
c591925342 |
DRINGEND: Inhaltsrichtlinie legte die App lahm
Symptom: Die installierte App zeigte "Keine Verbindung", obwohl die Seite online war, der Server lief und jede Pruefung Erfolg meldete. Ursache war meine eigene Zeile von heute Vormittag. Fuer alles, was keine Seite ist, setzte die Middleware "default-src 'none'" -- mit dem Gedanken "kostet nichts und schadet nie". Der zweite Halbsatz war falsch. Ein Service Worker uebernimmt die Inhaltsrichtlinie, die beim Herunterladen SEINER EIGENEN Skriptdatei gesetzt war, nicht die der Seite, fuer die er arbeitet. sw.js ist keine Seite, bekam also 'none' und durfte damit nichts mehr abrufen. Jede Anfrage scheiterte -- und weil der Service Worker fuer genau diesen Fall eine Offline-Seite bereithaelt, sah es aus wie ein Netzausfall beim Benutzer. Fuer Bilder, Stylesheets und Schriften bringt eine Richtlinie ohnehin nichts: Sie steuert, was ein DOKUMENT nachladen darf. Ein Bild laedt nichts nach. Dem Schaden stand also nie ein Gewinn gegenueber. Jetzt: Richtlinie nur noch fuer HTML-Dokumente. Warum der Test das nicht gefunden hat, folgt gleich -- er hat die Seiten geladen, aber nie den Service Worker arbeiten lassen. Genau die Luecke, durch die es durchgerutscht ist. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
03a533f143 |
Inhaltsrichtlinie (CSP): mit Pruefsummen statt mit unsafe-inline
Fuenf Schutz-Kopfzeilen waren gesetzt, die wichtigste fehlte. Sie entscheidet als einzige darueber, ob eingeschleuster Text zu ausgefuehrtem Code wird oder sichtbarer Text bleibt. WARUM NICHT DER BEQUEME WEG Ueblich waere script-src 'self' 'unsafe-inline'. Eine Zeile, nichts geht kaputt -- und der Schutz ist weg: Der Browser kann nicht unterscheiden, ob ein Skript im Seitentext vom Entwickler stammt oder von einem Angreifer. Das Ergebnis ist eine Kopfzeile, die gut aussieht und im Ernstfall nichts tut. Der Bestand liess den sauberen Weg zu: keine fremden Skriptquellen, keine externen Schriften, ein Inline-Block je Seite. Von jedem Block wird die Pruefsumme gebildet. DIE PRUEFSUMMEN STEHEN BEWUSST NICHT IM CODE Das waere hier eine Falle mit Ansage: Statische Dateien gehen per "git pull" live, OHNE Neustart. Eine fest hinterlegte Summe waere nach der naechsten Textaenderung falsch -- und die Seite wuerde ihr eigenes Skript nicht mehr ausfuehren. Sichtbar erst im Browser des Besuchers, nicht beim Deploy, und aussehend wie kaputtes JavaScript. Deshalb liest die Middleware die Datei selbst und merkt sich das Ergebnis, solange die Aenderungszeit gleich bleibt. Ein Test aendert index.html im laufenden Betrieb und prueft, dass die Summe nachzieht und die Seite weiterlaeuft. WAS DER TEST GEFUNDEN HAT Die erste Fassung haette die Startseite und stimmen.html beschaedigt: Team-Fotos, Event des Jahres und die Stimmen kommen von der postfach-Subdomain, img-src erlaubte nur 'self'. Der Deploy haette Erfolg gemeldet, der Server waere gestartet -- und die Bilder waeren weg gewesen. Gefunden, weil der Test alle 48 Seiten in einem echten Browser oeffnet und mitschreibt, was blockiert wird. Ein zweiter Fehlschlag lag am Test selbst: Er verlangte eine Pruefsumme auf jeder Seite, auch auf denen ohne Inline-Block. Ein Test, der Unmoegliches fordert, wird frueher oder spaeter abgeschaltet -- er unterscheidet jetzt nach dem tatsaechlichen Inhalt der Datei. DREI onclick-ATTRIBUTE ENTFERNT Sie haetten 'unsafe-inline' erzwungen. Zweimal ein "Coming soon"-Knopf, dessen onclick nur Klicks abfing -- ein <a> ohne href tut das von selbst, ganz ohne Skript. Einmal ein Schliessen-Knopf im Verwaltungsbereich, jetzt mit angehaengtem Zuhoerer. GEGENPROBE Ohne sie waere der Rest wertlos: Eine Richtlinie, die alles erlaubt, blockiert auch nichts und besteht jede Pruefung. Der Test schleust deshalb echten Code ein -- ein Inline-Skript und eines von fremder Adresse -- und beide muessen scheitern. style-src behaelt 'unsafe-inline': 587 style-Attribute im Bestand, deren Umbau ein echtes Risiko fuers Aussehen waere, bei kleinem Gewinn. Ueber Stile laesst sich verschleiern und ueberdecken, aber kein Code ausfuehren. Bleibt als eigener Punkt auf der Liste. 15 Pruefungen gruen, 48 Seiten sauber, Portfolio-Suite unveraendert 35. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
2e2172202e |
Rechtstexte in fuenf Sprachen
Impressum, AGB, Widerrufsbelehrung und Datenschutzerklaerung gibt es jetzt auf Deutsch, Schweizer Hochdeutsch, Englisch, Franzoesisch und Portugiesisch. 95 Textbloecke, rund 13.000 Zeichen je Sprache. DIE MASSGEBLICHKEITSKLAUSEL STEHT IN JEDER SPRACHE Nur die deutsche Fassung ist verbindlich; die Uebersetzung dient dem Verstaendnis. Ohne diesen Hinweis waere die Uebersetzung ein Risiko -- ein Kunde koennte sich auf die franzoesische Fassung berufen. Der Hinweis stand schon auf der Seite, aber selbst nur auf Deutsch: Genau die Leute, fuer die er gedacht ist, konnten ihn nicht lesen. WIDERRUFSBELEHRUNG UND MUSTERFORMULAR SIND AMTLICH Sie folgen dem Wortlaut aus Anhang I der Richtlinie 2011/83/EU in der jeweiligen Amtssprache -- nicht einer eigenen Uebersetzung. Der Gesetzgeber hat diese Saetze selbst formuliert; wer sie neu uebersetzt, verliert den Schutz der Musterbelehrung. Angepasst ist nur die Person: Die Muster sprechen von "wir/uns", hier schreibt ein Einzelunternehmer "ich/mir" -- diese Anpassung sieht das Muster ausdruecklich vor. SCHWEIZERDEUTSCH GIBT ES HIER BEWUSST NICHT Auf allen anderen Seiten spricht "de-CH" echten Dialekt. In Rechtstexten waere das unserioes -- es gibt keine Widerrufsbelehrung auf Mundart. Die Schweiz schreibt Hochdeutsch, nur ohne Eszett. Genau das erzeugt eine Zeile Code aus dem deutschen Text, statt 95 von Hand gepflegter Doppeleintraege, die beim naechsten Aendern auseinanderlaufen wuerden. DER FEHLER, DER FAST LIVE GEGANGEN WAERE Beim Aufbau wurden zwei Bloecke uebersprungen: eine reine Formularlinie und eine zweite "Fassung vom"-Zeile. Ab dort war jede Schluesselnummer um eins verschoben. Im Musterformular haette dadurch ueber jedem Feld die falsche Beschriftung gestanden -- "Datum" wo "Name" hingehoert. Und in fuenf Sprachen waere es niemandem aufgefallen, denn jede Sprache war ja vollstaendig gefuellt: Eine Vollstaendigkeitspruefung ist gegen diese Art Fehler wehrlos. Die Schluessel sind deshalb jetzt ueber den TEXT zugeordnet, nicht ueber eine laufende Nummer. Ein eigener Durchlauf vergleicht jeden deutschen Text im Woerterbuch mit dem an derselben Stelle im HTML. WAS DER NEUE DURCHLAUF SONST PRUEFT - Greift die Umschaltung in jeder der fuenf Sprachen, folgt das lang-Attribut, bleibt kein Textblock leer? - Gegenprobe, dass die Umschaltung ueberhaupt etwas tut: Englisch, Franzoesisch und Portugiesisch MUESSEN sich vom Deutschen unterscheiden. Ohne diese Probe waere ein Woerterbuch, das ueberall denselben deutschen Text zurueckgibt, gruen durchgelaufen. - Kein Eszett in der Schweizer Fassung, sonst wortgleich. - Die Massgeblichkeitsklausel nennt in jeder Sprache die deutsche Fassung. Geprueft: 1303 Pruefungen gruen (Browser 737, Server 566), i18n ohne Fehler, WCAG ohne Fundstellen. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
0ef64ba222 |
Systemabnahme: fuenf Altlasten geschlossen
Vollstaendiger Durchlauf ueber alle Pruefungen. Dabei kamen fuenf Dinge ans Licht, die teils seit Wochen offen standen. 1. WCAG-KONTRAST -- der einzige Punkt, der echte Besucher betraf Die lila Schilder erreichten nur 4,08:1, verlangt sind 4,5:1 fuer normalen Text. 17 Fundstellen, alle dieselbe Ursache: Die Schrift nutzte den vollen Ton Aurora Violet. Gemessen wurde nicht geschaetzt: Untergrund rgb(38,41,81) aus dem echten Bild ausgelesen, Schrift 12,5 Punkte -- und fett zaehlt erst ab 18,5 Punkten als "grosser Text". Neu ist --wd-lila-hell (#C197FF, 6,02:1). Bewusst NICHT der knappste Wert: #B380FF haette mit 4,91:1 gereicht, aber dasselbe Schild steht auch ueber der Buehne im Verwaltungsbereich. Ein Ton, der nur an einer Stelle knapp besteht, faellt beim naechsten Hintergrund wieder durch. Dasselbe Muster wie --wd-blau-hell, das genau deshalb existiert. 2. GEHEIMNIS-TEST -- der Test war veraltet, nicht der Code Er verlangte ".env hat Vorrang", die Umsetzung macht das Gegenteil. Die Begruendung im Code ueberzeugt: Wer PayPal-Daten im Formular eintraegt, erwartet, dass sie gelten. Andernfalls koennte ein alter Wert in der .env sie stumm ueberstimmen -- und man sucht stundenlang. Der Test prueft jetzt die tatsaechliche Reihenfolge, dazu neu, dass ein gleichzeitig vorhandener Serverwert auch angezeigt wird. Ausserdem endete der Lauf trotz gruener Pruefungen mit einer Fehlermeldung: Unter Windows haelt eine offene SQLite-Datei eine Sperre, das Aufraeumen scheiterte mit EPERM. Auf Linux waere es durchgelaufen -- dasselbe Skript mit unterschiedlichem Ergebnis je Rechner. Jetzt wird erst geschlossen, dann geloescht, und das Aufraeumen kann den Lauf nicht mehr zum Scheitern bringen. 3. PORTAL-TEST -- ebenfalls veraltet Er suchte "1500,00" und schlug fehl, seit der Formatierer den Tausenderpunkt setzt. "1.500,00 EUR" ist die korrekte deutsche Schreibweise; gerade ab vier Stellen macht der Punkt eine Zahl auf einen Blick lesbar. 4. ZWEI SEITEN OHNE WOERTERBUCH -- eine Entscheidung, keine Luecke "diagnose" ist ein Betriebswerkzeug. "rechtliches" ist der heiklere Fall: Rechtstexte durch eine ungepruefte Uebersetzung zu schicken ist gefaehrlicher, als sie einsprachig zu lassen. Ein Fehler in einer Widerrufsbelehrung wirkt gegen den Verfasser. Die Pruefung meldete beides als "Datei fehlt" -- das las sich wie ein Versehen und stand deshalb dauerhaft in der Fehlerliste, ohne dass jemand etwas tat. Jetzt sind beide benannt und begruendet. 5. TAG-UNGLEICHGEWICHT -- eine Fehlmessung Die Pruefung zaehlte auch HTML-Schnipsel, die als Zeichenketten im JavaScript stehen. Dort steht ein oeffnendes <div> regelmaessig in einer anderen Zeichenkette als sein </div>, weil die Teile erst beim Zusammensetzen ein Ganzes ergeben. Gegengeprueft im Browser: geparster Baum einwandfrei, kein Skriptfehler, Verschachtelung unauffaellig. Es war nie ein Strukturfehler. Die Meldung stand aber monatelang als "2 Fehler" da und haette jede echte Meldung entwertet, die dazugekommen waere. STAND Browser 717 Pruefungen 0 offen Server 566 Pruefungen 0 offen i18n keine Fehler WCAG 0 Fundstellen (vorher 17) Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
4fe66e1e0e |
"Preise & Zeit" entfernt -- Inhalte in die Leistungen uebernommen
"leistungen und preis&zeit ist ja das gleiche, nimm die kategorie
preise&zeit komplett weg"
Stimmt bei den Paketen und Preisen: Beide Seiten zeigten dieselben
Zahlen. Zwei Orte fuer dieselbe Zahl sind eine Einladung, dass sie
irgendwann auseinanderlaufen -- und dann steht ein falscher Preis auf
der Seite, ohne dass es jemand merkt.
NICHT ALLES WAR DOPPELT
Vor dem Loeschen nachgesehen statt einfach geloescht. Zwei Abschnitte
gab es NUR dort:
"Was den Preis bewegt" -- beantwortet die Frage, die nach jeder
Preisliste kommt: Warum kostet es bei mir mehr oder weniger?
Ohne sie ist eine Preisspanne eine Behauptung.
"Wie bezahlt wird" -- Angebot, 30 % Anzahlung, Restbetrag, Betreuung.
Rechtlich relevant und aus den AGB verlinkt.
Beide sind in die Leistungen umgezogen, samt ihrer 24 Textbausteine in
allen fuenf Sprachen. Waeren sie mitgeloescht worden, haette es niemand
sofort bemerkt -- und die Seite haette ab dann Preise genannt, ohne sie
zu erklaeren.
WEITERLEITUNG STATT 404
Die Adresse /webdesign/preise.html bleibt bedient und fuehrt auf die
Leistungen. Lesezeichen, alte Links aus Nachrichten und die installierte
App zeigen sonst ins Leere, und ein 404 auf einer Preisseite ist der
denkbar schlechteste erste Eindruck.
302 statt 301: Eine dauerhafte Weiterleitung merken sich Browser
hartnaeckig; sollte die Seite je zurueckkehren, muesste jeder Besucher
seinen Zwischenspeicher leeren.
EIN FEHLER BEIM EINBAU
Die Weiterleitung stand zuerst weiter unten in der Schranke, bei den
ohne Code erreichbaren Seiten. Dort haette sie nur fuer NICHT angemeldete
Besucher gegriffen -- wer angemeldet ist, passiert die Schranke vorher
mit next() und haette einen 404 auf die geloeschte Datei bekommen.
Genau die Person also, die die Seite am ehesten im Lesezeichen hat.
Jetzt steht sie ganz vorne, vor jeder Zugangspruefung.
GEPRUEFT: 10 Pruefungen -- beide uebernommenen Abschnitte erscheinen in
allen fuenf Sprachen, kein unuebersetzter Schluessel sichtbar. Kein
Verweis auf die alte Seite blieb irgendwo stehen (ablauf.html hatte
einen, der ist umgebogen). Gestaltung 0 Befunde, Textkodierung sauber,
Designsystem 5.
Versionsstempel und Cache auf v20.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
dd4010e75d |
Diagnoseseite: findet und behebt haengende Zwischenspeicher
Rueckmeldung: "garnichts laedt in der verwaltungsseite". Geprueft statt geraten -- die Serverseite ist in Ordnung: Dienst aktiv, keine Fehler im Protokoll CORS-Vorabanfrage 204 mit allow-origin echte Anfrage 401 (korrekt ohne Anmeldung), Antwortzeit unauffaellig ausgelieferte Seite enthaelt den neuen Code Damit bleibt fast nur der Browser: ein alter Service Worker, der veraltete Dateien ausliefert. Er ueberlebt ein normales Neuladen, und niemand kann ihn ohne Entwicklerwerkzeuge sehen. webdesign/diagnose.html prueft sechs Dinge und sagt im Klartext, welches davon klemmt: Service Worker aktiv? Zwischenspeicher gefuellt? Server erreichbar und wie schnell? Kennt der Server die neuen Adressen (404 = Server veraltet)? Liegt eine Anmeldung vor? Und wird die AKTUELLE Gestaltungsdatei ausgeliefert -- erkennbar an einem Merkmal, das es erst seit heute gibt. Ein Knopf meldet den Service Worker ab, loescht die Zwischenspeicher und laedt die Verwaltung mit Zeitstempel neu. Der Text sagt ausdruecklich, dass Anmeldung und Daten unberuehrt bleiben -- sonst traut sich niemand zu klicken. ZWEI ENTSCHEIDUNGEN Die Seite laedt KEINE externen Dateien, alles steht inline. Sie muss funktionieren, wenn genau das kaputt ist, was sie untersucht -- eine Diagnoseseite, die an derselben veralteten CSS-Datei scheitert, ist wertlos. Sie ist von der Zugangswand ausgenommen, wie Widerruf und Rechtstexte. Gebraucht wird sie genau dann, wenn etwas klemmt; dann darf nicht ausgerechnet die Zugangswand davorstehen. Sie enthaelt keine Kunden- oder Projektdaten, sondern prueft nur den eigenen Browser und meldet Statusnummern. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
14ad108c87 |
Rechtliches: elektronische Widerrufsfunktion (§ 356a BGB), Impressum, AGB,
Widerrufsbelehrung und Datenschutz
RECHERCHIERT, NICHT AUS DEM GEDAECHTNIS
Der Webdesign-Bereich hatte KEINE eigene Rechtsseite -- obwohl dort
Vertraege geschlossen und Zahlungen ausgeloest werden. Die Fusszeile
verwies auf die Kontaktseite des Universe, die ein Content-Projekt
beschreibt, kein Dienstleistungsgeschaeft.
Die Web-Recherche hat eine Pflicht zutage gefoerdert, die seit zwei
Monaten gilt und die die Seite nicht erfuellt hat:
§ 356a BGB -- elektronische Widerrufsfunktion, in Kraft seit
19.06.2026. Sie gilt fuer ALLE Fernabsatzvertraege, die ueber eine
Online-Benutzeroberflaeche geschlossen werden, nicht nur fuer
Finanzdienstleistungen.
WARUM DAS HIER GILT: Im Kundenportal nimmt der Kunde Zusatzangebote per
Klick VERBINDLICH an ("Damit nimmst du das Zusatzangebot verbindlich
an"). Das ist ein Vertragsschluss ueber eine Online-Benutzeroberflaeche.
Fuer die geplanten PayPal-Zahlungen gilt dasselbe.
Der Anbieter sitzt in Luxemburg. Fuer Verbraucher mit gewoehnlichem
Aufenthalt in Deutschland gilt nach Art. 6 Rom-I-VO trotzdem das
deutsche zwingende Verbraucherrecht, weil die Seite sich erkennbar an den
deutschsprachigen Markt richtet. Deshalb wurde der STRENGERE Standard
umgesetzt, nicht der bequemere.
WAS GEBAUT WURDE
webdesign/widerruf.html -- die Widerrufsfunktion, genau nach dem
Wortlaut der Vorschrift:
* Beschriftung "Vertrag widerrufen" (gesetzlich vorgegeben)
* ZWEITE Schaltflaeche "Widerruf bestaetigen" (ebenfalls vorgegeben --
ein einstufiges Formular wuerde die Vorschrift nicht erfuellen)
* unverzuegliche Eingangsbestaetigung mit Nummer, ZEITPUNKT (nicht nur
Datum), Empfaenger und dem Wortlaut der Erklaerung
* Link in der Fusszeile JEDER Seite -- "staendig verfuegbar,
hervorgehoben platziert, leicht zugaenglich" heisst nicht "in den AGB
versteckt"
Drei Entscheidungen, die unmittelbar aus dem Sinn der Vorschrift folgen:
KEINE ANMELDUNG. Die Seite ist von der Zugangswand ausgenommen. Wer
seinen Code verlegt hat, wuerde sonst seine Frist verlieren --
Fristverlust durch eine selbstgebaute Huerde ist der schlimmste
denkbare Fall.
KEINE MENGENBEGRENZUNG. Ueberall sonst richtig, hier ein
Rechtsverlust: Wer in der letzten Stunde seiner Frist wegen eines
hakenden Netzes dreimal klickt, darf nicht abgewiesen werden.
KEIN ZWISCHENSPEICHER. Beim Anfrageformular ein Segen, hier eine
Falle: Auf einem geteilten Rechner laege der halb ausgefuellte Widerruf
des einen im Browser des naechsten.
webdesign/rechtliches.html -- Impressum, AGB, Widerrufsbelehrung samt
Muster-Widerrufsformular, Datenschutzerklaerung. Alle Betreiberangaben
sind aus den bestehenden Seiten UEBERNOMMEN, nichts erfunden: Anschrift
in Mondercange, Kleinunternehmerregelung nach Art. 57 TVA-Gesetz LU und
Richtlinie (EU) 2020/285, netcup/Cloudflare, PayPal Luxemburg.
Migration 0014: wd_widerrufe (der dauerhafte Datentraeger und der
Nachweis, wird nie geleert) und wd_zustimmungen. Letztere speichert nicht
nur den Haken, sondern den WORTLAUT, den der Kunde gesehen hat -- die
Beweislast fuer die Zustimmung zum vorzeitigen Leistungsbeginn liegt beim
Unternehmer (§ 356 Abs. 4 BGB), und im Streit zaehlt, WAS bestaetigt
wurde. Bewusst OHNE Fremdschluessel: CASCADE wuerde den Nachweis mit dem
Kunden mitloeschen, RESTRICT wuerde eine DSGVO-Loeschung blockieren.
Druckansicht: Die Eingangsbestaetigung ist ein Rechtsnachweis. Auf Papier
schwarz auf weiss, ohne Navigation und Knoepfe -- ein Nachweis, den
niemand ausdruckt, weil er eine halbe Patrone kostet, erfuellt seinen
Zweck nicht.
ZWEI ECHTE FEHLER GEFUNDEN
1. Die Pflicht-Sternchen verschwanden nach der Uebersetzung. Ursache:
data-i18n stand auf dem <label> selbst und ersetzte dessen ganzen
Inhalt -- samt <span class="wd-pflicht">. Das Anfrageformular macht es
laengst richtig (data-i18n auf einem INNEREN span); die neue Seite
hatte das Muster nicht uebernommen. Aufgefallen ist es nur, weil der
Test die Pflichtfelder GEZAEHLT hat statt sie vorauszusetzen.
2. window.WD.sprache() gibt es nicht, die Funktion heisst getSprache().
Dadurch brach der Uebergang zur zweiten Stufe stumm ab.
GEPRUEFT: 58 Pruefungen, alle bestanden. Darunter die gesetzlich
vorgegebenen Beschriftungen in allen FUENF Sprachen, "kein Grund noetig",
genau drei Pflichtfelder, Datum UND Uhrzeit in der Bestaetigung, und die
Druckansicht.
WAS FILIPE NOCH PRUEFEN LASSEN MUSS: Diese Texte sind sorgfaeltig
recherchiert, aber ich bin keine Rechtsanwaeltin. Vor dem oeffentlichen
Start gehoert das Ganze einmal zu einer im luxemburgischen Recht
qualifizierten Fachperson -- besonders die grenzueberschreitende Lage
(Sitz LU, Kunden in DE/CH/FR/PT) und die Frage, ob die Seite in
Franzoesisch und Portugiesisch aktiv verkaufen soll. Dann muessen die
Rechtstexte auch dorthin uebersetzt werden, und zwar fachlich.
Versionsstempel und Cache-Name auf v7.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
38bc741660 |
Aufraeumen: versehentlich mitcommittete Dateien entfernt
Ein 'git add -A' hat 13 Bild-Sicherungskopien (.bak-*, zusammen 2,6 MB), den lokalen Testserver und eine erzeugte package-lock.json mitgenommen. Die package-lock.json war der schaedlichste Teil: Auf dem Server existiert eine eigene, dort erzeugte Fassung. Eine versionierte Datei gleichen Namens laesst 'git pull' abbrechen -- der Deploy stand sofort still. Alle drei Muster stehen jetzt in .gitignore. |
||
|
|
4ce51c127e | WIP: Aufgaben- und Postfach-Routen (Test folgt auf dem Server) | ||
|
|
74091590b8 |
Verwaltung: nur noch EINMAL den Code eingeben
Rueckmeldung 22.08.2026: "ich hab auf der verwaltungs seite 2 mal dass ich
den zugangscode eingeben muss und vanvan auch, ich will es nur einmal
eingeben muessen." Berechtigt.
Die Zugangswand hat serverseitig laengst geprueft, WER da ist -- Dogfather
oder VanVan, laut Masterplan S.4 beide gleichberechtigte
Volladministratoren. Ein zweites Passwort danach bringt keinen
zusaetzlichen Schutz, es kostet nur jedes Mal Zeit.
Warum es nicht einfach "Cookie mitschicken" ist: Die Verwaltungsdaten
liegen hinter postfach.dogfather-universe.com, einem ANDEREN Rechnernamen.
Das Sitzungs-Cookie gilt dort nicht -- so sind Cookies gebaut, und das ist
gut so.
Loesung: Die Zugangswand stellt unter /webdesign/api-ausweis einen
kurzlebigen, signierten Ausweis aus, den die interne API anerkennt.
- 15 Minuten gueltig, die Seite holt bei Bedarf still einen neuen
- traegt bereich="wd-admin", damit ein Sitzungs-Token der Zugangswand
hier NICHT durchgeht und umgekehrt
- nur mit gueltiger Zugangssitzung zu bekommen
- gilt AUSSCHLIESSLICH fuer die /webdesign-Endpunkte. Postfach,
Bewerbungen, Supporter und Teamverwaltung bleiben unberuehrt
Fehlt WEBDESIGN_API_SECRET auf einer der beiden Seiten, gilt kein Ausweis
und die Verwaltung fragt wie bisher nach dem Team-Code. Ein fehlender
Konfigurationswert darf niemals eine Tuer oeffnen -- nur eine schliessen.
Genau das prueft der letzte Testfall.
Bei einem 401 wird EINMAL still ein neuer Ausweis geholt und die Anfrage
wiederholt, statt jemanden mitten im Arbeiten rauszuwerfen.
10/10 Tests, darunter: gefaelschte Signatur, fremdes Geheimnis,
abgelaufen, falscher Bereich, erfundene Rolle.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
1b432f456f |
Kundenportal: Oberflaeche (Masterplan S.12)
Vier Ansichten in einer Seite: Anmeldung, Passwort festlegen ueber den
Einladungslink, Uebersicht, Projektdetail. 71 Textbausteine in fuenf
Sprachen.
Korrektur an einer frueheren Entscheidung: Ich hatte das Portal als "nur
Deutsch" eingestuft wie die Verwaltung. Denkfehler -- die Verwaltung
nutzen Dogfather und VanVan, das PORTAL nutzen Kunden, und die koennen
Franzosen oder Portugiesen sein. Jetzt fuenfsprachig, und die Sprache des
Kunden wird bei der Anmeldung automatisch uebernommen.
Gestaltungsentscheidungen:
* Eine Phasenleiste zeigt auf einen Blick, wo das Projekt steht. Das ist
die haeufigste Frage ueberhaupt und der Grund, warum Kunden anrufen.
Bei pausierten oder abgebrochenen Projekten wird KEINE Leiste gezeigt --
ein Fortschrittsbalken waere dort irrefuehrend.
* Eine Marke sagt, wer gerade am Zug ist ("Wir warten auf dich" /
"Dogfather ist dran"). Das beendet die haeufigste Unklarheit im
Projektverlauf.
* Offene Zahlungen stehen ganz oben und in Gold -- das Einzige, was den
Kunden wirklich zum Handeln auffordert.
* Rueckfrage nur beim ANNEHMEN eines Zusatzangebots, nicht beim Ablehnen.
Annehmen erzeugt eine Zahlungspflicht, Ablehnen ist folgenlos.
* Abgelaufene Sitzung fuehrt zur Anmeldung mit klarer Ansage statt zu
einer leeren Seite, die wie "du hast keine Projekte" aussaehe.
* Der Einladungslink wird nach Gebrauch aus der Adresszeile entfernt --
er ist verbraucht und hat in der Chronik nichts verloren.
* Die Zahlungsknoepfe sagen ehrlich, dass PayPal noch eingerichtet wird,
statt so zu tun als wuerde etwas passieren.
Pruefskript zweimal geschaerft, beide Male waren es Fehlalarme:
* Die Heuristik fuer Nachschlagetabellen hielt gewoehnliche Woerter wie
"abnahme" und "uebergeben" fuer Woerterbuch-Schluessel. Jetzt muss ein
Unterstrich im Namen sein, so wie bei allen echten Schluesseln.
* Eine Ueberschrift gilt jetzt auch als uebersetzt, wenn die Uebersetzung
INNEN sitzt (fester Teil + dynamischer Teil).
i18n vollstaendig, 45/45 Handy-Abnahme.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
9f74167f84 |
Sprungmarken brechen um statt zu scrollen, keine Silbentrennung in Ueberschriften
Rueckmeldung 22.08.2026: "ich will nicht dass man die hin und her schieben muss man soll die alle sehen aber nicht schieben muessen." Richtig, und aus zwei Gruenden: Eine Wischleiste verbirgt, DASS es noch mehr gibt -- was rechts aus dem Bild ragt, existiert fuer die meisten Menschen schlicht nicht. Dazu kam ein haesslicher Scrollbalken quer ueber die Seite. Jetzt brechen die Knoepfe um, alle fuenf sind auf einen Blick da, auch bei 320px. Der Text in den Knoepfen darf dabei mitbrechen (white-space: normal) -- ohne das sprengt ein langer Name wie "Buchhaltungs- & Steuerverwaltungsseiten" auf schmalen Bildschirmen die Zeile und der waagerechte Ueberlauf waere durch die Hintertuer zurueck. Dabei mitgefunden: "hyphens: auto" auf Ueberschriften. Auf dem Handy stand dadurch "Alles, was vorher ge-klaert sein sollte". Der Browser trennt damit nach Silben, auch wenn ueberhaupt kein Platzproblem besteht. In Fliesstext ist das ein Gewinn, in grossen Ueberschriften sieht es billig aus -- und genau die sind das Erste, was jemand sieht. overflow-wrap: break-word bleibt und faengt echte Ueberlaeufe weiterhin ab. Pruefskript: die Sprungmarken-Leisten waren als "absichtlich scrollbar" von der Ueberlaufpruefung ausgenommen. Diese Ausnahme ist raus -- sonst wuerde ein zurueckkehrender Ueberlauf dort nie auffallen. 45/45 weiterhin sauber. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
de4a90362e |
Verwaltungsbereich fuer Projektanfragen
Masterplan S.13. Anfragen ansehen, filtern, durchsuchen, Status aendern, interne Notizen, archivieren. 9/9 Sicherheitstests. Bewusste Entscheidungen: * NUR AUF DEUTSCH. Der oeffentliche Teil laeuft in fuenf Sprachen, weil dort Kunden landen. Hier landen ausschliesslich Dogfather und VanVan -- fuenf Sprachen waeren fuenffache Pflege und fuenffache Fehlerflaeche ohne einen einzigen Nutzer, der sie braucht. Genau wie der bestehende interne Bereich des Universe. * Anmeldung ueber die BESTEHENDE Team-Anmeldung (/auth/login) statt einer zweiten eigenen. Zwei Anmeldungen fuer dieselben zwei Personen waeren doppelte Pflege und ein zweiter Ort, an dem ein Zugang vergessen werden kann. Der Code der Zugangswand gilt hier ausdruecklich NICHT -- die Verwaltung steckt hinter zwei getrennten Tueren. * Sitzungstoken im sessionStorage, nicht localStorage: es verschwindet beim Schliessen, dieselbe Regel wie an der Zugangswand. Der Test prueft das ausdruecklich. * Bei abgelaufener Sitzung geht es zurueck zur Anmeldung statt zu einer leeren Liste. Eine leere Liste sieht aus wie "keine Anfragen" und ist damit eine stille Falschaussage. * Gold nur beim Status "neu" -- also genau dort, wo wirklich etwas zu tun ist. Wuerde alles leuchten, leuchtet nichts. * Archivieren statt Loeschen, und die Oberflaeche sagt das auch dazu. Pruefskript: kennt jetzt bewusst einsprachige Seiten (verwaltung, portal) und prueft dort nur die Struktur, statt ein fehlendes Woerterbuch zu melden. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
eaeaec6b56 |
Anfrageformular fertig - vier Schritte, Zwischenspeicherung, echte Absendung
Masterplan S.10 "Projektanfrage ohne Informationsverlust" umgesetzt.
End-to-End gegen die echte Datenbank belegt: Anfrage A-2608-0002 liegt drin.
38/38 Browsertests, 45/45 Handy-Abnahme.
Aufbau: 4 Schritte + Zusammenfassung + Dankeseite.
- Zwischenspeicherung nach jedem Tastendruck. Geschlossener Tab, leerer
Akku oder versehentliches Zurueck kosten keine Arbeit. Entwuerfe
verfallen nach 30 Tagen -- ein halbes Jahr alter Entwurf verwirrt mehr
als er hilft.
- Folgefragen erscheinen nur passend zur Auswahl und werden beim
Zurueckwechseln NICHT mitgeschickt, sonst landen alte Shop-Antworten in
einer Onepager-Anfrage.
- Die Zusammenfassung wird aus den Feldern gelesen, nicht aus einem
nebenher gepflegten Objekt -- sie kann dadurch nie etwas anderes
behaupten als das, was tatsaechlich abgeschickt wird.
- Telefon wird zur Pflicht, sobald "Per Telefon" gewaehlt ist. Ein Wunsch,
der nicht erfuellbar ist, ist schlimmer als eine Pflichtangabe.
Drei Fehler, die erst der Test gefunden hat:
1. Der "Zurueck"-Knopf stand auch auf Schritt 1 da. Ursache: das
hidden-Attribut wird nur ueber "display:none" umgesetzt und verliert
gegen jedes eigene display -- und Knoepfe sind inline-flex. Zentral
behoben ueber ".wd [hidden] { display:none !important }".
2. Nach erfolgreichem Absenden legte zeigeSeite() den geloeschten Entwurf
sofort wieder an. Beim naechsten Besuch haette eine bereits gesendete
Anfrage erneut im Formular gestanden.
3. Der Server meldet bei Spamverdacht bewusst Erfolg ohne Nummer. Ein
echter Mensch, der zufaellig sehr schnell war, haette eine Dankeseite
mit "—" gesehen und auf eine Antwort gewartet, die nie kommt. Jetzt
ein ehrlicher Hinweis mit zweitem Weg, und der Entwurf bleibt erhalten.
Pruefskripte geschaerft:
- i18n-Pruefung liest jetzt auch assets/js/wd-<seite>.js, sonst meldet sie
reihenweise "unbenutzt" fuer Schluessel, die aus dem Seitenskript kommen.
- Handy-Abnahme ueberspringt absichtlich unsichtbare Eingabefelder
(Auswahlkacheln, Honigtopf). Fehlalarme sind das Ende jeder Pruefung,
weil man sie irgendwann pauschal ignoriert.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
29a054c359 |
Bilder waren hochkant gestreckt und ungleich hoch, Abstaende halbiert
Rueckmeldung 22.08.2026 per Bildschirmfoto: "die sollen alle gleich
aussehen und nicht einer groesser oder kleiner" und "ich will nicht soooo
viel abstand".
1) Verzerrte, ungleich hohe Projektbilder
Nachgemessen: 576px breit, aber 750px bzw. 696px hoch -- also hochkant
gestreckt und unterschiedlich, obwohl im CSS sauber "aspect-ratio:
16/10" stand. Ursache: die width/height-Attribute im HTML (die dort
bewusst stehen, damit der Browser vor dem Laden den Platz reserviert
und die Seite nicht springt) wirken wie eine CSS-Hoehe und schlagen
aspect-ratio. Fix zentral ueber ".wd img[width][height] { height:
auto }" statt in jeder einzelnen Regel -- so kann es bei einem neuen
Bild nicht vergessen werden.
Jetzt beide 576x360, Karten beide 853px hoch.
2) Zu viel Leerraum
.wd-abschnitt hatte 100,8px oben UND unten, also gut 200px zwischen
zwei Abschnitten. Halbiert auf 57,6px, Hero von 78svh auf 68svh.
Seitenlaenge dadurch 8798px -> 7089px bei gleichem Inhalt.
3) Zwei neue Dauerpruefungen in pruefe-webdesign-handy.mjs, damit genau
diese beiden Fehlerarten nicht wieder per Bildschirmfoto auffallen
muessen:
- verzerrte Bilder (gewuenschtes vs. tatsaechlich gerendertes
Seitenverhaeltnis, 2 % Toleranz)
- ungleich hohe Karten innerhalb EINER Rasterzeile
40/40 Abnahme weiterhin sauber.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
356bb974b8 |
Knopf war unlesbar, und der Code wird jetzt bei jedem Schliessen neu verlangt
Zwei Rueckmeldungen vom 22.08.2026, beide behoben und mit Tests abgesichert.
1) "das sieht nicht gut aus" (Bildschirmfoto des Hauptknopfs)
Ursache: ".wd a" ist Klasse+Element und damit spezifischer als die reine
Knopfklasse ".wd-btn--haupt". Die Textfarbe des Knopfs wurde dadurch
ueberstimmt -- hellblaue Schrift auf hellblauem Grund, praktisch
unlesbar. Derselbe Spezifitaetsfehler wie zuvor bei den Namen auf der
Zugangswand. Fix: ".wd a:not(.wd-btn)" plus zweistufig geschriebene
Knopfregeln, damit das nicht wieder passieren kann.
2) "das sieht lang gezogen aus"
Die Pillenform (border-radius 999px) laesst breite Knoepfe
auseinandergezogen wirken, weil der Radius optisch mit der Breite
mitwaechst. Jetzt fester Radius von 14px -- gleiche Form bei jeder
Breite, ruhiger und hochwertiger.
3) "ich will das ich jedes mal den code gefragt werde wenn man die seite
zu macht"
Das Sitzungs-Cookie allein reicht dafuer nicht: Browser stellen genau
solche Cookies beim Wiederherstellen von Tabs zurueck ("Dort
fortfahren, wo du aufgehoert hast"), man landet dann ohne Codeabfrage
wieder mitten in der Seite. Zusaetzlich jetzt eine Sitzungsmarke im
sessionStorage, die beim echten Schliessen verschwindet. Fehlt sie bei
vorhandenem Cookie, wird die Sitzung serverseitig beendet und zur
Zugangswand geleitet. Token-Notbremse von 24 auf 8 Stunden gesenkt.
13/13 Tests im echten Browser, inklusive Schutz vor Endlosschleife.
DEPLOY.md: zwei Checkouts auf dem Server dokumentiert (/home/dogiweb und
/home/dogiintern) und der Vorfall, dass /webdesign nach dem Pull kurz ohne
Zugangsschutz erreichbar war, weil der Dienstneustart fehlte.
Co-Authored-By: Claude Opus 5 <[email protected]>
|
||
|
|
4b3ec450d5 |
Webdesign-Bereich: Fundament, oeffentliche Seiten, Zugangsschutz, PayPal
Umsetzung des "Website Masterplan" (16 Seiten) unter /webdesign. Zugangsschutz mit EIGENER Schranke (server/webdesign-gate.js) statt gate.js: gate.js laesst seit dem oeffentlichen Start am 21.08.2026 jeden durch, weil die Pruefung auf SITE_PUBLIC_LAUNCH_AT als allererste Zeile steht. Haette man /webdesign dahintergehaengt, waere der ausdruecklich nicht-oeffentliche Bereich inklusive Preisen und spaeteren Kundendaten ab der ersten Sekunde fuer jeden lesbar gewesen. Eigenes Sitzungs-Cookie, bereich="webdesign" im Token, damit ein gueltiges Universe-Cookie hier NICHT gilt. 37/37 Tests. Sieben oeffentliche Seiten in fuenf Sprachen (de, de-CH mit echtem Dialekt, en, fr, pt). Preise, Zeitrahmen, Paketnamen und die 30-%-Regel stehen an genau EINER Stelle in wd-core.js -- der Masterplan verlangt "ueberall widerspruchsfrei", und vier Kopien laufen bei der ersten Preisaenderung auseinander. Als App installierbar auf Handy und PC. Der Service Worker speichert bewusst KEINE HTML-Seite zwischen: nach dem Abmelden wuerden sonst geschuetzte Seiten weiter ausgeliefert, ohne dass der Server je gefragt wird. 18/18 Tests. Handy-Abnahme ueber alle Seiten in fuenf Breiten (320-1440) und fuenf Sprachen: 40/40. Der Test fand 35 echte Fehler (Touch-Ziele unter 44px), behoben im Designsystem statt einzeln pro Seite. PayPal (Wunsch 22.08.2026 "sofort auf meinem paypal"): Orders API mit intent=CAPTURE, also sofortiger Einzug statt blosser Reservierung. Gebuehr und Nettobetrag getrennt gespeichert. Betraege durchgehend als Ganzzahl in Cent. Gefaelschte Webhooks werden abgewiesen. Fail closed solange Zugangsdaten fehlen. 28/28 Tests gegen einen nachgebauten PayPal-Server. Datenbank: 15 Tabellen mit Praefix wd_, fachlich vollstaendig vom Universe getrennt. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
57966e24d0 |
Automatischer öffentlicher Start um 21 Uhr + Countdown auf der Zugangsseite
Nutzer-Wunsch 21.08.2026: "ich will dass du auch ein countdown zu der seite hinzufügst wo wir den zugangscode eingeben müssen. den um 21h heute abend geht die seite live. kannst du das sogar so anpassen dass es automatisch läuft?" server/gate.js: - Neue Einstellung SITE_PUBLIC_LAUNCH_AT (ISO-Zeitstempel mit Zeitzone). Ab diesem Moment lässt gateMiddleware ausnahmslos jeden durch -- ganz ohne Neustart oder manuellen Eingriff, weil jede Anfrage die aktuelle Serverzeit live neu prüft. Die Freischaltung "passiert" also von selbst in der Sekunde, in der die Uhrzeit erreicht wird. Vorher bleiben die Zugangscodes unverändert nötig, damit das Team schon vorher rein kann. Fail-safe statt fail-open geprüft: ein kaputter/unparsbarer Zeitwert (z.B. Tippfehler in der .env) lässt die Schranke aktiv, statt die Seite versehentlich für alle zu öffnen. - Neuer öffentlicher Endpunkt GET /gate-launch-info (immer erreichbar, auch ohne gültige Sitzung) liefert launchAt/isLive/serverTime für die Countdown-Anzeige im Frontend. gate.html: - Neue Countdown-Box zwischen Titel-Karte und den Zugangscode-Kacheln (bleibt unsichtbar, solange kein Starttermin konfiguriert ist). Rechnet auf der SERVERZEIT statt der eigenen Uhr (einmaliger Zeit-Abgleich beim Laden), damit eine falsch gehende Besucher-Uhr weder zu früh noch zu spät zählt. Bei Erreichen von Null folgt ein letzter Abgleich mit dem Server, bevor automatisch zur Zielseite weitergeleitet wird -- kein Klick, kein Neuladen nötig. - Zugangscode-Kacheln (Dogi/VanVan/Diene) bleiben während des Countdowns unverändert nutzbar. Getestet: 18 Middleware-Tests (inkl. Fail-safe bei kaputtem Zeitwert, weiterhin funktionierender Zugangscode vor dem Start) + 10 Playwright- Tests der Countdown-Oberfläche (Anzeige, Format, automatischer Sprung bei Ablauf, sofortige Weiterleitung falls schon live, stiller Fallback bei Netzwerkfehler). Zusätzlich alle 32 echten Seiten auf PC-Installierbarkeit geprüft (Manifest, Icons, Service Worker, Install-Knopf, echter Install-Klick-Ablauf simuliert) -- keine Probleme gefunden. Cache-Busting-Version auf 20260821s erhöht. Co-Authored-By: Claude Sonnet 5 <[email protected]> |
||
|
|
e2bd436084 |
Arbeit der parallelen Session gesichert (Profilbilder für Stimmen, Diene-Zugang)
Wie beim vorherigen Mal lag das nur als Arbeitskopie auf dem Server, nicht in git. Unverändert übernommen, bevor darauf aufgebaut wird: - Profilbild-Auswahl für die Stimmen (data-stimmen-avatare.js neu, stimmen.js, i18n-stimmen.js, stimmen.html, verwaltung.html, main.css) - Dritte Zugangs-Kachel für Diene (gate.html, server/gate.js) Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
6dad6a5af5 |
Fix: Deploys blieben bei Besuchern bis zu 4 Std im Browser-Cache haengen
Nutzer-Report: sah den Nav-Fix und die neue installierbare Verwaltungsseite trotz erfolgreichem Deploy nicht. Ursache: Express schickt standardmaessig KEIN Cache-Control mit -- da die Seite hinter Cloudflare (orange-cloud) liegt, sprang Cloudflare dafuer mit seinem eigenen Standardwert ein (Browser Cache TTL 4 Std, per curl bestaetigt: max-age=14400). Ein frischer Deploy war dadurch bis zu 4 Std lang im eigenen Browser-Cache jedes/jeder Besuchers unsichtbar. Cloudflare respektiert ein vom Origin gesetztes Cache-Control -- jetzt explizit "no-cache" gesetzt (erzwingt Revalidierung per ETag bei jedem Laden, kein Performance-Verlust durch schnelle 304-Antworten bei unveraendertem Inhalt). Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
2c5e04e433 |
Fix: manifest-verwaltung.json wurde von der Zugangsschranke blockiert
Die site-weite Zugangsschranke (server/gate.js) laesst bislang nur den exakten Pfad /manifest.json unauthentifiziert durch (fuer die PWA-Installierbarkeit der Haupt-Website noetig) -- das neue manifest-verwaltung.json fiel dadurch nicht unter die Ausnahme und wurde zur Login-Seite umgeleitet statt als JSON ausgeliefert zu werden. Neuen Pfad zur Ausnahmeliste hinzugefuegt. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
9adebd9bc4 |
KRITISCH: Server-Quellcode + kompletter Git-Verlauf waren oeffentlich abrufbar
Sicherheits-Audit vor dem geplanten oeffentlichen Start morgen (21.08.2026, Nutzer-Anfrage: "duerfen die leute keinen zugriff auf veraenderungen haben"). SITE_DIR ist der GESAMTE Repo-Ordner (join(__dirname, "..")), express.static lieferte daher nicht nur die Website aus, sondern auch: - server/ (inkl. gate.js, das komplette Sicherheitskonzept im Klartext) - server-internal/ (Admin-/Supporter-Backend-Quellcode) - cloudflare-worker/ (altes Backend) - .git/ (VOLLSTAENDIGE Commit-Historie, rekonstruierbar per Git-Dump) - CLAUDE.md, DEPLOY.md, wrangler.toml, netlify.toml, gate-worker.js, gate.html.bak-07-08-2026 (Alt-Backup-Datei einer frueheren Session) Live nachgewiesen (mit gueltigem Zugangscode -- morgen faellt die Schranke fuer ALLE weg): /server/gate.js und /.git/config lieferten HTTP 200. Ursache: serve-static blockt per Default nur Dateien, deren EIGENER Name mit einem Punkt beginnt (server/.env -> zufaellig schon 404), aber NICHT rekursiv -- .git/config wird trotzdem ausgeliefert, weil "config" selbst nicht mit einem Punkt beginnt, nur der Ordner davor. Fix: eigene Sperr-Middleware VOR express.static, unabhaengig von gateMiddleware (bleibt also auch nach dem Entfernen der Zugangsschranke wirksam). Blockt ganze Ordner (server/, server-internal/, cloudflare-worker/) + versteckte Ordner/Dateien rekursiv (jedes Pfadsegment, das mit "." beginnt, ausser .well-known) + eine feste Liste an Alt-Dateien + jedes *.bak-Muster, damit auch kuenftige Backup-Reste automatisch mitgeschuetzt sind. Lokal mit echtem Express-Server verifiziert (gateMiddleware absichtlich deaktiviert, um exakt den morgigen "oeffentlich"-Zustand zu simulieren): alle vorher gefundenen Luecken jetzt 404, alle echten Seiten/Assets (index.html, main.css, main.js, manifest.json, robots.txt, favicon) weiterhin 200. Getrennt prooft: server-internal/ (eigener Dienst unter postfach.dogfather-universe.com, Port 4200) hat sein EIGENES, unabhaengiges Session-System -- jede /admin/*-Route ist einzeln per requireTeamSession-Middleware abgesichert (in index.js durchgezaehlt, keine Ausnahme gefunden), live mit einer unauthentifizierten Anfrage gegen /admin/users/list bestaetigt (401). Dieser Dienst war nie vom Website-Gate abhaengig und ist von diesem Fund nicht betroffen. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
50371d5404 |
Zugangs-Sperre traf ALLE Besucher gleichzeitig statt nur den Verursacher
Nutzer-Report 19.08.2026: "ich komme auf der .com nicht rein" -- der RICHTIGE Zugangscode wurde mit "Falscher Zugangscode" abgewiesen. Ursache: gateClientKey() nutzte req.ip. Das ist hier NICHT die IP des Besuchers, sondern die des Cloudflare-Knotens (Kette Besucher -> Cloudflare -> Caddy -> Express; bei trust proxy: 1 bleibt genau Cloudflare uebrig). Damit teilten sich alle Besucher EINEN Fehlversuchs-Zaehler -- fuenf Vertipper von irgendwem sperrten die Seite fuer jeden, 15 Minuten lang. Live nachgewiesen, nicht vermutet: derselbe richtige Code wurde ueber dogfather-universe.com abgelehnt und im selben Moment ueber www.dogfather-universe.com akzeptiert -- zwei Namen, zwei Cloudflare-Knoten, zwei getrennte Zaehler. Fix 1 -- echte Besucher-IP aus CF-Connecting-IP. Dieser Header war am 05.08.2026 bewusst verworfen worden, weil er faelschbar war, solange der Server auch direkt unter seiner IP erreichbar war. Diese Voraussetzung gilt nicht mehr: die Firewall laesst 80/443 nur noch aus den Cloudflare-Netzen zu. Vor der Umstellung von aussen gegengeprueft -- Direktzugriff auf beide Ports kommt gar nicht mehr zustande, der Header kann also nur von Cloudflare stammen. Abhaengigkeit im Code vermerkt: wird der Direktzugriff je wieder geoeffnet, muss diese Stelle zurueckgebaut werden. Ungueltige Header-Werte fallen sauber auf req.ip zurueck. Fix 2 -- ehrliche Meldung bei Sperre (429 statt 401), mit Restzeit in Minuten. Die bisher absichtlich identische Meldung sollte Angreifern nichts verraten, hat aber in der Praxis den Besitzer der Seite selbst ratlos gemacht: richtiger Code, Anzeige "Falscher Zugangscode", keine Chance zu erkennen dass nur eine Wartezeit laeuft. Die Sperre bleibt in voller Laenge bestehen, der Code wird dadurch nicht leichter erratbar. Fix 3 -- abgelaufene Eintraege werden aufgeraeumt. Pro echter Besucher-IP kann die Map sonst unbegrenzt wachsen (vorher gab es nur eine Handvoll Cloudflare-Knoten). Regressionstest ergaenzt (server/test-gate.mjs, 12 Pruefungen). Gegen den ALTEN Code laufen gezielt 5 davon auf Fehler -- darunter "Dogi kommt trotz fremder Sperre rein" --, gegen den neuen alle gruen. Der Test faengt also wirklich diesen Bug. Co-Authored-By: Claude Opus 5 <[email protected]> |
||
|
|
7201c6a300 | Sicherheitskorrekturen am Gate + Mobil-Scroll-Bugfix (Audit-Funde 07.08.2026) | ||
|
|
d6489f787a |
Sicherheits- und Stabilitaetskorrekturen nach vollstaendiger Pruefung
- Login-Sperre war umgehbar: clientKey() vertraute dem Header CF-Connecting-IP. Bei Cloudflare war das sicher (CF ueberschreibt ihn), auf dem eigenen Server nicht: der Ursprungsserver ist auch direkt unter seiner IP erreichbar, dort konnte der Header frei gesetzt und die 5-Versuche-Sperre komplett ausgehebelt werden (nachgewiesen). Jetzt req.ip hinter trust proxy. - Absturzsicherheit: Express 4 faengt Fehler aus async-Handlern nicht ab, eine einzige fehlerhafte Anfrage konnte den ganzen Dienst beenden. wrap() um alle Handler, zentraler Fehler-Handler, unhandledRejection/uncaughtException-Netz. - Sicherheits-Header (X-Content-Type-Options, X-Frame-Options, Referrer-Policy, Permissions-Policy, HSTS) wurden bisher nur ueber die Datei _headers gesetzt, die auf dem eigenen Server wirkungslos ist. Jetzt im Express-Server. - x-powered-by abgeschaltet. - Datenschutzerklaerung/AGB: nannten Cloudflare als Hoster und eine Cloudflare-D1- Datenbank. Jetzt korrekt netcup (Rechenzentrum Nuernberg) als Hoster, Cloudflare als vorgeschaltetes CDN mit Drittlandhinweis. |
||
|
|
61729d4f12 |
Zugangs-Sperre: Code wird nach dem Schliessen des Browsers wieder gefragt
Sitzungs-Cookie ohne maxAge/expires statt 90-Tage-Cookie; zusaetzlich Notbremse von 12 Stunden im signierten Token, falls ein Browser sehr lange offen bleibt. |
||
|
|
9af0698056 | Node.js/Express-Server als Ersatz fuer den Cloudflare gate-worker.js |