Commit Graph

218 Commits

Author SHA1 Message Date
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
Ulas 63a0febfa1 docs: add awesome-selfhosted submission files
Prepared oikos.yml and issue template for awesome-selfhosted-data.
Submission blocked until first release (v0.1.0, 2026-03-30) is 4 months old (earliest: 2026-07-30).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 17:13:22 +02:00
Ulas 1a7ad72d9a docs: use absolute URLs for OG meta images
Social media crawlers require absolute URLs to resolve images correctly.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:48:58 +02:00
Ulas f425af390f docs: add project landing page for GitHub Pages
Static bilingual (EN/DE) landing page with dark/light theme support,
responsive design, scroll animations, theme-aware screenshot gallery,
and Open Graph images for social sharing.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:34:02 +02:00
Ulas 7ef1389d44 fix(ci): remove Node.js 24.x from test matrix
Node 24 is not yet LTS and native dependencies (bcrypt, better-sqlite3,
sharp) fail to compile on it, causing CI failures.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 15:05:27 +02:00
Ulas 28cf388917 docs: add comprehensive installation guide and link from README
New docs/installation.md covers the full setup journey for Docker
beginners: prerequisites, step-by-step install, .env reference,
Nginx/HTTPS, updates, backup/restore, and troubleshooting.
README Quick Start updated to include clone + .env steps and
links to the detailed guide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:54:20 +02:00
Ulas 789f07100e docs: refine README structure and Quick Start section
Separate docker compose and setup steps for clarity, remove redundant
horizontal rules, split License into its own section per style guide.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:45:02 +02:00
Ulas f7b9f8c876 docs: overhaul README with modern, concise project presentation
Replace verbose README with a streamlined structure inspired by
Immich/Mealie/LobeChat. Focus on scanability, mobile-first screenshots,
and clear communication of architectural decisions (zero-dependency
frontend, privacy-first, PWA).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:43:19 +02:00
Ulas 9a96a1a406 chore: remove CLAUDE.md.proposed after applying to local CLAUDE.md
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:30:23 +02:00
Ulas 604fb7fc2c docs: add CLAUDE.md audit and optimized proposal
Audit identifies redundancies with CONTRIBUTING.md, missing paths
(utils/ux.js, locales/, offline.html), incorrect info (node:20 vs 22,
non-existent public/assets/), and informational sections that don't
steer behavior. Proposed version reduces to 82 lines with clear hard
constraints block and reference document table.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-02 14:29: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 922c0b7fd6 chore: add .nvmrc and README sections for API docs and roadmap
- Add .nvmrc (22) for nvm/fnm users
- README: add API section pointing to SPEC.md and server/routes/
- README: add Roadmap section linking to BACKLOG.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 14:19:56 +02:00
Ulas c59338fe2c chore: repository hygiene — P2 cleanup
- .gitignore: add coverage/ and data/ patterns
- .dockerignore: exclude screenshots, tests, scripts, .github, docs
  assets from build context for faster Docker builds
- Delete docs/social-preview.html (one-time generator, no longer needed)
- Delete public/locales/.gitkeep (directory has de.json and en.json)
- scripts/seed-demo.js: replace hardcoded absolute path with portable
  resolve(__dirname, '..', 'data', 'oikos.db') default
- Add .github/PULL_REQUEST_TEMPLATE.md with summary, changes, checklist

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 14:19:27 +02:00
Ulas 83a80bfd6b chore: remove duplicate social-preview.png and clean up BACKLOG.md
- Delete root social-preview.png (identical copy of docs/social-preview.png,
  only the docs/ version is referenced in README)
- Consolidate BACKLOG.md: all 10 entries were completed, compress into a
  reference table and clear the active section for future use
- Delete prompt-i18n.md (untracked, i18n fully shipped in v0.5.0)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-02 14:18:17 +02:00
Ulas 5cb71bb424 fix: align Node.js version to >=22 across Dockerfile and package.json
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>
2026-04-02 14:16:49 +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 f39152cf7e ci: add GitHub Actions workflow for automated tests
Runs npm test on push and pull requests to main.
Matrix covers Node.js 22.x and 24.x.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 11:42:56 +02:00
Ulas d8503bc54b chore: exclude docs/superpowers/ from version control
Internal Claude Code working documents (plans, specs) are not relevant
for contributors. Remove tracked files and add to .gitignore.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 11:42:15 +02:00
Ulas b2fbd11287 fix: add social-preview.png, correct test count, add engines field
- 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>
2026-04-01 11:41:34 +02:00
Ulas 617e3cf007 fix: rename screenshots to bust GitHub CDN cache for updated images
Files that kept their original names after content replacement were served
from GitHub's CDN cache. Rename with -2 suffix to force fresh delivery.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 11:33:28 +02:00
Ulas 27bb95fc41 docs: replace screenshots with updated versions, add calendar/meal/settings/shopping
- Remove household screenshots (renamed to shopping)
- Add new calendar, meal, settings, shopping screenshots (mobile + tablet, light + dark)
- Update README screenshot section: 3x3 mobile grid covering all 9 modules, expanded tablet section

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 11:30:44 +02:00
Ulas ef51c43032 fix: meals drag & drop crash — destructure dragging before cleanup()
cleanup() set dragging = null, then onUp accessed dragging.slot,
.mealId, .sourceDate, .sourceType on the now-null reference.
Fix: destructure all needed values before calling cleanup().

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 10:11:24 +02:00
Ulas be8801aef7 fix: proxy weather icons through server to fix PWA standalone on Android
External image requests to openweathermap.org fail silently in Chrome
Android PWA standalone mode. Icons are now proxied via
GET /api/v1/weather/icon/:code, making them same-origin — cacheable by
the service worker and free of CORS/CSP issues.

Tightened CSP: removed openweathermap.org from imgSrc (no longer needed).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:57:48 +02:00
Ulas ac294628e8 fix: serve PWA icons with no-cache to prevent stale icon on Android
Icons were cached with immutable/30-day headers, so Chrome Android kept
serving the old placeholder even after new icons were deployed.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:47:22 +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 af69431eac fix: weather icons in PWA + locale picker dropdown
- SW: skip cross-origin asset requests (opaque responses caused weather
  icons to break in PWA standalone mode on Android)
- Replace oikos-locale-picker radio buttons with <select> dropdown
- Add settings.localeLabel i18n key (de + en)
- Bump SW cache to v22

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:42:06 +02:00
Ulas cd9f26911b fix: improve PWA manifest and SW cache for Android standalone mode
- Add id field and display_override to manifest.json for reliable
  Chrome Android PWA recognition
- Serve manifest.json with application/manifest+json MIME type
- Add /i18n.js and locale files to SW app shell cache (were missing)
- Bump SW cache version to v21

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 09:07:57 +02:00