Commit Graph

50 Commits

Author SHA1 Message Date
f53ae184ea fix: Kalender-Verbindungen ueber user-include liefern verschluesseltes Token
Some checks failed
Playwright Tests / test (push) Has been cancelled
Test and SonarQube / quality (push) Has been cancelled
Die accessToken/refreshToken-Entschluesselung (Prisma-Extension in lib/prisma.ts)
faengt nur direkte calendarConnection-Queries ab, keine ueber user.findUnique({include})
geladenen Relationen. Outlook-Tokens werden bei jedem Refresh neu geschrieben (also
verschluesselt) und wurden dadurch als Chiffretext an Microsoft Graph geschickt -> 401
"JWT is not well formed". Apple/Synology blieben unbemerkt, weil ihre statischen
App-Passwoerter nie neu geschrieben und damit nie verschluesselt wurden.

Betroffen: calendar/events, calendar/sync, calendar/background-sync,
calendar/connections. Alle vier laden CalendarConnection jetzt direkt statt ueber
user-include.

v1.129.3

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-15 11:48:36 +02:00
e579fc0be8 fix: Kalender-Abfragefenster skaliert mit der eingestellten Tage-Ansicht
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
fetchCalendarEvents holte serverseitig immer nur currentWeekStart -7/+14 Tage, egal
wie breit die Ansicht (bis zu 31 Tage) tatsächlich war. Spalten jenseits von Tag 14
blieben leer, der "all day"-Zaehler zaehlte nur die geladenen Termine. timeMax
skaliert jetzt mit viewDays (max(14, viewDays + 7) Tage vorwaerts), 7-Tage-Standard
unveraendert.

v1.129.2

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 23:27:05 +02:00
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
2042c54b2d feat: Aufgaben per Touch zwischen Zeitslots verschieben (Mobile-Drag-and-Drop)
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
M3 aus TODO.md, nach v1.126.0 als gemeldete Luecke aufgenommen und jetzt geschlossen:
Aufgaben liessen sich bislang nur am Desktop per Maus verschieben, weil WeeklyView.tsx
ausschliesslich natives HTML5-Drag nutzte (draggable/onDragStart/onDrop), das auf
Touch-Geraeten grundsaetzlich nicht feuert.

Neuer Long-Press-Mechanismus, keine neue Dependency:
- GridTaskBlock bekommt onTouchStart/onTouchMove (handleTaskTouchStart/
  handleTaskTouchMovePending) -- 200ms Halten ohne wesentliche Fingerbewegung
  aktiviert den Drag (Vibration als Feedback, wie beim bestehenden Muster)
- Zwei-Phasen-Architektur identisch zum bereits vorhandenen Touch-Long-Press fuer
  "Termin per Ziehen anlegen" (upgradeToDragListeners/handleTouchStart weiter oben in
  derselben Datei): passiver Timer zum Aktivieren, danach ein document-weiter,
  nicht-passiver touchmove-Listener nur waehrend des aktiven Drags (blockiert Scrollen
  nur dann, nicht davor)
- handleDrop akzeptiert jetzt e: DragEvent | null -- der Touch-Pfad ruft dieselbe
  Funktion direkt auf (kein natives DragEvent vorhanden), decideTaskDrop (v1.126.0)
  unveraendert wiederverwendet, keine eigene Entscheidungslogik, keine geaenderte
  API-Payload

Echt verifiziert, nicht nur angenommen: lokale Instanz mit Wegwerf-Postgres (Docker)
aufgesetzt, Testnutzer + Task geseedet, per Playwright ein echter Touch-Drag simuliert
(dispatchte TouchEvent-Objekte, 200ms Halten, schrittweise Bewegung, Loslassen) --
Task landete nachweislich per DB-Abfrage auf dem neuen Zeitslot. Derselbe Aufbau mit
dragTo() bestaetigt: der Desktop-Pfad (Maus) funktioniert unveraendert weiter.

Ausserdem: Typecheck, Lint (0 Fehler), 100 Unit-Tests, Produktions-Build -- alle gruen.

v1.127.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-14 10:22:32 +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
4e3c6087de chore: TODO.md aus dem Repository ausschliessen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Persoenliche Arbeitsliste, kein Projektartefakt.

