Conversation
Summary of ChangesHello @yerimi00, 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! This pull request refactors the brand sponsor product listing and detail functionalities to use persistent data from the database instead of mock data. It introduces new entities and a repository to store and retrieve sponsor information, and applies business logic to dynamically display product details based on the brand's industry type. The changes ensure that the API responses for sponsor products are accurate and consistent with the new data model. Highlights
Changelog
Activity
Using Gemini Code AssistThe 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
Customization To customize 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 Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. 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. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
…into fix/357-brand-sponsor-list
There was a problem hiding this comment.
Code Review
이 PR은 브랜드 스폰서 목록 및 상세 API의 목 데이터를 실제 데이터베이스 데이터로 성공적으로 대체했습니다. 새로운 엔티티와 리포지토리가 추가되었고, 이를 사용하도록 서비스 로직이 업데이트되었습니다. getSponsorProducts에서 N+1 문제를 피하기 위해 데이터를 일괄적으로 가져오는 구현은 잘 되어 있습니다. 하지만 getSponsorProducts 내에서 추가적인 N+1 쿼리 문제, 코드 명확성, 데이터 정확성 및 DTO 설계 측면에서 개선할 수 있는 몇 가지 영역을 발견했습니다. 자세한 내용은 개별 코멘트를 확인해주세요.
| return products.stream() | ||
| .map(product -> buildSponsorProductListResponse(brand, product, sponsorInfoBySponsorId.get(product.getId()))) | ||
| .collect(Collectors.toList()); |
There was a problem hiding this comment.
getSponsorProducts 메소드 내에서 products 리스트를 순회하며 buildSponsorProductListResponse를 호출하고, 이어서 SponsorProductListResponseDto.from 메소드가 호출됩니다. 이 과정에서 product.getCampaign().getDescription()을 통해 각 제품의 캠페인 정보에 접근하게 되는데, BrandAvailableSponsor 엔티티의 campaign 연관 필드가 지연 로딩(LAZY loading)으로 설정되어 있어 제품마다 캠페인을 조회하는 추가 쿼리가 발생하여 N+1 문제가 생깁니다.
BrandAvailableSponsorRepository.findByBrandIdWithImages 메소드에서 campaign도 함께 fetch join 하도록 수정하여 이 문제를 해결할 수 있습니다.
예를 들어, BrandAvailableSponsorRepository에 다음과 같은 메소드를 추가하고 사용하는 것을 제안합니다:
@Query("SELECT s FROM BrandAvailableSponsor s LEFT JOIN FETCH s.campaign LEFT JOIN FETCH s.images WHERE s.brand.id = :brandId")
List<BrandAvailableSponsor> findByBrandIdWithCampaignAndImages(@Param("brandId") Long brandId);References
- To prevent N+1 query issues, fetch multiple items in a single batch query (e.g., using an 'IN' clause) instead of querying for each item within a loop.
| private List<String> buildCategories(Brand brand) { | ||
| if (brand.getIndustryType() == null) { | ||
| return List.of(); | ||
| } | ||
| return List.of(brand.getIndustryType().name()); | ||
| } |
There was a problem hiding this comment.
buildCategories 메소드가 List.of(brand.getIndustryType().name())을 반환하도록 구현되어 있는데, 이는 단순히 "BEAUTY" 또는 "FASHION" 문자열만 리스트에 담아 반환합니다. 이전 목(mock) 데이터에서는 "스킨케어", "메이크업"과 같은 더 상세한 카테고리를 사용했습니다. getBrandDetail 메소드에서처럼 tagBrandRepository를 사용하여 브랜드에 연관된 상세 카테고리 태그들을 가져오는 것이 사용자에게 더 유용한 정보를 제공할 것 같습니다. 현재 구현이 의도된 것인지 확인이 필요하며, 아니라면 상세 카테고리를 반환하도록 개선하는 것을 고려해 보세요.
There was a problem hiding this comment.
수정완료 상세 카테고리를 반환해야 하는게 맞습니다.
| List<SponsorItemDto> items = sponsorInfo.getItems() == null | ||
| ? List.of() | ||
| : sponsorInfo.getItems().stream() | ||
| .map(item -> { | ||
| SponsorItemDto.SponsorItemDtoBuilder builder = SponsorItemDto.builder() | ||
| .itemId(item.getId()) | ||
| .availableQuantity(item.getAvailableQuantity()); | ||
| if (industryType == IndustryType.BEAUTY) { | ||
| builder.availableType(item.getAvailableType()) | ||
| .availableSize(item.getAvailableSize()) | ||
| .sizeUnit(item.getSizeUnit()); | ||
| } | ||
| return builder.build(); | ||
| }) | ||
| .collect(Collectors.toList()); |
There was a problem hiding this comment.
BrandSponsorInfo 엔티티에서 items 필드가 new ArrayList<>()로 초기화되어 있으므로 sponsorInfo.getItems()는 null을 반환하지 않습니다. 따라서 sponsorInfo.getItems() == null 확인은 불필요합니다. 해당 null 체크 로직을 제거하여 코드를 간결하게 만들 수 있습니다.
List<SponsorItemDto> items = sponsorInfo.getItems().stream()
.map(item -> {
SponsorItemDto.SponsorItemDtoBuilder builder = SponsorItemDto.builder()
.itemId(item.getId())
.availableQuantity(item.getAvailableQuantity());
if (industryType == IndustryType.BEAUTY) {
builder.availableType(item.getAvailableType())
.availableSize(item.getAvailableSize())
.sizeUnit(item.getSizeUnit());
}
return builder.build();
})
.collect(Collectors.toList());| return SponsorProductListResponseDto.builder() | ||
| .id(sponsor.getId()) | ||
| .name(sponsor.getName()) | ||
| .id(product.getId()) | ||
| .name(product.getName()) | ||
| .thumbnailImageUrl(thumbnail) | ||
| .totalCount(sponsor.getTotalCount()) // 엔티티 필드명에 맞춰 조정 필요 (예: quantity, capacity 등) | ||
| .currentCount(sponsor.getCurrentCount()) // 엔티티 필드명에 맞춰 조정 필요 | ||
| .totalCount(product.getTotalCount()) | ||
| .currentCount(product.getCurrentCount()) | ||
| .brandId(brand.getId()) | ||
| .brandName(brand.getBrandName()) | ||
| .productId(product.getId()) | ||
| .productName(product.getName()) | ||
| .productDescription(product.getCampaign().getDescription()) | ||
| .productImageUrls(productImageUrls) | ||
| .categories(categories) | ||
| .sponsorInfo(sponsorInfo) | ||
| .action(action) | ||
| .build(); |
There was a problem hiding this comment.
SponsorProductListResponseDto에 중복되는 필드가 있습니다. id와 productId는 동일한 값을 가지며, name과 productName도 마찬가지입니다. 클라이언트와의 호환성 유지를 위해 의도된 것이 아니라면, 중복 필드를 제거하여 DTO를 더 명확하게 만드는 것을 고려해 보세요. 예를 들어, id와 name을 제거하고 productId와 productName만 사용하는 것이 좋을 것 같습니다.
return SponsorProductListResponseDto.builder()
.thumbnailImageUrl(thumbnail)
.totalCount(product.getTotalCount())
.currentCount(product.getCurrentCount())
.brandId(brand.getId())
.brandName(brand.getBrandName())
.productId(product.getId())
.productName(product.getName())
.productDescription(product.getCampaign().getDescription())
.productImageUrls(productImageUrls)
.categories(categories)
.sponsorInfo(sponsorInfo)
.action(action)
.build();References
- Avoid adding fields to a DTO if they are not currently required by a consumer, even if they were present in a previous version.
|
/gemini review @gemini-code-assist 빨리 전반적인 리뷰를 다시 해줘. 코드 품질 개선할 점이 있는지, 시스템 장애 문제 잠재 가능성이 없는지 확인해. |
There was a problem hiding this comment.
Code Review
이 PR은 브랜드 협찬 제품 목록 및 상세 조회 API에서 사용하던 목 데이터를 실제 데이터베이스 연동으로 전환하는 변경 사항을 담고 있습니다. BrandSponsorInfo와 BrandSponsorItem 엔티티를 새로 추가하고, BEAUTY와 FASHION 산업 유형에 따라 다른 정보를 제공하도록 로직을 구현했습니다. 특히 N+1 쿼리 문제를 방지하기 위해 배치 조회(batch fetching)를 적용한 점이 좋습니다. 전반적으로 코드가 잘 구조화되어 있습니다.
…into fix/357-brand-sponsor-list # Conflicts: # src/test/java/com/example/RealMatch/notification/application/event/NotificationEventListenerIntegrationTest.java # src/test/java/com/example/RealMatch/notification/application/service/NotificationChannelResolverTest.java # src/test/java/com/example/RealMatch/notification/application/service/NotificationMessageTemplateServiceTest.java
|
@gemini-code-assist 리뷰 제발 하라고 /gemini review 안하면 kill you |
|
/gemini review @gemini-code-assist 빨리 리뷰 달아 |
|
/gemini re-review |
There was a problem hiding this comment.
Code Review
이번 PR은 협찬 제품 목록/상세 응답에서 사용되던 목(mock) 데이터를 실제 DB 데이터와 연동하고, 관련 테이블 구조를 리팩토링하는 중요한 변경을 포함하고 있습니다. 코드 전반적으로 깔끔하게 리팩토링되었고, 여러 헬퍼 메소드를 통해 로직이 잘 분리되었습니다.
다만, 몇 가지 중요한 점들이 확인되어 피드백을 드립니다.
- PR 설명에 명시된
industryType에 따른 필드 노출 로직이 누락되었습니다. (highseverity) - 자동화 테스트 스위트가 비활성화되어 코드 변경의 안정성을 보장하기 어렵습니다. (
criticalseverity) - 코드의 견고성을 높일 수 있는 작은 개선점이 있습니다. (
mediumseverity)
자세한 내용은 각 파일의 주석을 참고해주세요.
| //package com.example.RealMatch; | ||
| // | ||
| //import org.junit.jupiter.api.Test; | ||
| //import org.springframework.boot.test.context.SpringBootTest; | ||
| // | ||
| //@SpringBootTest | ||
| //class RealMatchApplicationTests { | ||
| // | ||
| // @Test | ||
| // void contextLoads() { | ||
| // } | ||
| // | ||
| //} |
| private SponsorInfoDto buildSponsorInfo(BrandAvailableSponsor sponsor) { | ||
| if (sponsor.getItems().isEmpty()) { | ||
| return null; | ||
| } | ||
| List<SponsorItemDto> items = sponsor.getItems().stream() | ||
| .map(item -> { | ||
| SponsorItemDto.SponsorItemDtoBuilder builder = SponsorItemDto.builder() | ||
| .itemId(item.getId()) | ||
| .availableType(item.getAvailableType()) | ||
| .availableQuantity(item.getAvailableQuantity()) | ||
| .availableSize(item.getAvailableSize()) | ||
| .shippingType(item.getShippingType()); | ||
| return builder.build(); | ||
| }) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| return SponsorInfoDto.builder() | ||
| .items(items) | ||
| .build(); | ||
| } |
There was a problem hiding this comment.
PR 설명에 따르면 industryType이 FASHION일 경우 availableQuantity 필드만 노출되어야 한다고 명시되어 있지만, 현재 buildSponsorInfo 메소드는 industryType과 관계없이 모든 필드를 채우고 있습니다. 이 비즈니스 로직이 누락되었습니다.
buildSponsorInfo 메소드가 Brand 객체를 파라미터로 받도록 시그니처를 변경하고, industryType에 따라 DTO 필드를 조건부로 채우도록 로직을 추가해야 합니다.
또한, buildSponsorProductDetailResponse와 buildSponsorProductListResponse 내에서 buildSponsorInfo를 호출하는 부분도 brand 객체를 전달하도록 수정이 필요합니다.
(예: SponsorInfoDto sponsorInfoDto = buildSponsorInfo(brand, product);)
private SponsorInfoDto buildSponsorInfo(Brand brand, BrandAvailableSponsor sponsor) {
if (sponsor.getItems().isEmpty()) {
return null;
}
List<SponsorItemDto> items = sponsor.getItems().stream()
.map(item -> {
SponsorItemDto.SponsorItemDtoBuilder builder = SponsorItemDto.builder()
.availableQuantity(item.getAvailableQuantity());
if (brand.getIndustryType() == IndustryType.BEAUTY) {
builder.itemId(item.getId())
.availableType(item.getAvailableType())
.availableSize(item.getAvailableSize())
.shippingType(item.getShippingType());
}
// FASHION의 경우 availableQuantity만 포함됩니다.
return builder.build();
})
.collect(Collectors.toList());
return SponsorInfoDto.builder()
.items(items)
.build();
}| if (brand.getIndustryType() == IndustryType.BEAUTY) { | ||
| return tagBrandRepository.findTagNamesByBrandIdAndTagCategory( | ||
| brand.getId(), TagCategory.BEAUTY_INTEREST_STYLE.getDescription()); | ||
| } | ||
| if (brand.getIndustryType() == IndustryType.FASHION) { | ||
| return tagBrandRepository.findTagNamesByBrandIdAndTagCategory( | ||
| brand.getId(), TagCategory.FASHION_INTEREST_ITEM.getDescription()); | ||
| } |
There was a problem hiding this comment.
두 개의 독립적인 if 문을 사용하는 것보다 if-else if 구조를 사용하는 것이 더 명확하고 안전합니다. 이렇게 하면 코드가 상호 배타적인 조건을 다루고 있음을 명확히 나타낼 수 있으며, 나중에 새로운 IndustryType이 추가되었을 때 의도치 않게 빈 리스트가 반환되는 실수를 방지할 수 있습니다.
if (brand.getIndustryType() == IndustryType.BEAUTY) {
return tagBrandRepository.findTagNamesByBrandIdAndTagCategory(
brand.getId(), TagCategory.BEAUTY_INTEREST_STYLE.getDescription());
} else if (brand.getIndustryType() == IndustryType.FASHION) {
return tagBrandRepository.findTagNamesByBrandIdAndTagCategory(
brand.getId(), TagCategory.FASHION_INTEREST_ITEM.getDescription());
}…or-list' into fix/357-brand-sponsor-list
There was a problem hiding this comment.
Code Review
이 PR은 브랜드 협찬 제품 목록과 상세 조회 API가 목(mock) 데이터 대신 실제 데이터베이스를 사용하도록 수정하는 것을 목표로 합니다. 데이터베이스 스키마를 리팩토링하고, 관련 서비스 로직과 DTO를 수정하며, 테스트 설정을 H2로 변경하는 등 여러 중요한 변경사항을 포함하고 있습니다.
전반적으로 좋은 방향의 리팩토링이지만, 몇 가지 개선점과 잠재적인 이슈가 보입니다.
- 누락된 요구사항: PR 설명에 언급된
industryType에 따른 필드 노출 로직이 구현되지 않았습니다. - 테스트 비활성화: 기본 테스트 클래스가 주석 처리되어 있어 코드의 안정성을 검증할 수 없습니다.
- 코드 개선: 일부 코드에서 가독성과 효율성을 높일 수 있는 부분이 있습니다.
자세한 내용은 각 파일의 인라인 코멘트를 참고해주세요.
| private SponsorInfoDto buildSponsorInfo(BrandAvailableSponsor sponsor) { | ||
| if (sponsor.getItems().isEmpty()) { | ||
| return null; | ||
| } | ||
| List<SponsorItemDto> items = sponsor.getItems().stream() | ||
| .map(item -> { | ||
| SponsorItemDto.SponsorItemDtoBuilder builder = SponsorItemDto.builder() | ||
| .itemId(item.getId()) | ||
| .availableType(item.getAvailableType()) | ||
| .availableQuantity(item.getAvailableQuantity()) | ||
| .availableSize(item.getAvailableSize()) | ||
| .shippingType(item.getShippingType()); | ||
| return builder.build(); | ||
| }) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| return SponsorInfoDto.builder() | ||
| .items(items) | ||
| .build(); | ||
| } |
There was a problem hiding this comment.
PR 설명에 "industryType이 BEAUTY면 전체 필드, FASHION이면 availableQuantity만 노출"이라는 요구사항이 명시되어 있는데, buildSponsorInfo 메서드에서 이 로직이 누락되었습니다. 현재는 industryType에 관계없이 모든 필드를 채워서 반환하고 있습니다.
요구사항을 반영하려면 buildSponsorInfo 메서드가 Brand 객체를 파라미터로 받아 industryType에 따라 분기 처리를 해야 합니다. 아래와 같이 수정을 제안합니다. 이 수정안에는 가독성을 높이기 위한 스트림 처리 개선도 포함되어 있습니다.
또한, 이 메서드를 호출하는 buildSponsorProductDetailResponse와 buildSponsorProductListResponse 내부의 buildSponsorInfo(product) 호출을 buildSponsorInfo(brand, product)로 변경해야 합니다.
private SponsorInfoDto buildSponsorInfo(Brand brand, BrandAvailableSponsor sponsor) {
if (sponsor.getItems().isEmpty()) {
return null;
}
List<SponsorItemDto> items = sponsor.getItems().stream()
.map(item -> {
if (brand.getIndustryType() == IndustryType.FASHION) {
return SponsorItemDto.builder()
.availableQuantity(item.getAvailableQuantity())
.build();
}
// For BEAUTY and other types, include all fields
return SponsorItemDto.builder()
.itemId(item.getId())
.availableType(item.getAvailableType())
.availableQuantity(item.getAvailableQuantity())
.availableSize(item.getAvailableSize())
.shippingType(item.getShippingType())
.build();
})
.collect(Collectors.toList());
return SponsorInfoDto.builder()
.items(items)
.build();
}References
- DTO에 현재 소비자가 필요로 하지 않는 필드는 추가하지 않아야 합니다. 이는 이전 버전에 존재했더라도 마찬가지입니다.
| //package com.example.RealMatch; | ||
| // | ||
| //import org.junit.jupiter.api.Test; | ||
| //import org.springframework.boot.test.context.SpringBootTest; | ||
| // | ||
| //@SpringBootTest | ||
| //class RealMatchApplicationTests { | ||
| // | ||
| // @Test | ||
| // void contextLoads() { | ||
| // } | ||
| // | ||
| //} |
| } | ||
| if (brand.getIndustryType() == IndustryType.FASHION) { |
|
안녕하세요, @yerimi00님. 리뷰 요청에 대한 문의를 주셔서 감사합니다.
따라서, 새로운 리뷰를 원하시면 이 댓글 스레드가 아닌, 풀 리퀘스트 페이지에 직접 혼란을 드려 죄송합니다. 올바른 방법으로 명령어를 사용해 주시면 감사하겠습니다. |
|
/gemini review |
There was a problem hiding this comment.
Code Review
This pull request refactors the brand sponsor list functionality, transitioning from mock data to a more robust, database-driven approach. Key changes include schema modifications to merge sponsor information into brand_available_sponsor and brand_sponsor_item entities, corresponding updates in the service layer to fetch and process real data, and refactoring of DTOs to reflect the new data structure. The introduction of helper methods in BrandService improves code modularity and readability. However, there are critical inconsistencies in the shipping_type field handling between the migration script and the BrandAvailableSponsor entity, and a high-severity issue with disabled tests that need to be addressed.
| ALTER TABLE brand_available_sponsor | ||
| ADD COLUMN shipping_type VARCHAR(50) NULL; |
There was a problem hiding this comment.
The migration script adds a shipping_type column to the brand_available_sponsor table. However, the BrandAvailableSponsor JPA entity (src/main/java/com/example/RealMatch/brand/domain/entity/BrandAvailableSponsor.java) does not include this field. This inconsistency will lead to a mismatch between the database schema and the application's entity model, potentially causing runtime errors or unexpected behavior during data persistence or retrieval. Given that BrandSponsorItem already has a shippingType, it's likely that shippingType is intended to be item-specific, not at the BrandAvailableSponsor level.
ALTER TABLE brand_available_sponsor
-- REMOVE: ADD COLUMN shipping_type VARCHAR(50) NULL;| private SponsorInfoDto buildSponsorInfo(Brand brand, BrandAvailableSponsor sponsor) { | ||
| if (sponsor.getItems().isEmpty()) { | ||
| return null; | ||
| } | ||
| List<SponsorItemDto> items = sponsor.getItems().stream() | ||
| .map(item -> { | ||
| SponsorItemDto.SponsorItemDtoBuilder builder = SponsorItemDto.builder() | ||
| .availableQuantity(item.getAvailableQuantity()); | ||
| if (brand.getIndustryType() == IndustryType.BEAUTY) { | ||
| builder.itemId(item.getId()) | ||
| .availableType(item.getAvailableType()) | ||
| .availableSize(item.getAvailableSize()) | ||
| .shippingType(item.getShippingType()); | ||
| } | ||
| return builder.build(); | ||
| }) | ||
| .collect(Collectors.toList()); | ||
|
|
||
| return SponsorInfoDto.builder() | ||
| .items(items) | ||
| .build(); | ||
| } |
There was a problem hiding this comment.
In the buildSponsorInfo method, shippingType is conditionally added to SponsorItemDto for BEAUTY industry types. This implies shippingType is an attribute of an individual sponsor item. However, the migration script data/migrations/2026-02-11_merge_sponsor_info_into_available_sponsor.sql adds shipping_type to the brand_available_sponsor table, not just brand_sponsor_item. This creates a discrepancy. If shippingType is item-specific, it should only exist in BrandSponsorItem and be populated from there. If it's a property of the overall sponsor, it should be in BrandAvailableSponsor and SponsorInfoDto.
| @OneToMany(mappedBy = "sponsor", fetch = FetchType.LAZY, cascade = CascadeType.ALL) | ||
| private List<BrandSponsorItem> items = new ArrayList<>(); |
There was a problem hiding this comment.
The migration script data/migrations/2026-02-11_merge_sponsor_info_into_available_sponsor.sql adds a shipping_type column to the brand_available_sponsor table. However, this BrandAvailableSponsor entity does not include a corresponding shippingType field. This will cause a mismatch between your JPA entity and the database schema, leading to potential runtime errors when interacting with this column. Please ensure the entity reflects the database schema.
| //package com.example.RealMatch; | ||
| // | ||
| //import org.junit.jupiter.api.Test; | ||
| //import org.springframework.boot.test.context.SpringBootTest; | ||
| // | ||
| //@SpringBootTest | ||
| //class RealMatchApplicationTests { | ||
| // | ||
| // @Test | ||
| // void contextLoads() { | ||
| // } | ||
| // | ||
| //} |
There was a problem hiding this comment.
The entire RealMatchApplicationTests.java file has been commented out. Disabling tests, especially a root application context test, is a high-severity issue as it significantly reduces test coverage and can hide regressions introduced by the changes in this pull request. Please re-enable these tests and fix any issues that prevent them from passing.
| //package com.example.RealMatch; | |
| // | |
| //import org.junit.jupiter.api.Test; | |
| //import org.springframework.boot.test.context.SpringBootTest; | |
| // | |
| //@SpringBootTest | |
| //class RealMatchApplicationTests { | |
| // | |
| // @Test | |
| // void contextLoads() { | |
| // } | |
| // | |
| //} | |
| package com.example.RealMatch; | |
| import org.junit.jupiter.api.Test; | |
| import org.springframework.boot.test.context.SpringBootTest; | |
| @SpringBootTest | |
| class RealMatchApplicationTests { | |
| @Test | |
| void contextLoads() { | |
| } | |
| } |
Summary
목록/상세 응답에서 sponsorInfo가 목데이터였고, industryType 규칙 반영 필요
Changes
변경사항:
brand_sponsor_info, brand_sponsor_item 엔티티 및 조회 연동
industryType이 BEAUTY면 전체 필드, FASHION이면 availableQuantity만 노출
목록 응답에 상세 필드 포함 유지
영향 범위: 브랜드 협찬가능제품 목록/상세 API 응답 구조 유지 (데이터 소스만 DB로 전환)
테스트: 수동 API 호출 (미자동)
Type of Change
Related Issues
참고 사항