fix: URL 경로 기반으로 페이지 트리 계층 구성 + 중복 제거

parent_url(크롤링 발견 순서) 대신 URL path 계층으로 트리를 구성하여
/howyoutubeworks가 /about 하위로 잘못 표시되는 문제 수정.
동일 URL 중복 노드도 제거.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
jungwoo choi
2026-02-14 07:17:43 +09:00
parent 1098e9e05f
commit 9f58485a87

View File

@ -18,9 +18,50 @@ interface PageTreeProps {
aggregateScores: AggregateScores | null;
}
/**
* URL 경로 기반으로 부모 페이지를 찾는다.
* 경로 세그먼트를 하나씩 올라가며 실제 존재하는 페이지를 찾고,
* 없으면 null (최상위)을 반환한다.
*
* 예: /about/press → /about (존재) → 부모
* /howyoutubeworks → / (존재) → 부모
* /creators/podcasts → / (존재, /creators 없음) → 부모
*/
function findPathParent(url: string, pageUrls: Set<string>): string | null {
try {
const parsed = new URL(url);
const path = parsed.pathname;
// 루트 경로는 부모 없음
if (path === "/" || path === "") return null;
const cleanPath = path.endsWith("/") ? path.slice(0, -1) : path;
const segments = cleanPath.split("/").filter(Boolean);
// 경로를 한 단계씩 올라가며 존재하는 페이지 찾기
for (let i = segments.length - 1; i >= 1; i--) {
const parentPath = "/" + segments.slice(0, i).join("/");
const parentUrl = `${parsed.origin}${parentPath}`;
if (pageUrls.has(parentUrl)) {
return parentUrl;
}
}
// 루트 페이지 확인 (trailing slash 유무 모두)
const rootWithSlash = `${parsed.origin}/`;
const rootWithout = parsed.origin;
if (pageUrls.has(rootWithSlash) && rootWithSlash !== url) return rootWithSlash;
if (pageUrls.has(rootWithout) && rootWithout !== url) return rootWithout;
return null;
} catch {
return null;
}
}
/**
* 페이지 트리 사이드바 컴포넌트.
* flat 배열을 parent_url 기준으로 트리 구조로 변환하여 렌더링한다.
* flat 배열을 URL 경로 계층 기준으로 트리 구조로 변환하여 렌더링한다.
*/
export function PageTree({
pages,
@ -29,25 +70,33 @@ export function PageTree({
aggregateScores,
}: PageTreeProps) {
/**
* flat 배열에서 parent_url → children 맵 구성.
* root 노드(parent_url === null)를 최상위 자식으로 처리.
* URL 경로 기반으로 트리 구성.
* /about/press → /about 하위, /howyoutubeworks → / 하위
*/
const { rootPages, childrenMap, allPagesMap } = useMemo(() => {
const childrenMap = new Map<string, DiscoveredPage[]>();
const allPagesMap = new Map<string, DiscoveredPage>();
const rootPages: DiscoveredPage[] = [];
const pageUrls = new Set<string>();
// 중복 URL 제거 (첫 번째 등장만 유지)
const uniquePages: DiscoveredPage[] = [];
for (const page of pages) {
if (!pageUrls.has(page.url)) {
pageUrls.add(page.url);
allPagesMap.set(page.url, page);
uniquePages.push(page);
}
}
for (const page of pages) {
if (page.parent_url === null) {
for (const page of uniquePages) {
const parentUrl = findPathParent(page.url, pageUrls);
if (parentUrl === null) {
rootPages.push(page);
} else {
const siblings = childrenMap.get(page.parent_url) || [];
const siblings = childrenMap.get(parentUrl) || [];
siblings.push(page);
childrenMap.set(page.parent_url, siblings);
childrenMap.set(parentUrl, siblings);
}
}