Skip to content

[REFACTOR] 프로젝트 구조 FSD로 개편#26

Merged
waldls merged 6 commits into
mainfrom
feature/#25-fsd-refactor
Jun 7, 2026
Merged

[REFACTOR] 프로젝트 구조 FSD로 개편#26
waldls merged 6 commits into
mainfrom
feature/#25-fsd-refactor

Conversation

@waldls

@waldls waldls commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

📢 PR 유형

어떤 변경 사항이 있었나요?

  • 새로운 기능 추가
  • 버그 수정
  • 코드에 영향을 주지 않는 변경사항(오타 수정, 탭 사이즈 변경, 변수명 변경)
  • 코드 리팩토링
  • 주석 추가 및 수정
  • 문서 수정
  • 빌드 부분 혹은 패키지 매니저 수정
  • 파일 혹은 폴더명 수정
  • 파일 혹은 폴더 삭제

📌 관련 이슈번호


✅ Key Changes

  • components, assets, constants, lib 등 레이어 구분 없이 흩어져 있던 공통 자원을 shared 레이어(ui, lib, assets, config, types)로 통합 이동
  • 강사 홈/새 외주 작성/온보딩 관련 코드를 도메인-기능 단위(features/instructor/home, features/instructor/write, features/signup 등)로 재배치
  • 도메인 모델이 아닌 화면 종속 데이터·UI였던 entities/instructor/homefeatures/instructor/home으로 이동하고 entities 레이어 제거
  • 외부에서 features 모듈을 가져다 쓸 때 내부 세부 경로(ui/, model/, lib/, config/)를 직접 import하던 부분을 배럴 파일(index.ts) 경로로 통일

📸 스크린샷 or 실행영상


🎸 기타 사항 or 추가 코멘트

폴더 구조 개편 관련해서 노션 컨벤션 > 폴더 구조 가이드 (FSD 기반) 에 문서화 해두었습니다.

Summary by CodeRabbit

릴리스 노트

  • Refactor
    • 코드 구조를 개선하기 위해 모듈 경로를 정리했습니다.
    • 공유 UI 컴포넌트와 자산을 @/shared 네임스페이스로 통합했습니다.
    • 기능별 모듈(@/features)을 생성하여 코드 구성을 명확하게 정리했습니다.
    • 임포트 경로를 표준화하여 유지보수성을 향상시켰습니다.

@waldls waldls self-assigned this Jun 7, 2026
@waldls waldls added ♻️ Refactor 코드 리팩토링 ❄️ 유민 labels Jun 7, 2026
@coderabbitai

coderabbitai Bot commented Jun 7, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto incremental reviews are disabled on this repository.

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 Plus

Run ID: 67dddc2b-e082-42e1-8dce-0ccf623a012f

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
📝 Walkthrough

Walkthrough

이 PR은 코드베이스 전체를 FSD(Feature Sliced Design) 아키텍처로 개편합니다. 공유 자산(@/shared)을 새로운 위치로 이동하고, 기능 단위(@/features)로 모듈을 조직화하며, 컨테이너/위젯들을 @/widgets로 재구성합니다. 모든 import 경로를 새로운 구조에 맞춰 일괄 업데이트하고, 각 레이어의 공개 API를 barrel export로 정의합니다.

Changes

공유 자산 레이어 이관

