Skip to content

fix: address second pass QA issues#20

Merged
seoJing merged 2 commits into
mainfrom
qa-second-pass
Jun 6, 2026
Merged

fix: address second pass QA issues#20
seoJing merged 2 commits into
mainfrom
qa-second-pass

Conversation

@seoJing

@seoJing seoJing commented Jun 6, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix my-page toggle copy/style, AI feed detail visibility, and owner application approval/reject role handling
  • Limit map bottom card deck to viewport markers and add bookmark active-state/favorites invalidation
  • Expand AI feed → post form prefill across request/offer steps and add recent-view local cache fallback
  • Distinguish feed vs spot chat contexts and gate owner/supporter actions by role

Verification

  • pnpm lint (pass; existing warnings only)
  • pnpm test (36 files / 160 tests passed)
  • pnpm build (pass)
  • git diff --check (pass)
  • Notjing final gate (pass)

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • 최근 본 피드가 로컬에 저장되어 조회 이력이 유지됩니다.
    • 포스트/오퍼 생성 시 이전 입력 내용이 자동으로 보존됩니다.
  • 개선 사항

    • 북마크 상태가 즉시 적용되며, 북마크 버튼의 시각적 피드백이 개선됩니다.
    • 최근 본 피드 기능이 서버 연결 실패 시에도 정상 작동합니다.
    • 채팅방에서 역할 정보 표시가 더 정확해집니다.

@vercel

vercel Bot commented Jun 6, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
frontend Ready Ready Preview, Comment Jun 6, 2026 9:05am

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Worried about impact? Review this PR in Change Stack to explore blast radius before you approve or request changes.

Review Change Stack

Warning

Review limit reached

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

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

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ 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: CHILL

Plan: Pro

Run ID: 061f8576-c850-45a3-befa-9d6f42369ad9

📥 Commits

Reviewing files that changed from the base of the PR and between 779513f and c989096.

📒 Files selected for processing (7)
  • src/features/chat/model/mock.ts
  • src/features/chat/model/room-role.ts
  • src/features/chat/ui/ChatCreationPanel.tsx
  • src/features/chat/ui/ChatDetail.tsx
  • src/features/feed/ui/FeedCard.tsx
  • src/features/feed/ui/detail/FeedRecentViewRecorder.tsx
  • src/features/my/model/recent-feed-views-store.ts
📝 Walkthrough

Walkthrough

이 PR은 최근 본 피드 추적, 스팟 채팅방 권한 시스템 리팩토링, 피드 UI 북마크 표시 개선, AI 시뮬레이션 기반 포스트 생성 폼 프리필 강화를 포괄하는 다기능 업데이트이다. 로컬 스토리지 캐시 기반 최근 조회 기록, 백엔드 파생 필드 기반 채팅방 권한 판정, 동적 북마크 상태 표시, sessionStorage 기반 폼 초기값 전달 메커니즘을 추가한다.

Changes

최근 본 피드 추적

레이어 / 파일(들) 요약
피드 조회 기록 컴포넌트 및 로컬 저장소
src/features/feed/ui/detail/FeedRecentViewRecorder.tsx, src/features/my/model/recent-feed-views-store.ts, src/app/(detail)/feed/[id]/page.tsx
피드 상세 페이지에 FeedRecentViewRecorder 컴포넌트를 추가해 방문 시 조회를 기록하고, localStorage에 최대 20개까지 최근 본 피드를 저장/조회/삭제/초기화하는 로컬 저장소를 구현한다.
내 페이지 최근 조회 API 통합
src/features/my/model/use-my.ts
최근 조회 목록 조회/삭제 훅을 로컬 캐시 우선 전략으로 업데이트하여 백엔드 실패 시에도 로컬 UX가 차단되지 않도록 개선한다.

스팟 채팅방 권한 및 라이프사이클

