Skip to content

[FEAT] 마이페이지 면접 내역 조회 필터링/검색 추가 및 Redis 직렬화 설정 보완#141

Merged
gudals2040 merged 3 commits intodevfrom
fix/cors-policy
Mar 12, 2026
Merged

[FEAT] 마이페이지 면접 내역 조회 필터링/검색 추가 및 Redis 직렬화 설정 보완#141
gudals2040 merged 3 commits intodevfrom
fix/cors-policy

Conversation

@khyun722
Copy link
Collaborator

작업 내용

  • 마이 페이지 면접 세션 목록 조회 API에 면접 모드 필터링 및 키워드 검색 기능 추가
  • QueryDSL을 활용해 검색 조건에 따른 동적 쿼리 구현
  • Redis에 통계 등 수치 데이터 저장 시 BigDecimal 타입이 정상적으로 처리되도록 JSON 직렬화 설정 추가

변경 사항 및 주의 사항

  • 면접 목록 조회 API에 @RequestParam으로 mode와 keyword 파라미터 추가
  • Controller로부터 전달받은 type과 keyword를 Repository로 전달하도록 메서드 시그니처 수정
  • 인터페이스에 type과 keyword 매개변수 추가
  • eqType(), containsKeyword() 메서드를 통한 QueryDSL 동적 쿼리 조건 추가
  • 검색어 필터링이 올바르게 동작하도록 전체 개수 조회에도 resume, jobPosting 테이블 LEFT JOIN 추가
  • PolymorphicTypeValidator 설정에 .allowIfBaseType("java.math")를 추가하여 수학 관련 객체 직렬화 허용

체크 리스트

  • PR 제목 규칙을 준수했습니다
  • 관련 이슈를 연결했습니다
  • 본문 내용을 명확하게 작성했습니다
  • 정상 작동을 로컬 환경에서 검증했습니다

@gemini-code-assist
Copy link
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은 사용자 마이페이지의 면접 세션 목록 조회 기능을 강화하고, Redis 데이터 처리의 안정성을 높입니다. 사용자는 이제 면접 모드별로 필터링하거나 특정 키워드로 면접 내역을 검색할 수 있어, 자신의 면접 기록을 더욱 효율적으로 관리하고 탐색할 수 있게 됩니다. 또한, Redis에 BigDecimal 타입의 데이터가 올바르게 저장되도록 직렬화 설정을 보완하여 데이터 무결성을 확보했습니다.

Highlights

  • 마이페이지 면접 내역 조회 기능 개선: 마이페이지 면접 세션 목록 조회 API에 면접 모드 필터링 및 키워드 검색 기능이 추가되었습니다.
  • QueryDSL 동적 쿼리 구현: 검색 조건(면접 모드, 키워드)에 따라 동적으로 쿼리를 생성하도록 QueryDSL이 활용되었습니다.
  • Redis 직렬화 설정 보완: Redis에 통계 등 수치 데이터 저장 시 BigDecimal 타입이 정상적으로 직렬화되도록 JSON 직렬화 설정이 추가되었습니다.
Changelog
  • src/main/java/com/aibe/team2/domain/interview/repository/InterviewSessionRepositoryCustom.java
    • findInterviewSessionList 메서드 시그니처에 InterviewType type과 String keyword 매개변수가 추가되었습니다.
  • src/main/java/com/aibe/team2/domain/interview/repository/InterviewSessionRepositoryImpl.java
    • findInterviewSessionList 메서드의 매개변수에 InterviewType type과 String keyword가 추가되어 인터페이스 변경 사항을 반영했습니다.
    • eqType(InterviewType type) 및 containsKeyword(String keyword) 프라이빗 메서드가 추가되어 QueryDSL 동적 쿼리 조건을 구현했습니다.
    • 데이터 조회 쿼리와 전체 개수 조회 쿼리 모두에 resume 및 jobPosting 테이블에 대한 LEFT JOIN이 추가되었고, eqType 및 containsKeyword 조건을 적용하여 필터링 및 검색 기능을 활성화했습니다.
  • src/main/java/com/aibe/team2/domain/mypage/controller/MypageInterviewController.java
    • getInterviewSessionList 엔드포인트에 @RequestParam으로 mode (InterviewType)와 keyword 파라미터가 추가되었습니다.
    • mypageInterviewService.getInterviewSessionList 호출 시 새로운 type과 keyword 매개변수를 전달하도록 수정되었습니다.
    • 더 이상 직접 사용되지 않는 CustomUserDetails import와 @AuthenticationPrincipal 어노테이션이 제거되었습니다.
  • src/main/java/com/aibe/team2/domain/mypage/service/MypageInterviewService.java
    • getInterviewSessionList 메서드 시그니처에 InterviewType type과 String keyword 매개변수가 추가되었고, 이를 interviewSessionRepository로 전달하도록 로직이 업데이트되었습니다.
  • src/main/java/com/aibe/team2/global/redis/RedisConfig.java
    • PolymorphicTypeValidator 설정에 .allowIfBaseType("java.math")가 추가되어 BigDecimal과 같은 수학 관련 객체의 Redis 직렬화를 허용했습니다.
Activity
  • 현재까지 이 PR에 대한 특별한 활동(댓글, 리뷰 진행 상황 등)은 없습니다.
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 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 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

  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.

Copy link
Contributor

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

Choose a reason for hiding this comment

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

Code Review