v1.125.4

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-13 07:55:47 +02:00
6c0bf23104 fix: Node-Heap fuer SonarQube-Analyse-Bridge im GitHub-Actions-Runner erhoehen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Nachdem SONAR_TOKEN als GitHub-Secret gesetzt ist (frisches Token vom Besitzer, siehe
CHANGELOG v1.125.2), authentifiziert der Sonar-Schritt jetzt erfolgreich -- scheiterte im
ersten echten Testlauf aber an einem neuen, unabhaengigen Problem: der Standard-Node-Heap
der JS/TS-Analyse-Bridge (~2,2 GB) reicht auf dem GitHub-Hosted-Runner fuer dieses Repo
nicht ("Node.js process running out of memory"). Dieselbe Fehlerklasse wie der
next-build-OOM-Absturz auf dem Produktionscontainer (v1.119.3/v1.119.4).

-Dsonar.javascript.node.maxspace=4096 ergaenzt.

v1.125.3

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 20:57:58 +02:00
3ac3d135a7 fix: ungueltigen if-Ausdruck im sonarqube.yml-Workflow entfernen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Der vorherige Commit (v1.125.1) fuegte "if: \${{ secrets.SONAR_TOKEN != '' }}" ein, um
den Sonar-Schritt bei fehlendem Secret zu ueberspringen. GitHub selbst lehnte den
Workflow damit komplett ab: 0-Sekunden-Fehlschlag, kein einziger Job-Log, "likely failed
because of a workflow file issue" -- live verifiziert, nicht nur vermutet.

Ersetzt durch reines continue-on-error: true ohne Bedingung auf demselben Schritt.
Erreicht dasselbe Ziel (fehlendes Secret oder nicht erreichbarer Sonar-Server reisst den
Workflow nicht mit runter), ohne den ungueltigen Ausdruck.

v1.125.2

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 18:00:02 +02:00
1eeae2fd5f fix: GitHub-Actions-Workflow nicht mehr dauerhaft rot, Unit-Tests ergaenzt
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
L7 aus dem TODO-Block Sicherheitsdurchgang. .github/workflows/sonarqube.yml war seit dem
02.09. dauerhaft rot -- nicht mehr wegen Typecheck/Lint (die sind seit Block C1 gruen),
sondern weil SONAR_TOKEN als Repo-Secret nie gesetzt wurde.

- Sonar-Schritt laeuft nur noch, wenn das Secret existiert (if: secrets.SONAR_TOKEN != '')
- zusaetzlich continue-on-error, damit ein nicht erreichbarer selbst gehosteter
  SonarQube-Server nicht den Rest des Workflows mitreisst
- Unit-Test-Schritt ergaenzt (npm run test:unit) -- fehlte trotz des Workflow-Namens
  "Test and SonarQube" komplett

playwright.yml bewusst unangetastet gelassen (Nutzerentscheidung).

Nebenbefund, kein Code-Fix moeglich: der lokale naechtliche SonarQube-Scan auf dem Spark
laeuft seit mindestens 09.09. jede Nacht fehl (fehlende ~/.sonar-token). Braucht ein
frisches Token vom Besitzer, um sowohl die lokale Datei als auch das GitHub-Secret
wiederherzustellen.

v1.125.1

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 17:57:28 +02:00
a20cc6dc65 feat: Content-Security-Policy im Report-Only-Modus einfuehren
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
L4 aus dem TODO-Block Sicherheitsdurchgang. Bewusst vorsichtig: die Policy laeuft
zunaechst nur als "Content-Security-Policy-Report-Only" und blockiert nichts, meldet
aber ueber den neuen Endpunkt POST /api/csp-report jeden Verstoss (console.error/PM2).

Whitelist aus dem tatsaechlichen Code abgeleitet, nicht geraten:
- fonts.googleapis.com/fonts.gstatic.com: FontPicker.tsx/WeeklyView.tsx laden
  Nutzer-Schriftarten zur Laufzeit per <link> nach
- 'unsafe-inline' fuer script-src/style-src: Next.js' App-Router-Hydration und der
  eine dangerouslySetInnerHTML-Block in WeeklyView.tsx (View-Transition-Styles)
  brauchen das ohne Nonce-Infrastruktur (eigener, groesserer Umbau)
