Pangea
⏎
자동 분석 · 1달 전
로그인
데모 · 1D1S 프로젝트를 읽기 전용으로 보고 있습니다. 편집·AI 실행은 할 수 없습니다.내 레포로 시작하기 →
1D1S
홈브리핑진전이슈8일정화면API지도 탐색플로우문서변경

문서
루트/AI 역문서/2. 핵심 기능

AI 초안 · 검토 전노근 · 1달 전 수정

2.7 홈과 콘텐츠 탐색

AI 역문서 · 1D1S-client@ad5edf9 기준 · 코드에서 거꾸로 만든 초안입니다. 근거 링크로 확인하세요.

관련 소스 파일

  • 1D1S-client/src/app/page.tsx
  • 1D1S-client/src/app/explore/page.tsx
목적과 범위

이 페이지는 1D1S-client에서 루트 경로 홈과 /explore 탐색 페이지가 어떤 컴포넌트 조합으로 시작되고, 서버와 클라이언트에서 어떤 초기 데이터를 전달받는지 설명합니다. 홈에서는 MainPage가 HomeMobileHeader, HomeScreen, StoryRingSkeleton을 연결하고, 홈의 비동기 렌더링과 로딩 셸을 구성하는 흐름을 다룹니다. 탐색 페이지에서는 공식 챌린지와 가이드 목록을 서버에서 미리 읽어 ExploreScreen에 전달하는 구조를 설명합니다.

이 원문에는 오늘의 기록, 추천 챌린지, 일지, 배너, 팝업의 실제 데이터 필드와 API 호출 코드가 직접 제시되어 있지 않습니다. 또한 공지, 검색어 처리, 검색 API, 공식 챌린지 목록의 상세 화면 구성도 확인되지 않습니다. 따라서 해당 기능은 확인된 진입점과 초기 데이터 전달 범위까지만 기술하고, 코드로 확인할 수 없는 내용은 확인 필요 절에 질문으로 남깁니다.

관련 내용은 1.1 서비스와 레포 개요, 1.2 저장소 구조, 1.3 시스템 아키텍처, 2.1 챌린지 탐색과 참여, 2.3 일지 작성과 조회, 3.2 API와 응답 구조, 4.1 클라이언트 화면 구조에서 이어서 확인할 수 있습니다.

출처: page.tsx:1-15, page.tsx:1-13

구성 요소와 역할

홈의 루트 페이지는 1D1S-client/src/app/page.tsx의 MainPage입니다. MainPage는 전체 화면을 세로 방향으로 배치하는 바깥 컨테이너를 만든 뒤, 검색 엔진용 JSON-LD와 모바일 헤더, 비동기 홈 화면을 순서대로 배치합니다.

구성 요소역할
MainPage루트 홈의 페이지 컴포넌트입니다. 전체 컨테이너와 홈의 상위 렌더링 흐름을 조합합니다.
HomeMobileHeader홈 상단의 모바일 헤더 구성 요소입니다. 내부 버튼이나 검색 진입점은 제공된 코드만으로 확인할 수 없습니다.
HomeScreen홈의 실제 콘텐츠 화면입니다. 오늘의 기록, 추천 챌린지, 일지 등 세부 섹션의 내부 구현은 제공된 원문에 없습니다.
HomeLoadingSkeletonHomeScreen이 준비되기 전 표시하는 로딩 화면입니다.
StoryRingSkeleton홈 로딩 화면에서 스토리 링 영역을 대신 표시하는 스켈레톤입니다.
JsonLd조직 정보와 웹사이트 정보를 구조화 데이터로 출력합니다.
ExplorePage/explore 경로의 서버 페이지입니다. 공식 챌린지와 가이드 목록을 준비합니다.
ExploreScreen탐색 화면을 렌더링하는 클라이언트 화면 컴포넌트입니다.
fetchPublicOfficialChallengePage공식 챌린지의 초기 페이지 데이터를 가져오는 함수입니다.
fetchGuideList가이드 목록을 가져오는 함수입니다.

홈의 페이지 컴포넌트는 세부 데이터를 직접 표시하지 않고 HomeScreen에 위임합니다. 반면 탐색 페이지는 ExploreScreen을 렌더링하기 전에 두 데이터 조회 함수를 실행하고, 결과를 initialOfficialPage와 guideArticles라는 props로 전달합니다.

출처: page.tsx:1-8, page.tsx:49-59, page.tsx:1-3, page.tsx:22-35

홈 진입과 렌더링 흐름

홈의 렌더링은 MainPage가 반환하는 JSX 트리를 기준으로 진행됩니다. 최상위 컨테이너는 flex min-h-screen w-full flex-col 클래스를 사용하므로 화면 전체 높이를 확보하고 자식 요소를 세로 방향으로 배치합니다.

JsonLd는 두 번 호출됩니다. 첫 번째 호출은 buildOrganizationJsonLd()의 결과를, 두 번째 호출은 buildWebSiteJsonLd()의 결과를 전달합니다. 이는 홈 화면의 시각적 콘텐츠라기보다 조직과 웹사이트 정보를 구조화 데이터로 출력하는 별도 경로입니다. 홈의 canonical metadata는 metadata의 alternates.canonical에 /로 지정되어 있습니다.

HomeMobileHeader는 Suspense 바깥에 배치되어 있습니다. 따라서 HomeScreen의 비동기 렌더링이나 useSearchParams에 따른 CSR 경계와 별개로 헤더가 페이지 구조에 포함됩니다. HomeScreen은 Suspense의 자식이며, 준비되지 않은 동안 HomeLoadingSkeleton이 fallback으로 사용됩니다.

번호로 정리한 흐름은 다음과 같습니다.

  1. 사용자가 루트 경로에 진입하면 Next.js 페이지 컴포넌트인 MainPage가 실행됩니다.
  2. MainPage가 buildOrganizationJsonLd()와 buildWebSiteJsonLd()를 호출해 각각 JsonLd에 전달합니다.
  3. HomeMobileHeader가 홈의 모바일 헤더 위치에 배치됩니다.
  4. Suspense가 HomeScreen을 렌더링하려고 시도합니다.
  5. HomeScreen이 준비되기 전에는 HomeLoadingSkeleton이 표시됩니다.
  6. HomeScreen이 준비되면 fallback이 실제 홈 화면으로 교체됩니다.

출처: page.tsx:10-15, page.tsx:49-59

홈 로딩 셸

HomeLoadingSkeleton은 HomeScreen 컨테이너와 동일한 여백을 유지하도록 작성되어 있습니다. 바깥 영역은 mx-auto w-full max-w-[1200px] px-4 pt-4 pb-5를 사용하고, 큰 화면에서는 lg:px-8 lg:py-10을 적용합니다. 내부는 flex flex-col gap-4로 세로 배치됩니다.

로딩 콘텐츠는 세 종류로 구성됩니다.

순서표시 요소코드상 표현
1스토리 링 자리StoryRingSkeleton
2첫 번째 일반 블록h-24, rounded-2xl
3두 번째 일반 블록h-32, rounded-2xl
4큰 콘텐츠 블록h-72, rounded-2xl

세 개의 일반 블록은 모두 bg-skeleton과 animate-pulse를 사용합니다. 이 코드만으로 각 블록이 오늘의 기록인지, 추천 챌린지인지, 일지인지 특정할 수는 없습니다. 따라서 스켈레톤의 시각적 개수와 크기는 확인되지만 실제 섹션과의 일대일 대응은 확인 필요입니다.

출처: page.tsx:17-34

홈 데이터 로딩과 캐시 경계

홈의 데이터 로딩에 대해 코드 주석은 랜덤 챌린지와 일지 데이터가 클라이언트 React Query의 useHomeRandomData로 이관되었다고 설명합니다. 그러나 제공된 코드에는 useHomeRandomData의 import나 호출부가 없습니다. 따라서 이 파일에서 직접 확인되는 것은 데이터 로딩 구현 자체가 아니라, HomeScreen이 그 로딩 경계를 담당한다는 점과 해당 데이터가 서버에서 미리 주입되지 않는다는 설명입니다.

