3 min read
Next.js App Router 블로그 MVP 설계
App Router 기반 블로그 MVP를 Clean Architecture 관점으로 설계하고, 레이어 책임과 인프라 트레이드오프를 정리한 실무 가이드
도입
블로그 MVP는 빠르게 출시하는 것이 목표지만, 초기 구조를 잘못 잡으면 기능이 늘어날수록 콘텐츠 처리, SEO, 배포 안정성이 함께 무너진다. App Router는 서버 컴포넌트 중심 개발에 유리하지만, 라우트 파일에 비즈니스 로직이 몰리기 쉬운 구조이기도 하다.
이 글은 App Router 기반 MVP를 Clean Architecture 레이어 분리로 설계해, 출시 속도와 확장 가능성을 동시에 확보하는 방법을 다룬다.
문제 정의
초기 MVP에서 자주 생기는 문제는 다음과 같다.
app/**라우트 파일에 데이터 접근/검증/가공 로직이 섞임- SEO 메타데이터 생성 규칙이 페이지마다 분산됨
- 콘텐츠 파싱 실패가 런타임에서만 드러남
- 배포 파이프라인은 통과했지만 실제 페이지 데이터가 불완전함
핵심은 "라우팅"과 "유스케이스"를 분리하고, 콘텐츠 모델을 단일 경로로 유지하는 것이다.
개념 설명
MVP에서 필요한 최소 레이어
| 레이어 | 책임 | 파일 예시 |
|---|---|---|
| Presentation | route/page 구성, 요청/응답 바인딩 | app/posts/[slug]/page.tsx |
| Application | 유스케이스, 정렬/필터 정책 | lib/application/get-post-list.ts |
| Domain | 포스트 모델, 태그 규칙, 날짜 정책 | lib/domain/post.ts |
| Infrastructure | 파일 읽기, MDX 파싱, 배포 연동 | lib/posts.ts |
MVP 기능 범위
- 콘텐츠:
content/posts/*.mdx - 라우트:
/,/posts,/posts/[slug],/tags,/about - SEO:
generateMetadata+ sitemap + rss - 검증: 빌드 단계 frontmatter 체크
코드 예시
예시 1: Route Handler에서 유스케이스 호출
import { getPostListUseCase } from "@/lib/application/get-post-list";
export default async function PostsPage() {
const posts = await getPostListUseCase({
sortBy: "date_desc",
limit: 20,
});
return <PostList posts={posts} />;
}
예시 2: Application 계층에서 경계 고정
import { postRepository } from "@/lib/infrastructure/post-repository";
type Params = {
sortBy: "date_desc" | "date_asc";
limit: number;
};
export async function getPostListUseCase(params: Params) {
const items = await postRepository.findAll();
const sorted = [...items].sort((a, b) =>
params.sortBy === "date_desc"
? new Date(b.date).getTime() - new Date(a.date).getTime()
: new Date(a.date).getTime() - new Date(b.date).getTime(),
);
return sorted.slice(0, params.limit);
}
아키텍처 설명
App Router MVP에서는 요청 흐름과 콘텐츠 흐름을 별도로 보아야 한다.
Mermaid diagram rendering...
Clean Architecture 레이어 구조
실무에서 유지보수 가능한 MVP를 만들려면 아래 경계를 명확히 유지해야 한다.
- Presentation: 라우팅, 사용자 입력 바인딩, 페이지 단위 조합
- Application: 유스케이스 오케스트레이션, 정렬/필터링 정책
- Domain: 핵심 규칙(태그/날짜/slug 정책), 타입 불변성
- Infrastructure: 파일 시스템 접근, MDX 파싱, 외부 플랫폼 연동
인프라 구성도
Mermaid diagram rendering...
트레이드오프 분석
| 선택 | 장점 | 단점 | 권장 상황 |
|---|---|---|---|
| 라우트 중심 단일 구현 | 빠른 초기 개발 | 책임 혼재, 테스트 어려움 | 단기 데모 |
| Clean Architecture 분리 | 변경 내성 높음, 테스트 용이 | 초기 구조 비용 증가 | 운영 예정 MVP |
| 정적 생성 극대화 | 성능/비용 유리 | 실시간성 제한 | 콘텐츠 중심 서비스 |
| 동적 렌더링 혼합 | 실시간 반영 유리 | 캐시/비용 관리 필요 | 빈번한 데이터 변동 |
MVP 단계에서는 "너무 많은 추상화"도 위험하지만, 경계 없이 시작하는 것 역시 확장 비용을 키운다. 최소 레이어를 먼저 정의하고, 필요할 때만 확장하는 방식이 가장 실용적이다.
정리
App Router 블로그 MVP의 핵심은 기능 목록보다 경계 설계다. 아래 세 가지를 우선 고정하면 이후 기능 추가가 훨씬 안전해진다.
- 라우트는 조합만 담당하고 유스케이스는 별도 계층에 둔다.
- 콘텐츠 모델은 단일 검증 경로로 관리한다.
- metadata/sitemap/rss 생성은 같은 데이터 소스를 사용한다.
이 원칙을 지키면 MVP 이후 검색, 태그, 분석, 추천 기능을 붙여도 구조가 쉽게 흔들리지 않는다.