Files
oikos/README.md
T
Ulas 443c8635a5 docs: add project logo and embed in README
Geometric house icon on blue gradient rounded square (SVG).
Replaces shields.io badge placeholder in README hero section.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 17:41:45 +02:00

19 KiB
Raw Blame History

Oikos

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

Screenshots ·  Features ·  Quick Start ·  Security ·  Contributing


Oikos Dashboard


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 26 people.


📸 Screenshots

Tasks
Tasks
Shopping
Shopping
Budget
Budget
Notes
Notes
Contacts
Contacts
Dashboard Mobile
Dashboard
Tablet views
Tasks — Tablet
Tasks
Shopping — Tablet
Shopping
Notes — Tablet
Notes
Budget — Tablet
Budget
Contacts — Tablet
Contacts

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


Features

📋 Dashboard At-a-glance family overview — weather, upcoming events, urgent tasks, today's meals, pinned notes.

Tasks List + Kanban views, subtasks, recurring tasks (RRULE), swipe gestures, priority levels.

🛒 Shopping Multiple lists, aisle-grouped categories, auto-import from meal plan, swipe to check off.

🍽️ Meals Weekly planner (MonSun), drag & drop between slots, ingredients, one-click shopping list export.

📅 Calendar Month / week / day / agenda views. Two-way sync with Google Calendar and Apple iCloud.

📌 Notes Colored sticky notes, pinning, full-text search, Markdown formatting toolbar.

👥 Contacts Category filters, tap-to-call/email, map links, vCard import & export.

💰 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 · accessibility (skip links, ARIA, reduced motion) · staggered animations · bottom sheet modals on mobile.


🛠 Tech Stack

Express SQLite Vanilla JS Docker PWA

Layer Technology
Server Node.js ≥ 22 · Express · better-sqlite3 · bcrypt · Helmet
Database SQLite with optional SQLCipher encryption (AES-256)
Frontend Vanilla JavaScript ES modules — no framework, no build step. Web Components (oikos-*). Lucide Icons (self-hosted)
Auth Session-based · httpOnly cookies · CSRF double-submit · express-session
Deployment Docker + Docker Compose · Nginx reverse proxy · Let's Encrypt SSL
Integrations Google Calendar API v3 (OAuth 2.0) · Apple iCloud CalDAV (tsdav) · OpenWeatherMap

🚀 Quick Start

Prerequisites: Docker and Docker Compose installed on a Linux server.

# 1. Clone the repository
git clone https://github.com/ulsklyc/oikos.git && cd oikos

# 2. Configure environment
cp .env.example .env
# Edit .env — set SESSION_SECRET (≥32 chars) and optionally DB_ENCRYPTION_KEY

# 3. Start the container
docker compose up -d
# First build takes 23 minutes (compiles SQLCipher)

# 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 for a reverse proxy config with SSL. If you use Nginx Proxy Manager, 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:

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

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
  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:
    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 → 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:

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

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

npm test           # 146+ 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

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

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
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

🤝 Contributing

Contributions are welcome! If you find a bug or have a feature idea, open an issue. Pull requests are appreciated — please keep the vanilla JS constraint in mind (no frameworks, no build tools).

See CONTRIBUTING.md for setup instructions, code conventions, commit format, and workflow.


License

MIT © 2026 ulsklyc

Made with care for families who value their privacy.