Skip to content

[fix] 모집기간 설정 시간 보정#690

Merged
lepitaaar merged 2 commits intodevelop-fefrom
fix/correct-korean-time
Aug 23, 2025
Merged

[fix] 모집기간 설정 시간 보정#690
lepitaaar merged 2 commits intodevelop-fefrom
fix/correct-korean-time

Conversation

@lepitaaar
Copy link
Contributor

@lepitaaar lepitaaar commented Aug 22, 2025

#️⃣연관된 이슈

#689

📝작업 내용

모집기간 변경 요청 -> be에서 저장시 -9시간이 되어 저장됨. -> 따라서 변경 요청시 +9 시간을 해어 보정해줌
모집기간 응답 요청 -> 보정된 +9시간을 다시 빼주어 정상적으로 표시되게 변경

임시조치

임시로 땜빵 ㅎㅎ
이대로 배포시 지금 (보정X)저장되어있는 시간을 불러올때 -9시간으로 표시되어 불편함 생길수도있음.

중점적으로 리뷰받고 싶은 부분(선택)

리뷰어가 특별히 봐주었으면 하는 부분이 있다면 작성해주세요

ex) 메서드 XXX의 이름을 더 잘 짓고 싶은데 혹시 좋은 명칭이 있을까요?

논의하고 싶은 부분(선택)

논의하고 싶은 부분이 있다면 작성해주세요.

🫡 참고사항

Summary by CodeRabbit

  • 버그 수정
    • 관리자 > 모집 편집 탭에서 모집 시작/종료 일시가 한국 시간대(KST) 기준으로 잘못 표시되던 문제를 수정했습니다.
    • 초기 값 로딩 시 9시간 오프셋으로 시간이 어긋나던 현상을 해소했습니다.
    • 일시 저장 시 KST 기준으로 정확히 변환되어 서버에 반영되도록 개선했습니다.
    • 표시와 저장 간 시간대 일관성을 강화했습니다. 기존 사용자 흐름과 외부 API는 변경되지 않았습니다.

@lepitaaar lepitaaar self-assigned this Aug 22, 2025
@lepitaaar lepitaaar added 💻 FE Frontend 🛠Fix 기능이 의도한 대로 동작하지 않는 버그를 수정 labels Aug 22, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Aug 22, 2025

Warning

.coderabbit.yaml has a parsing error

The CodeRabbit configuration file in this repository has a parsing error and default settings were used instead. Please fix the error(s) in the configuration file. You can initialize chat with CodeRabbit to get help with the configuration file.

💥 Parsing errors (1)
Validation error: Invalid regex pattern for base branch. Received: "**" at "reviews.auto_review.base_branches[0]"
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

RecruitEditTab.tsx now uses two internal date helpers to adjust recruitmentStart/recruitmentEnd for Korea Standard Time: subtract 9 hours when initializing from server data and add 9 hours before sending updates. Initialization and update flows were modified accordingly; external interfaces remain unchanged.

Changes

Cohort / File(s) Summary
RecruitEditTab 시간대 보정
`frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx`
내부 헬퍼 `correctRequestKoreanDate(+9h)`, `correctResponseKoreanDate(-9h)` 추가. 초기값 세팅 시 서버 값에 -9h 적용, 업데이트 전 요청 값에 +9h 적용 후 `.toISOString()` 호출. 외부 API 시그니처 변경 없음.

Sequence Diagram(s)

sequenceDiagram
  participant Admin as Admin (UI)
  participant RET as RecruitEditTab
  participant DH as DateHelpers
  participant API as Backend API

  rect rgb(245,245,255)
    note over RET,DH: 초기 렌더링 (Response 보정)
    Admin->>RET: 페이지 열기
    RET->>API: 모집 정보 조회
    API-->>RET: { recruitmentStart, recruitmentEnd (UTC ISO) }
    RET->>DH: correctResponseKoreanDate(-9h)
    DH-->>RET: 표시용 Date (KST 기준)
    RET-->>Admin: 폼에 시간 표시
  end

  rect rgb(245,255,245)
    note over RET,DH: 업데이트 (Request 보정)
    Admin->>RET: 변경 사항 저장 클릭
    RET->>DH: correctRequestKoreanDate(+9h)
    DH-->>RET: 전송용 Date
    RET->>API: 업데이트 (toISOString)
    API-->>RET: 저장 결과
    RET-->>Admin: 완료 상태 표시
  end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers

  • Zepelown
  • seongwon030
  • suhyun113

