Commit Graph

122 Commits

Author SHA1 Message Date
d6de7e8f06 fix: Prisma-Import raus aus dem Client-Bundle der Einstellungen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
export-fields.ts importierte prisma auf Modulebene fuer fetchExportData, wurde aber
von der Client-Komponente SettingsSidebar wegen EXPORT_FIELDS mitgezogen -- Oeffnen
der Einstellungen warf "PrismaClient is unable to run in this browser environment".
fetchExportData liegt jetzt in export-data-server.ts, export-fields.ts bleibt frei
von Server-only-Importen.

v1.129.1

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 19:01:02 +02:00
64f0eb73f8 feat: Uebersicht ueberfaelliger Aufgaben
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
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>
2026-09-14 18:01:05 +02:00
7f850bb4e9 fix: URLs im Aufgabentitel als anklickbaren Link darstellen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Eine im Titel getippte URL war bisher reiner Text innerhalb des klickbaren Bereichs
der Aufgabe -- ein Klick darauf hat je nach Ansicht die Aufgabe durchgestrichen
(Tagesraster, GridTaskBlock) oder den Bearbeiten-Modus geoeffnet (Kanban/Someday/
Liste/Prioritaet, weekly/TaskItem.tsx und PriorityView.tsx), statt den Link zu oeffnen.

