Adds a Notifications tab to Settings so an operator can pick which events
reach their phone, published to a single self-hosted ntfy topic.
The notifier subscribes to the realtime event hub the dashboard already
consumes, so every notifiable event keeps exactly one publisher. Inbound
media had no event, so `media.received` is added and published from the
existing durable `gotImage` gate in the chat service — one notification
per conversation, never repeated when the room re-syncs. It feeds the
in-app notification bell as well.
- Best-effort delivery: a rejecting or unreachable ntfy server is logged
and never propagated into the path that produced the event.
- Events buffered before the notifier attaches are skipped, so a restart
cannot replay a backlog to somebody's phone.
- Settings are applied field by field onto the live config object, so a
save takes effect without a restart.
- The access token is environment-owned (NTFY_AUTH_TOKEN) like the other
secrets: stripped before the settings record is written, never returned
by the API, which reports only `hasAuthToken`.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds an inline subreddit editor on the dashboard that lets you add,
remove, and edit (tone, type, weight) the subreddit list, with changes
persisted to config.yaml on disk so they survive restarts.
Backend
- src/config/persistence.ts: round-trips config.yaml via
YAML.parseDocument, mutating existing row nodes in place so their
trailing inline `# ...` comments survive an edit; new rows are
appended as flow-style maps to match the on-disk idiom; removed rows
are dropped. Default values ('default' tone, 'image' type) are
omitted on write so the file stays clean. Atomic via tmp+rename.
- src/web/routes/config.ts: GET /api/config now also returns the
current subreddit list and the available tone keys. PUT /api/config
accepts a `subreddits` field, validates with the existing
SubredditConfigSchema, rejects duplicates, persists, then mutates
ctx.config.reddit.subreddits in place so the processor picks up the
new tone immediately without a restart.
Frontend
- public/index.html: replaces the read-only subreddit chip list in the
Configuration snapshot section with a grid of editable rows (name,
type, tone dropdown, weight, remove). + Add / Save buttons with
inline status. Tones are sourced from /api/config so the catalog
drives the dropdown.
Tests
- tests/config-persistence.test.ts: covers in-place mutation comment
preservation, removal, appends, reorder, default omission, and
atomic write cleanup.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>