Skip to content

feat: 채팅 도배 방지 (Flood Protection)#110

Merged
parkjuyeong0312 merged 16 commits into
mainfrom
feature/flood-protection-chatting
May 27, 2026
Merged

feat: 채팅 도배 방지 (Flood Protection)#110
parkjuyeong0312 merged 16 commits into
mainfrom
feature/flood-protection-chatting

Conversation

@parkjuyeong0312
Copy link
Copy Markdown
Member

@parkjuyeong0312 parkjuyeong0312 commented May 27, 2026

변경 내용

  • 채팅/장소 공유 메시지 전송 시 사용자별 빈도 제한 (1초 5회, in-memory sliding window)
  • 빈도 초과 시 서버 사이드 cooldown 적용 (1분 내 반복 위반 시 5초 → 15초 → 30초 점진 증가)
  • CHAT_RATE_LIMIT_EXCEEDED 에러와 남은 cooldown 시간(retryAfterMs)을 /user/queue/errors로 전달
  • CustomExceptionretryAfterMs 필드 추가
  • 전용 MessageRateLimitedEvent 이벤트 및 UserErrorPayload 확장

변경 이유

  • 채팅 도배를 서버 단에서 방지하여 다른 사용자의 채팅 경험을 보호하기 위함
  • 반복 위반 시 점진적으로 제한을 강화하여 악의적 사용을 억제

테스트

  • ./gradlew build
  • /review-code-against-docs 스킬로 검증
  • 그 외 수동 검증: MessageRateLimiterTest(sliding window, cooldown, 점진 증가), MessageWebSocketControllerTest(rate limit 에러 이벤트 발행), MessageServiceTest(send/sharePlace 호출 시 checkRate 선행), RoomMessageBroadcasterTest(rate limited 이벤트 브로드캐스트), CustomExceptionTest(retryAfterMs 필드)

체크리스트

  • PR 제목이 커밋 컨벤션 형식을 따른다.
  • 변경 사유를 PR 설명에 기록했다.
  • 테스트 방법과 결과를 기록했다.
  • 문서 변경이 필요한 경우 반영했다.

하네스 변경 체크리스트

  • CLAUDE.md(AGENTS.md) 변경이 포함되어 있는가? — 해당 없음
  • 변경 사유가 PR 설명에 기록되어 있는가? — 해당 없음
  • 기존 규칙과 충돌하지 않는가? — 해당 없음
  • 팀원에게 변경 사항을 공유했는가? — 해당 없음

Summary by CodeRabbit

Release Notes

  • New Features

    • Added chat rate limiting: Users are restricted to 5 messages per second on chat and place-sharing endpoints.
    • Implemented server-side cooldown periods: Rate limit violations trigger progressive cooldowns (5s → 15s → 30s) with retry-after timing sent to clients.
  • Documentation

    • Added comprehensive design and implementation planning documents for flood protection functionality.

Review Change Stack

Copilot AI review requested due to automatic review settings May 27, 2026 04:09
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

Warning

Review limit reached

@parkjuyeong0312, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 18 minutes and 45 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bac3f4b6-8318-48ae-9032-85aeafe40a3d

📥 Commits

Reviewing files that changed from the base of the PR and between e8a38d8 and 177eba4.

📒 Files selected for processing (12)
  • src/main/java/com/howaboutus/backend/common/config/ClockConfig.java
  • src/main/java/com/howaboutus/backend/common/error/CustomException.java
  • src/main/java/com/howaboutus/backend/messages/controller/MessageWebSocketController.java
  • src/main/java/com/howaboutus/backend/messages/exception/ChatRateLimitException.java
  • src/main/java/com/howaboutus/backend/messages/service/MessageRateLimiter.java
  • src/main/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcaster.java
  • src/main/java/com/howaboutus/backend/realtime/service/dto/UserRateLimitErrorPayload.java
  • src/test/java/com/howaboutus/backend/common/error/CustomExceptionTest.java
  • src/test/java/com/howaboutus/backend/messages/controller/MessageWebSocketControllerTest.java
  • src/test/java/com/howaboutus/backend/messages/service/MessageRateLimiterTest.java
  • src/test/java/com/howaboutus/backend/messages/service/MessageServiceTest.java
  • src/test/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcasterTest.java