Tip

🔌 Remote MCP (Model Context Protocol) integration is now available!

Pro plan users can now connect to remote MCP servers from the Integrations page. Connect with popular remote MCPs such as Notion and Linear to add more context to your reviews and chats.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/correct-korean-time

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

CodeRabbit Commands (Invoked using PR/Issue comments)

Type @coderabbitai help to get the list of available commands.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

Status, Documentation and Community

  • Visit our Status Page to check the current availability of CodeRabbit.
  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@vercel
Copy link

vercel bot commented Aug 22, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
moadong Ready Ready Preview Comment Aug 22, 2025 0:53am

Copy link
Member

@seongwon030 seongwon030 left a comment

Choose a reason for hiding this comment

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

임시조"취" 감사합니다

@lepitaaar
Copy link
Contributor Author

임시조"취" 감사합니다

후다닥 수정 .. 아이부끄러워라

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx (2)

38-46: KST 오프셋(9시간) 매직 넘버 상수화 + 헬퍼 단순화 제안

  • 96060*1000은 상수로 분리해주세요(코딩 가이드라인: 매직 넘버 지양).
  • 이미 null 가드가 있어 date?.getTime()?.는 불필요합니다.
  • 동일 로직이 두 함수에 중복되어 있어 가독성과 유지보수성이 떨어집니다.

아래처럼 상수화 및 중복 제거를 권합니다.

-  const correctRequestKoreanDate = (date: Date | null): Date | null => {
-    if (!date) return null;
-    return new Date(date?.getTime() + 9 * 60 * 60 * 1000);
-  }
+  const correctRequestKoreanDate = (date: Date | null): Date | null => {
+    if (!date) return null;
+    return new Date(date.getTime() + KST_OFFSET_MS);
+  }

-  const correctResponseKoreanDate = (date: Date | null): Date | null => {
-    if (!date) return null;
-    return new Date(date?.getTime() - 9 * 60 * 60 * 1000);
-  }
+  const correctResponseKoreanDate = (date: Date | null): Date | null => {
+    if (!date) return null;
+    return new Date(date.getTime() - KST_OFFSET_MS);
+  }

모듈 상단(컴포넌트 밖) 또는 해당 useEffect 인근에 다음 상수를 추가해주세요(선호: 모듈 상단).

// BE 임시 보정(UTC↔KST)용 상수. BE 고도화 시 제거 예정(#689)
export const KST_OFFSET_MS = 9 * 60 * 60 * 1000;

추가로, 이 두 헬퍼는 다른 화면에서도 재사용될 가능성이 높습니다. utils/date 등으로의 추출을 검토해주세요.


38-46: 임시 보정 로직의 롤백 용이성 확보(플래그화/주석 추가)

BE가 수정되는 순간 FE 보정이 중복 적용될 수 있습니다. 간단한 환경 변수 플래그를 두고, 주석으로 제거 조건을 명시해 주세요.

예시:

// .env: VITE_ENABLE_KST_COMPENSATION=true
const ENABLE_KST_COMP = import.meta.env.VITE_ENABLE_KST_COMPENSATION === 'true';

const correctRequestKoreanDate = (d: Date | null) =>
  !d ? null : (ENABLE_KST_COMP ? new Date(d.getTime() + KST_OFFSET_MS) : d);

const correctResponseKoreanDate = (d: Date | null) =>
  !d ? null : (ENABLE_KST_COMP ? new Date(d.getTime() - KST_OFFSET_MS) : d);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

💡 Knowledge Base configuration:

  • MCP integration is disabled by default for public repositories
  • Jira integration is disabled by default for public repositories
  • Linear integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between d8b3de5 and 72cd6e4.

📒 Files selected for processing (1)
  • frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
frontend/**/*.{ts,tsx}

📄 CodeRabbit inference engine (frontend/.cursorrules)

frontend/**/*.{ts,tsx}: Replace magic numbers with named constants for clarity.
Replace complex or nested ternary operators with if/else statements or IIFEs for readability.
Assign complex boolean conditions to named variables.
Use consistent return types for similar functions and hooks.
Avoid hidden side effects; functions should only perform actions implied by their signature (Single Responsibility Principle).
Use unique, descriptive names for custom wrappers and functions to avoid ambiguity.
Define constants near related logic or ensure names link them clearly.

Files:

  • frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx
frontend/**/*.tsx

