Conversation
Walkthrough
Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Possibly related PRs
Suggested labels
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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 |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@src/app/`(main)/teampsylog/head/[uuid]/page.tsx:
- Around line 17-24: The code is using a client-exposed env var and no request
timeout; update the axios call in page.tsx (where generateMetadata/server-side
logic runs) to use the server-only environment variable process.env.API_BASE_URL
instead of process.env.NEXT_PUBLIC_API_BASE_URL, and add a timeout to the
request (e.g., via the axios config timeout option or by creating an axios
instance with a default timeout) so the GET to /teamficial-log/requester with
params { requesterUuid: uuid } fails fast on slow responses.
- Around line 37-43: The OG image URL in the metadata images array is currently
a relative path ('/og/Teamficial_metatag_Image.jpg') which social crawlers don't
resolve; update the images entry in the metadata object in page.tsx to use an
absolute URL (e.g., https://your-domain.com/og/Teamficial_metatag_Image.jpg) or
alternatively set metadataBase in your root layout (export const metadata with
metadataBase: new URL('https://your-domain.com')) so the existing relative path
resolves correctly; modify either the images URL in page.tsx or add metadataBase
in layout.tsx accordingly.
In `@src/components/common/Footer.tsx`:
- Around line 32-59: In the Footer component update the two Image elements for
the social links (the Instagram and Thread images) to be treated as decorative
by screen readers: set their alt attribute to an empty string (alt="") and also
add aria-hidden="true" or role="presentation" to the Image elements so the
screen reader ignores them and avoids duplicate announcements with the anchor's
aria-label.
🧹 Nitpick comments (2)
src/app/(main)/teampsylog/head/[uuid]/page.tsx (2)
5-5: Next.js 서버 컴포넌트에서는fetch사용을 권장합니다.
generateMetadata는 서버에서 실행되므로, Next.js의 내장fetch를 사용하면 자동 캐싱 및 재검증 기능을 활용할 수 있습니다. 프로젝트 전반에서 axios를 일관되게 사용 중이라면 유지해도 무방합니다.
31-46: Twitter 카드 메타데이터 추가를 고려해 보세요.OG 태그는 잘 설정되었습니다. Twitter에서의 노출을 개선하려면
✨ Twitter 메타데이터 추가 예시
openGraph: { title: `${userName}님의 팀피셜록을 작성해볼까요?`, description: `소프트스킬 팀빌딩 서비스, 팀피셜`, images: [ { url: '/og/Teamficial_metatag_Image.jpg', width: 1200, height: 630, }, ], }, + twitter: { + card: 'summary_large_image', + title: `${userName}님의 팀피셜록을 작성해볼까요?`, + description: `소프트스킬 팀빌딩 서비스, 팀피셜`, + images: ['/og/Teamficial_metatag_Image.jpg'], + }, };
| const res = await axios.get( | ||
| `${process.env.NEXT_PUBLIC_API_BASE_URL}/teamficial-log/requester`, | ||
| { | ||
| params: { | ||
| requesterUuid: uuid, | ||
| }, | ||
| }, | ||
| ); |
There was a problem hiding this comment.
환경 변수 및 요청 타임아웃 설정을 확인하세요.
NEXT_PUBLIC_접두사가 붙은 환경 변수는 클라이언트에 노출됩니다.generateMetadata는 서버에서만 실행되므로 서버 전용 환경 변수(예:API_BASE_URL) 사용을 권장합니다.- 타임아웃이 설정되지 않아 API 응답 지연 시 페이지 렌더링이 블로킹될 수 있습니다.
🔧 타임아웃 추가 예시
const res = await axios.get(
`${process.env.NEXT_PUBLIC_API_BASE_URL}/teamficial-log/requester`,
{
params: {
requesterUuid: uuid,
},
+ timeout: 5000,
},
);🤖 Prompt for AI Agents
In `@src/app/`(main)/teampsylog/head/[uuid]/page.tsx around lines 17 - 24, The
code is using a client-exposed env var and no request timeout; update the axios
call in page.tsx (where generateMetadata/server-side logic runs) to use the
server-only environment variable process.env.API_BASE_URL instead of
process.env.NEXT_PUBLIC_API_BASE_URL, and add a timeout to the request (e.g.,
via the axios config timeout option or by creating an axios instance with a
default timeout) so the GET to /teamficial-log/requester with params {
requesterUuid: uuid } fails fast on slow responses.
| images: [ | ||
| { | ||
| url: '/og/Teamficial_metatag_Image.jpg', | ||
| width: 1200, | ||
| height: 630, | ||
| }, | ||
| ], |
There was a problem hiding this comment.
OG 이미지 URL은 절대 경로로 지정해야 합니다.
소셜 미디어 크롤러(Facebook, Twitter 등)는 상대 경로를 인식하지 못합니다. metadataBase를 설정하거나 전체 URL을 직접 명시해야 합니다.
🐛 수정 방안
방안 1: 절대 URL 직접 사용
images: [
{
- url: '/og/Teamficial_metatag_Image.jpg',
+ url: `${process.env.NEXT_PUBLIC_BASE_URL}/og/Teamficial_metatag_Image.jpg`,
width: 1200,
height: 630,
},
],방안 2: metadataBase 설정 (layout.tsx에서)
// layout.tsx
export const metadata: Metadata = {
metadataBase: new URL('https://your-domain.com'),
};🤖 Prompt for AI Agents
In `@src/app/`(main)/teampsylog/head/[uuid]/page.tsx around lines 37 - 43, The OG
image URL in the metadata images array is currently a relative path
('/og/Teamficial_metatag_Image.jpg') which social crawlers don't resolve; update
the images entry in the metadata object in page.tsx to use an absolute URL
(e.g., https://your-domain.com/og/Teamficial_metatag_Image.jpg) or alternatively
set metadataBase in your root layout (export const metadata with metadataBase:
new URL('https://your-domain.com')) so the existing relative path resolves
correctly; modify either the images URL in page.tsx or add metadataBase in
layout.tsx accordingly.
| <a | ||
| href="https://www.instagram.com/teamficial.official/" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| aria-label="인스타그램" | ||
| > | ||
| <Image | ||
| src="/icons/mobile-instagram.svg" | ||
| alt="instagram" | ||
| width={24} | ||
| height={24} | ||
| className="justify-end" | ||
| /> | ||
| </a> | ||
| <a | ||
| href="https://www.threads.com/@teamficial.official" | ||
| target="_blank" | ||
| rel="noopener noreferrer" | ||
| aria-label="쓰레드" | ||
| > | ||
| <Image | ||
| src="/icons/mobile-thread.svg" | ||
| alt="thread" | ||
| width={24} | ||
| height={24} | ||
| className="justify-end" | ||
| /> | ||
| </a> |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
fd "Footer.tsx" --type fRepository: TEAMFICIAL/teamficial-fe
Length of output: 162
🌐 Web query:
Next.js Image component aria-hidden attribute support
💡 Result:
Yes. next/image forwards “other properties” to the underlying <img> element (it only excludes srcSet and decoding), so aria-hidden="true" is supported and will end up on the rendered <img>. [1]
For decorative images, accessibility guidance is to use an empty alt (alt="") so screen readers ignore it; you can add aria-hidden="true" as an extra safeguard, but alt is still required by next/image. [1][2][3]
import Image from "next/image";
<Image
src="/decorative.png"
width={200}
height={200}
alt=""
aria-hidden="true"
/>Sources: [1] Next.js <Image> API (“Other Props” forwarding) • [2] W3C WAI decorative images (use alt="") • [3] MDN aria-hidden behavior
🌐 Web query:
decorative images accessibility best practices alt empty string aria-hidden
💡 Result:
Decorative images: what to do (and when)
1) For a purely decorative <img> (no meaning, no function): use a null alt
<img src="..." alt="">- This marks the image as decorative so screen readers ignore it.
- Do not omit
alt(missingaltcan cause some AT to announce the filename). - Make sure it’s exactly empty—no spaces like
alt=" "(some AT may still announce it).
Sources: WebAIM on decorative images andalt=""[1], W3C Images tutorial (decorative) [2], W3C tips re: no space in empty alt [3].
2) Prefer CSS for purely visual styling when possible
- If it’s only for decoration/layout (borders, flourishes, background textures), use a CSS background image instead of
<img>to keep it out of the semantic content.
Sources: WebAIM [1], HTML Standard guidance [4].
3) role="presentation" / role="none": usually unnecessary for <img>
- An
<img>withalt=""is already treated as decorative in accessibility mappings; addingrole="presentation"/noneis typically redundant.
Source: W3C ACT rule describing “marked as decorative” viaalt=""or presentational roles [5].
4) aria-hidden="true": use sparingly, and don’t use it to “fix” missing alt
aria-hidden="true"removes content from the accessibility tree, which is a different intent than “this image is decorative.”- Avoid putting
aria-hidden="true"on anything focusable/interactive (it can create confusing keyboard/AT behavior).
Source: W3C ACT notes on programmatically hidden content and focusable elements [6].
Practical rule of thumb
- Decorative
<img>→alt=""(best default). - Decorative pure styling → CSS background (best if feasible).
- Only use
aria-hidden="true"when you intentionally want something not exposed to AT at all (and ensure it’s not focusable/interactive).
References
- WebAIM – Alternative Text (Decorative images use
alt="") [1] - W3C WAI Images Tutorial – Decorative images (
alt="", don’t omitalt) [2] - W3C WAI Images Tips – empty alt must not contain spaces [3]
- HTML Standard – decorative/supplemental images and empty
alt, CSS for site-wide decoration [4] - W3C ACT – “marked as decorative” includes
imgwithalt=""or role none/presentation [5] - W3C ACT – cautions about
aria-hiddenand focusable elements [6]
🏁 Script executed:
cat -n src/components/common/Footer.tsx | head -100Repository: TEAMFICIAL/teamficial-fe
Length of output: 4501
이미지 alt 속성 수정 필요 - 중복 낭독 방지
앵커에 aria-label이 있으므로 이미지는 장식 요소로 처리해야 합니다. alt=""만 사용하면 스크린리더가 무시하므로 중복 낭독을 피할 수 있습니다.
♿ 제안 수정
<Image
src="/icons/mobile-instagram.svg"
- alt="instagram"
+ alt=""
width={24}
height={24}
className="justify-end"
/> <Image
src="/icons/mobile-thread.svg"
- alt="thread"
+ alt=""
width={24}
height={24}
className="justify-end"
/> <Image src="/icons/mail.svg"
- alt="mail"
+ alt=""
width={24} height={24} /> <Image src="/icons/instagram.svg"
- alt="instagram"
+ alt=""
width={24} height={24} /> <Image src="/icons/thread.svg"
- alt="thread"
+ alt=""
width={24} height={24} />🤖 Prompt for AI Agents
In `@src/components/common/Footer.tsx` around lines 32 - 59, In the Footer
component update the two Image elements for the social links (the Instagram and
Thread images) to be treated as decorative by screen readers: set their alt
attribute to an empty string (alt="") and also add aria-hidden="true" or
role="presentation" to the Image elements so the screen reader ignores them and
avoids duplicate announcements with the anchor's aria-label.
✅ PR 유형
어떤 변경 사항이 있었나요?
📌 관련 이슈번호
✅ Key Changes
📸 스크린샷 or 실행영상
🎸 기타 사항 or 추가 코멘트
Summary by CodeRabbit
릴리스 노트
✏️ Tip: You can customize this high-level summary in your review settings.