mirror of
https://github.com/skoelle/calender_sync.git
synced 2026-09-17 18:20:24 +00:00
README.md
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
title: "Google Calender Sync"
|
||||
emoji: "📅"
|
||||
category: code
|
||||
subcategory: "Smart Home Apps"
|
||||
status: active
|
||||
stack: [Python, FastAPI, Uvicorn, Jinja2]
|
||||
@@ -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
|
||||
|
||||
[](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)
|
||||
|
||||
Reference in New Issue
Block a user