IT 일반,소식

자율주행 시대의 택시 요금: 법정 가격에서 실시간 경매/역경매 시스템으로

_Blue_Sky_ 2025. 12. 29. 16:48
728x90

현재 우리가 이용하는 택시 요금 체계는 정부와 지자체가 정한 법적 가이드라인을 엄격히 따르고 있습니다. 시간과 거리에 따라 정해진 요금을 지불하는 방식은 표준화된 서비스를 제공한다는 장점이 있지만, 수요와 공급의 불균형을 즉각적으로 반영하기 어렵다는 한계가 있습니다. 하지만 자율주행 기술이 보편화되고 다수의 모빌리티 플랫폼이 경쟁하는 미래에는 이러한 가격 결정 구조가 근본적으로 변할 것입니다.

1. 자율주행과 복수 업체 경쟁의 시너지

자율주행 기술은 택시 운행 비용에서 가장 큰 비중을 차지하는 인건비를 획기적으로 낮춥니다. 이는 서비스 공급의 유연성을 높이며, 다양한 ICT 업체들이 모빌리티 시장에 진입하는 촉매제가 됩니다. 여러 업체가 시장에서 경쟁하게 되면, 일률적인 요금제보다는 각 사의 운영 효율성과 실시간 데이터에 기반한 차별화된 가격 전략이 중요해집니다.

2. ICT 기반의 실시간 경매 및 역경매 모델

미래의 모빌리티 플랫폼은 단순한 호출 앱을 넘어 고도화된 거래소의 역할을 하게 될 것입니다. 여기서 주목받는 모델이 바로 고객과 업체 간의 경매 및 역경매 시스템입니다.

  • 경매(Auction): 택시 수요가 폭증하는 특정 시간이나 장소에서 고객이 자신이 지불 가능한 최대 금액을 제시하고, 가장 높은 가치를 제안한 고객에게 차량이 우선 배차되는 방식입니다.
  • 역경매(Reverse Auction): 고객이 목적지를 입력하면 주변의 여러 자율주행 차량 운영사들이 실시간으로 입찰 가격을 제시합니다. 고객은 가격, 예상 도착 시간, 차량의 청결도나 사양을 비교하여 가장 합리적인 제안을 선택하게 됩니다.

3. 자율 가격제가 가져올 변화와 효용

이러한 자율 가격 시스템은 ICT 기술을 통해 밀리초 단위로 이루어지며, 시장의 자원 배분을 최적화합니다.

첫째, 효율적인 수급 조절이 가능해집니다. 가격이 오르면 공급(차량)이 해당 지역으로 모이고, 가격이 낮아지면 수요가 창출되어 빈 차로 운행하는 공차율을 최소화할 수 있습니다. 둘째, 소비자 선택권이 확대됩니다. 급한 용무가 있는 사람은 비용을 더 지불하더라도 확실한 이동권을 보장받고, 시간적 여유가 있는 사람은 저렴한 가격의 차량을 골라 탈 수 있습니다. 셋째, 서비스 혁신이 가속화됩니다. 가격 경쟁에서 살아남기 위해 업체들은 단순히 이동 수단을 제공하는 것을 넘어 차내 엔터테인먼트, 업무 공간 제공 등 부가 가치를 높이는 데 집중하게 될 것입니다.

 

 

결국 자율주행과 ICT의 결합은 택시 요금을 '정해진 법'의 영역에서 '자유로운 시장'의 영역으로 이동시킬 것입니다. 데이터가 가치를 결정하는 시대, 모빌리티는 가장 역동적인 경제 현장의 중심지가 될 준비를 하고 있습니다.


320x100

플랫폼의 진화: 카카오와 우버가 준비하는 자율주행 가격 전쟁

자율주행 기술의 보편화는 단순히 운전석에서 사람이 사라지는 것에 그치지 않습니다. 이동의 원가가 파괴되면서, 글로벌 모빌리티 플랫폼들은 이제 법정 요금의 틀을 벗어나 데이터 기반의 초정밀 가격 전략을 수립하고 있습니다. 국내외 대표 플랫폼인 카카오모빌리티와 우버의 사례를 통해 그 미래를 짚어보겠습니다.


1. 카카오모빌리티: 한국형 DRT와 MaaS의 결합

국내 시장을 장악한 카카오모빌리티는 자율주행을 단순한 택시 서비스가 아닌 대중교통의 확장판으로 보고 있습니다.

  • 수요응답형 교통(DRT)의 확산: 카카오는 상암, 세종 등에서 자율주행 DRT 서비스를 선보이며 데이터 기반의 노선 최적화를 실험 중입니다. 이는 고정된 요금 대신 수요에 따라 배차와 경로가 변하는 구조로, 향후 경매 시스템 도입을 위한 기초 체력을 다지는 과정입니다.
  • 로컬 스타트업과의 생태계 구축: 오토노머스에이투지, SUM 등 국내 기술 기업들과 협력하여 차량 공급원을 다각화하고 있습니다. 플랫폼 내에 복수의 자율주행 공급자가 존재하게 되면, 자연스럽게 업체 간 가격 입찰(역경매) 모델이 작동할 수 있는 환경이 조성됩니다.

