Skip to content

feat: 내 정보 조회 + 사용자 언어 설정 변경#66

Merged
Hminkyung merged 25 commits into
developfrom
feat/#62-language-change
May 25, 2026
Merged

feat: 내 정보 조회 + 사용자 언어 설정 변경#66
Hminkyung merged 25 commits into
developfrom
feat/#62-language-change

Conversation

@Hminkyung
Copy link
Copy Markdown
Collaborator

@Hminkyung Hminkyung commented May 25, 2026

📌 작업 요약

  • 요약: 내 정보를 조회하는 API를 디자인에 맞게 수정하고 사용자 언어 설정을 변경하는 즉시 해당 언어로 번역, AI, 체크리스트가 해당언어로 출력되게 진행합니다.
  • 가정통신문 업로드 당시에 parameter로 받았던 언어를 사용자 언어 설정 변경에 맞게 받아와서 적용하게 합니다.
  • flyway migration 파일들을 추가합니다. V12& V13
  • 제목과 체크리스트들도 해당 언어로 번역합니다.
  • FIX: httpClient 맞지 않는 부분을 맞춥니다.
  • 테스트 코드에 언어 코드 추가
  • 관련 이슈: closes [FEAT] 언어설정 변경 API #62

🌿 브랜치 정보

  • Source: feat/#62-language-change
  • Target: develop (기본)

✅ 체크리스트

  • 브랜치 컨벤션 준수 (feat/refac/hotfix/chore/design/bugfix)
  • 커밋 컨벤션 준수 (feat/fix/refactor/docs/style/chore)
  • self-review 완료
  • 테스트 및 로컬 실행 확인 완료

🧪 테스트 결과

  • (테스트 코드 실행 결과 스크린샷이나 로그, 또는 테스트 방법)
스크린샷 2026-05-25 084926 스크린샷 2026-05-25 145151

에러코드 추가

USER4001 (HTTP 400 Bad Request): 지원하지 않는 언어 코드 요청 차단

  • 허용값(KO/US/ZH/VI) 외의 언어 코드가 PATCH /api/v1/users/me/language 요청에 포함된 경우
  • 에러 메시지: "지원하지 않는 언어 코드입니다. (KO, US, ZH, VI 중 하나여야 합니다.)"
  • 발생 위치: ChangeLanguageRequest.languageCode @pattern 검증 실패
  • 커밋 해시: 9273a8d

Summary by CodeRabbit

  • 새로운 기능

    • 회원가입 시 선호 언어(KO/US/ZH/VI) 선택 항목 추가
    • 내 정보에서 언어 변경(PATCH /me/language) 기능 추가
    • 알림 설정 변경 API 추가
  • 개선사항

    • 내 정보 조회에 언어 코드, 알림 상태, 가입일 포함
    • 뉴스레터 업로드에 사용자 언어 자동 적용
    • 뉴스레터 생성 파이프라인에 요청 언어 기반 번역/국문화 지원

Review Change Stack

@Hminkyung Hminkyung self-assigned this May 25, 2026
@Hminkyung Hminkyung added the feat 새로운 기능 추가 작업 label May 25, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 25, 2026

📝 Walkthrough

Walkthrough

사용자 엔티티에 언어 코드와 알림 설정을 저장하고, 회원가입 시 언어를 지정하도록 변경했습니다. 사용자 정보 조회 및 언어 변경 API를 추가하고, 뉴스레터 업로드 시 사용자의 저장된 언어를 활용하도록 수정했습니다.

Changes

사용자 엔티티 확장 및 회원가입 언어 지원