주석에 따르면 현재 홈 라우트는 서버에서 쿠키를 읽지 않으므로 dynamic 강제에서 해제되었습니다. 이에 따라 <Link>의 prefetch로 RSC 셸을 미리 채울 수 있고, 로고 클릭 등으로 홈에 돌아올 때 QueryClient 캐시가 즉시 제공될 수 있습니다. 이 동작에서 확인되는 구분은 다음과 같습니다.

구분코드 주석에서 확인되는 내용
서버 사전 처리홈의 랜덤 챌린지와 일지 데이터는 서버에서 읽지 않습니다.
클라이언트 처리useHomeRandomData와 React Query가 관련 데이터 처리 위치로 언급됩니다.
캐시 재사용홈 재진입 시 QueryClient 캐시가 즉시 제공될 수 있습니다.
인증 힌트서버의 initialHasAuthHint 프리페치를 제거한 상태로 설명됩니다.
마운트 후 인증 판정HomeScreen이 마운트 이후 useIsLoggedIn으로 권위 있게 판정한다고 주석에 적혀 있습니다.

홈 데이터 흐름은 제공된 구현과 주석을 합쳐 다음처럼 정리할 수 있습니다.

  1. 사용자가 홈에 진입합니다.
  2. 서버 페이지 MainPage는 쿠키를 읽어 홈 랜덤 데이터를 직접 채우지 않습니다.
  3. Suspense 내부에서 HomeScreen이 렌더링됩니다.
  4. 홈의 랜덤 챌린지와 일지 데이터는 클라이언트 측 React Query 흐름으로 처리되는 것으로 주석에 기록되어 있습니다.
  5. 클라이언트 네비게이션으로 재진입하면 QueryClient 캐시가 사용될 수 있습니다.
  6. 인증 UI는 하드 로드와 클라이언트 네비게이션에서 서로 다른 첫 화면을 보일 수 있으며, 최종 판정은 useIsLoggedIn이 담당하는 것으로 설명되어 있습니다.

이 원문에는 useHomeRandomData의 반환 필드, 쿼리 키, 호출 API, 캐시 시간, 성공·실패 상태가 없습니다. 따라서 오늘의 기록, 추천 챌린지, 일지의 구체적인 데이터 흐름은 해당 훅과 API 파일을 추가로 확인해야 합니다.

출처: page.tsx:36-47

탐색 페이지의 초기 콘텐츠

ExplorePage는 /explore 경로에 대응하는 async 페이지 컴포넌트입니다. metadata는 buildPageMetadata로 만들며, 제목은 탐색 | 1Day 1Streak, 설명은 관심 있는 챌린지와 사람들의 기록을 둘러보세요., 경로는 /explore, 타입은 website로 지정되어 있습니다.

공식 챌린지와 가이드 목록은 Promise.all로 동시에 조회됩니다. 첫 번째 결과는 initialOfficialPage, 두 번째 결과는 guideArticles라는 이름으로 받아 ExploreScreen에 전달됩니다.

입력 props생성 함수의미
initialOfficialPagefetchPublicOfficialChallengePage()공식 챌린지의 초기 페이지 데이터입니다. 페이지 내부 필드는 확인되지 않습니다.
guideArticlesfetchGuideList()가이드 목록입니다. 개별 가이드 필드는 확인되지 않습니다.

페이지 주석은 공식 챌린지만 서버에서 미리 읽어 초기 HTML에 싣는다고 설명합니다. 반면 “오늘 시작해볼 챌린지”와 “오늘의 응원”은 랜덤·개인화 데이터이므로 클라이언트에서 받는다고 기록되어 있습니다. 이 두 섹션은 제공된 ExplorePage 코드에서 직접 조회하지 않으며, ExploreScreen 내부 처리로 추정할 수 있지만 실제 호출은 확인되지 않습니다.

또한 가이드 목록을 ExplorePage에서 읽는 이유도 주석에 기술되어 있습니다. ExploreScreen이 클라이언트 컴포넌트이므로 그 안에서 직접 await하면 클라이언트 번들에 async 컴포넌트가 포함되고, 렌더가 무한 재시도되며 /guides를 반복 호출할 수 있기 때문이라고 설명합니다. 따라서 현재 구조에서는 서버 페이지가 가이드 목록을 조회하고, 클라이언트 화면은 props로 전달받습니다.

