Skip to content

Release v0.15.0#120

Merged
suminb99 merged 15 commits into
mainfrom
develop
May 14, 2026
Merged

Release v0.15.0#120
suminb99 merged 15 commits into
mainfrom
develop

Conversation

@suminb99

@suminb99 suminb99 commented May 14, 2026

Copy link
Copy Markdown
Contributor

@suminb99 suminb99 self-assigned this May 14, 2026
@vercel

vercel Bot commented May 14, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
snow-code-client Ready Ready Preview, Comment May 14, 2026 1:45am

@coderabbitai

coderabbitai Bot commented May 14, 2026

Copy link
Copy Markdown
📝 Walkthrough

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 과제 제출 이력 조회 기능 추가
    • 코드 에디터에서 터미널과 제출 이력 간 전환 가능
  • 개선 사항

    • 남은 기간을 한글로 표시 ('오늘', 'N일 전')
    • GitHub 이슈 템플릿을 개선된 형식으로 업데이트
    • 제출 이력 패널을 통한 이전 제출물 재조회 기능
  • 스타일

    • 코드 에디터 헤더 레이아웃 개선
    • 뱃지 표시 방식 최적화

워크스루

과제 제출 이력 조회 기능과 GitHub Issue Template을 Markdown에서 YAML 형식으로 마이그레이션했습니다. 제출 이력 스키마와 API 엔드포인트를 추가하고, 제출 페이지에서 터미널과 제출 이력 패널을 토글하는 UI를 구현했습니다.

변경사항

GitHub Issue Template 마이그레이션 (Markdown → YAML)

Layer / File(s) Summary
Issue template 형식 전환
.github/ISSUE_TEMPLATE/bug_report.*, .github/ISSUE_TEMPLATE/feature_request.*, .github/ISSUE_TEMPLATE/etc.*
기존 Markdown 기반 템플릿을 GitHub Issue Form YAML 형식으로 변환. 버그 리포트, 기능 요청, 기타 작업용 템플릿이 각각 새로운 구조화된 폼 정의로 대체됨. 필수/선택 필드와 타이틀 프리픽스를 명시적으로 정의.

Assignment 제출 이력 조회 기능

Layer / File(s) Summary
제출 이력 데이터 모델
src/entities/assignment/model/schemas.ts
assignmentSubmissionHistorySchema 추가: 과제 ID와 제출 목록(코드 ID, 성공 여부, 제출 시간)을 검증하는 Zod 스키마. TAssignmentSubmissionHistory 타입 추출.
제출 이력 API 및 쿼리 통합
src/entities/assignment/api/assignmentApi.ts, src/entities/assignment/api/assignmentQueries.ts
getAssignmentSubmissionHistory(unitId, assignmentId) API 함수와 React Query 옵션 빌더 추가. 제출 목록을 역순으로 정렬하여 최신 항목부터 표시.
제출 이력 UI 컴포넌트
src/pages/submit-assignment/ui/SubmissionHistoryPanel.tsx
새로운 SubmissionHistoryPanel 컴포넌트: 제출 목록을 시각화하고 순위, 상태(성공/실패), 상대 시간(예: "2일 전")을 표시. 특정 제출 버전을 선택하여 불러올 수 있는 "가져오기" 버튼 제공. 현재 활성 코드 ID 표시 기능 포함.
제출 페이지 통합 및 상태 관리
src/pages/submit-assignment/AssignmentSubmitPage.tsx
unitId 상태 추가 및 currentCodeId를 통한 코드 추적. 터미널과 제출 이력 패널을 토글하는 isTerminalOpen 상태 추가. useAssignmentSubmission 훅에 제출 성공 시 currentCodeId 업데이트 콜백 연결. 제출 이력 조회 후 조건부 렌더링(터미널 또는 제출 이력 패널).
코드 에디터 UI 확장
src/pages/submit-assignment/ui/CodeEditor.tsx
CodeEditorPropsonTerminalToggle 콜백과 isTerminalOpen 상태 추가. 헤더에 토글 버튼 추가: isTerminalOpen 상태에 따라 "제출이력 보기" 또는 "터미널 열기" 레이블 표시.
제출 훅 리팩토링 및 무효화 로직
src/features/assignment/submit-assignment/lib/useAssignmentSubmission.ts
함수 시그니처 변경: unitId를 파라미터로 받도록 변경. 선택적 onSubmitSuccess 콜백 추가. 뮤테이션 성공 시 assignmentQueries.getAssignmentSubmissionHistory() 무효화 로직으로 변경하여 제출 이력 자동 갱신.
한글 포맷팅 및 표시 업데이트
src/shared/lib/course.ts, src/pages/dashboard/ui/ScheduleCard.tsx, src/shared/ui/badge/Badge.tsx
formatDaysAgo(isoString) 유틸리티 함수 추가: ISO 문자열을 받아 "오늘" 또는 "{n}일 전" 형식으로 포맷. ScheduleCard 배지와 Badge 컴포넌트의 schedule 변형에서 한글 표시 방식으로 통일.
마이너 리팩토링
src/pages/submit-assignment/ui/Terminal.tsx, src/shared/config/endpoints.ts
Terminal 컴포넌트의 외부 래퍼 스타일 제거 (h-full, bg-primary-black 클래스 삭제). ENDPOINTS.ENROLLMENTS.BY_COURSE 엔드포인트 포맷팅 정리 (기능 변경 없음).

