Commit Graph

346 Commits

Author SHA1 Message Date
Ulas 8f8b3f7951 feat(ux): microinteraction improvements
- Zentralisiere @keyframes check-pop in layout.css (war dupliziert in shopping.css + tasks.css)
- Subtask-Checkbox erhaelt check-pop Animation (konsistent mit Haupt-Checkbox)
- Quick-Add: Checkmark-Feedback auf +-Button nach erfolgreichem Hinzufuegen (700ms, DOM-API)
- Swipe-Affordance Hint: swipe-row--hint via localStorage-Counter (max. 3x, nur Mobile)
2026-04-04 23:53:11 +02:00
Ulas 187af593f7 fix(styles): resolve design system audit violations
- Replace off-grid spacing (3px, 5px) with space tokens (--space-0h, --space-1)
- Replace below-minimum font-size 9px with var(--text-xs) in calendar, dashboard, notes
- Replace hardcoded 2.5rem with var(--text-4xl) in weather widget
- Replace hardcoded box-shadow with var(--shadow-sm) in toggle thumb
- Replace 0.85em and #666 with type/color tokens in print styles
2026-04-04 23:07:39 +02:00
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 d472e9b9e8 docs: update SPEC.md for none-priority and view mode persistence
- Add 'none' to task priority enum in data model
- Document view mode persistence (localStorage + ?view= URL param)
- Add --color-priority-none to design tokens section
2026-04-04 22:42:26 +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
ulsklyc 7b13275882 Update README.md 2026-04-04 12:54:18 +02:00
Ulas 6454c1fc9f chore: bump version to v0.7.5 and update changelog 2026-04-04 07:27:42 +02:00
Ulas 38c5852c78 fix(ux): improve microinteractions across the app
1. Nav-item tap: smooth scale transition instead of abrupt snap
2. Custom toggle switch: iOS-style toggle replaces native checkboxes
3. Focus-visible: outline on cards, buttons, FABs for keyboard users
4. Empty-state: gentle fade-in animation
5. Toast icons: SVG icons for success/danger/warning types
6. Swipe haptic: vibrate(15) fires at threshold during touchmove
2026-04-04 07:25:54 +02:00
Ulas db60279f87 docs: add interface design system documentation
Captures existing design decisions - palette, spacing, depth strategy,
typography, layout patterns, and module accent rationale.
2026-04-04 07:13:53 +02:00
Ulas dd10974997 fix(ux): defer old stylesheet removal until after page content is gone
Previous fix removed the old CSS when new CSS loaded, but that happened
BEFORE the out-animation completed - causing a flash of unstyled content.
Now the old stylesheet stays until replaceChildren removes the old DOM.
2026-04-04 07:04:52 +02:00
Ulas a9d2a802ab fix(ux): prevent flash of unstyled content during page transitions
- Keep old page stylesheet until new one is fully loaded
- Hide new page wrapper until render() completes before starting animation
2026-04-04 06:58:12 +02:00
Ulas 1c7b77401d chore: bump version to v0.7.4 and update changelog 2026-04-04 06:51:38 +02:00
Ulas d92f7ca446 fix(design): replace hardcoded values with design tokens
Audit found ~35 violations against the token system. Fixed:
- Hardcoded shadows in layout.css replaced with --shadow-sm/md
- 8 rgba colors extracted to new glass tokens (--color-glass-*)
- border-radius: 50% replaced with var(--radius-full)
- ~25 off-grid spacing values (5px, 6px, 7px, 14px, 15px, 22px,
  26px, 34px) aligned to 4px grid using space tokens
2026-04-04 06:50:19 +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 87186c03c0 docs: add BL-11 CardDAV contacts provider to backlog (issue #10) 2026-04-04 01:43:08 +02:00
Ulas 1146588212 docs: update public docs post-audit for v0.7.0
- SECURITY.md: add bcrypt v6 reference and mandatory SESSION_SECRET note
- CODE_OF_CONDUCT.md: add enforcement contact (GitHub Private Reporting)
- BACKLOG.md: add completed features table entries for v0.5.0 through v0.7.0
- docs/SPEC.md: add supported languages table with Italian (v0.5.8)
- Remove CLAUDE.md.proposed (tracked, deleted from disk)
2026-04-04 01:37:20 +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 9a68fb7b0c fix(auth): remove SESSION_SECRET fallback - always throw if unset
App refuses to start without SESSION_SECRET regardless of NODE_ENV.
Removes risk of accidental insecure deployment when NODE_ENV is not
explicitly set to production.
2026-04-04 01:16:59 +02:00
Ulas c1176de661 fix(audit): address security audit findings
- Translate German error/warn messages in auth.js to English
- Add CODE_OF_CONDUCT.md (Contributor Covenant v2.1)
- Remove docs/claude-md-migration.md (internal migration artifact)
- Clarify README first-login instruction with credential hint
2026-04-04 01:13:50 +02:00
Ulas 7a2516153c fix(esm): fix stale comments and use node: prefix for crypto import 2026-04-03 23:19:16 +02:00
Ulas b139eea623 refactor(esm): migrate server and tests from CommonJS to ESM
Convert all server/, test, and setup files from require()/module.exports
to import/export syntax. Activate ESM globally via "type": "module" in
package.json and load dotenv via --import dotenv/config in npm scripts.
2026-04-03 23:11:20 +02:00
Ulas 2f6127911e fix(imports): convert require() to ESM import for randomBytes in auth.js 2026-04-03 23:00:38 +02:00
Ulas 3b90074723 refactor(logging): replace console.* with structured logger across server
Add server/logger.js - zero-dependency, level-based logger that outputs
JSON in production and human-readable format in development. Controlled
via LOG_LEVEL env var (debug/info/warn/error, default: info).

Replaces all 100 console.log/warn/error calls in 14 server files.
2026-04-03 22:05:22 +02:00
Ulas 5b1e6915ac fix(security): replace hardcoded session secret fallback with random generation
Instead of a static 'dev-only-secret-not-for-production' fallback,
generate a random one-time secret in development. Warns that sessions
won't survive restarts. Production guard unchanged.
2026-04-03 21:59:41 +02:00
Ulas ae8fbdd465 fix(deps): upgrade bcrypt 5.1.1->6.0.0 and patch path-to-regexp ReDoS
Resolves all 5 npm audit vulnerabilities (4 high in tar via
node-pre-gyp, 1 high path-to-regexp ReDoS). bcrypt 6 replaces
node-pre-gyp with prebuildify, removing 46 transitive packages.
2026-04-03 21:58:28 +02:00
Ulas 72eeee27c9 chore: translate .gitignore comments to English and add audit report patterns 2026-04-03 21:55:10 +02:00
Ulas 614a496256 docs: translate package.json description and .env.example to English
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-03 21:54:31 +02:00
Ulas ecff4a6e04 chore: remove orphaned audit docs
Internal dev artifacts (claude-md-audit, repo-audit) no longer needed -
findings have been actioned and tracked in git history.
2026-04-03 21:53:12 +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 6046cac7a8 docs: translate German documentation files to English
Translate BACKLOG.md and docs/SPEC.md from German to English for
international contributor accessibility. Fix outdated CONTRIBUTING.md
statement that claimed UI text is German-only — app now supports
multiple locales via i18n.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-03 17:01:19 +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
ulsklyc 2e6fb3de65 Update README.md 2026-04-03 11:14:06 +02:00
ulsklyc fe3853594a Refine README formatting and punctuation
Updated formatting and punctuation in the README file for consistency and clarity.
2026-04-03 11:13:10 +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 7a520a24de ci: add GitHub Actions workflow to publish Docker image to GHCR
Builds and pushes to ghcr.io/ulsklyc/oikos on every push to main
and on version tags. Tags: branch name, semver, short SHA.
Uses Docker layer caching via GitHub Actions cache.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 21:58:39 +02:00