Skip to content

feat: 방장 일정 등록 폼 추가 및 대시보드 연동 기능 구현 - #78

Merged
yoohyun-1203 merged 3 commits into
devfrom
feature/32-schedule-ui
Jun 14, 2026
Merged

feat: 방장 일정 등록 폼 추가 및 대시보드 연동 기능 구현#78
yoohyun-1203 merged 3 commits into
devfrom
feature/32-schedule-ui

Conversation

@yoohyun-1203

@yoohyun-1203 yoohyun-1203 commented Jun 14, 2026

Copy link
Copy Markdown
Collaborator

🚀 작업 내용 (What)

  • 방장(Host)이 자신의 모임에 일정을 제출할 수 없던 문제를 해결했습니다.
  • 유저가 일정을 제출하면 해당 모임이 개인 대시보드에 즉시 동기화되도록 개선했습니다.

📣 핵심 변경 이유 (Why)

  • DB 스키마 추가: ScheduleParticipant 모델에 userId 필드를 추가하여 일정 제출 시 유저 계정과 연동되도록 수정. (prisma db push 필요)
  • 대시보드 쿼리 개선: /dashboard에서 내가 생성한 모임(creatorId)뿐만 아니라, 내가 참여자로 등록된 모임도 함께 불러와 달력과 목록에 표시하도록 쿼리 수정.
  • 방장 UI(UX) 개선: 방장이 모임 현황판(Host View)에 접속했을 때, 본인의 일정을 아직 제출하지 않았다면 상단에 '가능한 시간을 알려주세요' 폼이 나타나도록 로직 추가.
  • 맞춤형 문구 적용: 방장이 폼을 볼 때는 "이런 모임에 초대받았어요!" 대신 "방장님도 일정을 등록해 주세요!" 등 맞춤형 텍스트(Copy)가 노출되도록 개선.

📸 스크린샷 (Visuals, 선택)

⚠️ 체크리스트 (Checklist)

  • 브랜치 컨벤션(feature/00-name)을 지켰나요?
  • 커밋 컨벤션(feat:, fix: 등)을 지켰나요?
  • 작업 전에 관련 이슈를 생성하고 연결했나요?
  • 내 코드가 팀의 기존 코드를 망가뜨리지 않았는지 확인했나요?

🔗 관련 이슈 (Issue)

Close #

@vercel

vercel Bot commented Jun 14, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
moim-app Ready Ready Preview, Comment Jun 14, 2026 12:06pm

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@yoohyun-1203, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 41 minutes and 9 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 12512d64-17c1-44b3-847b-37362ee6ca3e

📥 Commits

Reviewing files that changed from the base of the PR and between eddcf03 and b09605f.

📒 Files selected for processing (7)
  • fetch_prs.js
  • prisma/schema.prisma
  • src/app/api/schedules/[id]/availability/route.ts
  • src/app/schedule/[id]/page.tsx
  • src/lib/__tests__/api-handler.test.ts
  • src/lib/calendar/adapters/__tests__/manual.test.ts
  • src/lib/schedules/store.ts

Walkthrough

ScheduleParticipant Prisma 모델에 선택적 userId 필드를 추가한다. 가용성 제출 API에서 Supabase 세션을 통해 userId를 추출·저장하고, 스토어 인터페이스와 매핑 함수를 확장한다. 대시보드는 생성자 외 참여자 포함 일정도 조회하며, ScheduleRoomClient에서 forceParticipant prop이 제거된다.

Changes

참여자 userId 연동

Layer / File(s) Summary
스키마 및 스토어 타입·로직 확장
prisma/schema.prisma, src/lib/schedules/store.ts
ScheduleParticipant 모델에 userId String? 필드를 추가하고, AddParticipantAvailabilityInput·ScheduleParticipant 인터페이스에 userId를 선언한다. addParticipantAvailability에서 upsert 시 userId를 유지 또는 갱신하며, toScheduleParticipantuserId를 반환 객체에 포함한다.
가용성 API: Supabase 세션 userId 주입
src/app/api/schedules/[id]/availability/route.ts
createClient import를 추가하고, POST 핸들러에서 세션을 조회해 session?.user?.iduserId로 포함한 객체를 addParticipantAvailability에 전달한다.
ScheduleRoomClient: forceParticipant 제거 및 isHostView 재정의
src/app/schedule/[id]/ScheduleRoomClient.tsx
HostParticipant 타입에 userId?: string | null을 추가한다. forceParticipant prop과 관련 디폴트를 제거하고, isHostViewhostToken 존재 또는 creatorId === currentUser.id 조건으로 단순화한다.
대시보드 쿼리 확장
src/app/dashboard/page.tsx
prisma.schedule.findMany where 절을 OR 조건으로 변경해 사용자가 생성자이거나 participants에 포함된 일정을 모두 조회한다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • Siul49/moim#73: ?participate=1 쿼리 파라미터로 forceParticipant prop을 도입한 PR로, 본 PR이 해당 prop을 제거하기 때문에 직접적인 코드 역전 관계다.
  • Siul49/moim#71: 대시보드 recentSchedules 쿼리를 creatorId 단일 필터로 변경한 PR로, 본 PR이 OR 조건으로 재확장하는 동일 쿼리를 다룬다.

Suggested labels

feature

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목이 'feat:' 접두사로 시작하며, 방장 일정 등록 폼 추가와 대시보드 연동이라는 핵심 변경 사항을 명확하게 설명하고 있습니다.
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.
Description check ✅ Passed PR 설명이 템플릿 구조를 충실히 따르고 변경사항, 변경 이유, 체크리스트를 모두 포함했으나 '관련 이슈' 번호가 기입되지 않았습니다.

✏️ 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/32-schedule-ui

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: 3

Caution

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

⚠️ Outside diff range comments (1)
src/lib/schedules/store.ts (1)

155-182: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

인증 참여자를 여전히 이름으로만 매칭하면 중복 제출과 오버라이트가 발생합니다.

이유: 이제 userId를 저장하면서도 기존 레코드 조회는 scheduleId + name만 사용합니다. 그래서 같은 사용자가 표시 이름을 바꾸면 새 행이 생기고, 반대로 서로 다른 사용자가 같은 이름을 쓰면 기존 제출을 덮어쓸 수 있습니다. 이번 PR의 userId 연동 목적 자체가 여기서 깨집니다.

수정:

핵심 수정 예시
       const normName = normalizeParticipantName(input.name);
       const existing = await tx.scheduleParticipant.findFirst({
-        where: { scheduleId, name: normName },
+        where: input.userId
+          ? { scheduleId, userId: input.userId }
+          : { scheduleId, name: normName },
       });

       if (existing) {
         return tx.scheduleParticipant.update({
           where: { id: existing.id },
           data: {
+            name: normName,
             available: JSON.stringify(
               normalizeAvailability(schedule, input.available),
             ),
             submittedAt: new Date(),
             userId: input.userId ?? existing.userId,
           },
         });
       }
