Skip to content

Feature:SlangFilter 추가 닉네임에 욕설 유무 포함#208

Open
KII1ua wants to merge 1 commit into
developfrom
feature/slangcheck
Open

Feature:SlangFilter 추가 닉네임에 욕설 유무 포함#208
KII1ua wants to merge 1 commit into
developfrom
feature/slangcheck

Conversation

@KII1ua
Copy link
Copy Markdown
Member

@KII1ua KII1ua commented Jun 2, 2026

📌 관련 이슈

  • closes #

🔍 작업 내용

입력된 단어에 욕설데이터를 불러와 일치하는지 확인하는 유틸 클래스 생성
UserService 욕설 체크 메서드 추가
UserController 욕설 체크 엔드포인트 추가

📝 변경 사항

💬 리뷰어에게

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능
    • 닉네임에 부적절한 표현 포함 여부를 검사하는 기능을 추가했습니다. 사용자는 이제 닉네임 설정 시 금칙어 필터링을 통해 사용 가능 여부를 미리 확인할 수 있습니다.

@KII1ua KII1ua self-assigned this Jun 2, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 2, 2026

Review Change Stack

검토 요약

사용자 닉네임에서 금칙어를 감지하는 기능이 추가되었습니다. 슬랭 필터 유틸리티, 워드 서비스, 사용자 서비스, 그리고 REST 엔드포인트 계층으로 구성되며, KMP 문자열 매칭 알고리즘을 사용합니다.

변경 사항

닉네임 슬랭 감지

Layer / File(s) 요약
KMP 슬랭 필터 유틸리티
src/main/java/com/ject/vs/util/SlangFilter.java
KMP 알고리즘을 구현하는 buildFailure, kmpContains, containsSlang 메서드를 통해 입력 문자열이 금칙어 목록에 포함되는지 선형 시간에 판정합니다.
워드 서비스 슬랭 통합 및 데이터 로드
src/main/java/com/ject/vs/user/port/WordService.java, src/main/resources/data/slang.txt
WordService는 초기화 시 classpath:data/slang.txt에서 2141개의 금칙어를 로드하고, containSlang 메서드가 SlangFilter를 위임하여 검사 결과를 반환합니다.
사용자 서비스 슬랭 검사 비즈니스 로직
src/main/java/com/ject/vs/user/port/UserService.java
checkNicknameSlang 메서드는 사용자 존재를 검증한 뒤 wordService.containSlang 결과를 부정하여 닉네임 사용 가능 여부를 판정합니다.
닉네임 슬랭 검사 REST 엔드포인트
src/main/java/com/ject/vs/user/adapter/web/UserController.java
POST /api/users/nickname/slang 엔드포인트가 인증된 사용자의 닉네임 검사 요청을 처리하여 NicknameCheckResponse를 200 OK로 반환합니다.

🎯 2 (Simple) | ⏱️ ~10 분

🐰 금칙어 필터로 닉네임 지킴이,
KMP 알고리즘 빠르게 작동해,
슬랭 목록 불러 검사 완료,
서비스 계층 깔끔히 정리,
사용자들의 품격을 지켜요!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목이 주요 변경사항인 욕설 필터링 기능 추가를 명확하게 설명하고 있으며, 변경된 파일들의 내용과 일치합니다.
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.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/slangcheck

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.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 2, 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: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/main/java/com/ject/vs/user/port/WordService.java (1)

34-43: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

로딩 실패 시 슬랭 검사가 무력화(fail-open)됩니다.

init()에서 slang.txt 로딩이 실패하면 slang은 빈 리스트로 남고, 이후 containSlang은 항상 false를 반환하여 모든 닉네임이 금칙어 검사를 통과합니다. 로그만 남기고 정상 기동되므로 운영 중 조용히 필터가 비활성화될 수 있습니다. 필수 리소스 로딩 실패 시 기동을 중단하거나 별도 헬스 지표로 노출하는 것을 검토해 주세요.

🤖 Prompt for 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.

In `@src/main/java/com/ject/vs/user/port/WordService.java` around lines 34 - 43,
The init() method currently swallows IOExceptions and leaves the slang list
empty so containSlang will always return false; change init() (and callers if
needed) to treat slang.txt as a required resource: when
loadWords("classpath:data/slang.txt") throws, rethrow a runtime exception or
call System.exit(1) (or set a failing health flag) so the application fails to
start (or exposes an unhealthy status) instead of continuing with an empty slang
list; ensure the change references init(), loadWords(...) and the slang field so
the service either aborts startup or flips a health indicator when slang loading
fails.
🧹 Nitpick comments (2)
src/main/java/com/ject/vs/user/adapter/web/UserController.java (1)

44-47: 💤 Low value

Swagger 문서화 누락: @Operation 추가 권장.

인접한 다른 엔드포인트들은 모두 @Operation(summary=..., description=...)을 부여하고 있으나 신규 /nickname/slang만 누락되어 API 문서에서 설명이 비게 됩니다. 일관성을 위해 추가해 주세요.