이 PR은 마이페이지의 면접 내역 조회 기능에 필터링과 검색을 추가하고, Redis 직렬화 설정을 개선하는 내용을 담고 있습니다. 전반적으로 기능 구현은 잘 이루어졌습니다. QueryDSL을 사용한 동적 쿼리 구현과 카운트 쿼리 동기화 등 좋은 변경 사항들이 포함되어 있습니다. 다만, 코드의 유지보수성과 명확성을 높이기 위한 몇 가지 개선점을 제안합니다. 컨트롤러에서 요청 파라미터 이름과 변수 이름의 일관성을 맞추고, Repository 구현체에서 중복되는 쿼리 로직을 리팩토링하는 것을 고려해볼 수 있습니다. 또한, 더 타입-안전한 코드를 위해 엔티티 필드 타입에 대한 제안도 포함했습니다. 자세한 내용은 각 파일의 주석을 참고해주세요.

Comment on lines +62 to +73
JPAQuery<Long> countQuery = queryFactory
.select(interviewSession.count())
.from(interviewSession)
.where(interviewSession.memberId.eq(memberId));
// ✨ [수정됨] 검색어 필터링을 위해 JOIN이 필요하므로 카운트 쿼리에도 추가
.leftJoin(resume).on(interviewSession.resumeId.eq(resume.id))
.leftJoin(jobPosting).on(interviewSession.jobPostingId.eq(jobPosting.id))
// ✨ [수정됨] 데이터 쿼리와 완벽하게 동일한 조건 적용
.where(
interviewSession.memberId.eq(memberId),
eqType(type),
containsKeyword(keyword)
);
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

내용 조회 쿼리와 개수 조회 쿼리에서 from, leftJoin, where 절이 중복되고 있습니다. 이는 향후 쿼리 조건이 변경될 때 두 군데를 모두 수정해야 하므로 유지보수 과정에서 실수를 유발할 수 있습니다.

다음과 같이 공통 쿼리 로직을 추출하여 중복을 제거하는 리팩토링을 고려해볼 수 있습니다.

@Override
public Page<InterviewSessionListResponse> findInterviewSessionList(
        Long memberId,
        InterviewType type,
        String keyword,
        Pageable pageable
) {
    // from, join, where 절을 포함하는 기본 쿼리
    JPAQuery<?> baseQuery = queryFactory
            .from(interviewSession)
            .leftJoin(resume).on(interviewSession.resumeId.eq(resume.id))
            .leftJoin(jobPosting).on(interviewSession.jobPostingId.eq(jobPosting.id))
            .where(
                    interviewSession.memberId.eq(memberId),
                    eqType(type),
                    containsKeyword(keyword)
            );

    // 1. 실제 데이터 조회 쿼리 (select, orderBy, offset, limit 추가)
    List<InterviewSessionListResponse> content = baseQuery.clone() // baseQuery를 복제하여 사용
            .select(Projections.constructor(InterviewSessionListResponse.class,
                interviewSession.id,
                resume.title,
                jobPosting.companyName,
                jobPosting.jobTitle,
                interviewSession.interviewMode,
                interviewSession.interviewType,
                interviewSession.status,
                interviewSession.finalScore,
                interviewSession.createdAt
            ))
            .orderBy(interviewSession.createdAt.desc())
            .offset(pageable.getOffset())
            .limit(pageable.getPageSize())
            .fetch();

    // 2. 전체 개수 조회 쿼리 (select count 추가)
    JPAQuery<Long> countQuery = baseQuery.clone().select(interviewSession.count());

    // 3. 데이터와 카운트 쿼리를 조합하여 Page 객체로 반환
    return PageableExecutionUtils.getPage(content, pageable, countQuery::fetchOne);
}

JPAQuery는 상태를 가지므로, clone()을 사용하여 각 쿼리를 독립적으로 실행하는 것이 중요합니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정완료

Comment on lines +80 to +85
private BooleanExpression eqType(InterviewType type) {
if (type == null) {
return null; // 프론트에서 값이 안 오면(전체 조회 시) 조건을 무시
}
return interviewSession.interviewType.eq(type.name());
}
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

InterviewSession 엔티티의 interviewType 필드가 String 타입이어서 type.name()으로 비교하고 있습니다. 이는 enum의 이름이 변경될 경우 문제가 발생할 수 있어 잠재적으로 취약합니다. 장기적인 유지보수성을 위해 InterviewSession 엔티티의 interviewType 필드 타입을 InterviewType enum으로 변경하고 @Enumerated(EnumType.STRING)을 사용하는 것을 고려해보세요. 이렇게 하면 interviewSession.interviewType.eq(type)와 같이 타입-안전한 비교가 가능해져 코드가 더 견고해집니다.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

추후 수정 예정

@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "10") int size
@RequestParam(defaultValue = "10") int size,
@RequestParam(name = "mode", required = false) InterviewType type,
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

요청 파라미터의 이름은 mode인데, 이를 받는 변수명은 type으로 되어 있어 불일치가 발생합니다. 이는 코드를 읽는 개발자에게 혼동을 줄 수 있습니다. 코드의 명확성과 일관성을 위해 파라미터 이름을 변수명과 일치시키는 것이 좋습니다.

Suggested change
@RequestParam(name = "mode", required = false) InterviewType type,
@RequestParam(name = "type", required = false) InterviewType type,

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

수정완료

@gudals2040 gudals2040 merged commit b1b38df into dev Mar 12, 2026
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.

2 participants