- Kein <iframe>, keine Drittanbieter-Bilder, keine clientseitigen fetch()-Aufrufe zu
  fremden Domains gefunden. FontAwesome laeuft als React-Komponente im eigenen
  Bundle. OAuth-Redirects sind Top-Level-Navigation, von CSP nicht betroffen.

src/middleware.ts: /api/csp-report von der Login-Pflicht ausgenommen -- der Browser
schickt Reports automatisch, auch von der nicht angemeldeten Login-Seite.

Scharf schalten (Report-Only aus dem Header-Namen entfernen) erst, nachdem ein paar
Tage Reports durchgesehen wurden -- die OAuth-Flows (Google/Microsoft/Apple/Notion)
liessen sich hier nicht interaktiv durchklicken.

Verifiziert: Typecheck, Lint, 85 Unit-Tests, Produktions-Build, Header und
Report-Endpunkt manuell im gebauten Standalone-Server geprueft.

v1.125.0

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 17:43:48 +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
e62294a204 fix: Standalone-Output-Wurzel fest verankern -- Smoke-Test scheiterte nach next@15
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Der erste Deploy nach dem next@15-Upgrade (v1.123.0) brach am Smoke-Test ab:
Next.js hatte den Standalone-Output um einen Ordner tiefer verschachtelt als
scripts/update-app.sh erwartet, weil es per Lockfile-Suche nach oben eine
verwaiste, leere package-lock.json in /root auf dem Produktionshost fand und
/root faelschlich fuer die Projektwurzel hielt.

outputFileTracingRoot: __dirname in next.config.js verankert die Wurzel jetzt
explizit. Die laufende App war nie betroffen -- der Smoke-Test hat den Build
wie vorgesehen abgefangen, bevor umgeschaltet wurde.

Verifiziert lokal mit denselben Env-Variablen wie scripts/update-app.sh
(NEXT_DIST_DIR=.next-build): .next-build/standalone/server.js liegt jetzt an
der erwarteten Stelle. Typecheck, Lint, 79 Unit-Tests weiterhin gruen.

v1.123.1

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 14:56:37 +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
bc41ef340d docs: Changelog für v1.121.0-v1.121.2 nachtragen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
v1.121.3

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 09:34:32 +02:00
dcbcb77dba fix: Build-Erkennung an den gebauten Commit koppeln, Smoke-Server sauber beenden
Some checks failed
Playwright Tests / test (push) Has been cancelled
Test and SonarQube / quality (push) Has been cancelled
Zwei Fehler im neuen Deploy-Weg, beide bei einem Testlauf gefunden.

1. Das Skript uebersprang den Build, wenn vorher von Hand git pull lief.
   Die Entscheidung haengte an HEAD vs. origin/main -- nach einem manuellen
   Pull sind beide gleich, also "Nothing to do", obwohl der vorhandene Build
   aus einem aelteren Commit stammte. Genau das ist beim Deploy von v1.120.0
   passiert: gepullt wurde, gebaut nicht, ausgeliefert blieb 1.119.4.
   Massgeblich ist jetzt .next/BUILD_COMMIT.

   Mein Rat, vor dem Skript git pull auszufuehren, hat den Fall ueberhaupt
   erst ausgeloest -- das Skript pullt selbst.

2. Der Smoke-Test-Server ueberlebte das Beenden. ( ... ) & startet eine
   Subshell, $! ist deren PID; node lief als Waise weiter und hielt Port
   3999 belegt. Jeder weitere Deploy waere daran gescheitert. exec ersetzt
   die Subshell, kill greift, kill -9 fasst nach, der ERR-Trap raeumt
   ebenfalls auf, und vorab wird geprueft ob der Port frei ist.

Beide Szenarien getestet: alter Build wird erkannt und neu gebaut,
gleicher Stand wird uebersprungen, Port bleibt frei.

v1.120.1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 22:41:26 +02:00
162c56d0d3 feat: fehlgeschlagener Build reisst die laufende App nicht mehr mit
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
next build lief 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 mit ueber 790
Versuchen. Am 07.09. war die Seite dadurch rund eine Stunde unbrauchbar.

Neuer Ablauf:
1. Build nach .next-build, .next bleibt unangetastet
2. statische Dateien und .env in den neuen Baum
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, alter Stand bleibt als .next-previous liegen
5. PM2 neu starten

Scheitert etwas davon, raeumt der ERR-Trap .next-build weg und die laufende
App bleibt unveraendert. Die Meldung "die laufende App bleibt unberuehrt"
stimmt damit endlich -- vorher war sie schlicht falsch.

Geprueft wurde vorher, dass der umbenannte Build ueberhaupt startet: der
standalone-Ausgabebaum traegt den distDir-Namen intern, server.js findet
seine Dateien aber relativ zu sich selbst. Testweise gestartet, Login-Seite
und JS-Dateien lieferten 200.

Beide Faelle durchgespielt: Abbruch liess .next samt Markierung unberuehrt
und raeumte .next-build weg; Erfolg schaltete um, legte .next-previous an
und bestand den Smoke-Test.

v1.120.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 22:33:04 +02:00
bea9723a6f fix: Heap-Limit fuer den Build auf 4 GB -- 2 GB waren zu knapp
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Der Wert 2048 aus v1.119.3 stammte aus der Zeit, als der Container 3 GB
hatte. Er war zu niedrig gewaehlt: Der Build starb punktgenau bei 2045 MB,
also an meiner eigenen Grenze. Gemessener Bedarf sind rund 2,6 GB, deshalb
jetzt 4096. Der Container hat inzwischen 6 GB und damit genug Luft.

v1.119.4

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 21:36:50 +02:00
0628ec58ba fix: Build-Speicher auf dem Container -- NODE_OPTIONS statt Rateschluss
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Der Deploy starb mit "Ineffective mark-compacts near heap limit". Nodes
Standard-Heap richtet sich nach dem Arbeitsspeicher und liegt auf dem
Container bei rund 1,5 GB -- zu wenig fuer next build. update-app.sh setzt
jetzt --max-old-space-size=2048.

Ich hatte zuerst ESLint im Build verdaechtigt (mein ignoreDuringBuilds:
false aus v1.117.4) und die Aenderung zurueckgenommen. Eine Messung
widerlegte das: Spitzenspeicher mit ESLint 2.590 MB, ohne 2.595 MB -- kein
Unterschied. Die Ruecknahme ist damit hinfaellig, ESLint bleibt im Build.

Der Build braucht rund 2,6 GB. Bei 3 GB Container-RAM bleibt das knapp;
NODE_OPTIONS ist die Sofortmassnahme, mehr RAM fuer LXC 202 die eigentliche
Loesung. Steht als Block J in TODO.md, zusammen mit der Alternative, den
Build auf den Spark zu verlagern.

v1.119.3

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 19:06:41 +02:00
e8198190fd refactor: restliche fuenf Fremdkomponenten aus WeeklyView.tsx herausloesen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
TaskInput, SomedayAddTask, TaskItem (ueber 900 Zeilen), ListVisualsPopover
und TabVisualsPopover liegen jetzt unter src/components/weekly/. Dazu die
Prioritaets-Abzeichen: GridTaskBlock importierte getPriorityBadge aus
WeeklyView.tsx und zog sich damit die gesamte Wochenansicht in seinen
Abhaengigkeitsgraphen.

WeeklyView.tsx: 11.148 -> 9.711 Zeilen, erstmals unter 10.000. Gegenueber
dem Stand vor dem Audit (11.906) sind das 2.195 Zeilen oder 18 Prozent.

Der Typecheck hat den Schnitt in mehreren 19-Sekunden-Runden gefuehrt und
dabei zwei Dinge gefunden, die sonst erst im Browser aufgeschlagen waeren:
ein doppeltes export-Schluesselwort und -- feiner -- dass DragEvent in
WeeklyView aus React stammt, in den neuen Dateien ohne Import aber das
globale DOM-DragEvent gewesen waere.

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