🤖 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/lib/schedules/store.ts` around lines 155 - 182, The findFirst query in
the participant lookup is only matching on scheduleId and the normalized name,
ignoring the userId even though it's now being persisted. This causes issues
where the same authenticated user changing their display name creates duplicate
records, and different users with identical names can overwrite each other's
submissions. Modify the where clause in the findFirst call to conditionally
include userId in the matching criteria when the input has a userId value, so
that authenticated participants are matched by (scheduleId, normalizedName,
userId) and unauthenticated ones by (scheduleId, normalizedName) only. This
ensures proper deduplication at the user level when userId is available.
🤖 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 `@prisma/schema.prisma`:
- Around line 70-72: The ScheduleParticipant model in the Prisma schema is
missing an index on the userId field, which causes performance degradation when
the dashboard queries schedules using participants.some.userId. Add a new index
entry for userId in the @@index array to enable efficient lookups, allowing the
database to avoid full table scans as the ScheduleParticipant table grows. The
existing scheduleId index should remain alongside the new userId index.

In `@src/app/api/schedules/`[id]/availability/route.ts:
- Around line 20-25: The code is using getSession() to retrieve the userId for
database operations, but this method only trusts client cookies without
cryptographic verification, creating a security vulnerability where clients can
inject arbitrary userIds into the participants table. Replace the getSession()
call with getUser() which validates the JWT cryptographically with the Auth
server, ensuring the userId passed to addParticipantAvailability() is properly
authenticated and cannot be spoofed.

In `@src/app/schedule/`[id]/ScheduleRoomClient.tsx:
- Around line 284-289: The isHostView logic in the useMemo function (lines
284-289) immediately returns true when currentUser.id matches
schedule.creatorId, which prevents the host/creator from accessing the
submission form that only renders when isHostView is false (lines 478-709). To
fix this, you need to either: (1) modify the isHostView condition to check if
the creator has already submitted their availability before switching to host
view, OR (2) ensure the submission form is also rendered within the HostView
component so creators can submit their availability. Choose one approach and
implement it consistently - if you modify the isHostView logic, verify the
submission form is accessible to creators; if you add the form to HostView,
ensure it's not duplicated elsewhere.

---

Outside diff comments:
In `@src/lib/schedules/store.ts`:
- Around line 155-182: The findFirst query in the participant lookup is only
matching on scheduleId and the normalized name, ignoring the userId even though
it's now being persisted. This causes issues where the same authenticated user
changing their display name creates duplicate records, and different users with
identical names can overwrite each other's submissions. Modify the where clause
in the findFirst call to conditionally include userId in the matching criteria
when the input has a userId value, so that authenticated participants are
matched by (scheduleId, normalizedName, userId) and unauthenticated ones by
(scheduleId, normalizedName) only. This ensures proper deduplication at the user
level when userId is available.
🪄 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: 3cd84caf-d86f-486c-a2bd-d94d14ac30ea

📥 Commits

Reviewing files that changed from the base of the PR and between 648ce26 and eddcf03.

📒 Files selected for processing (5)
  • prisma/schema.prisma
  • src/app/api/schedules/[id]/availability/route.ts
  • src/app/dashboard/page.tsx
  • src/app/schedule/[id]/ScheduleRoomClient.tsx
  • src/lib/schedules/store.ts

Comment thread prisma/schema.prisma
Comment thread src/app/api/schedules/[id]/availability/route.ts Outdated
Comment on lines 284 to +289
const isHostView = useMemo(() => {
if (!schedule || !("participants" in schedule)) return false;
if (hostToken) return true;
// 호스트가 "일정 등록하기"로 진입한 경우(?participate=1)에는
// 생성자여도 결과 화면이 아닌 참여(가능 시간 입력) 폼을 보여준다.
if (forceParticipant) return false;
if (currentUser && schedule.creatorId === currentUser.id) return true;
return false;
}, [schedule, hostToken, currentUser, forceParticipant]);
}, [schedule, hostToken, currentUser]);

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

creatorId만으로 즉시 호스트 뷰로 보내면 방장 제출 경로가 사라집니다.

이유: 현재는 currentUser.id === schedule.creatorId면 바로 호스트 뷰로 전환되는데, 같은 파일 Line 478-709의 제출 폼은 !isHostView일 때만 렌더링됩니다. 그런데 HostView 쪽에는 방장 자신의 가능 시간을 보내는 경로가 없어서, 이번 PR의 핵심 목표인 “방장도 일정 제출”이 여전히 막힙니다.

수정: 최소한 “내가 이미 제출했는가”를 확인한 뒤에만 호스트 뷰로 넘기거나, 의도대로라면 HostView 상단에 동일한 제출 폼을 함께 렌더링해야 합니다.

핵심 수정 예시
+  const hasOwnSubmission = useMemo(() => {
+    if (!schedule || !("participants" in schedule) || !currentUser) return false;
+    return schedule.participants.some(
+      (participant) => participant.userId === currentUser.id,
+    );
+  }, [schedule, currentUser]);
+
   const isHostView = useMemo(() => {
     if (!schedule || !("participants" in schedule)) return false;
     if (hostToken) return true;
-    if (currentUser && schedule.creatorId === currentUser.id) return true;
+    if (
+      currentUser &&
+      schedule.creatorId === currentUser.id &&
+      hasOwnSubmission
+    ) {
+      return true;
+    }
     return false;
-  }, [schedule, hostToken, currentUser]);
+  }, [schedule, hostToken, currentUser, hasOwnSubmission]);
🤖 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/app/schedule/`[id]/ScheduleRoomClient.tsx around lines 284 - 289, The
isHostView logic in the useMemo function (lines 284-289) immediately returns
true when currentUser.id matches schedule.creatorId, which prevents the
host/creator from accessing the submission form that only renders when
isHostView is false (lines 478-709). To fix this, you need to either: (1) modify
the isHostView condition to check if the creator has already submitted their
availability before switching to host view, OR (2) ensure the submission form is
also rendered within the HostView component so creators can submit their
availability. Choose one approach and implement it consistently - if you modify
the isHostView logic, verify the submission form is accessible to creators; if
you add the form to HostView, ensure it's not duplicated elsewhere.

@yoohyun-1203
yoohyun-1203 merged commit a1c527a into dev Jun 14, 2026
5 checks passed
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