Skip to content

RELEASE-20260421#203

Merged
alsgud8311 merged 6 commits into
mainfrom
development
Apr 21, 2026
Merged

RELEASE-20260421#203
alsgud8311 merged 6 commits into
mainfrom
development

Conversation

@alsgud8311
Copy link
Copy Markdown
Contributor

  • prod 무중단배포 작업
  • 어드민 관련 페이지 추가

- 관리자 대시보드 및 결제 내역 관리 페이지 추가
- 관리자 질문 관리 기능을 위한 컴포넌트 및 API 구현
- 결제 내역 조회 및 취소 기능 추가
- 관리자 사이드바 및 레이아웃 구성
- 관련 타입 및 쿼리 키 정의 추가
- Changed instances of "대시보드" to "마이페이지" across multiple components including the dashboard, interview results, header, tab bar, and layout stories for consistency in terminology.
- Changed API base URL to use NEXT_PUBLIC_V3_API_BASE_URL for consistency.
- Added toast notifications for context loss and response analysis in the InterviewAnswerForm component.
- Improved speech recognition handling with context loss detection.
- Updated toast component to support multiple positions and enhanced functionality.
- Introduced a RankGuideTooltip component to provide detailed explanations of feedback grades (A to F) within the FeedbackAccordion.
- Enhanced the visual presentation of feedback items by adjusting styles and adding a tooltip for better user experience.
- Updated the layout of the feedback section in the interview result page for improved aesthetics.
- Updated admin API to include `withCredentials` for secure requests.
- Modified the `cancelAdminPayment` function to accept a cancellation reason.
- Implemented a new payment history section with detailed views and cancellation options in the admin panel.
- Refactored authentication checks to use `withAdminCheck` for better access control.
- Improved header navigation to conditionally display admin links based on user role.
- Replaced existing container stop and removal steps with a blue-green deployment approach.
- Introduced a new script `blue-green-deploy.sh` to manage the deployment process.
- Updated Docker Compose configuration to support blue and green profiles for the client service.
- Enhanced deployment summary to reflect the new deployment strategy.
- Added new Traffic Server configuration files for improved traffic management and security headers.
@alsgud8311 alsgud8311 merged commit 93c82c0 into main Apr 21, 2026
2 of 7 checks passed
Copy link
Copy Markdown
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

This pull request introduces an administrative dashboard for managing payments and interview questions, featuring new API integrations, UI components, and role-based access control. It also transitions the deployment strategy to a blue-green model using Apache Traffic Server and renames 'Dashboard' to 'My Page' across the application. Feedback focuses on preventing data loss in the voice recognition logic, enforcing admin access controls in the middleware, and enhancing the flexibility of the payment cancellation API.

Comment on lines 72 to 82
if (mode === "VOICE") {
const accumulatedText = result.current.join(" ").trim();
if (accumulatedText.length > 0 && onContextLost) {
onContextLost();
}

publishInterviewEvent("interview:stopVoiceRecognition");
setTimeout(() => {
publishInterviewEvent("interview:startVoiceRecognition");
}, 500);
}
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

VOICE 모드에서 음성 인식이 종료될 때 누적된 텍스트가 있으면 onContextLost를 호출하여 입력을 초기화하고 있습니다. 이는 사용자가 말을 잠시 멈추거나 브라우저에 의해 인식이 끊겼을 때 작성 중인 답변이 모두 사라지게 만들어 심각한 사용자 경험 저하를 초래할 수 있습니다. 단순히 인식을 재시작하려는 의도라면 onContextLost 호출 로직을 제거해야 합니다.

    if (mode === "VOICE") {
      publishInterviewEvent("interview:stopVoiceRecognition");
      setTimeout(() => {
        publishInterviewEvent("interview:startVoiceRecognition");
      }, 500);
    }

Comment on lines +41 to +47
// TODO: admin 전용 체크 (서버에서 is_admin API 구현 후 활성화)
// if (pathname.startsWith("/admin")) {
// const isAdmin = await checkIsAdmin(sessionId);
// if (!isAdmin) {
// return NextResponse.redirect(new URL("/dashboard", request.url));
// }
// }
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.

security-high high

관리자 페이지(/admin)에 대한 접근 권한 체크 로직이 주석 처리되어 있습니다. 현재 로직으로는 로그인한 모든 사용자가 관리자 페이지에 접근할 수 있는 보안 취약점이 존재합니다. withAdminCheck 유틸리티가 이미 구현되어 있으므로, 미들웨어에서도 이를 활용하여 관리자 권한이 없는 사용자의 접근을 차단해야 합니다.

Comment on lines +32 to +36
export const cancelAdminPayment = async (paymentId: number): Promise<void> => {
return adminApiInstance
.post(`/admin/payments/${paymentId}/cancel`, { cancel_reason: "고객 요청" })
.then((res) => res.data);
};
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

결제 취소 사유가 "고객 요청"으로 고정되어 있습니다. 관리자 기능의 유연성을 위해 취소 사유를 파라미터로 전달받아 처리할 수 있도록 개선하는 것이 좋습니다.

Suggested change
export const cancelAdminPayment = async (paymentId: number): Promise<void> => {
return adminApiInstance
.post(`/admin/payments/${paymentId}/cancel`, { cancel_reason: "고객 요청" })
.then((res) => res.data);
};
export const cancelAdminPayment = async (paymentId: number, cancelReason: string = "고객 요청"): Promise<void> => {
return adminApiInstance
.post(`/admin/payments/${paymentId}/cancel`, { cancel_reason: cancelReason })
.then((res) => res.data);
};

Comment on lines +38 to +55
// TODO: 질문 수정 API (서버 구현 후 활성화)
// export const updateAdminQuestion = async (
// questionId: number,
// content: string
// ): Promise<void> => {
// return adminApiInstance
// .put(`/admin/questions/${questionId}`, { content })
// .then((res) => res.data);
// };

// TODO: 질문 삭제 API (서버 구현 후 활성화)
// export const deleteAdminQuestion = async (
// questionId: number
// ): Promise<void> => {
// return adminApiInstance
// .delete(`/admin/questions/${questionId}`)
// .then((res) => res.data);
// };
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

주석 처리된 미구현 API 코드들이 포함되어 있습니다. 코드의 가독성과 유지보수를 위해 사용하지 않는 코드는 제거하고, 필요한 경우 TODO 주석만 남겨두는 것을 권장합니다.

Comment on lines +297 to +302
onError: (error: Error) => {
setCancelTarget(null);
errorToast({
title: "결제 취소 실패",
description: error.message ?? "서버 오류가 발생했습니다."
});
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

에러 발생 시 error.message를 그대로 노출하고 있습니다. 사용자에게 더 친절한 안내를 위해 서버에서 반환하는 에러 메시지가 있다면 이를 우선적으로 표시하도록 개선이 필요합니다.

echo "[INFO] ATS 컨테이너 시작..."
docker compose --env-file "$ENV_FILE" -f "$COMPOSE_FILE" up -d ats
echo "[INFO] ATS 기동 대기 (5초)..."
sleep 5
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

sleep 5와 같이 고정된 시간을 대기하는 방식은 환경에 따라 불안정할 수 있습니다. ATS 컨테이너가 정상적으로 준비되었는지 확인하는 헬스체크 로직을 추가하는 것이 더 안전합니다.

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.

1 participant