v1.119.2

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 18:55:54 +02:00
7db4dfbf47 refactor: ProjectIcon, ProjectsSidebar und NotesSidebar in eigene Dateien
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Beim Vermessen der Struktur zeigte sich: In WeeklyView.tsx stecken acht
eigenstaendige Komponenten mit zusammen rund 1.870 Zeilen, die gar nichts
mit der Wochenansicht zu tun haben. Sie haben bereits eigene Props -- der
Schnitt braucht also kein Props-Design, nur die richtigen Importe.

Drei davon sind jetzt heraus, unter src/components/weekly/. Die Symbolliste
projectIconsGlobal ist zu ProjectIcon gewandert, wo sie als einzige
gebraucht wird.

11.556 -> 11.148 Zeilen.

Der scharfe Typecheck aus v1.118.1 hat sich hier zum ersten Mal richtig
ausgezahlt: Er nannte in 19 Sekunden praezise jeden fehlenden Import, in
mehreren schnellen Runden. Vor C1 haette der Build all das stumm
durchgewunken -- und die Fehler waeren erst im Browser aufgeschlagen.

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

v1.119.1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 14:26:08 +02:00
6fe4b69514 feat: Heute-Hervorhebung im Spaltenkopf, Termin-Symbole nach oben rechts
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Zwei UI-Wuensche aus der Wochenansicht (TODO.md Block I).

Der Spaltenkopf ist position: sticky und deckte mit --weekly-bg ab -- die
Hervorhebung des heutigen Tages begann daher erst unterhalb von Wochentag
und Datum. Jetzt faerbt sich der Kopf mit.

Die Symbole sitzen statt unten rechts oben rechts. Damit Titel und Uhrzeit
nicht darunter laufen, bekommen sie rechts Freiraum -- ueber
:has(.event-icons-row) nur dort, wo ueberhaupt Symbole erscheinen. Fuer
beide Darstellungen umgesetzt: Zeitraster und Liste.

Verifiziert: npm run build Exit 0. Das Ergebnis ist rein visuell und daher
nur im Browser wirklich pruefbar.

v1.119.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 14:08:23 +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
4a9b276d3c fix: Build meldet wieder ESLint-Fehler
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
eslint.ignoreDuringBuilds stand auf true, der Build verschluckte also jede
Lint-Meldung. Im gesamten Projekt gab es genau zwei echte Errors -- beide
"let json" statt "const json" in SettingsSidebar.tsx. Behoben, Schalter aus,
next lint endet mit Exit 0.

Die 695 Warnungen (470 no-explicit-any, 209 ungenutzte Variablen, 11
unvollstaendige Hook-Abhaengigkeiten) blockieren den Build nicht. Die
Hook-Warnungen sind davon die interessantesten, weil daraus echte Bugs
entstehen -- stehen als eigener Punkt in TODO.md.

Naechster Schritt ist typescript.ignoreBuildErrors; der volle tsc-Lauf
dauert wegen WeeklyView.tsx ueber 15 Minuten und laeuft noch.

v1.117.4

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 08:57:20 +02:00
391134f36d security: Zugangsdaten aus dem Arbeitsverzeichnis entfernen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
.env.production.save und .env.local geloescht (per shred ueberschrieben) --
beide waren identische Kopien derselben Zugangsdaten. In deployment-notes.md
und INFRASTRUCTURE_REQUIREMENTS.md sind die Klartext-Werte durch Platzhalter
ersetzt, die Dateien bleiben als Dokumentation lesbar.

Ausserhalb der Git-Historie liegt damit kein Zugangsdatum mehr im Projekt.
Das alte NEXTAUTH_SECRET und SMTP_PASSWORD sind laut Nutzer rotiert und
ausser Betrieb; offen bleibt allein der Status des Datenbank-Passworts
(Pruefbefehl in TODO.md Block F).

v1.117.3

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 23:47:53 +02:00
b4e45aca9c security: weitere Dateien mit Zugangsdaten aus dem Git nehmen
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Das Audit hatte nur src/ nach Passwoertern durchsucht -- zu eng. Betroffen
sind vier getrackte Dateien, nicht eine:

- INFRASTRUCTURE_REQUIREMENTS.md fuehrt das DB-Passwort unverschleiert als
  "**Password**: ..." auf, dazu SMTP und NEXTAUTH_SECRET