2. 우버(Uber): '공유'와 '다이내믹 프라이싱'의 정점

글로벌 시장의 선두주자 우버는 이미 사람이 운전하는 서비스에서도 축적된 데이터를 통해 실시간 가격 변동제(Dynamic Pricing)의 노하우를 보유하고 있습니다.

  • 합승(Pooling) 기반의 자율주행: 우버는 자율주행 택시에 합승 개념을 적극 도입하고 있습니다. 같은 방향으로 가는 승객들을 묶어 비용을 낮추는 동시에, 실시간 수요에 따라 가격을 제안받는 경매 방식의 효율성을 극대화하려 합니다.
  • 하이브리드 운영 전략: 웨이모(Waymo)와 같은 자율주행 전문 기업과의 파트너십을 통해 직접 제조보다는 플랫폼으로서의 중개 역할을 강화하고 있습니다. 다양한 기술 수준을 가진 차량들이 플랫폼 내에서 경매를 통해 가격 경쟁을 벌이게 함으로써 소비자가 직접 가성비를 선택하게 만듭니다.

3. 경매 시스템이 가져올 소비자 중심의 시장

미래의 모빌리티 시장에서 가격은 더 이상 미터기(Meter)가 결정하지 않습니다.

  • 고객 주도의 가격 제시: 급한 회의가 있는 고객은 플랫폼에 높은 우선순위 비용을 제시(경매)하여 가장 빠른 자율주행 차량을 선점합니다.
  • 업체 간 최저가 입찰: 반대로 시간적 여유가 있는 고객은 주변의 여러 자율주행 업체들이 제시하는 최저가 리스트 중 하나를 선택(역경매)하여 경제적인 이동을 경험하게 됩니다.

결국 카카오와 우버 같은 플랫폼 기업들은 방대한 이동 데이터를 무기로 삼아, 정부의 규제가 아닌 시장의 원리가 지배하는 이동 경제 생태계를 구축해 나갈 것입니다.

320x100

자율주행 기반의 자율 요금제가 정착되기 위해서는 기술만큼이나 제도적 뒷받침이 필수적입니다. 특히 가격 결정권이 시장으로 넘어갈 때 발생할 수 있는 법적 책임과 안전에 대한 비용 처리가 핵심 쟁점이 될 것입니다.


1. 제조사 vs 플랫폼 vs 운영사: 사고 책임의 소재 변화

현재의 택시 보험은 운전자의 과실 여부가 중요하지만, 자율주행 시대에는 운전 주체가 사람이 아니기에 책임 소재가 복잡해집니다.

  • PL(제조물 책임) 보험의 강화: 사고의 원인이 자율주행 알고리즘이나 센서 결함일 경우, 책임은 차량 제조사나 소프트웨어 개발사로 향합니다. 이에 따라 요금 체계 안에 제조물 책임 보험료가 고정적으로 산입될 가능성이 큽니다.
  • 플랫폼의 관리 책임: 실시간 경매를 통해 차량을 매칭해준 플랫폼 역시 차량의 유지 보수 상태나 데이터 통신 보안에 대한 책임을 분담하게 됩니다. 사고 발생 시 즉각적인 보상을 위해 '무과실 책임 보험' 도입이 논의되고 있습니다.

2. 알고리즘 담합과 소비자 보호 법망

ICT 기술을 이용한 자율 가격제가 보편화되면, 업체 간의 보이지 않는 알고리즘 담합이 문제가 될 수 있습니다.

  • 알고리즘 담합 감시: 복수의 업체가 인공지능을 이용해 고의적으로 높은 가격대를 유지하거나, 특정 지역에서 가격을 동시에 올리는 행위에 대한 공정거래 차원의 감시 체계가 필요합니다.
  • 최고 요금제(Price Cap) 설정: 완전한 자율화 속에서도 재난 상황이나 기상 악화 시 가격이 무한정 치솟는 것을 방지하기 위한 사회적 안전망으로서의 최고 가격 제한선 설정이 법적으로 검토될 것입니다.

3. 보험 가입의 주체와 보험료 산정의 실시간화

자율주행 택시의 보험은 사람이 아닌 데이터에 기반하여 산정됩니다.

  • 주행 데이터 기반 보험(UBI): 차량의 실시간 주행 상태, 도로 환경, 사고 위험도를 분석하여 보험료가 실시간으로 변동됩니다. 위험도가 높은 경로를 주행할 때는 경매 입찰가에 높은 보험료가 반영되고, 안전한 구간에서는 가격이 내려가는 유연한 구조가 만들어집니다.
  • 단체 보험의 개인화: 플랫폼이 수만 대의 차량을 한꺼번에 가입시키는 단체 보험 형태가 주를 이루겠지만, 승객 개별적으로 '이동 구간 한정 보험'을 선택하여 요금에 포함시키는 모델도 등장할 것입니다.