📄 CodeRabbit inference engine (frontend/.cursorrules)

frontend/**/*.tsx: Abstract complex logic/interactions into dedicated components or higher-order components (HOCs).
Separate significantly different conditional UI/logic into distinct components.
Colocate simple, localized logic or use inline definitions to reduce context switching.
Choose field-level or form-level cohesion based on form requirements.
Break down broad state management into smaller, focused hooks or contexts.
Use component composition instead of props drilling.

Files:

  • frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx
🔇 Additional comments (1)
frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx (1)

32-33: 초기 표시값 보정 방향 검증 필요 (오프바이원 데이 위험 체크)

parseRecruitmentPeriod와 correctResponseKoreanDate의 동작 방식을 실제 구현 및 서버 응답 예시로 반드시 확인해주세요.

  • parseRecruitmentPeriod(…)가 반환하는 Date 객체가 로컬 타임인지 UTC기준인지 확인
  • correctResponseKoreanDate(…)가 내부적으로 9시간을 감산/가산하는지, 그 방식이 KST 자정 정규화 목적에만 부합하는지 검토
  • 서버에서 내려오는 recruitmentPeriod 원문(예: "2025.08.01 00:00 ~ 2025.08.07 23:59")과 parse→보정→set까지 흐름에서 날짜가 하루 앞뒤로 밀리는지 테스트 데이터로 검증

점검 위치

  • frontend/src/utils/recruitmentPeriodParser.ts (parseRecruitmentPeriod 구현부)
  • correctResponseKoreanDate 정의 위치
  • frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx 의 setRecruitmentStart/End 호출부

Comment on lines +53 to +54
recruitmentStart: correctRequestKoreanDate(recruitmentStart)?.toISOString(),
recruitmentEnd: correctRequestKoreanDate(recruitmentEnd)?.toISOString(),
Copy link
Contributor

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

null 시 undefined 전송 방지 및 DTO 계약 정합성 확인

현재 구현은 Date | null일 때 ?.toISOString()undefined를 생성합니다. API가 부분 업데이트에서 undefined를 무시하는지 혹은 null을 요구하는지에 따라 문제가 될 수 있습니다. 안전하게 조건부 스프레드로 키 자체를 생략하는 방식을 권장합니다.

-      recruitmentStart: correctRequestKoreanDate(recruitmentStart)?.toISOString(),
-      recruitmentEnd: correctRequestKoreanDate(recruitmentEnd)?.toISOString(),
+      ...(recruitmentStart
+        ? { recruitmentStart: correctRequestKoreanDate(recruitmentStart).toISOString() }
+        : {}),
+      ...(recruitmentEnd
+        ? { recruitmentEnd: correctRequestKoreanDate(recruitmentEnd).toISOString() }
+        : {}),

아래 스크립트로 DTO 타입과 훅 시그니처를 확인해 주세요. API가 string | null을 요구한다면, 위 스프레드 대신 : null을 명시하도록 바꾸어야 합니다.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# 업데이트 훅과 DTO 타입 확인
rg -n -C3 'useUpdateClubDescription' --type ts
rg -n -C3 'interface .*Update.*Club.*|type .*Update.*Club.*' --type ts

# 서버 요청 바디에서 recruitment(Start|End) 타입 사용 위치
rg -n -C3 '\brecruitment(Start|End)\b' --type ts | sed -n '1,200p'

Length of output: 2639


아래 스크립트로 ClubDescription 타입 정의와 updateClubDescription API 구현을 확인해주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# ClubDescription 타입 정의 확인
type_file=$(rg -l -g 'frontend/src/types/**' 'export (interface|type) ClubDescription' | head -n1)
echo "Type file: $type_file"
sed -n '1,200p' "$type_file"

# updateClubDescription API 구현 확인
api_file=$(rg -l -g 'frontend/src/apis/**' 'export function updateClubDescription' | head -n1)
if [ -z "$api_file" ]; then
  api_file=$(rg -l -g 'frontend/src/apis/**' 'const updateClubDescription' | head -n1)
fi
echo "API file: $api_file"
sed -n '1,200p' "$api_file"

Length of output: 1097


아직 updateClubDescription 구현 위치를 찾지 못했습니다. API 파일 경로를 재확인하기 위해 아래 스크립트를 실행해 주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# frontend/src/apis 디렉터리 내 모든 ts/tsx 파일 중 updateClubDescription 정의 검색
rg -n --type ts --type tsx 'updateClubDescription' frontend/src/apis