- deployment-notes.md enthaelt DATABASE_URL und NEXTAUTH_SECRET
- tests/debug/db-connection-test.spec.ts eine Connection-URL samt echter IP
- .env.production.save, der urspruengliche Fund

Die ersten beiden und .env.production.save sind aus dem Index genommen
(lokal bleiben sie), im Testskript ist das Passwort ersetzt. .gitignore
greift jetzt auf .env* statt auf feste Namen -- genau daran war
.env.production.save vorbeigerutscht.

Im Git liegen zwei verschiedene DB-Passwoerter: eines aus dem alten
Docker-Compose-Setup (@db:5432, vermutlich tot), eines aus dem
Supabase-Zugang. Ob letzteres noch aktiv ist, klaert der Pruefbefehl
in TODO.md Block F.

v1.117.2

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 23:32:38 +02:00
f1eeca6ab6 docs: Schritt 2 der Secret-Rotation auf selbst gehostetes Supabase korrigiert
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Die Anleitung beschrieb Supabase Cloud mit Dashboard-Knopf. Tatsaechlich laeuft
Supabase per Docker auf einem eigenen LXC (scripts/supabase-setup.sh), ohne
Cloud-Dashboard. Der Weg geht ueber POSTGRES_PASSWORD in supabase/docker/.env
plus ALTER USER, mit pg_dumpall als Rueckfahrkarte -- das Passwort steckt an
mehreren Stellen, ein halber Wechsel legt die Datenbank lahm.

Ergaenzt um die Ports und eine ehrliche Einordnung: Die Datenbank hoert auf
einer privaten LAN-Adresse, dieser Schritt hat von den dreien die niedrigste
Prioritaet.

v1.117.1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 23:15:14 +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
155c9881bd fix: improve calendar event text contrast
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
Event titles were coloured with color-mix(... 78%, black), which stayed so
close to the event's own colour that it barely separated from the tinted
background. Mixing 30% of the colour into a dark slate keeps the calendar
colour recognisable while making the text properly legible.

v1.116.4

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-06 18:25:12 +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
d3a990270b fix: remove only saved location suggestions
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
2026-09-05 08:32:49 +02:00
3ed7ec9825 fix: keep display settings per device 2026-09-05 08:00:38 +02:00
8c82db037a feat: add OpenStreetMap location autocomplete
Some checks are pending
Playwright Tests / test (push) Waiting to run
Test and SonarQube / quality (push) Waiting to run
2026-09-04 14:19:58 +02:00
d4ec6b0ef3 fix: key drag targets by date, not weekday, in views wider than a week
Some checks are pending
Playwright Tests / test (push) Waiting to run
The drop preview and the empty-slot input were keyed by date.getDay(), which
is only unique inside a 7-day window. At 21 days every column sharing the
hovered column's weekday lit up — the mirrored drop targets, one per Tuesday.

The invisible half was worse: handleDrop resolved its target with
visibleDays.find(d => d.getDay() === dayOfWeek), so dropping on the second or
third Tuesday scheduled the task on the first one. Both now use the column's
own date; handleDragOver/handleDrop take a Date instead of a weekday number.

Task rendering was already date-based, so only drag state was affected.

v1.115.3

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:54:50 +02:00
6f4fe219dc fix: make update-app.sh the single update path and run it at boot
Some checks are pending
Playwright Tests / test (push) Waiting to run
There were two near-identical update 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. my-weekly-todo-update.service now runs update-app.sh, and
boot-update.sh is a shim kept only so a not-yet-recopied unit still works.

To be usable at boot the script needed three things it did not have:

- Skip the rebuild when HEAD already matches origin/main and a standalone
  build exists, so a reboot is not a full rebuild every time (--force
  overrides).
- Do not restart PM2 when its daemon is not up yet. At boot this unit runs
  before pm2-root.service, and probing with `pm2 describe` would spawn a
  stray daemon that races the real service, so it checks the pid file.
- A flock single-instance lock, so a boot run and a manual run cannot install
  into the same tree at once.

It also picks up prisma migrate deploy / generate and the .env copy that only
the boot script had. The log moved to /var/log/my-weekly-todo-update.log.

