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>
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>
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>
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>
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>
.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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
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
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
After dragging a calendar event to a new time or date, trigger
fetchCalendarEvents on both the old and new date context so the
move is reflected instantly without waiting for the next poll cycle.
Applies to both non-recurring and recurring drag confirms.
v1.112.2
- Calendar icon is now a standalone button to the left of the << < Today > >> cluster
- Uses its own ref (navDatePickerBtnRef) so SimpleDatePicker anchors and
opens directly below the icon instead of at the center date display
- Removed separator inside nav pill (no longer needed)
v1.112.1
- Location field shows dropdown suggestions from previously saved locations
as the user types; selected/submitted locations are persisted to
profile.viewSettings.savedLocations (max 20, most recent first)
- Reminder dropdown gains a "Custom…" option that opens an inline editor
for entering X minutes / hours / days before the event; confirmed custom
values are persisted to profile.viewSettings.customReminderMinutes
(max 10) and appear in future reminder dropdowns
v1.112.0
Changed alignItems from flex-start to center on outer div and span.
Removed manual top/left offsets on checkbox (no longer needed with
center alignment). Icon column uses justifyContent: center.
v1.111.4
- borderLeft now always 4px (transparent when no project/kanban color)
so all tasks have the same left padding (8px) and checkboxes align
- Rolling and provider icons moved from inline text flow to a right-
aligned sibling span in the outer flex row (always at line end)
- paddingRight: 30px when weatherEnabled to prevent temperature overlay
from overlapping task text
v1.111.3
Icon column (14px fixed width) is now always rendered when priority or
project icon settings are enabled, even when a task has no icons.
Each icon slot is a 12×12px centered container so icons are the same
size and horizontally aligned. Increased gap to 2px for breathing room.
v1.111.2
The project assign button and dropdown list now show the project's
actual icon (or faFolder as fallback) instead of a plain circle,
matching the icon rendering used in the task row stacked column.
v1.111.1
Priority icon (top) + project icon (bottom) now rendered in a fixed
leading column before the checkbox, matching the AnyDay area layout.
Provider/sync icon always inline at end (removed absolute fallback).
v1.111.0
- Eye icon now opens a combined vis-display flyout (visibility toggles
+ appearance settings in one panel, with divider)
- History flyout reduced to undo+redo only; Refresh moved back to
standalone rail icon
- Navigation flyout stays open when clicking prev/next day/week
(removed setFlyoutSection(null) from all nav button handlers,
both desktop and mobile)
- Mobile rail mirrors desktop flyout structure (vis-display, history,
nav, refresh standalone)
v1.110.7
- Nav arrows (5 icons) → single ArrowLeftRight flyout with prev/next week/day + today
- Undo/Redo/Refresh/Print (4 icons) → single Undo2 history flyout
- Removed duplicate standalone dark mode toggle (already in Appearance flyout)
- Same flyout sections added to mobile icon rail
- Nav flyout also added to mobile rail
v1.110.6
Was calling setShowSubHourSlots (local state) + saveSetting, but effectiveShowSubHourSlots
reads from profile via getEffective — so the toggle had no visible effect. Fixed all 5
occurrences to use saveViewSetting("showSubHourSlots", ..., true) matching the Settings
sidebar behavior.
v1.110.3
- PanelLeftOpen in header now toggles the icon rail open/close
- Close button in rail uses same PanelLeftOpen icon for visual consistency
- Removed nav arrows (prev/next day/week, today) from rail — available in Quick Settings
- Removed Printer from rail (rarely used on mobile)
- Added SlidersHorizontal (Quick Settings) to bottom of rail
v1.110.2
- PanelLeftOpen in mobile header now opens Quick Settings (left panel)
- Added "Icon Rail" link at bottom of Quick Settings to open the icon sidebar
- Mobile icon sidebar now matches collapsed desktop left rail: View, Columns,
Slot, Plus, Repeat, Goal, Visibility, Appearance flyouts (tap-to-toggle),
Undo, Redo, Refresh, Print, dark mode, Settings, Sign out
v1.110.1
- Someday task edit: add icon/checkbox column spacers before the
textarea so the edit field aligns exactly with the task text column
- Settings tabs: remove outer padding, use space-around + nowrap so all
9 icons fit in a single row without wrapping
- Mobile: left sidebar rail (PanelLeftOpen button) — slides in from
left with nav controls (prev/next day/week, today), actions (search,
calendar jump, projects, focus, quick settings), and bottom controls
(dark mode, settings, sign out). CSS class .mobile-left-sidebar and
.mobile-rail-btn added for easy customization.
v1.110.0
SomedayAddTask now accepts showProjectIcons and showTaskCheckboxes props.
The bottom add-task row renders as a flex layout with matching spacers
for the icon column (18px) and checkbox column (16px), so the input
field left-edge exactly aligns with the task name column. Right-padding
keeps the input from extending into the provider icon column.
v1.109.1
- Completed tasks in someday lists now always render below all active
tasks. Slot system builds from incomplete tasks only; done tasks get
their own section at the bottom outside the droppable slots.
- "Add task..." input right margin increased to 24px so its right edge
stops before the provider icon (G) column, matching task row layout.
v1.109.0
The ANY DAY label/icon div sits at the flex-end of the tab bar but
appeared misaligned with the tab buttons. margin-bottom: 6px brings
it to the correct visual baseline.
v1.108.4
ListVisualsPopover used position:absolute which was clipped by the
weekly-someday-list card's overflow:hidden. Now uses position:fixed
anchored to the card's bounding rect. IconPicker sub-panel also
updated to position:fixed. Stabilized mousedown listener (onCloseRef
pattern, empty deps).
v1.108.3
margin-bottom was -1px but the tab bar border-bottom is 2px thick, so
the active tab only covered half the border. Changed to -2px so the
active tab fully overlaps the bar border. Also cleaned up redundant
CSS properties in the active state rule.
v1.108.2
The ⚡ priority and delegation icons were still rendering inside the
text span (after the checkbox). Now ALL task icons (project, priority,
delegation) are consolidated into the single fixed-width 18px column
before the checkbox for someday tasks. Tasks with no icon get an empty
placeholder so checkboxes and task names stay column-aligned.
v1.108.1
- Fix tab double-click popover not showing: tab bar overflow-x:auto was
clipping the position:absolute popover. Now uses position:fixed anchored
to the button's bounding rect, captured on dblclick. Also stabilizes
the outside-click listener (onCloseRef pattern, empty deps).
- Restructure someday task item order to: [project icon column] [checkbox]
[task name]. Fixed-width 18px icon column (placeholder when no project)
keeps all checkboxes and task names vertically aligned.
v1.108.0