diff --git a/README.md b/README.md index 8923202..c1f9121 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,18 @@ -

- Oikos -

+
+ Oikos +

Oikos

+

Self-hosted family planner for small households

+

Tasks · Shopping Lists · Meal Planning · Calendar Sync · Budget · Notes · Contacts

-

Oikos

- -

- The self-hosted family planner that respects your privacy.
- Tasks, calendars, shopping, meals, budget, notes, contacts —
- all in one place, on your own server. -

- -

- Latest Release MIT License - Node.js ≥22 - Docker Ready - SQLCipher Encrypted - PWA Offline - i18n: de | en -

- -

- Screenshots ·  - Features ·  - Quick Start ·  - Security ·  - Contributing -

+ Latest Release + Docker + Node.js + PRs Welcome +

-

- Oikos — The self-hosted family planner -

- ---- - -## Why Oikos? - -Most family organizers are cloud apps with monthly subscriptions, data mining, and vendor lock-in. Oikos takes a different approach: - -- **Your server, your data** — runs in a single Docker container on your own hardware. Nothing leaves your network. -- **No subscriptions** — free and open source, forever. MIT licensed. -- **No tracking** — zero telemetry, zero analytics, zero third-party scripts. -- **Offline-first** — works as a PWA on phones and tablets, even without connectivity. -- **Encrypted at rest** — optional AES-256 database encryption via SQLCipher. -- **Lightweight** — vanilla JavaScript frontend with no framework and no build step. Express + SQLite backend. Minimal resource footprint. - -Oikos is designed for **one family on one server** — not a SaaS product, not a team tool, not multi-tenant. It's a private, self-contained household organizer for 2–6 people. - ---- - -## 📸 Screenshots - - - - - - - - - - -
@@ -61,7 +21,6 @@ Oikos is designed for **one family on one server** — not a SaaS product, not a Dashboard -
Dashboard
@@ -69,25 +28,6 @@ Oikos is designed for **one family on one server** — not a SaaS product, not a Tasks -
Tasks -
- - - - Calendar - -
Calendar -
- - - - Shopping - -
Shopping
@@ -95,448 +35,91 @@ Oikos is designed for **one family on one server** — not a SaaS product, not a Meals -
Meals -
- - - - Budget - -
Budget -
- - - - Notes - -
Notes -
- - - - Contacts - -
Contacts -
- - - - Settings - -
Settings
-
-Tablet views -
- - - - - - - - - - - - - - - - - -
- - - - Dashboard — Tablet - -
Dashboard -
- - - - Tasks — Tablet - -
Tasks -
- - - - Calendar — Tablet - -
Calendar -
- - - - Shopping — Tablet - -
Shopping -
- - - - Meals — Tablet - -
Meals -
- - - - Budget — Tablet - -
Budget -
- - - - Notes — Tablet - -
Notes -
- - - - Contacts — Tablet - -
Contacts -
-
- -

- Screenshots adapt to your GitHub theme — toggle light/dark mode to see both variants. -

+

Toggle GitHub light/dark mode to see both themes.

--- -## ✨ Features +## Highlights - - - - - -
+📋 **Task Management** — Shared tasks with deadlines, priorities, subtasks, recurring schedules, and Kanban view -**📋 Dashboard** -At-a-glance family overview — weather, upcoming events, urgent tasks, today's meals, pinned notes. +🛒 **Shopping Lists** — Collaborative lists with aisle categories and one-click import from meal plans -**✅ Tasks** -List + Kanban views, subtasks, recurring tasks (RRULE), swipe gestures, priority levels. +🍽️ **Meal Planning** — Weekly drag-and-drop planner with ingredient lists and shopping export -**🛒 Shopping** -Multiple lists, aisle-grouped categories, auto-import from meal plan, swipe to check off. +📅 **Calendar Sync** — Two-way sync with Google Calendar (OAuth) and Apple iCloud (CalDAV) -**🍽️ Meals** -Weekly planner (Mon–Sun), drag & drop between slots, ingredients, one-click shopping list export. +💰 **Budget Tracking** — Income and expenses, recurring entries, monthly trends, CSV export - +📌 **Notes & Contacts** — Colored sticky notes with Markdown, contact directory with vCard import/export -**📅 Calendar** -Month / week / day / agenda views. Two-way sync with Google Calendar and Apple iCloud. +⚡ **Zero Build Step** — Pure ES modules, no bundler, no transpiler, no framework. Ships what you write. -**📌 Notes** -Colored sticky notes, pinning, full-text search, Markdown formatting toolbar. +🔒 **Privacy First** — SQLCipher AES-256 encrypted database, fully self-hosted, zero telemetry -**👥 Contacts** -Category filters, tap-to-call/email, map links, vCard import & export. +📱 **PWA Native Feel** — Installable on any device, works offline, dark mode, responsive from phone to desktop -**💰 Budget** -Income & expense tracking, recurring entries, month-over-month trends, CSV export. - -
- -**And also:** dark mode with system detection · responsive design (mobile / tablet / desktop) · offline PWA with install prompt · per-module accent colors · multilingual UI (de / en, auto-detected, switchable in Settings) · accessibility (skip links, ARIA, reduced motion) · staggered animations · bottom sheet modals on mobile. +🌍 **Multilingual** — German and English UI with automatic locale detection --- -## 🛠 Tech Stack +## Quick Start + +```bash +git clone https://github.com/ulsklyc/oikos.git && cd oikos +cp .env.example .env # Set SESSION_SECRET (≥32 chars) +docker compose up -d # First build takes ~3 min (compiles SQLCipher) +docker compose exec oikos node setup.js # Create admin account +``` + +Open `http://localhost:3000` — add family members from Settings. + +> For HTTPS and reverse proxy setup, see [`nginx.conf.example`](nginx.conf.example). + +--- + +## Tech Stack

