feat(room): per-channel slowmode (LC-534) #507

Merged
longjacksonle merged 4 commits from feat/LC-534-slowmode into main 2026-07-04 04:29:59 +02:00

Second build from the Round 3 shortlist (LC-531): per-channel slowmode.

What it does: a room manager sets a minimum interval between a member's posts (Off / 5s / 10s / 30s / 1m) from the room manage page. Posting faster returns a 429 with the seconds remaining. Moderators are exempt, and the setting is written to the mod log.

How it works: a new rooms.slowmode_seconds column (chat migration 0082, default 0 = off) and a RateLimits::check_cooldown minimum-interval limiter that reuses the existing DashMap under a distinct "slow" kind tag. Enforced in post_message after the posting-policy gate, and only when enabled, so non-slowmode rooms pay nothing. Presets are capped at 60s (the limiter window) so the shared sweep never drops an active cooldown early.

Four small commits: column + limiter, enforcement, manage control, tests.

Verification - driven end-to-end: an HTTP integration test asserts a plain member's second rapid post is 429'd, a room with slowmode off allows rapid posts, and a room moderator is exempt. Plus a limiter unit test. just test + just test-saas + just check green.

Moderation note: standard anti-flood control, manager-configurable, mod-exempt, audit-logged. No new privacy surface.

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

Generated with Claude Code.

Second build from the Round 3 shortlist (LC-531): per-channel slowmode. **What it does:** a room manager sets a minimum interval between a member's posts (Off / 5s / 10s / 30s / 1m) from the room manage page. Posting faster returns a 429 with the seconds remaining. Moderators are exempt, and the setting is written to the mod log. **How it works:** a new `rooms.slowmode_seconds` column (chat migration 0082, default 0 = off) and a `RateLimits::check_cooldown` minimum-interval limiter that reuses the existing DashMap under a distinct "slow" kind tag. Enforced in `post_message` after the posting-policy gate, and only when enabled, so non-slowmode rooms pay nothing. Presets are capped at 60s (the limiter window) so the shared sweep never drops an active cooldown early. Four small commits: column + limiter, enforcement, manage control, tests. **Verification - driven end-to-end:** an HTTP integration test asserts a plain member's second rapid post is 429'd, a room with slowmode off allows rapid posts, and a room moderator is exempt. Plus a limiter unit test. `just test` + `just test-saas` + `just check` green. **Moderation note:** standard anti-flood control, manager-configurable, mod-exempt, audit-logged. No new privacy surface. Not operator-visible (no env/config change; the migration auto-applies). Generated with Claude Code.
Adds the per-room slowmode interval (chat migration 0082, default 0 = off) with get/set accessors, plus RateLimits::check_cooldown - a minimum-interval limiter reusing the existing DashMap (distinct "slow" kind tag). First action per key is allowed; a faster follow-up is denied with the seconds remaining. Cooldowns must stay <= WINDOW so the shared sweep never drops an active one early. Not yet enforced or settable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTRhc4n7A2uB2Y5PHV2ewL
Checks the room's slowmode cooldown after the posting-policy gate (so a user who cannot post at all is never slowmoded) and only when slowmode > 0, so non-slowmode rooms pay nothing. Room moderators are exempt. Over-cooldown posts get a 429 with the seconds remaining. Not yet settable from the UI (rooms default to 0/off), so no behavior change until the manage control lands.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTRhc4n7A2uB2Y5PHV2ewL
Adds a Slowmode card to the room manage page: a manager picks Off / 5s / 10s / 30s / 1m, saved via POST /room/{id}/slowmode. Same require_can_manage authorization as the posting policy, validated against a fixed preset list (all <= 60s to respect the limiter window), and written to the mod log. get_page now loads the current value. i18n en + es.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NTRhc4n7A2uB2Y5PHV2ewL
test(slowmode): end-to-end enforcement, off, and mod-exempt (LC-534)
All checks were successful
check-secrets / TruffleHog (push) Successful in 4s
check-secrets / Nosey parker (push) Successful in 4s
check-secrets / Kingfisher (push) Successful in 16s
check-secrets / TruffleHog (pull_request) Successful in 5s
check-secrets / Kingfisher (pull_request) Successful in 6s
check-secrets / Nosey parker (pull_request) Successful in 7s
Check / clippy + fmt + tests (pull_request) Successful in 3m41s
Create release / Create release from merged PR (pull_request) Has been skipped
d6662ee990
HTTP integration test: a plain member's second rapid post in a slowmode room is 429'd; a room with slowmode off allows rapid posts; a room moderator is exempt. Also folds in a cargo fmt reflow of the LC-534 rate_limit change.

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-04 04:26:58 +02:00
longjacksonle deleted branch feat/LC-534-slowmode 2026-07-04 04:29:59 +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!507
No description provided.