Aufgaben, die in der Vergangenheit geplant und nicht erledigt wurden, waren bislang praktisch unsichtbar: nur Aufgaben mit aktiviertem Rolling-Schalter (oder bei global aktiviertem Auto-Rolling) wandern automatisch auf heute (rollOverdueTasks in WeeklyView.tsx) -- alles andere blieb fuer immer auf seinem urspruenglichen Datum stehen, sobald man in der Wochenansicht weitergeklickt hat. - src/lib/weekly/overdue.ts: reine Funktionen getOverdueTasks/groupOverdueByDate (unerledigt, kein Someday, scheduledDate vor heute -- Datumsvergleich als String, damit Uhrzeit/Zeitzone keine Rolle spielen). 10 Unit-Tests. - src/components/OverdueTasksManager.tsx: Dialog, gruppiert nach dem urspruenglich geplanten Tag (aelteste zuerst), Checkbox zum Erledigen, Knopf zum Verschieben auf heute pro Aufgabe, "Alle auf heute verschieben". Nutzt LinkifiedText (v1.128.0) -- Titel mit URLs bleiben auch hier anklickbar. Verschieben/Erledigen laeuft ueber die bestehenden moveTaskToSlot/toggleTask-Pfade, keine neue API. - Neuer Menuepunkt "Ueberfaellig" mit Anzahl-Badge neben "Wiederkehrend" in allen bestehenden Menue-Varianten (linke/obere Randleiste, mobile Leiste, Kopfzeile). Verifiziert nicht nur mit Unit-Tests: lokale Instanz mit Wegwerf-Postgres (Docker) aufgesetzt, drei ueberfaellige Aufgaben geseedet (eine mit URL im Titel), per Playwright eingeloggt -- Badge, Gruppierung und Link-Rendering per Screenshot geprueft. Danach real geklickt: eine Aufgabe per Checkbox erledigt, eine per Knopf auf heute verschoben, die restlichen zwei per Sammelknopf -- alle drei Aenderungen per Datenbankabfrage bestaetigt. Ausserdem: Typecheck, Lint (0 Fehler), 118 Unit-Tests (10 neu), Produktions-Build. v1.129.0 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
42 KiB
Changelog
All notable changes to this project are documented in this file.
[1.129.0] - 2026-09-14
Added
- Neue "Überfällig"-Übersicht für Aufgaben, die in der Vergangenheit geplant und
nicht erledigt wurden. Bislang wandern nur Aufgaben mit aktiviertem Rolling-Schalter
(oder bei global aktiviertem Auto-Rolling) automatisch auf heute — alles andere blieb
für immer auf seinem ursprünglichen Datum stehen und verschwand aus dem Blick, sobald
man in der Wochenansicht weitergeklickt hat.
- Neuer Menüpunkt "Überfällig" mit Anzahl-Badge, direkt neben "Wiederkehrend" in allen bestehenden Menü-Varianten (linke/obere Randleiste, mobile Leiste, Kopfzeile).
- Dialog gruppiert nach dem ursprünglich geplanten Tag (älteste zuerst), pro Aufgabe Checkbox zum Erledigen und ein Knopf zum Verschieben auf heute, dazu "Alle auf heute verschieben".
- Reine Erkennungs-/Gruppierungslogik in
src/lib/weekly/overdue.ts(10 Unit-Tests), Darstellung insrc/components/OverdueTasksManager.tsx— nutztLinkifiedText(v1.128.0), Titel mit URLs bleiben also auch hier anklickbar. - Verschieben/Erledigen läuft über die bestehenden
moveTaskToSlot/toggleTask-Pfade, keine neue API, keine neue Persistenzlogik.
Verifiziert nicht nur mit Unit-Tests: lokale Instanz mit Wegwerf-Postgres (Docker) aufgesetzt, drei überfällige Aufgaben geseedet (eine davon mit URL im Titel), per Playwright eingeloggt und die Übersicht geöffnet — Badge, Gruppierung und Link-Rendering per Screenshot geprüft. Danach real geklickt: eine Aufgabe per Checkbox erledigt, eine per Knopf auf heute verschoben, die restlichen zwei per Sammelknopf — alle drei Änderungen per Datenbankabfrage bestätigt. Zusätzlich: Typecheck, Lint (0 Fehler), 118 Unit-Tests (10 neu), Produktions-Build.
[1.128.0] - 2026-09-14
Fixed
- Eine im Aufgabentitel getippte URL war kein Link, sondern nur Text — ein Klick
darauf hat je nach Ansicht die Aufgabe durchgestrichen (Tagesraster) oder den
Bearbeiten-Modus geöffnet (Kanban/Someday/Liste/Priorität), statt den Link zu öffnen.
Neue reine Erkennungsfunktion
splitTextAndUrls(src/lib/weekly/format.ts, 8 Unit-Tests) zerlegt den Titel in Text- und URL-Abschnitte; die neue KomponenteLinkifiedText(src/components/weekly/LinkifiedText.tsx) rendert URL-Abschnitte als echten Link mitstopPropagation, damit ein Klick darauf ausschließlich den Link öffnet. Eingebaut inGridTaskBlock.tsx,weekly/TaskItem.tsxundPriorityView.tsx— überall dort, wo ein Aufgabentitel als reiner Text stand. Keine Änderung an Daten, API oder dem separatentask.url-Feld.
Verifiziert: Typecheck, Lint (0 Fehler), 108 Unit-Tests (8 neu), Produktions-Build.
[1.127.0] - 2026-09-14
Added
- Aufgaben lassen sich jetzt auch auf Touch-Geräten zwischen Zeitslots verschieben.
Bisher funktionierte das nur am Desktop, weil
WeeklyView.tsxausschließlich natives HTML5-Drag nutzte, das auf Touch-Geräten nicht feuert (siehe v1.126.0). Neuer Long-Press-Mechanismus inGridTaskBlock/WeeklyView.tsx(200 ms Halten, danach Ziehen), technisch dieselbe Zwei-Phasen-Architektur wie der bereits bestehende Touch-Long-Press für „Termin per Ziehen anlegen". Ruft am Ende dasselbehandleDropwie der Desktop-Pfad auf — keine eigene Entscheidungslogik, keine geänderte API-Payload.
Verifiziert nicht nur mit Unit-Tests, sondern gegen eine echte, lokal laufende Instanz
mit eigener Wegwerf-Datenbank: ein per Playwright simulierter Touch-Drag (echte
TouchEvent-Objekte, 200 ms Halten, schrittweise Bewegung, Loslassen) hat eine Aufgabe
tatsächlich auf einen neuen Zeitslot verschoben, in der Datenbank nachgeprüft. Derselbe
Test mit dragTo() (Maus/Desktop) bestätigt, dass der bestehende Pfad unverändert
funktioniert. Zusätzlich: Typecheck, Lint (0 Fehler), 100 Unit-Tests, Produktions-Build.
[1.126.0] - 2026-09-13
Changed
- Erster Refactoring-Schnitt aus
TODO-CODESCENE-FORTSETZUNG-2026-09-12.md: die fachliche Drop-Entscheidung ausWeeklyView.tsxshandleDrop(Ziel-Slot-Suche bei Belegung, Unterschied Subtask-Beförderung/Someday-Verschieben/normales Verschieben) ist jetzt eine reine, isoliert getestete FunktiondecideTaskDropinsrc/lib/weekly/drag-drop.ts.handleDropliest nur noch Eingaben, ruft die Entscheidung auf und führt exakt die bisherigen Seiteneffekte aus (kein geändertesfetch, kein geändertes optimistisches UI-Update, keine geänderte API-Payload). - 15 neue Unit-Tests decken die Entscheidung ab: freier/belegter/geschützter Slot, Drop ohne Slot mit/ohne vorhandene Startzeit, Subtask-Beförderung, Someday-Provider-Vererbung, externe Sync-Bedingung, virtuelle wiederkehrende Instanzen (Server materialisiert sie weiterhin unverändert).
Bekannter, nicht behobener Befund
- Aufgaben lassen sich per Drag-and-Drop zwischen Zeitslots nur auf dem Desktop
verschieben —
WeeklyView.tsxnutzt dafür ausschließlich natives HTML5-Drag (draggable/onDragStart/onDrop), das auf Touch-Geräten nicht feuert. Kein separater Touch-Mechanismus existiert;react-dnd/react-dnd-html5-backendsind installiert, aber nirgends importiert.decideTaskDropkennt "Drag" gar nicht (nur Quelle/Ziel als Daten) und könnte von einem künftigen Touch-Mechanismus unverändert wiederverwendet werden — das Bauen dieses Mechanismus selbst ist ein eigenes Feature-Vorhaben, nicht Teil dieses Refactorings.
Verifiziert: Typecheck, Lint (0 Fehler), 100 Unit-Tests (85 → 100, 15 neu),
Produktions-Build — alle grün. Kein Playwright-E2E-Lauf für Drag-and-Drop (existiert im
Repo bislang nicht, siehe TODO-CODESCENE-FORTSETZUNG-2026-09-12.md).
[1.125.4] - 2026-09-13
Changed
.gitignore:TODO.mdausgeschlossen — persönliche Arbeitsliste, nicht Teil des Repos.
[1.125.3] - 2026-09-12
Fixed
SONAR_TOKEN/SONAR_HOST_URLsind jetzt als GitHub-Secret/-Variable gesetzt (frisches Token vom Besitzer erhalten, gleichzeitig~/.sonar-tokenauf dem Spark wiederhergestellt — der nächtliche lokale Scan lief seit mindestens 09.09. fehl). Der Sonar-Schritt im Workflow authentifiziert jetzt erfolgreich, scheiterte im ersten echten Testlauf aber an einem neuen, unabhängigen Problem: der Standard-Node-Heap der JS/TS-Analyse-Bridge (~2,2 GB) reicht auf dem GitHub-Hosted-Runner für dieses Repo nicht — dieselbe Fehlerklasse wie dernext build-OOM-Absturz von v1.119.3/v1.119.4. Behoben mit-Dsonar.javascript.node.maxspace=4096.
[1.125.2] - 2026-09-12
Fixed
- v1.125.1s
if: ${{ secrets.SONAR_TOKEN != '' }}machte den Workflow bei GitHub selbst ungültig (0-Sekunden-Fehlschlag ohne Job-Log, "likely failed because of a workflow file issue") — live im Actions-Lauf verifiziert, nicht nur vermutet. Ersetzt durch reinescontinue-on-error: trueauf dem Sonar-Schritt, ohne Bedingung. Erreicht dasselbe Ziel (fehlendes Secret reißt den Workflow nicht mit runter) ohne den ungültigen Ausdruck.
[1.125.1] - 2026-09-12
Fixed
.github/workflows/sonarqube.ymlwar seit dem 02.09. dauerhaft rot — nicht mehr wegen Typecheck/Lint (die sind seit Block C1 grün), sondern weilSONAR_TOKENals Repo-Secret nie gesetzt wurde. Der Sonar-Schritt läuft jetzt nur noch, wenn das Secret existiert, und ist zusätzlichcontinue-on-error, damit ein nicht erreichbarer selbst gehosteter SonarQube-Server nicht den ganzen Workflow mit runterreißt. Ergänzt: ein Unit-Test-Schritt (npm run test:unit), der bislang trotz des Workflow-Namens „Test and SonarQube" komplett fehlte.- Der lokale nächtliche SonarQube-Scan auf dem Spark lief seit mindestens dem 09.09.
jede Nacht fehl (
ERROR: no readable token at ~/.sonar-token— die Datei war schlicht weg), unbemerkt mangels Alarmierung. Kein Code-Fix hierfür möglich: braucht ein frisches Sonar-Token vom Besitzer (Login unter https://sq.martin-bierschenk.de), um sowohl~/.sonar-tokenauf dem Spark als auch das GitHub-Secret wiederherzustellen.
[1.125.0] - 2026-09-12
Security
- Content-Security-Policy ergänzt, vorerst als
Content-Security-Policy-Report-Only. Blockiert nichts, meldet aber jeden Verstoß an den neuen EndpunktPOST /api/csp-report(loggt überconsole.error/PM2). Die Whitelist ist aus dem tatsächlichen Code abgeleitet:fonts.googleapis.com/fonts.gstatic.comfür zur Laufzeit nachgeladene Schriftarten (FontPicker.tsx,WeeklyView.tsx),'unsafe-inline'für Next.js' App-Router-Hydration und den einendangerouslySetInnerHTML-Block. Kein<iframe>, keine Drittanbieter-Bilder, keine clientseitigen Fetches zu fremden Domains gefunden. Scharf geschaltet wird erst, nachdem ein paar Tage Reports durchgesehen wurden — insbesondere die OAuth-Login-Flows ließen sich hier nicht interaktiv durchklicken.
[1.124.0] - 2026-09-12
CREDENTIAL_ENCRYPTION_KEY wurde vor dem Deploy in der Produktions-.env gesetzt.
Security
- Apple-/Synology-Kalenderpasswörter und OAuth-Tokens werden jetzt verschlüsselt
gespeichert.
CalendarConnection.accessToken/refreshTokenenthielten bei Apple- und Synology-Verbindungen das echte Passwort im Klartext ("email:passwort"). Neue Prisma-Client-Extension (src/lib/prisma.ts) ver-/entschlüsselt diese Felder transparent für alle bestehenden Aufrufstellen (AES-256-GCM,src/lib/credential-crypto.ts). Bestehende Klartextzeilen bleiben lesbar (enc1:-Präfix unterscheidet altes von neuem Format) und werden beim nächsten Schreiben automatisch verschlüsselt — keine Migration, keine erzwungene Neuverbindung nötig.
Erforderlich vor dem Deploy
CREDENTIAL_ENCRYPTION_KEY (32 Byte, base64) muss in der Produktions-.env stehen. Ohne
diese Variable wirft jeder Kalender-Request eine Exception. Erzeugen mit:
node -e "console.log(require('crypto').randomBytes(32).toString('base64'))"
Verifiziert: Typecheck, Lint, 85 Unit-Tests (6 neu für credential-crypto),
Produktions-Build — alle grün, mit einem Test-Schlüssel gebaut.
[1.123.2] - 2026-09-12
Erste drei Punkte aus dem TODO-Block L (Sicherheitsdurchgang vom 12.09.) — sichere, in sich abgeschlossene Änderungen ohne Datenmodell-Migration.
Security
- Kein automatischer
db push --accept-data-loss-Fallback mehr inscripts/update-app.sh. Eine fehlgeschlageneprisma migrate deploybricht das Deployment jetzt sauber ab statt unbeaufsichtigt das Schema zu überschreiben — genau dieser Fallback ist am 11.09. beim Boot-Lauf tatsächlich ausgelöst worden. - 14 API-Routen gaben rohe Fehlermeldungen (
error.message) direkt an den Client zurück (Kalender-Connect/-Sync, Task-Import/-Sync, Someday-Listen, Datenimport). Neuer Helpersrc/lib/api-error.ts(safeErrorMessage): generische Meldung in Produktion, echte Meldung nur noch lokal beim Entwickeln. Volles Logging bleibt unverändert inconsole.error. - SMTP-Zertifikatsprüfung wieder aktiv:
tls: { rejectUnauthorized: false }insrc/lib/email.tsentfernt — stand unbegründet seit dem allerersten Commit der Datei und öffnete Tür für Man-in-the-Middle auf Passwort-Reset-/Verifizierungs-Mails.
Verifiziert: Typecheck, Lint, 79 Unit-Tests, Produktions-Build alle grün.
[1.123.1] - 2026-09-12
Fixed
- Erster Deploy nach dem next@15-Upgrade schlug am Smoke-Test fehl, weil
Next.js den Standalone-Output um einen Ordner tiefer verschachtelt hat als
erwartet:
.next-build/standalone/My-Weekly-ToDo-List/server.jsstatt.next-build/standalone/server.js. Ursache: Next sucht per Lockfile-Suche nach oben einen "Workspace-Root" fuer das File-Tracing und fand dabei eine verwaiste, leerepackage-lock.jsonin/rootauf dem Produktionshost -- hielt/rootfaelschlich fuer die Projektwurzel und spiegelte deren Ordnerstruktur in den Output.scripts/update-app.sherwartet den flachen Pfad fest.outputFileTracingRoot: __dirnameinnext.config.jsverankert die Wurzel jetzt explizit -- unabhaengig davon, was sonst noch im Dateisystem oberhalb des Projekts liegt. - Die laufende App war davon nicht betroffen: der Smoke-Test hat den kaputten Build wie vorgesehen abgefangen, bevor umgeschaltet wurde.
[1.123.0] - 2026-09-12
Security
next14.2.35 → 15.5.24. Patcht mehrere kritische Advisories, darunter zwei unauthentifizierte RCE-Klassen (Windows-Hosts, AVIF-Bildoptimierung — beide auf diesem Linux-Host ohnehin nicht direkt erreichbar, aber jetzt geschlossen) sowie diverse DoS-, SSRF- und Cache-Poisoning-Advisories. 15.5.24 patcht bereits alles, was sonst erst next@16 fordern würde — ein Major-Sprung statt zwei.next-auth4.24.13 → 4.24.15, plus@auth/coreperoverridesauf 0.41.3 erzwungen (next-auth pinnt es sonst exakt auf die verwundbare 0.34.3 — als optionalen Peer, den dieses Projekt nirgends importiert). Behebt einen E-Mail-Normalisierungs-Bypass, einen Absturz bei fehlerhaften Bearer-Headern und eine fehlende Provider-Bindung bei OAuth-State/Nonce/PKCE-Cookies.nodemailer7 → 10 (overrides, da next-auth einen ungenutzten optionalen Peer auf 7.x haelt). Behebt SMTP-Command-Injection, CRLF-Header-Injection, eine SSRF/Arbitrary-File-Read-Luecke ueber denraw-Nachrichtenmodus und eine IDN/Punycode-Domain-Bypass beim Empfaenger-Check.postcss(auch die vonnextselbst intern gebündelte Kopie, peroverrides) auf 8.5.28. Behebt XSS in der CSS-Ausgabe und mehrfache Pfad-Traversal-/ Arbitrary-File-Read-Lücken übersourceMappingURL.- Ungenutztes
@auth/prisma-adapter(v5-Adapter, nirgends importiert — das Projekt nutzt@next-auth/prisma-adapterfür v4) entfernt. npm audit: 24 → 0 gemeldete Schwachstellen.
Fixed
google-auth-librarywar ein undeklarierter, nur übergoogleapistransitiv gehofftes Hoisting verfügbarer Import ingoogle-tasks.ts. Ein frischerpackage-lock.json(Nebeneffekt der obigen Audit-Fixes) hob ihn nicht mehr passend, wodurch zwei strukturell inkompatible Kopien nebeneinander existierten und der Typecheck brach. Jetzt eine direkte Abhängigkeit plusoverrides-Eintrag, damit immer genau eine Instanz installiert wird.nodemailer.Transportergibt es als Namespace-Property seit@types/nodemailer8 nicht mehr —Transporterist jetzt ein benannter Type-Export. Einzige betroffene Stelle:src/lib/email.ts.- Next.js 15: dynamische Routen-Parameter (
{ params }) sind jetzt ein Promise. Einzige betroffene Route:PATCH/DELETEunter/api/calendar/cross-sync/rules/[id].
Verifiziert: Typecheck, Lint und 79 Unit-Tests grün; Produktions-Build erfolgreich; Login-Seite, Sicherheitsheader und die Auth-Middleware (Redirect bei fehlendem Token) im gebauten Standalone-Server manuell geprüft. Kein Playwright-E2E-Lauf, da dafür eine echte Datenbank und OAuth-Zugangsdaten nötig sind.
[1.122.0] - 2026-09-12
Security
- Login-Endpunkt hatte kein Rate-Limit. signup/reset-password/verify-email/
resend-verification waren bereits gedrosselt, der eigentliche Login
(
authorize()insrc/lib/auth.ts) nicht -- ein Bruteforce gegen ein bekanntes Konto lief unbegrenzt durch. Jetzt maximal 8 Versuche pro E-Mail in 15 Minuten, mit eigener Fehlermeldung auf der Login-Seite. - Fehlende Standard-Sicherheitsheader ergaenzt (
X-Content-Type-Options,X-Frame-Options,Referrer-Policy,Permissions-Policy) undX-Powered-By: Next.jsabgeschaltet. Bewusst ohne Content-Security-Policy -- die braucht eine sorgfaeltige Whitelist fuer OAuth, Google Fonts und die FontAwesome-CDN und ist ein eigener Schritt. npm audit fix(ohne--force) eingespielt: 24 auf 10 gemeldete Schwachstellen reduziert, alles ohne Breaking Changes.
Fixed
scripts/update-app.shsetzt jetzt selbstPATH=/usr/local/bin:$PATH. Ein Lauf ohne Login-Shell (z. B.ssh host 'scripts/update-app.sh') fandpm2sonst nicht und brach direkt nach einem erfolgreichen Build beim Neustart ab -- am 12.09. live aufgetreten, siehe Betriebsnotiz.tsconfig.jsonnimmt.next-build/types/**/*.tsmit auf. Next.js traegt diesen Pfad beim Bauen mitNEXT_DIST_DIR=.next-buildautomatisch ein; ohne den committeten Eintrag stand das auf dem Produktionshost als staendige, nie eingecheckte Abweichung ingit status.
Known issues
next(14.2.35) undnext-auth/@auth/core(4.24.x) bleiben mit bekannten kritischen CVEs (u. a. ein E-Mail-Normalisierungs-Bypass in Auth.js und mehrere Next.js-Advisories bis hin zu RCE-Klassen). Der Fix ist ein Major-Upgrade auf next@16 und next-auth v5 -- ein eigenes, sorgfaeltig zu testendes Vorhaben, kein Patch.npm auditzeigt den aktuellen Stand.
[1.121.2] - 2026-09-12
Changed
- Die Spaltenaufteilung sich überlappender Termine im Tagesraster ist aus
WeeklyView.tsxinsrc/lib/weekly/event-layout.tsausgelagert (layoutDaySegments/computeEventOverlapLayout), mit eigenen Tests abgesichert. Erster Schnitt der CodeScene-getriebenen Sanierung; der Algorithmus selbst ist unverändert, kein sichtbares Verhalten geändert.
[1.121.1] - 2026-09-12
Fixed
/api/calendar/apple/syncwar ohne Anmeldung erreichbar und hat beliebige Apple-Zugangsdaten aus dem Request gegen Apple CalDAV geschickt. Die Instanz liess sich damit als Relay zum Durchprobieren fremder Zugangsdaten missbrauchen. Die Route verlangt jetzt dieselbe Session-Prüfung wie/api/calendar/apple/connect.AuthForm.tsxschrieb E-Mail-Adresse und Passwort im Klartext in die Browser-Konsole. Die Debug-Ausgaben sind entfernt.
[1.121.0] - 2026-09-12
Fixed
- Termine über Mitternacht verlängerten den Starttag, statt am Folgetag
weiterzulaufen. Ein Termin von 22:00 bis 02:00 erschien bisher als ein
überlanger Block im Starttag; jetzt wird er an der Tagesgrenze geteilt:
22:00–24:00 am Starttag, 00:00–02:00 am Folgetag — so, wie es Kalender-Apps
zeigen. Die Aufteilungsregel (
splitEventByDayinsrc/lib/weekly/date-utils.ts) ist mit Unit-Tests abgesichert. Klick, Drag und Resize wirken weiterhin auf den ungeteilten Termin; Payloads und API sind unverändert.
[1.120.1] - 2026-09-07
Fixed
- Das Skript übersprang den Build, wenn vorher von Hand
git pullausgeführt wurde. Die Entscheidung hing anHEADvs.origin/main— nach einem manuellen Pull sind beide gleich, und das Skript sah keinen Grund zu bauen, obwohl der vorhandene Build aus einem älteren Commit stammte. Es lieferte weiter den alten Stand aus und meldete dabei „Nothing to do". Massgeblich ist jetzt.next/BUILD_COMMIT: aus welchem Commit der vorhandene Build tatsächlich stammt. - Der Smoke-Test-Server überlebte das Beenden.
( … ) &startet eine Subshell,$!ist deren PID —nodedarin lief als Waise weiter und hielt Port 3999 belegt, womit jeder weitere Deploy am Smoke-Test gescheitert wäre. Mitexecersetztnodedie Subshell,killgreift, und einkill -9fasst nach. Zusätzlich prüft das Skript vorab, ob der Port frei ist, und der ERR-Trap beendet den Server ebenfalls.
Beide Fehler kamen bei einem Testlauf ans Licht, nicht in Produktion.
[1.120.0] - 2026-09-07
Changed
-
Ein fehlgeschlagener Build reisst die laufende App nicht mehr mit.
next buildlief bisher direkt auf.next— also auf dem Verzeichnis, aus dem die laufende Instanz bedient wird. Brach der Build ab, fand PM2server.jsnicht mehr (MODULE_NOT_FOUND) und geriet in eine Neustartschleife; am 07.09. war die Seite deshalb rund eine Stunde unbrauchbar.Der neue Ablauf in
scripts/update-app.sh:- Build nach
.next-build—.nextbleibt dabei unangetastet - Statische Dateien und
.envin den neuen Baum kopieren - Smoke-Test: Der neue Build wird auf Port 3999 gestartet und muss auf
/auth/loginantworten. Ein Build kann durchlaufen und trotzdem nicht starten. - Erst danach umschalten; der alte Stand bleibt als
.next-previousliegen - PM2 neu starten
Scheitert irgendetwas davon, wird
.next-buildweggeräumt und die laufende App bleibt unverändert. Zum Zurückrollen genügtmv .next-previous .nextplus PM2-Neustart. - Build nach
-
next.config.js:distDirkommt jetzt ausNEXT_DIST_DIRund fällt auf.nextzurück.
Beide Fälle sind praktisch getestet: Ein abgebrochener Lauf liess .next samt Markierung
unberührt und räumte .next-build weg; ein erfolgreicher schaltete sauber um, legte
.next-previous an und bestand den Smoke-Test.
[1.119.4] - 2026-09-07
Fixed
- Heap-Limit für den Build von 2048 auf 4096 MB angehoben. Der Wert aus v1.119.3 stammte aus der Zeit, als der Container 3 GB hatte, und war schlicht zu niedrig: Der Build starb punktgenau bei 2045 MB — also an der gesetzten Grenze. Gemessener Bedarf sind rund 2,6 GB.
[1.119.3] - 2026-09-07
Fixed
scripts/update-app.shsetzt beim BuildNODE_OPTIONS="--max-old-space-size=2048". Nodes Standard-Heap richtet sich nach dem Arbeitsspeicher und landet auf dem Produktionscontainer bei rund 1,5 GB — zu wenig fürnext build, der Deploy starb mitFATAL ERROR: Ineffective mark-compacts near heap limit.
Notes
- Gemessen, nicht vermutet: ESLint im Build ist nicht die Ursache. Spitzenspeicher
mit ESLint 2.590 MB, ohne 2.595 MB.
eslint.ignoreDuringBuildsbleibt daher auffalse— eine zwischenzeitliche Rücknahme beruhte auf einer falschen Annahme. - Der Build braucht rund 2,6 GB. Bei 3 GB Container-RAM bleibt das knapp; mehr Speicher
für LXC 202 steht als Block J in
TODO.md.
[1.119.2] - 2026-09-07
Changed
- Die restlichen fünf Fremdkomponenten aus
WeeklyView.tsxliegen jetzt untersrc/components/weekly/:TaskInput,SomedayAddTask,TaskItem(mit über 900 Zeilen die grösste),ListVisualsPopoverundTabVisualsPopover. - Die Prioritäts-Abzeichen sind nach
weekly/priority-badge.tsxgewandert.GridTaskBlockimportiertegetPriorityBadgeausWeeklyView.tsxund zog sich damit die gesamte Wochenansicht in seinen Abhängigkeitsgraphen;WeeklyViewre-exportiert die Funktion, bestehende Importe bleiben gültig. WeeklyView.tsx: 11.148 → 9.711 Zeilen — erstmals unter 10.000. Gegenüber dem Stand vor dem Audit (11.906) sind das 2.195 Zeilen oder 18 Prozent.
Verifiziert: Typecheck 0 Fehler, npm run build Exit 0, 63 Unit-Tests grün.
[1.119.1] - 2026-09-07
Changed
ProjectIcon,ProjectsSidebarundNotesSidebarliegen jetzt als eigene Dateien untersrc/components/weekly/. Sie standen inWeeklyView.tsx, hatten dort aber bereits eigene Props und nichts mit der Wochenansicht zu tun. Die SymbollisteprojectIconsGlobalist zuProjectIcongewandert, wo sie als einzige gebraucht wird.WeeklyView.tsx: 11.556 → 11.148 Zeilen.
In WeeklyView.tsx stecken insgesamt acht solcher eigenständigen Komponenten mit
zusammen rund 1.870 Zeilen — fünf davon warten noch (siehe TODO.md D1).
Verifiziert: Typecheck 0 Fehler, npm run build Exit 0, 63 Unit-Tests grün.
[1.119.0] - 2026-09-07
Changed
- Der laufende Tag ist jetzt auch im Spaltenkopf hervorgehoben, nicht mehr nur im
Spaltenkörper. Der Kopf ist
position: stickyund deckte mit--weekly-bgab, weshalb die Färbung erst unterhalb von Wochentag und Datum begann. - Die Symbole in Kalenderterminen (Wiederholung, Anbieter) sitzen jetzt oben rechts statt
unten rechts. Titel und Uhrzeit bekommen dort Freiraum, damit sich nichts überlappt —
über
:has(.event-icons-row)nur bei Terminen, die überhaupt Symbole zeigen. Umgesetzt für beide Darstellungen: Zeitraster und Liste.
[1.118.2] - 2026-09-07
Fixed
- Kein
@ts-nocheckmehr im Projekt. Drei Dateien hatten die Typprüfung komplett abgeschaltet und blieben deshalb auch vonignoreBuildErrors: falseunberührt:calendar-cache.tsbrauchte die Ausnahme überhaupt nicht — ohne sie: null Fehler.microsoft-todo.ts: vier Fälle zirkulärer Typinferenz (url→data→response→url), aufgelöst durch explizite Annotationen.outlook-calendar.ts: Hinter der Ausnahme steckte ein möglicher Laufzeitfehler. Der Code streuteresponse!-Assertions, eine Stelle war vergessen. Statt einer weiteren Assertion prüft der Code jetzt echt, ob nach den drei Wiederholversuchen überhaupt eine Antwort vorliegt.
Added
TODO.md: Block I mit zwei UI-Wünschen — Hervorhebung des aktuellen Tages auch im Spaltenkopf, und die Symbole in Kalenderterminen nach oben rechts. Beide mit den konkreten Fundstellen inglobals.css.
[1.118.1] - 2026-09-07
Fixed
- Der Build prüft wieder Typen.
typescript.ignoreBuildErrorssteht auffalse. Damit ist ein erfolgreicher Build endlich wieder ein Beleg dafür, dass der Code übersetzbar ist — bisher war er es nicht. - Notion-Anbindung war defekt. Der Code rief
notion.databases.query()auf; in@notionhq/clientv5 gibt es diese Methode nicht mehr, der Aufruf lief zur Laufzeit in ein "is not a function". Umgestellt aufdataSources.query(), die Suche filtert jetzt aufdata_source. Ungetestet (kein Notion-Zugang), und gespeicherte Verbindungen enthalten altedatabase_ids — betroffene Nutzer müssen Notion neu verbinden. WeeklyView.tsximportierteisAllDayEventweiterhin ausformat, obwohl die Funktion in v1.118.0 nachdate-utilsgewandert war. Wäre zur Laufzeit gescheitert.- Export-Helfer (
EXPORT_FIELDS,isoWeek,weekLabel,csvCell…) liegen jetzt insrc/lib/export-fields.ts. Next.js erlaubt in einerroute.tsnur Route-Handler als Exporte; zudem importierteSettingsSidebarsie direkt aus der Route und zog damit einen Server-Handler in den Client-Graphen. push-notifications.ts:applicationServerKeybraucht seit TypeScript 5.7 einen Cast aufBufferSource.- Typdeklaration für
web-pushinsrc/types/web-push.d.tsergänzt — als lokale Datei statt als Abhängigkeit, weilnpm installim Projektordner nicht läuft.
Changed
tsconfig.json:includevon**/*aufsrc/**/*eingegrenzt. Das war die Ursache dafür, dass der Typecheck über 30 Minuten lief — nicht die Größe vonWeeklyView.tsx, wie zuvor vermutet. Der vollständige Lauf dauert jetzt 19 Sekunden.
[1.118.0] - 2026-09-07
Added
- 63 Unit-Tests in
tests/unit/für die ausgelagerten reinen Funktionen. Sie laufen in rund 170 ms über Nodes eingebauten Test-Runner — ohne Browser, ohne Datenbank, ohne neue Abhängigkeit.npm testführt sie aus,npm run test:e2estartet weiterhin Playwright. Geprüft werden ISO-Kalenderwochen, Wochenstart-Berechnung, das Zeitraster, die 12/24-Stunden-Anzeige, der Round-Trip zwischenformatDateToISOundparseCalendarDatesowie Farbinvertierung und Spaltenbegrenzung.
Fixed
isAllDayEventriefparseCalendarDateauf, ohne es zu importieren — beim Auslagern ausWeeklyView.tsxin v1.117.7 übersehen. Der Build meldete nichts, weiltypescript.ignoreBuildErrorsnoch aktiv ist; zur Laufzeit hätte der erste ganztägige Termin mit Uhrzeit einenReferenceErrorausgelöst. Die Funktion liegt jetzt indate-utils.ts, wo sie thematisch hingehört.resolveViewDaysnutzteclampViewDaysohne Import — derselbe Fehler beim selben Schnitt.clampViewDaysundMAX_VIEW_DAYSsind nachdevice-settings.tsgewandert;DaysSelectorre-exportiert sie, bestehende Importe bleiben gültig.
Beide Fehler sind genau die Sorte, die typescript.ignoreBuildErrors verdeckt — und beide
wären von den neuen Tests sofort gefunden worden.
[1.117.7] - 2026-09-07
Changed
- Geräteabhängige Einstellungen nach
src/lib/weekly/device-settings.ts(Cookie-Helfer und die vier Schlüssellisten, die bewusst nur im Cookie und nicht in der Datenbank landen). - Darstellungs-Helfer nach
src/lib/weekly/format.ts(stripHtml,invertColor,isAllDayEvent,getSomedaySlotCount). WeeklyView.tsx: 11.655 → 11.556 Zeilen. Mitnpm run buildverifiziert (Exit 0).
Damit sind die reinen Funktionen ohne Komponenten-State heraus — insgesamt 11.906 → 11.556 Zeilen (rund 3 %). Der Rest ist die Komponente selbst und braucht echtes Props-Design statt Verschieben.
[1.117.6] - 2026-09-07
Changed
- Datums-, Wochen- und Zeitraster-Helfer nach
src/lib/weekly/date-utils.tsverschoben (13 reine Funktionen ohne Komponenten-State:getStartOfWeek,getDayName,getTimeSlots,formatHour,getWeekNumber,formatCustomHeaderund weitere).WeeklyView.tsx: 11.830 → 11.655 Zeilen. Mitnpm run buildverifiziert (Exit 0).
Notes
getWeekNumberexistiert im Projekt dreimal — hier, inWeekPrintModal.tsxund inapp/api/user/export-week-view/route.ts. Die Duplikate zu ersetzen steht in TODO.md; vorher müssen die drei Implementierungen auf Gleichheit geprüft werden.
[1.117.5] - 2026-09-07
Changed
- Die gemeinsamen Datentypen der Wochenansicht liegen jetzt in
src/lib/weekly/types.ts(Task,CalendarEvent,SomedayList,ViewStyle,KanbanStage,CellDuration,RecurringTaskException).SettingsSidebarundGridTaskBlockimportierten sie bisher ausWeeklyView.tsxund zogen sich damit die gesamte 11.900-Zeilen-Komponente in ihren Abhängigkeitsgraphen.WeeklyView.tsxre-exportiert die Typen weiterhin, bestehende Importe funktionieren also unverändert. - Erster Schritt der Aufteilung von
WeeklyView.tsx: 11.906 → 11.830 Zeilen. Mitnpm run buildverifiziert (Exit 0, 36 Seiten,/tasksunverändert bei 265 kB).
[1.117.4] - 2026-09-07
Fixed
- Der Build meldet wieder ESLint-Fehler:
eslint.ignoreDuringBuildssteht auffalse. Es waren nur zwei echte Errors im gesamten Projekt (let jsonstattconst jsoninSettingsSidebar.tsx), beide behoben.next lintendet jetzt mit Exit 0. Die 695 Warnungen — 470-malno-explicit-any, 209 ungenutzte Variablen, 11 unvollständige Hook-Abhängigkeiten — blockieren den Build nicht und werden fortlaufend abgebaut.
[1.117.3] - 2026-09-06
Security
.env.production.saveund.env.localaus dem Arbeitsverzeichnis gelöscht — mitshredüberschrieben, damit die Werte nicht aus freiem Speicher rekonstruierbar bleiben. Beide waren identische Kopien derselben Zugangsdaten.- Klartext-Werte in
deployment-notes.mdundINFRASTRUCTURE_REQUIREMENTS.mddurch Platzhalter ersetzt (je drei Vorkommen: DB-Passwort,NEXTAUTH_SECRET, SMTP-Passwort). Die Dateien bleiben als Dokumentation lesbar. - Damit liegt außerhalb der Git-Historie kein Zugangsdatum mehr im Projekt.
[1.117.2] - 2026-09-06
Security
- Weitere Dateien mit echten Zugangsdaten aus dem Git-Index genommen (lokal bleiben sie
erhalten):
deployment-notes.mdundINFRASTRUCTURE_REQUIREMENTS.md— letztere führt das Datenbank-Passwort sogar unverschleiert als**Password**: …auf. Ebenfalls entfernt:.env.production.save, der ursprüngliche Fund. - Passwort aus
tests/debug/db-connection-test.spec.tsentfernt; dort stand eine vollständige Connection-URL samt echter IP. .gitignoregreift jetzt auf.env*statt auf eine Liste fester Namen. Die alte Regel listete.env.production, weshalb.env.production.savedurchs Raster fiel.
Changed
TODO.md: Die Rotation des Datenbank-Passworts ist in einen neuen Block F verschoben — bewusst zurückgestellt. Die Datenbank hört auf einer privaten LAN-Adresse, und bei selbst gehostetem Supabase steckt dasselbe Passwort an mehreren Stellen, was einen halben Wechsel gefährlich macht. Enthält jetzt einen Prüfbefehl, mit dem sich ohne Klartext-Ausgabe feststellen lässt, ob eines der geleakten Passwörter noch aktiv ist.
[1.117.1] - 2026-09-06
Fixed
docs/secret-rotation.md, Schritt 2: Die Anleitung ging von Supabase Cloud mit Dashboard und "Reset database password"-Knopf aus. Tatsächlich läuft Supabase selbst gehostet per Docker auf einem eigenen LXC (siehescripts/supabase-setup.sh) — es gibt kein Cloud-Dashboard. Korrigiert samt Ports (6543 Pooler, 5432 direkt, 8000 API, 8001 Studio) und dem tatsächlichen Weg überPOSTGRES_PASSWORDplusALTER USER, inklusive Backup-Schritt.
[1.117.0] - 2026-09-06
Security
- Rate-Limiting für alle Auth-Endpunkte:
signup(5/15 Min),resend-verification(3/15 Min),verify-email(10/15 Min) undreset-password(5/15 Min), je Client-IP. Bisher waren sie unbegrenzt aufrufbar — beliebig viele Mails über den eigenen SMTP-Zugang, beliebig viele Rateversuche auf Verifizierungscodes. - Passwort-Reset-Token wird nur noch als SHA-256-Hash gespeichert. Bisher lag er im Klartext in der Datenbank: Lesezugriff auf die DB genügte, um fremde Konten zu übernehmen.
- Tote Mock-Login-Route
src/app/api/auth/login/route.tsentfernt. Sie verglich gegen ein hartcodiertes Fake-Passwort, erzeugte ein bedeutungslosesmock-jwt-token-…und war über die Middleware-Ausnahme für/api/auth/*ohne Anmeldung erreichbar. Kein Login-Bypass, aber sie protokollierte jede probierte E-Mail-Adresse. - Passwort-Reset nutzt jetzt bcrypt-Kosten 12 statt 10 — gleicher Wert wie beim Signup.
Fixed
npm testlief ins Leere: Das Skript riefjestauf, obwohl es weder eine Jest-Config noch einen einzigen Jest-Test gibt. Zeigt jetzt auf Playwright;jest,ts-jestund@types/jestsind entfernt (letzteres kollidiert mit den Playwright-Globals).- Falscher
sonar.projectKeyim GitHub-Workflow — er hätte in ein zweites, leeres SonarQube-Projekt geschrieben statt in das bestehende.
Changed
- Die zwölf Wegwerf-Skripte aus der Fehlersuche (
login-debug,css-debug-test, …) liegen jetzt untertests/debug/und sind pertestIgnoreaus dem normalen Testlauf genommen. Aktiv bleiben die drei echten Testdateien. Erreichbar übernpm run test:debug.
Added
TODO.md: abhakbare Liste aus dem Repository-Audit.docs/secret-rotation.md: Anleitung zum Austausch der Zugangsdaten, ohne dass ein Wert auf dem Bildschirm erscheint.scripts/quality-check.sh: bündeltnpm audit, Typecheck, Lint und den SonarQube-Scan für den nächtlichen Lauf.npm auditfehlte bisher komplett.
[1.116.4] - 2026-09-06
Fixed
- Improved calendar event text contrast while retaining the calendar-colored background.
[1.116.3] - 2026-09-05
Added
- Calendar events can now be reassigned to another editable calendar from the event editor.
- Moving an event updates the source and target calendar caches.
Changed
- Calendar event backgrounds now use the calendar color with a lighter, readable contrast.
- Google event-specific colors no longer override the selected calendar's color.
[1.116.2] - 2026-09-05
Fixed
- The remove action now applies to saved local location suggestions only. OpenStreetMap search results remain available, while removed saved locations are deleted from the user's stored location list.
[1.116.1] - 2026-09-05
Fixed
- Display preferences such as the number of visible days now remain device-specific. Automatic profile saving no longer sends browser-only settings back to the shared account.
- An explicitly selected day count now survives mobile reloads and orientation changes.
- Cancelled or superseded location autocomplete requests no longer update the event form.
- Photon autocomplete requests now have a five-second timeout and input length limit.
[1.116.0] - 2026-09-04
Added
- Added a two-day reminder preset for calendar events.
- Added optional address and business autocomplete using Photon/OpenStreetMap, with debounced server-side search and OpenStreetMap attribution.
- Users can keep their original location text or explicitly select a suggested result.
[1.115.3] - 2026-09-03
Fixed
- Drag & drop in views wider than 7 days: the drop target was keyed by weekday
(
date.getDay()), which is only unique inside a 7-day window. In a 21-day view every column sharing the weekday of the hovered one lit up as a drop target — three mirrored highlights, one per Tuesday. Now keyed by the local date. - Same bug, worse half:
handleDropresolved the target date withvisibleDays.find(d => d.getDay() === dayOfWeek), so dropping a task on the second or third Tuesday of a wide view silently scheduled it on the first Tuesday. The drop now uses the column's own date. Tasks dragged in a >7-day view before this fix may sit on the wrong date. - The inline "click an empty slot to add a task" input had the same weekday key, so clicking one slot opened an input in every column with that weekday.
[1.115.2] - 2026-09-03
Changed
scripts/update-app.shis now the single update path, used both for a manual deploy and for the boot run;my-weekly-todo-update.servicepoints at it. There were two near-identical scripts and they drifted — thenpm cifix from 1.114.1 only ever landed in update-app.sh, so the boot path kept runningnpm install.scripts/boot-update.shis now a shim that calls it, kept only so a not-yet-recopied unit file still works.- The update log moved from
/var/log/app-boot-update.logto/var/log/my-weekly-todo-update.log.
Added
update-app.shskips the rebuild whenHEADalready matchesorigin/mainand.next/standalone/server.jsexists, so a reboot no longer costs a full rebuild. Pass--forceto rebuild anyway.update-app.shtakes aflocksingle-instance lock, so a boot run and a manual run can no longer install into the same tree at once — which is how node_modules ended up in a state npm could not clean up.update-app.shrunsprisma migrate deployandprisma generate(previously only the boot script did), and copies.envinto the standalone output.
Fixed
update-app.shno longer fails at boot trying to restart a PM2 process that does not exist yet. It restarts only when the PM2 daemon is actually running, and otherwise leaves the start topm2-root.service, which is ordered after this unit. It deliberately does not probe withpm2 describe, since any pm2 command spawns a daemon that would race the real service.
[1.115.1] - 2026-09-03
Fixed
scripts/boot-update.sh(the "update on reboot" unit): every command was piped intotee, soset -eonly ever saw tee's exit status. A failednpm installornpm run builddid not stop the script and did not fail the systemd unit — it logged "Boot update finished" and left a half-built tree. Now usesset -euo pipefail, logs through a singleexecredirect, and traps ERR.scripts/boot-update.sh: switched fromnpm installtonpm ci. Same fix update-app.sh got in 1.114.1 —npm installrewrites package-lock.json, leaving the tree dirty so the nextgit pullaborts.scripts/boot-update.sh: body wrapped in a function so bash parses it in one go. The script lives inside the checkout it pulls, sogit pullrewriting it mid-run made bash resume at a stale file offset.scripts/boot-update.sh: setGIT_TERMINAL_PROMPT=0so a git credential prompt fails fast instead of hanging the unit at boot, where there is no tty.scripts/my-weekly-todo-update.service: raisedTimeoutStartSecfrom 300 to 1800.npm ci+prisma generate+next buildtakes far longer than 5 minutes in the container; systemd SIGTERMed the oneshot unit mid-install, which left anode_modulestree npm could no longer remove (ENOTEMPTY: rmdir node_modules/date-fns/isEqual).package-lock.json: version resynced withpackage.json(missed in the 1.115.0 commit).
[1.115.0] - 2026-09-03
Added
- Day columns: a "Custom" option next to the 1/2/3/5/7 presets, where any number of days from 1 to 31 can be typed (e.g. 14, 21, 28). The chosen value shows up as its own chip beside the presets and is available in every place the day count can be set — sidebar, both settings flyouts, the desktop toolbar and the header overflow menu.
Fixed
- Day grid and all-day grid only had CSS for
cols-1/2/3/5/7, so any other day count silently fell back to a 5-column layout. Both grids now derivegrid-template-columnsfrom the actual day count.
[1.114.2] - 2026-09-01
Fixed
- Deploy script: copy
public/and.next/static/into.next/standalone/after the build.next.config.jssetsoutput: 'standalone', and Next.js does not copy those itself. Without the copy every deploy left the old chunk hashes in the standalone tree, so the browser's requests for the new chunks 404'd, React never hydrated, and the app hung on "Loading session..." — while the API kept returning 200, which made it look like an auth problem.
[1.114.1] - 2026-09-01
Added
scripts/update-app.sh: the production deploy script, now version-controlled instead of living only on the server. Hardened withset -euo pipefail(a failedgit pullused to still trigger a rebuild and PM2 restart on unchanged code) and switched fromnpm installtonpm ci(npm install rewrote package-lock.json, leaving the tree dirty so the next pull aborted).
[1.114.0] - 2026-09-01
Added
- Focus Mode: "SKIP" button to move on to the next task of the day without completing the current one. Skipped tasks are remembered until Focus Mode is closed, and the timer resets for each new task. The button is disabled when no other task is left for today.
Changed
- Styling settings: removed the standalone "Element Colors" and "Weekend Colors" sections — those controls now live only in the CSS Variables panel (added there in 1.113.1).
- Styling settings: larger, borderless color swatches and bigger labels in the CSS Variables panel.
[1.113.1] - 2026-07-08
Changed
- CSS Variables panel: added the existing "Today Highlight", "Past Days", "Saturday" and "Sunday" color controls as their own groups (bound to the same profile fields as the standalone Element/Weekend Colors sections, so both stay in sync).
- CSS Variables panel: every row now shows the color swatch before its label.
[1.113.0] - 2026-07-08
Added
- Styling settings: "CSS Variables" panel with a color picker and description for every
customizable color token in
globals.css(base colors, settings sidebar, design token aliases, event colors, all-day chips). - Styling settings: "Custom CSS" textarea to inject a personal stylesheet that loads after the app's default styles and can override any rule.