📝 Walkthrough

개요

사용자별 메시지 전송 빈도를 1초 5회로 제한하는 in-memory sliding window 기반 rate limiting과 반복 위반 시 점진적으로 증가하는 서버 사이드 cooldown(5초→15초→30초) 시스템을 구현합니다. Rate limit 초과 시 CHAT_RATE_LIMIT_EXCEEDED 오류와 남은 cooldown 시간(retryAfterMs)을 사용자 오류 큐로 전달합니다.

변경 사항

채팅 도배 방지 통합 구현

레이어 / 파일(s) 요약
에러 코드 및 예외 기반 구조
src/main/java/com/howaboutus/backend/common/error/CustomException.java, src/main/java/com/howaboutus/backend/common/error/ErrorCode.java, src/test/java/com/howaboutus/backend/common/error/CustomExceptionTest.java
CustomExceptionretryAfterMs 필드를 추가하고 세 가지 생성자 오버로드를 제공하며, ErrorCode에 HTTP 429 CHAT_RATE_LIMIT_EXCEEDED 열거값을 추가합니다. 테스트는 기본값과 명시적 설정을 검증합니다.
Rate Limiting 핵심 로직 및 테스트
src/main/java/com/howaboutus/backend/messages/service/MessageRateLimiter.java, src/test/java/com/howaboutus/backend/messages/service/MessageRateLimiterTest.java
사용자별 sliding window(1초/5회), 위반 기록, 점진적 cooldown(5초→15초→30초)을 관리하는 MessageRateLimiter를 구현합니다. 스케줄 태스크는 만료된 타임스탐프와 위반 기록을 주기적으로 정리합니다. 테스트는 정상 동작, 임계값, 사용자 분리, 윈도우 만료, cooldown 상태, 점진 증가를 포괄합니다.
서비스 레벨 Rate Limiting 통합
src/main/java/com/howaboutus/backend/messages/service/MessageCommandService.java, src/test/java/com/howaboutus/backend/messages/service/MessageServiceTest.java
MessageCommandService.send()sharePlace() 메서드 시작에 checkRate(userId) 호출을 추가하여 메시지 전송 전 빈도 제한을 검사합니다. 테스트는 한계 초과 시 예외 발생을 검증합니다.
이벤트 및 페이로드 확장
src/main/java/com/howaboutus/backend/realtime/event/MessageRateLimitedEvent.java, src/main/java/com/howaboutus/backend/realtime/service/dto/UserErrorPayload.java
Rate limit 초과 상황을 전달하는 MessageRateLimitedEvent 레코드를 신규 작성하고, UserErrorPayloadLong retryAfterMs 필드를 추가하여 MessageRateLimitedEvent로부터의 팩토리를 지원합니다.
컨트롤러 및 실시간 브로드캐스터 통합
src/main/java/com/howaboutus/backend/messages/controller/MessageWebSocketController.java, src/main/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcaster.java, src/test/java/com/howaboutus/backend/messages/controller/MessageWebSocketControllerTest.java, src/test/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcasterTest.java
MessageWebSocketControllerpublishCustomError() 헬퍼를 추가하여 CHAT_RATE_LIMIT_EXCEEDED 예외를 감지하고 MessageRateLimitedEvent를 발행합니다. RoomMessageBroadcasterhandleMessageRateLimited() 리스너를 추가하여 오류를 /queue/errors로 브로드캐스트합니다. 테스트는 예외 분기와 이벤트 발행을 검증합니다.
설계 및 구현 계획 문서
docs/ai/features.md, docs/superpowers/plans/2026-05-25-chat-flood-protection.md, docs/superpowers/plans/2026-05-27-flood-protection-cooldown.md, docs/superpowers/specs/2026-05-25-chat-flood-protection-design.md, docs/superpowers/specs/2026-05-27-flood-protection-cooldown-design.md
기능 명세, 기술 설계, 5개 태스크별 구현 계획을 문서화합니다. rate limit 정책(1초/5회, in-memory sliding window), 제외 대상(/ai, /read), 점진적 cooldown, 오류 전달 경로를 명시합니다.

시퀀스 다이어그램

sequenceDiagram
  participant Client
  participant Controller as MessageWebSocketController
  participant Limiter as MessageRateLimiter
  participant Broadcaster as RoomMessageBroadcaster
  participant Queue as UserQueue
  
  Client->>Controller: send(userId, message)
  Controller->>Limiter: checkRate(userId)
  Limiter-->>Controller: allow or throw CustomException
  alt Rate Limit Exceeded
    Controller->>Controller: publishCustomError
    Controller->>Broadcaster: emit MessageRateLimitedEvent
    Broadcaster->>Queue: convertAndSendToUser(/queue/errors)
  else Within Limit
    Controller->>Controller: process message send
  end
Loading

예상 코드 리뷰 난이도

🎯 3 (Moderate) | ⏱️ ~25 분

관련 이슈

관련 PR

  • how-about-us/backend-server#102: 메인 PR과 같은 MessageWebSocketControllerCustomException 처리 경로를 수정하므로 코드 레벨에서 연관이 있습니다.

🐰 메시지 도배 막는 새 담장,
Sliding window 설렘 있고,
Cooldown 초마다 늘어나면서,
빠른손가락도 숨이 차네!
오류큐로 살며시 알려주며,
프론트는 버튼 잠그고 기다린다. 🔒

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 채팅 도배 방지(Flood Protection) 기능 추가를 명확하게 요약하며, 커밋 컨벤션(feat:) 형식을 따르고 주요 변경사항을 정확하게 반영합니다.
Description check ✅ Passed PR 설명이 변경 내용, 변경 이유, 테스트 결과를 상세히 기록하였으며, 모든 체크리스트 항목을 완료했습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

WebSocket 기반 채팅/장소 공유 메시지 전송에 대해 사용자별 전송 빈도 제한과 서버 사이드 cooldown(반복 위반 시 점진 증가)을 추가하고, 제한 초과 시 클라이언트로 retryAfterMs를 포함한 전용 에러 이벤트를 전달하도록 확장한 PR입니다.

Changes:

  • MessageRateLimiter(in-memory sliding window + cooldownUntil/violations) 도입 및 MessageCommandService.send/sharePlace 진입 시 rate limit 선행 체크 추가
  • CustomException.retryAfterMs 추가 후, MessageRateLimitedEventRoomMessageBroadcaster/user/queue/errors 경로로 retryAfterMs 전달
  • 관련 단위/컨트롤러/브로드캐스터 테스트 및 기능 명세 문서 업데이트

Reviewed changes

Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/main/java/com/howaboutus/backend/messages/service/MessageRateLimiter.java 사용자별 sliding window + cooldown/점진 증가 로직 구현
src/main/java/com/howaboutus/backend/messages/service/MessageCommandService.java send/sharePlace 시작 시 rate limit 체크 추가
src/main/java/com/howaboutus/backend/common/error/CustomException.java retryAfterMs 필드 및 생성자 추가
src/main/java/com/howaboutus/backend/common/error/ErrorCode.java CHAT_RATE_LIMIT_EXCEEDED(429) 추가
src/main/java/com/howaboutus/backend/realtime/event/MessageRateLimitedEvent.java rate limit 전용 이벤트(재시도 시간 포함) 추가
src/main/java/com/howaboutus/backend/realtime/service/dto/UserErrorPayload.java /user/queue/errors payload에 retryAfterMs 확장
src/main/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcaster.java rate limited 이벤트 수신/유저 큐 전송 핸들러 추가
src/main/java/com/howaboutus/backend/messages/controller/MessageWebSocketController.java rate limit 예외를 전용 이벤트로 분기 발행하도록 변경
src/test/java/com/howaboutus/backend/messages/service/MessageRateLimiterTest.java sliding window/cooldown/점진 증가 동작 테스트 추가
src/test/java/com/howaboutus/backend/messages/service/MessageServiceTest.java send/sharePlace 경로에서 rate limit 예외 전파 테스트 추가
src/test/java/com/howaboutus/backend/common/error/CustomExceptionTest.java retryAfterMs 기본값/지정값 테스트 추가
src/test/java/com/howaboutus/backend/messages/controller/MessageWebSocketControllerTest.java rate limit 발생 시 이벤트 발행 테스트 추가
src/test/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcasterTest.java rate limited 이벤트가 user queue errors로 전달되는지 테스트 추가
docs/ai/features.md Flood Protection 기능/정책(점진 cooldown 포함) 문서 반영
docs/superpowers/specs/2026-05-25-chat-flood-protection-design.md Flood Protection 설계 문서 추가
docs/superpowers/specs/2026-05-27-flood-protection-cooldown-design.md 서버 사이드 cooldown/점진 제한 설계 문서 추가
docs/superpowers/plans/2026-05-25-chat-flood-protection.md 구현 계획 문서 추가
docs/superpowers/plans/2026-05-27-flood-protection-cooldown.md cooldown/점진 제한 구현 계획 문서 추가