레이어 / 파일(들) 요약
채팅방 API 계약 확장
src/features/chat/api/chat-api.ts
BackendRoom 타입에 feedType/spotType, currentUserRole/participationRole, owner/isOwner, authorId/authorNickname 필드를 추가하고, toChatRoom에서 sourceKind 기반으로 spotType/status를 역매핑하며 participationRole을 currentUserRole에서 유도하도록 변경한다.
채팅방 모델 타입 및 목 데이터
src/features/chat/model/types.ts, src/features/chat/model/mock.ts
SpotChatRoom에 sourceKind 필드를 추가하고, 목 데이터 생성 시 spot.status 기반으로 sourceFeedId/sourceKind를 재정의하며 participationRole을 supportership 여부로 산출한다.
채팅방 생성 패널 권한 판정
src/features/chat/ui/ChatCreationPanel.tsx
사용자 피드 역할(participationRole 우선, 없으면 소유/작성자 여부)과 라이프사이클 소스(sourceKind 또는 status 기반)를 기반으로 reverse-offer 생성 가능 여부를 판정하도록 업데이트한다.
채팅 상세 UI 및 역할 표시
src/features/chat/ui/ChatDetail.tsx
라이프사이클 소스와 사용자 역할을 기반으로 오너 액션 관리 가능 여부, 역제안 생성 가능 여부, 대화 제목, 역할 정보 라벨을 새로 계산하여 UI 표시와 버튼 가시성을 제어한다.

피드 UI 및 북마크 표시 개선

레이어 / 파일(들) 요약
피드 카드 프로필 및 스크롤
src/features/feed/ui/FeedCard.tsx
작성자 프로필 객체를 우선 사용하도록 변경하고, 자동 스크롤 루프를 자식 항목 수 기반으로 조건부 실행하여 불필요한 렌더링을 제거한다.
북마크 상태 동적 표시
src/features/feed/ui/MapFeedCardPager.tsx, src/features/map/ui/MapFeedInfoCard.tsx, src/features/map/ui/MapFeedStackCard.tsx
카드와 맵 UI 컴포넌트에서 isBookmarked 상태에 따라 아이콘 채우기, 라벨, 버튼 스타일을 동적으로 렌더링한다.
지도 뷰포트 기반 피드 필터링
src/features/map/client/MapClient.tsx
카드 페이저에 표시할 피드를 visibleFeedItems에서 viewportFeedItems(지도 뷰포트에 포함된 마커의 아이템)으로 변경하여 더 정확한 지도 기반 필터링을 제공한다.

포스트 폼 프리필 및 AI 시뮬레이션

레이어 / 파일(들) 요약
피드 신청 처리 및 메시지 정제
src/features/feed/ui/detail/FeedParticipationActions.tsx, src/features/feed/ui/detail/FeedParticipationActions.test.tsx, src/features/feed/model/use-feed.ts
신청자 수락/거절 로직을 handleApplicationDecision으로 정리하고 역할 라벨 기반 메시지를 지정하며, AI 피드에 대해 offer/request 타입별로 포스트 생성 폼으로 라우팅한다. 또한 북마크 토글 후 "내 즐겨찾기" 캐시도 무효화한다.
폼 프리필 시스템 강화
src/features/post/model/use-post-form-prefill.ts, src/features/post/model/use-post-base-form.ts, src/features/post/client/OfferFormClient.tsx, src/features/post/client/RequestFormClient.tsx
URL query와 sessionStorage 저장 컨텍스트를 병합하는 향상된 prefill 시스템을 구현하고, Request/Offer 폼 클라이언트의 상태 동기화를 추가하며, 기본 폼 타입을 spotName/deadline 필드로 확장한다.

기타 UI 스타일

레이어 / 파일(들) 요약
토글 버튼 스타일
src/features/my/ui/my-page/MyFormControls.tsx
토글 버튼 체크 상태 시 배경/테두리를 accent 색상으로 변경하고 그림자 효과를 추가한다.
AI 피드 SpotPromotionProgress 숨김
src/app/(detail)/feed/[id]/page.tsx
OFFER/REQUEST 상세에서 AI 피드인 경우 SpotPromotionProgress 섹션을 조건부로 숨긴다.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • spot-platform/frontend#8: 스팟 채팅방 오너/액션 권한 판정 로직(특히 ChatDetail.tsx, ChatCreationPanel.tsx)을 리팩토링하여 reverse-offer 등의 액션 가능 여부를 백엔드 파생 필드 기반으로 결정하는 코드 레벨 연관성이 있다.
  • spot-platform/frontend#6: src/features/chat/api/chat-api.ts의 스팟/채팅방 매핑 로직(특히 toChatRoom, spot 관련 필드)을 수정하여 프론트엔드와 백엔드 계약을 정렬하는 코드 레벨 연관성이 있다.
  • spot-platform/frontend#18: src/features/chat/api/chat-api.ts의 스팟/채팅방 변환 로직(특히 toChatRoom의 설명/스팟 채팅방 메타)을 수정하는 코드 레벨 연관성이 있다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 5.71% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR 제목은 '특정 QA 이슈 해결'을 간략히 나타내지만, 다양한 기능 변경사항(최근 조회 캐시, 북마크 상태, AI 피드 처리, 채팅 권한 분기, 지도 뷰포트 필터링 등)을 모두 담지 못해 전체 변경 범위를 정확히 전달하지 못합니다.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch qa-second-pass

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

