GitHub

Next.js로 기획에서 프로덕트를 만든 방법 : 데이터 기반 장기렌트 견적 추적 서비스 - 프롤로그

hojun lee · 08/06/2025
커버이미지

역대카 : 데이터 기반 신차 장기렌트 견적추적 서비스

https://alltime-car.com

"이 가격, 정말 합리적일까?" - 소비자의 고민

"이 차량 진짜 저렴한데 알릴 방법이 없네" - 장기렌트 컨설턴트의 고민

모든 기획은 문제에서 시작된다. 사소하지만 중요한 고민을 문제로 인식하고 그 문제를 기술로 해결할 수 있는 기회를 포착하는게 중요하다. 이번 프로젝트는 장기렌트 컨설턴트의 지인으로부터 'EV 3'가 역대 가장 저렴한데!라는 문제의식에서부터 시작되었다. 그렇게 문제를 해결하기 위해 장기렌트 라는 복잡하고 재밌는 산업에 뛰어 들었다.

나는 자동차를 잘 알지 못한다.

특히 장기렌트 도메인은 더욱 그렇다. 신차 장기렌트 시장은 정말 복잡하다. 매월, 매주, 매순간 바뀌는 프로모션과 가격 정책 속에서 소비자는 "지금 내가 보고 있는 이 견적이 과연 합리적인가"라는 의문을 품게 된다. 그래서 주변 장기렌트를 실제로 진행해봤던 ( 주로 사업자 ) 사람들에게 장기렌트를 계약하는 과정에 대해 FGI를 커피 사주면서 실시했다. 여기서 여러가지 소비자가 생각하는 장기렌트의 문제점을 마주할 수 있었는데, 첫째 객관적인 자료 없이 서로 자기들이 싸다고 우기는 탓에 시작부터 지켜버린다. 둘째 내가 열심히 발품팔아서 견적을 요청해도 이게 지금 싼건지 비싼건지 도통 모르겠다. 셋째 장기렌트카 업체는 20곳도 넘는 것으로 알고 있는데, 아무리 노력해봤자 3곳이상 가격정보를 얻을 수 없다. 결국 요약해보면 제한된 시간 속에서 장기렌트의 가격을 찾는 여정은 엄청난 탐색비용을 거치게 되고, 그 중에서 한정된 정보 안에서 (최선은 만나보지도 못하고) 차선을 선택을 할 수 밖에 없는 구조이다.

차량 구조 : 브랜드 -> 차량 -> 엔진 -> 트림 -> 옵션

장기렌트 구조 : 50% 이상 3사 대기업 시장 점유, 하위 업체들의 마케팅 전쟁 (치킨게임)

차량 견적을 주식 시세처럼 추적하고 비교해보면

역대카(alltime-car) 프로젝트는 바로 이 지점에서 시작되었다. 소비자가 특정 차량의 가격 변동 추이를 데이터에 기반해 명확히 인지하고, 적정한 가격을 확인하고 구매 시점을 판단할 수 있도록 돕는 것. 이 것이 요즘 현명한 소비를 추구하는 소비자를 잡는 핵심 가치라고 생각했다.

더 이상 소비자가 '감'이 아닌 '데이터'에 의존해 최적의 결정을 내릴 수 있는, 투명하고 합리적인 신차 장기렌트 시장을 구축해보면 어떨까.

어떻게 IT 서비스로 만들 수 있을까🫢

기획은 원래 가볍다. 어 그냥 견적 받아서 가격 월단위로 모으면 되는거잖아? 쉽잖아? 그렇다. 원래 말은 쉬운 것이다. 최근 프로젝트를 기획해보며 느낀 점은 데이터구조실현가능성의 조화를 잘 이루어야 한다는 것을 배웠다. 확장성도 고려해야겠지만, 무리한 계획은 결국 암초를 만난다. 그럼 프로젝트는 당연 타이타닉처럼 좌초된다.

그래서 쉽게! 현대차 / 기아차 / 다나와 장기렌트 를 보며 DB 설계를 고민해보았다. 그리고 지금 특가 차량인 EV3를 프론트페이지에서 가격정보와 함께 보여주는 것을 목표로 잡았다. 왠지 할 수 있을 것 같았다. (역시 처음은 막연한 자신감이 필요하다)

아키텍처 선정

개발 아키텍처 : 시스템을 구성하는 요소(component)는 무엇이며, 이 요소들이 어떻게 서로 관계를 맺고 상호작용하는지에 대한 규칙 설계

