freezmo/app/api
Martin Dvorak 77819b5961 Push reminders: personal to the notes, generic without them
The daily reminder said one generic line to everyone, because the server
never sees a deck. Now the notification text is written in the browser
(lib/reminder.ts) and travels with the subscription:

- Personal: "3 cards are due in Sky deck", in the app's language, tapping
  through to /review. Without notes (or with nothing due) it is the plain
  nudge, translated in both languages — push.title / push.due.* / push.generic.
- POST /api/push accepts an optional message {title, body, url}; url must be
  a path on this app, so a stolen subscription cannot make the notification
  link elsewhere. The store keeps endpoint, keys, the message and createdAt
  (a refresh no longer resets the timestamp).
- components/PushReminderSync.tsx refreshes the stored text when the app
  opens and whenever the tab becomes visible (throttled to twice a day), so a
  count is only ever sent while it is true.
- scripts/send-reminders.mjs sends each device its own text and falls back to
  PUSH_REMINDER_TITLE/_BODY for a subscription that has none
  (scripts/reminder-payload.mjs, unit-checked).
- /api/push/test previews the real reminder with a "Test:" prefix.
- deploy/freezmo-reminders.{service,timer}: the daily send as a systemd user
  timer (18:00 local, Persistent, randomised), documented in the README.
- Settings copy, privacy page (en+cs) and .env.example say exactly what the
  server now holds.
- phase2-test grew the whole path with a faked browser subscription: personal
  text in en and cs, the generic fallback in both, the URL guard, and the
  sender's preference order (81 checks).

Version 0.8.2, SW v104.
2026-10-18 14:34:15 +00:00
..
chat Teach it back: the AI becomes the curious student 2026-10-16 23:05:24 +00:00
generate Codebase audit: fix bugs, performance issues, dead code, and edge cases 2026-10-14 19:00:17 +00:00
grade Bring-your-own keys for cloud providers (OpenAI-compatible) 2026-10-14 06:29:39 +00:00
health Aero chat welcome panel: frosted and flush; honest model availability 2026-10-14 08:51:14 +00:00
healthz App versioning + the create page's missing top padding 2026-10-12 20:04:26 +00:00
homework Codebase audit: fix bugs, performance issues, dead code, and edge cases 2026-10-14 19:00:17 +00:00
podcast Podcast mode: notes read aloud with a lyric-style word highlight 2026-10-16 11:42:15 +00:00
providers Bring-your-own keys for cloud providers (OpenAI-compatible) 2026-10-14 06:29:39 +00:00
push Push reminders: personal to the notes, generic without them 2026-10-18 14:34:15 +00:00
reports Security: model budget + concurrency caps, SSRF guards, spoof-proof limits 2026-10-12 20:40:57 +00:00
sync Codebase audit: fix bugs, performance issues, dead code, and edge cases 2026-10-14 19:00:17 +00:00
tts Podcast voices: natural provider TTS, and system-voice hygiene 2026-10-16 16:34:46 +00:00