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>
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>
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>
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>
Dockerfile used node:20-slim but the project requires Node >=22
(--experimental-sqlite in tests, CI matrix). package.json had a
duplicate engines block where the second (>=20.0.0) silently
overwrote the correct first one (>=22.0.0).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
- Add social-preview.png to version control (referenced in README but untracked)
- Update README: test count 146+ → 162 across 9 suites
- Add engines.node >=22.0.0 to package.json (required for --experimental-sqlite)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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>
Configure manifest.json with scope, maskable icons, and categories. Add iOS/Android
meta tags for standalone behavior. Create pwa.css for native touch/scroll handling
and safe area insets. Add oikos-install-prompt Web Component with Chrome install
flow and iOS guidance. Optimize service worker with network-first navigation and
expanded precache (v19). Add dynamic theme-color per route and modal overlay dimming
in standalone mode. Generate placeholder icons via sharp script.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Einladender Hero-Bereich mit klarem Value Proposition
- Vergleichstabelle Cloud vs. Selfhosted
- Ausführliche Schritt-für-Schritt-Installationsanleitung mit Erklärungen für Einsteiger
- Expandierbare Details-Blöcke für zusätzliche Hilfe
- FAQ-Sektion für häufige Fragen
- Sicherheitsübersicht als übersichtliche Tabelle
- Bessere visuelle Struktur mit mehr Whitespace und klarerer Hierarchie
- package.json Beschreibung verbessert
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- connect-sqlite3 durch eigenen BetterSQLiteStore ersetzt (sessions-Tabelle
in der bestehenden DB, keine native Kompilierung nötig)
- db.init() vor require('./auth') gezogen damit BetterSQLiteStore-Konstruktor
db.get() erfolgreich aufrufen kann
- router.js: App-Shell und pageWrapper vor module.render() in DOM einfügen
damit document.getElementById() in Seiten-Modulen funktioniert
- Seiten-Module (meals, notes, contacts, calendar, budget): _container-Referenz
eingeführt, alle document.getElementById() auf _container.querySelector() bzw.
document.querySelector() für body-Elemente umgestellt
- login.js: User-Objekt nach erfolgreichem Login an navigate() übergeben
damit auth.me()-Roundtrip entfällt
- calendar.js: /users → /auth/users korrigiert (404-Fix)
- SW-Cache v8 (erzwingt Reload aller gecachten Seiten-Module)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- LICENSE: MIT-Lizenz (bereits vorhanden, korrekt)
- package.json: "license": "MIT" ergänzt
- README.md: Lizenz-Badge auf MIT aktualisiert, Lizenz-Sektion angepasst
- .gitignore: .claude/ und *.txt hinzugefügt (verhindert versehentliches
Committen von Claude Code Einstellungen und Token-Textdateien)
- server/auth.js: Fail-Fast in Produktion wenn SESSION_SECRET fehlt;
Fallback-String auf 'dev-only-secret-not-for-production' umbenannt
(klarere Intention, kein bekannter Produktions-Wert im Public Repo)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Backend:
- GET /shopping — alle Listen mit item_total/item_checked Zähler
- POST/PUT/DELETE /shopping/:listId — Listen-CRUD
- GET /shopping/:listId/items — Artikel nach Supermarkt-Gang sortiert
(Obst→Backwaren→Milch→Fleisch→Tiefkühl→Getränke→Haushalt→Drogerie→Sonstiges)
Abgehakte innerhalb der Kategorie ans Ende
- POST /shopping/:listId/items — Artikel hinzufügen
- PATCH /shopping/items/:id — Artikel aktualisieren (abhaken, umbenennen)
- DELETE /shopping/items/:id — Einzelartikel löschen
- DELETE /shopping/:listId/items/checked — nur abgehakte löschen
- GET /shopping/suggestions?q= — Autocomplete aus bisherigen Einträgen
Frontend:
- Multi-Listen-Tabs (horizontal scrollbar, Artikel-Zähler im Tab)
- Quick-Add: Name + Menge + Kategorie-Dropdown in einer Zeile
- Autocomplete-Dropdown mit Tastaturnavigation (↑↓ Enter Escape)
- Optimistisches Toggle: Checkbox reagiert sofort, Rollback bei Fehler
- "Abgehakt löschen"-Button erscheint dynamisch bei checked > 0
- Listen umbenennen/löschen direkt im Header
- Kategorie-Icons (Lucide) in Gruppen-Überschriften
Tests: 17/17 bestanden (71 gesamt)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>