feat: pwa notifications

This commit is contained in:
2026-07-14 20:49:30 +02:00
parent 2cf7b283e0
commit 5198826f83
21 changed files with 1563 additions and 8 deletions
+40
View File
@@ -84,6 +84,42 @@ If you ever do need a real APK (Play Store, or an installable file), the manifes
here is all [PWABuilder](https://www.pwabuilder.com) needs to wrap it in a
Trusted Web Activity — no Android SDK on your side.
## Reminders (Web Push)
Android notifications for doses you haven't ticked off, delivered to the
installed PWA. No second app, no Firebase account.
**1. Generate a VAPID key pair, once:**
```bash
uv run python manage.py generate_vapid_keys
```
Put both values in the server's environment (`VAPID_PUBLIC_KEY`,
`VAPID_PRIVATE_KEY`). Regenerating them later invalidates every subscription and
each device has to re-enable reminders, so keep them.
**2. Set a reminder time per dose** in the admin — Morning 08:00, Evening 19:00,
and so on. A dose with no reminder time never notifies.
**3. Turn reminders on** in the Reminders card on the Today page, and use **Send
test** there to confirm the whole chain works before trusting it with the cat.
**4. Run the sender from cron**, every ten minutes:
```cron
*/10 * * * * cd /path/to/Osiris && uv run python manage.py send_reminders >> /var/log/osiris-reminders.log 2>&1
```
The command only pushes a dose that is due and not already ticked off, and
records what it sent, so a dose is reminded at most once per day no matter how
often cron fires. Doses due at the same time share one notification rather than
buzzing once per pill. `--grace-minutes` (default 120) stops a server that was
down all morning from firing the 08:00 reminder at 23:00; `--dry-run` shows what
would go out without sending it.
Notifications require HTTPS and an installed PWA — see the Android section below.
## Data model
- `Medication` — the drug, e.g. Vetmedin. Deactivate rather than delete when a
@@ -123,6 +159,10 @@ expire; revoke them in Admin → Api tokens.
| `POST` | `/api/tracker/pulse` | record the pulse; posting twice a day overwrites |
| `GET` | `/api/tracker/pulse/stats` | average, range, and `trend_bpm_per_day` |
| `DELETE` | `/api/tracker/pulse/{date}`| remove a reading |
| `POST` | `/api/push/subscribe` | register a device for reminders |
| `POST` | `/api/push/unsubscribe` | stop reminders on a device |
| `POST` | `/api/push/test` | send a test notification now |
| `GET` | `/api/push/public-key` | the VAPID key a client needs in order to subscribe |
`GET /api/tracker/day` is the one the app's home screen needs: