My-Weekly-ToDo-List/CHANGELOG.md
mARTin-B78 3742ae52c6
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
fix: Login-Rate-Limit, Sicherheitsheader und Deploy-Skript-PATH nachziehen
Sicherheitsdurchgang vor dem geplanten Beta-Test mit Security-Scannern:

- Login (authorize() in src/lib/auth.ts) hatte als einziger Auth-Endpunkt kein
  Rate-Limit, obwohl signup/reset-password/verify-email/resend-verification es
  bereits nutzen. Jetzt max. 8 Versuche pro E-Mail in 15 Minuten.
- Fehlende Standardheader ergaenzt (X-Content-Type-Options, X-Frame-Options,
  Referrer-Policy, Permissions-Policy), X-Powered-By abgeschaltet. Bewusst
  ohne CSP -- braucht eine eigene, getestete Whitelist fuer OAuth/Fonts/CDN.
- npm audit fix (ohne --force): 24 -> 10 gemeldete Schwachstellen, keine
  Breaking Changes. Die verbleibenden 10 haengen an next@14 und next-auth@4
  (siehe CHANGELOG "Known issues") und brauchen ein eigenes Major-Upgrade.

Ausserdem zwei Betriebsfixes, die beim heutigen Deploy live auffielen:

- scripts/update-app.sh setzt jetzt selbst PATH=/usr/local/bin:$PATH. Ohne
  Login-Shell fand es pm2 nicht und brach nach erfolgreichem Build beim
  Neustart ab -- die Instanz blieb dabei auf dem alten Stand, kein Datenverlust,
  aber ein unnoetiger manueller Eingriff.
- tsconfig.json nimmt .next-build/types/**/*.ts mit auf; Next.js traegt das
  beim Bauen mit NEXT_DIST_DIR=.next-build sonst als nie eingecheckte
  Abweichung auf dem Produktionshost ein.

v1.122.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 10:30:12 +02:00

27 KiB
Raw Blame History

Changelog

All notable changes to this project are documented in this file.

[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() in src/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) und X-Powered-By: Next.js abgeschaltet. 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.sh setzt jetzt selbst PATH=/usr/local/bin:$PATH. Ein Lauf ohne Login-Shell (z. B. ssh host 'scripts/update-app.sh') fand pm2 sonst nicht und brach direkt nach einem erfolgreichen Build beim Neustart ab -- am 12.09. live aufgetreten, siehe Betriebsnotiz.
  • tsconfig.json nimmt .next-build/types/**/*.ts mit auf. Next.js traegt diesen Pfad beim Bauen mit NEXT_DIST_DIR=.next-build automatisch ein; ohne den committeten Eintrag stand das auf dem Produktionshost als staendige, nie eingecheckte Abweichung in git status.

Known issues

  • next (14.2.35) und next-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 audit zeigt den aktuellen Stand.

[1.121.2] - 2026-09-12