번호로 정리하면 다음과 같습니다.

  1. 사용자가 /explore에 접근합니다.
  2. ExplorePage가 서버에서 실행됩니다.
  3. Promise.all이 fetchPublicOfficialChallengePage()와 fetchGuideList()를 병렬 실행합니다.
  4. 공식 챌린지 결과를 initialOfficialPage에, 가이드 결과를 guideArticles에 저장합니다.
  5. ExploreScreen에 두 props를 전달합니다.
  6. ExploreScreen이 공식 챌린지와 가이드 관련 화면을 렌더링합니다.
  7. 랜덤·개인화 섹션의 실제 클라이언트 조회 방식은 제공된 코드 밖에서 확인해야 합니다.

출처: page.tsx:8-13, page.tsx:15-35

화면 구성과 검색 노출

홈은 MainPage의 전체 화면 컨테이너 안에서 모바일 헤더와 HomeScreen을 표시합니다. 홈의 로딩 상태는 실제 화면과 동일한 좌우 여백을 사용하도록 작성되어 있으며, 최대 너비는 1200px로 제한됩니다. 큰 화면에서는 lg:px-8과 lg:py-10이 적용됩니다.

탐색 페이지는 서버에서 metadata를 생성합니다. 다음 항목이 코드에 고정되어 있습니다.