Layer / File(s) Summary
사용자 엔티티 스키마 및 DB 마이그레이션
src/main/java/com/gachi/be/domain/user/entity/User.java, src/main/java/com/gachi/be/domain/user/entity/enums/UserStatus.java, src/main/resources/db/migration/V12__*.sql, src/main/resources/db/migration/V13__*.sql
User 엔티티에 languageCode(기본값 "KO")와 notificationEnabled(기본값 true) 필드를 추가하고, updateLanguage(), updateNotificationEnabled() 메서드를 정의합니다. UserStatus enum을 entity.enums 패키지로 이동하고 DB 마이그레이션으로 두 컬럼을 추가합니다.
회원가입 요청 스키마 및 인증 처리
src/main/java/com/gachi/be/domain/auth/dto/request/SignupRequest.java, src/main/java/com/gachi/be/domain/auth/service/impl/AuthServiceImpl.java, src/main/java/com/gachi/be/domain/auth/service/AuthenticatedUserResolver.java
SignupRequest@Pattern 검증이 적용된 languageCode 필드를 추가하고, 회원가입 시 User.builder()에서 언어 코드를 저장하도록 AuthServiceImpl을 수정합니다. 인증 관련 파일의 UserStatus import 경로를 갱신합니다.
UserStatus 임포트 경로 일관성 업데이트
src/main/java/com/gachi/be/domain/user/repository/UserRepository.java, src/main/java/com/gachi/be/global/security/JwtAuthenticationFilter.java, src/test/java/com/gachi/be/domain/auth/api/controller/AuthRateLimitIntegrationTest.java, src/test/java/com/gachi/be/domain/child/api/controller/ChildControllerIntegrationTest.java
모든 파일에서 UserStatus import를 com.gachi.be.domain.user.entity.enums.UserStatus로 통일합니다.

사용자 정보 및 언어 변경 API

Layer / File(s) Summary
사용자 DTO 및 응답 스키마 정의
src/main/java/com/gachi/be/domain/user/dto/response/UserMeResponse.java, src/main/java/com/gachi/be/domain/user/dto/request/ChangeLanguageRequest.java, src/main/java/com/gachi/be/domain/user/dto/request/ChangeNotificationRequest.java
UserMeResponse를 확장하여 languageCode, notificationEnabled, createdAt 필드를 포함하고 phoneNumber를 제거합니다. ChangeLanguageRequestChangeNotificationRequest DTO를 신규로 추가하여 요청 검증을 정의합니다.
사용자 API 엔드포인트 및 언어 변경 로직
src/main/java/com/gachi/be/domain/user/api/controller/UserController.java
GET /me 응답에 새로운 필드를 채우도록 수정합니다. PATCH /me/language 엔드포인트를 추가하여 사용자 언어를 업데이트하고 저장한 뒤, 진행 중인 뉴스레터(PENDING/PROCESSING)를 FAILED로 취소 처리한 후 성공 응답을 반환합니다.
전역 응답 코드 추가
src/main/java/com/gachi/be/global/code/ErrorCode.java, src/main/java/com/gachi/be/global/code/SuccessCode.java
ErrorCodeUSER_LANGUAGE_CODE_INVALID(USER4001, BAD_REQUEST), SuccessCodeUSER_LANGUAGE_UPDATED(USER2001, OK) 상수를 추가합니다.

뉴스레터 업로드 언어 처리 재구성

Layer / File(s) Summary
뉴스레터 컨트롤러 파라미터 단순화
src/main/java/com/gachi/be/domain/newsletter/api/controller/NewsletterController.java
upload 메서드의 language 파라미터와 관련 검증 로직을 제거하여 userId, file, childId만 수신하도록 축소합니다.
뉴스레터 서비스 언어 조회 로직 추가
src/main/java/com/gachi/be/domain/newsletter/service/NewsletterService.java, src/main/java/com/gachi/be/domain/newsletter/service/impl/NewsletterServiceImpl.java
NewsletterService.upload() 시그니처에서 userLanguage 파라미터를 제거합니다. 구현에서 UserRepository 의존성을 추가하고 resolveUserLanguage(userId) 헬퍼를 구현하여 사용자 엔티티에서 언어를 조회하며, 조회 실패 또는 공백 시 기본값 "KO"를 반환합니다.
뉴스레터 리포지토리 일괄 취소 메서드
src/main/java/com/gachi/be/domain/newsletter/repository/NewsletterRepository.java
cancelInProgressByUserId(userId, targetStatuses, failedStatus) 메서드를 추가하여 사용자별로 특정 상태의 뉴스레터를 일괄 업데이트하는 JPQL 쿼리를 정의합니다.

