From e10c6fc16984bd38721b6a2e905643cb8e8a1c7f Mon Sep 17 00:00:00 2001 From: Stefan Koelle Date: Mon, 10 Aug 2026 17:01:27 +0200 Subject: [PATCH] demo showcase README.md --- AGENTS.md | 23 ++++++++++++++++++++--- README.md | 25 +++++++++++++++++++++++++ api/templates/index.html | 2 +- demo/seed.py | 29 +++++++++++++++++------------ 4 files changed, 63 insertions(+), 16 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 9a01392..608bac5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -9,7 +9,7 @@ Python-basierter Google Calendar → MariaDB Synchronizer. Läuft als Docker Con ## Technologie-Stack - **Sprache**: Python 3.12 -- **Datenbank**: MariaDB (mysql-connector-python) +- **Datenbank**: MariaDB (mysql-connector-python) oder SQLite (stdlib) via `DB_BACKEND` Env-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 @@ -21,9 +21,12 @@ Python-basierter Google Calendar → MariaDB Synchronizer. Läuft als Docker Con ├── sync.py # Hauptskript (alles in einer Datei) ├── api/ │ ├── main.py # FastAPI App (REST API + HTML UI) -│ ├── database.py # DB-Verbindung für die API +│ ├── 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 @@ -71,7 +74,7 @@ Sendet täglich um konfigurierte Uhrzeit eine HTML-Email mit anstehenden Termine ## Entwicklung -### Lokaler Test +### Lokaler Test (Docker) ```bash # Dependencies installieren pip install -r requirements.txt @@ -83,6 +86,20 @@ cp .env.example .env python sync.py ``` +### Lokaler Test (Demo, ohne MariaDB) +```bash +# Startet venv, erstellt SQLite Demo-DB mit 4 Events, startet API +./demo.sh +``` + +Oder manuell: +```bash +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: - `ruff` für Linting diff --git a/README.md b/README.md index 377fea6..47d32c3 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,31 @@ Läuft als Docker Container, pollt periodisch einen privaten Google Calendar ICS docker compose up -d ``` +## Demo / Lokaler Test (ohne Docker) + +Schneller Weg um Web-UI und API lokal zu testen, ohne MariaDB oder Docker: + +```bash +./demo.sh +``` + +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 + +**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 | + +Die Demo verwendet SQLite (`DB_BACKEND=sqlite`) statt MariaDB. Die Events werden relativ zum heutigen Datum erstellt. + ## Konfiguration | Variable | Default | Beschreibung | diff --git a/api/templates/index.html b/api/templates/index.html index 6de8b79..974e12e 100644 --- a/api/templates/index.html +++ b/api/templates/index.html @@ -116,7 +116,7 @@ } .event-location::before { - content: "\\1F4CD "; + content: "\1F4CD "; } .badge { diff --git a/demo/seed.py b/demo/seed.py index ced3f00..e6c7389 100644 --- a/demo/seed.py +++ b/demo/seed.py @@ -42,52 +42,57 @@ def seed(): now = datetime.now().replace(second=0, microsecond=0, tzinfo=None) today = now.replace(hour=0, minute=0, second=0) + # Wenn es nach 14 Uhr ist, alle Termine einen Tag verschieben + # damit sie in der Demo immer sichtbar sind + day_offset = 1 if now.hour >= 14 else 0 + base = today + timedelta(days=day_offset) + events = [ { "calendar_label": "demo", - "instance_key": f"team-daily-{today.strftime('%Y%m%d')}", + "instance_key": f"team-daily-{base.strftime('%Y%m%d')}", "uid": "team-daily-001@demo", "summary": "Team Daily", "description": "Tägliches Standup-Meeting mit dem gesamten Team.", "location": "Besprechungsraum A / Zoom", - "start_at": (today + timedelta(hours=14)).strftime("%Y-%m-%d %H:%M:%S"), - "end_at": (today + timedelta(hours=15)).strftime("%Y-%m-%d %H:%M:%S"), + "start_at": (base + timedelta(hours=14)).strftime("%Y-%m-%d %H:%M:%S"), + "end_at": (base + timedelta(hours=15)).strftime("%Y-%m-%d %H:%M:%S"), "all_day": 0, "status": "CONFIRMED", }, { "calendar_label": "demo", - "instance_key": f"yoga-{today.strftime('%Y%m%d')}", + "instance_key": f"yoga-{base.strftime('%Y%m%d')}", "uid": "yoga-002@demo", "summary": "Yoga Kurs", "description": "Wöchentlicher Yoga-Kurs in der Volkshochschule.", "location": "Volkshochschule, Raum 204", - "start_at": (today + timedelta(hours=18, minutes=30)).strftime("%Y-%m-%d %H:%M:%S"), - "end_at": (today + timedelta(hours=20)).strftime("%Y-%m-%d %H:%M:%S"), + "start_at": (base + timedelta(hours=18, minutes=30)).strftime("%Y-%m-%d %H:%M:%S"), + "end_at": (base + timedelta(hours=20)).strftime("%Y-%m-%d %H:%M:%S"), "all_day": 0, "status": "CONFIRMED", }, { "calendar_label": "demo", - "instance_key": f"deadline-{(today + timedelta(days=1)).strftime('%Y%m%d')}", + "instance_key": f"deadline-{(base + timedelta(days=1)).strftime('%Y%m%d')}", "uid": "deadline-003@demo", "summary": "Projekt-Deadline", "description": "Abgabe des Projektberichts an die Geschäftsleitung.", "location": "", - "start_at": (today + timedelta(days=1)).strftime("%Y-%m-%d 00:00:00"), - "end_at": (today + timedelta(days=1)).strftime("%Y-%m-%d 23:59:59"), + "start_at": (base + timedelta(days=1)).strftime("%Y-%m-%d 00:00:00"), + "end_at": (base + timedelta(days=1)).strftime("%Y-%m-%d 23:59:59"), "all_day": 1, "status": "TENTATIVE", }, { "calendar_label": "demo", - "instance_key": f"arzt-{(today + timedelta(days=2)).strftime('%Y%m%d')}", + "instance_key": f"arzt-{(base + timedelta(days=2)).strftime('%Y%m%d')}", "uid": "arzt-004@demo", "summary": "Arzttermin", "description": "Routineuntersuchung beim Hausarzt. Bitte Impfpass mitbringen.", "location": "Dr. Müller, Gesundheitsstraße 12", - "start_at": (today + timedelta(days=2, hours=10)).strftime("%Y-%m-%d %H:%M:%S"), - "end_at": (today + timedelta(days=2, hours=11, minutes=30)).strftime("%Y-%m-%d %H:%M:%S"), + "start_at": (base + timedelta(days=2, hours=10)).strftime("%Y-%m-%d %H:%M:%S"), + "end_at": (base + timedelta(days=2, hours=11, minutes=30)).strftime("%Y-%m-%d %H:%M:%S"), "all_day": 0, "status": "CONFIRMED", },