"이 가격, 정말 합리적일까?" - 소비자의 고민
"이 차량 진짜 저렴한데 알릴 방법이 없네" - 장기렌트 컨설턴트의 고민
모든 기획은 문제
에서 시작된다. 사소하지만 중요한 고민을 문제로 인식하고 그 문제를 기술로 해결할 수 있는 기회를 포착하는게 중요하다. 이번 프로젝트는 장기렌트 컨설턴트의 지인으로부터 'EV 3'가 역대 가장 저렴한데!
라는 문제의식에서부터 시작되었다. 그렇게 문제를 해결하기 위해 장기렌트 라는 복잡하고 재밌는 산업에 뛰어 들었다.
특히 장기렌트 도메인은 더욱 그렇다. 신차 장기렌트 시장은 정말 복잡하다. 매월, 매주, 매순간 바뀌는 프로모션과 가격 정책 속에서 소비자는 "지금 내가 보고 있는 이 견적이 과연 합리적인가"라는 의문을 품게 된다. 그래서 주변 장기렌트를 실제로 진행해봤던 ( 주로 사업자 ) 사람들에게 장기렌트를 계약하는 과정에 대해 FGI를 커피 사주면서 실시했다. 여기서 여러가지 소비자가 생각하는 장기렌트의 문제점을 마주할 수 있었는데, 첫째 객관적인 자료 없이 서로 자기들이 싸다고 우기는 탓에 시작부터 지켜버린다. 둘째 내가 열심히 발품팔아서 견적을 요청해도 이게 지금 싼건지 비싼건지 도통 모르겠다. 셋째 장기렌트카 업체는 20곳도 넘는 것으로 알고 있는데, 아무리 노력해봤자 3곳이상 가격정보를 얻을 수 없다. 결국 요약해보면 제한된 시간 속에서 장기렌트의 가격을 찾는 여정은 엄청난 탐색비용을 거치게 되고, 그 중에서 한정된 정보 안에서 (최선은 만나보지도 못하고) 차선을 선택을 할 수 밖에 없는 구조이다.
차량 구조 : 브랜드 -> 차량 -> 엔진 -> 트림 -> 옵션
장기렌트 구조 : 50% 이상 3사 대기업 시장 점유, 하위 업체들의 마케팅 전쟁 (치킨게임)
역대카(alltime-car) 프로젝트는 바로 이 지점에서 시작되었다. 소비자가 특정 차량의 가격 변동 추이를 데이터에 기반해 명확히 인지하고, 적정한 가격을 확인하고 구매 시점을 판단할 수 있도록 돕는 것. 이 것이 요즘 현명한 소비를 추구하는 소비자를 잡는 핵심 가치라고 생각했다.
더 이상 소비자가 '감'이 아닌 '데이터'에 의존해 최적의 결정을 내릴 수 있는, 투명하고 합리적인 신차 장기렌트 시장을 구축해보면 어떨까.
기획은 원래 가볍다. 어 그냥 견적 받아서 가격 월단위로 모으면 되는거잖아? 쉽잖아? 그렇다. 원래 말은 쉬운 것이다. 최근 프로젝트를 기획해보며 느낀 점은 데이터구조
와 실현가능성
의 조화를 잘 이루어야 한다는 것을 배웠다. 확장성도 고려해야겠지만, 무리한 계획은 결국 암초를 만난다. 그럼 프로젝트는 당연 타이타닉처럼 좌초된다.
그래서 쉽게! 현대차 / 기아차 / 다나와 장기렌트 를 보며 DB 설계를 고민해보았다. 그리고 지금 특가 차량인 EV3를 프론트페이지에서 가격정보와 함께 보여주는 것을 목표로 잡았다. 왠지 할 수 있을 것 같았다. (역시 처음은 막연한 자신감이 필요하다)
개발 아키텍처 : 시스템을 구성하는 요소(component)는 무엇이며, 이 요소들이 어떻게 서로 관계를 맺고 상호작용하는지에 대한 규칙 설계
이제 역대카 프로젝트는 '무엇을' 만들 것인가는 도안이 나왔다. 이제 어떻게 만들 것인가에 대한 고민이다. 안정적이면서도 확장성 있는 서비스를 만들기 위해 그리고 비교적 최신 기술을 사용하려고 했다.
여러 개별 프로젝트 (예: admin, user, db, UI) 의 코드를 단일 Git 저장소에서 관리하는 개발 방식이다. 비교적 커진 프로젝트에서 코드의 일관성과 재사용성을 높여야겠다고 판단했다.
하나의 레포에 재사용성을 높이는 패키지 전략을 사용한다. 설정과 타입관리를 한 번에 진행한다. 원자적 리팩토링 및 변경이 가능하다. 특히 DB 관련 파일을 하나의 레포에서 관리하므로서 admin 과 service 에서 단 하나의 커밋으로 적용하여 안정성을 높인다.
npm, yarn 은 가라! 요즘은 pnpm : node_modules를 제대로 관리한다.
pnpm이 효율적인 저장 구조를 만들었다면, Turborepo는 그 위에 개발 워크플로우를 관리한다. turbo.json을 통해 작업의 효율을 극대화한다.
{
"$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가 알아서 의존 관계를 파악하고 올바른 순서대로 작업을 실행한다.
현대적인 웹 애플리케이션의 표준으로 자리 잡은 Next.js를 프레임워크 선택했다. 강력한 서버-사이드 렌더링(SSR)과 정적 사이트 생성(SSG) 기능은 뛰어난 성능과 검색 엔진 최적화(SEO)의 기반이 된다. 여기에 TypeScript를 더해, 데이터 기반 서비스의 핵심인 타입 안정성을 확보하고 잠재적인 버그를 사전에 방지한다. 빨간 줄 멈춰.
데이터베이스와의 상호작용은 타입 세이프한 Prisma ORM을 통해 관리한다. 복잡한 SQL 쿼리를 직관적인 코드로 작성하게 도와주며, 개발 생산성을 크게 높여준다. 백엔드 인프라는 오픈소스 Firebase 대안으로 각광받는 Supabase를 활용하여, 데이터베이스(PostgreSql)와 인증 시스템을 안정적으로 구축한다.
이 기술 블로그를 통해 '역대카' 프로젝트의 시작부터 현재까지, 내가 겪었던 치열한 고민과 문제 해결 과정을 공유하고자 한다. 이는 단순한 개발 기록을 넘어, 아이디어가 실제로 사용자의 행동과 연결과는 일련과정을 다룬다.
단순한 문제의식이 성취와 사업으로 연결되는 과정을 기대하시라.