Sequence Diagram

sequenceDiagram
  participant User as 사용자
  participant AuthAPI as 회원가입 API
  participant UserService as 사용자 서비스
  participant Database as 데이터베이스
  User->>AuthAPI: POST /signup (언어 코드 포함)
  AuthAPI->>UserService: signup(SignupRequest)
  UserService->>Database: User.builder().languageCode(...).save()
  Database-->>UserService: User 저장 완료
  UserService-->>AuthAPI: 회원가입 성공
  AuthAPI-->>User: 토큰 반환
  User->>UserAPI: PATCH /me/language (새 언어)
  UserAPI->>Database: updateLanguage(newLanguage)
  UserAPI->>Database: cancelInProgressByUserId(FAILED)
  Database-->>UserAPI: 취소된 건수
  UserAPI-->>User: USER_LANGUAGE_UPDATED
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • GACHI-Project/GACHI-BE#12: 본 PR에서 추가된 AuthenticatedUserResolverUserStatus import 경로 갱신과 사용자 상태 검증 로직이 검색된 PR과 동일 코드 경로를 공유합니다.
  • GACHI-Project/GACHI-BE#5: 본 PR과 검색된 PR 모두 AuthServiceImpl.signup(SignupRequest) 회원가입 로직을 확장하여 User 엔티티 저장 시 추가 필드를 처리합니다.
  • GACHI-Project/GACHI-BE#9: 두 PR 모두 AuthServiceImpl의 회원가입 경로를 수정하여 사용자 생성 시 새로운 필드 또는 검증을 추가합니다.

Suggested labels

feat

Suggested reviewers

  • deli-minju
🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive PR 설명이 기본 구조는 갖추었으나 필수 섹션이 완전하지 않습니다. 테스트 결과 섹션을 구체적으로 작성하고, 브랜치/커밋 컨벤션 체크리스트를 명확히 표시해주세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 주요 변경사항을 명확하게 요약하고 있습니다. 내 정보 조회 API 수정과 사용자 언어 설정 변경이라는 두 가지 핵심 기능을 간결하게 표현했습니다.
Linked Issues check ✅ Passed PR이 이슈 #62의 요구사항인 언어설정 변경 API 구현과 반환값의 해당 언어로 변경을 모두 충족합니다. User 엔티티에 languageCode 필드 추가, 언어 변경 API 구현, NewsletterService에서 사용자 언어 조회 등이 포함되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 언어설정 변경 API 구현과 내 정보 조회 API 개선이라는 정의된 목표와 관련있습니다. UserStatus enum 경로 이동은 기술적 리팩토링으로 필요한 변경입니다.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/#62-language-change

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

@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: 5

