블로그 만들기 06 - 방문 트래커 수정하기

2025-08-29

#블로그#Nextjs#Vercel#Supabase#방문자통계

🧠 요약

  • 방문자 수 추적 오류 수정: 기존 구현한 Tracker의 치명적 로직 수정

📌 본문

1. 이슈 발생

블로그 만들기 04에서 만든 방문자 추적 트래커에 문제가 있다는 것을 깨달았다.

다시 한번 트래커 코드를 살펴보면

"use client";

import { useEffect } from "react";
import { usePathname } from "next/navigation";
/**
 * 방문 기록 추적
 */
const Tracker = () => {
  const pathname = usePathname();

  // 페이지 별 방문 기록 추적
  useEffect(() => {
    const today = new Date().toDateString();

    const visitedStr = localStorage.getItem("visited");
    const visited: { path: string; date: string }[] = visitedStr
      ? JSON.parse(visitedStr)
      : [];

    const alreadyVisitedToday = visited.some(
      (entry) => entry.path === pathname && entry.date === today,
    );
    if (alreadyVisitedToday) return;

    fetch("/api/track", {
      method: "POST",
      body: JSON.stringify({ path: pathname }),
      headers: { "Content-Type": "application/json" },
    }).then(() => {
      visited.push({ path: pathname, date: today });
      localStorage.setItem("visited", JSON.stringify(visited));
    });
  }, [pathname]);

  return null;
};

export default Tracker;

페이지 별 방문 추적에서, 현재 경로를 방문하지 않았을 경우, 바로 방문했음을 전송하고 있다.

여기서 문제가 발생한다. 바로, 유효하지 않은 경로도 저장이 될 수 있다는 것이다.

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="ko" data-theme="dark">
      <body
        className={`${Pretendard.className} w-full h-screen min-w-[320px] flex relative bg-background overflow-x-hidden`}
      >
		<Tracker />
        <Sidebar />
        <main className="flex-1 h-screen overflow-y-auto">
          <Header />
          {children}
        </main>
      </body>
    </html>
  );
}

이전 글에서, Tracker를 Layout에서 Provider 형식으로 사용하면 된다라고 했었는데, 그러면 안된다는것을 깨달았다.

아니, 해도 되지만 이렇게 하려면 몇 가지 보완이 필요하다.

2. 해결 방안

내가 생각한 해결 방안은 두 가지이다.

  1. 현재 코드를 그대로 사용하면서, 서버에 미리 유효한 경로를 저장한 후, 클라이언트에서 잘못된 경로에 방문했다면, 유효하지 않은 경로로 저장하지 않는 방법
  2. 정말 유효한 페이지에서만 조건부로 방문 추적하기

이 중 내가 선택한 방안은 2번이다. 일단 1번을 살펴보면, 블로그와 같이 게시글이 계속 늘어나서 경로가 가변하는 상황에 미리 유효한 경로를 저장하기 위해서는 2번 방안보다 복잡한 과정이 동반되어야한다.

내가 현재 쓰고있는 Next.js 특성 상, 동적 라우팅을 편하게 할 수 있기 때문에, 유효한 페이지인지 확인하는 로직만 추가해주면 더 빠르게 해결할 수 있을 것이다.

3. 유효 페이지 검사

블로그 게시글을 표시하는 페이지를 보자.

// posts/[id]/page.tsx
import { getAllPosts } from "app/_lib/post";
import TOC from "app/_components/toc";
import Content from "app/_components/content";
import NotFound from "app/not-found";

export default async function PostPage({
  params,
}: {
  params: Promise<{ id: string }>;
}) {
  const allPosts = getAllPosts();
  const { id } = await params;
  const post = allPosts.find((p) => p.id === id);
  if (!post) {
    return <NotFound />;
  }
  
  return (
    <div className="relative flex justify-center">
	  <Tracker /> {/* 여기에 방문자 추적 추가 */}
      <Content post={post} />

      {/* 사이드바 목차 */}
      <TOC items={toc} />
    </div>
  );
}

"/posts/게시글1" 이라는 경로라면 이미 "게시글1"이라는 id를 통해 유효한 post를 찾고 있어, 유효한 페이지 검증을 수행할 수 있다.

따라서 바로 Tracker를 이 코드에 적용시키면 유효한 경로만 방문 추적을 할 수 있게 된다.

🔄 회고 및 인사이트

  • 클라이언트 추적은 섬세하게 설계해야 한다

처음에는 단순히 pathname만을 기반으로 방문 기록을 수집했지만, 이 접근은 404 페이지와 같이 유효하지 않은 경로도 기록되는 문제로 이어졌다.

클라이언트 측에서 라우팅은 곧바로 변경되지만, 그 경로가 실제로 존재하는 페이지인지는 별개라는 사실을 이번에 명확히 체감했다.

  • Tracker는 전역보단 조건부가 옳다

처음에는 RootLayout에 Tracker를 배치해 전역에서 추적을 진행했지만, 이는 유효성 검증 없이 모든 경로를 추적하는 부작용을 낳았다. 결국엔 유효한 콘텐츠가 렌더링된 후에만 Tracker를 실행하도록 설계 방향을 바꿨고, 이는 통계의 신뢰도를 크게 높여주는 계기가 되었다.

  • Supabase만으로도 충분한 통계 시스템 구축 가능

Supabase는 인증이나 서버 구축 없이도 간단한 API 호출만으로 데이터 저장과 조회가 가능하다는 점에서, 서버리스 환경에서 통계 기능을 빠르게 구현할 수 있는 강력한 도구임을 다시금 느꼈다.