feat(notifications): keyword / highlight-word notifications (LC-304) #330

Merged
longjacksonle merged 1 commit from feat/lc-304-keyword-notifications into main 2026-06-15 02:17:28 +02:00

Summary

Per-user highlight words: when a message contains one of your words, it is treated like an @mention (sidebar badge, row highlight, inbox/activity, and opt-in email/push), without anyone @-mentioning you.

Approach

Reuses the mention pipeline end-to-end. A new resolve_targets_for_body wrapper resolves @tokens then appends members whose highlight word matches the body, deduped, before reconcile_mentions. All 5 reconcile sites (post / edit / webhook / email-ingress / bridge) call it, so a keyword match becomes a normal mentions row and every downstream surface works with no change.

Changes

  • server/migrations/auth/0027_notification_keywords.sql (new): notification_keywords(user_id, word, ...).
  • server/src/db/notification_keywords.rs (new): list / all / add / remove / count; cap constants (25 words, 50 chars).
  • server/src/routes/room.rs: resolve_targets_for_body + append_keyword_targets + keyword_matches_body (case-insensitive, word-bounded); the 5 sites swapped to the wrapper (4 new-message sites gate on !targets.is_empty(), edit stays unconditional so removals reconcile). Matching skips the author, non-members, and already-mentioned users; the member set is resolved only after a word hits the body.
  • server/src/routes/settings.rs + views/settings.rs + partials/keyword_list.html: a "Highlight words" chip list under Notifications (POST /settings/keywords, POST /settings/keywords/delete, each re-rendering the fragment).
  • server/locales/{en,es}/common.ftl: new UI strings.

Notification eligibility reuses the existing per-mention opt-in; no new pref column, no new badge/highlight plumbing.

Testing

  • just check, just fmt, just test, just test-saas all pass.
  • db_notification_keywords.rs (add/list/remove/idempotent/all) and routes_keyword_mentions.rs (member match inserts a mention; case-insensitive; word-boundary; author no self-notify; non-member not targeted).
  • No LC-77 fixture change (message.html untouched).

Not operator-visible (new table is internal; no env/config/contract change).

## Summary Per-user highlight words: when a message contains one of your words, it is treated like an @mention (sidebar badge, row highlight, inbox/activity, and opt-in email/push), without anyone @-mentioning you. ## Approach Reuses the mention pipeline end-to-end. A new `resolve_targets_for_body` wrapper resolves `@tokens` then appends members whose highlight word matches the body, deduped, before `reconcile_mentions`. All 5 reconcile sites (post / edit / webhook / email-ingress / bridge) call it, so a keyword match becomes a normal `mentions` row and every downstream surface works with no change. ## Changes - `server/migrations/auth/0027_notification_keywords.sql` (new): `notification_keywords(user_id, word, ...)`. - `server/src/db/notification_keywords.rs` (new): list / all / add / remove / count; cap constants (25 words, 50 chars). - `server/src/routes/room.rs`: `resolve_targets_for_body` + `append_keyword_targets` + `keyword_matches_body` (case-insensitive, word-bounded); the 5 sites swapped to the wrapper (4 new-message sites gate on `!targets.is_empty()`, edit stays unconditional so removals reconcile). Matching skips the author, non-members, and already-mentioned users; the member set is resolved only after a word hits the body. - `server/src/routes/settings.rs` + `views/settings.rs` + `partials/keyword_list.html`: a "Highlight words" chip list under Notifications (`POST /settings/keywords`, `POST /settings/keywords/delete`, each re-rendering the fragment). - `server/locales/{en,es}/common.ftl`: new UI strings. Notification eligibility reuses the existing per-mention opt-in; no new pref column, no new badge/highlight plumbing. ## Testing - `just check`, `just fmt`, `just test`, `just test-saas` all pass. - `db_notification_keywords.rs` (add/list/remove/idempotent/all) and `routes_keyword_mentions.rs` (member match inserts a mention; case-insensitive; word-boundary; author no self-notify; non-member not targeted). - No LC-77 fixture change (message.html untouched). Not operator-visible (new table is internal; no env/config/contract change).
feat(notifications): keyword / highlight-word notifications (LC-304)
Some checks failed
check-secrets / Kingfisher (push) Successful in 4s
check-secrets / TruffleHog (push) Successful in 5s
check-secrets / Nosey parker (push) Successful in 5s
check-secrets / Nosey parker (pull_request) Successful in 3s
check-secrets / TruffleHog (pull_request) Successful in 5s
check-secrets / Kingfisher (pull_request) Successful in 6s
Check / clippy + fmt + tests (pull_request) Failing after 43s
Create release / Create release from merged PR (pull_request) Has been skipped
00084065ae
Each user can configure highlight words in Settings; when a posted or edited message in a room they can see contains one of their words, they get the same treatment as an @mention: a raised sidebar badge, a highlighted message row, an inbox/activity entry, and (if opted in) an email/push notification.

The feature reuses the mention pipeline end-to-end. A new resolve_targets_for_body wrapper resolves @tokens (as before) and then appends members whose highlight word matches the body, deduped, before reconcile_mentions. All five reconcile sites (post, edit, webhook, email-ingress, bridge) call the wrapper, so a keyword match becomes a normal mentions row and every downstream surface works unchanged. Matching is case-insensitive and word-bounded ("deploy" matches "deploy" / "deploy!" but not "deployment"); the author never matches their own message; only room members are targeted (no access leak); the member set is resolved only after a word actually hits the body, so the common no-match path stays cheap.

Words live in a new auth.db notification_keywords table (capped 25 per user, 50 chars each), managed via a chip list under Settings > Notifications (add / remove are their own HTMX posts that re-render the list fragment). Notification eligibility reuses the existing per-mention opt-in; no new pref column.

#LC-304
#LC-305

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
longjacksonle deleted branch feat/lc-304-keyword-notifications 2026-06-15 02:17:28 +02:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
psa-systems/lets-chat!330
No description provided.