🤖 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/gachi/be/domain/auth/dto/request/SignupRequest.java`:
- Around line 20-22: The languageCode parameter in SignupRequest is only
annotated with `@Pattern`, allowing nulls to pass and default to "KO"; change the
declaration for languageCode in the SignupRequest (the parameter named
languageCode in the SignupRequest record/constructor) to be required by adding a
null-check constraint (e.g., annotate with `@NotNull` or `@NotBlank` alongside the
existing `@Pattern`) so validation fails on missing language selection instead of
silently falling back.

In
`@src/main/java/com/gachi/be/domain/newsletter/repository/NewsletterRepository.java`:
- Around line 100-112: The cancelInProgressByUserId query only updates status
and leaves Newsletter.language unchanged, causing retried jobs to use the old
language; modify the repository method cancelInProgressByUserId to accept a new
language parameter (e.g., `@Param`("language") String newLanguage) and change the
JPQL to "SET n.status = :failedStatus, n.language = :language" (update the
method signature to include the language param), then update the caller (e.g.,
UserController.changeLanguage(...) where cancelInProgressByUserId is invoked) to
pass request.languageCode() so in-progress PENDING/PROCESSING newsletters get
their language updated; alternatively, if you prefer, ensure retryAnalysis()
overwrites newsletter.language with the current user language before
reprocessing (refer to methods cancelInProgressByUserId and retryAnalysis).

In `@src/main/java/com/gachi/be/domain/user/api/controller/UserController.java`:
- Around line 69-80: The controller unconditionally cancels in-progress
pipelines even when the language didn't change; modify UserController to compare
previousLanguage and newLanguage (e.g., using Objects.equals or String.equals)
and only call user.updateLanguage(...), userRepository.save(user) and
newsletterRepository.cancelInProgressByUserId(...) when the language actually
changed; if unchanged, skip the cancel logic (and optionally skip calling
update/save) to avoid interrupting active pipelines.

In
`@src/main/java/com/gachi/be/domain/user/dto/request/ChangeNotificationRequest.java`:
- Around line 6-7: Change the record field type in ChangeNotificationRequest
from the primitive boolean to the wrapper Boolean so `@NotNull` can actually
validate presence; update the record declaration (the notificationEnabled
component) to use Boolean and adjust any call sites or tests that construct this
DTO to pass a Boolean (or handle null) so missing JSON produces a null and
triggers validation.

In `@src/main/java/com/gachi/be/domain/user/entity/User.java`:
- Around line 116-118: updateLanguage 메서드가 null 또는 blank 값을 허용해 DB 제약이나 잘못된 언어
처리로 이어지므로 User.updateLanguage에서 입력값을 검증해 도메인 불변식을 강제하세요: languageCode가 null이거나 빈
문자열(또는 공백만 있는 경우)일 때는 trim 후에도 비어있으면 IllegalArgumentException(또는 도메인 전용 예외)로 즉시
실패시키고, 유효하면 trim한 값을 this.languageCode에 할당하도록 수정하세요; 메서드명 updateLanguage와 엔티티
User, 컬럼 users.language_code를 참고해서 변경하세요.
🪄 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: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 93e39d3a-234f-48af-816f-d78220be4b5b

📥 Commits

Reviewing files that changed from the base of the PR and between 79d16a0 and cb243b3.

📒 Files selected for processing (21)
  • src/main/java/com/gachi/be/domain/auth/dto/request/SignupRequest.java
  • src/main/java/com/gachi/be/domain/auth/service/AuthenticatedUserResolver.java
  • src/main/java/com/gachi/be/domain/auth/service/impl/AuthServiceImpl.java
  • src/main/java/com/gachi/be/domain/newsletter/api/controller/NewsletterController.java
  • src/main/java/com/gachi/be/domain/newsletter/repository/NewsletterRepository.java
  • src/main/java/com/gachi/be/domain/newsletter/service/NewsletterService.java
  • src/main/java/com/gachi/be/domain/newsletter/service/impl/NewsletterServiceImpl.java
  • src/main/java/com/gachi/be/domain/user/api/controller/UserController.java
  • src/main/java/com/gachi/be/domain/user/dto/request/ChangeLanguageRequest.java
  • src/main/java/com/gachi/be/domain/user/dto/request/ChangeNotificationRequest.java
  • src/main/java/com/gachi/be/domain/user/dto/response/UserMeResponse.java
  • src/main/java/com/gachi/be/domain/user/entity/User.java
  • src/main/java/com/gachi/be/domain/user/entity/enums/UserStatus.java
  • src/main/java/com/gachi/be/domain/user/repository/UserRepository.java
  • src/main/java/com/gachi/be/global/code/ErrorCode.java
  • src/main/java/com/gachi/be/global/code/SuccessCode.java
  • src/main/java/com/gachi/be/global/security/JwtAuthenticationFilter.java
  • src/main/resources/db/migration/V12__user_add_language_code.sql
  • src/main/resources/db/migration/V13__user_add_notification_enabled.sql
  • src/test/java/com/gachi/be/domain/auth/api/controller/AuthRateLimitIntegrationTest.java
  • src/test/java/com/gachi/be/domain/child/api/controller/ChildControllerIntegrationTest.java

Comment thread src/main/java/com/gachi/be/domain/newsletter/repository/NewsletterRepository.java Outdated
Comment thread src/main/java/com/gachi/be/domain/user/api/controller/UserController.java Outdated
Comment on lines +6 to +7
public record ChangeNotificationRequest(
@NotNull(message = "notificationEnabled는 필수입니다.") boolean notificationEnabled) {}
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 | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# primitive boolean + `@NotNull` 조합 확인
rg -nP '`@NotNull`\([^\n]*\)\s*boolean\s+notificationEnabled' src/main/java/com/gachi/be/domain/user/dto/request/ChangeNotificationRequest.java

# 동일 패턴이 다른 DTO에도 있는지 점검
rg -nP '`@NotNull`\([^\n]*\)\s*boolean\s+' src/main/java

Repository: GACHI-Project/GACHI-BE

Length of output: 324


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 1) 해당 선언을 정확히 확인
echo "---- ChangeNotificationRequest.java (lines around record) ----"
nl -ba src/main/java/com/gachi/be/domain/user/dto/request/ChangeNotificationRequest.java | sed -n '1,120p'

# 2) 동일 안티패턴 전체 개수/경로 확인
echo "---- All occurrences of `@NotNull`(...) boolean <name> in src/main/java ----"
rg -nP '`@NotNull`\([^\n]*\)\s*boolean\s+\w+' src/main/java || true

echo "---- Count ----"
rg -nP '`@NotNull`\([^\n]*\)\s*boolean\s+\w+' src/main/java | wc -l

Repository: GACHI-Project/GACHI-BE

Length of output: 190


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "---- ChangeNotificationRequest.java (lines around record) ----"
cat -n src/main/java/com/gachi/be/domain/user/dto/request/ChangeNotificationRequest.java | sed -n '1,120p'

echo "---- All occurrences of `@NotNull`(...) boolean <name> in src/main/java ----"
rg -nP '`@NotNull`\([^\n]*\)\s*boolean\s+\w+' src/main/java || true

echo "---- Count ----"
rg -nP '`@NotNull`\([^\n]*\)\s*boolean\s+\w+' src/main/java | wc -l || true

Repository: GACHI-Project/GACHI-BE

Length of output: 687


@NotNull을 primitive boolean에 적용한 부분 수정 필요 (ChangeNotificationRequest.java)

  • notificationEnabledboolean primitive라 @NotNull은 null 검증이 불가능합니다.
  • 요청 JSON에서 해당 필드가 누락되면 primitive 기본값(예: false)으로 처리되어 “필수” 의미가 깨질 수 있습니다.
  • 동일 패턴(@NotNull(...) boolean)은 src/main/java에서 이 DTO 1건만 확인됩니다.

booleanBoolean(래퍼 타입)으로 바꿔 null 유무로 필수 검증이 되게 하세요.

🤖 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/gachi/be/domain/user/dto/request/ChangeNotificationRequest.java`
around lines 6 - 7, Change the record field type in ChangeNotificationRequest
from the primitive boolean to the wrapper Boolean so `@NotNull` can actually
validate presence; update the record declaration (the notificationEnabled
component) to use Boolean and adjust any call sites or tests that construct this
DTO to pass a Boolean (or handle null) so missing JSON produces a null and
triggers validation.

Comment thread src/main/java/com/gachi/be/domain/user/entity/User.java
@Hminkyung Hminkyung requested a review from deli-minju May 25, 2026 15:00
Copy link
Copy Markdown
Contributor

@deli-minju deli-minju left a comment

Choose a reason for hiding this comment

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

내 정보 조회 응답과 언어 설정 변경 흐름이 디자인 요구사항에 맞게 잘 반영된 것 같습니다. 고생하셨습니다!

@Hminkyung Hminkyung merged commit ecd502f into develop May 25, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat 새로운 기능 추가 작업

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 언어설정 변경 API

2 participants