Skip to content

v0.4패치#58

Merged
rktclgh merged 9 commits into
mainfrom
develop
Mar 12, 2026
Merged

v0.4패치#58
rktclgh merged 9 commits into
mainfrom
develop

Conversation

@rktclgh

@rktclgh rktclgh commented Mar 12, 2026

Copy link
Copy Markdown
Owner

📢 기능 설명

필요시 실행결과 스크린샷 첨부

연결된 issue

연결된 issue를 자동으로 닫기 위해 아래 {이슈넘버}를 입력해주세요.

close #{이슈넘버}



🩷 Approve 하기 전 확인해주세요!

  • 리뷰어가 확인해줬으면 하는 사항 적어주세요.
  • [ ]

✅ 체크리스트

  • PR 제목 규칙 잘 지켰는가?
  • 추가/수정사항을 설명하였는가?
  • 이슈넘버를 적었는가?
  • Approve 하기 전 확인 사항 체크했는가?

@coderabbitai

coderabbitai Bot commented Mar 12, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 625d165f-7619-4e74-a308-4292b657d683

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch develop

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.

@rktclgh rktclgh merged commit 9bb6083 into main Mar 12, 2026
2 checks passed
@github-project-automation github-project-automation Bot moved this from Backlog to Done in Vlainter_BackEnd Mar 12, 2026
@gemini-code-assist

Copy link
Copy Markdown

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!

이 Pull Request는 AI 면접 시스템의 핵심 기능을 대폭 확장하고 안정성을 강화하는 데 중점을 둡니다. 문서 처리 지원 파일 형식을 늘리고, AI 질문 생성 및 답변 평가 로직을 고도화하여 사용자 경험을 개선합니다. 또한, 보안 취약점을 보완하고 내부 지원 시스템을 현대화하여 서비스의 전반적인 품질과 운영 효율성을 향상시킵니다.

Highlights

  • 문서 처리 기능 확장: 기존 PDF 외에 DOCX 및 PPTX 파일 형식에 대한 문서 처리 지원이 추가되어, 사용자가 다양한 형식의 문서를 활용하여 면접을 준비할 수 있게 되었습니다.
  • AI 면접 로직 개선 및 다국어 지원: AI 면접 질문 생성 및 답변 평가 로직이 정교화되었으며, 특히 문서 기반 질문과 자기소개 질문에 대한 평가 기준이 강화되었습니다. 또한, 면접 언어(한국어/영어)를 지정하고 이에 맞춰 질문 및 답변 내용을 현지화하는 기능이 도입되었습니다.
  • 보안 강화 (리프레시 토큰 로테이션): 리프레시 토큰 로테이션 과정에 Redis Lua 스크립트를 활용한 원자적(atomic) 처리가 적용되어, 토큰 재사용 공격 방어 및 보안 안정성이 향상되었습니다.
  • 사용자 라이프사이클 이메일 및 지원 리포트 시스템 개선: 회원 가입 환영 및 계정 탈퇴 안내 이메일 발송 기능이 추가되었으며, 기존 이메일 기반의 지원 리포트 시스템이 Discord 웹훅 연동 방식으로 변경되어 운영 효율성이 증대되었습니다.

🧠 New Feature in Public Preview: You can now enable Memory 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.

