5.8 KiB
AGENTS.md
Richtlinien für AI-Agenten die mit dem calender_sync Projekt arbeiten.
Projektübersicht
Python-basierter Google Calendar → MariaDB Synchronizer. Läuft als Docker Container im Homelab und pollt periodisch einen ICS-Feed.
Technologie-Stack
- Sprache: Python 3.12
- Datenbank: MariaDB (mysql-connector-python) oder SQLite (stdlib) via
DB_BACKENDEnv-Var - API: FastAPI + Uvicorn + Jinja2
- Docker: Multi-Stage Build nicht verwendet, simples Slim-Image
- Dependencies: requests, icalendar, recurring-ical-events, mysql-connector-python, fastapi, uvicorn, jinja2
Projektstruktur
.
├── sync.py # Hauptskript (alles in einer Datei)
├── api/
│ ├── main.py # FastAPI App (REST API + HTML UI)
│ ├── database.py # DB-Verbindung (MySQL + SQLite)
│ └── templates/
│ └── index.html # Jinja2 Template für Web-UI
├── demo/
│ └── seed.py # SQLite Demo-Datenbank erstellen
├── demo.sh # Lokaler Demo-Start (ohne Docker)
├── requirements.txt # Python Dependencies
├── Dockerfile # Docker Image Definition
├── docker-compose.yml # Docker Compose Konfiguration
├── mariadb-setup.sql # Manuelles DB-Setup Script
├── .env.example # Beispiel-Umgebungsvariablen
└── .github/workflows/ # CI/CD (Docker Build + Push)
Wichtige Hinweise
Kein Framework
Das Projekt verwendet kein Web-Framework für den Sync-Teil. sync.py ist ein eigenständiges Python-Skript mit einer Endlosschleife (main() → time.sleep()).
FastAPI Applikation
Die API (api/main.py) ist eine separarte FastAPI-App die als eigenständiger Container läuft:
- Web-UI:
GET /- Jinja2 Template mit anstehenden Termine und Suchfunktion - REST API:
GET /api/events- JSON-Liste zukünftiger Events - Einzeln-Event:
GET /api/events/{id}- Einzelnes Event als JSON - Health Check:
GET /api/health- Gibt{"status": "ok"}zurück - Läuft über Uvicorn auf Port 8000
- Teilt sich die Datenbank mit
sync.py, verwendet aber eigene DB-Verbindung (api/database.py)
Datenbank-Schema
Schema wird in ensure_schema() per CREATE TABLE IF NOT EXISTS erstellt. Bei Schema-Änderungen:
ensure_schema()insync.py:83anpassen- MariaDB-kompatibles SQL verwenden (kein PostgreSQL-Specific)
- Indexe für Performance bedenken
Event-Expansion
Verwendet recurring_ical_events Bibliothek für RRULE/EXDATE/RECURRENCE-ID Expansion. Fenster wird über WINDOW_PAST_DAYS/WINDOW_FUTURE_DAYS gesteuert.
UTC-Normalisierung
Alle Zeiten werden in naive UTC datetime konvertiert (to_naive_utc()). Bei Datumsänderungen sicherstellen, dass die Zeitzone korrekt verarbeitet wird.
Soft-Delete
Events werden nicht gelöscht, sondern mit deleted=1 markiert (mark_missing_as_deleted()).
Tägliche E-Mail-Benachrichtigung
Sendet täglich um konfigurierte Uhrzeit eine HTML-Email mit anstehenden Terminen:
- Nur Termine mit Uhrzeit (
all_day=0), keine Ganztagstermine - Subject: Bei 1 Termin direkt "Kalender heute: HH:MM - Termin", bei mehreren "Kalender heute: X Termine"
- Tracking via
daily_notification_logTabelle (verhindert Doppelversand) - Konfiguration über SMTP_* und NOTIFY_* Umgebungsvariablen
- Funktionen:
get_today_events(),should_notify(),send_notification(),log_notification()
Wöchentliche E-Mail-Benachrichtigung (Vorab-Info)
Sendet wöchentlich (standardmäßig Freitags) eine HTML-Email mit Terminen, die auf Suchbegriffe passen:
- Sucht nach Begriffen in summary, description und location
- Zeitraum: Samstag bis Freitag der nächsten Woche
- Subject: Bei 1 Termin "Vorab-Info: Termin am Mo, DD.MM.", bei mehreren "Vorab-Info: X Termine nächste Woche"
- Tracking via
weekly_notification_logTabelle (verhindert Doppelversand) - Nur Termine mit Uhrzeit (
all_day=0), keine Ganztagstermine - Keine Email wenn keine Treffer
- Konfiguration über WEEKLY_* Umgebungsvariablen
- Funktionen:
parse_weekly_searchwords(),get_weekly_events(),should_send_weekly(),send_weekly_notification(),log_weekly_notification(),check_and_send_weekly_notification()
Entwicklung
Lokaler Test (Docker)
# Dependencies installieren
pip install -r requirements.txt
# .env anlegen (aus .env.example kopieren)
cp .env.example .env
# Direkt ausführen
python sync.py
Lokaler Test (Demo, ohne MariaDB)
# Startet venv, erstellt SQLite Demo-DB mit 4 Events, startet API
./demo.sh
Oder manuell:
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python demo/seed.py
DB_BACKEND=sqlite DB_PATH=demo/demo.db python -m uvicorn api.main:app --port 8000
Linting & Type Checking
Keine Linting/Type-Checking Tools konfiguriert. Bei Bedarf hinzufügen:
rufffür Lintingmypyfür Type Checking
Tests
Keine Tests vorhanden. Bei Bedarf:
pytestals Test-Framework verwenden- Mock für
requests.get()undmysql.connectorerstellen - Unit Tests für
to_naive_utc(),instance_key_for(),expand_events()
Code-Style
- Kein Docstring-Standard definiert
- Logging über
loggingModul mit configurable Level - Error Handling: Exceptions fangen, loggen, aber nicht verschlucken
- Keine externen Config-Libraries (nur
os.environ)
Docker
- Image basiert auf
python:3.12-slim - Kein Multi-Stage Build nötig (einfaches Projekt)
PYTHONUNBUFFERED=1für Logging im Container- Watchtower Label für Auto-Updates
CI/CD
GitHub Actions Workflow:
- Baut Docker Image bei Push zu
main - Published nach
ghcr.io/skoelle/calender_sync:latest - Keine Tests im Workflow (derzeit)
Lizenz
MIT License - Copyright (c) 2026 Stefan Koelle (https://stefankoelle.de)
- Vollständiger Text in
LICENSE - Lizenz-Header in allen Python-Dateien