Revert "feat: replace Web Push with ntfy for medication reminders"

This reverts commit 1cada42370.
This commit is contained in:
Frank Schwenk
2026-07-08 08:25:34 +02:00
parent 1cada42370
commit bff14167c9
17 changed files with 323 additions and 251 deletions
+27 -29
View File
@@ -1,6 +1,6 @@
# TakeYourMeds
Persönliche Medikamenten-PWA mit dezenten ntfy-Erinnerungen, Einnahme-Logging und sarkastischem Humor.
Persönliche Medikamenten-PWA mit dezenten Push-Erinnerungen, Einnahme-Logging und sarkastischem Humor.
**Domain:** [medis.schwenk.online](https://medis.schwenk.online)
@@ -11,7 +11,7 @@ Persönliche Medikamenten-PWA mit dezenten ntfy-Erinnerungen, Einnahme-Logging u
## Features
### Kern
- **ntfy-Erinnerungen** um 8:00 und 12:00 (`Europe/Berlin`) — dezent, kein Alarm
- **Push-Erinnerungen** um 8:00 und 12:00 (`Europe/Berlin`) — dezent (`silent`), kein Alarm
- **Einnahme loggen:** genommen / verpasst / snooze
- **PIN-Login** mit langer JWT-Session (90 Tage)
- **PWA:** installierbar, offline-fähige App-Shell, Service Worker
@@ -38,7 +38,7 @@ Persönliche Medikamenten-PWA mit dezenten ntfy-Erinnerungen, Einnahme-Logging u
| Backend | FastAPI + uvicorn |
| DB | SQLite (`data/medis.sqlite`) |
| Frontend | Vanilla JS (kein Build-Step) |
| Push | ntfy ([ntfy.schwenk.online](https://ntfy.schwenk.online/)) |
| Push | Web Push (pywebpush + VAPID) |
| Scheduler | APScheduler (8:00, 12:00, 21:00) |
| KI (optional) | OpenRouter |
| Deployment | Docker Compose + Traefik |
@@ -57,9 +57,13 @@ pip install -e .
# 2. Konfiguration
cp .env.example .env
# APP_PIN, JWT_SECRET, NTFY_TOKEN anpassen
# APP_PIN und JWT_SECRET anpassen
# 3. Starten
# 3. VAPID keys (für Push)
python tools/gen_vapid.py
# Output in .env eintragen
# 4. Starten
uvicorn server.app:app --reload --host 0.0.0.0 --port 8000
```
@@ -71,7 +75,7 @@ App: http://localhost:8000
```bash
cp .env.example .env
# .env ausfüllen (PIN, JWT_SECRET, NTFY_TOKEN, optional OPENROUTER_API_KEY)
# .env ausfüllen (PIN, JWT_SECRET, VAPID keys, optional OPENROUTER_API_KEY)
docker compose up -d --build
```
@@ -94,10 +98,9 @@ Volumes:
| `APP_PIN` | Login-PIN (46 Ziffern) |
| `JWT_SECRET` | Geheimer Key für JWT (min. 32 Zeichen empfohlen: `openssl rand -hex 32`) |
| `JWT_EXPIRE_DAYS` | Session-Laufzeit (Default: 90) |
| `NTFY_URL` | ntfy-Server (Default: `https://ntfy.schwenk.online`) |
| `NTFY_TOPIC` | Topic für Reminder (Default: `takeyourmeds`) |
| `NTFY_TOKEN` | Access-Token zum Publizieren (Bearer) |
| `NTFY_CLICK_URL` | PWA-URL für Tap/Actions (Default: `https://medis.schwenk.online`) |
| `VAPID_PRIVATE_KEY` | Web-Push Private Key (PEM) |
| `VAPID_PUBLIC_KEY` | Web-Push Public Key |
| `VAPID_CLAIMS_EMAIL` | mailto:-Adresse für VAPID |
| `OPENROUTER_API_KEY` | Optional — für Roast-of-the-Day |
| `OPENROUTER_MODEL` | Default: `google/gemini-2.0-flash-001` |
@@ -127,12 +130,12 @@ Texte frei editierbar — kein Neustart nötig (wird beim ersten Request geladen
## API
Alle Endpunkte unter `/api/*`. Auth via `Authorization: Bearer <token>` (außer `/api/auth/pin`).
Alle Endpunkte unter `/api/*`. Auth via `Authorization: Bearer <token>` (außer `/api/auth/pin` und `/api/vapid-public-key`).
| Methode | Pfad | Beschreibung |
|---------|------|--------------|
| POST | `/api/auth/pin` | `{ "pin": "1234" }``{ "token": "..." }` |
| GET | `/api/notify-config` | ntfy Topic + Subscribe-URL |
| GET | `/api/vapid-public-key` | Public Key für Push-Subscription |
| GET | `/api/config` | Meds-Config |
| GET | `/api/today` | Heutige Slots + Status |
| POST | `/api/log` | `{ "slot_id", "status", "day?", "source?" }` |
@@ -140,23 +143,18 @@ Alle Endpunkte unter `/api/*`. Auth via `Authorization: Bearer <token>` (außer
| GET | `/api/history?days=90` | Heatmap-Daten + Stats |
| GET | `/api/stats` | Streak, Compliance, Meilensteine |
| GET | `/api/roast` | Roast-of-the-Day |
| POST | `/api/push/subscribe` | Web-Push Subscription speichern |
---
## ntfy einrichten
## PWA / Push einrichten
1. **Server:** `NTFY_TOKEN` in `.env` auf boka setzen, Container neu starten
2. **Handy:** ntfy-App → Topic `takeyourmeds` abonnieren (oder Link unter **Einstellungen** in der PWA)
3. Optional: PWA auf Homescreen — für Loggen/Snooze; Reminder kommen über ntfy
1. App im Browser öffnen (HTTPS erforderlich — lokal ohne Push)
2. Einloggen → Tab **Einstellungen****Push aktivieren**
3. Optional: **Auf Homescreen** installieren
4. Android-Shortcuts: Long-Press App-Icon → „Genommen (Morgens/Mittags)"
Notification-Actions in ntfy: **Genommen ✓**, **+15 Min**, **+30 Min** (öffnen PWA mit Deep-Link)
Test von der Shell:
```bash
curl -d "Test" -H "Title: Med-Time" -H "Authorization: Bearer $NTFY_TOKEN" \
https://ntfy.schwenk.online/takeyourmeds
```
Notification-Actions: **Genommen ✓**, **+15 Min**, **+30 Min**
---
@@ -175,7 +173,7 @@ curl -d "Test" -H "Title: Med-Time" -H "Authorization: Bearer $NTFY_TOKEN" \
| **Ein FastAPI-Container** statt nginx+api | KISS — weniger Moving Parts, StaticFiles reicht für Single-User-PWA |
| **Vanilla JS** statt React/Vue | Kein Build-Step, schnelle Iteration, passt zu persönlicher App |
| **SQLite** statt Postgres | Single-User, eine Datei, Backup = `data/medis.sqlite` kopieren |
| **ntfy vom Server** statt Web Push | Zuverlässig auf Android; eine Notification-Logik |
| **Web Push vom Server** statt Client-Timer | Zuverlässig auch bei geschlossener App; APScheduler im Container |
| **OpenRouter nur für Roast** | Kosten/Latenz — Notifications nutzen statische `messages.yaml` |
| **Model: gemini-2.0-flash** | Günstig, schnell, gut genug für kurze deutsche Roasts |
| **PIN plain in .env** statt Hash | Single-User, unkritische Daten; `hmac.compare_digest` gegen Timing-Leaks |
@@ -183,7 +181,7 @@ curl -d "Test" -H "Title: Med-Time" -H "Authorization: Bearer $NTFY_TOKEN" \
| **`reminder_window_minutes: 90`** | ADHS-realistisch — nicht sofort „verpasst" um 08:01 |
| **Badge = Streak**, nicht offene Dosen | Streak ist motivierender Dopamin-Hook |
| **Icons: PNG für alle Größen** | 556×556 Quelle — Browser skaliert; kein ImageMagick nötig |
| **Abend-Check 21:00** | Markiert überfällige Slots als `missed`, optional ntfy |
| **Abend-Check 21:00** | Markiert überfällige Slots als `missed`, optional Push |
| **Offline-Queue via IndexedDB** | Einfacher als SW-only; Flush bei App-Start + Background-Sync |
---
@@ -199,7 +197,7 @@ takeyourmeds/
├── icon.png / icon.svg # App-Icons (Quelle)
├── server/ # FastAPI Backend
├── public/ # PWA Frontend
├── tools/ # schema.sql
├── tools/ # schema.sql, gen_vapid.py
└── data/ # SQLite (gitignored)
```
@@ -220,8 +218,8 @@ Service Worker cached aggressiv — für SW-Änderungen: DevTools → Applicatio
| Problem | Lösung |
|---------|--------|
| Reminder kommt nicht | `NTFY_TOKEN` in `.env`? Topic in ntfy-App abonniert? |
| „ntfy nicht konfiguriert" | `NTFY_URL` + `NTFY_TOPIC` in `.env` setzen |
| Push kommt nicht | VAPID keys in `.env`? HTTPS? Push in Einstellungen aktiviert? |
| „VAPID keys nicht konfiguriert" | `python tools/gen_vapid.py` ausführen |
| KI-Roast zeigt Fallback | `OPENROUTER_API_KEY` fehlt oder API-Fehler — Fallback aus `messages.yaml` |
| Streak = 0 trotz Log | Streak zählt nur Tage wo **alle** Slots genommen wurden |
| SW zeigt alte Version | `version.json` bumpen + Cache leeren |