Layer / File(s) Summary
아이콘 및 로고 자산 마이기레이션
src/assets/icons/index.ts, src/assets/logos/index.ts, src/shared/assets/icons/index.ts, src/shared/assets/logos/index.ts
기존 src/assets/* 경로의 아이콘/로고 41개 export를 모두 제거하고, 새로운 src/shared/assets/* 경로에서 동일한 icon들을 re-export합니다.
공유 UI 컴포넌트 import 경로 업데이트
src/shared/ui/Button.tsx, src/shared/ui/Chip.tsx, src/shared/ui/Modal.tsx, src/shared/ui/Header.tsx, src/shared/ui/FileDragAndDrop.tsx, src/shared/ui/FileUpload.tsx, src/shared/ui/AccordionMenu.tsx, src/shared/ui/Toggle.tsx
공유 UI 컴포넌트들이 아이콘/로고 및 공유 유틸을 @/shared/* 경로에서 import하도록 일괄 수정합니다.
공유 설정 및 유틸 경로 업데이트
src/shared/config/sidebarMenu.ts, src/shared/lib/hooks/useWheelColumn.ts, src/shared/lib/hooks/useUploadedFiles.ts, src/shared/lib/utils/dropdown.ts, src/shared/ui/SidebarMenu.tsx
공유 설정 파일과 유틸/훅들이 새로운 모듈 경로를 참조하도록 import를 업데이트합니다.
세부 공유 UI 컴포넌트 경로 수정
src/shared/ui/input/InputField.tsx, src/shared/ui/input/SmallInput.tsx, src/shared/ui/input/TextField.tsx, src/shared/ui/dropdown/BankDropdown.tsx, src/shared/ui/dropdown/DateDropdownBox.tsx, src/shared/ui/dropdown/DateDropdownMenu.tsx, src/shared/ui/dropdown/WheelColumn.tsx
입력 필드, 드롭다운, 토글 등 세부 공유 UI 컴포넌트들과 그들이 사용하는 아이콘/유틸의 import 경로를 정리합니다.

기능별 feature 모듈 통합

Layer / File(s) Summary
Instructor Home 기능 재구성
src/features/instructor/home/index.ts, src/features/instructor/home/lib/getDDay.ts, src/features/instructor/home/ui/DraftSubmissionStatusRow.tsx, src/features/instructor/home/ui/MatchingCommissionsRow.tsx, src/features/instructor/home/ui/ModifyingCommissionsRow.tsx
instructor home의 데이터/유틸/UI 컴포넌트들을 @/features/instructor/home으로 이동하고, D-day 계산 유틸을 추가하며, 각 row 컴포넌트의 import 경로를 업데이트하고 barrel export로 정리합니다.
Instructor Write 기능 재구성
src/features/instructor/write/index.ts, src/features/instructor/write/config/write.ts, src/features/instructor/write/model/writeFormStore.ts, src/features/instructor/write/model/write.ts, src/features/instructor/write/lib/date.ts, src/features/instructor/write/*.tsx
instructor write의 설정/유틸/타입/스토어/UI 컴포넌트들을 @/features/instructor/write로 이동하고, write 관련 import를 단일 경로에서 가져오도록 통합하며, 중복 유틸(getDDay)을 제거합니다.
Signup 기능 재구성
src/features/signup/index.ts, src/features/signup/model/useSignupStep2Form.ts, src/features/signup/ui/UserTypeBtn.tsx
signup 관련 상수/훅/컴포넌트들을 @/features/signup으로 통합하고 barrel export로 공개 API를 정의합니다.

위젯 및 페이지 레이어 연결

Layer / File(s) Summary
Instructor Home 위젯 및 페이지 통합
src/widgets/instructor/home/index.ts, src/widgets/instructor/home/ui/DraftSubmissionStatusSection.tsx, src/widgets/instructor/home/ui/MatchingCommissionsSection.tsx, src/widgets/instructor/home/ui/ModifyingCommissionsSection.tsx, src/app/instructor/page.tsx
instructor home 위젯들을 @/widgets/instructor/home으로 이동하고 barrel export를 추가하며, home 페이지가 위젯을 import하도록 업데이트합니다.
Instructor Write 위젯 및 페이지 통합
src/widgets/instructor/write/index.ts, src/widgets/instructor/write/ui/Step*.tsx, src/widgets/instructor/write/ui/*Section.tsx, src/app/instructor/write/layout.tsx, src/app/instructor/write/page.tsx
instructor write 위젯들을 @/widgets/instructor/write로 이동하고 barrel export를 추가하며, write layout과 page가 새로운 경로를 import하도록 업데이트합니다.
회원가입 및 로그인 페이지 경로 업데이트
src/app/login/layout.tsx, src/app/login/page.tsx, src/app/signup/layout.tsx, src/app/signup/page.tsx, src/app/signup/designer/step*.tsx, src/app/signup/instructor/step*.tsx
login/signup 페이지들과 회원가입 step 페이지들이 새로운 shared/features 경로를 import하도록 일괄 업데이트합니다.
레이아웃 컴포넌트 경로 정리
src/app/designer/layout.tsx, src/app/instructor/layout.tsx, src/app/signup/layout.tsx
designer/instructor/login/signup layout이 header/sidebar 등을 @/shared/ui/* 경로에서 import하도록 업데이트합니다.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • Ditda-Official/Ditda-Frontend#24: 강사 대시보드 로직을 features/instructor/home/widgets/instructor/home로 이관하면서 새로운 getDDay 유틸과 섹션/row 컴포넌트를 구성한 점이 직접 연결됩니다.
  • Ditda-Official/Ditda-Frontend#22: 회원가입 UI 페이지 컴포넌트들의 import 경로를 새 구조에 맞춰 재정렬하는 변경이 중복됩니다.
  • Ditda-Official/Ditda-Frontend#16: instructor/write 기능의 Step1 상태 관리 및 컴포넌트 구조를 @/features·@/widgets·@/shared로 재정리한 변경과 직접 연관됩니다.

Suggested reviewers

  • KOJ50
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 PR의 주요 변경사항인 FSD 방식으로의 프로젝트 구조 개편을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed PR의 모든 코드 변경사항이 #25 이슈의 요구사항을 충족합니다. shared 레이어 정리, widgets/features/entities로의 폴더 재구성, 배럴 파일 기반 import 경로 통일, 단방향 의존성 규칙이 모두 적용되었습니다.
Out of Scope Changes check ✅ Passed 모든 변경사항이 FSD 구조 개편 범위 내에 있으며, 내부 로직이나 컴포넌트 동작을 수정하지 않고 폴더 이동과 import 경로 정리만 수행했습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/#25-fsd-refactor

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.

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🧹 Nitpick comments (3)
src/shared/ui/AccordionMenu.tsx (1)

15-17: ⚡ Quick win

조건부 Tailwind 클래스 결합은 cn()으로 통일해 주세요.

Line 15, Line 17에서 템플릿 문자열로 조건부 클래스를 직접 이어붙이고 있어 스타일 조합 규칙이 분산됩니다. 이 파일도 cn() 패턴으로 맞추면 가독성과 일관성이 좋아집니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/AccordionMenu.tsx` around lines 15 - 17, Replace the inline
template-string conditional classNames in AccordionMenu.tsx with the shared cn()
helper: update the <p> element that uses `{selected ? "text-main-main" :
"text-gray-90"}` and the ArrowDownIcon className that uses `{selected ?
"text-main-main rotate-180" : "text-gray-70"}` to call cn("text-body1-sb",
selected ? "text-main-main" : "text-gray-90") and cn("size-6
transition-transform duration-200", selected ? "text-main-main rotate-180" :
"text-gray-70") respectively so all conditional Tailwind class merging uses
cn().

Source: Coding guidelines

src/shared/ui/FileDragAndDrop.tsx (1)

45-49: ⚡ Quick win

드래그 상태 클래스 조합도 cn()으로 맞춰주세요.

Line 45-49는 조건부 클래스 문자열을 직접 이어붙이고 있습니다. 이미 cn을 사용 중이므로 이 구간도 cn()으로 통일하면 유지보수가 쉬워집니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/FileDragAndDrop.tsx` around lines 45 - 49, Replace the inline
template-string className construction with the existing cn() utility: locate
the JSX element that sets className using the isDragging conditional (the block
using isDragging ? "border-main-main bg-purple-10" : "bg-gray-10 ...") and wrap
the static classes and the conditional classes in cn(...) (e.g., pass static
class string and a conditional object or array keyed by isDragging). Update the
className assignment so it uses cn(...) with the same static classes ("group
rounded-12 w-full border border-dashed px-12 py-8 transition-colors") plus the
conditional classes based on isDragging to keep behavior identical but
consistent with other usages of cn.

Source: Coding guidelines

src/shared/ui/dropdown/DateDropdownBox.tsx (1)

27-31: ⚡ Quick win

조건부 텍스트/아이콘 클래스는 cn() 사용을 권장합니다.

Line 27, Line 31에서 템플릿 문자열로 조건부 클래스를 직접 합치고 있습니다. 공통 규칙대로 cn()으로 바꾸면 스타일 조건 관리가 더 명확해집니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/dropdown/DateDropdownBox.tsx` around lines 27 - 31, Replace the
template-string conditional classNames in the DateDropdownBox component with the
cn() helper: for the paragraph using selectedValue and placeholder (currently
`text-body1-sb ${selectedValue ? "text-main-main" : "text-gray-70"}`) and for
the ArrowDownIcon using isOpen (currently `text-gray-70 size-6
transition-transform duration-200 ${isOpen ? "rotate-180" : "rotate-0"}`),
import/ensure cn is available and build className with cn() so the shared
classes are passed as strings and the conditional classes use object/conditional
arguments (preserving text-main-main/text-gray-70 and rotate-180/rotate-0
behavior).

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/features/instructor/home/lib/getDDay.ts`:
- Around line 4-7: The getDDay function currently constructs target = new
Date(deadline) and computes diff without checking for invalid dates; add a
validation after creating target (use Number.isNaN(target.getTime())) and if
invalid return a safe fallback (e.g., "-" ) or throw an error, otherwise
continue computing diff and returning `D-{n}`/`D+{n}` using the existing target,
today, and diff logic; update any callers/tests if they expect the previous
string.

In `@src/shared/ui/dropdown/BankDropdown.tsx`:
- Around line 5-12: BankDropdown currently imports BANK_OPTIONS, BankCode, and
BankOption from the features layer which breaks FSD one-way dependency; either
move the constants/types (BANK_OPTIONS, BankCode, BankOption) into the shared
layer and update BankDropdown to import them from shared, or relocate the
BankDropdown component into the features/signup layer so it depends inward;
modify imports in BankDropdown.tsx (and update any other files using those
symbols) to reflect the new module locations and ensure type exports for
BankCode/BankOption are available from the chosen target.

---

Nitpick comments:
In `@src/shared/ui/AccordionMenu.tsx`:
- Around line 15-17: Replace the inline template-string conditional classNames
in AccordionMenu.tsx with the shared cn() helper: update the <p> element that
uses `{selected ? "text-main-main" : "text-gray-90"}` and the ArrowDownIcon
className that uses `{selected ? "text-main-main rotate-180" : "text-gray-70"}`
to call cn("text-body1-sb", selected ? "text-main-main" : "text-gray-90") and
cn("size-6 transition-transform duration-200", selected ? "text-main-main
rotate-180" : "text-gray-70") respectively so all conditional Tailwind class
merging uses cn().

In `@src/shared/ui/dropdown/DateDropdownBox.tsx`:
- Around line 27-31: Replace the template-string conditional classNames in the
DateDropdownBox component with the cn() helper: for the paragraph using
selectedValue and placeholder (currently `text-body1-sb ${selectedValue ?
"text-main-main" : "text-gray-70"}`) and for the ArrowDownIcon using isOpen
(currently `text-gray-70 size-6 transition-transform duration-200 ${isOpen ?
"rotate-180" : "rotate-0"}`), import/ensure cn is available and build className
with cn() so the shared classes are passed as strings and the conditional
classes use object/conditional arguments (preserving text-main-main/text-gray-70
and rotate-180/rotate-0 behavior).

In `@src/shared/ui/FileDragAndDrop.tsx`:
- Around line 45-49: Replace the inline template-string className construction
with the existing cn() utility: locate the JSX element that sets className using
the isDragging conditional (the block using isDragging ? "border-main-main
bg-purple-10" : "bg-gray-10 ...") and wrap the static classes and the
conditional classes in cn(...) (e.g., pass static class string and a conditional
object or array keyed by isDragging). Update the className assignment so it uses
cn(...) with the same static classes ("group rounded-12 w-full border
border-dashed px-12 py-8 transition-colors") plus the conditional classes based
on isDragging to keep behavior identical but consistent with other usages of cn.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 409f4f1c-aa73-4052-a7e6-1449a6ca01d2

📥 Commits

Reviewing files that changed from the base of the PR and between f292f23 and 3f1a4bb.

⛔ Files ignored due to path filters (44)
  • src/shared/assets/icons/icon_arrow_down.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_arrow_left.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_arrow_left_circle_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_arrow_right.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_arrow_right_circle_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_arrow_up.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_check_circle_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_checkbox_border_gray.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_checkbox_border_white.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_checkbox_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_close.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_close_circle.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_close_circle_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_enter.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_exclamation_mark_circle.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_exit.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_exit_bold.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_eye_closed.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_eye_open.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_file.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_file_bold.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_file_image.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_file_image_bold.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_folder_add.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_loading.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_matching_off.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_matching_on.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_number_one_circle_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_number_three_circle_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_number_two_circle_fill.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_profile_circle.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_profile_circle_bold.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_search.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_search_bold.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_share.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_step_one_designer.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_step_one_instructor.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_step_three_designer.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_step_two_designer.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_step_two_instructor.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_user_type_designer.svg is excluded by !**/*.svg
  • src/shared/assets/icons/icon_user_type_instructor.svg is excluded by !**/*.svg
  • src/shared/assets/logos/ditda_logo_black.svg is excluded by !**/*.svg
  • src/shared/assets/logos/ditda_logo_purple.svg is excluded by !**/*.svg
📒 Files selected for processing (95)
  • src/app/designer/layout.tsx
  • src/app/instructor/layout.tsx
  • src/app/instructor/page.tsx
  • src/app/instructor/write/layout.tsx
  • src/app/instructor/write/page.tsx
  • src/app/login/layout.tsx
  • src/app/login/page.tsx
  • src/app/signup/designer/step1/page.tsx
  • src/app/signup/designer/step2/page.tsx
  • src/app/signup/designer/step3/page.tsx
  • src/app/signup/instructor/step1/page.tsx
  • src/app/signup/instructor/step2/page.tsx
  • src/app/signup/layout.tsx
  • src/app/signup/page.tsx
  • src/assets/icons/index.ts
  • src/assets/logos/index.ts
  • src/features/instructor/home/index.ts
  • src/features/instructor/home/lib/getDDay.ts
  • src/features/instructor/home/model/home.ts
  • src/features/instructor/home/ui/CommissionsHeader.tsx
  • src/features/instructor/home/ui/DraftSubmissionStatusRow.tsx
  • src/features/instructor/home/ui/MatchingCommissionsRow.tsx
  • src/features/instructor/home/ui/ModifyingCommissionsRow.tsx
  • src/features/instructor/write/config/write.ts
  • src/features/instructor/write/index.ts
  • src/features/instructor/write/lib/color.ts
  • src/features/instructor/write/lib/date.ts
  • src/features/instructor/write/model/write.ts
  • src/features/instructor/write/model/writeFormStore.ts
  • src/features/instructor/write/ui/ColorChooseCard.tsx
  • src/features/instructor/write/ui/ColorPicker.tsx
  • src/features/instructor/write/ui/ConceptKeywordCard.tsx
  • src/features/instructor/write/ui/PaperSizeCard.tsx
  • src/features/instructor/write/ui/PaymentModal/PaymentModal.tsx
  • src/features/instructor/write/ui/PaymentModal/Step1.tsx
  • src/features/instructor/write/ui/PaymentModal/Step2.tsx
  • src/features/instructor/write/ui/PlanChooseCard.tsx
  • src/features/instructor/write/ui/ProgressBar.tsx
  • src/features/instructor/write/ui/SizeRecommendedCard.tsx
  • src/features/instructor/write/ui/StepHeader.tsx
  • src/features/signup/config/signup.ts
  • src/features/signup/index.ts
  • src/features/signup/model/useSignupStep2Form.ts
  • src/features/signup/ui/UserTypeBtn.tsx
  • src/shared/assets/icons/index.ts
  • src/shared/assets/logos/index.ts
  • src/shared/config/dropdown.ts
  • src/shared/config/sidebarMenu.ts
  • src/shared/lib/hooks/useUploadedFiles.ts
  • src/shared/lib/hooks/useWheelColumn.ts
  • src/shared/lib/utils/cn.ts
  • src/shared/lib/utils/dropdown.ts
  • src/shared/lib/utils/file.ts
  • src/shared/types/file.ts
  • src/shared/ui/AccordionMenu.tsx
  • src/shared/ui/Badge.tsx
  • src/shared/ui/Button.tsx
  • src/shared/ui/Chip.tsx
  • src/shared/ui/FileDragAndDrop.tsx
  • src/shared/ui/FileUpload.tsx
  • src/shared/ui/Header.tsx
  • src/shared/ui/Modal.tsx
  • src/shared/ui/PageIndicator.tsx
  • src/shared/ui/Radio.tsx
  • src/shared/ui/Sidebar.tsx
  • src/shared/ui/SidebarMenu.tsx
  • src/shared/ui/Tag.tsx
  • src/shared/ui/Toggle.tsx
  • src/shared/ui/dropdown/BankDropdown.tsx
  • src/shared/ui/dropdown/DateDropdownBox.tsx
  • src/shared/ui/dropdown/DateDropdownMenu.tsx
  • src/shared/ui/dropdown/WheelColumn.tsx
  • src/shared/ui/input/InputField.tsx
  • src/shared/ui/input/SmallInput.tsx
  • src/shared/ui/input/TextField.tsx
  • src/widgets/instructor/home/config/home.ts
  • src/widgets/instructor/home/index.ts
  • src/widgets/instructor/home/lib/usePagination.ts
  • src/widgets/instructor/home/ui/DraftSubmissionStatusSection.tsx
  • src/widgets/instructor/home/ui/MatchingCommissionsSection.tsx
  • src/widgets/instructor/home/ui/ModifyingCommissionsSection.tsx
  • src/widgets/instructor/write/index.ts
  • src/widgets/instructor/write/ui/AttachFileSection.tsx
  • src/widgets/instructor/write/ui/BasicInfoTypingSection.tsx
  • src/widgets/instructor/write/ui/CategorySection.tsx
  • src/widgets/instructor/write/ui/ColorChooseSection.tsx
  • src/widgets/instructor/write/ui/DeadlineChooseSection.tsx
  • src/widgets/instructor/write/ui/DesignConceptSection.tsx
  • src/widgets/instructor/write/ui/NecessaryPageChooseSection.tsx
  • src/widgets/instructor/write/ui/PlanChooseSection.tsx
  • src/widgets/instructor/write/ui/ReferenceSection.tsx
  • src/widgets/instructor/write/ui/SizeSection.tsx
  • src/widgets/instructor/write/ui/Step1Content.tsx
  • src/widgets/instructor/write/ui/Step2Content.tsx
  • src/widgets/instructor/write/ui/Step3Content.tsx
💤 Files with no reviewable changes (3)
  • src/assets/logos/index.ts
  • src/features/instructor/write/lib/date.ts
  • src/assets/icons/index.ts

Comment on lines +4 to +7
const target = new Date(deadline);
target.setHours(0, 0, 0, 0);
const diff = Math.ceil((target.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
return diff >= 0 ? `D-${diff}` : `D+${Math.abs(diff)}`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

유효하지 않은 날짜 입력 시 D+NaN이 반환됩니다.

new Date(deadline)가 Invalid Date인 경우 현재 분기에서 그대로 문자열이 만들어져 잘못된 D-Day가 노출됩니다. Number.isNaN(target.getTime()) 검증 후 안전한 fallback(예: "-" 반환 또는 예외 처리)을 넣어 주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/features/instructor/home/lib/getDDay.ts` around lines 4 - 7, The getDDay
function currently constructs target = new Date(deadline) and computes diff
without checking for invalid dates; add a validation after creating target (use
Number.isNaN(target.getTime())) and if invalid return a safe fallback (e.g., "-"
) or throw an error, otherwise continue computing diff and returning
`D-{n}`/`D+{n}` using the existing target, today, and diff logic; update any
callers/tests if they expect the previous string.

Comment on lines 5 to +12
import {
BANK_DROPDOWN_MAX_HEIGHT,
BANK_OPTIONS,
type BankCode,
type BankOption,
} from "@/constants/signup";
import { cn } from "@/lib/utils/cn";
} from "@/features/signup";
import { ArrowDownIcon, ArrowUpIcon } from "@/shared/assets/icons";
import { cn } from "@/shared/lib/utils/cn";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Shared 레이어에서 Features 레이어를 직접 참조하고 있습니다

Line 10에서 src/shared/ui/dropdown/BankDropdown.tsx@/features/signup을 import하여, FSD의 단방향 의존성(하위→상위 금지)을 깨고 있습니다. 이 상태는 shared 재사용성과 레이어 캡슐화를 약화시킵니다. BANK_OPTIONS/BankCode/BankOptionshared로 내리거나, 해당 드롭다운을 features/signup로 올려 의존 방향을 맞춰주세요.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/shared/ui/dropdown/BankDropdown.tsx` around lines 5 - 12, BankDropdown
currently imports BANK_OPTIONS, BankCode, and BankOption from the features layer
which breaks FSD one-way dependency; either move the constants/types
(BANK_OPTIONS, BankCode, BankOption) into the shared layer and update
BankDropdown to import them from shared, or relocate the BankDropdown component
into the features/signup layer so it depends inward; modify imports in
BankDropdown.tsx (and update any other files using those symbols) to reflect the
new module locations and ensure type exports for BankCode/BankOption are
available from the chosen target.

@github-actions

github-actions Bot commented Jun 7, 2026

Copy link
Copy Markdown

@waldls waldls merged commit accec95 into main Jun 7, 2026
2 checks passed
@waldls waldls deleted the feature/#25-fsd-refactor branch June 7, 2026 13:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[REFACTOR] FSD 방식으로 폴더 구조 개편

1 participant