ulsklyc b08ba42b89 fix: CSP-Verletzung durch Inline-Script (SW-Registrierung)
Das Inline-Script in index.html für die Service-Worker-Registrierung
wurde von der Content-Security-Policy blockiert (kein 'unsafe-inline'
in script-src). Ausgelagert nach /sw-register.js ('self' erlaubt).

Außerdem: rel="preload" → rel="modulepreload" für ES-Module (korrekte
Browser-Semantik, behebt die Preload-Warnungen in der Console).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-25 09:36:10 +01:00
2026-03-24 13:46:15 +01:00

🏠 Oikos

Selbstgehosteter Familienplaner — privat, offen, ohne Abonnement

Node.js Docker SQLite PWA Lizenz: MIT

Alle Daten bleiben auf deinem eigenen Server. Kein Cloud-Zwang. Keine Datenweitergabe. Kein Tracking.

Screenshots · Module · Schnellstart · Konfiguration · Kalender-Sync · Sicherheit


Screenshots

☀️ Light Mode

Dashboard
Dashboard
Wetter · Termine · Aufgaben · Essen
Aufgaben
Aufgaben
Prioritäten · Zuweisung · Filter
Kalender
Kalender
Monatsansicht · Google & Apple Sync
Einkaufsliste
Einkauf
Mehrere Listen · Kategorien · Fortschritt
Essensplan
Essensplan
Wochenplan · Zutaten · → Einkaufsliste

🌙 Dark Mode

Dashboard Dark
Dashboard
Wetter · Termine · Aufgaben · Essen
Aufgaben Dark
Aufgaben
Prioritäten · Zuweisung · Filter
Kalender Dark
Kalender
Monatsansicht · Google & Apple Sync
Einkaufsliste Dark
Einkauf
Mehrere Listen · Kategorien · Fortschritt
Essensplan Dark
Essensplan
Wochenplan · Zutaten · → Einkaufsliste

Dark Mode wird automatisch über die Systemeinstellung des Geräts aktiviert.


Module

Modul Highlights
📋 Dashboard Wetter-Widget, anstehende Termine, dringende Aufgaben, Essen heute, Pinnwand-Vorschau
Aufgaben Listenansicht + Kanban, Teilaufgaben, Swipe-Gesten, wiederkehrende Aufgaben (RRULE)
🛒 Einkauf Mehrere Listen, automatische Kategorie-Sortierung, Integration mit Essensplan
🍽️ Essensplan Wochenansicht, Zutatenverwaltung, Zutaten → Einkaufsliste mit einem Klick
📅 Kalender Monats-/Wochen-/Tages-/Agenda-Ansicht, Google Calendar & Apple Calendar Sync
📌 Pinnwand Farbige Sticky Notes, Markdown-Light (fett, kursiv, Listen)
👥 Kontakte Wichtige Familien-Kontakte, Direktanruf (tel:), Maps-Links
💰 Budget Einnahmen/Ausgaben, Kategorien, Monatsvergleich, CSV-Export
⚙️ Einstellungen Passwort ändern, Kalender-Sync verwalten, Familienmitglieder anlegen

Tech Stack

Backend: Node.js · Express · SQLite/SQLCipher · express-session · bcrypt

Frontend: Vanilla JavaScript (ES-Module) · Kein Framework · Kein Build-Step

Deployment: Docker · Nginx Reverse Proxy · PWA (Service Worker + Manifest)

Optional: Google Calendar API v3 (OAuth 2.0) · Apple iCloud CalDAV (tsdav)


Installation

Voraussetzungen

  • Docker und Docker Compose (auf dem Server installiert)
  • Einen Linux-Server oder eine lokale Linux-Maschine
  • Für den produktiven Betrieb: eine Domain und einen Reverse Proxy mit SSL (empfohlen: Nginx Proxy Manager)

Schritt 1 — Repository klonen

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

Schritt 2 — Umgebungsvariablen konfigurieren

