- 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>
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>
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>
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>
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>
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>
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>
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>
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>
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>
- 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>
- 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>
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>
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>
- 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>
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>
- 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>
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>
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>
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>
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>
- 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>
Android was showing only a blue circle because maskable icons had no
visible content after the adaptive icon mask was applied. All icons now
use the actual Oikos house logo from docs/logo.svg. Maskable variants
use full-bleed background with logo within the 80% safe zone.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The locale JSON files use nested structure (e.g. {"nav":{"tasks":"…"}}),
but t() did a flat lookup, always falling back to the raw key string.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace all hardcoded German strings in router.js (navItems labels,
aria-labels, skip-link, error/toast messages) with t() calls. Add a
locale-changed event listener that re-renders sidebar and bottom-nav
items on language switch.
Replace hardcoded German strings in modal.js and oikos-install-prompt.js
with t() calls; wire locale-changed event listener for live re-render on
locale switch.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>