Ulas 235b793d4b Add missing Login and Settings module specs to SPEC.md
Both pages exist in the codebase but were undocumented in the product
specification.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-30 16:02:57 +02:00
2026-03-24 13:46:15 +01:00

Oikos

Oikos

Self-hosted family planner — tasks, calendars, shopping, meals, budget.
Your data stays on your server. No subscriptions. No tracking. No cloud lock-in.

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

Features · Quick Start · Configuration · Calendar Sync · Security


Oikos is a self-hosted family organizer for 26 people. Tasks, calendars, shopping lists, meal plans, budget tracking, notes, and contacts — all running on your own server inside a single Docker container. No cloud dependency, no telemetry, no data leaves your network.

Built with Express.js, SQLite (optionally encrypted via SQLCipher), and vanilla JavaScript — no frontend framework, no build step. Works offline as a PWA on phones and tablets.

Oikos is not a SaaS product, not a team collaboration tool, and not designed for public multi-tenant use. It is a private tool for one family on one server.


Screenshots

Dashboard

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

Screenshots adapt to your GitHub theme — switch between light and dark mode to see both variants.


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 with ingredients Week view (MonSun) · ingredient management · one-click export to shopping list
📅 Calendar Family calendar with external sync Month/week/day/agenda views · Google Calendar & Apple iCloud two-way sync
📌 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

Layer Technology
Server Node.js ≥ 20 · 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 SVG sprite)
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 + Docker Compose on a Linux server.

1. Clone

git clone https://github.com/ulsklyc/oikos.git
cd oikos

2. Configure

cp .env.example .env

Edit .env and set the two required variables:

SESSION_SECRET=your-random-string-at-least-32-chars
DB_ENCRYPTION_KEY=your-sqlcipher-aes256-key

3. Start

docker compose up -d

First build takes 23 minutes (compiles SQLCipher against better-sqlite3).

4. Create admin account

docker compose exec oikos node setup.js

Interactive script — sets up username, display name, and password. This admin can create additional family members from the settings page.

5. Open

Navigate to http://localhost:3000 — or your configured domain after Nginx setup.

Nginx: See nginx.conf.example for a production-ready config. If you use Nginx Proxy Manager, paste the contents into the "Advanced" tab. Make sure X-Forwarded-Proto is set so session cookies work correctly in production.


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)

  1. Go to appleid.apple.com → Sign-In and Security → App-Specific Passwords
  2. Generate a new password for "Oikos"
  3. Add to .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

Oikos is designed to run on a private server behind SSL. No public endpoints exist except the login page.

  • SessionshttpOnly, 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 /api/v1/auth/login)
  • No public registration — Only admins can create user accounts

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

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

Database migrations run automatically on startup. Data in the oikos_data volume is preserved across container rebuilds.


Updates & Family Members

Updating Oikos

git pull
docker compose up -d --build

Migrations run automatically. Your data volume stays intact.

Adding 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. 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 © 2025 ulsklyc


Made with by ulsklyc

S
Description
Friborg-maintained Oikos core mirror/branch stack for upstreamable modular home-planning work
Readme 112 MiB
Languages
JavaScript 76.9%
CSS 17.5%
HTML 4.9%
Shell 0.7%