Express - SQLite - Vanilla JS + SQLite + Vanilla JS + CSS Docker PWA

-| Layer | Technology | -|:---|:---| -| **Server** | Node.js ≥ 22 · Express · better-sqlite3 · bcrypt · Helmet | -| **Database** | SQLite with optional [SQLCipher](https://www.zetetic.net/sqlcipher/) encryption (AES-256) | -| **Frontend** | Vanilla JavaScript ES modules — no framework, no build step. [Web Components](https://developer.mozilla.org/en-US/docs/Web/API/Web_components) (`oikos-*`). [Lucide Icons](https://lucide.dev) (self-hosted) | -| **Auth** | Session-based · httpOnly cookies · CSRF double-submit · [express-session](https://github.com/expressjs/session) | -| **Deployment** | Docker + Docker Compose · Nginx reverse proxy · Let's Encrypt SSL | -| **Integrations** | [Google Calendar API v3](https://developers.google.com/calendar) (OAuth 2.0) · [Apple iCloud CalDAV](https://developer.apple.com/library/archive/documentation/DataManagement/Conceptual/CloudKitWebServicesReference/) (tsdav) · [OpenWeatherMap](https://openweathermap.org/api) | +--- + +## Documentation + +| 📖 [Spec & Data Model](docs/SPEC.md) | 🤝 [Contributing](CONTRIBUTING.md) | 🔒 [Security](SECURITY.md) | 📋 [Changelog](CHANGELOG.md) | 📌 [Backlog](BACKLOG.md) | +|---|---|---|---|---| --- -## 🚀 Quick Start +## Roadmap -> **Prerequisites:** Docker and Docker Compose installed on a Linux server. +✅ Core modules — Dashboard, Tasks, Shopping, Meals, Calendar, Notes, Contacts, Budget -```bash -# 1. Clone the repository -git clone https://github.com/ulsklyc/oikos.git && cd oikos +✅ Calendar sync — Google Calendar + Apple iCloud bidirectional sync -# 2. Configure environment -cp .env.example .env -# Edit .env — set SESSION_SECRET (≥32 chars) and optionally DB_ENCRYPTION_KEY +✅ PWA — Service worker, offline mode, install prompt -# 3. Start the container -docker compose up -d -# First build takes 2–3 minutes (compiles SQLCipher) +📋 Push notifications for deadlines and reminders -# 4. Create your admin account -docker compose exec oikos node setup.js - -# 5. Open http://localhost:3000 -``` - -The admin can create additional family members from **Settings → Family Members**. - -> **Production:** See [`nginx.conf.example`](nginx.conf.example) for a reverse proxy config with SSL. If you use [Nginx Proxy Manager](https://nginxproxymanager.com), paste the contents into the Advanced tab. Ensure `X-Forwarded-Proto` is set for session cookies to work correctly. - ---- - -## 🔒 Security - -Oikos is designed to run on a private server behind SSL. No public endpoints exist except the login page. - -| Layer | Implementation | -|:---|:---| -| **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, 300 API requests/min per IP | -| **Headers** | Strict Content Security Policy via Helmet (`self`-only) | -| **Encryption** | Optional SQLCipher AES-256 database encryption at rest | -| **Access control** | No API endpoint accessible without session auth (except login) | -| **Registration** | Disabled — only admins can create user accounts | - ---- - -
-Configuration - -### 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 - -Oikos syncs bidirectionally with Google Calendar and Apple iCloud. External events are visually distinguished in the UI. On conflict, the external source wins. - -### 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) - -**Option A — via Settings UI** (recommended, no restart required): - -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. In Oikos: **Settings → Calendar Sync → Apple Calendar** → enter CalDAV URL, Apple ID, and app-specific password → click **Verbinden & testen** - -Credentials are stored in the database. No server restart needed. - -**Option B — via `.env`:** - -```env -APPLE_CALDAV_URL=https://caldav.icloud.com -APPLE_USERNAME=your@apple-id.com -APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx -``` - -Restart: `docker compose up -d`. The sync button appears automatically in Settings. `.env` credentials are used as fallback when no UI credentials are saved. - -
- -
-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 # 162 tests across 9 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 - middleware/ # CSRF, input validation - 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 (app-shell caching) -``` - -**Request flow:** Browser → Express static (`public/`) 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 -``` - -Migrations run automatically on startup. Data in the `oikos_data` volume is preserved across container rebuilds. - -
- -
-Updates - -```bash -git pull -docker compose up -d --build -``` - -Migrations run automatically. Your data volume stays intact. - -### Adding Family Members - -Only admins can create accounts — there is no public registration. - -- **In the browser:** Settings → Family Members → Add Member -- **Via CLI:** `docker compose exec oikos node setup.js` - -
- ---- - -## 📡 API - -All endpoints live under `/api/v1/` and require session authentication (except login). Each route file in `server/routes/` corresponds to one module. Responses follow a consistent format: `{ data: ... }` on success, `{ error: string, code: number }` on failure. See [`docs/SPEC.md`](docs/SPEC.md) for the data model and [`server/routes/`](server/routes/) for endpoint details. - ---- - -## 🗺 Roadmap - -See [`BACKLOG.md`](BACKLOG.md) for planned features and ideas. Got a suggestion? [Open a feature request](https://github.com/ulsklyc/oikos/issues/new?template=feature_request.md). - ---- - -## 🤝 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). - -See [`CONTRIBUTING.md`](CONTRIBUTING.md) for setup instructions, code conventions, commit format, and workflow. +📋 Household inventory tracking --- ## License -[MIT](LICENSE) © 2026 ulsklyc +MIT License -

- Made with care for families who value their privacy. -

+
+ Built with care for families who value privacy and simplicity. +