diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7634e59..bc994a9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,8 @@ public/ components/ # Reusable Web Components (oikos-* prefix) pages/ # Page modules — each exports a render() function sw.js # Service worker -tests/ # One test file per module + offline.html # Offline fallback page (served by service worker) +test-[module].js # One test file per module (project root) docs/ # Product spec, screenshots ``` @@ -195,7 +196,7 @@ PRs are reviewed by the maintainer. Expect feedback within a few days. Once appr ### Testing -- One test file per module in `tests/` +- One test file per module in the project root (`test-[module].js`) - Tests use in-memory SQLite via `--experimental-sqlite` - Import route handlers directly — no HTTP calls, no running server diff --git a/README.md b/README.md index c9acf2c..c5e4f5c 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@

MIT License - Node.js ≥20 + Node.js ≥22 Docker Ready SQLCipher Encrypted PWA Offline @@ -115,8 +115,8 @@ Oikos is **not** a SaaS product, not a team collaboration tool, and not designed | 🛒 | **Shopping** | Collaborative grocery lists | Multiple lists · aisle-grouped categories · auto-import from meal plan | | 🍽️ | **Meals** | Weekly meal planning with ingredients | 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 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 | +| 📌 | **Notes** | Shared family pinboard | Colored sticky notes · pinning · full-text search · lightweight Markdown (bold, italic, lists) | +| 👥 | **Contacts** | Important family contacts | Category filters · tap-to-call · tap-to-email · map links · vCard import/export | | 💰 | **Budget** | Income & expense tracking | Category breakdown · month-over-month comparison · CSV export | | ⚙️ | **Settings** | User & sync management | Password changes · calendar sync config · family member admin | @@ -134,7 +134,7 @@ Oikos is **not** a SaaS product, not a team collaboration tool, and not designed | Layer | Technology | |---|---| -| **Server** | Node.js ≥ 20 · Express · better-sqlite3 · bcrypt · Helmet | +| **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 SVG sprite) | | **Auth** | Session-based · httpOnly cookies · CSRF double-submit · express-session | @@ -266,17 +266,23 @@ Oikos syncs bidirectionally with Google Calendar and Apple iCloud. External even ### 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. 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` +3. In Oikos: **Settings → Calendar Sync → Apple Calendar** → enter the CalDAV URL, Apple ID email and the app-specific password → click **Verbinden & testen** -The sync button appears automatically in Settings. +Credentials are stored in the database. No server restart required. + +**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. @@ -401,7 +407,7 @@ Only admins can create new accounts — there is no public registration endpoint 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. +See [`CONTRIBUTING.md`](CONTRIBUTING.md) for setup instructions, code conventions, commit format, and workflow. --- diff --git a/docs/SPEC.md b/docs/SPEC.md index d0bb5db..ee57c00 100644 --- a/docs/SPEC.md +++ b/docs/SPEC.md @@ -109,8 +109,26 @@ Jede Tabelle: `id INTEGER PRIMARY KEY`, `created_at TEXT`, `updated_at TEXT` (IS | date | TEXT | DATE, NOT NULL | | is_recurring | INTEGER | 0/1 | | recurrence_rule | TEXT | iCal RRULE | +| recurrence_parent_id | INTEGER | FK → Budget Entries (generierte Instanz zeigt auf Original) | | created_by | INTEGER | FK → Users, NOT NULL | +### Budget Recurrence Skipped +Speichert vom Nutzer gelöschte Instanzen eines wiederkehrenden Eintrags, damit sie nicht erneut generiert werden. + +| Spalte | Typ | Constraint | +|--------|-----|-----------| +| parent_id | INTEGER | FK → Budget Entries, NOT NULL | +| month | TEXT | YYYY-MM, NOT NULL | +| PRIMARY KEY | | (parent_id, month) | + +### Sync Config +Schlüssel-Wert-Tabelle für OAuth-Tokens und CalDAV-Credentials. + +| Spalte | Typ | Constraint | +|--------|-----|-----------| +| key | TEXT | PRIMARY KEY | +| value | TEXT | NOT NULL | + --- ## Module @@ -185,6 +203,7 @@ Masonry-Grid mit farbigen Sticky Notes. - Anpinnen → erscheint oben + Dashboard - Ersteller angezeigt (Avatar-Farbe) - Markdown-Light: fett, kursiv, Listen (regex-basiert) +- Volltextsuche: client-seitige Filterleiste, filtert sofort nach Titel + Inhalt ### Kontakte (`/contacts`) @@ -192,6 +211,8 @@ Masonry-Grid mit farbigen Sticky Notes. - Telefon: `tel:`-Link, E-Mail: `mailto:`-Link - Adresse: Maps-Link (Google/Apple via User-Agent) - Echtzeit-Suchfilter +- vCard-Export: jeder Kontakt als `.vcf` herunterladbar (`GET /api/v1/contacts/:id/vcard`) +- vCard-Import: Datei hochladen → client-seitiger Parser (FN, TEL, EMAIL, ADR, NOTE, CATEGORIES) → Kontakt anlegen ### Login (`/login`)