feat: overhaul with modular API, agent endpoints, migrations, backup and tests
- Split monolithic app.py into server/api/ routers - Add Pydantic schemas for input validation - Add /agent/* API with separate AGENT_TOKEN auth - Replace static schema.sql with versioned migrations (datenerhaltend) - Add tools/backup_db.py for SQLite backups - Add Dockerfile HEALTHCHECK and compose.yml AGENT_TOKEN env - Add pytest tests for user and agent API - Update README with API docs and deployment safety notes - Bump version to 1.2.0
This commit is contained in:
@@ -14,7 +14,9 @@ Persönliche Medikamenten-PWA mit dezenten Push-Erinnerungen, Einnahme-Logging u
|
||||
- **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)
|
||||
- **Agent-API** für externe Automatisierung (`/agent/*`) mit separatem Token
|
||||
- **PWA:** installierbar, offline-fähige App-Shell, Service Worker
|
||||
- **DB-Migrationen** — versionierte SQL-Skripte für deploymentsichere Schema-Updates
|
||||
|
||||
### Spaß
|
||||
- **Dopamin-Drop** — Animation + Erfolgsspruch beim Loggen
|
||||
@@ -78,7 +80,7 @@ App: http://localhost:8000
|
||||
|
||||
```bash
|
||||
cp .env.example .env
|
||||
# .env ausfüllen (PIN, JWT_SECRET, VAPID keys, optional OPENROUTER_API_KEY)
|
||||
# .env ausfüllen (PIN, JWT_SECRET, AGENT_TOKEN, VAPID keys, optional OPENROUTER_API_KEY)
|
||||
|
||||
docker compose up -d --build
|
||||
```
|
||||
@@ -86,9 +88,22 @@ docker compose up -d --build
|
||||
Traefik routet `medis.schwenk.online` → Container Port 8000 (TLS via `myresolver`).
|
||||
|
||||
Volumes:
|
||||
- `./data` — SQLite-Datenbank
|
||||
- `./data` — SQLite-Datenbank + automatische Backups (`data/backups/`)
|
||||
- `./meds.yaml` — Medikamenten-Zeitplan (read-only)
|
||||
- `./messages.yaml` — Humor-Texte (read-only)
|
||||
- `./tools/migrations` — Schema-Migrationen (read-only)
|
||||
|
||||
### Keine Daten verlieren beim Deploy
|
||||
|
||||
1. **DB-Migrationen:** `tools/migrations/*.sql` werden beim Container-Start automatisch angewendet (`schema_version`-Tabelle). Neue Tabellen/Spalten kommen ohne Datenverlust dazu.
|
||||
2. **Backup vor Updates:**
|
||||
```bash
|
||||
python tools/backup_db.py
|
||||
# oder im Container:
|
||||
docker compose exec app python tools/backup_db.py
|
||||
```
|
||||
3. **Volumes nicht löschen:** `docker compose down` ohne `-v` lässt `./data` bestehen. Nie `data/` manuell löschen.
|
||||
4. **Healthcheck:** Der Container meldet sich über `/api/health/`; Docker wartet mit dem "healthy"-Status, bis die App antwortet.
|
||||
|
||||
---
|
||||
|
||||
@@ -101,6 +116,7 @@ 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) |
|
||||
| `AGENT_TOKEN` | Langer zufälliger Token für die `/agent/*` API (leer = deaktiviert) |
|
||||
| `VAPID_PRIVATE_KEY` | Web-Push Private Key (PEM) |
|
||||
| `VAPID_PUBLIC_KEY` | Web-Push Public Key |
|
||||
| `VAPID_CLAIMS_EMAIL` | mailto:-Adresse für VAPID |
|
||||
@@ -133,12 +149,13 @@ 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` und `/api/vapid-public-key`).
|
||||
Alle Endpunkte unter `/api/*`. Auth via `Authorization: Bearer <token>` (außer `/api/auth/pin`, `/api/health/` und `/api/vapid-public-key`).
|
||||
|
||||
| Methode | Pfad | Beschreibung |
|
||||
|---------|------|--------------|
|
||||
| GET | `/api/health/` | Liveness + App-Version |
|
||||
| POST | `/api/auth/pin` | `{ "pin": "1234" }` → `{ "token": "..." }` |
|
||||
| GET | `/api/vapid-public-key` | Public Key für Push-Subscription |
|
||||
| GET | `/api/vapid-public-key` | Public Key für Push-Subscription (Legacy-Pfad) |
|
||||
| GET | `/api/config` | Meds-Config |
|
||||
| GET | `/api/today` | Heutige Slots + Status |
|
||||
| POST | `/api/log` | `{ "slot_id", "status", "day?", "source?" }` |
|
||||
@@ -146,8 +163,24 @@ 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 |
|
||||
| GET | `/api/motivation` | Tägliche Motivation |
|
||||
| POST | `/api/push/subscribe` | Web-Push Subscription speichern |
|
||||
|
||||
### Agent-API
|
||||
|
||||
Separate API für externe Agents / Automatisierung. Aktivieren mit `AGENT_TOKEN` in `.env`. Auth ebenfalls via `Authorization: Bearer <agent_token>`.
|
||||
|
||||
| Methode | Pfad | Beschreibung |
|
||||
|---------|------|--------------|
|
||||
| GET | `/agent/health` | Status, App-Version, DB-Schema-Version |
|
||||
| GET | `/agent/status` | Heutiger Stand + Stats |
|
||||
| POST | `/agent/log` | `{ "slot_id", "status", "day?", "source?" }` |
|
||||
| GET | `/agent/history?days=90` | Heatmap-Daten + Stats |
|
||||
| GET | `/agent/config` | Meds-Config |
|
||||
| POST | `/agent/notify` | `{ "title", "body", "slot_id?", "tag?" }` — Push an alle Subscriptions |
|
||||
|
||||
Die Agent-API läuft auf denselben Tabellen wie die App; `source` ist frei wählbar, z. B. `"voice"`, `"watch"`, `"cron"`.
|
||||
|
||||
---
|
||||
|
||||
## PWA / Push einrichten
|
||||
@@ -186,6 +219,8 @@ Notification-Actions: **Genommen ✓**, **+15 Min**, **+30 Min**
|
||||
| **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 Push |
|
||||
| **Offline-Queue via IndexedDB** | Einfacher als SW-only; Flush bei App-Start + Background-Sync |
|
||||
| **Agent-API mit separatem Token** | Externe Automatisierung ohne User-PIN; lässt sich gezielt abschalten |
|
||||
| **Versionierte SQL-Migrationen** | Kein Alembic-Overhead; deploymentsicher, datenerhaltend |
|
||||
|
||||
---
|
||||
|
||||
@@ -193,16 +228,20 @@ Notification-Actions: **Genommen ✓**, **+15 Min**, **+30 Min**
|
||||
|
||||
```
|
||||
takeyourmeds/
|
||||
├── server/ # FastAPI Backend
|
||||
│ ├── api/ # API-Router (auth, intake, push, stats, content, agent, health)
|
||||
│ ├── schemas.py # Pydantic-Input-Modelle
|
||||
│ ├── migrations.py # DB-Migrationssystem
|
||||
│ └── ...
|
||||
├── frontend/ # PWA-Quellen (JS, CSS, Templates)
|
||||
├── public/ # Build-Output (index.html, sw.js, assets/)
|
||||
├── tools/ # migrations/, gen_vapid.py, build_frontend.py, backup_db.py
|
||||
├── compose.yml # Docker + Traefik
|
||||
├── Dockerfile
|
||||
├── meds.yaml # Medikamenten-Zeitplan
|
||||
├── messages.yaml # Humor-Pool
|
||||
├── icon.png / icon.svg # App-Icons (Quelle)
|
||||
├── server/ # FastAPI Backend
|
||||
├── public/ # Build-Output (index.html, sw.js, assets/)
|
||||
├── tools/ # schema.sql, gen_vapid.py, build_frontend.py
|
||||
└── data/ # SQLite (gitignored)
|
||||
└── data/ # SQLite + Backups (gitignored)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -219,6 +258,12 @@ Quellen liegen in `frontend/`; Build-Output in `public/` (gehashte JS/CSS unter
|
||||
|
||||
Service Worker: bei Deploy neuer `CACHE`-Name automatisch via Build. Update-Banner erscheint bei veralteter Client-Version.
|
||||
|
||||
### Tests
|
||||
|
||||
```bash
|
||||
python -m pytest tests/ -v
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
Reference in New Issue
Block a user