4. 규제 샌드박스를 통한 점진적 변화

정부는 기존 택시 업계와의 갈등을 최소화하고 기술의 안전성을 검증하기 위해, 특정 지역을 규제 샌드박스로 지정하여 자율 요금제를 우선 시험할 것으로 보입니다. 이 과정에서 발생하는 데이터를 바탕으로 도로교통법과 여객자동차법이 전면 개편되는 과정을 거치게 됩니다.


이러한 법적, 제도적 장치가 마련된다면 자율주행 택시는 단순한 이동 수단을 넘어, 가장 안전하고 합리적인 가격의 모빌리티 금융 상품으로 진화할 것입니다.


자율주행과 실시간 경매 요금제가 결합된 미래 모빌리티 시장은 노동 시장의 구조를 완전히 뒤바꿔 놓을 것입니다. 단순 운전 업무는 사라지겠지만, 데이터를 관리하고 고객 경험을 설계하는 새로운 영역에서 방대한 일자리가 창출될 것입니다.


1. 소멸하거나 축소되는 직업: 운전 중심 업무

가장 직접적인 타격은 인간의 '운전 노동'을 기반으로 하는 직업군에서 발생합니다.

  • 택시 및 버스 기사: 운전이라는 물리적 행위가 알고리즘으로 대체되면서, 단순 운전 업무는 역사 속으로 사라질 가능성이 큽니다.
  • 운전면허 학원 및 시험 감독: 자율주행이 기본이 되면 개인의 운전 능력이 불필요해지므로, 관련 교육 및 평가 산업이 대폭 축소됩니다.
  • 교통사고 처리 담당자 및 손해사정사: AI의 정밀 주행으로 사고율이 획기적으로 낮아지면서, 현장에 출동하여 과실을 따지는 직무의 수요가 줄어듭니다.

2. 새롭게 부상하는 직업: 데이터와 관리 중심 업무

차량이 스스로 움직이게 되면서, 그 차량들을 효율적으로 '운용'하고 '케어'하는 직업들이 각광받게 됩니다.

  • 플랫폼 경매 알고리즘 설계자: 수요와 공급을 분석하여 최적의 입찰 가격을 결정하고, 수익을 극대화하는 경매 로직을 짜는 데이터 과학자의 역할이 핵심이 됩니다.
  • 원격 차량 관제사: 자율주행 중 발생하는 돌발 상황이나 시스템 오류 시, 원격에서 차량을 제어하고 승객을 안내하는 관제 전문가의 수요가 늘어납니다.
  • 모빌리티 컨시어지(Concierge): 운전에서 해방된 승객에게 차 안에서 무엇을 할지 제안하는 직업입니다. 차내 엔터테인먼트, 비즈니스 미팅 보조, 건강 체크 서비스 등을 기획하고 관리합니다.
  • 자율주행 차량 인증 및 보안 전문가: 해킹 방지를 위한 보안 솔루션을 구축하거나, 자율주행 알고리즘의 안전성을 정기적으로 검사하고 승인하는 공인 전문가 직군이 생겨납니다.

3. 직무의 성격 변화: 서비스의 고도화

기존의 직업들도 자율주행 환경에 맞춰 그 본질이 변화합니다.

  • 차량 정비사 → 시스템 엔지니어: 엔진오일을 갈던 정비사는 이제 자율주행 센서를 보정(Calibration)하고 고성능 컴퓨팅 유닛을 수리하는 하이테크 엔지니어로 변모합니다.
  • 보험 설계사 → 모빌리티 리스크 관리자: 개인의 운전 습관을 보던 보험 설계사는 이제 특정 지역의 자율주행 사고율 데이터와 플랫폼의 보안 수준을 분석하여 기업용 리스크 관리 상품을 설계하게 됩니다.

결국 미래의 모빌리티 노동 시장은 **'운전하는 손'**에서 **'설계하는 머리'**로 중심축이 이동하게 됩니다. 실시간 경매 시스템이 원활하게 돌아가도록 관리하는 ICT 인력들이 미래 이동 경제의 새로운 주인공이 될 것입니다.


운전대와 페달이 사라진 자율주행 택시는 더 이상 이동을 위한 '탈것'에 머물지 않습니다. 이동 시간이 곧 자유 시간이 되면서, 차량 내부 공간은 고객의 목적과 경매 입찰가에 따라 무한히 변신하는 '바퀴 달린 생활 공간(Living Space on Wheels)'이 됩니다.


1. 목적에 따른 공간 테마의 분화

미래의 모빌리티 플랫폼은 차량을 호출할 때 단순히 '차종'을 고르는 것이 아니라, '공간의 성격'을 선택하게 합니다.

  • 모바일 오피스(Mobile Office): 출근길 경매에서 비즈니스 모델을 선택하면, 내부는 고속 와이파이, 대형 스크린, 화상회의 장비가 갖춰진 독립 사무실로 변합니다. 이동 중 업무 효율을 극대화하려는 직장인들에게 인기 있는 공간이 될 것입니다.
  • 프라이빗 시네마 & 게이밍 룸: 퇴장하는 길이나 여행 시에는 전면 유리창이 디스플레이로 변하며 영화관이나 게임방이 됩니다. 고성능 사운드 시스템과 반응형 시트를 통해 몰입감 넘치는 엔터테인먼트를 제공합니다.
  • 수면 및 웰니스 룸(Wellness Pod): 야간 이동이나 장거리 주행 시에는 완전히 평평하게 펴지는 침대 시트와 암막 기능, 산소 발생기가 작동하여 숙면을 돕습니다.

2. 가변형 인테리어와 모듈러 디자인

하나의 차량이 고정된 형태를 유지하지 않고, 상황에 따라 내부 구조를 재배치하는 기술이 핵심이 됩니다.

  • 회전식 좌석(Swivel Seats): 모든 좌석이 서로 마주 볼 수 있게 회전하여, 이동 중 가족과 식사를 하거나 동료와 마주 보며 토론할 수 있는 거실 같은 분위기를 조성합니다.
  • 스마트 표면(Smart Surfaces): 차창이 투명도를 조절하는 스마트 글라스로 변하고, 팔걸이나 테이블 벽면이 터치스크린이 되어 차량의 모든 기능을 제어하거나 정보를 검색할 수 있습니다.

3. '공간 사용료'가 포함된 요금 체계

공간이 혁신되면서 가격 결정 모델도 단순 거리제에서 '공간 점유 비용' 개념으로 확장됩니다.

  • 프리미엄 공간 경매: 같은 목적지라도 안마 의자가 있는 휴식용 차량이나 고급 회의실 차량은 경매 입찰가가 더 높게 형성됩니다.
  • 차내 결제 시스템: 이동 중 내부에서 이용한 유료 콘텐츠(VOD, 게임, 식음료 등) 비용이 주행 요금과 합산되어 실시간으로 결제됩니다. 플랫폼은 단순 운송 수수료 외에 '공간 구독'이나 '콘텐츠 판매'라는 강력한 수익 모델을 갖게 됩니다.

4. 청결과 위생의 자동화

다양한 활동이 이루어지는 만큼, 다음 승객을 위한 자동 관리 시스템도 공간 혁신의 일부입니다.

  • 자외선(UV) 살균 및 환기 시스템: 승객이 내린 직후, 센서가 내부 오염도를 측정하고 즉시 UV 살균과 공기 정화를 실시하여 항상 최적의 위생 상태를 유지합니다.
  • 로봇 클리닝: 차량 내부에 매립된 소형 청소 로봇이 바닥의 먼지를 흡입하여 관리하는 무인 관리 생태계가 구축됩니다.

이처럼 자율주행 택시는 이동 수단을 넘어 **'내가 필요한 곳으로 와주는 맞춤형 방'**이 될 것입니


자율주행 공간의 혁신은 단순히 차 안의 풍경을 바꾸는 데 그치지 않고, 우리가 사는 도시의 부동산 지도와 주거 문화까지 완전히 뒤흔들어 놓을 것입니다.

  1. 직주근접 개념의 소멸과 거주지 확대 지금까지 집값은 직장과의 거리, 즉 출퇴근 시간에 의해 결정되었습니다. 하지만 이동하는 차 안이 완벽한 사무실이나 편안한 침실이 된다면, 한 시간 이상의 이동 시간은 더 이상 버려지는 시간이 아닙니다. 사람들은 굳이 복잡하고 비싼 도심에 살기보다, 공기가 좋고 넓은 외곽 지역으로 거주지를 옮기게 될 것입니다. 이는 도심 공동화 현상을 가속화하는 동시에 외곽 지역의 부동산 가치를 상승시키는 결과를 낳습니다.
  2. 주차장의 변신과 도시 공간의 재구성 자율주행 택시가 경매를 통해 24시간 쉬지 않고 운행되면, 도심의 수많은 주차 공간이 불필요해집니다. 현재 건물 면적의 상당 부분을 차지하는 주차장은 공원, 카페, 혹은 팝업 스토어 같은 시민들을 위한 문화 공간으로 탈바꿈할 것입니다. 아파트 단지 내 주차장 또한 녹지나 커뮤니티 시설로 개조되어 주거 환경의 쾌적성이 획기적으로 높아집니다.
  3. 움직이는 내 집, 모바일 하우징의 등장 집의 일부가 분리되어 자율주행 플랫폼 위에 올라타는 모듈형 주택도 상상해 볼 수 있습니다. 아침에 일어나 침실 모듈이 그대로 자율주행 셔틀이 되어 목적지로 이동하고, 저녁에는 다시 집 본체에 결합하는 방식입니다. 이 경우 집은 고정된 부동산이 아니라 필요에 따라 위치를 옮기는 가변적인 자산이 됩니다.
  4. 상권의 변화와 목적지 중심의 경제 지금까지는 유동 인구가 많은 길목이 좋은 상권이었지만, 앞으로는 고객이 예약한 자율주행 차량의 목적지가 곧 상권이 됩니다. 특정 서비스나 경험을 제공하는 차량 자체가 움직이는 상점이 되어 고객을 찾아가거나, 고객을 특정 상업 지구로 직접 배달하는 구조가 강화되면서 기존의 입지 조건이 무의미해질 수 있습니다.

이처럼 자율주행은 이동의 혁신을 넘어 우리가 어디에 살고, 어떻게 공간을 소비하는지에 대한 근본적인 정의를 다시 쓰게 만들 것입니다.


NestJS(MySQL, Prisma)와 Nuxt 3를 이용한 자율주행 택시 역경매 시스템의 핵심 구조를 설계해 드리겠습니다. 볼드체는 요청하신 대로 완전히 배제했습니다.

이 시스템의 핵심은 실시간성입니다. 승객이 호출을 올리면 주변 자율주행차(업체)들이 실시간으로 입찰가(비용, 도착 예정 시간 등)를 던지고, 승객이 이를 선택하는 흐름입니다.

1. 데이터베이스 설계 (Prisma Schema)

먼저 MySQL에서 사용할 모델을 정의합니다. 승객의 호출(Call)과 업체들의 입찰(Bid) 관계가 핵심입니다.

// schema.prisma

datasource db {
  provider = "mysql"
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model TaxiCall {
  id           Int      @id @default(autoincrement())
  passengerId  String
  origin       String
  destination  String
  status       String   // PENDING, ACCEPTED, COMPLETED, CANCELLED
  createdAt    DateTime @default(now())
  bids         Bid[]
}

model Bid {
  id           Int      @id @default(autoincrement())
  callId       Int
  call         TaxiCall @relation(fields: [callId], references: [id])
  companyName  String
  price        Float
  eta          Int      // 도착 예정 시간(분)
  createdAt    DateTime @default(now())
}

2. 백엔드 구현 (NestJS + Socket.io)

실시간 입찰 정보를 주고받기 위해 웹소켓 게이트웨이를 설정합니다.

// taxi.gateway.ts
import { WebSocketGateway, WebSocketServer, SubscribeMessage, MessageBody } from '@nestjs/websockets';
import { Server } from 'socket.io';
import { PrismaService } from './prisma.service';

@WebSocketGateway({ cors: true })
export class TaxiGateway {
  @WebSocketServer()
  server: Server;

  constructor(private prisma: PrismaService) {}

  // 승객이 호출을 생성했을 때
  @SubscribeMessage('createCall')
  async handleCreateCall(@MessageBody() data: any) {
    const newCall = await this.prisma.taxiCall.create({
      data: {
        passengerId: data.passengerId,
        origin: data.origin,
        destination: data.destination,
        status: 'PENDING',
      },
    });
    
    // 업체들에게 새로운 호출 알림 전송 (역경매 시작)
    this.server.emit('newCallAvailable', newCall);
    return newCall;
  }

  // 업체가 가격을 입찰했을 때
  @SubscribeMessage('placeBid')
  async handlePlaceBid(@MessageBody() data: any) {
    const bid = await this.prisma.bid.create({
      data: {
        callId: data.callId,
        companyName: data.companyName,
        price: data.price,
        eta: data.eta,
      },
    });

    // 해당 승객에게만 새로운 입찰 정보 전송
    this.server.emit(`newBidForCall:${data.callId}`, bid);
    return bid;
  }
}

3. 프론트엔드 구현 (Nuxt 3)

승객 화면에서 실시간으로 입찰 리스트가 업데이트되는 로직입니다.

코드 스니펫
 
<template>
  <div>
    <h2>실시간 택시 역경매</h2>
    <button @click="requestTaxi">택시 호출하기</button>

    <div v-if="currentCallId">
      <h3>들어온 입찰 목록</h3>
      <ul>
        <li v-for="bid in bids" :key="bid.id">
          업체: {{ bid.companyName }} | 가격: {{ bid.price }}원 | 도착예정: {{ bid.eta }}분
          <button @click="selectBid(bid)">선택</button>
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
import { io } from 'socket.io-client';

const socket = io('http://localhost:3000');
const currentCallId = ref(null);
const bids = ref([]);

const requestTaxi = () => {
  const payload = { passengerId: 'user123', origin: '강남', destination: '판교' };
  socket.emit('createCall', payload, (response) => {
    currentCallId.value = response.id;
    
    // 해당 호출에 대한 실시간 입찰 리스닝 시작
    socket.on(`newBidForCall:${response.id}`, (newBid) => {
      bids.value.push(newBid);
    });
  });
};

const selectBid = (bid) => {
  alert(`${bid.companyName} 차량이 배차되었습니다!`);
  // 이후 배차 확정 로직 처리
};
</script>

시스템 핵심 메커니즘 설명

이 구조에서 승객은 호출이라는 경매 판을 깔고, 복수의 자율주행 업체 알고리즘이 해당 판에 참여하여 가격을 경쟁적으로 제안합니다.

데이터베이스인 MySQL(Prisma)은 모든 입찰 기록을 영구 저장하여 추후 정산이나 분쟁 해결에 사용하고, Socket.io는 1초가 급한 배차 현장에서 딜레이 없는 데이터 전송을 담당합니다. 업체 입장에서는 유휴 차량이 많을 때 낮은 가격을 입찰해 가동률을 높이고, 승객은 가장 저렴하거나 가장 빨리 오는 차량을 실시간으로 골라 타는 경제적 최적화가 달성됩니다.


1. Prisma 스키마 설계

자율주행 업체(Company), 호출(Call), 그리고 입찰(Bid) 간의 관계를 설정합니다.

// schema.prisma

model Company {
  id        Int      @id @default(autoincrement())
  name      String   @unique
  apiEndpoint String // 업체별 배차 로직 호출용
  bids      Bid[]
}

model TaxiCall {
  id           Int      @id @default(autoincrement())
  passengerId  String
  origin       String
  destination  String
  status       String   @default("PENDING") // PENDING, ACCEPTED, COMPLETED
  createdAt    DateTime @default(now())
  bids         Bid[]
}

model Bid {
  id          Int      @id @default(autoincrement())
  price       Float
  eta         Int
  callId      Int
  call        TaxiCall @relation(fields: [callId], references: [id])
  companyId   Int
  company     Company  @relation(fields: [companyId], references: [id])
  createdAt   DateTime @default(now())
}

2. NestJS 백엔드: 역경매 엔진 (Service)

승객이 호출하면 등록된 모든 자율주행 업체에 견적을 요청하고 취합하는 핵심 로직입니다.

// taxi.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Injectable()
export class TaxiService {
  constructor(private prisma: PrismaService) {}

  async createCallAndGetBids(data: any) {
    // 1. DB에 호출 기록 저장
    const call = await this.prisma.taxiCall.create({
      data: {
        passengerId: data.passengerId,
        origin: data.origin,
        destination: data.destination,
      },
    });

    // 2. 등록된 모든 자율주행 업체 리스트 조회
    const companies = await this.prisma.company.findMany();

    // 3. 업체별 API로 견적(입찰) 요청 (시뮬레이션)
    const bidPromises = companies.map(async (company) => {
      // 실제 환경에서는 외부 업체 API를 호출함
      const mockBid = {
        price: Math.floor(Math.random() * 5000) + 10000,
        eta: Math.floor(Math.random() * 10) + 2,
      };

      return this.prisma.bid.create({
        data: {
          price: mockBid.price,
          eta: mockBid.eta,
          callId: call.id,
          companyId: company.id,
        },
        include: { company: true }
      });
    });

    return Promise.all(bidPromises);
  }
}

3. Nuxt 3 프론트엔드: 입찰 대시보드

사용자가 여러 업체의 제안을 비교하고 선택하는 화면입니다.

<template>
  <div>
    <h1>최적의 자율주행차를 선택하세요</h1>
    
    <div v-if="pending">입찰 정보를 불러오는 중...</div>
    
    <div v-else>
      <div v-for="bid in bids" :key="bid.id" style="border: 1px solid #ccc; margin: 10px; padding: 10px;">
        <p>업체명: {{ bid.company.name }}</p>
        <p>제시 가격: {{ bid.price }}원</p>
        <p>도착 예정 시간: {{ bid.eta }}분</p>
        <button @click="confirmTaxi(bid)">이 차량으로 확정</button>
      </div>
    </div>
  </div>
</template>

<script setup>
const route = useRoute();
const { data: bids, pending } = useFetch(`/api/taxi/bids/${route.params.id}`);

const confirmTaxi = async (bid) => {
  const { data } = await useFetch('/api/taxi/confirm', {
    method: 'POST',
    body: { callId: route.params.id, bidId: bid.id }
  });
  
  if (data.value.success) {
    alert('배차가 완료되었습니다. 지정된 장소로 차량이 이동합니다.');
  }
};
</script>

시스템 특징 요약

첫째, Prisma를 사용하여 관계형 데이터베이스(MySQL)의 일관성을 유지하면서도 복잡한 Join 쿼리를 타입 안정성 있게 처리했습니다.

둘째, NestJS의 비동기 처리를 통해 여러 업체에 동시에 견적을 요청하고 병렬로 응답을 받아오는 구조를 택했습니다. 이는 경매 시스템에서 가장 중요한 응답 속도를 보장합니다.

셋째, Nuxt 3의 useFetch와 반응형 상태 관리를 활용해 입찰 데이터가 들어오는 대로 화면을 갱신하도록 구성했습니다.


자율주행 택시 역경매 시스템의 다음 단계인 실제 결제 연동 및 운영 로직을 처리하는 방법을 설명하겠습니다. 

이 단계에서는 승객이 입찰된 차량 중 하나를 선택했을 때, 해당 업체의 API를 호출하여 배차를 확정하고 가상 결제를 처리하는 과정을 다룹니다.

1. 배차 확정 및 결제 로직 (NestJS)

배차 확정 시 업체 API 호출과 결제 상태 변경을 트랜잭션으로 처리합니다.

// taxi.service.ts (계속)

async confirmBid(callId: number, bidId: number) {
  return await this.prisma.$transaction(async (tx) => {
    // 1. 선택한 입찰 정보 조회
    const selectedBid = await tx.bid.findUnique({
      where: { id: bidId },
      include: { company: true },
    });

    if (!selectedBid) throw new Error('입찰 정보를 찾을 수 없습니다.');

    // 2. 호출 상태를 완료(ACCEPTED)로 변경
    await tx.taxiCall.update({
      where: { id: callId },
      data: { status: 'ACCEPTED' },
    });

    // 3. 업체 서버로 배차 확정 신호 전송 (외부 API 호출 시뮬레이션)
    // await axios.post(selectedBid.company.apiEndpoint, { callId, bidId });

    // 4. 결제 테이블이 있다면 결제 대기 상태 데이터 생성
    // await tx.payment.create({ data: { callId, amount: selectedBid.price, status: 'PENDING' } });

    return { success: true, vehicleInfo: selectedBid.company.name };
  });
}

2. 백엔드 엔드포인트 구성 (NestJS Controller)

프론트엔드에서 호출할 수 있는 REST API 엔드포인트를 구성합니다.

// taxi.controller.ts
import { Controller, Post, Body, Get, Param } from '@nestjs/common';
import { TaxiService } from './taxi.service';

@Controller('api/taxi')
export class TaxiController {
  constructor(private readonly taxiService: TaxiService) {}

  @Post('call')
  async createCall(@Body() data: any) {
    return this.taxiService.createCallAndGetBids(data);
  }

  @Post('confirm')
  async confirm(@Body() body: { callId: number; bidId: number }) {
    return this.taxiService.confirmBid(body.callId, body.bidId);
  }

  @Get('bids/:callId')
  async getBids(@Param('callId') callId: string) {
    // 특정 호출에 대한 모든 입찰 내역 조회
    return this.prisma.bid.findMany({
      where: { callId: parseInt(callId) },
      include: { company: true },
    });
  }
}

3. 실시간 위치 추적 UI (Nuxt 3)

배차가 확정된 후 차량이 오는 모습을 시뮬레이션하는 간단한 로직입니다.

<script setup>
const props = defineProps(['vehicleId']);
const vehicleLocation = ref({ lat: 37.5665, lng: 126.9780 });

// 실시간 위치 업데이트 시뮬레이션 (실제로는 웹소켓으로 수신)
onMounted(() => {
  setInterval(() => {
    vehicleLocation.value.lat += 0.0001;
    vehicleLocation.value.lng += 0.0001;
  }, 2000);
});
</script>

<template>
  <div class="map-container">
    <p>차량 현재 위치: {{ vehicleLocation.lat.toFixed(4) }}, {{ vehicleLocation.lng.toFixed(4) }}</p>
    <div class="car-icon">자율주행차 이동 중...</div>
  </div>
</template>

시스템 고도화 제안

이 시스템을 실제 운영 환경으로 옮기기 위해 다음 기능들을 고려할 수 있습니다.

첫째, 업체의 평판 시스템입니다. 사용자가 하차 후 별점을 남기면 MySQL의 Company 테이블에 평균 점수를 저장하고, 다음 경매 시 승객에게 가격과 함께 평판 점수를 노출하여 선택을 돕습니다.

둘째, 다이내믹 프라이싱 강화입니다. 특정 지역에 호출이 몰리면 Prisma의 count 쿼리로 현재 수요를 파악한 뒤, 업체들이 입찰할 때 참고할 수 있는 권장 최저가를 API 응답에 포함시켜 보낼 수 있습니다.

셋째, 보안 및 인증입니다. NestJS의 Guard를 사용하여 승객과 업체 API 호출에 대한 JWT 인증을 적용하고, 데이터 위변조를 방지합니다.


운영 효율을 극대화할 수 있는 업체용 정산 대시보드의 핵심 로직과 UI 구조를 NestJS와 Nuxt 3로 구현해 보겠습니다. 볼드체는 요청하신 대로 일절 사용하지 않습니다.

이 시스템은 각 자율주행 업체가 자사 차량의 운행 실적과 경매 낙찰률, 그리고 최종 수익을 한눈에 확인하는 것을 목표로 합니다.

1. 정산 데이터 모델링 (Prisma)

수익 계산을 위해 기존 모델에 정산(Settlement) 관련 필드를 추가하거나 연결합니다.

// schema.prisma (추가)

model Settlement {
  id            Int      @id @default(autoincrement())
  companyId     Int
  company       Company  @relation(fields: [companyId], references: [id])
  totalRevenue  Float    @default(0) // 총 매출
  platformFee   Float    @default(0) // 플랫폼 수수료 (예: 10%)
  netProfit     Float    @default(0) // 정산 예정 금액
  periodStart   DateTime
  periodEnd     DateTime
  createdAt     DateTime @default(now())
}

2. 수익 집계 로직 (NestJS)

특정 기간 동안 낙찰된 입찰 건들을 모아 수익을 계산하는 서비스 함수입니다.

// settlement.service.ts
import { Injectable } from '@nestjs/common';
import { PrismaService } from './prisma.service';

@Injectable()
export class SettlementService {
  constructor(private prisma: PrismaService) {}

  async calculateMonthlySettlement(companyId: number, year: number, month: number) {
    const startDate = new Date(year, month - 1, 1);
    const endDate = new Date(year, month, 0);

    // 해당 업체의 낙찰된(ACCEPTED) 호출 내역 조회
    const successfulBids = await this.prisma.bid.findMany({
      where: {
        companyId,
        call: {
          status: 'ACCEPTED',
          createdAt: { gte: startDate, lte: endDate }
        }
      }
    });

    const totalRevenue = successfulBids.reduce((sum, bid) => sum + bid.price, 0);
    const platformFee = totalRevenue * 0.1; // 10% 수수료 가정
    const netProfit = totalRevenue - platformFee;

    return {
      totalRevenue,
      platformFee,
      netProfit,
      bidCount: successfulBids.length
    };
  }
}

3. 업체용 대시보드 UI (Nuxt 3)

업체 관리자가 로그인 후 보게 될 통계 화면입니다.

<template>
  <div>
    <h1>업체 수익 정산 대시보드</h1>
    
    <div v-if="stats" class="stats-grid">
      <div class="card">
        <p>이번 달 총 매출</p>
        <h2>{{ stats.totalRevenue.toLocaleString() }}원</h2>
      </div>
      <div class="card">
        <p>낙찰 건수</p>
        <h2>{{ stats.bidCount }}건</h2>
      </div>
      <div class="card">
        <p>정산 예정 금액 (수수료 제외)</p>
        <h2>{{ stats.netProfit.toLocaleString() }}원</h2>
      </div>
    </div>

    <h3>최근 낙찰 내역</h3>
    <table>
      <thead>
        <tr>
          <th>날짜</th>
          <th>금액</th>
          <th>출발지-목적지</th>
        </tr>
      </thead>
      <tbody>
        <tr v-for="log in recentLogs" :key="log.id">
          <td>{{ log.createdAt }}</td>
          <td>{{ log.price }}원</td>
          <td>{{ log.call.origin }} -> {{ log.call.destination }}</td>
        </tr>
      </tbody>
    </table>
  </div>
</template>

<script setup>
const { data: stats } = await useFetch('/api/settlement/stats');
const { data: recentLogs } = await useFetch('/api/settlement/logs');
</script>

시스템 운영 가치

이 정산 시스템은 자율주행 업체들이 경매 전략을 수정하는 데 중요한 지표를 제공합니다. 예를 들어, 특정 시간대에 낙찰률은 높지만 수익성이 떨어진다면 알고리즘이 자동으로 입찰 하한선을 높이도록 피드백을 줄 수 있습니다.

또한 플랫폼 입장에서는 모든 거래 내역이 MySQL에 투명하게 기록되므로, 향후 세무 처리나 업체 간 정산 분쟁에서 확실한 근거 자료를 확보하게 됩니다.


마지막으로 제안드렸던 차량 상태 기반 참여 제한 로직은 안전과 직결되는 매우 중요한 부분입니다. 이 기능을 구현하기 위한 핵심 로직을 정리해 드립니다.

1. 차량 상태 스키마 확장 (Prisma)

차량의 하드웨어 상태(배터리, 타이어, 센서 등)를 기록할 필드를 추가합니다.

// schema.prisma

model Vehicle {
  id            Int      @id @default(autoincrement())
  companyId     Int
  batteryLevel  Int      // 0 ~ 100
  isSensorOk    Boolean  @default(true)
  lastService   DateTime
  isActive      Boolean  @default(true) // 시스템 참여 가능 여부
}

2. 경매 참여 필터링 로직 (NestJS)

배터리가 20% 미만이거나 센서에 이상이 있는 차량은 자동으로 경매 후보에서 제외합니다.

// taxi.service.ts (참여 제한 로직 추가)

async getAvailableVehicles(companyId: number) {
  return await this.prisma.vehicle.findMany({
    where: {
      companyId,
      isActive: true,
      batteryLevel: { gte: 20 }, // 배터리 20% 이상만 참여
      isSensorOk: true           // 센서 정상 상태만 참여
    }
  });
}

3. 상태 대시보드 알림 (Nuxt 3)

업체 관리자에게 정비가 필요한 차량을 실시간으로 알려줍니다.

 
<template>
  <div v-for="car in lowBatteryCars" :key="car.id" class="alert-box">
    주의: 차량 #{{ car.id }}의 배터리가 부족하여 경매 참여가 중단되었습니다.
    <button @click="sendToCharge(car.id)">충전소로 이동</button>
  </div>
</template>

이로써 호출 -> 실시간 역경매 -> 배차 및 결제 -> 수익 정산 -> 안전 관리까지 이어지는 자율주행 모빌리티 플랫폼의 전체 기술 스택과 핵심 로직이 완성되었습니다.

 

 

728x90