이제 역대카 프로젝트는 '무엇을' 만들 것인가는 도안이 나왔다. 이제 어떻게 만들 것인가에 대한 고민이다. 안정적이면서도 확장성 있는 서비스를 만들기 위해 그리고 비교적 최신 기술을 사용하려고 했다.

Monorepo with Truborepo & pnpm : 하나의 저장소

여러 개별 프로젝트 (예: admin, user, db, UI) 의 코드를 단일 Git 저장소에서 관리하는 개발 방식이다. 비교적 커진 프로젝트에서 코드의 일관성과 재사용성을 높여야겠다고 판단했다.

apps - 애플리케이션 폴더
  • service (고객용 웹앱) : 최종 사용자가 직접 상호작용하는 서비스이다. 차량 견적 조회, 가격 변동 차트 확인, 상담 신청 등 기능을 제공하고 packages에 있는 모든 공통 모듈에 의존하여 UI와 비즈니스 로직을 구현한다.
  • admin (관리자용 웹앱) : 데이터를 관리하는 내부 대시보드이다. 차량 정보 ( 차량 / 엔진 / 트림)와 가격 데이터 등을 등록하고 수정한다. 공통 packages를 공유하여 일관성을 유지한다.
packages - 재사용 가능한 공통 모듈
  • common: Button, Input, Card 등 여러 애플리케이션에서 공통으로 사용되는 React 컴포넌트와 유틸리티 함수를 모아놓은 패키지 (주요 UI를 위한 shadCN).
  • database: Prisma 스키마(schema.prisma)와 생성된 클라이언트를 포함한다. 데이터베이스 모델의 정의를 중앙에서 관리하여 모든 앱이 동일한 데이터 구조를 참조하도록 보장한다. (싱글톤 설계)
  • supabase: Supabase 클라이언트 초기화 코드, 인증 관련 훅(hook), 타입 정의 등 Supabase와 관련된 공통 로직을 담고 있다. supabase에서 가지고 있는 PostgreSql DB를 사용한다.
  • tailwind-config: Tailwind CSS의 설정을 중앙에서 관리합니다. service와 admin 앱이 동일한 디자인 시스템(색상, 폰트, 간격 등)을 공유하게 해준다.
  • typescript-config: tsconfig.json의 기본 설정을 관리한다. 모노레포 내 모든 프로젝트가 일관된 TypeScript 컴파일 옵션을 사용하도록 강제한다.
  • eslint-config: ESLint 규칙을 중앙에서 관리하여, 모든 코드베이스에 일관된 코딩 스타일과 품질기준을 적용한다.

하나의 레포에 재사용성을 높이는 패키지 전략을 사용한다. 설정과 타입관리를 한 번에 진행한다. 원자적 리팩토링 및 변경이 가능하다. 특히 DB 관련 파일을 하나의 레포에서 관리하므로서 admin 과 service 에서 단 하나의 커밋으로 적용하여 안정성을 높인다.

pnpm : 요즘 대세 패키지 매니저

npm, yarn 은 가라! 요즘은 pnpm : node_modules를 제대로 관리한다.

  • 디스크 공간 절약 : pnpm-workspace.yaml로 관리되는 '역대카' 프로젝트에서 service와 admin이 모두 react 라이브러리를 사용하더라도, 실제 파일은 중앙 저장소(~/.pnpm-store)에 단 한 벌만 저장된다. 각 앱의 node_modules에는 원본을 가리키는 링크만 생성되므로, 프로젝트가 커져도 디스크 사용량은 거의 늘어나지 않는다.
  • 의존성 전략 : pnpm은 package.json에 명시적으로 선언되지 않은 패키지는 코드에서 불러올 수 없도록 막는다. 이로 인해 '유령 의존성' 문제가 해결되어, 각 패키지(common, supabase 등)가 독립적으로 안정적인 동작을 보장받게 된다.

Turborepo : 초고속 빌드 엔진

