Add Web Push notifications, PWA support, and full-screen tablet kiosk

Parents get a real push notification when a kid checks off a task
(false->true transitions only, fire-and-forget, degrades gracefully with
no VAPID keys configured). Dashboard is a fully installable iOS/Android
PWA; each child's kiosk link gets its own dynamic per-token manifest so
"Add to Home Screen" opens straight into their board in standalone mode.

Kiosk view is reworked for tablets: safe-area-aware full-bleed layout,
the whole task row is now tappable (previously only the 24px checkbox
was, well under Apple's touch-target minimum), and app icons are
generated by a small dependency-free PNG encoder (no image tooling
available in this environment).

Push requires real HTTPS (iOS Safari won't allow it otherwise) - README
and UNRAID.md cover VAPID setup and the HTTPS prerequisite.
This commit is contained in:
ort
2026-08-15 16:14:56 -04:00
parent 56d8c4616c
commit 2826a3819c
27 changed files with 792 additions and 14 deletions
+41
View File
@@ -52,6 +52,9 @@ backup plugins (e.g. CA Backup/Restore) like any other app's data.
- SESSION_SECRET=${SESSION_SECRET:?set a long random value in .env}
- COOKIE_SECURE=${COOKIE_SECURE:-false}
- DISABLE_PUBLIC_SIGNUP=${DISABLE_PUBLIC_SIGNUP:-false}
- VAPID_PUBLIC_KEY=${VAPID_PUBLIC_KEY:-}
- VAPID_PRIVATE_KEY=${VAPID_PRIVATE_KEY:-}
- VAPID_SUBJECT=${VAPID_SUBJECT:-}
restart: unless-stopped
```
@@ -61,6 +64,9 @@ backup plugins (e.g. CA Backup/Restore) like any other app's data.
COOKIE_SECURE=false
DISABLE_PUBLIC_SIGNUP=false
```
Leave the three `VAPID_*` vars unset for now unless you're setting up
push notifications and already have real HTTPS in front of this stack —
see "Push notifications" below.
4. **Compose Up**. First run builds the image (a minute or so — it's
cloning the repo and running `npm install`), then the container starts
on port 3007.
@@ -79,6 +85,9 @@ cat > .env <<EOF
SESSION_SECRET=$(openssl rand -hex 32)
COOKIE_SECURE=false
DISABLE_PUBLIC_SIGNUP=false
VAPID_PUBLIC_KEY=
VAPID_PRIVATE_KEY=
VAPID_SUBJECT=
EOF
docker compose -f docker-compose.unraid.yml up -d --build
```
@@ -129,6 +138,38 @@ Proxy Manager, both common on Unraid) with a real HTTPS certificate:
`DISABLE_PUBLIC_SIGNUP=true` so `/signup.html` stops accepting new
households.
This same real-HTTPS setup is also the prerequisite for push notifications
below — Swag and Nginx Proxy Manager both produce real Let's Encrypt certs
given a domain, so if you've already followed this section, you qualify.
## Push notifications
Optional: parents get a real push notification (not just the silent
polling-based update) when a kid checks off a task on the kiosk.
**Needs the real HTTPS from the section above already in place** — a
self-signed cert doesn't satisfy iOS, and plain `http://<unraid-ip>:3007`
won't work for this feature at all, even though the rest of the app is
fine over plain HTTP on your LAN.
Once HTTPS is confirmed working through your reverse proxy:
1. Generate a VAPID keypair — from the Unraid terminal:
`docker run --rm node:22-alpine npx web-push generate-vapid-keys`.
2. Set `VAPID_PUBLIC_KEY`, `VAPID_PRIVATE_KEY`, `VAPID_SUBJECT`
(`mailto:you@example.com`) in the stack's **ENV** tab (or `.env` for the
terminal path), then rebuild (**Update & Rebuild**, or
`docker compose -f docker-compose.unraid.yml up -d --build`).
3. On the dashboard (loaded through your HTTPS domain, not the bare
`http://<unraid-ip>:3007`), each parent clicks "Enable notifications on
this device" — per-device, so repeat on every phone/computer.
On iPhone/iPad, Safari only allows push for web apps added to the Home
Screen — tap Share → Add to Home Screen on the dashboard first, then open
the app icon and enable notifications from there. The dashboard explains
this in place if needed. Regenerating the VAPID keypair invalidates every
existing subscription, so treat it as a one-time setup step.
## Backups
Since data lives at `/mnt/user/appdata/kids-calendar` (a plain file, the