Skip to content

[Feat] 회의록 페이지 및 작성 기능 구현 - #24

Merged
JiWoongE merged 3 commits into
developfrom
Feat/#21/meeting-notes-pages
Jul 9, 2026
Merged

[Feat] 회의록 페이지 및 작성 기능 구현#24
JiWoongE merged 3 commits into
developfrom
Feat/#21/meeting-notes-pages

Conversation

@JiWoongE

@JiWoongE JiWoongE commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Pull Request

작업 내용

  • 팀 프로젝트 워크스페이스용 회의록 목록 페이지와 작성 페이지를 구현했습니다.
  • 회의록 기능을 FSD 구조(app / views / features / entities)로 분리해 추가했습니다.
  • 회의록 작성 버튼 클릭 시 독립된 작성 페이지로 이동하고, 저장 후 목록으로 돌아오는 흐름을 구현했습니다.
  • 작성 페이지에서 날짜 입력 UX, 참석자 체크리스트 선택, 제목 필수 검증을 추가했습니다.
  • 목록 페이지에서 회의록 카드를 클릭하면 피그마 기준 상세 카드 형태로 결정사항 / 후속 업무가 펼쳐지도록 구현했습니다.
  • API 연동 전 단계로, 작성한 회의록이 목록에 바로 보이도록 클라이언트 임시 저장 store를 연결했습니다.

작업 결과

  • http://localhost:3000/workspaces/test/meeting-notes 에서 회의록 목록 페이지를 확인할 수 있습니다.
  • http://localhost:3000/workspaces/test/meeting-notes/new 에서 회의록 작성 페이지를 확인할 수 있습니다.
  • 회의록 작성 후 저장하면 목록 페이지로 이동하며, 방금 작성한 회의록이 바로 목록에 반영됩니다.
  • 참석자는 현재 워크스페이스 mock 멤버 목록을 기반으로 체크리스트 형태로 선택할 수 있습니다.
  • 목록 카드 클릭 시 해당 회의록의 상세 내용이 확장됩니다.

스크린샷

  • 회의록 목록 페이지:
image
  • 회의록 작성 페이지:
image
  • 회의록 상세 펼침 상태:
image

변경 사항

Added

  • 회의록 목록 라우트 추가
  • 회의록 작성 라우트 추가
  • entities/meeting-note 타입, mock 데이터, 카드 UI 추가
  • features/manage-meeting-notes 목록/작성 UI 및 임시 저장 store 추가
  • views/meeting-notes 페이지 조합 추가
  • test 워크스페이스용 mock 멤버 데이터 추가

Changed

  • 회의록 목록 폭과 카드 레이아웃을 피그마 기준으로 조정
  • 회의록 작성 폼 폭과 입력 레이아웃을 피그마 기준으로 조정
  • 날짜 입력을 연도 / 월 / 일 직접 입력 + 달력 버튼 방식으로 변경
  • 참석자 입력을 자유 텍스트에서 워크스페이스 멤버 체크리스트형 선택으로 변경
  • 회의록 데이터 구조를 결정사항[], 후속 업무[] 기준으로 정리

Fixed

  • 참석자 드롭다운 안쪽 클릭 시 선택이 되지 않던 문제 수정
  • 작성 후 목록으로 돌아가도 새 회의록이 보이지 않던 문제 수정

테스트

  • 로컬 실행 확인
  • 주요 시나리오 확인
  • 영향 범위 확인