v1.115.2

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:46:18 +02:00
9d4e40e4e3 fix: make the boot update actually fail loudly and survive long builds
Some checks are pending
Playwright Tests / test (push) Waiting to run
The "update on reboot" unit silently did nothing useful. boot-update.sh piped
every command into tee, so `set -e` only saw tee's exit status: a failed
npm install or build left a half-built tree and still logged "Boot update
finished". It also used npm install (rewrites package-lock.json, so the next
git pull aborts), had no GIT_TERMINAL_PROMPT=0, and was not wrapped in a
function even though git pull rewrites it mid-run.

The unit's TimeoutStartSec=300 was the other half: npm ci + prisma generate +
next build takes far longer than 5 minutes in the container, so systemd
SIGTERMed the oneshot mid-install and left a node_modules tree npm could no
longer remove (ENOTEMPTY on rmdir node_modules/date-fns/isEqual).

Also resyncs package-lock.json with package.json, missed in the 1.115.0 commit.

v1.115.1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 13:27:11 +02:00
224fdba5c6 feat: custom day count for the week view
Some checks are pending
Playwright Tests / test (push) Waiting to run
Add a "Custom" option next to the 1/2/3/5/7 presets where any number of
days from 1 to 31 can be typed. The seven duplicated preset button rows
are replaced by a shared DaysSelector component with panel/header/menu
variants.

The day grid and all-day grid only had CSS for cols-1/2/3/5/7, so any
other count silently fell back to five columns; both now derive
grid-template-columns from the actual day count.

v1.115.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-03 10:14:50 +02:00
2028ba80e0 fix: copy public/ and .next/static/ into standalone output on deploy
Some checks are pending
Playwright Tests / test (push) Waiting to run
next.config.js sets output: 'standalone', but Next.js does not copy public/
or .next/static/ into .next/standalone — that is a documented manual step.
Skipping it shipped new server code referencing new chunk hashes while the
old chunks stayed in the standalone tree, so those requests 404'd, React
never hydrated, and pages hung on "Loading session..." while the API kept
returning 200.

v1.114.2

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-02 13:13:42 +02:00
3338978163 chore: version-control the production deploy script
Moves the deploy script off the server and into the repo as
scripts/update-app.sh, with the two fixes made during the v1.114.0 deploy:

- set -euo pipefail, so a failed git pull aborts instead of rebuilding and
  restarting PM2 on unchanged code while printing "Update Complete"
- npm ci instead of npm install, which rewrote package-lock.json and left the
  tree dirty so the next git pull aborted

The body is wrapped in a main() function because the script lives inside the
checkout it updates, and git pull rewriting it mid-run would leave bash
reading from a stale file offset.

v1.114.1

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 19:03:08 +02:00
7e3e30ec83 feat: add SKIP button to Focus Mode
Focus Mode now shows a SKIP button that moves to the next task of the day
without completing the current one. Skipped task ids are tracked in
WeeklyView and filtered out of the focus queue, so completing a task still
picks the correct next one; the list is cleared when Focus Mode closes.
The timer resets on each new task, and the button is disabled when no other
task is left for today.

Also drops the standalone "Element Colors" and "Weekend Colors" sections from
Styling settings (those controls live in the CSS Variables panel since
1.113.1) and enlarges the CSS variable swatches.

v1.114.0

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-01 17:37:17 +02:00
5510197cf4 fix: add element/weekend color controls to CSS Variables panel, color-first layout
Today Highlight, Past Days, Saturday and Sunday now also appear as their
own groups in the CSS Variables panel, bound to the same profile fields
as the existing Element/Weekend Colors controls so both stay in sync.
Every row now shows the color swatch before its label.

v1.113.1
2026-07-08 20:51:01 +02:00
02b2e40649 feat: add customizable CSS variables and custom CSS to Styling settings
Adds a "CSS Variables" panel to the Styling tab with a color picker and
description for every color token in globals.css (base, sidebar, design
token aliases, event colors, all-day chips), plus a "Custom CSS" textarea
that loads after the default stylesheet and can override any rule.

Overrides are stored per-user (customCssVars, customCss) and applied on
the root container's inline style, so they take precedence over themes
and per-field settings.

v1.113.0
2026-07-08 19:57:21 +02:00