Length of output: 116


아래 스크립트로 updateClubDescription API 구현 파일을 찾아 시그니처를 확인해 주세요.


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# updateClubDescription.ts 파일 찾기 및 내용 출력
api_file=$(find frontend/src/apis -type f -name 'updateClubDescription.ts' | head -n1)
if [ -z "$api_file" ]; then
  echo "updateClubDescription.ts 파일을 찾을 수 없습니다."
  exit 1
fi
echo "API 파일: $api_file"
sed -n '1,200p' "$api_file"

Length of output: 1363


모집 기간 필드가 DTO에 정의되지 않음 및 null 처리 검토 필요

현재 RecruitEditTab.tsx에서 사용 중인 useUpdateClubDescription 훅은 ClubDescription 타입(id, description)만 허용하며, 실제 API(PUT /api/club/description)도 description만 처리합니다.
따라서 아래와 같이 recruitmentStart/recruitmentEnd를 포함해 호출해도

  • 컴파일 시 Excess property 오류 발생
  • 런타임에 JSON.stringify로 undefined 값은 아예 누락되어 전송되지 않음
  • correctRequestKoreanDate(null) 호출 시 함수 내부 에러 가능 (optional chaining은 .toISOString()만 방어)

아래 위치 확인 후 적절히 수정이 필요합니다.

  • frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx
  • frontend/src/types/club.ts (ClubDescription)
  • frontend/src/apis/updateClubDescription.ts (/api/club/description)

제안 드리는 수정 예시:

  1. 모집 기간 전용 훅/API 분리 사용

    - updateClubDescription({
    -   id,
    -   description,
    -   recruitmentStart: correctRequestKoreanDate(recruitmentStart)?.toISOString(),
    -   recruitmentEnd: correctRequestKoreanDate(recruitmentEnd)?.toISOString(),
    - });
    + // 모집 기간 업데이트 전용 훅/API 호출
    + updateClubRecruitmentPeriod({
    +   id,
    +   ...(recruitmentStart && { recruitmentStart: correctRequestKoreanDate(recruitmentStart).toISOString() }),
    +   ...(recruitmentEnd && { recruitmentEnd: correctRequestKoreanDate(recruitmentEnd).toISOString() }),
    + });
  2. 단일 엔드포인트로 통합 시 DTO 확장

    + // frontend/src/types/club.ts
    + export interface ClubUpdatePayload {
    +   id: string;
    +   description?: string | null;
    +   recruitmentStart?: string;
    +   recruitmentEnd?: string;
    + }

    그리고 훅과 API 시그니처를 ClubUpdatePayload로 변경해 주십시오.

위 두 가지 중 적합한 방안을 선택해 반영 후 다시 검토 부탁드립니다.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In frontend/src/pages/AdminPage/tabs/RecruitEditTab/RecruitEditTab.tsx around
lines 53-54, you're passing recruitmentStart/recruitmentEnd into a hook that
expects ClubDescription (id, description) which causes TypeScript "excess
property" errors and runtime issues (undefined omitted from JSON and
correctRequestKoreanDate(null) can throw); either (A) stop sending dates to
useUpdateClubDescription and call a dedicated recruitment-date API/hook, or (B)
extend the DTO/type to a ClubUpdatePayload that includes optional
recruitmentStart?: string | null and recruitmentEnd?: string | null, update
frontend/src/types/club.ts to add the new type, change
frontend/src/apis/updateClubDescription.ts and the hook signature to accept that
payload, and in RecruitEditTab guard calls so you only call
correctRequestKoreanDate when value is non-null and only include .toISOString()
after a successful date conversion (i.e., compute correctedDate =
correctRequestKoreanDate(val); if (correctedDate) payload.recruitmentStart =
correctedDate.toISOString()) so no undefined or null slips into JSON.

Copy link
Collaborator

@suhyun113 suhyun113 left a comment

Choose a reason for hiding this comment

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

문제도 빠르게 찾아내시고, 시간 설정에서 발생하던 오차도 임시로 잘 보정해주셨네요!
아주 좋습니다ㅏ

@lepitaaar lepitaaar merged commit 6302bdc into develop-fe Aug 23, 2025
5 checks passed
@lepitaaar lepitaaar deleted the fix/correct-korean-time branch September 20, 2025 01:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

💻 FE Frontend 🛠Fix 기능이 의도한 대로 동작하지 않는 버그를 수정

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants

Comments