cp .env.example .env

Die .env-Datei mit einem Texteditor öffnen und mindestens diese Felder ausfüllen:

# Zufälliger String mit mindestens 32 Zeichen — z.B. generieren mit:
# openssl rand -base64 32
SESSION_SECRET=hier_einen_langen_zufaelligen_string_eintragen

# Verschlüsselungsschlüssel für die Datenbank (AES-256)
# Leer lassen = keine Verschlüsselung (nicht empfohlen für Produktion)
DB_ENCRYPTION_KEY=hier_einen_starken_schluessel_eintragen

Tipp: Zufällige Schlüssel lassen sich einfach im Terminal generieren:

openssl rand -base64 32

Alle verfügbaren Variablen: Konfigurationsreferenz


Schritt 3 — Container bauen und starten

docker compose up -d --build

Der erste Build dauert 23 Minuten, da SQLCipher gegen better-sqlite3 kompiliert wird. Folgende Builds sind deutlich schneller (Docker-Layer-Cache).

Den Status des Containers prüfen:

docker compose ps
docker compose logs oikos --tail=20

Der Server ist bereit, wenn in den Logs erscheint:

[Oikos] Server läuft auf Port 3000

Schritt 4 — Admin-Account anlegen

docker compose exec oikos node setup.js

Das interaktive Script fragt nach Benutzername, Anzeigename und Passwort. Dieser erste Account erhält Admin-Rechte und kann später weitere Familienmitglieder anlegen.


Schritt 5 — App öffnen und einloggen

Ohne Reverse Proxy (lokaler Test):

http://localhost:3000

Wichtig bei direktem HTTP-Zugriff ohne Reverse Proxy: Da NODE_ENV=production gesetzt ist, erwartet der Server standardmäßig HTTPS für Session-Cookies. Beim Zugriff per http:// muss daher in der .env folgende Zeile ergänzt werden:

SESSION_SECURE=false

Danach Container neu starten: docker compose down && docker compose up -d Diese Einstellung unbedingt entfernen, sobald ein Reverse Proxy mit SSL eingerichtet ist.


Schritt 6 — Reverse Proxy mit SSL einrichten (Produktion)

Für den produktiven Betrieb sollte Oikos hinter einem Nginx Reverse Proxy mit SSL betrieben werden.

Mit Nginx Proxy Manager:

  1. Neuen Proxy Host anlegen: oikos.deine-domain.delocalhost:3000
  2. SSL-Zertifikat via Let's Encrypt ausstellen
  3. Im Feld „Advanced" den Inhalt aus nginx.conf.example eintragen

Wichtig: Der Header X-Forwarded-Proto muss gesetzt sein (ist in der Beispielkonfiguration enthalten). Ohne ihn weiß der Server nicht, dass er hinter HTTPS läuft, und setzt Cookies nicht korrekt.

Sobald SSL aktiv ist: SESSION_SECURE=false aus der .env entfernen und Container neu starten.


Konfiguration

Pflichtfelder

Variable Beschreibung
SESSION_SECRET Zufälliger String ≥ 32 Zeichen für Session-Signing
DB_ENCRYPTION_KEY SQLCipher AES-256-Schlüssel (leer lassen = keine Verschlüsselung)

Sicherheit

Variable Standard Beschreibung
SESSION_SECURE (nicht gesetzt) false setzen wenn kein HTTPS-Reverse-Proxy vorhanden (direktes HTTP)
RATE_LIMIT_MAX_ATTEMPTS 5 Max. Login-Versuche pro Minute pro IP

Wetter-Widget

Kostenlosen API-Key bei openweathermap.org registrieren:

OPENWEATHER_API_KEY=dein_api_key
OPENWEATHER_CITY=Berlin
OPENWEATHER_UNITS=metric   # metric = °C, imperial = °F
OPENWEATHER_LANG=de

Weitere Optionen

Variable Standard Beschreibung
PORT 3000 Server-Port
NODE_ENV production Umgebung (nicht ändern)
DB_PATH /data/oikos.db Pfad zur SQLite-Datei im Container
SYNC_INTERVAL_MINUTES 15 Automatischer Kalender-Sync-Intervall

Vollständige Vorlage: .env.example


Kalender-Synchronisation

Google Calendar

Einrichtung anzeigen

Google Cloud Console vorbereiten

  1. Projekt unter console.cloud.google.com anlegen
  2. Google Calendar API aktivieren
  3. OAuth 2.0-Client-ID erstellen (Typ: „Webanwendung")
  4. Autorisierte Redirect-URI eintragen:
    https://oikos.deine-domain.de/api/v1/calendar/google/callback
    
  5. In .env eintragen:
    GOOGLE_CLIENT_ID=...
    GOOGLE_CLIENT_SECRET=...
    GOOGLE_REDIRECT_URI=https://oikos.deine-domain.de/api/v1/calendar/google/callback
    
  6. Container neu starten: docker compose up -d

Verbindung herstellen

  1. Mit einem Admin-Konto einloggen
  2. Einstellungen → Kalender-Synchronisation → Mit Google verbinden
  3. Google-Konto autorisieren → automatische Weiterleitung zurück

Sync-Verhalten:

  • Erster Sync: Events der letzten 3 Monate + nächsten 12 Monate
  • Folge-Syncs: nur Änderungen via Google syncToken (effizient)
  • Outbound: neue lokale Termine werden nach Google übertragen
  • Konflikt: Google gewinnt bei gleichzeitiger Änderung

Apple Calendar (iCloud CalDAV)

Einrichtung anzeigen

App-spezifisches Passwort erstellen

  1. appleid.apple.com → „Anmeldung und Sicherheit" → „App-spezifische Passwörter"
  2. Neues Passwort für „Oikos" erstellen
  3. In .env eintragen:
    APPLE_CALDAV_URL=https://caldav.icloud.com
    APPLE_USERNAME=deine@apple-id.de
    APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx
    
  4. Container neu starten: docker compose up -d

Der Sync-Button erscheint automatisch in den Einstellungen.


Familienmitglieder

Neue Mitglieder können nur Admins anlegen — es gibt keinen öffentlichen Registrierungs-Endpoint.

Im Browser: Einstellungen → Familienmitglieder → Mitglied hinzufügen

Per Script (z.B. für weiteren Admin):

docker compose exec oikos node setup.js

Updates

git pull
docker compose up -d --build

Datenbank-Migrationen laufen automatisch beim Start — kein manueller Eingriff nötig. Alle Daten im Volume oikos_data bleiben erhalten.

Empfehlung: Vor jedem Update ein Backup erstellen — siehe Datensicherung.


Entwicklung

npm install
cp .env.example .env
# SESSION_SECRET setzen — DB_ENCRYPTION_KEY weglassen (kein SQLCipher lokal)
npm run dev        # Server mit Auto-Reload
npm test           # 146 Tests, 7 Suiten (In-Memory-SQLite, keine laufende App nötig)

Datensicherung

# Backup erstellen
docker run --rm \
  -v oikos_oikos_data:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/oikos-backup-$(date +%Y%m%d).tar.gz /data

# Backup wiederherstellen
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

Sicherheit

  • Sessions: httpOnly, SameSite=Strict, Secure in Produktion, 7 Tage TTL
  • CSRF-Schutz via Double Submit Cookie auf allen schreibenden Requests
  • Passwörter mit bcrypt (Cost Factor 12) gehasht
  • Login-Rate-Limit: 5 Versuche/Minute
  • API-Rate-Limit: 300 Requests/Minute pro IP
  • Content Security Policy via Helmet
  • Datenbank optional mit SQLCipher AES-256 verschlüsselt (im Docker-Container)
  • Kein API-Endpoint ohne Session-Auth erreichbar (außer /api/v1/auth/login)

Lizenz

MIT © 2025 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%