feat(kudos): per-user opt-out of the leaderboard (LC-526 follow-up) #505

Merged
longjacksonle merged 4 commits from feat/LC-526-kudos-optout into main 2026-07-03 04:23:05 +02:00

Delivers the per-user opt-out that was deferred from the LC-526 kudos PR (#504): a member can hide themselves from the public /kudos leaderboard.

Behavior: off by default (everyone is listed). When a user enables "Hide me from the kudos leaderboard" in Settings > Preferences, they disappear from BOTH the "most appreciated" and "most generous" lists. They can still give and receive kudos - the recognition message still posts and still notifies; only the public ranking excludes them.

How: a new users.kudos_leaderboard_opt_out column (auth migration 0035, default 0). The flag is queried on demand (settings render + leaderboard build) rather than carried on the hot User projection. Because the tally lives in chat.db and the flag in auth.db, the exclusion is applied as a NOT IN list passed into top_receivers/top_givers, not a join.

Four small logical commits: column + accessors, leaderboard exclusion, settings toggle, tests.

Tests: db-layer exclusion (a listed user is removed from both boards while others rank normally); i18n parity (en + es). just test + just test-saas + just check green.

Not operator-visible (no env/config/security change; the migration auto-applies).

🤖 Generated with Claude Code

Delivers the per-user opt-out that was deferred from the LC-526 kudos PR (#504): a member can hide themselves from the public `/kudos` leaderboard. **Behavior:** off by default (everyone is listed). When a user enables "Hide me from the kudos leaderboard" in Settings > Preferences, they disappear from BOTH the "most appreciated" and "most generous" lists. They can still give and receive kudos - the recognition message still posts and still notifies; only the public ranking excludes them. **How:** a new `users.kudos_leaderboard_opt_out` column (auth migration 0035, default 0). The flag is queried on demand (settings render + leaderboard build) rather than carried on the hot `User` projection. Because the tally lives in `chat.db` and the flag in `auth.db`, the exclusion is applied as a `NOT IN` list passed into `top_receivers`/`top_givers`, not a join. Four small logical commits: column + accessors, leaderboard exclusion, settings toggle, tests. Tests: db-layer exclusion (a listed user is removed from both boards while others rank normally); i18n parity (en + es). `just test` + `just test-saas` + `just check` green. Not operator-visible (no env/config/security change; the migration auto-applies). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Adds the per-user opt-out flag (auth migration 0035, default off) plus get/set accessors and a bulk `kudos_opted_out_ids` helper. Queried on demand rather than carried on the User projection, since it is only needed at settings-render and leaderboard time. Not yet consumed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTRhc4n7A2uB2Y5PHV2ewL
Threads an `exclude` id list through top_receivers / top_givers as a NOT IN clause (the opt-out flag lives in auth.db and the tally in chat.db, so it cannot join). The /kudos route now fetches kudos_opted_out_ids and passes it, so an opted-out user disappears from both lists while still being able to give and receive kudos. Existing db_kudos tests pass `&[]`.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTRhc4n7A2uB2Y5PHV2ewL
Adds a "Hide me from the kudos leaderboard" toggle to Settings > Preferences. get_settings reads the flag for the checkbox state; post_settings persists it via set_kudos_opt_out. The help text clarifies you still give/receive kudos, only the ranking hides you. i18n en + es.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTRhc4n7A2uB2Y5PHV2ewL
test(kudos): cover leaderboard exclusion of opted-out users (LC-526)
All checks were successful
check-secrets / Nosey parker (push) Successful in 6s
check-secrets / Kingfisher (push) Successful in 8s
check-secrets / TruffleHog (push) Successful in 9s
check-secrets / Nosey parker (pull_request) Successful in 6s
check-secrets / TruffleHog (pull_request) Successful in 9s
check-secrets / Kingfisher (pull_request) Successful in 10s
Check / clippy + fmt + tests (pull_request) Successful in 6m20s
Create release / Create release from merged PR (pull_request) Has been skipped
5fdc438791
Adds a db test asserting the exclude list removes a user from both the receivers and givers boards while others rank normally. Also folds in cargo fmt normalizations of the earlier opt-out commits.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTRhc4n7A2uB2Y5PHV2ewL
longjacksonle scheduled this pull request to auto merge when all checks succeed 2026-07-03 04:22:32 +02:00
longjacksonle deleted branch feat/LC-526-kudos-optout 2026-07-03 04:23:05 +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!505
No description provided.