Changed

  • Die Spaltenaufteilung sich überlappender Termine im Tagesraster ist aus WeeklyView.tsx in src/lib/weekly/event-layout.ts ausgelagert (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/sync war 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.tsx schrieb 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 (splitEventByDay in src/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 pull ausgeführt wurde. Die Entscheidung hing an HEAD vs. 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 — node darin lief als Waise weiter und hielt Port 3999 belegt, womit jeder weitere Deploy am Smoke-Test gescheitert wäre. Mit exec ersetzt node die Subshell, kill greift, und ein kill -9 fasst 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 build lief bisher direkt auf .next — also auf dem Verzeichnis, aus dem die laufende Instanz bedient wird. Brach der Build ab, fand PM2 server.js nicht 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:

    1. Build nach .next-build — .next bleibt dabei unangetastet
    2. Statische Dateien und .env in den neuen Baum kopieren
    3. Smoke-Test: Der neue Build wird auf Port 3999 gestartet und muss auf /auth/login antworten. Ein Build kann durchlaufen und trotzdem nicht starten.
    4. Erst danach umschalten; der alte Stand bleibt als .next-previous liegen
    5. PM2 neu starten

    Scheitert irgendetwas davon, wird .next-build weggeräumt und die laufende App bleibt unverändert. Zum Zurückrollen genügt mv .next-previous .next plus PM2-Neustart.

  • next.config.js: distDir kommt jetzt aus NEXT_DIST_DIR und fällt auf .next zurü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.sh setzt beim Build NODE_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ür next build, der Deploy starb mit FATAL 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.ignoreDuringBuilds bleibt daher auf false — 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.tsx liegen jetzt unter src/components/weekly/: TaskInput, SomedayAddTask, TaskItem (mit über 900 Zeilen die grösste), ListVisualsPopover und TabVisualsPopover.
  • Die Prioritäts-Abzeichen sind nach weekly/priority-badge.tsx gewandert. GridTaskBlock importierte getPriorityBadge aus WeeklyView.tsx und zog sich damit die gesamte Wochenansicht in seinen Abhängigkeitsgraphen; WeeklyView re-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, ProjectsSidebar und NotesSidebar liegen jetzt als eigene Dateien unter src/components/weekly/. Sie standen in WeeklyView.tsx, hatten dort aber bereits eigene Props und nichts mit der Wochenansicht zu tun. Die Symbolliste projectIconsGlobal ist zu ProjectIcon gewandert, 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: sticky und deckte mit --weekly-bg ab, 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-nocheck mehr im Projekt. Drei Dateien hatten die Typprüfung komplett abgeschaltet und blieben deshalb auch von ignoreBuildErrors: false unberührt:
    • calendar-cache.ts brauchte 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 streute response!-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 in globals.css.

[1.118.1] - 2026-09-07

Fixed

  • Der Build prüft wieder Typen. typescript.ignoreBuildErrors steht auf false. 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/client v5 gibt es diese Methode nicht mehr, der Aufruf lief zur Laufzeit in ein "is not a function". Umgestellt auf dataSources.query(), die Suche filtert jetzt auf data_source. Ungetestet (kein Notion-Zugang), und gespeicherte Verbindungen enthalten alte database_ids — betroffene Nutzer müssen Notion neu verbinden.
  • WeeklyView.tsx importierte isAllDayEvent weiterhin aus format, obwohl die Funktion in v1.118.0 nach date-utils gewandert war. Wäre zur Laufzeit gescheitert.
  • Export-Helfer (EXPORT_FIELDS, isoWeek, weekLabel, csvCell …) liegen jetzt in src/lib/export-fields.ts. Next.js erlaubt in einer route.ts nur Route-Handler als Exporte; zudem importierte SettingsSidebar sie direkt aus der Route und zog damit einen Server-Handler in den Client-Graphen.
  • push-notifications.ts: applicationServerKey braucht seit TypeScript 5.7 einen Cast auf BufferSource.
  • Typdeklaration für web-push in src/types/web-push.d.ts ergänzt — als lokale Datei statt als Abhängigkeit, weil npm install im Projektordner nicht läuft.

Changed

  • tsconfig.json: include von **/* auf src/**/* eingegrenzt. Das war die Ursache dafür, dass der Typecheck über 30 Minuten lief — nicht die Größe von WeeklyView.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 test führt sie aus, npm run test:e2e startet weiterhin Playwright. Geprüft werden ISO-Kalenderwochen, Wochenstart-Berechnung, das Zeitraster, die 12/24-Stunden-Anzeige, der Round-Trip zwischen formatDateToISO und parseCalendarDate sowie Farbinvertierung und Spaltenbegrenzung.

Fixed

  • isAllDayEvent rief parseCalendarDate auf, ohne es zu importieren — beim Auslagern aus WeeklyView.tsx in v1.117.7 übersehen. Der Build meldete nichts, weil typescript.ignoreBuildErrors noch aktiv ist; zur Laufzeit hätte der erste ganztägige Termin mit Uhrzeit einen ReferenceError ausgelöst. Die Funktion liegt jetzt in date-utils.ts, wo sie thematisch hingehört.
  • resolveViewDays nutzte clampViewDays ohne Import — derselbe Fehler beim selben Schnitt. clampViewDays und MAX_VIEW_DAYS sind nach device-settings.ts gewandert; DaysSelector re-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. Mit npm run build verifiziert (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.ts verschoben (13 reine Funktionen ohne Komponenten-State: getStartOfWeek, getDayName, getTimeSlots, formatHour, getWeekNumber, formatCustomHeader und weitere). WeeklyView.tsx: 11.830 → 11.655 Zeilen. Mit npm run build verifiziert (Exit 0).

Notes

  • getWeekNumber existiert im Projekt dreimal — hier, in WeekPrintModal.tsx und in app/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). SettingsSidebar und GridTaskBlock importierten sie bisher aus WeeklyView.tsx und zogen sich damit die gesamte 11.900-Zeilen-Komponente in ihren Abhängigkeitsgraphen. WeeklyView.tsx re-exportiert die Typen weiterhin, bestehende Importe funktionieren also unverändert.
  • Erster Schritt der Aufteilung von WeeklyView.tsx: 11.906 → 11.830 Zeilen. Mit npm run build verifiziert (Exit 0, 36 Seiten, /tasks unverändert bei 265 kB).

[1.117.4] - 2026-09-07

Fixed

  • Der Build meldet wieder ESLint-Fehler: eslint.ignoreDuringBuilds steht auf false. Es waren nur zwei echte Errors im gesamten Projekt (let json statt const json in SettingsSidebar.tsx), beide behoben. next lint endet jetzt mit Exit 0. Die 695 Warnungen — 470-mal no-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.save und .env.local aus dem Arbeitsverzeichnis gelöscht — mit shred überschrieben, damit die Werte nicht aus freiem Speicher rekonstruierbar bleiben. Beide waren identische Kopien derselben Zugangsdaten.
  • Klartext-Werte in deployment-notes.md und INFRASTRUCTURE_REQUIREMENTS.md durch 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.md und INFRASTRUCTURE_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.ts entfernt; dort stand eine vollständige Connection-URL samt echter IP.
  • .gitignore greift jetzt auf .env* statt auf eine Liste fester Namen. Die alte Regel listete .env.production, weshalb .env.production.save durchs 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 (siehe scripts/supabase-setup.sh) — es gibt kein Cloud-Dashboard. Korrigiert samt Ports (6543 Pooler, 5432 direkt, 8000 API, 8001 Studio) und dem tatsächlichen Weg über POSTGRES_PASSWORD plus ALTER 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) und reset-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.ts entfernt. Sie verglich gegen ein hartcodiertes Fake-Passwort, erzeugte ein bedeutungsloses mock-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 test lief ins Leere: Das Skript rief jest auf, obwohl es weder eine Jest-Config noch einen einzigen Jest-Test gibt. Zeigt jetzt auf Playwright; jest, ts-jest und @types/jest sind entfernt (letzteres kollidiert mit den Playwright-Globals).
  • Falscher sonar.projectKey im 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 unter tests/debug/ und sind per testIgnore aus dem normalen Testlauf genommen. Aktiv bleiben die drei echten Testdateien. Erreichbar über npm 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ündelt npm audit, Typecheck, Lint und den SonarQube-Scan für den nächtlichen Lauf. npm audit fehlte 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: handleDrop resolved the target date with visibleDays.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.sh is now the single update path, used both for a manual deploy and for the boot run; my-weekly-todo-update.service points at it. There were two near-identical scripts and they drifted — the npm ci fix from 1.114.1 only ever landed in update-app.sh, so the boot path kept running npm install. scripts/boot-update.sh is 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.log to /var/log/my-weekly-todo-update.log.

Added

  • update-app.sh skips the rebuild when HEAD already matches origin/main and .next/standalone/server.js exists, so a reboot no longer costs a full rebuild. Pass --force to rebuild anyway.
  • update-app.sh takes a flock single-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.sh runs prisma migrate deploy and prisma generate (previously only the boot script did), and copies .env into the standalone output.

Fixed

  • update-app.sh no 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 to pm2-root.service, which is ordered after this unit. It deliberately does not probe with pm2 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 into tee, so set -e only ever saw tee's exit status. A failed npm install or npm run build did not stop the script and did not fail the systemd unit — it logged "Boot update finished" and left a half-built tree. Now uses set -euo pipefail, logs through a single exec redirect, and traps ERR.
  • scripts/boot-update.sh: switched from npm install to npm ci. Same fix update-app.sh got in 1.114.1 — npm install rewrites package-lock.json, leaving the tree dirty so the next git pull aborts.
  • scripts/boot-update.sh: body wrapped in a function so bash parses it in one go. The script lives inside the checkout it pulls, so git pull rewriting it mid-run made bash resume at a stale file offset.
  • scripts/boot-update.sh: set GIT_TERMINAL_PROMPT=0 so a git credential prompt fails fast instead of hanging the unit at boot, where there is no tty.
  • scripts/my-weekly-todo-update.service: raised TimeoutStartSec from 300 to 1800. npm ci + prisma generate + next build takes far longer than 5 minutes in the container; systemd SIGTERMed the oneshot unit mid-install, which left a node_modules tree npm could no longer remove (ENOTEMPTY: rmdir node_modules/date-fns/isEqual).
  • package-lock.json: version resynced with package.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 derive grid-template-columns from 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.js sets output: '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 with set -euo pipefail (a failed git pull used to still trigger a rebuild and PM2 restart on unchanged code) and switched from npm install to npm 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.