📝 제안
+    `@Operation`(summary = "닉네임 금칙어 확인", description = "닉네임에 금칙어 포함 여부를 확인합니다.")
     `@PostMapping`("/nickname/slang")
     public ResponseEntity<NicknameCheckResponse> checkNicknameSlang(`@AuthenticationPrincipal` Long userId, `@RequestBody` UserNicknameRec nickname) {
🤖 Prompt for 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.

In `@src/main/java/com/ject/vs/user/adapter/web/UserController.java` around lines
44 - 47, Add Swagger metadata to the checkNicknameSlang endpoint by annotating
the UserController.checkNicknameSlang method with `@Operation`(summary = "...",
description = "...") similar to adjacent endpoints; include a concise summary
like "Check nickname for slang" and a description stating the behavior (inputs:
UserNicknameRec.nickname, requires authentication, returns
NicknameCheckResponse), ensuring imports for
io.swagger.v3.oas.annotations.Operation are present if missing.
src/main/java/com/ject/vs/user/port/WordService.java (1)

84-86: 💤 Low value

메서드명 문법 제안: containSlangcontainsSlang.

3인칭 단수 형태가 자연스럽고 SlangFilter.containsSlang과도 일관됩니다. 호출부(UserService)도 함께 변경이 필요합니다.

🤖 Prompt for 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.

In `@src/main/java/com/ject/vs/user/port/WordService.java` around lines 84 - 86,
Rename the method containSlang to containsSlang in WordService (change the
method declaration name from containSlang to containsSlang) and update all call
sites to use the new name (notably the UserService caller); keep the
implementation body as-is (it already delegates to SlangFilter.containsSlang),
and ensure any interfaces, overrides, and unit tests referencing containSlang
are renamed to containsSlang so the code compiles and remains consistent with
SlangFilter.containsSlang.
🤖 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/ject/vs/util/SlangFilter.java`:
- Around line 40-48: containsSlang은 현재 입력 내부의 부분 문자열만 검사하므로 짧거나 일상어인
금칙어(slangList의 "시간","초딩","년" 등)에 대해 과도한 오탐이 발생합니다; 수정 방안으로 containsSlang과
kmpContains 호출 로직을 변경해 짧은 항목(예: 길이<=2 또는 <=3)이나 명시된 일상어 목록에 대해선 전체 단어 일치 또는 단어
경계 검사만 허용하고(예: 공백/문장부호/문자 경계 기준), 긴 항목에 대해서만 기존 부분 문자열 검색을 유지하도록 구현하세요; 이를 위해
containsSlang에서 각 slang에 대해 slang.length()를 검사하고 짧은/화이트리스트 항목은 단어 경계 검사
함수(isWordBoundaryMatch)로 처리하고 나머지는 kmpContains(text, slang.toCharArray())를 호출하도록
변경하세요.
- Line 44: SlangFilter currently iterates slangList without a null guard; add a
defensive null-check at the start of the public method in SlangFilter that uses
the slangList (e.g., if (slangList == null || slangList.isEmpty()) return
<no-op>), so the method treats a null list as empty and returns the input/result
unchanged (or false) instead of throwing NPE; update the method that contains
the for(String slang : slangList) loop to return early when slangList is null.

In `@src/main/resources/data/slang.txt`:
- Line 1: The first word contains a leading BOM (U+FEFF) so
WordService.loadWords currently yields "\uFEFF..." and String::trim doesn't
remove it; update loadWords to strip a leading BOM when reading lines (e.g.,
remove '\uFEFF' or use Character.isWhitespace check for U+FEFF) or ensure the
file is saved as BOM-free UTF-8; specifically modify WordService.loadWords to
call something like line = line.replaceFirst("^\uFEFF", "") (or equivalent)
before trimming and adding to the word list so the first forbidden word matches
correctly.

---

Outside diff comments:
In `@src/main/java/com/ject/vs/user/port/WordService.java`:
- Around line 34-43: The init() method currently swallows IOExceptions and
leaves the slang list empty so containSlang will always return false; change
init() (and callers if needed) to treat slang.txt as a required resource: when
loadWords("classpath:data/slang.txt") throws, rethrow a runtime exception or
call System.exit(1) (or set a failing health flag) so the application fails to
start (or exposes an unhealthy status) instead of continuing with an empty slang
list; ensure the change references init(), loadWords(...) and the slang field so
the service either aborts startup or flips a health indicator when slang loading
fails.

---

Nitpick comments:
In `@src/main/java/com/ject/vs/user/adapter/web/UserController.java`:
- Around line 44-47: Add Swagger metadata to the checkNicknameSlang endpoint by
annotating the UserController.checkNicknameSlang method with `@Operation`(summary
= "...", description = "...") similar to adjacent endpoints; include a concise
summary like "Check nickname for slang" and a description stating the behavior
(inputs: UserNicknameRec.nickname, requires authentication, returns
NicknameCheckResponse), ensuring imports for
io.swagger.v3.oas.annotations.Operation are present if missing.

In `@src/main/java/com/ject/vs/user/port/WordService.java`:
- Around line 84-86: Rename the method containSlang to containsSlang in
WordService (change the method declaration name from containSlang to
containsSlang) and update all call sites to use the new name (notably the
UserService caller); keep the implementation body as-is (it already delegates to
SlangFilter.containsSlang), and ensure any interfaces, overrides, and unit tests
referencing containSlang are renamed to containsSlang so the code compiles and
remains consistent with SlangFilter.containsSlang.
🪄 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

Run ID: c2140d02-1c26-428d-83ab-50fc806bcb4a

📥 Commits

Reviewing files that changed from the base of the PR and between 589756c and c8dc491.

📒 Files selected for processing (5)
  • src/main/java/com/ject/vs/user/adapter/web/UserController.java
  • src/main/java/com/ject/vs/user/port/UserService.java
  • src/main/java/com/ject/vs/user/port/WordService.java
  • src/main/java/com/ject/vs/util/SlangFilter.java
  • src/main/resources/data/slang.txt

Comment on lines +40 to +48
public static boolean containsSlang(String input, List<String> slangList) {
if(input == null || input.isBlank()) return false;
char[] text = input.toCharArray();

for(String slang : slangList) {
if(kmpContains(text, slang.toCharArray())) return true;
}
return false;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

부분 문자열(substring) 매칭으로 인한 과도한 오탐 위험.

containsSlang은 닉네임에 금칙어가 부분 문자열로 포함되기만 하면 매칭됩니다. 그런데 slang.txt에는 시간(Line 2134), 초딩(Line 2106), 보딩(Line 2109), (Line 1473), (Line 1474) 등 단독으로는 일상어이거나 매우 짧은 항목이 다수 포함되어 있습니다. 그 결과 시간여행자, 초딩탈출 같은 정상 닉네임이 차단되는 오탐이 광범위하게 발생합니다.

단어 경계 검사나 짧은/일상어 항목에 대한 별도 정책(완전 일치 등)을 도입하는 것을 검토해 주세요.

🤖 Prompt for 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.

In `@src/main/java/com/ject/vs/util/SlangFilter.java` around lines 40 - 48,
containsSlang은 현재 입력 내부의 부분 문자열만 검사하므로 짧거나 일상어인 금칙어(slangList의 "시간","초딩","년" 등)에
대해 과도한 오탐이 발생합니다; 수정 방안으로 containsSlang과 kmpContains 호출 로직을 변경해 짧은 항목(예: 길이<=2
또는 <=3)이나 명시된 일상어 목록에 대해선 전체 단어 일치 또는 단어 경계 검사만 허용하고(예: 공백/문장부호/문자 경계 기준), 긴 항목에
대해서만 기존 부분 문자열 검색을 유지하도록 구현하세요; 이를 위해 containsSlang에서 각 slang에 대해
slang.length()를 검사하고 짧은/화이트리스트 항목은 단어 경계 검사 함수(isWordBoundaryMatch)로 처리하고 나머지는
kmpContains(text, slang.toCharArray())를 호출하도록 변경하세요.

if(input == null || input.isBlank()) return false;
char[] text = input.toCharArray();

for(String slang : slangList) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

slangList가 null일 때 NPE 가능성.

현재 호출부(WordService)는 빈 리스트로 초기화하므로 안전하지만, 공개 정적 메서드인 만큼 방어적으로 null 가드를 추가해두면 향후 오용을 예방할 수 있습니다.

🛡️ 제안
-        if(input == null || input.isBlank()) return false;
+        if(input == null || input.isBlank() || slangList == null) return false;
🤖 Prompt for 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.

In `@src/main/java/com/ject/vs/util/SlangFilter.java` at line 44, SlangFilter
currently iterates slangList without a null guard; add a defensive null-check at
the start of the public method in SlangFilter that uses the slangList (e.g., if
(slangList == null || slangList.isEmpty()) return <no-op>), so the method treats
a null list as empty and returns the input/result unchanged (or false) instead
of throwing NPE; update the method that contains the for(String slang :
slangList) loop to return early when slangList is null.

@@ -0,0 +1,2141 @@
가슴빨아
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

첫 줄에 BOM(U+FEFF)이 포함되어 첫 금칙어가 무력화됩니다.

파일 선두에 BOM이 있어 첫 항목이 "\uFEFF가슴빨아"로 로드됩니다. WordService.loadWordsString::trim은 U+0020 이하 문자만 제거하므로 BOM은 제거되지 않고, 결과적으로 첫 번째 금칙어가 정상적으로 매칭되지 않습니다. 파일을 BOM 없는 UTF-8로 저장하거나, 로딩 시 선두 BOM을 제거하도록 처리해 주세요.

🤖 Prompt for 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.

In `@src/main/resources/data/slang.txt` at line 1, The first word contains a
leading BOM (U+FEFF) so WordService.loadWords currently yields "\uFEFF..." and
String::trim doesn't remove it; update loadWords to strip a leading BOM when
reading lines (e.g., remove '\uFEFF' or use Character.isWhitespace check for
U+FEFF) or ensure the file is saved as BOM-free UTF-8; specifically modify
WordService.loadWords to call something like line = line.replaceFirst("^\uFEFF",
"") (or equivalent) before trimming and adding to the word list so the first
forbidden word matches correctly.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant