Skip to content

Main & Develop 코드 버전 동기화#360

Merged
pooreumjung merged 15 commits into
mainfrom
develop
Jun 15, 2026
Merged

Main & Develop 코드 버전 동기화#360
pooreumjung merged 15 commits into
mainfrom
develop

Conversation

@pooreumjung

Copy link
Copy Markdown
Member

#️⃣ Issue Number

  • resolved #

📝 요약(Summary)

💬 공유사항 to 리뷰어

✅ PR Checklist

PR이 다음 요구 사항을 충족하는지 확인하세요.

  • 커밋 메시지 컨벤션에 맞게 작성했습니다.
  • 변경 사항에 대한 테스트를 했습니다.(버그 수정/기능에 대한 테스트).

pooreumjung and others added 15 commits March 13, 2026 21:51
…mail

fix: Apple 재로그인 시 email 없는 경우 providerId로 기존 유저 조회
menuLike/menuId 누락 시 FAILED_VALIDATION으로 실패시키고, isLike/imageUrls/menuLikes null도 안전하게 처리해 NPE를 방지합니다.
CreateMenuReviewRequestV2의 rating/menuLike와 MenuLikeRequest의 menuId에 검증을 추가해 잘못된 요청을 조기에 400으로 처리합니다.
Removed placeholder for resolved issue number in PR template.
fix: 리뷰v2 - menu 리뷰 작성시 menuLike가 null일때 발생하는 NPE을 방지해요
…iod-type

feat: 제휴 기간 타입 구분을 위한 periodType 추가
* feat: User Entity내 language컬럼 추가 및 flyway 쿼리문 추가

* feat: 유저 언어 설정 API 추가 및 UserService 중복 코드 제거

* feat: College Entity내 i8n컬럼 추가 및 flyway 쿼리문 추가

* feat: Department Entity내 i8n컬럼 추가 및 flyway 쿼리문 추가

* feat: PartnershipRestaurant Entity내 i8n컬럼 추가 및 flyway 쿼리문 추가

* feat: 제휴정보 조회 시 유저의 언어 설정에 따라서 store_name 분기 처리 추가

* feat: 단과대/학과 정보 조회 시 유저의 언어 설정에 따른 분기 처리 추가

* feat: 유저 프로필 조회에 언어 값 추가 및 유저의 언어 설정 조회 API 추가

* fix: 리뷰사항 반영

* fix: UserService @component 중복 선언 제거 및 @transactional import 경로 수정

* fix: 리뷰 반영
@pooreumjung pooreumjung self-assigned this Jun 15, 2026
@pooreumjung pooreumjung merged commit ac8ff95 into main Jun 15, 2026
1 of 2 checks passed
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

이 PR은 다국어 지원(i18n) 기능을 도입하여 글로벌 사용자 경험을 개선하고, 파트너십 정보에 기간 타입을 추가하여 운영의 유연성을 확보했습니다. 또한, Apple 로그인 시 발생할 수 있는 이메일 누락 케이스를 처리하고 리뷰 관련 입력값 검증을 강화하여 시스템의 전반적인 안정성을 향상시켰습니다.

Highlights

  • 다국어 지원(i18n) 도입: College, Department, PartnershipRestaurant 엔티티에 다국어(KO, EN, JA, VI) 지원을 위한 필드를 추가하고, 관련 API 응답을 사용자의 언어 설정에 맞게 반환하도록 개선했습니다.
  • 사용자 언어 설정 기능: User 엔티티에 언어 설정 필드를 추가하고, 이를 조회 및 수정할 수 있는 API 엔드포인트를 신설했습니다.
  • 파트너십 기간 타입 추가: Partnership 엔티티에 PeriodType(NORMAL, FESTIVAL)을 추가하여 파트너십 기간을 구분할 수 있도록 데이터 구조를 변경했습니다.
  • Apple 로그인 예외 처리 개선: Apple 로그인 시 이메일 정보가 없는 신규 사용자에 대한 예외 처리를 추가하여 인증 안정성을 높였습니다.
  • 리뷰 입력값 검증 강화: 리뷰 작성 및 수정 시 메뉴 좋아요 요청에 대한 유효성 검사를 강화하여 잘못된 데이터 입력을 방지했습니다.
New Features

🧠 You can now enable Memory (public preview) to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.


다국어 지원으로 넓어지는 세상, 코드마다 언어의 꽃이 피어나네. 사용자 설정에 맞춘 정보들, 더 나은 서비스로 나아가는 길.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

이번 풀 리퀘스트는 다국어 지원(KO, EN, JA, VI) 기능 추가 및 사용자 언어 설정 API 구현, 그리고 제휴(Partnership) 정보에 기간 타입(PeriodType)을 도입하는 변경 사항을 포함하고 있습니다. 리뷰어는 성능 향상을 위해 ReviewServiceV2 내 루프 및 스트림 수집기에서 findById를 반복 호출하는 대신 findAllById를 사용하여 배치 조회할 것을 제안했습니다. 또한, 다국어 지원의 일관성을 위해 PartnershipInfo.fromEntityLanguage 파라미터를 추가하여 단과대 및 학과명을 처리하도록 권장하였으며, SystemAppleAuthenticator에서 JWT 검증 시 발생할 수 있는 다양한 예외를 포괄적으로 처리하도록 예외 캐치 범위를 넓힐 것을 제안했습니다. 마지막으로, JPA EnumType.STRING 매핑 시 향후 확장성을 고려하여 DB 마이그레이션 파일에서 ENUM 타입 대신 VARCHAR 타입을 사용할 것을 제안했습니다.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +85 to 94
List<MenuLikeRequest> menuLikes = Optional.ofNullable(request.getMenuLikes()).orElse(Collections.emptyList());
for (MenuLikeRequest menuLike : menuLikes) {
if (menuLike == null || menuLike.getMenuId() == null) {
throw new BaseException(FAILED_VALIDATION);
}
Menu menu = menuRepository.findById(menuLike.getMenuId())
.orElseThrow(() -> new BaseException(NOT_FOUND_MENU));
review.addReviewMenuLike(menu, menuLike.getIsLike());
boolean isLike = Boolean.TRUE.equals(menuLike.getIsLike());
review.addReviewMenuLike(menu, isLike);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

[Reviewer, 2024-01-01] 루프 내에서 menuRepository.findById를 매번 호출하는 대신, findAllById를 사용하여 한 번에 조회하면 데이터베이스 쿼리 횟수를 줄여 성능을 향상시킬 수 있습니다.

        List<MenuLikeRequest> menuLikes = Optional.ofNullable(request.getMenuLikes()).orElse(Collections.emptyList());
        if (menuLikes.stream().anyMatch(m -> m == null || m.getMenuId() == null)) {
            throw new BaseException(FAILED_VALIDATION);
        }
        List<Long> menuIds = menuLikes.stream().map(MenuLikeRequest::getMenuId).distinct().toList();
        List<Menu> menus = menuRepository.findAllById(menuIds);
        if (menus.size() != menuIds.size()) {
            throw new BaseException(NOT_FOUND_MENU);
        }
        Map<Long, Menu> menuMap = menus.stream().collect(Collectors.toMap(Menu::getId, m -> m));
        for (MenuLikeRequest menuLike : menuLikes) {
            Menu menu = menuMap.get(menuLike.getMenuId());
            boolean isLike = Boolean.TRUE.equals(menuLike.getIsLike());
            review.addReviewMenuLike(menu, isLike);
        }

Comment on lines +403 to +416
List<MenuLikeRequest> menuLikeRequests = Optional.ofNullable(request.getMenuLikes()).orElse(Collections.emptyList());

Map<Menu, Boolean> menuLikes = menuLikeRequests.stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(
menuLike -> {
if (menuLike.getMenuId() == null) {
throw new BaseException(FAILED_VALIDATION);
}
return menuRepository.findById(menuLike.getMenuId())
.orElseThrow(() -> new BaseException(
NOT_FOUND_MENU));
},
menuLike -> Boolean.TRUE.equals(menuLike.getIsLike())));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

[Reviewer, 2024-01-01] Collectors.toMap 내부에서 menuRepository.findById를 호출하면 매 요소마다 쿼리가 실행되므로, findAllById를 사용하여 일괄 조회한 후 Map으로 변환하여 처리하는 것이 효율적입니다.

Suggested change
List<MenuLikeRequest> menuLikeRequests = Optional.ofNullable(request.getMenuLikes()).orElse(Collections.emptyList());
Map<Menu, Boolean> menuLikes = menuLikeRequests.stream()
.filter(Objects::nonNull)
.collect(Collectors.toMap(
menuLike -> {
if (menuLike.getMenuId() == null) {
throw new BaseException(FAILED_VALIDATION);
}
return menuRepository.findById(menuLike.getMenuId())
.orElseThrow(() -> new BaseException(
NOT_FOUND_MENU));
},
menuLike -> Boolean.TRUE.equals(menuLike.getIsLike())));
List<MenuLikeRequest> menuLikeRequests = Optional.ofNullable(request.getMenuLikes()).orElse(Collections.emptyList());
if (menuLikeRequests.stream().anyMatch(m -> m == null || m.getMenuId() == null)) {
throw new BaseException(FAILED_VALIDATION);
}
List<Long> menuIds = menuLikeRequests.stream().map(MenuLikeRequest::getMenuId).distinct().toList();
List<Menu> menus = menuRepository.findAllById(menuIds);
if (menus.size() != menuIds.size()) {
throw new BaseException(NOT_FOUND_MENU);
}
Map<Long, Menu> menuMap = menus.stream().collect(Collectors.toMap(Menu::getId, m -> m));
Map<Menu, Boolean> menuLikes = menuLikeRequests.stream()
.collect(Collectors.toMap(
menuLike -> menuMap.get(menuLike.getMenuId()),
menuLike -> Boolean.TRUE.equals(menuLike.getIsLike()),
(existing, replacement) -> replacement));

.description(partnership.getDescription())
.startDate(partnership.getStartDate())
.endDate(partnership.getEndDate())
.periodType(partnership.getPeriodType())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

[Reviewer, 2024-01-01] 단과대 및 학과명을 다국어로 지원하기 위해, fromEntity 메서드에 Language 파라미터를 추가하고 collegeName 설정 시 getNameByLanguage(language)를 호출하도록 수정해야 합니다.

Comment on lines +48 to +56
try {
claims = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(identityToken)
.getBody();
} catch (ExpiredJwtException exception) {
throw new BaseException(INVALID_IDENTITY_TOKEN);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

[Reviewer, 2024-01-01] ExpiredJwtException뿐만 아니라 SignatureException, MalformedJwtException 등 다른 JWT 관련 예외도 처리할 수 있도록 JwtException 및 IllegalArgumentException을 캐치하는 것이 안전합니다.

Suggested change
try {
claims = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(identityToken)
.getBody();
} catch (ExpiredJwtException exception) {
throw new BaseException(INVALID_IDENTITY_TOKEN);
}
try {
claims = Jwts.parserBuilder()
.setSigningKey(publicKey)
.build()
.parseClaimsJws(identityToken)
.getBody();
} catch (JwtException | IllegalArgumentException exception) {
throw new BaseException(INVALID_IDENTITY_TOKEN);
}

-- =========================

ALTER TABLE partnership
ADD COLUMN period_type ENUM ('NORMAL', 'FESTIVAL') NOT NULL DEFAULT 'NORMAL';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

[Reviewer, 2024-01-01] JPA의 EnumType.STRING을 사용할 때는 데이터베이스 컬럼 타입을 ENUM 대신 VARCHAR로 정의하는 것이 새로운 Enum 값이 추가될 때 스키마 변경 없이 대응할 수 있어 유지보수에 유리합니다.

    ADD COLUMN period_type VARCHAR(50) NOT NULL DEFAULT 'NORMAL';

@@ -0,0 +1,2 @@
ALTER TABLE user
ADD COLUMN language ENUM ('KO', 'EN', 'JA', 'VI') NOT NULL DEFAULT 'KO';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

[Reviewer, 2024-01-01] JPA의 EnumType.STRING 매핑 시 ENUM 타입 대신 VARCHAR 타입을 사용하면, 추후 새로운 언어가 추가될 때 데이터베이스 DDL 변경 없이 Java 코드 수정만으로 대응이 가능하여 유연성이 높아집니다.

    ADD COLUMN language VARCHAR(20) NOT NULL DEFAULT 'KO';

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants