Skip to content

[FEAT] 파비콘·SEO 메타데이터 설정 및 아키텍처 문서 동기화 - #216

Merged
kimminna merged 4 commits into
developfrom
feat/web/215-favicon-seo-metadata
Jul 15, 2026
Merged

[FEAT] 파비콘·SEO 메타데이터 설정 및 아키텍처 문서 동기화#216
kimminna merged 4 commits into
developfrom
feat/web/215-favicon-seo-metadata

Conversation

@kimminna

@kimminna kimminna commented Jul 15, 2026

Copy link
Copy Markdown
Member

ISSUE 🔗

close #215



What is this PR? 🔍

파비콘과 로케일별 SEO 메타데이터를 설정하고, 실제 구현과 어긋나 있던 아키텍처·컨벤션·디자인 토큰 문서를 최신 상태로 동기화했습니다.

배경

  • 기존 구조: 루트 레이아웃이 정적 metadata 객체(title/description)만 export했고, 파비콘·Open Graph·hreflang 등 SEO 관련 메타데이터는 설정돼 있지 않았습니다.
  • 발생 문제: 로케일이 en/ko로 분리돼 있음에도 메타데이터는 고정 문자열이라 언어별 검색 노출·소셜 공유 미리보기가 구분되지 않았고, docs/ 아키텍처 문서 일부가 실제 코드와 어긋나 있어(API 클라이언트 표기, 존재하지 않는 디렉터리 등) 온보딩 시 혼란을 줄 수 있었습니다.
  • 해결 방향: 정적 metadata를 next-intl 기반 generateMetadata로 전환해 로케일별 텍스트·hreflang·OG locale을 반영하고, 문서는 실제 소스 파일(orval.config.ts, theme.css 등)을 대조해 정정했습니다.

파비콘·SEO 메타데이터 (apps/timo-web)

  • 변경 요약: public/favicon.png를 파비콘으로 연결하고, 루트 레이아웃의 메타데이터를 로케일 인식 generateMetadata로 전환해 SEO 필드를 추가했습니다.
  • 이유: 브라우저 탭에 파비콘이 없었고, title/description이 로케일과 무관하게 고정돼 있어 언어별 검색·소셜 미리보기 최적화가 불가능했습니다.
  • 구현 방식: messages/{en,ko}.jsonMetadata 네임스페이스(title, description)를 추가하고, layout.tsxgenerateMetadata({ params })에서 hasLocale로 유효성 검증 후 getTranslations({ locale, namespace: "Metadata" })로 텍스트를 가져옵니다. metadataBasehttps://timo.kr로 고정하고, title.template(%s | timo), openGraph(locale을 en_US/ko_KR로 매핑, alternateLocale), twitter(summary 카드), robots(index/follow 명시), formatDetection.telephone: false를 설정했습니다. OG 이미지 에셋이 아직 없어 summary_large_image 대신 summary 카드를 사용했습니다.
  • 경계 · 제약: OG/Twitter 카드용 이미지(og-image.png)는 이번 범위에 포함하지 않았습니다. 추후 디자인 에셋이 준비되면 openGraph.images/twitter.images를 추가하는 후속 작업이 필요합니다.

문서 동기화 (docs/)

  • 변경 요약: docs/architecture/*, docs/conventions/commit.md, docs/design/tokens.md를 실제 구현 기준으로 정정했습니다.
  • 이유: API 클라이언트가 문서에는 swagger-typescript-api로 적혀 있었지만 실제로는 Orval(orval.config.ts)이었고, 모노레포 트리에 존재하지 않는 lib/가 남아 있었으며, 컴포넌트 계층 예시가 실존하지 않는 auth 도메인을 참조하는 등 여러 항목이 실제 코드와 어긋나 있었습니다. packages/tailwind-config/theme.css에는 Shadow·Z-Index 토큰이, tokens/radius.css에는 Radius 토큰이 정의돼 있었지만 tokens.md에는 반영되지 않았습니다.
  • 구현 방식: 각 문서 항목을 실제 소스(orval.config.ts, .husky/pre-commit, lint-staged.config.js, generate-icons.mjs, 실제 apps/timo-web 디렉터리 구조, packages/tailwind-config/theme.css·tokens/radius.css)와 대조해 표·트리·예시를 갱신했습니다. components.md의 예시 도메인은 _components/_containers/_hooks/_queries/_types/_utils가 모두 존재하는 focus 도메인으로 교체했습니다.
  • 경계 · 제약: 코드 변경은 포함하지 않았으며, 문서 텍스트만 수정했습니다.

코드 리뷰 반영 — 경로 종속 메타데이터 분리 (apps/timo-web)

  • 변경 요약: 루트 레이아웃에서 경로 종속 필드(alternates.canonical/languages, openGraph.url)를 제거하고, 인증이 필요한 (main) 라우트 그룹은 robots noindex로 비공개 처리했으며, 공개 페이지인 로그인·약관에는 페이지별 메타데이터를 추가했습니다.
  • 이유: 코드 리뷰에서 app/[locale]/layout.tsx[locale] 세그먼트까지의 params만 받아 하위 경로를 알 수 없는데도, alternates.canonical/languagesopenGraph.url을 항상 locale 루트 경로로 고정해 /en/today, /en/focus, /en/settings/account 등 모든 하위 라우트가 홈 URL을 canonical/OG URL로 상속한다는 점이 지적됐습니다.
  • 구현 방식: 경로 종속 필드는 루트 레이아웃에서 제거하고, locale에만 의존하는 openGraph 필드(type, siteName, title, description, locale, alternateLocale)만 유지했습니다. (main) 라우트 그룹(home/today/focus/settings/statistics)은 모두 AuthGuardProvider로 감싸진 로그인 필수·개인화 화면이라, 그룹 레이아웃 한 곳에 정적 metadata: { robots: { index: false, follow: false } }를 추가해 그룹 전체를 검색 노출에서 제외했습니다. 반대로 login, policy는 비로그인 상태에서도 접근 가능한 공개 페이지이므로 각각 generateMetadata를 추가해 로케일별 title/description과 페이지 고유 alternates.canonical(/{locale}/login, /{locale}/policy)을 설정했습니다. policytype 쿼리 파라미터(SERVICE/PRIVACY)에 따라 기존 Settings.nav.policy/privacy 문자열을 재사용해 제목을 다르게 표시하도록 했습니다(새 번역 키를 만들지 않음).
  • 경계 · 제약: onboarding, oauth/callback도 인증이 필요하거나 콘텐츠가 없는 페이지지만, 이번에 합의한 범위(공개 페이지 일부 + 인증 그룹 전체 noindex)에는 포함하지 않았습니다. 필요 시 후속 작업으로 처리합니다.



To Reviewers

hasLocale + notFound() 가드가 이제 루트 레이아웃(컴포넌트/generateMetadata 각각), 로그인·약관 페이지의 generateMetadata까지 총 4곳에 반복됩니다. Next.js가 generateMetadata와 컴포넌트를 별도 시점에 호출하고, 각 페이지의 generateMetadata가 부모 레이아웃의 setRequestLocale 실행 여부를 보장받지 못해 각자 명시적으로 { locale, namespace }를 넘기도록 했는데, 반복이 늘어난 만큼 공용 헬퍼로 추출할지 판단 부탁드립니다.
SEO 메타데이터의 도메인은 https://timo.kr로 지정했습니다. 실제 배포 도메인이 다르면 알려주세요.
문서 커밋은 코드 변경과 무관한 정정이라 별도 커밋으로 분리했습니다.



Screenshot 📷



Test Checklist ✔

  • pnpm check-types:web 통과
  • pnpm lint:web 통과
  • 실제 배포 환경에서 소셜 공유 미리보기(OG) 렌더링 확인 — 후속 작업
  • /en/today, /en/settings 등 하위 라우트에서 canonical 태그가 더 이상 홈 URL을 가리키지 않는지 확인 — 후속 작업

kimminna added 2 commits July 15, 2026 13:29
- public/favicon.png를 next.js metadata.icons에 연결해 브라우저 탭 파비콘을 표시했습니다.
- 정적 title/description을 generateMetadata로 전환해 로케일(en/ko)별 텍스트가 반영되도록 했습니다.
- metadataBase, Open Graph, Twitter Card, hreflang(alternates), robots, formatDetection 등 SEO 메타데이터를 추가했습니다.
- messages/en.json, messages/ko.json에 Metadata 네임스페이스를 추가했습니다.
- API 클라이언트가 실제로는 swagger-typescript-api가 아닌 Orval 기반임을 반영해 stack.md를 수정했습니다.
- Git Hooks를 Husky 단독이 아닌 Husky + lint-staged 조합으로 정정했습니다.
- SVG 아이콘 생성 방식을 SVG sprite에서 실제 사용 중인 SVGR로 수정했습니다.
- structure.md의 모노레포 트리에서 존재하지 않는 lib/를 제거하고 api/, containers/ 등 실제 디렉터리를 반영했습니다.
- components.md의 예시 도메인을 존재하지 않는 auth에서 실제 존재하는 focus 도메인으로 교체했습니다.
- commit.md의 config 스코프에 누락된 tailwind-config 패키지를 추가했습니다.
- tokens.md에 실제 CSS에는 있지만 문서화되지 않았던 Radius, Shadow, Z-Index, overlay 색상 토큰을 추가했습니다.
@vercel

vercel Bot commented Jul 15, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
timo Ready Ready Preview, Comment Jul 15, 2026 5:06am

Request Review

@github-actions
github-actions Bot requested review from ehye1 and yumin-kim2 July 15, 2026 04:33
@github-actions github-actions Bot added ⏰ Timo-web Timo 웹 서비스 ✨ Feature 새로운 기능(기능성) 구현 ♦️ 민아 민아상 labels Jul 15, 2026
@coderabbitai

coderabbitai Bot commented Jul 15, 2026

Copy link
Copy Markdown

Review Change Stack

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Linked Issues check ❓ Inconclusive 문서와 메타데이터 작업은 충족된 것으로 보이지만, public/favicon.png는 PNG 필터로 제외되어 연결 여부를 검증할 수 없습니다. apps/timo-web/public/favicon.png를 포함해 metadata.icons 연결 여부를 확인할 수 있도록 PNG 파일을 리뷰 범위에 포함해 주세요.
✅ Passed checks (4 passed)
Check name Status Explanation
Out of Scope Changes check ✅ Passed 변경된 코드와 문서는 모두 #215의 목표인 SEO 설정과 아키텍처 문서 동기화 범위 안에 있습니다.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Title check ✅ Passed 파비콘과 SEO 메타데이터 설정, 문서 동기화라는 실제 변경 범위를 잘 요약합니다.
Description check ✅ Passed 파비콘, 로케일별 메타데이터, 문서 정정 등 변경 내용과 목적이 일관되게 설명됩니다.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/web/215-favicon-seo-metadata

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.

@github-actions

github-actions Bot commented Jul 15, 2026

Copy link
Copy Markdown

Timo Performance Report

Bundle Size — timo-web
라우트 크기 First Load JS
/[locale]/home 209.86 kB 🔴 415.72 kB
/[locale]/today 193.98 kB 🔴 399.83 kB
/[locale]/focus 160.05 kB 🔴 365.91 kB
/[locale]/settings 166.59 kB 🔴 372.45 kB
/[locale]/statistics 232.92 kB 🔴 438.78 kB
/[locale]/[...rest] 0 B 🟡 205.86 kB
/[locale]/login 212.94 kB 🔴 418.79 kB
/[locale]/oauth/callback 119.65 kB 🟡 325.50 kB
/[locale]/onboarding 232.90 kB 🔴 438.75 kB
/[locale] 118.96 kB 🟡 324.82 kB
/[locale]/policy 125.09 kB 🟡 330.94 kB

공유 번들: 205.86 kB
🟢 < 200kB  |  🟡 < 350kB  |  🔴 ≥ 350kB (First Load JS · gzip)

Lighthouse — timo-web
URL Perf A11y LCP CLS TBT
/en/home 🔴 62 🟢 95 🔴 15.7s 🟢 0.000 🟡 485ms
/en/today 🟡 71 🟢 95 🔴 15.5s 🟢 0.000 🟡 234ms
/en/focus 🔴 62 🟢 95 🔴 15.3s 🟢 0.000 🟡 516ms
/en/statistics 🔴 62 🟢 95 🔴 15.2s 🟢 0.000 🟡 488ms

Perf ≥ 70 / A11y ≥ 85 목표
LCP 🟢 < 2.5s 🟡 < 4s 🔴 ≥ 4s  |  CLS 🟢 < 0.1 🟡 < 0.25 🔴 ≥ 0.25  |  TBT 🟢 < 200ms 🟡 < 600ms 🔴 ≥ 600ms

Image Optimization — timo-web
파일 크기 포맷 상태
favicon.png 27.84 kB PNG ⚠️ 🟢
images/google-calendar.png 36.20 kB PNG ⚠️ 🟢
images/google-logo.png 26.79 kB PNG ⚠️ 🟢

총 3개 · 90.84 kB  |  🟢 < 200KB  |  🟡 < 500KB  |  🔴 ≥ 500KB
⚠️ 3개 파일 WebP/AVIF 변환 권장

측정 커밋: 3ebe0da

@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

🤖 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 `@apps/timo-web/app/`[locale]/layout.tsx:
- Around line 61-79: Remove the path-dependent canonical, languages, and
openGraph.url fields from the root layout’s metadata configuration. Keep
locale-independent Open Graph fields and move these route-specific SEO values to
each top-level or individual page metadata definition, where the current
pathname is available, so child routes do not inherit the homepage URL.
🪄 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: fe8d26cc-f259-4658-82c9-5e9140bbb5c0

📥 Commits

Reviewing files that changed from the base of the PR and between 3cca2a5 and ebfa649.

⛔ Files ignored due to path filters (1)
  • apps/timo-web/public/favicon.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • apps/timo-web/app/[locale]/layout.tsx
  • apps/timo-web/messages/en.json
  • apps/timo-web/messages/ko.json
  • docs/architecture/components.md
  • docs/architecture/stack.md
  • docs/architecture/structure.md
  • docs/conventions/commit.md
  • docs/design/tokens.md

Comment thread apps/timo-web/app/[locale]/layout.tsx Outdated

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

확인했습니다. 좋으네요

kimminna added 2 commits July 15, 2026 14:03
- app/[locale]/layout.tsx는 locale 세그먼트까지의 params만 받아 하위 경로를 알 수 없는데도, alternates.canonical/languages와 openGraph.url을 항상 locale 루트 경로로 고정해 모든 하위 라우트가 홈 URL을 상속했습니다.
- 경로 종속 필드를 제거하고, locale에만 의존하는 openGraph 필드(type, siteName, title, description, locale, alternateLocale)는 유지했습니다.
- (main) 라우트 그룹은 AuthGuardProvider로 로그인이 필요한 개인화 화면이라 robots.index/follow를 false로 설정해 검색 엔진 노출에서 제외했습니다.
- 로그인 페이지에 generateMetadata를 추가해 로케일별 title/description과 경로 고유 canonical(/{locale}/login)을 설정했습니다. messages의 Login 네임스페이스에 title 키를 새로 추가했습니다.
- 약관 페이지에 generateMetadata를 추가해 type 쿼리 파라미터(SERVICE/PRIVACY)에 따라 기존 Settings.nav.policy/privacy 문자열을 재사용한 제목과 경로 고유 canonical(/{locale}/policy)을 설정했습니다.
@kimminna
kimminna merged commit fef3dcb into develop Jul 15, 2026
13 checks passed
@kimminna
kimminna deleted the feat/web/215-favicon-seo-metadata branch July 15, 2026 05:10
@kimminna kimminna mentioned this pull request Jul 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

✨ Feature 새로운 기능(기능성) 구현 ⏰ Timo-web Timo 웹 서비스 ♦️ 민아 민아상

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] 파비콘·SEO 메타데이터 설정 및 아키텍처 문서 동기화

2 participants