Revert "feat: replace Web Push with ntfy for medication reminders"
This reverts commit 1cada42370.
This commit is contained in:
@@ -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 (4–6 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 |
|
||||
|
||||
Reference in New Issue
Block a user