Comment thread src/test/java/com/howaboutus/backend/messages/service/MessageRateLimiterTest.java Outdated
Comment thread src/test/java/com/howaboutus/backend/messages/service/MessageServiceTest.java Outdated
Comment thread src/main/java/com/howaboutus/backend/common/error/CustomException.java Outdated
@parkjuyeong0312 parkjuyeong0312 linked an issue May 27, 2026 that may be closed by this pull request
@parkjuyeong0312 parkjuyeong0312 self-assigned this May 27, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/java/com/howaboutus/backend/common/error/CustomException.java`:
- Around line 10-18: The CustomException constructors should call the
RuntimeException superclass with the error message so stack traces show a useful
message: in class CustomException update both constructors (the one taking
ErrorCode errorCode and the one taking ErrorCode errorCode, long retryAfterMs)
to invoke super(errorCode.getMessage()) before assigning fields so the exception
message is populated for logging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ca84f9eb-3a76-411d-9389-ef38c2d06a00

📥 Commits

Reviewing files that changed from the base of the PR and between 8b223d8 and e8a38d8.

📒 Files selected for processing (18)
  • docs/ai/features.md
  • docs/superpowers/plans/2026-05-25-chat-flood-protection.md
  • docs/superpowers/plans/2026-05-27-flood-protection-cooldown.md
  • docs/superpowers/specs/2026-05-25-chat-flood-protection-design.md
  • docs/superpowers/specs/2026-05-27-flood-protection-cooldown-design.md
  • src/main/java/com/howaboutus/backend/common/error/CustomException.java
  • src/main/java/com/howaboutus/backend/common/error/ErrorCode.java
  • src/main/java/com/howaboutus/backend/messages/controller/MessageWebSocketController.java
  • src/main/java/com/howaboutus/backend/messages/service/MessageCommandService.java
  • src/main/java/com/howaboutus/backend/messages/service/MessageRateLimiter.java
  • src/main/java/com/howaboutus/backend/realtime/event/MessageRateLimitedEvent.java
  • src/main/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcaster.java
  • src/main/java/com/howaboutus/backend/realtime/service/dto/UserErrorPayload.java
  • src/test/java/com/howaboutus/backend/common/error/CustomExceptionTest.java
  • src/test/java/com/howaboutus/backend/messages/controller/MessageWebSocketControllerTest.java
  • src/test/java/com/howaboutus/backend/messages/service/MessageRateLimiterTest.java
  • src/test/java/com/howaboutus/backend/messages/service/MessageServiceTest.java
  • src/test/java/com/howaboutus/backend/realtime/service/RoomMessageBroadcasterTest.java

@sonarqubecloud
Copy link
Copy Markdown

@parkjuyeong0312 parkjuyeong0312 merged commit 33e3838 into main May 27, 2026
4 checks passed
@parkjuyeong0312 parkjuyeong0312 deleted the feature/flood-protection-chatting branch May 27, 2026 04:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: 채팅 도배 방지 (Flood Protection) 구현

2 participants