Changelog
  • build.gradle.kts
    • Apache POI 라이브러리(poi-ooxml) 의존성이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/auth/service/AuthService.kt
    • 회원 가입 시 환영 이메일 발송 로직이 추가되었고, 리프레시 토큰 로테이션 로직이 원자적(atomic) 스크립트 기반으로 변경되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/auth/service/EmailVerificationService.kt
    • 이메일 인증 코드 발송 시 이메일 템플릿에 로고 이미지가 인라인으로 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/auth/service/PasswordRecoveryService.kt
    • 임시 비밀번호 발송 시 이메일 템플릿에 로고 이미지가 인라인으로 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/ai/InterviewAiOrchestrator.kt
    • AI 면접 질문 생성 및 답변 평가 로직에 언어(한국어/영어) 파라미터가 추가되었고, 배치 평가 기능이 도입되었습니다. 문서 질문 유형 및 근거 종류에 따른 프롬프트 규칙과 유효성 검사 로직이 강화되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/dto/DocumentInterviewDtos.kt
    • 문서 기반 모의면접 시작 요청 DTO에 언어(language) 필드가 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/dto/InterviewPracticeDtos.kt
    • 기술 면접 시작 요청 및 응답 DTO, 세션 이력 및 재개 응답 DTO에 언어(language) 필드가 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/entity/InterviewEnums.kt
    • 면접 언어를 나타내는 InterviewLanguage(KO, EN) enum이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/service/DocumentInterviewService.kt
    • DOCX 및 PPTX 파일에서 텍스트를 추출하는 기능이 추가되었고, 문서 질문 생성 시 DocumentQuestionGenerationPolicy를 활용하도록 변경되었습니다. 면접 턴 생성 시 질문 및 모범답안 현지화 로직이 통합되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/service/DocumentQuestionGenerationPolicy.kt
    • 문서 유형별 질문 할당 및 스니펫 분류 정책을 정의하는 새로운 파일이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/service/InterviewEvaluationService.kt
    • 미평가된 면접 턴에 대한 배치 평가 기능이 추가되었고, 문서 기반 답변에 대한 휴리스틱 평가 로직이 강화되었습니다. 답변 언어에 따른 평가 기준 및 피드백 현지화 로직이 적용되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/service/InterviewPracticeService.kt
    • 기술 면접 시작 시 질문 현지화 로직이 추가되었고, 영어 면접 시 영어 답변만 허용하도록 언어 검증 로직이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/interview/service/TurnLocalizationSupport.kt
    • 면접 턴 콘텐츠 현지화를 위한 유틸리티 함수 및 데이터 클래스를 정의하는 새로운 파일이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/support/service/DiscordSupportWebhookNotifier.kt
    • Discord 웹훅을 통해 지원 리포트를 전송하는 기능을 구현한 새로운 파일이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/support/service/SupportReportService.kt
    • 지원 리포트 전송 방식이 기존 이메일에서 Discord 웹훅으로 변경되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/user/repository/UserRepository.kt
    • 관리자에게 리포트 이메일을 찾는 findReportRecipients 메서드가 제거되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/user/service/UserLifecycleEmailService.kt
    • 회원 가입 환영 및 계정 탈퇴 안내 이메일 발송을 담당하는 새로운 서비스 파일이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/user/service/UserService.kt
    • 계정 탈퇴 시 UserLifecycleEmailService를 통해 탈퇴 안내 이메일을 발송하도록 변경되었습니다.
  • src/main/kotlin/com/cw/vlainter/domain/userFile/service/UserFileService.kt
    • 이력서/자기소개서/포트폴리오 파일 업로드 시 DOCX 및 PPTX 파일 형식이 허용되도록 변경되었습니다.
  • src/main/kotlin/com/cw/vlainter/global/config/SecurityConfig.kt
    • 새로운 정적 리소스(favicon.png, social-preview.png)에 대한 접근 권한이 추가되었습니다.
  • src/main/kotlin/com/cw/vlainter/global/mail/EmailTemplateService.kt
    • 회원 가입 환영 및 계정 탈퇴 이메일 템플릿 빌드 메서드가 추가되었고, 모든 이메일 템플릿에 로고 이미지가 포함되도록 변경되었습니다.
  • src/main/kotlin/com/cw/vlainter/global/security/LoginSessionStore.kt
    • 리프레시 토큰 로테이션을 위한 Redis Lua 스크립트가 추가되었고, 토큰 검증 및 로테이션 결과에 대한 새로운 enum(RefreshTokenValidationResult, RefreshTokenRotationResult)이 정의되었습니다.
  • src/main/resources/application.properties
    • Discord 웹훅 URL 설정을 위한 app.support.discord.webhook-url 속성이 추가되었습니다.
  • src/main/resources/email/content/auth/account-deletion.html
    • 계정 탈퇴 안내 이메일 템플릿이 추가되었습니다.
  • src/main/resources/email/content/auth/temporary-password.html
    • 임시 비밀번호 이메일 템플릿의 스타일이 업데이트되었습니다.
  • src/main/resources/email/content/auth/verification-code.html
    • 이메일 인증 코드 템플릿의 스타일이 업데이트되었습니다.
  • src/main/resources/email/content/auth/welcome.html
    • 회원 가입 환영 이메일 템플릿이 추가되었습니다.
  • src/main/resources/email/frame/default.html
    • 기본 이메일 프레임에 로고 이미지를 표시하는 스타일 및 요소가 추가되었습니다.