Sequence Diagram

sequenceDiagram
    actor User
    participant Page as AssignmentSubmitPage
    participant Editor as CodeEditor
    participant API as AssignmentAPI
    participant Query as React Query
    participant Server as Backend

    User->>Page: 페이지 로드 (이전 제출 코드 ID 포함)
    Page->>Page: currentCodeId 초기화<br/>unitId 계산
    Page->>Query: assignmentCode 쿼리<br/>(currentCodeId 기반)
    Query->>Server: GET /assignment/{id}
    Server-->>Query: 과제 코드 반환
    Query-->>Page: assignmentCode 데이터
    
    Page->>Query: getAssignmentSubmissionHistory<br/>(unitId, assignmentId)
    Query->>Server: GET /submission-history
    Server-->>Query: 제출 이력 목록 반환
    Query-->>Page: submissionList (역순)

    Page->>Editor: CodeEditor 렌더링<br/>(currentCodeId, runCode, onTerminalToggle)
    Editor->>Editor: 토글 버튼 표시<br/>(터미널/이력 모드)

    User->>Editor: "제출이력 보기" 클릭
    Editor->>Page: onTerminalToggle()
    Page->>Page: isTerminalOpen = false
    Page->>Page: SubmissionHistoryPanel 렌더링<br/>(submissionList, currentCodeId)

    User->>Page: 제출 이력에서 "가져오기" 클릭
    Page->>Page: setCurrentCodeId(selectedCodeId)
    Page->>Query: assignmentCode 다시 쿼리<br/>(새로운 currentCodeId)
    Query->>Server: GET /assignment/{selectedCodeId}
    Server-->>Query: 선택된 코드 반환
    Query-->>Page: 업데이트된 코드
    Editor->>Editor: 선택된 코드 에디터에 표시

    User->>Editor: 코드 실행 또는 제출
    Editor->>Page: runCode() / onSubmit()
    Page->>API: 제출 요청
    API->>Server: POST /submit
    Server-->>API: 제출 결과 (codeId)
    API-->>Page: 성공 응답
    Page->>Page: currentCodeId 업데이트<br/>submissionList 무효화
    Query->>Server: 제출 이력 재조회
    Server-->>Query: 업데이트된 이력
    Query-->>Page: 최신 submissionList
    Page->>Page: SubmissionHistoryPanel 자동 갱신
Loading

예상 코드 리뷰 난이도

🎯 3 (Moderate) | ⏱️ ~45분

이 변경사항은 새로운 제출 이력 기능을 추가하면서 여러 계층(스키마, API, 쿼리, UI, 페이지 통합)에 걸쳐 수행되어 중간 정도의 복잡도를 가집니다. 변경사항이 상태 관리, 컴포넌트 통합, 데이터 흐름을 포함하므로 각 부분의 일관성을 확인해야 합니다. 다행히 GitHub Issue Template 마이그레이션은 단순하고 반복적인 변경이므로 리뷰 시간을 다소 단축시킵니다.

관련 PR

  • 2025-snowCode/snowCode-Client#114: 제출 이력 기능의 핵심 구현—스키마, API, 쿼리, SubmissionHistoryPanel 통합이 직접적으로 연결됨.
  • 2025-snowCode/snowCode-Client#112: 제출 페이지 및 CodeEditor 컴포넌트 수정이 겹치는 영역이 있어 병합 충돌 가능성 확인 필요.
  • 2025-snowCode/snowCode-Client#72: 제출 흐름의 기반 기능(useAssignmentSubmission, AssignmentSubmitPage, CodeEditor)을 이전에 도입했으므로 이 기능과의 의존성 확인.

제안 라벨

🧩 feature, 🎨 ui, 🛠️ refactor

제안 리뷰어

  • JiiminHa
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning PR 설명은 템플릿 형식만 남겨진 상태로, 실제 작업 내용, 관련 이슈, 변경사항에 대한 구체적인 정보가 전혀 작성되지 않았습니다. 템플릿의 각 섹션(작업 내용, 관련 이슈번호, 스크린샷, 리뷰 요청사항)을 실제 내용으로 채워주세요. 커밋 메시지에 따르면 제출이력 기능 추가가 핵심이므로 이를 명시하세요.
Title check ❓ Inconclusive PR 제목 'Release'는 실제 변경사항(제출이력 조회 기능 추가, 이슈 템플릿 변경, UI 개선 등)을 설명하지 못하는 매우 모호한 표현입니다. 'Add assignment submission history feature' 같이 핵심 변경사항을 명확히 드러내는 구체적인 제목으로 수정하세요.
✅ Passed checks (3 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • 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.

@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 (1)
src/pages/submit-assignment/ui/SubmissionHistoryPanel.tsx (1)

38-44: ⚡ Quick win

조건부 className 패턴 개선 제안

현재 템플릿 리터럴로 조건부 클래스를 적용하고 있는데, 가독성을 위해 clsx 라이브러리를 활용하거나 논리 연산자를 사용하는 것을 권장합니다.

♻️ 개선 제안

방법 1: 논리 연산자 활용

-                  className={`px-3.5 py-1.5
-                  ${
-                    submission.codeId === currentCodeId
-                      ? 'bg-[`#CAC2F7`] rounded-[35px]'
-                      : 'bg-transparent'
-                  }
-                `}>
+                  className={`px-3.5 py-1.5 ${
+                    submission.codeId === currentCodeId
+                      ? 'bg-[`#CAC2F7`] rounded-[35px]'
+                      : 'bg-transparent'
+                  }`}>

방법 2: clsx 라이브러리 사용 (프로젝트에 이미 설치되어 있다면)

className={clsx(
  'px-3.5 py-1.5',
  submission.codeId === currentCodeId
    ? 'bg-[`#CAC2F7`] rounded-[35px]'
    : 'bg-transparent'
)}
🤖 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/pages/submit-assignment/ui/SubmissionHistoryPanel.tsx` around lines 38 -
44, In SubmissionHistoryPanel.tsx update the conditional className on the
element that uses submission and currentCodeId: replace the long template
literal with a clearer pattern (preferably using clsx) and add the clsx import;
e.g. import clsx from 'clsx' at the top and set className via clsx combining the
base classes ('px-3.5 py-1.5') with a conditional class that applies
'bg-[`#CAC2F7`] rounded-[35px]' when submission.codeId === currentCodeId and
'bg-transparent' otherwise; alternatively you may use logical && to append the
active classes instead of a ternary.
🤖 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/pages/dashboard/ui/ScheduleCard.tsx`:
- Line 23: In ScheduleCard.tsx replace the loose equality check with a strict
one: update the conditional that renders {remainingDays == 0 ? '오늘' :
`${remainingDays}일 전`} to use === for remainingDays (use remainingDays === 0) so
the comparison in the ScheduleCard component is type-safe and avoids implicit
coercion.

In `@src/pages/submit-assignment/AssignmentSubmitPage.tsx`:
- Around line 43-70: unitId can be undefined causing Number(unitId) to become
NaN and be passed into useAssignmentSubmission; avoid this by adding an early
return (e.g., return null or a loading state) before any hooks that depend on
unitId so useAssignmentSubmission(Number(unitId), ...) is never called when
unitId is falsy; specifically, check the computed unitId (from
courseDetails.units.find(...)) and if not present render a fallback UI before
invoking useAssignmentSubmission, leaving other safe hooks unchanged.

---

Nitpick comments:
In `@src/pages/submit-assignment/ui/SubmissionHistoryPanel.tsx`:
- Around line 38-44: In SubmissionHistoryPanel.tsx update the conditional
className on the element that uses submission and currentCodeId: replace the
long template literal with a clearer pattern (preferably using clsx) and add the
clsx import; e.g. import clsx from 'clsx' at the top and set className via clsx
combining the base classes ('px-3.5 py-1.5') with a conditional class that
applies 'bg-[`#CAC2F7`] rounded-[35px]' when submission.codeId === currentCodeId
and 'bg-transparent' otherwise; alternatively you may use logical && to append
the active classes instead of a ternary.
🪄 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

