Skip to content

feat(notifications): email notifications with opt-out and one-click unsubscribe - #178

Open
ajianaz wants to merge 1 commit into
developfrom
feat/73-email-notifications
Open

ajianaz wants to merge 1 commit into
developfrom
feat/73-email-notifications

Conversation

@ajianaz

@ajianaz ajianaz commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

What

Email notifications for Rungu (issue #73): notify post authors and commenters by email when a post receives a new comment or changes status.

Why

Feedback boards live or die by the feedback loop — right now users have to poll the board manually. Closing #73 unblocks the core "submit and forget" UX.

Changes

  • Config — env-driven, exactly as designed in feat: email notifications (new comments, status changes) #73: all SMTP env empty → notifications disabled (one INFO log at startup, toggle hidden); SMTP_DRIVER=log → render to tracing (dev/CI); SMTP_HOST+SMTP_FROM set → active. Partial config = fail-fast exit(1) so a typo can't silently kill notifications in prod.
  • SMTP client — minimal implementation (EHLO → STARTTLS → AUTH LOGIN → MAIL/RCPT/DATA) on tokio-rustls + webpki-roots, sharing the rustls stack already used by reqwest. No lettre — keeps the dep tree lean per no-dep policy.
  • Eventscomment.created and post.status_changed notify post author + all commenters, excluding the actor and opted-out users. Delivery via tokio::spawn: never blocks the request path.
  • DB — migration 003 (sqlite + postgres): users.notifications_opt_out boolean, default opted-in.
  • APIGET/POST /api/me/notifications/preferences (authed, camelCase), GET /api/notifications/unsubscribe?token= (public, HMAC-SHA256 signed token, minimal HTML confirmation page).
  • Emails — multipart text+HTML, per-recipient unsubscribe link.

Testing

  • cargo test --workspace: 117 passed, 0 failed (incl. 2 new integration tests: preferences roundtrip + unsubscribe link roundtrip incl. bogus-token rejection, and unit tests for token signing/rendering).
  • cargo clippy --workspace --all-targets clean; cargo fmt --check clean.
  • Cora review: 5 CRITICAL "hardcoded secret" findings — all verified false positives (unit-test SECRET const + format! string interpolation, not credentials).

Closes #73

…nsubscribe (#73)

- SMTP env-driven config: empty = disabled, SMTP_DRIVER=log for dev/CI,
  partial config = fail-fast at startup
- Minimal SMTP client (STARTTLS + AUTH) built on tokio-rustls
- Events: comment.created + post.status_changed -> post author + commenters
  (actor excluded), fired via tokio::spawn (non-blocking)
- users.notifications_opt_out column (sqlite + postgres migrations 003)
- Routes: GET/POST /api/me/notifications/preferences (authed),
  GET /api/notifications/unsubscribe?token= (HMAC-signed, public HTML page)
- HTML+text multipart emails with unsubscribe links

Cora 'hardcoded secret' findings verified as false positives: SECRET const
in unit tests + format-string interpolation, not credentials.
@github-actions

Copy link
Copy Markdown

🔍 Cora AI Code Review

No issues found. Code looks good!


Review powered by cora-code · BYOK · MIT

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: email notifications (new comments, status changes)

1 participant