Activity
  • 이 Pull Request는 AI 면접 기능의 문서 처리 범위 확장, AI 로직의 정교화 및 다국어 지원 도입, 리프레시 토큰 로테이션 보안 강화, 그리고 사용자 라이프사이클 이메일 및 지원 리포트 시스템 개선 등 여러 주요 기능을 추가하고 기존 코드를 리팩토링했습니다. 현재까지 특별한 리뷰어 활동은 기록되지 않았습니다.
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.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9d72c08a3b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

return buildSessionLocalizedQueueEntries(
kind = InterviewQuestionKind.TECH,
entries = localized.entries.associate { (key, value) ->
key.toLong() to StoredLocalizedTurnContent(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Skip non-numeric localized keys before queue mapping

This code assumes every localized entry key is numeric and does key.toLong(), but localizeTurnContents can include arbitrary keys parsed from LLM output in addition to the original IDs. If the model emits an extra key like "item-1", this conversion throws NumberFormatException and the interview start flow fails (500) for English sessions. Use toLongOrNull() and ignore unknown keys when building queue entries.

Useful? React with 👍 / 👎.

val DOCUMENT_ACTION_SIGNALS_EN = setOf("implemented", "designed", "improved", "introduced", "analyzed", "resolved", "optimized", "refactored", "collaborated", "validated", "built", "led")
val DOCUMENT_RESULT_SIGNALS_EN = setOf("result", "outcome", "improved", "reduced", "increased", "shortened", "completed", "achieved", "stabilized", "launched")
val DOCUMENT_REASONING_SIGNALS_EN = setOf("because", "therefore", "so that", "in order to", "reason", "evidence", "validated", "compared", "trade-off")
val MOTIVATION_SIGNALS = setOf("지원", "동기", "가치", "가치관", "중요", "이유", "관심", "기준", "태도", "관점", "포부")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Add English motivation tokens to fallback rubric

MOTIVATION_SIGNALS is Korean-only, but it is used in document heuristic scoring for all languages via hasMotivationSignal. In English interview sessions, fallback evaluation can therefore mark motivation/principle as missing even when the answer clearly states it, lowering motivation-related scores and producing misleading guidance. Add an English motivation signal set (or branch by answerLanguage) like the other EN/KR signal groups.

Useful? React with 👍 / 👎.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

전반적으로 매우 인상적인 대규모 업데이트입니다. 한국어/영어 면접 지원, DOCX/PPTX 문서 업로드, 디스코드 웹훅을 이용한 고객 지원 리포팅 등 중요한 기능들이 추가되었습니다.

특히 원자적인 리프레시 토큰 회전(atomic refresh token rotation)을 구현하여 보안을 크게 강화했고, 면접 답변 일괄 평가 기능으로 성능도 개선했습니다. 복잡한 정책 로직을 DocumentQuestionGenerationPolicy, UserLifecycleEmailService 같은 별도 컴포넌트로 분리하여 코드 구조와 가독성을 높인 점도 훌륭합니다. AI 프롬프트 엔지니어링도 훨씬 정교해져 생성되는 질문과 평가의 품질이 향상될 것으로 기대됩니다.

전반적으로 매우 완성도 높은 기여이며, 일괄 평가 기능의 확장성에 대한 한 가지 제안 사항을 남깁니다.

Comment on lines +362 to +417
fun evaluateTurnsBatch(
items: List<BatchTurnEvaluationInput>,
responseLanguage: InterviewLanguage = InterviewLanguage.KO
): Map<String, AiTurnEvaluation> {
if (items.isEmpty()) return emptyMap()

val prompt = """
${evaluationSystemRole(responseLanguage, "interview evaluator")}
${jsonLanguageInstruction(responseLanguage)}

아래 각 항목을 서로 독립적으로 평가하고 반드시 JSON만 반환하세요.

출력 JSON 스키마:
{
"items": [
{
"key": "stable key",
"score": 0~100 숫자(소수점 2자리까지),
"feedback": "총평(2~4문장)",
"bestPractice": "개선 가이드(2~4문장)",
"rubric": {
"coverage": 0~100,
"accuracy": 0~100,
"communication": 0~100
},
"evidence": ["평가 근거", "..."]
}
]
}

공통 규칙:
- 항목별 평가는 서로 섞지 말고 독립적으로 수행
- 반드시 모든 입력 key를 유지해서 반환
- feedback, bestPractice, evidence는 모두 ${responseLanguage.displayLanguageName()}로 작성
- kind=TECH: 질문 의도 적합성, 기술 정확성, 실무 근거를 중심으로 평가
- kind=DOCUMENT: 사용자 답변 자체를 중심으로 평가하고 referenceAnswer는 정답 매칭이 아니라 보조 힌트로만 활용
- questionType이 INTRODUCE_MOTIVATION, INTRODUCE_VALUE, INTRODUCE_FUTURE_PLAN 인 DOCUMENT 항목은 STAR를 과도하게 강제하지 말고 동기, 판단 기준, 실제 적용 계획, 근거 연결성을 평가
- 그 외 DOCUMENT 항목은 질문 의도와 STAR 흐름(Situation, Task, Action, Result)을 함께 평가
- kind=INTRO: 자기소개 답변으로서 역할, 강점, 지원 맥락, 전달력을 평가
- answerLanguage=EN 이면 communication 점수에 grammar, sentence completeness, clarity, and natural professional English quality를 반영

[items]
${objectMapper.writeValueAsString(items)}
""".trimIndent()

return runCatching {
val generated = llmProviderRouter.generateJson(prompt)
parseBatchEvaluationJson(generated.text).mapValues { (_, value) ->
value.copy(model = generated.model, modelVersion = generated.modelVersion)
}
}.onFailure { ex ->
logger.warn("배치 면접 평가 실패(provider={}, count={}): {}", aiProperties.provider, items.size, ex.message)
}.getOrElse { ex ->
if (aiProperties.fallbackToHeuristic) emptyMap() else throw ex
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

medium

evaluateTurnsBatch 메서드는 평가할 모든 인터뷰 턴을 포함하는 단일 프롬프트를 생성합니다. 이는 적은 수의 턴에 대해서는 효율적이지만, 입력 아이템의 총 크기가 LLM의 컨텍스트 창을 초과하는 경우를 처리하는 메커니즘이 없습니다. 만약 인터뷰 세션에 긴 답변을 포함한 많은 턴이 있는 경우, 프롬프트가 너무 커져 API 오류가 발생할 수 있습니다.

향후 확장성을 위해 items 목록에 대한 청킹(chunking) 메커니즘을 구현하는 것을 고려해 보세요. 턴들을 컨텍스트 창에 맞게 더 작은 배치로 나누어 순차적으로 처리하면 배치 평가 기능이 더 안정적이고 확장 가능해질 것입니다.

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

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant