🏠 Oikos

Self-hosted family planner β€” private, open, no subscription.

MIT License Node.js >=20 Docker Ready SQLCipher Encrypted PWA Offline GitHub Stars Last Commit

Oikos is a self-hosted family organizer for 2–6 people. Tasks, calendars, shopping lists, meal plans, budget tracking, and more β€” all running on your own server. No cloud dependency. No data leaves your network. No tracking.

Features Β· Quick Start Β· Configuration Β· Calendar Sync Β· Security

--- ## Features | | Module | What it does | Highlights | |---|---|---|---| | πŸ“‹ | **Dashboard** | At-a-glance overview of your family's day | Weather widget, upcoming events, urgent tasks, today's meals, pinned notes | | βœ… | **Tasks** | Shared to-do lists with accountability | List + Kanban views, subtasks, recurring tasks (RRULE), swipe gestures, priority levels | | πŸ›’ | **Shopping** | Collaborative grocery lists | Multiple lists, aisle-grouped categories, auto-import from meal plan | | 🍽️ | **Meals** | Weekly meal planning | Week view (Mon–Sun), ingredient management, one-click export to shopping list | | πŸ“… | **Calendar** | Family calendar with external sync | Month/week/day/agenda views, Google Calendar & Apple iCloud sync (two-way) | | πŸ“Œ | **Notes** | Shared family pinboard | Colored sticky notes, pinning, lightweight Markdown (bold, italic, lists) | | πŸ‘₯ | **Contacts** | Important family contacts | Category filters, tap-to-call, tap-to-email, map links for addresses | | πŸ’° | **Budget** | Income & expense tracking | Category breakdown, month-over-month comparison, CSV export | | βš™οΈ | **Settings** | User & sync management | Password changes, calendar sync config, family member admin | ## Tech Stack

Express SQLite Vanilla JS Docker PWA

