Develop fe#1560
Conversation
LocationInfo에 min-width: 0과 overflow: hidden을 추가하여 모바일에서 긴 위치 텍스트가 지도 링크를 밀어내는 현상 해결
- .gitignore: .claude/commands/ 팀 공유 예외 처리 - CLAUDE.md: skill routing 규칙 추가 - .claude/commands/cross-review.md: /cross-review 슬래시 커맨드 - scripts/cross-review.sh: claude/codex 자동 감지, --writer 플래그로 반대 에이전트가 리뷰
- .claude/commands/jira-story.md: /jira-story 슬래시 커맨드 (대화형) - scripts/jira-story.sh: Jira REST API 호출, 스프린트 지정 지원, .env 자동 로드
카카오톡/페이스북 등 크롤러 요청 시 클럽 정보를 API에서 fetch하여 OG 태그가 포함된 HTML을 반환하는 Vercel Edge Middleware 추가 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
ObjectId만 매칭하던 regex를 @clubname 형식도 포함하도록 수정 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Vercel Edge 5초 실행 제한 대응, API 지연 시 SPA로 fallback Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-856 [feature] 클럽 상세 페이지 OG 태그 Edge Middleware 적용
JIRA_HOST, PROJECT_KEY 하드코딩 제거 및 .env / shell 환경 변수에서 로드하도록 변경. 누락 시 명확한 오류 메시지와 함께 종료하는 유효성 검사 추가.
- 네트워크 행 방지를 위해 --connect-timeout 5, --max-time 30 추가 - base64 수동 인코딩 제거, curl -u 옵션으로 이식성 보장
…ttps://github.com/Moadong/moadong into feature/#1545-cross-review-and-jira-story-MOA-854
…jira-story-MOA-854 [feature] 클로드 커맨드 추가 (cross-review, jira)
정규식 끝에 $ 앵커가 없어 /club/:clubId 하위 경로에도 OG HTML이 반환되던 버그 수정 (MOA-859)
percent-encoded 경로(@%EB...)를 디코딩하지 않아 API 호출 실패 및 og:url에 인코딩된 URL이 노출되던 문제 수정 (MOA-859)
잘못된 percent-encoding 입력 시 URIError가 try 블록 밖에서 발생하여 Edge Function이 500으로 터지는 문제 방지 잘못된 인코딩이어도 원본 문자열로 API 시도 후 fallback
…bug-MOA-860 [fix] OG 미들웨어 정규식 끝 앵커 누락 수정
…l-scroll-webview-MOA-830 fix(webview): 웹뷰 메인페이지 좌우 스크롤 방지 및 렌더링 개선
isPending 상태일 때 null 대신 shimmer 애니메이션 스켈레톤을 모바일/데스크탑/랩탑 전 해상도에서 표시
- useBanner staleTime/gcTime 24h → 1h (긴급 배너 교체 대응) - usePromotion staleTime 5min → 1min (refetchInterval보다 짧게 조정)
…-strategy-MOA-864 [refactor] React Query 캐싱 전략 개선
SkeletonOverlay를 BannerWrapper 위에 절대 위치로 얹어 API 응답 후 이미지 로딩 중에도 스켈레톤이 유지되도록 처리
…OA-862 [feature] 배너 로딩 중 shimmer 스켈레톤 UI 추가
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Warning Rate limit exceeded
You’ve run out of usage credits. Purchase more in the billing tab. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the 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 have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (17)
Warning
|
| Layer / File(s) | Summary |
|---|---|
Claude/Jira 명령 문서 및 .gitignore 설정 frontend/.claude/commands/cross-review.md, frontend/.claude/commands/jira-story.md, frontend/.gitignore |
크로스 에이전트 리뷰와 Jira 스토리 생성 CLI 명령 사용법을 정의하고, .claude/* 무시 규칙을 세분화하여 팀 공유 명령(/commands/)은 추적 허용. |
Skill routing 문서 및 캐싱 전략 가이드 frontend/CLAUDE.md, frontend/docs/claude/api.md, frontend/docs/features/hooks/cacheStrategy.md |
요청 유형별 Skill 도구/엔드포인트 라우팅 규칙 및 데이터 성격별 React Query staleTime/gcTime 설정 기준 문서화. |
크로스 에이전트 코드 리뷰 스크립트 frontend/scripts/cross-review.sh |
작성 도구 선택(--writer claude|codex)에 따라 반대 CLI를 실행하고 git diff를 통합 프롬프트로 리뷰 자동화. |
Jira 스토리 생성 스크립트 frontend/scripts/jira-story.sh |
대화형 입력(제목/설명/인수조건)으로 ADF 형식 description을 구성하여 Jira REST API 호출. |
OG Tag Generation for Social Sharing
| Layer / File(s) | Summary |
|---|---|
OG HTML 생성 Edge Middleware 구현 frontend/middleware.ts |
크롤러 User-Agent 감지, /club 및 /clubDetail 라우트 매칭, 클럽 API 호출(3초 타임아웃), OG/Twitter 메타 태그 포함 HTML 반환. |
OG 태그 및 Edge Middleware 문서 frontend/docs/claude/features.md |
크롤러 감지 기반 OG 생성 흐름, OG 커버 라우트, middleware 수정 방법, 현재 구조의 한계점 및 위험 시나리오 문서화. |
Banner Skeleton UI & Cache Optimization
| Layer / File(s) | Summary |
|---|---|
배너 스켈레톤 스타일 및 애니메이션 frontend/src/pages/MainPage/components/Banner/Banner.styles.ts |
shimmer 키프레임 정의, SkeletonBannerWrapper(전체 배너 스켈레톤), SkeletonOverlay(이미지 로드 대기) styled 컴포넌트. |
배너 컴포넌트 스켈레톤 UI 통합 frontend/src/pages/MainPage/components/Banner/Banner.tsx |
isPending 기반 스켈레톤 래퍼 렌더링, isImageLoaded 상태 추가, 첫 번째 이미지만 onLoad 핸들러 부착하여 Swiper loop 모드 중복 방지. |
배너 스켈레톤 UI 문서 frontend/docs/features/main/banner.md |
배너 스켈레톤 2단계 렌더링 조건(isPending, !isImageLoaded), 첫 이미지 onLoad 규칙, 반응형 사양 정리. |
React Query 캐시 설정 및 전역 스타일 조정 frontend/src/hooks/Queries/useBanner.ts, frontend/src/hooks/Queries/usePromotion.ts, frontend/src/pages/ClubDetailPage/components/ClubProfileCard/ClubProfileCard.styles.ts, frontend/src/styles/WebviewGlobal.styles.ts |
배너 staleTime(24h→1h), 프로모션 staleTime(5min→1min), LocationInfo overflow 처리, 전역 스타일에 가로 오버플로우 차단 및 WebKit 폰트 최적화. |
Estimated code review effort
🎯 3 (Moderate) | ⏱️ ~25 minutes
Possibly related PRs
- Moadong/moadong#1546: 크로스 리뷰 및 Jira 스토리 도구 스크립트와 Claude 명령 문서의 동일 기능 추가
- Moadong/moadong#1543: ClubProfileCard.styles.ts의 LocationInfo
min-width: 0,overflow: hidden스타일 조정이 동일한 오버플로우 수정 - Moadong/moadong#1557: Banner 컴포넌트의 shimmer 스켈레톤 UI(
SkeletonBannerWrapper,SkeletonOverlay) 구현이 동일
Suggested labels
🚁AI
Suggested reviewers
- lepitaaar
- suhyun113
- oesnuj
🚥 Pre-merge checks | ✅ 3 | ❌ 2
❌ Failed checks (2 warnings)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Title check | PR 제목 'Develop fe'는 매우 모호하며, 실제 변경사항의 핵심을 전혀 반영하지 못함. 배너 스켈레톤 UI, OG 미들웨어, 문서화, 클라이언트 명령어 등 다양한 기능이 포함되어 있으나 제목에서 알 수 없음. | 제목을 더 구체적으로 변경 (예: 'Add banner skeleton UI, OG middleware, and CLI commands' 또는 기능별 주요 변경사항을 명시) | |
| Docstring Coverage | Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. | Write docstrings for the functions missing them to satisfy the coverage threshold. |
✅ Passed checks (3 passed)
| Check name | Status | Explanation |
|---|---|---|
| Description Check | ✅ Passed | Check skipped - CodeRabbit’s high-level summary is enabled. |
| 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
develop-fe
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.
Comment @coderabbitai help to get the list of available commands and usage tips.
✅ UI 변경사항 없음
전체 57개 스토리 · 22개 컴포넌트 |
- CLUB_MAP_CLICKED 이벤트명 추가 - 지도 카드 및 프로필 카드 내 지도 버튼 두 진입점 트래킹 적용
- jira-task.sh: gh issue create로 GitHub 이슈 생성 → Actions가 Jira 하위 작업 + 브랜치 자동 생성 - /jira-story 스킬에 GitHub 이슈 연동 플로우 추가
- SearchBox: 하드코딩 문자열 → USER_EVENT.SEARCH_BOX_CLICKED 교체 - ClubCard: mixpanel.track() 직접 호출 → useMixpanelTrack 훅으로 통일 - ClubDetailTopBar, PromotionDetailTopBar: 뒤로가기 버튼 BACK_BUTTON_CLICKED 추가 - useHeaderNavigation: handleMenuOpen 추가 (MOBILE_MENU_BUTTON_CLICKED) - Header: 모바일 메뉴 열 때 handleMenuOpen 호출
- /check-tracking: 정의된 USER_EVENT와 실제 trackEvent 호출 현황 비교 - 트래킹 중인 이벤트 / 누락 의심 인터랙션 / 미사용 이벤트 표 형식 출력
- /prd: 기능 인터뷰 → 하위 작업 분해 → Jira 스토리 + GitHub 이슈 일괄 생성 - jira-story.sh + jira-task.sh를 연계해 스토리-하위작업 전체 플로우 자동화
…w-MOA-842 [fix] 동아리방 상세 위치가 긴 경우 지도 버튼이 가려지는 현상 수정
There was a problem hiding this comment.
Actionable comments posted: 8
🧹 Nitpick comments (2)
frontend/src/pages/MainPage/components/Banner/Banner.styles.ts (1)
16-16: ⚡ Quick win
prefers-reduced-motion대응을 추가해 주세요.현재 shimmer가 무한 애니메이션이라 모션 민감 사용자에게 부담이 될 수 있습니다.
prefers-reduced-motion: reduce에서 애니메이션을 비활성화하는 게 안전합니다.♻️ 제안 코드
export const SkeletonBannerWrapper = styled.div` width: 100%; @@ animation: ${shimmer} 1.5s infinite linear; + `@media` (prefers-reduced-motion: reduce) { + animation: none; + } ${media.mobile} { @@ export const SkeletonOverlay = styled.div` position: absolute; @@ animation: ${shimmer} 1.5s infinite linear; + `@media` (prefers-reduced-motion: reduce) { + animation: none; + } `;Also applies to: 30-30
🤖 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 `@frontend/src/pages/MainPage/components/Banner/Banner.styles.ts` at line 16, The shimmer animation is always running and should be disabled for users who prefer reduced motion; update the Banner.styles.ts where the animation is applied (the line using animation: ${shimmer} 1.5s infinite linear;) to wrap or override that rule with a prefers-reduced-motion: reduce media query that disables the animation (e.g., remove animation or set animation: none) for that query; apply the same change to the other occurrence referenced (the second animation line around the 30-30 area) so both shimmer usages respect reduced-motion preferences.frontend/docs/features/hooks/cacheStrategy.md (1)
19-19: ⚡ Quick win
refetchInterval규칙 설명을 명확히 할 수 있습니다.현재 설명이 약간 복잡합니다. 더 직관적으로 표현하면 이해하기 쉬울 것 같습니다.
✨ 명확성 개선 제안
-- `refetchInterval`을 함께 쓸 때는 `staleTime < refetchInterval`이어야 한다. 그렇지 않으면 폴링 후 refetch된 데이터가 여전히 stale로 판단되지 않아 `staleTime`이 의미를 잃는다. +- `refetchInterval`을 함께 쓸 때는 `staleTime < refetchInterval`이어야 폴링으로 가져온 새 데이터를 즉시 사용할 수 있다. `staleTime`이 더 길면 새 데이터도 여전히 fresh로 간주되어 리렌더링이 발생하지 않는다.🤖 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 `@frontend/docs/features/hooks/cacheStrategy.md` at line 19, 현재 문장이 다소 복잡하니 `refetchInterval`과 `staleTime` 규칙을 더 직관적으로 바꿔서 설명하세요; 예를 들어 "`refetchInterval`을 사용하는 경우 `staleTime`은 `refetchInterval`보다 작아야 합니다. 그렇지 않으면 폴링으로 다시 불러온 데이터가 여전히 `stale`로 간주되어 `staleTime`의 의미가 없어집니다."처럼 `refetchInterval`과 `staleTime`을 명시적으로 비교하고 결과를 간단히 설명하도록 `cacheStrategy.md`의 해당 문장을 교체하세요.
🤖 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 `@frontend/docs/claude/api.md`:
- Around line 12-32: The "React Query 캐싱 전략 (staleTime / gcTime)" table is
duplicated between frontend/docs/claude/api.md and cacheStrategy.md; remove the
full table and rules block from api.md (the section titled "React Query 캐싱 전략
(staleTime / gcTime)") and replace it with a short paragraph that notes the
existence of the caching strategy and links to cacheStrategy.md (as suggested in
the review), leaving the detailed table and rules only in cacheStrategy.md;
ensure the link path in api.md points to the canonical document (e.g.,
../features/hooks/cacheStrategy.md) and keep the section heading in api.md
minimal to preserve navigation.
- Around line 16-19: Remove the duplicated markdown table header and its
separator row so only one header remains; specifically delete the second
occurrence of the header row "데이터 성격 | staleTime | gcTime | 사용 예" and the
following separator row of dashes, leaving a single header + separator before
the table body to fix the rendering.
In `@frontend/docs/claude/features.md`:
- Around line 57-65: The example regex assigned to match is missing the end
anchor, causing overmatching; update the pattern used in the example for the
match variable so it exactly matches the middleware implementation by adding the
terminal anchor (i.e., ensure the regex for match is
^\/club(?:Detail)?\/([a-f0-9]{24}|@[^/]+)$), and confirm the config object
(export const config = { matcher: [...] }) examples remain consistent with the
actual routes shown (e.g., '/club/:path*' and '/clubDetail/:path*') so the docs
mirror the implemented middleware behavior.
- Around line 36-42: The fenced code block that begins with "크롤러 요청 →
middleware.ts (User-Agent 감지)" is missing a language tag and triggers
markdownlint MD040; update that block to include a language specifier (e.g.,
```text or ```plain) so the markdown linter recognizes it as a code fence and
suppresses the warning, leaving the block contents unchanged.
In `@frontend/middleware.ts`:
- Around line 64-69: The decoded clubId from safeDecode is being interpolated
directly into the fetch URL in the middleware (see safeDecode, API_BASE and the
fetch call), which can produce invalid or unintended paths; re-encode the
segment before building the URL (e.g., use encodeURIComponent on clubId) so the
request path is safe and consistent with other callers (see calendarOAuth.ts
pattern), and ensure the fetch uses the re-encoded value when calling
`${API_BASE}/api/club/...`.
In `@frontend/scripts/cross-review.sh`:
- Around line 11-15: The --writer branch currently reads "$2" blindly and
silently accepts invalid or missing values; update the case handling around the
--writer pattern to first assert an argument exists before using "$2"
(preventing set -u failures), validate that the value assigned to WRITER is one
of the allowed tokens (e.g., list of permitted writers) and on invalid or
missing value print a clear error and exit non‑zero, and change the default case
so unknown options are treated as errors instead of being ignored; refer to the
--writer pattern, the WRITER variable assignment and the case/esac block (and
STAGED handling) to locate where to add the presence check, allowed-values
check, error messages and proper shifts.
In `@frontend/scripts/jira-story.sh`:
- Around line 80-93: The script currently hardcodes the Jira sprint custom field
as .fields.customfield_10020 which breaks on other Jira instances; make the
sprint custom field name configurable (e.g., via an env var SPRINT_CUSTOM_FIELD
or JIRA_SPRINT_FIELD) and pass it into jq (similar to how SPRINT_ID is passed)
so the code conditionally sets .fields[$sprintField] = $sprintId instead of
.fields.customfield_10020; update the jq invocation and variable name references
around the existing SPRINT_ID handling to use the new SPRINT_CUSTOM_FIELD,
defaulting to null when unset.
In `@frontend/src/pages/MainPage/components/Banner/Banner.tsx`:
- Around line 133-139: The first banner's image currently only flips the loading
flag on success via onLoad, so if the first image errors the isImageLoaded flag
stays false and the skeleton/overlay never clears; add an onError handler to the
same <img> used in the Banner component that, when index === 0, calls
setIsImageLoaded(true) (or otherwise clears the loading state) so the
skeleton/overlay is removed on failure; look for the img element and the
setIsImageLoaded/isImageLoaded state in Banner.tsx and add the conditional
onError mirroring the onLoad behavior.
---
Nitpick comments:
In `@frontend/docs/features/hooks/cacheStrategy.md`:
- Line 19: 현재 문장이 다소 복잡하니 `refetchInterval`과 `staleTime` 규칙을 더 직관적으로 바꿔서 설명하세요;
예를 들어 "`refetchInterval`을 사용하는 경우 `staleTime`은 `refetchInterval`보다 작아야 합니다. 그렇지
않으면 폴링으로 다시 불러온 데이터가 여전히 `stale`로 간주되어 `staleTime`의 의미가 없어집니다."처럼
`refetchInterval`과 `staleTime`을 명시적으로 비교하고 결과를 간단히 설명하도록 `cacheStrategy.md`의 해당
문장을 교체하세요.
In `@frontend/src/pages/MainPage/components/Banner/Banner.styles.ts`:
- Line 16: The shimmer animation is always running and should be disabled for
users who prefer reduced motion; update the Banner.styles.ts where the animation
is applied (the line using animation: ${shimmer} 1.5s infinite linear;) to wrap
or override that rule with a prefers-reduced-motion: reduce media query that
disables the animation (e.g., remove animation or set animation: none) for that
query; apply the same change to the other occurrence referenced (the second
animation line around the 30-30 area) so both shimmer usages respect
reduced-motion preferences.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 52d6ae61-356d-480c-92ea-2f0adfa6141f
📒 Files selected for processing (17)
frontend/.claude/commands/cross-review.mdfrontend/.claude/commands/jira-story.mdfrontend/.gitignorefrontend/CLAUDE.mdfrontend/docs/claude/api.mdfrontend/docs/claude/features.mdfrontend/docs/features/hooks/cacheStrategy.mdfrontend/docs/features/main/banner.mdfrontend/middleware.tsfrontend/scripts/cross-review.shfrontend/scripts/jira-story.shfrontend/src/hooks/Queries/useBanner.tsfrontend/src/hooks/Queries/usePromotion.tsfrontend/src/pages/ClubDetailPage/components/ClubProfileCard/ClubProfileCard.styles.tsfrontend/src/pages/MainPage/components/Banner/Banner.styles.tsfrontend/src/pages/MainPage/components/Banner/Banner.tsxfrontend/src/styles/WebviewGlobal.styles.ts
…t-improve-MOA-878 Jira 스토리 생성 스크립트 개선 (Windows 호환성, 자동 스프린트/담당자/에픽 지정)
- Header toggleMenu: handleMenuOpen/Close 호출을 setState 외부로 이동 (React Strict Mode에서 updater 중복 실행 시 이벤트 중복 발생 방지) - SEARCH_BOX_CLICKED → SEARCH_EXCUTED 이벤트명 수정
…nt-tracking-MOA-868 [feature] 네이버 맵 클릭 이벤트 트래킹 및 누락 이벤트 전반 추가, /jira-task 대화형 커맨드 신규 생성
🚀 릴리즈 PR
📦 버전 정보
💾 BE/💻 FE🚨 MAJOR/➕ MINOR/🔧 PATCHvX.Y.Z📖 버전 라벨 선택 가이드 (Semantic Versioning)
🚨 MAJORv1.0.0→v2.0.0➕ MINORv1.0.0→v1.1.0🔧 PATCHv1.0.0→v1.0.1📋 포함된 변경사항
Summary by CodeRabbit
릴리스 노트
New Features
Improvements
Documentation