Commit Graph

49 Commits

Author SHA1 Message Date
Ulas 08159ec8b4 feat(meals): customizable meal type visibility in Settings (#14)
Users can now toggle which meal types (breakfast, lunch, dinner, snack)
are displayed in the meal planner via a new Settings section. Preference
is stored household-wide in sync_config and applied as a filter on the
meals page. Includes preferences API, i18n (DE/EN/IT), and Settings UI.
2026-04-04 22:51:57 +02:00
Ulas 0421b540cd feat(tasks): persist view mode and support ?view=kanban URL parameter
View mode (list/kanban) is now saved to localStorage and restored on
page load. URL parameter ?view=kanban takes precedence, enabling tablet
kiosk setups to default to Kanban view. Toggle buttons reflect the
active view correctly on initial render.

Closes #17
2026-04-04 22:34:29 +02:00
Ulas 2c36fa0307 feat(tasks): add optional "none" priority level for tasks without urgency
New tasks default to "none" priority instead of "medium". Tasks with no
priority hide the badge in list and dashboard views, reducing visual noise
for routine items. Includes DB migration v4 and i18n keys (de, en, it).

Closes #15
2026-04-04 22:13:51 +02:00
Ulas 2508473265 fix(pwa): fix UI overlap, scroll bleed and wrong nav height on iOS
Three root causes fixed:

1. Double safe-area padding: pwa.css set padding-top/bottom on body
   globally, but page containers already account for safe-area-inset
   in their height calculations. Removed body vertical padding (kept
   only in standalone media query for padding-top).

2. Wrong nav token: all page containers used --nav-height-mobile (56px)
   instead of --nav-bottom-height (68px = 56px scroll + 12px dots),
   causing 12px of content to render behind the bottom nav.

3. Scroll bleed: fixed-height page containers lacked overflow:hidden,
   allowing scroll events to propagate to the body. Added
   overscroll-behavior-y:contain on app-content globally.

Fixes #16
2026-04-04 22:02:19 +02:00
Ulas 7eb06ed905 fix(modal): replace native prompt() with custom modal dialogs
Native browser prompt() is unreliable on mobile browsers and PWAs,
often requiring multiple clicks to close. Replace all prompt() calls
with custom promptModal() and selectModal() functions that use the
existing modal system with proper focus management and animations.

Affected pages: shopping (create/rename list), tasks (add subtask),
meals (choose shopping list).

Fixes #12
2026-04-04 21:31:50 +02:00
Ulas c93be9049c feat(dashboard): add shopping list widget
Show shopping lists with open items directly on the dashboard.
Each list displays a progress bar, the first few unchecked items,
and a "+N more" overflow indicator. Widget only appears when there
are lists with open items.

Backend: new shoppingLists query in /api/v1/dashboard (up to 3 lists,
6 open items each). Frontend: renderShoppingLists() widget following
existing widget pattern. CSS: compact list/progress/item styles.
i18n: shoppingMore key added to de/en/it.

Requested in discussion #9
2026-04-04 14:30:31 +02:00
Ulas 47b34c4829 fix(modal): add fallback timer for mobile close animation
On mobile, closeModal() relies on the CSS animationend event to call
_doClose(). When the animation does not fire (prefers-reduced-motion,
tab switch, browser quirk), the modal stays stuck and the user cannot
dismiss it. A 300ms fallback timer now guarantees cleanup runs.

Reported in discussion #9
2026-04-04 14:16:00 +02:00
Ulas 597c2602aa fix(i18n): translate category names in tasks and budget displays
Category group headers in tasks and bar chart labels / transaction meta
in budget were showing raw German database keys instead of going through
CATEGORY_LABELS() i18n mapping.

Closes #11
2026-04-04 14:08:41 +02:00
Ulas 6454c1fc9f chore: bump version to v0.7.5 and update changelog 2026-04-04 07:27:42 +02:00
Ulas 1c7b77401d chore: bump version to v0.7.4 and update changelog 2026-04-04 06:51:38 +02:00
Ulas 364d029950 fix(ux): prevent iOS auto-zoom on inputs + lazy-load page CSS
Increase font-size to 16px on mobile for shopping quick-add inputs,
notes search, and contacts search. Desktop breakpoint restores compact
sizes. Move 9 page-specific stylesheets from index.html to on-demand
loading in router.js, reducing initial CSS payload.
2026-04-04 06:39:45 +02:00
Ulas 70c1291ae7 fix(a11y): skip-link target, priority labels, greeting tokens
- Rename #page-content to #main-content so skip-to-content link
  targets the semantic <main> landmark
- Add sr-only priority labels to dashboard task items for screen
  readers (WCAG 1.4.1 color-not-only)
- Replace hardcoded hex in greeting gradient with accent tokens
  so dark mode themes the banner correctly
- Replace hardcoded gap: 2px with --space-0h token
- Bump version to 0.7.2
2026-04-04 06:31:21 +02:00
Ulas 6bc4c46f03 fix(security): eliminate XSS vectors and restore zoom accessibility
- Extract shared esc() utility (public/utils/html.js) replacing 8
  duplicate escHtml() functions across all page modules
- Apply HTML escaping to all user-controlled data in innerHTML
  templates: titles, names, locations, descriptions, colors, notes
  content, weather data, autocomplete suggestions
- Remove user-scalable=no and maximum-scale=1 from viewport meta
  tag, restoring pinch-to-zoom for WCAG 1.4.4 compliance
- Bump version to 0.7.1
2026-04-04 06:25:28 +02:00
Ulas 9b21a72d40 chore: release v0.7.0 - audit remediation
Bump version to 0.7.0 and add CHANGELOG entry covering all
audit findings: bcrypt upgrade, ESM migration, session secret
hardening, structured logging, documentation translations,
and repository cleanup.
2026-04-04 01:22:39 +02:00
Ulas 660a3ffa1c fix(budget): fix category update failing with SQLite binding error
The `date` import from validate.js shadowed the `date` field from
req.body, so SQLite received a function reference instead of a string
when updating a budget entry - causing a TypeError.

Fix by aliasing the import to `validateDate` and adding `date` to
the req.body destructuring.

Closes #8

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 18:28:31 +02:00
Ulas 3d2604bab9 fix(security): address critical and high findings from security audit
Fix stored XSS in tasks (titles/subtasks) and settings (member list)
by applying escHtml(). Harden trust proxy to loopback default, add
OAuth state parameter for Google Calendar CSRF protection, sanitize
CSV export against formula injection, invalidate sessions on user
deletion, restrict usernames to alphanumeric chars, and require admin
role for calendar sync triggers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 17:28:36 +02:00
Ulas 1122bd269b style: replace em dashes with hyphens throughout codebase
Replace all — with - in all source files (JS, CSS, HTML, JSON,
Markdown) for consistency and readability.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:04:39 +02:00
Ulas b1ee4439be feat(i18n): add Italian localization
Add complete Italian translation (497 keys) based on PR #7 by
@albanobattistella. Fixed filename from "it. json" to "it.json" and
registered Italian in SUPPORTED_LOCALES and the locale picker component.

Co-Authored-By: albanobattistella <34811668+albanobattistella@users.noreply.github.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 15:35:08 +02:00
Ulas 678c896862 fix(calendar): expand recurring multi-day events and support YEARLY frequency
Root causes:
1. parseRRule did not strip the "RRULE:" prefix stored by the ICS parser,
   causing all recurrence rules from CalDAV sync to silently fail parsing
2. YEARLY frequency (used by birthday events) was not supported
3. expandRecurringEvents filtered instances only by start date, missing
   multi-day events that start before the view window but span into it
4. All-day recurring instances got datetime end values instead of date-only

Fixes #5 (follow-up from @tschig)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 12:47:18 +02:00
Ulas 261dae5990 fix(calendar): correct all-day DTEND handling, add DURATION support, include birthdays
All-day events showed on the correct day plus the next day because ICS
DTEND for VALUE=DATE is exclusive (RFC 5545) but was treated as inclusive.
Multi-day events using DURATION instead of DTEND were missing entirely.
Birthday calendars were explicitly filtered out during Apple Calendar sync.

Closes #5

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 12:31:29 +02:00
Ulas 2e3c5a9afa docs: replace em dashes with hyphens in public-facing docs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 12:25:47 +02:00
Ulas eafe2b964d fix(sync): resolve iCloud Calendar sync FOREIGN KEY crash and sync all calendars
The Apple Calendar sync hardcoded created_by=1 which fails when no user
with ID 1 exists, causing every single event import to fail silently.
Now dynamically resolves the first available user. Also syncs all
calendars instead of only the first one, adds the missing cfgDel helper,
and gracefully skips unreachable calendars.

Fixes #4

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 12:10:58 +02:00
Ulas cd963540cf fix(db): quote SQLCipher PRAGMA hex key to fix fresh install crash
The hex-encoded encryption key (x'...') is not valid as a bare PRAGMA
value in better-sqlite3. Wrapping it in double quotes produces valid
SQLCipher PRAGMA syntax.

Fixes #3

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 11:43:46 +02:00
Ulas 6e0eda8ba4 fix(security): address multiple security findings from audit
- Fix SQLCipher PRAGMA key interpolation (hex-encode key to prevent crash on single quotes)
- Enforce min password length (8 chars) on admin user creation
- Add length bounds on username/display_name and login inputs
- Invalidate other sessions on password change
- Multi-stage Docker build (exclude build tools from runtime)
- Exclude docs/ from Docker image
- Consolidate dotenv.config() to single entry point
- Document flat family authorization model in SECURITY.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 09:11:17 +02:00
Ulas 58b9d8e0ac chore: repository audit — fix CHANGELOG links, clean .dockerignore
Fix [Unreleased] compare link (v0.5.1→v0.5.2), add missing [0.5.2]
compare link, remove phantom social-preview.html from .dockerignore.
Add full repo audit document.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:25:16 +02:00
Ulas 59791df248 fix: enforce Secure flag on session and CSRF cookies by default
Cookies were sent without Secure flag outside of production (NODE_ENV check).
New logic: secure=true by default; set SESSION_SECURE=false in .env to
allow HTTP explicitly (local dev without reverse proxy). Affects session
cookie, CSRF cookie in login handler, and CSRF middleware.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 18:34:31 +02:00
Ulas 91c2e0ad98 fix: address CodeQL security findings (v0.5.2)
- Rate-limit SPA fallback route (missing rate limiting on fs access)
- Add csrfMiddleware to all state-changing auth routes (logout, create
  user, change password, delete user) — previously bypassed global CSRF
  middleware due to router registration order
- Fix incomplete vCard escaping: escape backslashes before other special
  characters to prevent injection via contact fields
- Restrict CI GITHUB_TOKEN to contents: read (least privilege)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 18:30:03 +02:00
Ulas b9b81a461e chore: release v0.5.1 — update CHANGELOG and package version
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 12:00:37 +02:00
Ulas 3544f4f36c docs: update CHANGELOG [Unreleased] with fixes from this session
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:44:26 +02:00
Ulas c66018ff49 chore: release v0.5.0 — update CHANGELOG, SPEC, and package version 2026-03-31 23:38:38 +02:00
Ulas 9e8338c9b9 chore: release v0.4.0 — update CHANGELOG and SPEC 2026-03-31 15:19:02 +02:00
Ulas ee47d1d370 docs: update changelog for meals/settings CSS fixes 2026-03-31 15:15:25 +02:00
Ulas 3085ad7bbc docs: update changelog for dark-mode module token fix 2026-03-31 15:12:45 +02:00
Ulas 52a2455e43 docs: update changelog for module accent colour feature 2026-03-31 15:05:50 +02:00
Ulas 0e035af492 feat: swipe gestures on shopping list items (toggle + delete) 2026-03-31 12:49:29 +02:00
Ulas fd94c58fea fix: hide FAB when virtual keyboard is open on mobile
Uses visualViewport resize event to detect keyboard state (viewport height
< 75% of window height). Sets body.keyboard-visible class; CSS hides
.fab and .page-fab via visibility:hidden on screens < 1024px.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 12:26:59 +02:00
Ulas 9446173247 fix: toast notifications no longer overlap bottom nav on mobile
Introduced --nav-bottom-height token (56px scroll + 12px dots indicator = 68px)
so that toast-container bottom and app-content padding-bottom both account for
the full nav-bottom height including the page-dots indicator.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 12:24:12 +02:00
Ulas 4fe4f6cb38 feat: BL-07–BL-10 — notes search, weather refresh, vCard import/export, PWA offline page
- Notes: client-side full-text search bar (filters title + content)
- Dashboard: weather refresh button + 30-min auto-refresh interval
- Contacts: vCard 3.0 export per contact (GET /:id/vcard); vCard import
  via file input with client-side parser (FN, TEL, EMAIL, ADR, NOTE, CATEGORIES)
- PWA: /offline.html served when network unavailable; cached in app-shell (sw v20)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:35:03 +02:00
Ulas 0defc3c589 chore: release v0.3.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:29:58 +02:00
Ulas d866d32336 feat: Apple CalDAV credentials form + connect/disconnect UI (BL-04)
Admin can now enter CalDAV URL, Apple-ID and app-specific password
directly in Settings; credentials are tested live before saving and
stored in sync_config (take precedence over .env); disconnect clears
DB-stored credentials without server restart. Auto-sync interval
(15 min, configurable via SYNC_INTERVAL_MINUTES) was already in place.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:27:07 +02:00
Ulas 6fd209ba5e feat: meals drag & drop between slots and days (BL-03)
Pointer Events-based drag & drop (touch + mouse compatible):
- Ghost element follows pointer; drops on empty slots move the meal,
  drops on occupied slots swap both meals via concurrent PUT requests
- prefers-reduced-motion: no ghost animation, interaction still works
- Suppress-click guard prevents accidental edit modal after drag

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:23:39 +02:00
Ulas 6a860f2c13 feat(calendar): expand recurring events in GET /calendar and /upcoming
expandRecurringEvents() iterates from the event's original start date,
generating all occurrences within the requested window using the existing
nextOccurrence() service (max 1000 iterations). The SQL query is extended
to also fetch recurring events that started before the window. Event
duration is preserved across instances. Virtual instances carry
is_recurring_instance=1 and are shown with a repeat icon in the agenda
view. /upcoming expands across a 90-day forward window.

Closes BL-01.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:17:39 +02:00
Ulas 82e5b2cd85 feat(budget): auto-generate recurring entry instances per month
Adds schema migration v3 (recurrence_parent_id column + budget_recurrence_skipped
table). On every GET /api/v1/budget, the server checks all recurring originals
(is_recurring=1, no parent) and creates missing instances for the requested month
using the same day-of-month (clamped to the last day). Deleted instances are
recorded in budget_recurrence_skipped so they are not recreated on the next visit.
Generated instances are shown with a ↩ indicator in the transaction list.

Closes BL-05.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-31 10:13:37 +02:00
Ulas 26d3d12a22 feat(budget): add month-over-month comparison to summary cards
Each summary card (Einnahmen, Ausgaben, Saldo) now shows a trend line
comparing the current month to the previous one. The previous month's
summary is fetched in parallel via the existing /budget/summary endpoint,
so there is no extra round-trip latency. Positive deltas render in green
(▲), negative in red (▼), unchanged in neutral grey (—).

Closes BL-02.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 22:54:04 +02:00
Ulas 675a0ff2b7 chore: bump to v0.2.1, finalize CHANGELOG
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 22:37:09 +02:00
Ulas 3e25339c86 fix: resolve event-listener leaks and CSS gaps found in code quality audit
- notes.js (Critical): move grid click listener from renderGrid() to
  render() — was re-registered on every save/pin/delete, causing
  multiple API calls per user action after several interactions
- dashboard.js (Major): introduce AbortController (_fabController) so
  the anonymous document click listener from initFab() is cancelled on
  each new render() cycle; also remove the redundant initFab() call on
  the skeleton render
- layout.css (Major): extend .label selector to include .form-label,
  covering usage in notes.js and settings.js without a mass-rename
- test-modal-utils.js (Major): 12 unit tests for wireBlurValidation,
  btnSuccess, btnError; registered as test:modal-utils in package.json
- notes.js (Minor): add btnError() shake feedback to save error handler
- calendar.js (Minor): add popup.isConnected guard to closePopup so
  the listener self-removes correctly after navigation without a click

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-30 22:26:49 +02:00
Ulas 656c1290dc chore: bump to v0.2.0, finalize CHANGELOG, update SPEC with UX patterns 2026-03-30 21:59:51 +02:00
Ulas 5aea8ca7f2 docs: update CHANGELOG for UX polish layer 1-4 changes 2026-03-30 21:23:48 +02:00
Ulas a4cc520342 Add CHANGELOG.md for initial v0.1.0 release
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-29 15:39:18 +02:00