🧹 Nitpick comments (2)
src/features/chat/model/mock.ts (1)

522-537: 💤 Low value

isSupporterForSpot 호출을 위해 부분 객체를 인라인으로 구성하는 것은 중복과 복잡성을 유발합니다.

isSupporterForSpot 함수는 room.spot.type, room.spot.authorId, userId만 사용합니다. 전체 SpotChatRoom 객체를 인라인으로 재구성하는 대신 로직을 직접 인라인하거나 더 단순한 헬퍼를 사용하는 것이 좋습니다.

♻️ 제안된 간소화
-        participationRole: isSupporterForSpot({
-            id: `spot-room-${spot.id}`,
-            category: 'spot',
-            currentUserId: CHAT_CURRENT_USER_ID,
-            currentUserName: CHAT_CURRENT_USER_NAME,
-            title: spot.title,
-            subtitle: '',
-            description: spot.description,
-            metaLabel: '',
-            updatedAt: spot.updatedAt,
-            unreadCount: 0,
-            spot,
-            messages: [],
-        })
-            ? 'SUPPORTER'
-            : 'PARTNER',
+        participationRole:
+            (spot.type === 'OFFER'
+                ? spot.authorId === CHAT_CURRENT_USER_ID
+                : spot.authorId !== CHAT_CURRENT_USER_ID)
+                ? 'SUPPORTER'
+                : 'PARTNER',
🤖 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/chat/model/mock.ts` around lines 522 - 537, The code builds a
full SpotChatRoom-like object just to call isSupporterForSpot when that helper
only needs room.spot.type, room.spot.authorId, and a userId; replace the inline
object with a direct call using those minimal values (e.g., isSupporterForSpot({
type: spot.type, authorId: spot.authorId, userId: CHAT_CURRENT_USER_ID }) or
inline the boolean check using spot.type/spot.authorId and CHAT_CURRENT_USER_ID)
and then set participationRole based on that result to remove the duplicated
complex object construction.
src/features/chat/ui/ChatDetail.tsx (1)

600-621: ⚖️ Poor tradeoff

roomLifecycleSourceuserFeedRole 계산 로직이 ChatCreationPanel.tsx와 중복됩니다.

두 파일 모두 동일한 로직으로 roomLifecycleSourceuserFeedRole을 계산합니다. 향후 로직 변경 시 불일치가 발생할 수 있으므로, 공통 유틸리티 함수로 추출하는 것을 고려해 보세요.

🤖 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/chat/ui/ChatDetail.tsx` around lines 600 - 621, The
roomLifecycleSource and userFeedRole calculation is duplicated; extract the
logic into a shared utility (e.g., a new function like
computeRoomLifecycleAndRole or two helpers computeRoomLifecycleSource and
computeUserFeedRole) and replace the in-file computations in ChatDetail (the
roomLifecycleSource, userFeedRole, canManageOwnerActions, canCreateReverseOffer)
and the equivalent code in ChatCreationPanel.tsx to call those utilities; ensure
the helpers accept the room object (currentRoom) and any helper predicates used
(isOwnedSpotRoom, isSupporterForSpot) or import them, and keep the same return
values so canManageOwnerActions and canCreateReverseOffer continue to derive
from the returned lifecycle source and role.
🤖 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/feed/ui/detail/FeedRecentViewRecorder.tsx`:
- Around line 21-23: The useEffect currently depends on the whole item object
which can change reference on parent re-renders and cause duplicate recordings;
update the dependency array of the useEffect that calls recordRecentFeedView
(the effect containing recordRecentFeedView(item)) to depend only on item.id
(use [item.id]) so the effect runs only when the feed ID changes.

In `@src/features/feed/ui/FeedCard.tsx`:
- Around line 286-287: Rendering childArray twice when shouldLoop is true causes
duplicate React keys (ExploreSlotStrip children using slot.key); to fix, when
producing the second render wrap/map childArray and assign unique keys (e.g.,
prefix or suffix existing slot.key) or clone elements with React.cloneElement to
set key={`loop-${slot.key}`} so the second set is distinct while preserving
other props.

In `@src/features/my/model/recent-feed-views-store.ts`:
- Around line 44-64: The pagination mixes 0-based and 1-based logic; in
getRecentFeedViews decide on 1-based paging (recommended) by defaulting page to
1 (change page = params?.page ?? 1), compute zeroBasedPage with Math.max(0, page
- 1) instead of page > 0 ? page - 1 : page, keep start = zeroBasedPage * size
and slice as-is, and preserve meta.page as the original 1-based page so meta,
start, and hasNext are consistent (update references to page, zeroBasedPage,
start, and meta accordingly).

---

Nitpick comments:
In `@src/features/chat/model/mock.ts`:
- Around line 522-537: The code builds a full SpotChatRoom-like object just to
call isSupporterForSpot when that helper only needs room.spot.type,
room.spot.authorId, and a userId; replace the inline object with a direct call
using those minimal values (e.g., isSupporterForSpot({ type: spot.type,
authorId: spot.authorId, userId: CHAT_CURRENT_USER_ID }) or inline the boolean
check using spot.type/spot.authorId and CHAT_CURRENT_USER_ID) and then set
participationRole based on that result to remove the duplicated complex object
construction.

In `@src/features/chat/ui/ChatDetail.tsx`:
- Around line 600-621: The roomLifecycleSource and userFeedRole calculation is
duplicated; extract the logic into a shared utility (e.g., a new function like
computeRoomLifecycleAndRole or two helpers computeRoomLifecycleSource and
computeUserFeedRole) and replace the in-file computations in ChatDetail (the
roomLifecycleSource, userFeedRole, canManageOwnerActions, canCreateReverseOffer)
and the equivalent code in ChatCreationPanel.tsx to call those utilities; ensure
the helpers accept the room object (currentRoom) and any helper predicates used
(isOwnedSpotRoom, isSupporterForSpot) or import them, and keep the same return
values so canManageOwnerActions and canCreateReverseOffer continue to derive
from the returned lifecycle source and role.
🪄 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: 8d8edb0d-97fa-4e9a-a698-18e0012d81e8

📥 Commits

Reviewing files that changed from the base of the PR and between ebccdb7 and 779513f.

📒 Files selected for processing (22)
  • src/app/(detail)/feed/[id]/page.tsx
  • src/features/chat/api/chat-api.ts
  • src/features/chat/model/mock.ts
  • src/features/chat/model/types.ts
  • src/features/chat/ui/ChatCreationPanel.tsx
  • src/features/chat/ui/ChatDetail.tsx
  • src/features/feed/model/use-feed.ts
  • src/features/feed/ui/FeedCard.tsx
  • src/features/feed/ui/MapFeedCardPager.tsx
  • src/features/feed/ui/detail/FeedParticipationActions.test.tsx
  • src/features/feed/ui/detail/FeedParticipationActions.tsx
  • src/features/feed/ui/detail/FeedRecentViewRecorder.tsx
  • src/features/map/client/MapClient.tsx
  • src/features/map/ui/MapFeedInfoCard.tsx
  • src/features/map/ui/MapFeedStackCard.tsx
  • src/features/my/model/recent-feed-views-store.ts
  • src/features/my/model/use-my.ts
  • src/features/my/ui/my-page/MyFormControls.tsx
  • src/features/post/client/OfferFormClient.tsx
  • src/features/post/client/RequestFormClient.tsx
  • src/features/post/model/use-post-base-form.ts
  • src/features/post/model/use-post-form-prefill.ts

Comment thread src/features/feed/ui/detail/FeedRecentViewRecorder.tsx Outdated
Comment thread src/features/feed/ui/FeedCard.tsx Outdated
Comment thread src/features/my/model/recent-feed-views-store.ts
@seoJing seoJing merged commit 56a9f03 into main Jun 6, 2026
5 checks passed
@seoJing seoJing deleted the qa-second-pass branch June 6, 2026 09:34
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