**Backend:** Node.js, Express, SQLite via better-sqlite3, optional SQLCipher encryption (AES-256), bcrypt, express-session, Helmet **Frontend:** Vanilla JavaScript ES modules β€” no framework, no build step, no bundler. Web Components for reusable UI. Lucide Icons (self-hosted SVG sprite). **Deployment:** Docker + Docker Compose, Nginx reverse proxy with SSL, PWA with service worker for offline support **Integrations:** Google Calendar API v3 (OAuth 2.0), Apple iCloud CalDAV via tsdav, OpenWeatherMap ## Quick Start **Prerequisites:** Docker + Docker Compose on a Linux server. **1. Clone** ```bash git clone https://github.com/ulsklyc/oikos.git cd oikos ``` **2. Configure** ```bash cp .env.example .env ``` Edit `.env` and set the two required variables: ```env SESSION_SECRET=your-random-string-at-least-32-chars DB_ENCRYPTION_KEY=your-sqlcipher-aes256-key ``` **3. Start** ```bash docker compose up -d ``` First build takes 2–3 minutes (compiles SQLCipher against better-sqlite3). **4. Create admin account** ```bash docker compose exec oikos node setup.js ``` Interactive script β€” sets up username, display name, and password. This admin can create additional family members. **5. Open** Navigate to `http://localhost:3000` β€” or your configured domain after Nginx setup. > See [`nginx.conf.example`](nginx.conf.example) for a ready-to-use reverse proxy configuration. If you use [Nginx Proxy Manager](https://nginxproxymanager.com), paste the contents into the "Advanced" tab. Make sure `X-Forwarded-Proto` is set so session cookies work correctly in production.
πŸ“‹ Configuration Reference ### Required | Variable | Description | |---|---| | `SESSION_SECRET` | Random string β‰₯ 32 characters for session signing | | `DB_ENCRYPTION_KEY` | SQLCipher AES-256 key. Leave empty to disable encryption | ### Optional | Variable | Default | Description | |---|---|---| | `PORT` | `3000` | Server port | | `NODE_ENV` | `development` | Set to `production` for deployment | | `DB_PATH` | `./oikos.db` | Path to SQLite database file | | `SYNC_INTERVAL_MINUTES` | `15` | Automatic calendar sync interval | | `RATE_LIMIT_MAX_ATTEMPTS` | `5` | Max login attempts per minute per IP | ### Weather Widget Register a free API key at [openweathermap.org](https://openweathermap.org/api): | Variable | Default | Description | |---|---|---| | `OPENWEATHER_API_KEY` | β€” | Your API key | | `OPENWEATHER_CITY` | `Berlin` | City name | | `OPENWEATHER_UNITS` | `metric` | `metric` (Β°C) or `imperial` (Β°F) | | `OPENWEATHER_LANG` | `de` | Language code | ### Integrations | Variable | Description | |---|---| | `GOOGLE_CLIENT_ID` | Google OAuth 2.0 Client ID | | `GOOGLE_CLIENT_SECRET` | Google OAuth 2.0 Client Secret | | `GOOGLE_REDIRECT_URI` | `https://your-domain/api/v1/calendar/google/callback` | | `APPLE_CALDAV_URL` | `https://caldav.icloud.com` | | `APPLE_USERNAME` | Your Apple ID email | | `APPLE_APP_SPECIFIC_PASSWORD` | App-specific password from Apple ID settings | Full template: [`.env.example`](.env.example)
πŸ“… Calendar Sync ### Google Calendar 1. Create a project at [console.cloud.google.com](https://console.cloud.google.com) 2. Enable the **Google Calendar API** 3. Create an **OAuth 2.0 Client ID** (type: Web application) 4. Add your redirect URI: ``` https://your-domain.com/api/v1/calendar/google/callback ``` 5. Add credentials to `.env`: ```env GOOGLE_CLIENT_ID=... GOOGLE_CLIENT_SECRET=... GOOGLE_REDIRECT_URI=https://your-domain.com/api/v1/calendar/google/callback ``` 6. Restart: `docker compose up -d` 7. In Oikos: **Settings β†’ Calendar Sync β†’ Connect Google** **Sync behavior:** - Initial sync pulls events from 3 months ago to 12 months ahead - Subsequent syncs use Google's `syncToken` for incremental updates - Local events push to Google automatically - Conflicts: Google wins on simultaneous edits ### Apple Calendar (iCloud CalDAV) 1. Go to [appleid.apple.com](https://appleid.apple.com) β†’ Sign-In and Security β†’ App-Specific Passwords 2. Generate a new password for "Oikos" 3. Add to `.env`: ```env APPLE_CALDAV_URL=https://caldav.icloud.com APPLE_USERNAME=your@apple-id.com APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx ``` 4. Restart: `docker compose up -d` The sync button appears automatically in Settings.
## Security - **Sessions:** `httpOnly`, `SameSite=Strict`, `Secure` in production, 7-day TTL - **CSRF:** Double Submit Cookie pattern on all state-changing requests - **Passwords:** bcrypt with cost factor 12 - **Rate limiting:** 5 login attempts/min per IP, 300 API requests/min per IP - **Headers:** Content Security Policy via Helmet (`self`-only) - **Encryption:** Optional SQLCipher AES-256 database encryption - **Access control:** No API endpoint accessible without session auth (except `/api/v1/auth/login`) - **No public registration:** Only admins can create user accounts
πŸ› οΈ Development ### Local Setup ```bash npm install cp .env.example .env # Set SESSION_SECRET β€” skip DB_ENCRYPTION_KEY (no SQLCipher needed locally) npm run dev # Starts server with --watch (auto-reload) ``` ### Tests ```bash npm test # 146 tests across 7 suites ``` Tests use Node.js built-in test runner with `--experimental-sqlite` for in-memory SQLite. No running server required. ### Architecture ``` server/ index.js # Express entry, middleware, static serving db.js # SQLite connection, migration runner auth.js # Session auth + user management routes routes/ # One file per module services/ # Calendar sync, recurrence engine public/ index.html # SPA shell router.js # History API router (~50 lines) api.js # Fetch wrapper with auth + CSRF styles/ # Design tokens, reset, layout, per-module CSS components/ # Web Components (oikos-* prefix) pages/ # Page modules with render() export sw.js # Service worker ``` **Request flow:** Client β†’ Express static or `/api/v1/*` β†’ session auth middleware β†’ route handler β†’ better-sqlite3 (sync) β†’ JSON response. **Database migrations** run automatically on startup. Each migration is an idempotent SQL block in `server/db.js`. Append new migrations β€” never modify existing ones.
πŸ’Ύ Backup & Restore ### Backup ```bash docker run --rm \ -v oikos_oikos_data:/data \ -v $(pwd):/backup \ alpine tar czf /backup/oikos-backup-$(date +%Y%m%d).tar.gz /data ``` ### Restore ```bash docker compose down docker run --rm \ -v oikos_oikos_data:/data \ -v $(pwd):/backup \ alpine tar xzf /backup/oikos-backup-YYYYMMDD.tar.gz -C / docker compose up -d ```
## Updates ```bash git pull docker compose up -d --build ``` Database migrations run automatically on startup. Data in the `oikos_data` volume is preserved. ## Family Members Only admins can create new accounts β€” there is no public registration endpoint. **In the browser:** Settings β†’ Family Members β†’ Add Member **Via CLI:** `docker compose exec oikos node setup.js` ## Contributing Contributions are welcome. If you find a bug or have a feature idea, [open an issue](https://github.com/ulsklyc/oikos/issues). Pull requests are appreciated β€” please keep the vanilla JS constraint in mind (no frameworks, no build tools). A `CONTRIBUTING.md` with detailed guidelines is coming soon. ## License [MIT](LICENSE) Β© 2025 ulsklyc ---

Made with β˜• by ulsklyc