From 3fccf6df67ca80cd00fe6fef6ce5dd6b5825f2e4 Mon Sep 17 00:00:00 2001 From: Stefan Koelle Date: Fri, 14 Aug 2026 23:43:40 +0200 Subject: [PATCH] README.md --- .moonweb.yml | 6 ++ README.md | 160 +++++++++++++++++++++++++-------------------------- 2 files changed, 86 insertions(+), 80 deletions(-) create mode 100644 .moonweb.yml diff --git a/.moonweb.yml b/.moonweb.yml new file mode 100644 index 0000000..564b8f2 --- /dev/null +++ b/.moonweb.yml @@ -0,0 +1,6 @@ +title: "Google Calender Sync" +emoji: "📅" +category: code +subcategory: "Smart Home Apps" +status: active +stack: [Python, FastAPI, Uvicorn, Jinja2] diff --git a/README.md b/README.md index c56b80e..61639ba 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,32 @@ -# calender_sync +# 📅 calender_sync -Google Calendar (ICS-Feed) → MariaDB Sync fürs Homelab. +> Google Calendar (ICS-Feed) → MariaDB Sync fürs Homelab. Läuft als Docker Container, pollt periodisch einen privaten Google Calendar ICS-Feed, expandiert RRULE/EXDATE/RECURRENCE-ID und schreibt einzelne Instanzen in eine MariaDB-Datenbank. -## Features +## ✨ Features -- Automatische Synchronisation alle 15 Minuten (konfigurierbar) -- Expandiert wiederkehrende Events (RRULE) und Serien-Exceptions (EXDATE, RECURRENCE-ID) -- Soft-Delete: Entfernte Events werden als `deleted=1` markiert, nicht gelöscht -- Optionales Database-Bootstrap: Erstellt DB und User automatisch bei `DB_BOOTSTRAP=true` -- Zeitfenster-konfiguration für Vergangenheit/Future (standardmäßig -90 Tage / +365 Tage) -- Web-UI zur Anzeige anstehender Termine mit Suchfunktion -- REST API für programmsprachigen Zugriff auf Kalenderdaten -- Optionale tägliche E-Mail-Benachrichtigung um konfigurierte Uhrzeit -- Optionale wöchentliche Vorab-Info (z.B. freitags) mit Termine nach Suchbegriffen +- 🔄 Automatische Synchronisation alle 15 Minuten (konfigurierbar) +- 📆 Expandiert wiederkehrende Events (RRULE) und Serien-Exceptions (EXDATE, RECURRENCE-ID) +- 🗑️ Soft-Delete: Entfernte Events werden als `deleted=1` markiert, nicht gelöscht +- 🛠️ Optionales Database-Bootstrap: Erstellt DB und User automatisch bei `DB_BOOTSTRAP=true` +- ⏰ Zeitfenster-konfiguration für Vergangenheit/Future (standardmäßig -90 Tage / +365 Tage) +- 🌐 Web-UI zur Anzeige anstehender Termine mit Suchfunktion +- 🔌 REST API für programmsprachigen Zugriff auf Kalenderdaten +- 📧 Optionale tägliche E-Mail-Benachrichtigung um konfigurierte Uhrzeit +- 📬 Optionale wöchentliche Vorab-Info (z.B. freitags) mit Termine nach Suchbegriffen [![UI](docs/screenshot_thumbnail.png)](docs/screenshot.png) -## Voraussetzungen +## 📋 Voraussetzungen -- Docker & Docker Compose -- MariaDB Instanz (z.B. als Proxmox LXC) -- Google Calendar mit privatem ICS-Feed +- 🐳 Docker & Docker Compose +- 🗃️ MariaDB Instanz (z.B. als Proxmox LXC) +- 📱 Google Calendar mit privatem ICS-Feed -## Quick Start +## 🚀 Quick Start -1. **MariaDB Setup** +1. **🔧 MariaDB Setup** Entweder manuell ausführen: ```bash @@ -40,7 +40,7 @@ Läuft als Docker Container, pollt periodisch einen privaten Google Calendar ICS DB_ROOT_PASSWORD=dein_root_passwort ``` -2. **.env anlegen** +2. **📄 .env anlegen** ```bash cp .env.example .env @@ -50,13 +50,13 @@ Läuft als Docker Container, pollt periodisch einen privaten Google Calendar ICS - `ICS_URL`: Privater ICS-Link aus den Google Calendar Einstellungen - `DB_PASSWORD`: Sicheres Passwort für den calendar_sync User -3. **Starten** +3. **▶️ Starten** ```bash docker compose up -d ``` -## Demo / Lokaler Test (ohne Docker) +## 🎮 Demo / Lokaler Test (ohne Docker) Schneller Weg um Web-UI und API lokal zu testen, ohne MariaDB oder Docker: @@ -66,22 +66,22 @@ Schneller Weg um Web-UI und API lokal zu testen, ohne MariaDB oder Docker: Das Script erstellt eine virtuelle Python-Umgebung, installiert Dependencies, legt eine SQLite Demo-Datenbank mit 4 Beispiel-Terminen an und startet die API auf Port 8000. -**Endpoints:** -- Web-UI: http://localhost:8000/ -- API JSON: http://localhost:8000/api/events -- Health: http://localhost:8000/api/health +**🔗 Endpoints:** +- 🌐 Web-UI: http://localhost:8000/ +- 📊 API JSON: http://localhost:8000/api/events +- ❤️ Health: http://localhost:8000/api/health -**Demo-Events (4 Stück):** +**🎯 Demo-Events (4 Stück):** | Termin | Zeit | Status | |--------|------|--------| -| Team Daily | heute 14:00–15:00 | CONFIRMED | -| Yoga Kurs | heute 18:30–20:00 | CONFIRMED | -| Projekt-Deadline | morgen Ganztag | TENTATIVE | -| Arzttermin | übermorgen 10:00–11:30 | CONFIRMED | +| 📅 Team Daily | heute 14:00–15:00 | ✅ CONFIRMED | +| 🧘 Yoga Kurs | heute 18:30–20:00 | ✅ CONFIRMED | +| ⚠️ Projekt-Deadline | morgen Ganztag | 🟡 TENTATIVE | +| 👨‍⚕️ Arzttermin | übermorgen 10:00–11:30 | ✅ CONFIRMED | Die Demo verwendet SQLite (`DB_BACKEND=sqlite`) statt MariaDB. Die Events werden relativ zum heutigen Datum erstellt. -## Konfiguration +## ⚙️ Konfiguration | Variable | Default | Beschreibung | |----------|---------|--------------| @@ -102,7 +102,7 @@ Die Demo verwendet SQLite (`DB_BACKEND=sqlite`) statt MariaDB. Die Events werden | `API_PORT` | `8000` | Port für den API/Web-UI Container | | `TIMEZONE` | `UTC` | Zeitzone für API/Web-UI Anzeige (z.B. `Europe/Berlin`) | -### Optionale E-Mail-Benachrichtigung +### 📧 Optionale E-Mail-Benachrichtigung Sendet täglich eine HTML-Email mit den anstehenden Terminen. Wird aktiviert wenn `SMTP_HOST` und `NOTIFY_EMAIL` gesetzt sind. @@ -118,13 +118,13 @@ Sendet täglich eine HTML-Email mit den anstehenden Terminen. Wird aktiviert wen | `NOTIFY_TIME` | `6` | Uhrzeit für Benachrichtigung (Stunde, 0-23) | | `NOTIFY_TIMEZONE` | `Europe/Berlin` | Zeitzone für die Benachrichtigung | -**Subject-Logik:** -- 1 Termin: `Kalender heute: 09:00 - Meeting mit Team` -- 2+ Termine: `Kalender heute: 3 Termine` +**📬 Subject-Logik:** +- 📌 1 Termin: `Kalender heute: 09:00 - Meeting mit Team` +- 📌 2+ Termine: `Kalender heute: 3 Termine` -**Hinweis:** Ganztagstermine werden nicht in der Benachrichtigung berücksichtigt. +**⚠️ Hinweis:** Ganztagstermine werden nicht in der Benachrichtigung berücksichtigt. -### Optionale wöchentliche Vorab-Info +### 📬 Optionale wöchentliche Vorab-Info Sendet wöchentlich (standardmäßig freitags) eine HTML-Email mit Terminen, die auf konfigurierte Suchbegriffe passen. Zeitraum ist immer Samstag bis Freitag der nächsten Woche. Wird aktiviert wenn `WEEKLY_NOTIFY_ENABLED=true` und mindestens ein Suchbegriff gesetzt ist. @@ -137,11 +137,11 @@ Sendet wöchentlich (standardmäßig freitags) eine HTML-Email mit Terminen, die | `WEEKLY_NOTIFY_EMAIL` | - | Empfänger (Fallback: `NOTIFY_EMAIL`) | | `WEEKLY_SEARCHWORDS` | - | Komma-separierte Suchbegriffe | -**Subject-Logik:** -- 1 Termin: `Vorab-Info: Termin am Fr, 15.08.` -- 2+ Termine: `Vorab-Info: 3 Termine naechste Woche` +**📬 Subject-Logik:** +- 📌 1 Termin: `Vorab-Info: Termin am Fr, 15.08.` +- 📌 2+ Termine: `Vorab-Info: 3 Termine naechste Woche` -**Beispiel:** +**💡 Beispiel:** ```bash WEEKLY_NOTIFY_ENABLED=true WEEKLY_NOTIFY_DAY=5 @@ -149,63 +149,63 @@ WEEKLY_NOTIFY_TIME=16 WEEKLY_SEARCHWORDS=Fussball,Arzttermine ``` -**Hinweis:** Keine Email wenn keine Treffer für die Suchbegriffe im Zeitraum. +**⚠️ Hinweis:** Keine Email wenn keine Treffer für die Suchbegriffe im Zeitraum. -## Datenbank-Schema +## 🗃️ Datenbank-Schema -Tabelle `calendar_events`: +**Tabelle `calendar_events`:** | Spalte | Typ | Beschreibung | |--------|-----|--------------| -| `id` | BIGINT PK | Auto-Increment | -| `calendar_label` | VARCHAR(64) | Kalender-Label | -| `instance_key` | VARCHAR(255) | SHA1-basierte eindeutige Instanz-ID | -| `uid` | VARCHAR(255) | ICS UID | -| `recurrence_id` | VARCHAR(64) | RECURRENCE-ID bei Serien-Exceptions | -| `summary` | VARCHAR(512) | Titel | -| `description` | TEXT | Beschreibung | -| `location` | VARCHAR(512) | Ort | -| `start_at` | DATETIME | Startzeit (UTC) | -| `end_at` | DATETIME | Endzeit (UTC) | -| `all_day` | TINYINT(1) | Ganz-tagig Flag | -| `status` | VARCHAR(32) | Event-Status | -| `deleted` | TINYINT(1) | Soft-Delete Flag | -| `last_seen_at` | DATETIME | Letzte Synchronisation | -| `created_at` | DATETIME | Erstellungszeitpunkt | -| `updated_at` | DATETIME | Letzte Änderung | +| `id` | 🆔 BIGINT PK | Auto-Increment | +| `calendar_label` | 🏷️ VARCHAR(64) | Kalender-Label | +| `instance_key` | 🔑 VARCHAR(255) | SHA1-basierte eindeutige Instanz-ID | +| `uid` | 📌 VARCHAR(255) | ICS UID | +| `recurrence_id` | 🔄 VARCHAR(64) | RECURRENCE-ID bei Serien-Exceptions | +| `summary` | 📝 VARCHAR(512) | Titel | +| `description` | 📄 TEXT | Beschreibung | +| `location` | 📍 VARCHAR(512) | Ort | +| `start_at` | 🚀 DATETIME | Startzeit (UTC) | +| `end_at` | 🏁 DATETIME | Endzeit (UTC) | +| `all_day` | ☀️ TINYINT(1) | Ganz-tagig Flag | +| `status` | 📊 VARCHAR(32) | Event-Status | +| `deleted` | 🗑️ TINYINT(1) | Soft-Delete Flag | +| `last_seen_at` | 👁️ DATETIME | Letzte Synchronisation | +| `created_at` | 🎨 DATETIME | Erstellungszeitpunkt | +| `updated_at` | 🔄 DATETIME | Letzte Änderung | -Tabelle `daily_notification_log` (optional, für E-Mail-Benachrichtigung): +**Tabelle `daily_notification_log` (optional, für E-Mail-Benachrichtigung):** | Spalte | Typ | Beschreibung | |--------|-----|--------------| -| `id` | INT PK | Auto-Increment | -| `notify_date` | DATE | Datum der Benachrichtigung | -| `sent_at` | DATETIME | Zeitpunkt des Versands | -| `event_count` | INT | Anzahl Termine in der Email | +| `id` | 🆔 INT PK | Auto-Increment | +| `notify_date` | 📅 DATE | Datum der Benachrichtigung | +| `sent_at` | ⏰ DATETIME | Zeitpunkt des Versands | +| `event_count` | 🔢 INT | Anzahl Termine in der Email | -Tabelle `weekly_notification_log` (optional, für wöchentliche Vorab-Info): +**Tabelle `weekly_notification_log` (optional, für wöchentliche Vorab-Info):** | Spalte | Typ | Beschreibung | |--------|-----|--------------| -| `id` | INT PK | Auto-Increment | -| `notify_date` | DATE | Datum der Benachrichtigung | -| `sent_at` | DATETIME | Zeitpunkt des Versands | -| `event_count` | INT | Anzahl Termine in der Email | +| `id` | 🆔 INT PK | Auto-Increment | +| `notify_date` | 📅 DATE | Datum der Benachrichtigung | +| `sent_at` | ⏰ DATETIME | Zeitpunkt des Versands | +| `event_count` | 🔢 INT | Anzahl Termine in der Email | -## Web-UI & API +## 🌐 Web-UI & API Das Projekt enthält eine FastAPI-basierte Webanwendung die als separater Container (`calendar-api`) läuft und auf Port `8000` erreichbar ist. -### Endpoints +### 🔗 Endpoints | Endpoint | Beschreibung | |----------|--------------| -| `GET /` | HTML-Seite mit anstehenden Terminen und Suchfunktion | -| `GET /api/health` | Health Check (gibt `{"status": "ok"}` zurück) | -| `GET /api/events?limit=10&search=...` | JSON-Liste zukünftiger Events (nicht gelöscht) | -| `GET /api/events/{event_id}` | Einzelnes Event als JSON | +| `GET /` | 🌐 HTML-Seite mit anstehenden Terminen und Suchfunktion | +| `GET /api/health` | ❤️ Health Check (gibt `{"status": "ok"}` zurück) | +| `GET /api/events?limit=10&search=...` | 📊 JSON-Liste zukünftiger Events (nicht gelöscht) | +| `GET /api/events/{event_id}` | 🔍 Einzelnes Event als JSON | -### API Beispiel +### 💡 API Beispiel ```bash # Alle anstehenden Events (max. 10) @@ -218,7 +218,7 @@ curl "http://localhost:8000/api/events?search=Meeting&limit=5" curl http://localhost:8000/api/events/42 ``` -### JSON Response Format +### 📋 JSON Response Format ```json { @@ -241,7 +241,7 @@ curl http://localhost:8000/api/events/42 } ``` -## CI/CD +## 🔄 CI/CD GitHub Actions Workflow (`docker-publish.yml`) baut und published das Docker Image automatisch nach GitHub Container Registry: @@ -249,6 +249,6 @@ GitHub Actions Workflow (`docker-publish.yml`) baut und published das Docker Ima ghcr.io/skoelle/calender_sync:latest ``` -## Lizenz +## 📜 Lizenz Lizenziert unter der [MIT License](LICENSE) - Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de)