리뷰 체크리스트

  • PR base branch가 올바릅니다. (feature/* -> develop, 배포 시 develop 또는 release/* -> main)
  • 브랜치명이 Type/#issue-number/description 형식을 따릅니다.
  • 커밋 메시지가 컨벤션을 따릅니다.
  • 불필요한 console.log, 주석, 임시 코드를 제거했습니다.
  • 타입 에러와 린트 에러를 확인했습니다.
  • CodeRabbit 1차 리뷰를 확인했습니다.
  • CodeRabbit 리뷰 반영 후 Discord에 공유했습니다.
  • 최소 1명 이상의 approve 후 merge합니다.

리뷰 요청사항

  • 현재 회의록 저장은 API/Supabase 연동 전 단계라, 클라이언트 임시 store 기준으로만 반영됩니다.
  • 새로고침 시 작성한 회의록은 유지되지 않으며, 실제 persistence는 후속 작업 예정입니다.
  • 참석자 선택 UI와 회의록 상세 펼침 방식이 팀에서 의도한 UX와 맞는지 확인 부탁드립니다.

관련 이슈

Closes #21

Summary by CodeRabbit

  • New Features
    • 워크스페이스별 회의록 목록과 새 회의록 작성 화면을 추가했습니다.
    • 작성 폼에서 참석자 선택, 날짜 입력, 결정사항/후속 업무 입력을 지원합니다.
    • 회의록 카드를 클릭해 상세를 펼치고, 목록에서 새 회의록 추가로 바로 이동할 수 있습니다.
  • Bug Fixes
    • 워크스페이스별 데이터가 섞이지 않도록 초기화/추가 동작을 개선했습니다.
    • 목록 렌더링 시 기존 데이터가 우선 반영되도록 정리했습니다.
  • Refactor
    • 페이지 간 글꼴 적용 방식을 통일했습니다.

@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

회의록 목록과 작성 화면이 추가되었고, 워크스페이스별 목업 회의록/멤버 조회, 상태 저장, 카드 렌더링, 라우트 연결이 함께 구성되었다. 공유 폰트 설정이 도입되어 일부 페이지가 해당 폰트를 사용하도록 변경되었다.

Changes

회의록 기능

Layer / File(s) Summary
타입과 목업 데이터
src/entities/meeting-note/model/meeting-note.types.ts, src/entities/meeting-note/model/mock-meeting-notes-by-workspace.ts, src/entities/meeting-note/index.ts, src/entities/workspace-member/model/mock-workspace-members.ts, src/entities/workspace-member/index.ts, src/features/manage-meeting-notes/index.ts
MeetingNoteParticipant, MeetingNote, MeetingNoteFormValues 타입과 워크스페이스별 회의록/멤버 조회 함수가 추가되고, 관련 엔트리 포인트에서 재-내보내기된다.
회의록 상태관리
src/features/manage-meeting-notes/model/use-meeting-notes-store.ts
useMeetingNotesStore가 추가되어 워크스페이스별 회의록 목록 초기화와 새 회의록 추가를 처리한다.
회의록 카드
src/entities/meeting-note/ui/MeetingNoteCard.tsx
MeetingNoteCard가 제목, 날짜, 참가자, 결정사항, 후속 업무를 렌더링하고, 키보드 확장 동작과 isExpanded 조건부 표시를 지원한다.
회의록 목록
src/features/manage-meeting-notes/ui/MeetingNotesList.tsx
MeetingNotesList가 store를 초기화한 뒤 워크스페이스별 회의록을 렌더링하고, 카드 확장 토글과 작성 페이지 링크를 제공한다.
회의록 작성 폼
src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx
MeetingNoteForm이 날짜 분해/검증, 참석자 선택, 결정사항/후속 업무 정규화, 저장 후 목록 라우팅을 수행한다.
뷰와 라우트
src/views/meeting-notes/ui/MeetingNotesPage.tsx, src/views/meeting-notes/ui/NewMeetingNotePage.tsx, src/views/meeting-notes/index.ts, src/app/workspaces/[workspaceId]/meeting-notes/page.tsx, src/app/workspaces/[workspaceId]/meeting-notes/new/page.tsx
회의록 목록/작성 뷰가 추가되고, 두 Next.js async 페이지가 params에서 workspaceId를 받아 해당 뷰로 전달한다.

공유 폰트

Layer / File(s) Summary
공유 폰트 설정
src/shared/lib/fonts.ts
Plus_Jakarta_Sans 기반의 plusJakartaSans 설정이 추가되었다.
폰트 적용 변경
src/views/project-management/ui/ProjectManagementPage.tsx
프로젝트 관리 페이지가 로컬 폰트 설정 대신 공유 폰트를 사용하도록 변경되었다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant MeetingNotesPageRoute
  participant MeetingNotesPage
  participant MeetingNotesList
  participant useMeetingNotesStore
  participant MeetingNoteCard

  User->>MeetingNotesPageRoute: /workspaces/{workspaceId}/meeting-notes 접속
  MeetingNotesPageRoute->>MeetingNotesPage: workspaceId 전달
  MeetingNotesPage->>MeetingNotesPage: getMockMeetingNotesByWorkspaceId(workspaceId)
  MeetingNotesPage->>MeetingNotesList: meetingNotes, workspaceId 전달
  MeetingNotesList->>useMeetingNotesStore: initializeWorkspace(workspaceId, meetingNotes)
  MeetingNotesList->>MeetingNoteCard: 회의록 카드 렌더링
  MeetingNoteCard-->>User: 제목/참석자/세부 항목 표시
Loading
sequenceDiagram
  participant User
  participant NewMeetingNotePageRoute
  participant NewMeetingNotePage
  participant MeetingNoteForm
  participant useMeetingNotesStore
  participant Router

  User->>NewMeetingNotePageRoute: /workspaces/{workspaceId}/meeting-notes/new 접속
  NewMeetingNotePageRoute->>NewMeetingNotePage: workspaceId 전달
  NewMeetingNotePage->>MeetingNoteForm: workspaceId 전달
  User->>MeetingNoteForm: 제목/날짜/참석자/내용 입력
  User->>MeetingNoteForm: 제출
  MeetingNoteForm->>useMeetingNotesStore: addMeetingNote(workspaceId, meetingNote)
  MeetingNoteForm->>Router: /workspaces/{workspaceId}/meeting-notes 이동
Loading

Suggested reviewers: Kwon812, 0011810, wjswlgh96

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning 목록/작성 페이지와 mock 데이터는 구현됐지만, 이슈의 필수 요구인 navigation 회의록 라우트 연결 증거가 없습니다. navigation 메뉴에 회의록 라우트를 연결한 변경을 추가하고, 해당 동선이 실제로 작동함을 확인할 수 있게 보완하세요.
Out of Scope Changes check ⚠️ Warning 회의록 기능과 무관한 ProjectManagementPage 폰트 교체가 포함되어 있어 이슈 범위를 벗어난 변경이 있습니다. 회의록 관련 변경과 분리해 별도 PR로 옮기거나, 해당 수정이 필요한 직접 연관성을 명확히 설명하세요.
✅ 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.
Title check ✅ Passed 회의록 목록과 작성 기능 구현을 정확히 요약한 제목입니다.
Description check ✅ Passed 템플릿의 주요 섹션(작업 내용, 결과, 변경 사항, 테스트, 체크리스트, 리뷰 요청사항, 관련 이슈)을 대부분 채웠습니다.
✨ 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 Feat/#21/meeting-notes-pages

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

@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: 8

🤖 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/entities/meeting-note/model/meeting-note.types.ts`:
- Around line 18-24: `MeetingNoteFormValues`의 `participants` 필드는
`MeetingNoteForm.tsx`에서 실제로 읽히지 않고 `selectedParticipantIds`와 제출 시 생성되는
`participants` 배열로만 처리되므로, 이 불필요한 상태를 타입에서 제거하거나 `MeetingNoteForm`의 실제 입력값과
연결되도록 정리하세요. 특히 `MeetingNoteFormValues`와 이를 사용하는 폼 초기값/제출 로직을 함께 확인해,
`participants`가 진짜 폼 데이터로 쓰이게 할지 아니면 타입 정의에서 없앨지 일관되게 맞추세요.

In `@src/entities/meeting-note/ui/MeetingNoteCard.tsx`:
- Around line 16-78: The clickable wrapper in MeetingNoteCard is invalid because
a <button> is containing <article> and <h3>, which are not allowed content for
that element. Update the outer interactive container in MeetingNoteCard to use a
non-button element such as a div with role="button" and tabIndex={0}, and add
keyboard support for Enter and Space while preserving the existing onClick and
aria-expanded behavior. Keep the internal article/heading structure unchanged so
the card remains accessible and semantically correct.

In `@src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx`:
- Around line 302-313: The hidden native date input in MeetingNoteForm is still
exposed to assistive technology despite being visually hidden and removed from
tab order. Update the input rendered in MeetingNoteForm to include
aria-hidden="true" alongside the existing ref, type, value, onChange, className,
aria-label, and tabIndex settings so the custom 3-part date fields remain the
only accessible control.
- Around line 15-21: The MeetingNoteForm state currently keeps a redundant
participants string in formValues that is only updated by toggleParticipant and
never used in the save flow, while selectedParticipantIds/selectedParticipants
already drive the real MeetingNoteParticipant payload. Remove the unused
formValues.participants field and any related string-join updates, and keep
participant selection logic centered on the existing selectedParticipantIds and
selectedParticipants handling so the form has a single source of truth.
- Around line 15-21: The default meeting date in MeetingNoteForm is hardcoded to
an old fixed value, so new notes always start with that date instead of today.
Update the defaultFormValues in MeetingNoteForm.tsx so meetingDate is
initialized dynamically to the current date when the form is created, keeping
the existing form fields and MeetingNoteFormValues structure unchanged.
- Around line 98-104: In MeetingNoteForm, the submit flow currently never
reaches handleSubmit when the title is empty because the save action is disabled
by isTitleValid, so the hasSubmitted-based title error can never appear. Update
the form behavior so submission can occur and validation happens inside
handleSubmit (keeping setHasSubmitted(true) and the !formValues.title.trim()
check), or alternatively remove the unreachable inline error logic tied to
hasSubmitted && !isTitleValid; make the save control and validation state
consistent around handleSubmit, isTitleValid, and the 저장하기 button.
- Around line 114-119: The MeetingNoteForm.tsx meetingNoteId generation
currently uses only workspaceId, meetingDate, and the trimmed title slug, so
identical titles on the same date can collide. Update the meetingNoteId
construction in MeetingNoteForm to include an additional unique discriminator
from the form or generated note state (for example an existing note identifier
or a newly generated unique suffix) so store entries and React list keys remain
unique even when title and date match.

In `@src/views/meeting-notes/ui/NewMeetingNotePage.tsx`:
- Around line 4-7: The font is being instantiated directly inside
NewMeetingNotePage via Plus_Jakarta_Sans, which can lead to duplicated
next/font/google setup across meeting-notes views. Move the font loading to the
shared layout (layout.tsx) so it is created once and applied globally, and then
remove the per-view font initialization here and in any similar components like
MeetingNotesPage to keep styling consistent.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: dc06e86c-4b69-4b13-93ac-902f0dda6bd9

📥 Commits

Reviewing files that changed from the base of the PR and between 03a84a2 and c1c472c.

📒 Files selected for processing (15)
  • src/app/workspaces/[workspaceId]/meeting-notes/new/page.tsx
  • src/app/workspaces/[workspaceId]/meeting-notes/page.tsx
  • src/entities/meeting-note/index.ts
  • src/entities/meeting-note/model/meeting-note.types.ts
  • src/entities/meeting-note/model/mock-meeting-notes-by-workspace.ts
  • src/entities/meeting-note/ui/MeetingNoteCard.tsx
  • src/entities/workspace-member/index.ts
  • src/entities/workspace-member/model/mock-workspace-members.ts
  • src/features/manage-meeting-notes/index.ts
  • src/features/manage-meeting-notes/model/use-meeting-notes-store.ts
  • src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx
  • src/features/manage-meeting-notes/ui/MeetingNotesList.tsx
  • src/views/meeting-notes/index.ts
  • src/views/meeting-notes/ui/MeetingNotesPage.tsx
  • src/views/meeting-notes/ui/NewMeetingNotePage.tsx

Comment thread src/entities/meeting-note/model/meeting-note.types.ts
Comment thread src/entities/meeting-note/ui/MeetingNoteCard.tsx Outdated
Comment thread src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx Outdated
Comment thread src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx
Comment thread src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx Outdated
Comment thread src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx
Comment thread src/views/meeting-notes/ui/NewMeetingNotePage.tsx Outdated

@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: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/entities/meeting-note/ui/MeetingNoteCard.tsx (2)

61-91: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

decisions/followUpActions 문자열을 React key로 그대로 사용 — 중복 시 충돌 위험

key={decision}, key={actionItem}은 배열 값 자체를 키로 씁니다. 동일한 텍스트가 두 번 이상 등장하면(예: 같은 결정사항을 반복 기록) key 충돌로 React 리스트 재조정이 부정확해지거나 콘솔 경고가 발생할 수 있습니다. 인덱스를 조합한 키가 더 안전합니다.

🔑 제안 수정
-                {meetingNote.decisions.map((decision) => (
-                  <li key={decision} className="flex items-start gap-2 text-[14px] leading-5 text-brand-ink">
+                {meetingNote.decisions.map((decision, index) => (
+                  <li key={`${decision}-${index}`} className="flex items-start gap-2 text-[14px] leading-5 text-brand-ink">
                     <Check className="mt-[3px] size-[14px] shrink-0 text-[`#00c950`]" />
                     <span>{decision}</span>
                   </li>
                 ))}
-                {meetingNote.followUpActions.map((actionItem) => (
-                  <li key={actionItem} className="flex items-start gap-2 text-[14px] leading-5 text-brand-ink">
+                {meetingNote.followUpActions.map((actionItem, index) => (
+                  <li key={`${actionItem}-${index}`} className="flex items-start gap-2 text-[14px] leading-5 text-brand-ink">
                     <ArrowRight className="mt-[3px] size-[14px] shrink-0 text-brand-start" />
                     <span>{actionItem}</span>
                   </li>
                 ))}
🤖 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/entities/meeting-note/ui/MeetingNoteCard.tsx` around lines 61 - 91, In
MeetingNoteCard’s expanded lists, the current React keys use the raw
decision/action text, which can collide when duplicate strings appear. Update
the list rendering for meetingNote.decisions and meetingNote.followUpActions to
use a stable unique key per item, such as combining the item value with its
index or another identifier, so the rendered lists in MeetingNoteCard remain
deterministic even with repeated entries.

46-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

참석자 아바타의 aria-labelgeneric role(div)에는 적용되지 않음

div는 명시적 role이 없으면 ARIA generic role로 매핑되며, ARIA 스펙상 generic role은 "Name from: Prohibited"이므로 aria-label이 접근성 트리에 노출되지 않을 수 있습니다(브라우저별 동작이 비표준적으로 다름). title 속성도 스크린리더에서 신뢰성 있게 읽히지 않으므로, 참석자 이름을 실제로 전달하려면 role="img"를 부여하거나 시각적으로 숨긴 텍스트를 함께 넣는 방식을 권장합니다.

♿️ 제안 수정
               <div
                 key={participant.id}
+                role="img"
                 className="flex size-7 items-center justify-center rounded-full text-[12px] font-semibold text-white"
                 style={{ backgroundColor: participant.color }}
                 title={participant.name}
                 aria-label={participant.name}
               >
🤖 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/entities/meeting-note/ui/MeetingNoteCard.tsx` around lines 46 - 58, The
participant avatar divs in MeetingNoteCard are using aria-label on the default
generic role, which may not expose the name to assistive tech. Update the
participant element rendering in MeetingNoteCard to use an accessible pattern
such as giving each avatar a non-generic role like img or adding visually hidden
text with the participant.name, and keep the unique participant.id/key and
existing participant fields intact while making the accessible name reliable.
🤖 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/manage-meeting-notes/ui/MeetingNoteForm.tsx`:
- Around line 15-24: The default meeting date is being computed once at module
load via getTodayIsoDate() and initialMeetingDate, so it can become stale if the
app stays open; move this to the MeetingNoteForm component and use a useState
lazy initializer so getTodayIsoDate() is recalculated on each mount. Update the
state setup that consumes initialMeetingDate to call getTodayIsoDate() directly
during initialization, keeping the date fresh when a new note form opens.

---

Outside diff comments:
In `@src/entities/meeting-note/ui/MeetingNoteCard.tsx`:
- Around line 61-91: In MeetingNoteCard’s expanded lists, the current React keys
use the raw decision/action text, which can collide when duplicate strings
appear. Update the list rendering for meetingNote.decisions and
meetingNote.followUpActions to use a stable unique key per item, such as
combining the item value with its index or another identifier, so the rendered
lists in MeetingNoteCard remain deterministic even with repeated entries.
- Around line 46-58: The participant avatar divs in MeetingNoteCard are using
aria-label on the default generic role, which may not expose the name to
assistive tech. Update the participant element rendering in MeetingNoteCard to
use an accessible pattern such as giving each avatar a non-generic role like img
or adding visually hidden text with the participant.name, and keep the unique
participant.id/key and existing participant fields intact while making the
accessible name reliable.
🪄 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: ASSERTIVE

Plan: Pro Plus

Run ID: 2a3b7765-3367-46d4-9227-134cef9e2b78

📥 Commits

Reviewing files that changed from the base of the PR and between c1c472c and 5e9fa5e.

📒 Files selected for processing (7)
  • src/entities/meeting-note/model/meeting-note.types.ts
  • src/entities/meeting-note/ui/MeetingNoteCard.tsx
  • src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx
  • src/shared/lib/fonts.ts
  • src/views/meeting-notes/ui/MeetingNotesPage.tsx
  • src/views/meeting-notes/ui/NewMeetingNotePage.tsx
  • src/views/project-management/ui/ProjectManagementPage.tsx
💤 Files with no reviewable changes (1)
  • src/entities/meeting-note/model/meeting-note.types.ts

Comment thread src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx Outdated
@JiWoongE JiWoongE changed the title [Feat] 팀 프로젝트 워크스페이스 회의록 페이지 및 작성 기능 구현 [Feat] 회의록 페이지 및 작성 기능 구현 Jul 8, 2026

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx (2)

372-398: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

참석자 드롭다운에 ARIA 상태 속성 부재

토글 버튼(Line 375-398)에 aria-haspopup/aria-expanded가 없고, 패널의 멤버 행(Line 400-436)에도 role="option"/aria-selected가 없습니다. 마우스·탭 키로는 동작하지만, 스크린리더 사용자는 드롭다운이 열려 있는지, 어떤 항목이 선택되어 있는지 인지하기 어렵습니다.

♿ 제안 수정
                 <button
                   type="button"
                   onClick={() => setIsParticipantListOpen((current) => !current)}
+                  aria-haspopup="listbox"
+                  aria-expanded={isParticipantListOpen}
                   className={`${fieldClassName} flex min-h-[58px] items-center justify-between gap-3 text-left`}
                 >
                           <button
                             key={member.userId}
                             type="button"
+                            role="option"
+                            aria-selected={isSelected}
                             onClick={() => toggleParticipant(member.userId)}
                             className="flex w-full items-center justify-between rounded-[14px] px-3 py-3 text-left transition hover:bg-brand-soft"
                           >

Also applies to: 400-436

🤖 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/manage-meeting-notes/ui/MeetingNoteForm.tsx` around lines 372 -
398, The participant dropdown is missing ARIA state and selection semantics,
making its open/selected state unclear to screen readers. Update the toggle
button in MeetingNoteForm to expose dropdown behavior with aria-haspopup and
aria-expanded tied to isParticipantListOpen, and add appropriate listbox/option
semantics to the participant panel and member rows, including role="option" and
aria-selected based on whether each member is in selectedParticipants. Use the
existing participantFieldRef, isParticipantListOpen, and selectedParticipants
logic to keep the accessibility state in sync.

116-150: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

제출 시 날짜 재검증 추가 필요
handleSubmit에서 제목만 확인하고 dateParts는 다시 검증하지 않습니다. handleDatePartBlur만 invalid 조합을 되돌리기 때문에, 유효하지 않은 날짜 입력 상태에서 바로 제출하면 화면에 보이던 값과 다른 이전 meetingDate가 저장될 수 있습니다. 제출 시 getIsoDateFromParts(...)로 날짜를 다시 확인하고, 유효한 값만 저장하도록 막아주세요.

🤖 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/manage-meeting-notes/ui/MeetingNoteForm.tsx` around lines 116 -
150, The submit handler in MeetingNoteForm.handleSubmit only validates the
title, so invalid date parts can still be saved as an older meetingDate value.
Re-check the current date parts at submit time using getIsoDateFromParts (the
same logic used by handleDatePartBlur), and block addMeetingNote unless the
assembled date is valid. Keep the existing participant mapping and router.push
flow unchanged, but ensure only a validated ISO date is written into the meeting
note payload.
🤖 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.

Outside diff comments:
In `@src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx`:
- Around line 372-398: The participant dropdown is missing ARIA state and
selection semantics, making its open/selected state unclear to screen readers.
Update the toggle button in MeetingNoteForm to expose dropdown behavior with
aria-haspopup and aria-expanded tied to isParticipantListOpen, and add
appropriate listbox/option semantics to the participant panel and member rows,
including role="option" and aria-selected based on whether each member is in
selectedParticipants. Use the existing participantFieldRef,
isParticipantListOpen, and selectedParticipants logic to keep the accessibility
state in sync.
- Around line 116-150: The submit handler in MeetingNoteForm.handleSubmit only
validates the title, so invalid date parts can still be saved as an older
meetingDate value. Re-check the current date parts at submit time using
getIsoDateFromParts (the same logic used by handleDatePartBlur), and block
addMeetingNote unless the assembled date is valid. Keep the existing participant
mapping and router.push flow unchanged, but ensure only a validated ISO date is
written into the meeting note payload.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: bfe9cbdd-6ecc-4a54-afcd-854960bdea9c

📥 Commits

Reviewing files that changed from the base of the PR and between 5e9fa5e and 9ba8c8e.

📒 Files selected for processing (1)
  • src/features/manage-meeting-notes/ui/MeetingNoteForm.tsx

@seongjinss555 seongjinss555 left a comment

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.

고생하셨습니다~

@JiWoongE
JiWoongE merged commit 376f240 into develop Jul 9, 2026
1 check passed
@JiWoongE
JiWoongE deleted the Feat/#21/meeting-notes-pages branch July 9, 2026 02:00
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.

[Feat] 팀프로젝트 회의록 페이지 및 작성 페이지 구현

2 participants