metadata 항목값
title`탐색
description관심 있는 챌린지와 사람들의 기록을 둘러보세요.
path/explore
typewebsite

홈은 metadata에 alternates: { canonical: '/' }를 지정합니다. 주석은 canonical을 페이지마다 자기 경로로 선언해야 하므로 루트 레이아웃에 두지 않고, 홈만 /을 선언한다고 설명합니다. 공개 페이지의 나머지 metadata는 buildPageMetadata가 채우는 구조라고 기록되어 있습니다.

검색 기능에 대해서는 이 원문에서 검색 입력 컴포넌트, 검색 상태, 검색어 파라미터, 검색 API가 확인되지 않습니다. HomeMobileHeader가 홈에 포함되지만 내부에 검색 UI가 있는지는 알 수 없습니다. useSearchParams가 HomeScreen의 CSR bailout 경계와 관련 있다는 주석은 있으나, 어떤 파라미터를 읽는지와 검색에 사용하는지는 제시되지 않았습니다.

배너와 팝업도 동일합니다. 홈 페이지에서 직접 확인되는 시각적 구성은 HomeMobileHeader, HomeScreen, HomeLoadingSkeleton, StoryRingSkeleton뿐이며, 배너 또는 팝업이라는 이름의 컴포넌트와 표시 조건은 없습니다. 따라서 홈에서 이 콘텐츠가 실제로 표시되는지, 표시된다면 HomeScreen의 어느 하위 컴포넌트가 담당하는지는 추가 파일 확인이 필요합니다.

출처: page.tsx:13-15, page.tsx:17-33, page.tsx:47-57, page.tsx:4-13

상태와 예외 처리

제공된 코드에서 직접 확인되는 상태는 홈의 Suspense fallback과 탐색 페이지의 서버 데이터 준비 단계입니다.

상태홈탐색
초기 표시HomeLoadingSkeleton이 fallback으로 사용됩니다.서버 페이지가 데이터를 조회한 뒤 화면을 반환합니다.
콘텐츠 준비 완료HomeScreen으로 교체됩니다.ExploreScreen이 두 props를 전달받아 렌더링됩니다.
데이터 실패별도 ErrorBoundary나 오류 UI는 확인되지 않습니다.조회 실패 처리나 오류 UI는 확인되지 않습니다.
인증 판정useIsLoggedIn이 마운트 후 판정하는 것으로 주석에 설명됩니다.인증 상태 처리는 확인되지 않습니다.
캐시 재사용QueryClient 캐시가 재진입 시 사용될 수 있습니다.초기 공식 챌린지와 가이드 데이터의 캐시 정책은 확인되지 않습니다.

홈에서는 Suspense가 HomeScreen의 useSearchParams CSR bailout 경계를 겸한다고 주석에 기록되어 있습니다. 따라서 HomeScreen이 검색 파라미터를 읽는 구조일 가능성은 코드 주석에서 확인되지만, 실제 파라미터 이름이나 그에 따른 화면 상태는 알 수 없습니다.

또한 주석은 하드 로드의 콜드 첫 페인트에서 로그인 사용자가 한 프레임 비로그인 UI를 볼 수 있다고 설명합니다. 클라이언트 네비게이션에서는 hasMounted=true이므로 이 시프트가 없고, 마운트 이후 useIsLoggedIn이 권위 있는 판정을 수행한다고 적혀 있습니다. 이 동작은 홈의 인증 표시 상태와 관련되지만, 어떤 버튼이나 섹션이 바뀌는지는 제공된 코드에 없습니다.

오류 처리 관점에서는 두 페이지 모두 명시적인 try/catch, ErrorBoundary, 오류 전용 컴포넌트, 재시도 버튼을 보여주지 않습니다. fetchPublicOfficialChallengePage() 또는 fetchGuideList() 중 하나가 실패했을 때 Promise.all이 어떻게 처리되는지도 이 파일만으로는 확인할 수 없습니다.

출처: page.tsx:36-47, page.tsx:55-57, page.tsx:22-35

확인 필요

다음 항목은 제공된 원문만으로는 확정할 수 없으므로 구현 파일과 API 정의를 추가로 확인해야 합니다.

  • HomeScreen 내부에서 오늘의 기록을 구성하는 컴포넌트와 데이터 필드는 무엇입니까?
  • 추천 챌린지와 랜덤 챌린지는 useHomeRandomData의 어떤 반환값으로 구분됩니까?
  • 홈의 일지 목록은 어떤 API 또는 React Query query key를 사용합니까?
  • useHomeRandomData는 실제로 어떤 엔드포인트를 호출하며, 응답의 페이지네이션이나 랜덤 기준은 무엇입니까?
  • HomeMobileHeader에 검색 입력, 검색 버튼, 알림 또는 프로필 진입점이 포함됩니까?
  • useSearchParams가 읽는 파라미터 이름과 값은 무엇이며, 홈의 어떤 상태를 변경합니까?
  • 홈의 배너와 팝업 컴포넌트 이름, 표시 조건, 닫기 상태, 노출 API는 무엇입니까?
  • 공지사항은 홈 또는 /explore의 어느 컴포넌트에서 조회하고 표시합니까?
  • 검색 기능은 별도 페이지입니까, /explore 내부 기능입니까? 검색 API와 결과 데이터 모델은 무엇입니까?
  • fetchPublicOfficialChallengePage()가 호출하는 실제 API 엔드포인트와 반환 필드는 무엇입니까?
  • 공식 챌린지의 초기 페이지는 ExploreScreen에서 어떻게 클라이언트 페이지네이션 또는 추가 조회와 연결됩니까?
  • fetchGuideList()의 반환 데이터에서 가이드 제목, 이미지, 링크, 게시 상태를 나타내는 필드는 무엇입니까?
  • “오늘 시작해볼 챌린지”와 “오늘의 응원”은 어떤 클라이언트 훅 또는 API를 사용합니까?
  • 공식 챌린지 탐색과 일반 챌린지 탐색의 관계는 2.1 챌린지 탐색과 참여의 목록·상세 API와 어떻게 이어집니까?
  • 홈의 데이터 조회 실패, 빈 목록, 인증 만료 상황에서 사용자에게 표시되는 UI는 무엇입니까?
  • HomeLoadingSkeleton의 네 영역이 실제 홈 섹션과 어떤 순서로 대응합니까?

출처: page.tsx:17-47, page.tsx:15-35

속성
분류스펙
폴더AI 역문서 / 2. 핵심 기능
#AI 역문서
연결된 화면·API2
화면explore
/explore
화면홈/
이 문서를 언급한 문서1
0 목차스펙
#AI 역문서