Run ID: 5f756167-4ba7-4dd6-86d1-914dede954de

📥 Commits

Reviewing files that changed from the base of the PR and between 4e82999 and 05857e3.

⛔ Files ignored due to path filters (1)
  • src/assets/svg/retrieveIcon.svg is excluded by !**/*.svg
📒 Files selected for processing (18)
  • .github/ISSUE_TEMPLATE/bug_report.md
  • .github/ISSUE_TEMPLATE/bug_report.yml
  • .github/ISSUE_TEMPLATE/etc.md
  • .github/ISSUE_TEMPLATE/etc.yml
  • .github/ISSUE_TEMPLATE/feature_request.md
  • .github/ISSUE_TEMPLATE/feature_request.yml
  • src/entities/assignment/api/assignmentApi.ts
  • src/entities/assignment/api/assignmentQueries.ts
  • src/entities/assignment/model/schemas.ts
  • src/features/assignment/submit-assignment/lib/useAssignmentSubmission.ts
  • src/pages/dashboard/ui/ScheduleCard.tsx
  • src/pages/submit-assignment/AssignmentSubmitPage.tsx
  • src/pages/submit-assignment/ui/CodeEditor.tsx
  • src/pages/submit-assignment/ui/SubmissionHistoryPanel.tsx
  • src/pages/submit-assignment/ui/Terminal.tsx
  • src/shared/config/endpoints.ts
  • src/shared/lib/course.ts
  • src/shared/ui/badge/Badge.tsx
💤 Files with no reviewable changes (3)
  • .github/ISSUE_TEMPLATE/etc.md
  • .github/ISSUE_TEMPLATE/bug_report.md
  • .github/ISSUE_TEMPLATE/feature_request.md

variant='schedule'
schedule={remainingDays <= 1 ? 'upcoming' : 'later'}>
{remainingDays}
{remainingDays == 0 ? '오늘' : `${remainingDays}일 전`}

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

엄격한 동등 연산자(===)를 사용하세요.

느슨한 동등 연산자(==) 대신 엄격한 동등 연산자(===)를 사용해야 합니다. TypeScript/JavaScript에서는 타입 강제 변환을 방지하기 위해 항상 ===를 사용하는 것이 권장됩니다.

📚 참고: MDN - 동등 비교 및 동일성

🔧 제안하는 수정
-          {remainingDays == 0 ? '오늘' : `${remainingDays}일 전`}
+          {remainingDays === 0 ? '오늘' : `${remainingDays}일 전`}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{remainingDays == 0 ? '오늘' : `${remainingDays}일 전`}
{remainingDays === 0 ? '오늘' : `${remainingDays}일 전`}
🤖 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/pages/dashboard/ui/ScheduleCard.tsx` at line 23, In ScheduleCard.tsx
replace the loose equality check with a strict one: update the conditional that
renders {remainingDays == 0 ? '오늘' : `${remainingDays}일 전`} to use === for
remainingDays (use remainingDays === 0) so the comparison in the ScheduleCard
component is type-safe and avoids implicit coercion.

Comment on lines +43 to +70
const unitId = courseDetails.units.find((unit) =>
unit.assignments.some(
(assignment) => assignment.id === Number(assignmentId)
)
)?.id;

const {data: submissionList} = useQuery({
...assignmentQueries.getAssignmentSubmissionHistory(
Number(unitId),
Number(assignmentId)
),
enabled: !!unitId,
});

const {data: assignmentCode} = useQuery({
...assignmentQueries.getAssignmentCode(Number(codeId || 0)),
enabled: !!codeId,
...assignmentQueries.getAssignmentCode(Number(currentCodeId || 0)),
enabled: !!currentCodeId,
});

const {runCode, output, isRunning} = useCodeExecution(Number(assignmentId));

const {onSubmit, result, isSubmitPending, isModalOpen, closeModal} =
useAssignmentSubmission(courseDetails, Number(assignmentId));
useAssignmentSubmission(
Number(unitId),
courseDetails,
Number(assignmentId),
setCurrentCodeId
);

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 | 🔴 Critical | ⚡ Quick win

unitIdundefined일 때 NaN이 전달되는 문제

unitId 찾기 로직(Line 43-47)에서 해당 과제를 포함한 유닛을 찾지 못하면 unitIdundefined가 됩니다. 이 상태에서 Line 65의 Number(unitId)NaN을 반환하고, 이 값이 useAssignmentSubmission 훅에 전달되어 API 호출 시 오류가 발생할 수 있습니다.

Line 49-55의 쿼리는 enabled: !!unitId로 보호되어 있지만, Line 65-70의 훅 호출은 보호되지 않았습니다.

🐛 개선 제안

방법 1: Early return 패턴

  const unitId = courseDetails.units.find((unit) =>
    unit.assignments.some(
      (assignment) => assignment.id === Number(assignmentId)
    )
  )?.id;

+ if (!unitId) {
+   // 에러 상태 표시 또는 로딩 처리
+   return <div>유닛을 찾을 수 없습니다.</div>;
+ }

  const {data: submissionList} = useQuery({
    ...assignmentQueries.getAssignmentSubmissionHistory(
-     Number(unitId),
+     unitId,
      Number(assignmentId)
    ),
-   enabled: !!unitId,
  });

방법 2: 조건부 훅 호출 (비추천 - Rules of Hooks 위반 가능성)
훅 호출은 항상 같은 순서로 이루어져야 하므로, 조건부로 보호하기보다는 방법 1을 권장합니다.

🤖 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/pages/submit-assignment/AssignmentSubmitPage.tsx` around lines 43 - 70,
unitId can be undefined causing Number(unitId) to become NaN and be passed into
useAssignmentSubmission; avoid this by adding an early return (e.g., return null
or a loading state) before any hooks that depend on unitId so
useAssignmentSubmission(Number(unitId), ...) is never called when unitId is
falsy; specifically, check the computed unitId (from
courseDetails.units.find(...)) and if not present render a fallback UI before
invoking useAssignmentSubmission, leaving other safe hooks unchanged.

@suminb99 suminb99 merged commit fb1b24e into main May 14, 2026
4 checks passed
@suminb99 suminb99 changed the title Release Release v1.5.0 May 14, 2026
@suminb99 suminb99 changed the title Release v1.5.0 Release v0.15.0 May 14, 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