- src/lib/weekly/format.ts: neue reine Funktion splitTextAndUrls zerlegt einen Titel
  in Text- und URL-Abschnitte (http(s)://, www.-Adressen). Abschliessende Satzzeichen
  (".", ",", ")", ...) bleiben Text, nicht Teil des Links.
- src/components/weekly/LinkifiedText.tsx: rendert diese Abschnitte, URL-Abschnitte als
  echtes <a target="_blank" rel="noopener noreferrer"> mit stopPropagation, damit ein
  Klick ausschliesslich den Link oeffnet und nicht an den umgebenden Klick-Handler
  durchgereicht wird. Kein Titel ohne URL bekommt ein zusaetzliches Wrapper-Element.
- Eingebaut ueberall dort, wo ein Aufgabentitel bislang als reiner Text stand:
  GridTaskBlock.tsx, weekly/TaskItem.tsx, PriorityView.tsx.

Keine Aenderung an Daten, API oder dem separaten task.url-Feld (der eigene "Termin-
Link"-Button in TaskItem.tsx) -- reine Darstellungsaenderung.

8 neue Unit-Tests fuer splitTextAndUrls (Titel ohne URL, nur URL, URL mit Text davor/
danach, www.-Form, Satzzeichen am Ende, Klammern, zwei URLs im selben Titel).

Verifiziert: Typecheck, Lint (0 Fehler), 108 Unit-Tests (8 neu), Produktions-Build.

v1.128.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 14:03:17 +02:00
fba9a5d533 refactor: Drop-Entscheidung aus handleDrop in reine, getestete Funktion ausgelagert
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Erster Schnitt aus TODO-CODESCENE-FORTSETZUNG-2026-09-12.md, nach Owner-Freigabe.

handleDrop (WeeklyView.tsx) vermischte fachliche Drop-Entscheidung (Zielslot bei
Belegung finden, Subtask-Befoerderung vs. Someday-Verschieben vs. normales
Verschieben) mit React-State-Updates und Netzwerkaufrufen. Die Entscheidung ist
jetzt eine reine Funktion decideTaskDrop in src/lib/weekly/drag-drop.ts:

- kennt weder DOM noch React noch Netzwerk, nur Task/Zieltag/Slot als Daten
- kein Import von date-utils.ts: der Aufrufer liefert dayOfWeek/scheduledDate/
  allSlots fertig, damit die Datei nur einen Typ-Import hat (wie date-utils.ts/
  format.ts/event-layout.ts in diesem Ordner) und ohne Next.js-Bundler in
  node:test laeuft
- 15 Charakterisierungstests: freier/belegter/geschuetzter Slot, Drop ohne Slot
  mit/ohne vorhandene Startzeit, Subtask-Befoerderung, Someday-Provider-
  Vererbung (eigener vs. geerbter Provider), externe Sync-Bedingung, virtuelle
  wiederkehrende Instanzen (Server materialisiert sie weiterhin unveraendert
  ueber VIRTUAL_ID_REGEX in api/tasks/route.ts)

handleDrop selbst liest jetzt nur noch Eingaben, ruft decideTaskDrop auf und
fuehrt in einem switch exakt die bisherigen Seiteneffekte aus -- keine
geaenderten fetch-Aufrufe, kein geaendertes optimistisches UI-Update, keine
geaenderte API-Payload.

Wichtiger Nebenbefund, kein Teil dieses Refactorings: Task-Drag-and-Drop
funktioniert nur am Desktop. WeeklyView.tsx nutzt ausschliesslich natives
HTML5-Drag (draggable/onDragStart/onDrop), das auf Touch-Geraeten nicht
feuert. Kein separater Touch-Mechanismus vorhanden; react-dnd/
react-dnd-html5-backend sind installiert, aber nirgends importiert.
decideTaskDrop ist bewusst so geschnitten, dass ein kuenftiger
Touch-Mechanismus sie unveraendert wiederverwenden koennte -- das Bauen dieses
Mechanismus ist ein eigenes Feature-Vorhaben (siehe TODO.md Block M3).

Verifiziert: Typecheck, Lint (0 Fehler), 100 Unit-Tests (85 -> 100, 15 neu),
Produktions-Build -- alle gruen. Kein Playwright-E2E fuer Drag-and-Drop
(existiert im Repo bislang nicht).

v1.126.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 13:54:28 +02:00
158051bb47 feat: Kalender-Zugangsdaten verschluesselt speichern (AES-256-GCM)
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
L1 aus dem TODO-Block Sicherheitsdurchgang: Apple-/Synology-Kalenderpasswoerter lagen
im Klartext in CalendarConnection.accessToken ("email:passwort"). Bei einem
Datenbank-Leak waeren das nicht nur App-Daten, sondern die echten Zugangsdaten der
Nutzer bei Apple bzw. auf ihrem NAS.

- src/lib/credential-crypto.ts: AES-256-GCM, Schluessel aus CREDENTIAL_ENCRYPTION_KEY.
  enc1:-Praefix unterscheidet neu verschluesselte Werte von Alt-Klartext -- Klartext
  bleibt beim Entschluesseln unveraendert lesbar statt zu brechen.
- src/lib/prisma.ts: Prisma-Client-Extension ver-/entschluesselt accessToken/refreshToken
  transparent fuer alle rund ein Dutzend Aufrufstellen (Google/Outlook/Notion-Tokens
  laufen mit, sind ebenso sensibel). Kein Aenderungsbedarf an den Aufrufstellen selbst.
- src/lib/auth.ts: PrismaAdapter braucht einen expliziten Typ-Cast fuer den erweiterten
  Client (kein $on/$use mehr in dessen TS-Form, zur Laufzeit unveraendert).

Bestehende Zeilen brauchen keine Migration: Alt-Klartext bleibt lesbar und wird beim
naechsten Schreiben (Token-Refresh, Neuverbinden) automatisch verschluesselt.

ACHTUNG -- NICHT DEPLOYEN, bevor CREDENTIAL_ENCRYPTION_KEY in der Produktions-.env
steht: ohne den Schluessel wirft jeder Kalender-Request eine Exception. Konnte nicht
selbst gesetzt werden (Remote-Schreibzugriff per SSH von der Sandbox verweigert).

Verifiziert: Typecheck, Lint, 85 Unit-Tests (6 neu), Produktions-Build -- alle gruen,
mit einem Test-Schluessel gebaut.

v1.124.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 16:53:33 +02:00
8f017cb879 fix: Deploy-Skript darf Daten nicht mehr automatisch loeschen, Fehlermeldungen haerten
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Erste drei Punkte aus dem TODO-Block L (Sicherheitsdurchgang vom 12.09.):

- scripts/update-app.sh: kein automatischer "prisma db push --accept-data-loss"-
  Fallback mehr, wenn "migrate deploy" fehlschlaegt. Das lief am 11.09. beim
  Boot-Lauf tatsaechlich unbeaufsichtigt durch. Ein fehlgeschlagenes Migrate
  bricht das Deployment jetzt sauber ab, exakt wie ein fehlgeschlagener Build.
- 14 API-Routen gaben error.message direkt an den Client zurueck (Kalender-
  Connect/-Sync, Task-Import/-Sync, Someday-Listen, Datenimport). Neuer Helper
  src/lib/api-error.ts (safeErrorMessage): generische Meldung in Produktion,
  echte Meldung nur noch lokal. Logging unveraendert in console.error.
- src/lib/email.ts: tls.rejectUnauthorized: false entfernt -- stand seit dem
  allerersten Commit unbegruendet drin, produktiver SMTP-Host (Kasserver) hat
  ein gueltiges Zertifikat.

Verifiziert: Typecheck, Lint, 79 Unit-Tests, Produktions-Build alle gruen.

v1.123.2

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 15:36:00 +02:00
114131f9e4 fix: next/next-auth/nodemailer/postcss auf gepatchte Versionen heben
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Letzter offener Punkt aus dem Sicherheitsdurchgang vor dem Beta-Test: npm audit
meldete 24 Schwachstellen, davon mehrere kritisch in next und next-auth.

- next 14.2.35 -> 15.5.24 (patcht alles, was next@16 sonst erfordert haette --
  ein Major-Sprung statt zwei; next 15 unterstuetzt weiterhin React 18)
- next-auth 4.24.13 -> 4.24.15, @auth/core per overrides auf 0.41.3 erzwungen
  (next-auth pinnt es sonst exakt auf die verwundbare 0.34.3, als ungenutzten
  optionalen Peer)
- nodemailer 7 -> 10 per overrides (next-auth haelt einen ungenutzten optionalen
  Peer auf 7.x)
- postcss auf 8.5.28, auch next's eigene interne Kopie per overrides
- ungenutztes @auth/prisma-adapter entfernt (Projekt nutzt @next-auth/prisma-adapter)

npm audit: 24 -> 0.

Zwei echte Codeaenderungen dafuer noetig:
- Next.js 15: { params } in Routen-Handlern ist jetzt ein Promise. Einzige
  betroffene Route: cross-sync/rules/[id].
- nodemailer.Transporter gibt es seit @types/nodemailer 8 nicht mehr als
  Namespace-Property, nur noch als benannter Type-Export. Einzige Stelle:
  src/lib/email.ts.

Ausserdem google-auth-library als direkte Abhaengigkeit deklariert (vorher nur
ueber googleapis transitiv gehofft) und per overrides auf eine Version gepinnt --
der frische package-lock.json aus den obigen Fixes hob sie sonst nicht mehr
passend, wodurch zwei inkompatible Kopien nebeneinander existierten und der
Typecheck brach.

Verifiziert: Typecheck, Lint, 79 Unit-Tests, Produktions-Build alle gruen.
Login-Seite, Sicherheitsheader und Auth-Middleware manuell im gebauten
Standalone-Server geprueft. Kein Playwright-E2E-Lauf (braucht echte DB/OAuth).

v1.123.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 14:41:52 +02:00
3742ae52c6 fix: Login-Rate-Limit, Sicherheitsheader und Deploy-Skript-PATH nachziehen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
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
85667b68c1 refactor: Spaltenaufteilung ueberlappender Termine aus WeeklyView herausloesen
Erster kleiner Schnitt aus Phase A des CodeScene-Auftrags: die Ueberlappungs-
Berechnung war ein rein funktionaler, aber verschachtelter Block mitten in der
Komponente. Sie liegt jetzt als layoutDaySegments/computeEventOverlapLayout in
src/lib/weekly/event-layout.ts und ist mit node:test abgedeckt (einzelner
Termin, Ueberschneidung, direkte Abfolge, drei gleichzeitige Termine,
Reihenfolgeunabhaengigkeit).

Kein sichtbares Verhalten geaendert; der Algorithmus ist unveraendert
uebernommen. WeeklyView.tsx: 9683 -> 9642 Zeilen.

v1.121.2

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 09:30:29 +02:00
d52e780967 feat: Termine ueber Mitternacht am Tageswechsel teilen
Ein Termin von 22:00 bis 02:00 wurde bisher als ein ueberlanger Block in den
Starttag gezeichnet und hat die Tagesspalte verlaengert. 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 Regel liegt als reine Funktion splitEventByDay in src/lib/weekly/date-utils.ts
und ist mit node:test abgedeckt (Teilung, Mehrtagestermine, Ende exakt um
Mitternacht, Ganztagstermine, ungueltige Zeiten). Die Wochenansicht arbeitet in
Raster und Liste nur noch mit diesen Tagesabschnitten; Klick, Drag und Resize
greifen weiterhin auf den ungeteilten Termin zu, damit Payloads unveraendert
bleiben. Die Slot-Sperre (protectEventTimes) erfasst dadurch auch die
Nachtstunden des Folgetags.

v1.121.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-12 09:25:12 +02:00
53de4017e5 fix: @ts-nocheck aus allen drei Dateien entfernen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Die Dateien schalteten die Typpruefung komplett ab und blieben deshalb auch
von ignoreBuildErrors: false unberuehrt -- eine Luecke im gerade erst
geschlossenen Netz.

- calendar-cache.ts brauchte die Ausnahme gar nicht: ohne sie null Fehler.
- microsoft-todo.ts hatte vier Faelle zirkulaerer Typinferenz
  (url -> data -> response -> url), aufgeloest durch explizite Annotationen.
- outlook-calendar.ts verbarg einen moeglichen Laufzeitfehler: Der Code
  streute response!-Assertions, eine Stelle war vergessen. Statt noch einer
  Assertion prueft er jetzt echt, ob nach drei Wiederholversuchen ueberhaupt
  eine Antwort vorliegt.

Ausserdem Block I in TODO.md: Hervorhebung des aktuellen Tages im
Spaltenkopf und die Symbole in Kalenderterminen nach oben rechts, beide mit
Fundstelle in globals.css.

Verifiziert: Typecheck 0 Fehler, npm run build Exit 0.

v1.118.2

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:59:57 +02:00
db99b486c7 fix: Build prueft wieder Typen -- 7 Fehler behoben, Notion-Anbindung war defekt
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
typescript.ignoreBuildErrors steht jetzt auf false. Ein erfolgreicher Build
ist damit wieder ein Beleg dafuer, dass der Code uebersetzbar ist.

Die Ursache der 30-Minuten-Laufzeit war nicht die Groesse von WeeklyView.tsx,
wie ich vermutet hatte, sondern das include-Muster **/* in tsconfig.json. Auf
src/**/* eingegrenzt laeuft der volle Typecheck in 19 Sekunden.

Die sieben gefundenen Fehler:

- notion-calendar.ts rief notion.databases.query() auf. Die Methode gibt es
  in @notionhq/client v5 nicht mehr -- die Notion-Anbindung war zur Laufzeit
  schlicht kaputt und niemandem aufgefallen. Migriert auf dataSources.query(),
  aber mangels Notion-Zugang ungetestet. Gespeicherte Verbindungen enthalten
  alte database_ids und muessen neu eingerichtet werden.
- WeeklyView.tsx importierte isAllDayEvent noch aus format statt date-utils
  -- mein eigener Fehler aus v1.118.0, der ohne scharfen Typecheck
  durchgerutscht war.
- Export-Helfer lagen in einer route.ts, wo Next.js nur Route-Handler
  erlaubt; SettingsSidebar importierte sie von dort und zog einen
  Server-Handler in den Client-Graphen. Jetzt in src/lib/export-fields.ts.
- push-notifications.ts: BufferSource-Cast fuer applicationServerKey.
- web-push hat keine Typen; lokale Deklaration statt neuer Abhaengigkeit.

Verifiziert: npm run build Exit 0 mit scharfem Typecheck, 63 Unit-Tests gruen.

v1.118.1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:45:03 +02:00
5c5f2a284e feat: 63 Unit-Tests fuer die ausgelagerten Funktionen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Nodes eingebauter Test-Runner mit --experimental-strip-types: keine neue
Abhaengigkeit, keine Browser, keine Datenbank, Laufzeit rund 170 ms.
npm test fuehrt sie aus, npm run test:e2e startet weiterhin Playwright.

Die Tests haben sofort zwei echte Fehler gefunden, die ich beim Auslagern
in v1.117.7 selbst eingebaut hatte:

- isAllDayEvent rief parseCalendarDate ohne Import auf
- resolveViewDays nutzte clampViewDays ohne Import

Beides haette zur Laufzeit einen ReferenceError gegeben. Der Build meldete
nichts, weil typescript.ignoreBuildErrors noch aktiv ist -- genau der Fall,
gegen den C1 laeuft. isAllDayEvent liegt jetzt in date-utils.ts, wo es
thematisch hingehoert; clampViewDays und MAX_VIEW_DAYS in
device-settings.ts, DaysSelector re-exportiert sie.

Geprueft werden ISO-Kalenderwochen gegen bekannte Kalenderdaten, die
Wochenstart-Berechnung inklusive Sonntag-Sonderfall, das Zeitraster, die
12/24-Stunden-Anzeige und der Round-Trip formatDateToISO <-> parseCalendarDate
-- die Bruecke zwischen Datenbank und Anzeige, aus der Ein-Tag-Verschiebungen
entstehen.

Mit npm run build verifiziert (Exit 0).

v1.118.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:19:41 +02:00
cd59c02995 refactor: Geraeteeinstellungen und Formatierungs-Helfer auslagern
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Dritter Schnitt an WeeklyView.tsx (D1):
- src/lib/weekly/device-settings.ts: Cookie-Helfer plus die vier
  Schluessellisten, die bewusst nur im Cookie und nicht in der Datenbank
  gehalten werden
- src/lib/weekly/format.ts: stripHtml, invertColor, isAllDayEvent,
  getSomedaySlotCount

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 (rund 3 %). Der Rest ist die Komponente selbst: JSX und
Handler auf gemeinsamem State. Jeder weitere Schnitt braucht echtes
Props-Design statt Verschieben.

v1.117.7

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:11:31 +02:00
c303e1cf2b refactor: Datums- und Zeitraster-Helfer nach src/lib/weekly/date-utils.ts
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Zweiter Schnitt an WeeklyView.tsx (D1). 13 reine Funktionen ohne
Komponenten-State: getStartOfWeek, getDayName, getTimeSlots, formatHour,
getWeekNumber, formatCustomHeader und weitere.

11.830 -> 11.655 Zeilen. Mit npm run build verifiziert (Exit 0).

Nebenbefund: getWeekNumber existiert im Projekt dreimal -- hier, in
WeekPrintModal.tsx und in api/user/export-week-view/route.ts. Das Ersetzen
der Duplikate steht in TODO.md; vorher gehoeren die drei Implementierungen
auf Gleichheit geprueft.

v1.117.6

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:09:26 +02:00
97cb306853 refactor: Datentypen der Wochenansicht in src/lib/weekly/types.ts
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Erster Schritt der Aufteilung von WeeklyView.tsx (D1). Die sieben gemeinsamen
Typen lagen in der Komponentendatei; SettingsSidebar und GridTaskBlock
importierten sie von dort und zogen sich damit die gesamte
11.900-Zeilen-Komponente in ihren Abhaengigkeitsgraphen.

WeeklyView.tsx re-exportiert die Typen weiterhin, bestehende Importe bleiben
also unveraendert -- kein Anfassen der beiden Importeure noetig.

11.906 -> 11.830 Zeilen. Mit npm run build verifiziert: Exit 0, 36 Seiten
generiert, /tasks unveraendert bei 265 kB.

v1.117.5

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:05:31 +02:00
230a4034e8 feat: rate limiting, token hashing, remove mock login route
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Erste Abarbeitung des Repository-Audits (siehe TODO.md).

Sicherheit:
- Rate-Limiting für alle vier Auth-Endpunkte. Sie waren unbegrenzt aufrufbar,
  also beliebig viele Mails über den eigenen SMTP-Zugang und beliebig viele
  Rateversuche auf Verifizierungscodes.
- Passwort-Reset-Token nur noch als SHA-256-Hash in der Datenbank. Bisher
  Klartext: Lesezugriff auf die DB genuegte zur Kontouebernahme.
- Tote Mock-Login-Route entfernt. Sie verglich gegen ein hartcodiertes
  Fake-Passwort und war ueber die Middleware-Ausnahme fuer /api/auth/*
  ohne Anmeldung erreichbar.
- Passwort-Reset auf bcrypt-Kosten 12, wie beim Signup.

Reparaturen:
- npm test rief jest auf, obwohl es weder Jest-Config noch Jest-Tests gibt.
  Zeigt jetzt auf Playwright; jest/ts-jest/@types/jest entfernt.
- Falscher sonar.projectKey im Workflow.

Verifiziert per tsc gegen die geaenderten Bereiche: keine neuen Typfehler.

v1.117.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 20:01:30 +02:00
24a8185587 feat: assign events to calendars
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
2026-09-05 12:34:46 +02:00
8958df03ce feat: focus-triggered MS To-Do delta sync for near-instant change reflection
Pull-sync now runs on visibilitychange + window focus (in addition to mount
and the slow 15-min safety-net interval), throttled to one call per 5s. The
moment the user returns to the tab the app reconciles, so an Outlook-side
checkbox/star/title change shows up within a second of refocusing the tab
instead of after a 15-minute wait.

To keep this cheap, the Microsoft Graph delta endpoint
(/me/todo/lists/{id}/tasks/delta) is used when we have a stored deltaToken
for a synced list — typically a few hundred bytes per call when nothing
changed. Tokens are persisted on SomedayList.syncDeltaToken (new column,
migration applied) and refreshed each call. On 410 Gone (token expired
>30 days) we fall back to a full fetch and prime a new chain. Delta also
brings remote deletions (@removed) so they propagate locally without
needing a full list scan.

v1.104.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 21:58:00 +02:00
bf2819ce67 fix: clear all cached series rows on recurring delete + render star for any important task
- deleteCachedEvent now removes every cached row that belongs to the same
  recurring series (master id + all "<masterId>::*" instances + rows whose
  recurringEventId matches the master), so deleting "all occurrences" no
  longer leaves orphan rows that resurface on the next read.
- getPriorityBadge: surface the yellow star whenever a task is marked
  important (e.g. a starred Outlook To-Do task pulled in via sync), even
  when the active priority style is Eisenhower / ABCDE / Ivy Lee.

v1.103.1

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 20:08:59 +02:00
42905641cd feat: bidirectional Outlook/MS To-Do sync, busyStatus + star, list-delete dialog
- Outlook recurring delete: also delete the specific instance after the master
  to clean up orphaned first occurrences.
- CachedCalendarEvent gains busyStatus column (migration applied) so showAs
  changes from Outlook flow back into the weekly view.
- Outlook create/update now round-trip the full event (busyStatus, visibility,
  attendees, reminders, recurrence link) via a shared response mapper.
- MS To-Do importance ('high' star) ⇄ local importance flag in pull-sync,
  push-sync, initial import, and local-task POST/PATCH; dueDateTime ⇄
  scheduledDate added to pull-sync.
- Local task PATCH now fires a best-effort push to Outlook/Google/Synology so
  any field change keeps both sides aligned.
- AnyDay list delete dialog now offers Cancel / hide locally / delete on both
  sides; new deleteMsTodoList + deleteGoogleTaskList helpers.

v1.103.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-03 19:53:09 +02:00
a040ba128b Merge branch 'main' into dev
# Conflicts:
#	package.json
#	tsconfig.tsbuildinfo
2026-05-02 01:01:44 +02:00
d3a40e32a0 fix: localise auth emails, repair verify link, recover from expired
Wave-3 user feedback (points 1–3):
- Email templates: extract de/en/fr/es/it copy into emailTemplates.ts
  and pick the user's language. Signup forwards navigator.language and
  the API also respects Accept-Language; resend/reset reuse user.language.
- Verify link: the email button now points at the client page instead of
  the API GET handler, so corporate inbox scanners (M365 Safe Links etc.)
  can no longer pre-fetch and silently consume the one-shot token. The
  client page requires a real click before calling PATCH /api/auth/
  verify-email. The legacy GET handler now just redirects to the client
  page so old in-flight emails keep working.
- Code expired UX: when users land via an expired-link redirect we no
  longer leave them with a blank email field — the page exposes an email
  input so the resend button has something to act on. The verify-email
  redirect also forwards the email param.

Misc: tsconfig migrated to moduleResolution=bundler and dropped
downlevelIteration to clear the TS 7.0 deprecation errors.

v1.101.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 20:09:33 +02:00
ffe2f46c64 feat: flag icons, real timezone picker, multi-timezone display
Wave-2 user feedback (points 4–6):
- Language picker: replace emoji flags (which don't render reliably on
  Windows) with inline-SVG flag components for GB/DE/FR/ES/IT. Used
  in both the Settings localisation tab and the onboarding wizard.
- Timezone: replace the read-only Intl.DateTimeFormat display with a
  real <select> over a curated list of major IANA zones. Each option
  shows "(UTC±hh:mm) CODE — Region" and the list is sorted by current
  offset, then code, then IANA name.
- Multi-timezone: new ExtraTimezonesEditor in the localisation tab lets
  users pin additional zones (stored in user.viewSettings.extraTimezones
  to avoid a migration). The time-grid axis now renders the equivalent
  hour for each pinned zone next to the local label, helpful for
  scheduling across regions.

v1.100.0

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 20:00:53 +02:00
3e19ebe85a fix: security hardening, Prisma singleton, tsconfig cleanup
- tsconfig: remove deprecated downlevelIteration (es2017 has native iterators),
  change moduleResolution from node to bundler
- auth: set allowDangerousEmailAccountLinking=false on all OAuth providers,
  restrict debug mode to development only
- prisma: replace new PrismaClient() with singleton import in 10 API routes
  to prevent connection pool exhaustion
- goal API: validate user-supplied quote URLs to block SSRF (private IPs,
  non-http(s) schemes)
- email: guard DEV verification/reset link console.logs behind NODE_ENV check

v1.98.0
2026-04-20 19:52:47 +02:00
2ec1278b19 feat: quote sources — preset buttons, universal parser, expanded local collection
Goal API (route.ts):
- Now actually uses profile.quoteSourceUrls — tries each user-configured URL
  in order before falling back to ZenQuotes
- Universal JSON parser handles ZenQuotes [{q,a}], Quotable {content,author},
  Forismatic {quoteText,quoteAuthor}, generic {text/quote/body, author/by},
  nested {data:{...}}, and advice-slip {slip:{advice}} formats
- ZenQuotes remains the built-in EN fallback when no user URLs are configured

SettingsSidebar:
- Adds clickable preset-source pill buttons below the "Add source" button:
  ZenQuotes, Stoic Quotes, Quotable, Forismatic (EN), Advice Slip
- Pills show ✓ and are disabled when the URL is already in the list
- Note explains DE/FR/IT/ES are served from the curated local collection

quotes.ts:
- Updated PRESET_QUOTE_SOURCES to match the 5 working English APIs
- +14 French quotes (Marcus Aurelius, Lombardi, Ali, MLK, Picasso, etc.)
- +13 Spanish quotes (Collier, Eliot, Darwin, Voltaire, Ashe, etc.)
- +13 Italian quotes (Collier, Eliot, Ali, MLK, Aurelius, da Vinci, etc.)

v1.84.0
2026-04-05 12:50:46 +02:00
3657fb284f fix: reverse FAB menu order + persist iOS PWA session
- FAB menu items reordered so Task is closest to button (top),
  Search is furthest (bottom)
- auth.ts: session maxAge=30d + updateAge=1d so the JWT cookie is
  written as a persistent cookie (Max-Age header), preventing iOS
  PWA from losing the session when the app is closed/backgrounded

v1.81.5
2026-04-01 20:25:23 +02:00
e800d87235 feat: overhaul header display options with mobile portrait/landscape settings
- Rename options to be clearer:
  - "Vollständiges Datum" → "Heutiges Datum" (always today's date)
  - "Aktueller Tag" → "Selektierter Tag" with custom format input
  - "Benutzerdefiniert" → "Woche Benutzerdefiniert" (week-based tokens)
- Add custom format input for "Selektierter Tag" (headerCurrentDayFormat)
  with tokens: DDDD, DDD, DD, MMMM, MMM, MM, YYYY, WW
- Add separate header display settings for Mobile Portrait and
  Mobile Landscape (mobilePortraitHeaderDisplay, mobileLandscapeHeaderDisplay)
- Move refresh/sync icon to fixed-width slot right of date — date no
  longer shifts when the icon appears or the spinner replaces it
- Add 3 new Prisma fields (db push required on deploy)
- All 5 languages updated (EN, DE, FR, ES, IT)

v1.81.0
2026-03-31 09:14:16 +02:00
033603e899 feat: add "Current Day" header display option
New "Current Day" option in the header display settings shows the
currently visible day formatted as "Mo., 30. März 2026" (weekday +
full date), using the user's locale.

- Available in all views (simple, calendar, list, kanban)
- In kanban view: defaults to "Current Day" when no setting is chosen
- On mobile portrait: existing behavior preserved (always shows current day)
- On mobile landscape: respects the new setting like other options
- No year separator shown (year is already part of the format)
- Added to all 5 languages (EN, DE, FR, ES, IT)

v1.80.4
2026-03-31 08:23:46 +02:00
a5f6edd82d perf: fix stale auto-save bug + extract SettingsSidebar to lazy chunk
- saveSetting: add setProfile(p => ({...p, [key]: value})) so profile
  stays in sync with individual setting changes — prevents auto-save
  from overwriting fresh settings with stale profile object values
- Extract SettingsSidebar (4725 lines) from WeeklyView.tsx into its own
  file; lazy-load with next/dynamic so the ~4500-line settings panel
  is deferred until the user opens settings
- Extract shared constants/helpers to src/lib/:
  fontConstants.ts (AVAILABLE_FONTS, FONT_WEIGHTS, isCustomFont)
  weeklyViewTranslations.ts (translations object, ~1100 lines)
  weeklyViewConstants.ts (WeatherDisplayKey, WEATHER_DISPLAY_DEFAULTS)
- WeeklyView.tsx: 16,209 → 10,364 lines (-36%)

v1.80.0
2026-03-30 22:03:09 +02:00
b8c8e9257a fix: retry individual Apple calendar fetches on network timeout
Batch errors like 'fetch failed' were only retried at the login/client-init
level. Per-calendar fetchCalendarObjects calls had no retry, so a single
transient iCloud network timeout silently dropped all events from that
calendar. Now wraps each fetchCalendarObjects with withRetry(2 retries, 3s/6s).

v1.77.5
2026-03-29 16:29:26 +02:00
620118e6d5 feat: add cross-provider calendar sync tool
Users can now create sync rules to automatically sync events between
any two connected calendar providers (Google, Apple, Outlook, Synology).

- New Prisma models: CalendarSyncRule + CalendarSyncMapping
- Sync engine in src/lib/calendar-cross-sync.ts: fingerprint-based
  change detection, anti-loop protection, one-way and two-way support
- API routes: GET/POST rules, PATCH/DELETE rule by id, POST run
- CalendarSyncRulesPanel component with rule list, add/edit form,
  toggle enable/disable, Sync Now button with result summary
- New "Sync" tab in settings sidebar (between Connections and Account)
- Sync rules run automatically after each forced calendar cache refresh

v1.76.0
2026-03-29 10:58:07 +02:00
d8c30cdb1f fix: double event on recurring create + mobile sticky day bar
- Skip optimistic UI update for new recurring events (causes duplicate
  when force-sync fetches expanded instances with different IDs)
- Mobile sticky day bar: listen on gridRef scroll instead of window
  (time-grid scrolls inside weekly-days-grid, not window)
- Remove broken position:sticky from mobile day headers (CSS sticky
  doesn't work inside CSS grid scroll containers); use fixed overlay only
- Also propagate isRecurring flag in create response for Google/Outlook

v1.75.8

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 09:34:09 +02:00
77e8e87b90 fix: eliminate extra iCloud login during sync - use stored calendars
Apple sync was doing 2 logins per cycle: getAppleCalendars (to get calendar
list for filtering) + getUpcomingEventsBatch (to fetch events). Now uses
stored calendar metadata from DB for filtering, reducing to 1 login total.

Same optimization applied to Synology. Also adds 24:00 end-of-day line
to time grid, and throttles tab-focus sync to max once per 5 minutes.

v1.75.3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 10:58:09 +01:00
f6e158af8f fix: reduce iCloud CalDAV connections to prevent rate limiting
- Apple/Synology: batch fetch events with single client login instead of N separate connections
- Apple: add client cache (5min TTL) to reuse authenticated DAVClient across operations
- Apple: add retry with backoff for transient ConnectTimeoutError/SSL failures
- Increase cache stale threshold from 2min to 15min
- Increase background sync interval from 2min to 15min
- Throttle tab-focus sync to at most once per 5min

v1.75.2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 09:35:25 +01:00
11e7b14c17 fix: add debug logging for Outlook recurring event updates
Log the event ID decomposition, update payload, and Graph API
response status to diagnose why recurring event updates aren't
persisting for Outlook.

v1.74.8

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 14:39:50 +01:00
59778d34fa fix: faster calendar sync - 2min interval, sync on tab focus
- Reduced cache stale threshold from 15 minutes to 2 minutes
- Reduced background sync polling from 15 minutes to 2 minutes
- Added visibilitychange listener: syncs calendars and tasks when
  the user switches back to the tab (catches external edits in
  Apple Calendar, Google Calendar, etc.)

v1.74.7

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 13:28:00 +01:00
08959c6ddb feat: drag-to-create calendar events, fix rolling tasks, fix Outlook recurring
- Drag on empty time slots to create calendar events with pre-filled time range
- Rolling tasks now work per-task without requiring global autoRolling setting
- Add firstDayOfWeek to Outlook weekly recurrence patterns
- Add debug logging for Outlook recurrence creation

v1.72.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 01:56:16 +01:00
131f92bd72 fix: Outlook event timezone offset on create/update responses
Outlook Graph API returns datetimes in the user's timezone without Z suffix
by default. The sync path already requested UTC and appended Z, but
create/update responses did not. This caused the optimistic UI update to
show events 1 hour off until the next sync corrected it.

Fix: add Prefer: outlook.timezone="UTC" header to create/update calls
and normalize response datetimes with Z suffix.

v1.71.3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 00:03:17 +01:00
92593cf616 fix: prevent Prisma connection pool exhaustion in production
Cache PrismaClient globally in ALL environments (was only cached in dev).
Without this, production could create multiple PrismaClient instances,
each with its own connection pool, exhausting the database connections.

v1.71.2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 23:17:29 +01:00
e1e31cef20 fix: use updateCalendarObject instead of updateObject for CalDAV updates
iCloud returned 501 Not Implemented for updateObject calls.
Switch to updateCalendarObject which properly sends CalDAV PUT requests.
Fixed in both Apple Calendar and Synology Calendar update + recurring delete paths.

v1.71.1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 22:27:35 +01:00
da2ebbedb5 feat: show location in events, fix HTML in notes, fix CalDAV TZID, reduce collapsed all-day space
- Strip HTML tags from descriptions before sending to CalDAV providers (Apple/Synology)
- Show event location underneath time in calendar event blocks (like Google Calendar)
- Fix German umlaut rendering by adding latin-ext font subset
- Fix CalDAV event updates losing TZID on DTSTART/DTEND (Apple Calendar recurring edit fix)
- Add error logging for CalDAV PUT responses
- Reduce wasted space when all-day events section is collapsed (24px max)
- Fix quotes with missing umlauts (ä, ö, ü, ß)

v1.71.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 22:14:21 +01:00
ff3d458b6d fix: reduce external API calls ~10x by optimizing sync intervals
Root cause: background calendar sync every 2min with forceRefresh:true
+ task sync every 5min + cache stale threshold of 2min = 12,500+
Google Calendar + 8,800 Google Tasks API calls/day for a single user.

Changes:
- Calendar background sync: 2min → 15min
- Task sync polling: 5min → 15min
- Cache stale threshold: 2min → 15min
- Remove forceRefresh:true from background sync (let staleness check
  decide naturally)
- Remove redundant 8s re-fetch after background sync
- User actions (create/update/delete) still sync immediately

Expected reduction: ~10-15x fewer external API calls.

v1.68.1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 12:35:22 +01:00
1e789d93ae feat: cross-day drag, note icon, Google recurring fix, no popup on drag
- Fix Google recurring events missing isRecurring flag (recurringEventId
  was not mapped from Google API response)
- Add note icon (FileText) on events with descriptions, tooltip on hover
- Cross-day drag-and-drop: detect day column under cursor and shift date
- Fix event detail popup opening after drag/resize by setting ref before
  async operations
- Add data-date attribute to day columns for drag target detection
- Use CSS class for icon row layout to prevent overlap

v1.67.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 12:03:33 +01:00
13de53fe0a feat: drag-to-move and resize handles for calendar events
Add resize handles (top/bottom) on hover to change event duration, and
drag-to-move support with live preview and 5-minute snapping. Includes
3px dead zone to distinguish clicks from drags, optimistic UI updates
with server rollback on failure, and recurring/provider icons on
time-grid events. Also fixes Google delete 410 Gone and Outlook delete
404/encodeURIComponent issues.

v1.66.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 11:35:01 +01:00
ba4f1ca280 feat: overlapping calendar events side by side + Outlook delete fix
- Overlapping calendar events on the same time slot are now rendered
  side by side instead of stacked on top of each other. Uses a greedy
  column assignment algorithm to compute layout per day.
- Outlook delete/update: use /me/events/{id} as primary endpoint
  (without encodeURIComponent) instead of calendar-scoped endpoint,
  with fallback. Fixes ErrorItemNotFound for recurring series masters.

v1.65.0

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 11:06:00 +01:00
18c2fc1a92 fix: Outlook update/delete fallback to non-calendar-scoped endpoint
When the calendar-scoped Graph API endpoint returns 404 for series
master or instance IDs, fall back to /me/events/{id} which handles
these cases. Fixes ErrorItemNotFound on delete/update of recurring
Outlook events.

v1.63.5

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 10:51:03 +01:00
c718aa584a fix: respect TZID when updating CalDAV event start/end times
When updating Apple/Synology events that have DTSTART with a TZID
parameter, convert the incoming UTC dateTime to local time in that
timezone before writing back. Prevents ICAL.js from storing UTC
values under a local timezone, which caused +1h shifts on update.

v1.63.4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 10:42:13 +01:00
fb7484c357 fix: CalDAV TZID parsing + recurring event icon on all providers
- Add icalTimeToUtcDate() helper to Apple/Synology parsers that
  correctly converts ICAL.Time with unresolved TZIDs to UTC dates
  (fixes +1h shift on Synology/Apple recurring events across DST)
- Add recurring icon (Repeat) to bottom-right of all calendar event
  blocks when event.isRecurring is true

v1.63.2

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 10:24:38 +01:00
346583fe78 fix: Google recurring event timezone + Outlook DST shift + Outlook delete
- Google: add timeZone to start/end objects when recurrence is present
  (fixes "Missing time zone definition for start time" error)
- Outlook: pass user timezone instead of UTC for event create/update,
  convert UTC dateTime to local representation (fixes +1h DST shift
  on recurring instances)
- Outlook: use instance ID for single-occurrence delete instead of
  series master ID (fixes ErrorItemNotFound on delete)

v1.63.1

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-24 10:16:05 +01:00