pnpm이 효율적인 저장 구조를 만들었다면, Turborepo는 그 위에 개발 워크플로우를 관리한다. turbo.json을 통해 작업의 효율을 극대화한다.

  • 캐싱 시스템 service 앱의 코드를 일부 수정하고 빌드(turbo run build)를 실행했다고 가정해보자. Turborepo는 service 앱이 의존하는 packages/common, packages/database 등의 코드는 변경되지 않았음을 감지한다. 따라서 이 패키지들의 빌드 과정은 건너뛰고, 이전에 빌드했던 캐시(cache)된 결과물을 그대로 사용한다. 오직 변경된 service 앱만 다시 빌드하므로 전체 빌드 시간은 극적으로 단축되는 효과.
  • 작업 파이프라인 설계
{
    "$schema": "https://turbo.build/schema.json",
    "ui": "tui",
    "globalDependencies": [".env"],
    "tasks": {
        "build": {
            "dependsOn": ["^db:generate", "^build"],
            "inputs": ["$TURBO_DEFAULT$", ".env*"],
            "outputs": ["dist/**", ".next/**", "!.next/cache/**", "^db:generate"],
            "env": [
                "POSTGRES_POOLING_URL",
                "POSTGRES_DIRECT_URL",
                "NEXT_PUBLIC_SUPABASE_URL",
                "NEXT_PUBLIC_SUPABASE_ANON_KEY"
            ]
        },
        "lint": {
            "dependsOn": ["^lint"]
        },
        "check-types": {
            "dependsOn": ["^check-types"]
        },
        "db:migrate:dev": {
            "cache": false,
            "persistent": true
        },
        "db:migrate:deploy": {
            "cache": false
        },
        "db:push": {
            "cache": false
        },
        "db:generate": {
            "cache": false
        },
        "dev": {
            "cache": false,
            "persistent": true
        }
    }
}

turbo.json에 정의된 파이프라인 덕분에, 개발자는 service 앱을 개발(turbo run dev)할 때, 의존성인 common 패키지가 먼저 빌드되어야 한다는 사실을 신경 쓸 필요가 없다. Turborepo가 알아서 의존 관계를 파악하고 올바른 순서대로 작업을 실행한다.

모던한 아키텍처 인가?

  1. 일관성 : tailwind-config, eslint-config, typescript-config를 packages로 분리하여 모든 코드베이스에 단일 공급원 마련
  2. 재사용성 :common, database, supabase 모듈을 통해 중복 코드를 제거하고 핵심 로직을 한곳에서 관리
  3. 효율성 : pnpm과 Turborepo를 통해 모노레포의 단점이었던 속도와 용량 문제를 해결하고, 개발 경험(DX)을 최상으로 끌어올림

핵심 기술 스택

Next.js & TypeScript (한국에선 react와 nextjs를 놓을 수 없다...)

현대적인 웹 애플리케이션의 표준으로 자리 잡은 Next.js를 프레임워크 선택했다. 강력한 서버-사이드 렌더링(SSR)과 정적 사이트 생성(SSG) 기능은 뛰어난 성능과 검색 엔진 최적화(SEO)의 기반이 된다. 여기에 TypeScript를 더해, 데이터 기반 서비스의 핵심인 타입 안정성을 확보하고 잠재적인 버그를 사전에 방지한다. 빨간 줄 멈춰.

Prisma & Supabase : 백엔드를 도와주셈

데이터베이스와의 상호작용은 타입 세이프한 Prisma ORM을 통해 관리한다. 복잡한 SQL 쿼리를 직관적인 코드로 작성하게 도와주며, 개발 생산성을 크게 높여준다. 백엔드 인프라는 오픈소스 Firebase 대안으로 각광받는 Supabase를 활용하여, 데이터베이스(PostgreSql)와 인증 시스템을 안정적으로 구축한다.

기획에서 프로덕트가 되는 과정의 이야기

이 기술 블로그를 통해 '역대카' 프로젝트의 시작부터 현재까지, 내가 겪었던 치열한 고민과 문제 해결 과정을 공유하고자 한다. 이는 단순한 개발 기록을 넘어, 아이디어가 실제로 사용자의 행동과 연결과는 일련과정을 다룬다.

  1. 프롤로그: '역대카'는 왜, 어떻게 시작되었는가? (바로 이 글입니다.)
  2. 백엔드: Prisma와 Supabase로 어떻게 데이터 모델링과 백엔드 로직을 구축했는가?
  3. 백엔드 to 프론트: Vercel의 '10초 타임아웃' 지옥에서 벗어나기 위한 쿼리 최적화와 데이터 구조 개선 여정.
  4. 프론트엔드: 복잡한 자동차 데이터를 사용자에게 가장 직관적으로 보여주기 위한 UI/UX 설계 과정.
  5. SEO와 데이터 분석: 어떻게 우리 서비스를 세상에 알리고, GA4와 Google Ads를 통해 사용자의 행동을 분석하고 개선했는가?
  6. 에필로그: 프로젝트를 통해 얻은 교훈과 앞으로의 방향. 그리고 돈.

결론

단순한 문제의식이 성취와 사업으로 연결되는 과정을 기대하시라.