feat: GCP Startup 심사용 공개 사이트 보강 - #122
Conversation
- 공개 제품 페이지와 랜딩 신뢰 정보 정의 - GitHub 검증 및 자동 심사 대응 기준 정리
- 공개 사실과 랜딩·제품 페이지 보강 작업을 TDD 단위로 구성 - 메타데이터·크롤링·로그인 초기 HTML 검증 절차를 명시
- 출시 상태와 회사 기본 정보를 단일 데이터 원천으로 구성 - 공동창업자 실명과 GitHub 검증 정보를 정의
- 출시 및 무료 이용 배지 대신 실제 화면과 사용 흐름으로 제품을 증명 - 회사 정보와 구조화 데이터에서 심사 대응형 상태 문구를 제거
- 공개 사실에서 제품 상태 배지와 회사 상태 행을 제거 - 검토용 상태 문구가 재도입되지 않도록 계약을 조정
- 제품 출시 상태와 공개 회사 정보를 랜딩에 추가 - 공동창업자 역할과 GitHub 상호 검증 링크를 통일 - 공개 제품 소개 페이지 진입 링크를 추가
- 실제 사용 흐름과 스크린샷 순서를 정적 데이터로 구성 - 모든 화면에 현재 운영 중인 실제 제품 맥락을 명시
- 실제 운영 화면 6개로 전체 여행 계획 흐름을 구성 - 로그인 없이 읽히는 정적 제품 페이지와 실제 로그인 CTA를 추가
- 랜딩과 제품 페이지 canonical 및 소셜 메타데이터 구성 - 회사와 제품의 검증된 JSON-LD를 서버 HTML에 추가
- 가격·무료·평점·성과 지표의 명시적 JSON 속성을 차단 - operatingSystem 부분문자열 오탐 없이 속성 경계를 검사
- robots에서 공개 페이지 허용과 앱 경로 제외 규칙을 구성 - 검토 가능한 공개 페이지를 sitemap에 등록
- Suspense fallback에서도 브랜드와 Google 로그인 문구를 노출 - hydration 전 버튼은 비활성 상태로 명확히 표시
- 공개 페이지를 세션·STOMP·Maps 없는 경량 셸로 분리 - 공개 약관과 분석을 클라이언트 세션 조회에서 격리 - 제품 CTA와 금지 문구 검증 범위를 정정
- full provider stack을 SSR 동적 client entry로 격리 - 익명 분석과 세션 분석의 import graph 분리 - 정책 페이지의 기존 query/retry UX 복원
- 조직 GitHub 링크를 공개 UI와 구조화 데이터에서 제거 - 공동창업자별 GitHub·LinkedIn 버튼과 sameAs 정보를 연결
- 팀 카드 소개를 서울시립대학교 컴퓨터과학부로 교체
- 공동창업자 역할을 Co-founder로 통일 - GitHub 버튼에서 프로필 닉네임 제거
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
📝 WalkthroughWalkthrough공개 사이트용 단일 데이터 원천, 회사·공동창업자 랜딩 정보, SEO 메타데이터와 JSON-LD, robots/sitemap 경로, 로그인 fallback, 경로별 프로바이더 및 익명 분석 추적이 추가·변경되었다. 관련 설계 및 구현 계획 문서와 테스트도 포함된다. Changes공개 사이트 컴플라이언스
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4✅ Passed checks (4 passed)
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: 4
🧹 Nitpick comments (2)
src/providers/root-providers.test.tsx (1)
44-58: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win이전 설계 초안에서 남은 데드 목(mock)들이 실제 구현과 불일치함.
세 위치 모두 최종 구현이 채택하지 않은(children 기반
ConsentGatedAnalyticsAPI로 대체된) 이전 설계의 흔적으로 보입니다. 테스트 통과에는 영향이 없지만, 존재하지 않는 추상화(AppChromeShell)나 사용되지 않는 prop(anonymous)/모듈(AnalyticsRouteTracker)을 실제처럼 보이게 해 향후 리팩터링 시 혼란을 줄 수 있습니다.
src/providers/root-providers.test.tsx#L70-L84: 실제로 임포트되지 않는@/providers/app-chrome-shellmock 제거.src/providers/root-providers.test.tsx#L44-L58: 절대 실행되지 않는anonymousprop/fallback 분기를 제거하고children만 받는 실제 시그니처에 맞게 mock 단순화.src/components/analytics/ConsentGatedAnalytics.test.tsx#L4-L6: 더 이상 참조되지 않는AnalyticsRouteTrackermock 제거.🤖 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/providers/root-providers.test.tsx` around lines 44 - 58, Remove the obsolete anonymous prop and fallback branch from the ConsentGatedAnalytics mock in src/providers/root-providers.test.tsx:44-58, leaving a children-only implementation matching the real API. Also remove the unused `@/providers/app-chrome-shell` mock in src/providers/root-providers.test.tsx:70-84 and the unused AnalyticsRouteTracker mock in src/components/analytics/ConsentGatedAnalytics.test.tsx:4-6.src/providers/root-providers.tsx (1)
22-37: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win셸 조합 로직(
MobileChrome+ConsentGatedAnalytics+Toaster)이 두 파일에 중복 구현됨.두 곳 모두 트래커 컴포넌트만 다를 뿐 동일한 조합 순서를 반복하고 있습니다. 공유 컴포넌트(예:
children과 analytics 트래커를 prop으로 받는 shell)로 추출하면 두 경로(공개/보호)에서 재사용할 수 있고, 향후 순서 변경 시 한 곳만 수정하면 됩니다.
src/providers/root-providers.tsx#L22-L37:LightweightPublicShell을 공유 shell 컴포넌트 호출로 교체.src/providers/full-app-provider-stack.tsx#L56-L68: 동일한 공유 shell 컴포넌트를 사용하도록 교체.🤖 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/providers/root-providers.tsx` around lines 22 - 37, Extract the duplicated MobileChrome, ConsentGatedAnalytics, and Toaster composition into a shared shell component that accepts children and the analytics tracker as props. In src/providers/root-providers.tsx#L22-L37, replace LightweightPublicShell’s inline composition with the shared component while preserving AnonymousAnalyticsRouteTracker; in src/providers/full-app-provider-stack.tsx#L56-L68, use the same shared component with that path’s existing tracker. Keep the existing composition order and analytics configuration unchanged.
🤖 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/app/login/page.tsx`:
- Around line 53-59: Update the aria-label on the back-home Link in the login
page to replace the apparent typo “우때” with the intended, meaningful Korean
product or home name. Preserve the existing navigation target and accessibility
attributes.
In `@src/lib/public-site.ts`:
- Around line 1-8: Restore the organization GitHub URL across the public-site
contract and Organization JSON-LD: add githubOrganizationUrl to
src/lib/public-site.ts (lines 1-8), assert its presence in
src/lib/public-site.test.ts (lines 10-25), add sameAs referencing
PUBLIC_SITE.githubOrganizationUrl in src/lib/public-site-metadata.ts (lines
26-49), and replace the absence assertion with an expected organization GitHub
URL in src/lib/public-site-metadata.test.ts (lines 11-41).
- Around line 16-34: Restore the bilingual founder role contract by changing
both role values in PUBLIC_FOUNDERS to “공동창업자 · Co-founder”. Update the
expectations in src/lib/public-site.test.ts lines 27-47 to assert the same
bilingual role string.
In `@src/providers/root-providers.tsx`:
- Around line 60-64: Restructure the provider hierarchy around the root provider
component so QueryClient state from FullAppProviderStack remains mounted while
navigating between PROVIDER_FREE_PUBLIC_PATHS and protected routes. Lift the
shared QueryClient—and, where supported by the existing provider APIs, the Stomp
connection—above the pathname branch, while keeping LightweightPublicShell and
FullAppProviderStack responsible only for route-specific providers; preserve the
current public and protected rendering behavior.
---
Nitpick comments:
In `@src/providers/root-providers.test.tsx`:
- Around line 44-58: Remove the obsolete anonymous prop and fallback branch from
the ConsentGatedAnalytics mock in src/providers/root-providers.test.tsx:44-58,
leaving a children-only implementation matching the real API. Also remove the
unused `@/providers/app-chrome-shell` mock in
src/providers/root-providers.test.tsx:70-84 and the unused AnalyticsRouteTracker
mock in src/components/analytics/ConsentGatedAnalytics.test.tsx:4-6.
In `@src/providers/root-providers.tsx`:
- Around line 22-37: Extract the duplicated MobileChrome, ConsentGatedAnalytics,
and Toaster composition into a shared shell component that accepts children and
the analytics tracker as props. In src/providers/root-providers.tsx#L22-L37,
replace LightweightPublicShell’s inline composition with the shared component
while preserving AnonymousAnalyticsRouteTracker; in
src/providers/full-app-provider-stack.tsx#L56-L68, use the same shared component
with that path’s existing tracker. Keep the existing composition order and
analytics configuration unchanged.
🪄 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 Plus
Run ID: b4000a38-a7d8-45d7-96ab-a1f8718f2499
📒 Files selected for processing (42)
docs/superpowers/plans/2026-07-23-gcp-startup-compliance.mddocs/superpowers/specs/2026-07-21-gcp-startup-compliance-design.mdsrc/app/_components/LandingCompanySection.tsxsrc/app/_components/LandingHeader.tsxsrc/app/_components/LandingHero.tsxsrc/app/_components/LandingStaticSections.test.tsxsrc/app/_components/LandingTeamSection.tsxsrc/app/_components/LandingView.test.tsxsrc/app/_components/LandingView.tsxsrc/app/layout.tsxsrc/app/login/page.test.tsxsrc/app/login/page.tsxsrc/app/page.tsxsrc/app/product/_components/ProductTourFinalCta.tsxsrc/app/product/_components/ProductTourHero.tsxsrc/app/product/_components/ProductTourStep.tsxsrc/app/product/_components/ProductTourView.test.tsxsrc/app/product/_components/ProductTourView.tsxsrc/app/product/page.tsxsrc/app/robots.test.tssrc/app/robots.tssrc/app/sitemap.test.tssrc/app/sitemap.tssrc/components/analytics/AnonymousAnalyticsRouteTracker.tsxsrc/components/analytics/ConsentGatedAnalytics.test.tsxsrc/components/analytics/ConsentGatedAnalytics.tsxsrc/components/icons/LinkedinIcon.tsxsrc/components/icons/index.tssrc/components/seo/StructuredData.test.tsxsrc/components/seo/StructuredData.tsxsrc/lib/landing/landing-content.test.tssrc/lib/landing/landing-content.tssrc/lib/product/product-tour-content.test.tssrc/lib/product/product-tour-content.tssrc/lib/public-site-metadata.test.tssrc/lib/public-site-metadata.tssrc/lib/public-site.test.tssrc/lib/public-site.tssrc/providers/full-app-provider-stack.test.tsxsrc/providers/full-app-provider-stack.tsxsrc/providers/root-providers.test.tsxsrc/providers/root-providers.tsx
| <Link | ||
| href="/" | ||
| aria-label="뒤로가기" | ||
| aria-label="우때 홈으로 돌아가기" | ||
| className="absolute left-4 top-4 flex h-9 w-9 items-center justify-center rounded-full text-dark-gray outline-none ring-offset-2 transition hover:bg-bubble-gray/80 hover:text-neutral-900 focus-visible:ring-2 focus-visible:ring-brand-red" | ||
| > | ||
| <ArrowLeft className="h-5 w-5" aria-hidden /> | ||
| </Link> |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
aria-label에 오타 의심.
aria-label="우때 홈으로 돌아가기"에서 "우때"는 표준 한국어 단어가 아니며 오타로 보입니다. 스크린리더 사용자에게 그대로 노출되는 문구이므로 의미가 통하도록 수정이 필요합니다.
✏️ 제안
- aria-label="우때 홈으로 돌아가기"
+ aria-label="홈으로 돌아가기"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Link | |
| href="/" | |
| aria-label="뒤로가기" | |
| aria-label="우때 홈으로 돌아가기" | |
| className="absolute left-4 top-4 flex h-9 w-9 items-center justify-center rounded-full text-dark-gray outline-none ring-offset-2 transition hover:bg-bubble-gray/80 hover:text-neutral-900 focus-visible:ring-2 focus-visible:ring-brand-red" | |
| > | |
| <ArrowLeft className="h-5 w-5" aria-hidden /> | |
| </Link> | |
| <Link | |
| href="/" | |
| aria-label="홈으로 돌아가기" | |
| className="absolute left-4 top-4 flex h-9 w-9 items-center justify-center rounded-full text-dark-gray outline-none ring-offset-2 transition hover:bg-bubble-gray/80 hover:text-neutral-900 focus-visible:ring-2 focus-visible:ring-brand-red" | |
| > | |
| <ArrowLeft className="h-5 w-5" aria-hidden /> | |
| </Link> |
🤖 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/login/page.tsx` around lines 53 - 59, Update the aria-label on the
back-home Link in the login page to replace the apparent typo “우때” with the
intended, meaningful Korean product or home name. Preserve the existing
navigation target and accessibility attributes.
| export const PUBLIC_SITE = { | ||
| origin: "https://www.uttae.app", | ||
| serviceName: "우때", | ||
| englishServiceName: "Uttae", | ||
| operatorName: "팀 우때 (Team Uttae)", | ||
| founded: "2026-06", | ||
| location: "Seoul, South Korea", | ||
| } as const; |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
조직 GitHub 연결을 공개 데이터와 Organization JSON-LD에 복원하세요.
조직 URL이 공개 데이터에서 빠졌고 Organization JSON-LD에도 sameAs가 없으며, 테스트가 그 부재를 고정합니다. 공개 조직과 사이트의 상호 검증 및 검색 엔진의 운영 주체 연결이 끊깁니다.
src/lib/public-site.ts#L1-L8:githubOrganizationUrl을 공개 사이트 계약에 추가하세요.src/lib/public-site.test.ts#L10-L25: 조직 GitHub URL 존재를 검증하세요.src/lib/public-site-metadata.ts#L26-L49:sameAs: [PUBLIC_SITE.githubOrganizationUrl]를 Organization JSON-LD에 추가하세요.src/lib/public-site-metadata.test.ts#L11-L41:sameAs부재 단언을 제거하고 조직 GitHub URL을 기대하세요.
📍 Affects 4 files
src/lib/public-site.ts#L1-L8(this comment)src/lib/public-site.test.ts#L10-L25src/lib/public-site-metadata.ts#L26-L49src/lib/public-site-metadata.test.ts#L11-L41
🤖 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/public-site.ts` around lines 1 - 8, Restore the organization GitHub
URL across the public-site contract and Organization JSON-LD: add
githubOrganizationUrl to src/lib/public-site.ts (lines 1-8), assert its presence
in src/lib/public-site.test.ts (lines 10-25), add sameAs referencing
PUBLIC_SITE.githubOrganizationUrl in src/lib/public-site-metadata.ts (lines
26-49), and replace the absence assertion with an expected organization GitHub
URL in src/lib/public-site-metadata.test.ts (lines 11-41).
| export const PUBLIC_FOUNDERS = [ | ||
| { | ||
| name: "김민형", | ||
| englishName: "Minhyung Kim", | ||
| role: "Co-founder", | ||
| githubUrl: "https://github.com/minbros", | ||
| githubLabel: "minbros", | ||
| linkedinUrl: "https://www.linkedin.com/in/minbros/", | ||
| }, | ||
| { | ||
| name: "박주영", | ||
| englishName: "PARK JU YEONG", | ||
| role: "Co-founder", | ||
| githubUrl: "https://github.com/parkjuyeong0312", | ||
| githubLabel: "parkjuyeong0312", | ||
| linkedinUrl: | ||
| "https://www.linkedin.com/in/%EC%A3%BC%EC%98%81-%EB%B0%95-75a83a2a4/", | ||
| }, | ||
| ] as const; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
공동창업자 역할의 공개 계약을 복구하세요.
두 창업자의 역할이 요구된 공동창업자 · Co-founder가 아니라 Co-founder만으로 공개되고, 테스트도 이를 고정합니다. 이 데이터를 소비하는 모든 공개 화면이 한국어 역할 정보를 잃습니다.
src/lib/public-site.ts#L16-L34: 두role값을공동창업자 · Co-founder로 변경하세요.src/lib/public-site.test.ts#L27-L47: 변경된 이중 언어 역할 문자열을 기대하도록 수정하세요.
📍 Affects 2 files
src/lib/public-site.ts#L16-L34(this comment)src/lib/public-site.test.ts#L27-L47
🤖 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/public-site.ts` around lines 16 - 34, Restore the bilingual founder
role contract by changing both role values in PUBLIC_FOUNDERS to “공동창업자 ·
Co-founder”. Update the expectations in src/lib/public-site.test.ts lines 27-47
to assert the same bilingual role string.
| if (PROVIDER_FREE_PUBLIC_PATHS.has(pathname)) { | ||
| return <LightweightPublicShell>{children}</LightweightPublicShell>; | ||
| } | ||
|
|
||
| return <FullAppProviderStack>{children}</FullAppProviderStack>; |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟠 Major | 🏗️ Heavy lift
공개↔보호 라우트 전환 시 FullAppProviderStack 전체 리마운트로 앱 상태 초기화.
PROVIDER_FREE_PUBLIC_PATHS에 해당하는 경로("/", "/product", "/login")와 그 외 경로를 오갈 때마다 FullAppProviderStack이 통째로 언마운트/리마운트됩니다. full-app-provider-stack.tsx의 useState(() => createQueryClient())는 매 마운트마다 새 QueryClient를 생성하므로, React Query 캐시가 초기화되고 StompProvider/GoogleMapsProvider도 재초기화됩니다.
로그인된 사용자가 앱 사용 중 로고 클릭 등으로 "/"에 다녀오기만 해도 채팅 소켓 재연결, 지도 재초기화, 캐시된 데이터 전체 재요청이 발생해 눈에 띄는 로딩/깜빡임과 불필요한 네트워크 비용이 생깁니다. 현재 테스트들은 각 경로를 독립적으로 렌더링만 검증하므로 이 전환 시나리오를 잡아내지 못합니다.
QueryClient(및 가능하면 Stomp 연결)는 경로 분기 상위(레이아웃 최상단)에서 항상 유지되도록 하고, 정말 무거운 초기화(지도 등)만 경로별로 분리하는 구조를 검토해 주세요.
🤖 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/providers/root-providers.tsx` around lines 60 - 64, Restructure the
provider hierarchy around the root provider component so QueryClient state from
FullAppProviderStack remains mounted while navigating between
PROVIDER_FREE_PUBLIC_PATHS and protected routes. Lift the shared
QueryClient—and, where supported by the existing provider APIs, the Stomp
connection—above the pathname branch, while keeping LightweightPublicShell and
FullAppProviderStack responsible only for route-specific providers; preserve the
current public and protected rendering behavior.
- 중복 /product 라우트와 전용 콘텐츠 제거 - 실제 화면 안내와 제품 구조화 데이터를 랜딩에 통합
There was a problem hiding this comment.
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 `@src/app/page.test.tsx`:
- Around line 21-29: Update the RootPage test to locate each JSON-LD script,
parse its contents with JSON.parse, and validate the resulting structures rather
than relying only on raw HTML string checks. Assert that the organization and
software application entries have the expected `@type` values and that the URL is
https://www.uttae.app, while preserving the check that the product URL is
absent.
🪄 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 Plus
Run ID: e9badd26-2f11-4df1-a1d2-7c4c3a805372
📒 Files selected for processing (12)
docs/superpowers/plans/2026-07-23-gcp-startup-compliance.mddocs/superpowers/specs/2026-07-21-gcp-startup-compliance-design.mdsrc/app/_components/LandingHeader.tsxsrc/app/_components/LandingHero.tsxsrc/app/_components/LandingView.test.tsxsrc/app/page.test.tsxsrc/app/page.tsxsrc/app/sitemap.test.tssrc/lib/public-site-metadata.test.tssrc/lib/public-site-metadata.tssrc/providers/root-providers.test.tsxsrc/providers/root-providers.tsx
💤 Files with no reviewable changes (3)
- src/app/sitemap.test.ts
- src/app/_components/LandingHeader.tsx
- src/providers/root-providers.test.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
- src/app/_components/LandingView.test.tsx
- src/providers/root-providers.tsx
- src/lib/public-site-metadata.test.ts
- src/lib/public-site-metadata.ts
- 공개 경로 전환 후에도 브라우저 QueryClient 캐시 재사용 - 공통 앱 크롬 셸 추출과 데드 테스트 mock 정리 - JSON-LD 구조 파싱 검증 강화
배경
Google for Startups Cloud Program 심사에서 공개 웹사이트만으로 제품의 실제 운영 상태와 팀 정보를 확인할 수 있도록 사이트를 보강합니다.
변경 사항
/product라우트와 전용 콘텐츠를 제거하고,기능 살펴보기CTA가 랜딩의 제품 기능 섹션으로 이동하도록 변경했습니다.우때 실제 서비스 화면임을 명시했습니다.Co-founder,서울시립대학교 컴퓨터과학부로 정리했습니다.robots.txt,sitemap.xml을 추가했습니다. SoftwareApplication과 sitemap은 단일 랜딩 구조를 기준으로 합니다.기대 효과
검증
npm test— 43개 파일, 206개 테스트 통과npx tsc --noEmitnpm run build— 성공, 생성 라우트 목록에서/product제외 확인기능 살펴보기→/#features이동