플랫폼의 UI/UX를 개편했다고 하면 흔히 디자인 변경이나 사용성 개선을 떠올린다. 하지만 이번 레인디어스 플랫폼의 UI/UX 개편은 그런 종류의 작업이 아니었다. 화면은 결과였고, 실제 변경의 중심은 주문과 견적을 해석하는 내부 구조였다.
고객사, 공급사, 포워딩이 동시에 사용하는 플랫폼에서 UI는 단순한 인터페이스가 아니라 각 주체가 현재 상황을 어떻게 인식하는지를 결정한다. 이 인식이 어긋나면, 기술적으로는 정상이어도 운영은 항상 충돌한다. 레인디어스에는 바이어 2,500곳 이상과 공급사 1,800곳 이상, 포워딩 업체 30곳 이상이 참여하고 있다. 이 4,300개 이상의 파트너가 동일한 주문을 서로 다른 관점에서 바라본다는 것은, 화면 하나의 문제가 곧 운영 전체의 문제가 된다는 뜻이다.
문제의 시작: 상태는 같았지만, 의미는 달랐다
기존 UI에서 가장 심각했던 문제는 같은 주문을 보고 있음에도 각 사용자가 전혀 다른 단계라고 인식한다는 점이었다.
- 고객사 화면에서는 "주문 완료"
- 공급사 화면에서는 "확정 전"
- 포워딩 화면에서는 "조건 미정"
데이터상 상태 값은 일치했지만,
그 상태가 의미하는 바는 사용자 역할마다 달랐다.
이는 단순한 UI 문제처럼 보였지만,
실제로는 주문 흐름 자체가 단선 구조로 설계되어 있었기 때문이었다.
기존에는 하나의 상태 필드가 모든 역할에 동일하게 노출되었다. ORDER_PLACED라는 상태가 구매자에게는 "주문을 넣었으니 기다리면 된다"였지만, 공급사에게는 "아직 내가 수락하지 않은 요청"이었고, 포워딩 업체에게는 "물류 조건이 아직 정의되지 않은 건"이었다. 하나의 상태 값이 세 가지 해석을 만들어내고 있었다.
UI 개편의 전제 조건: Draft 개념의 도입
UI를 바꾸기 전에 먼저 한 일은, 주문과 물류 흐름을 다시 정의하는 것이었다.
모든 프로세스의 중심에 Draft 개념을 두었다. 확정되지 않은 것은 확정되지 않은 상태로 명확히 표현하도록 했다.
- Draft Purchase Order
- Draft Delivery Order
- Draft Forwarding Quote
이 구조가 만들어진 이후에야
"지금 이 화면에서 사용자가 무엇을 결정할 수 있는가"를
UI로 정확히 표현할 수 있게 되었다.
Draft 상태의 객체는 생성자만 수정할 수 있고, 확정 액션을 취해야만 다음 단계로 전이된다.
이 규칙은 데이터베이스 레벨에서 강제된다. Turso(LibSQL) 기반 스토리지에서
Draft 상태의 레코드는 confirmed_at 필드가 NULL이며,
이 필드가 채워지기 전까지는 하위 객체 생성이 차단된다.
UI/UX 개편의 핵심 원칙
이번 개편에서 지킨 원칙은 단순했다.
- 입력이 아니라 의사결정 중심의 화면
- 상태 값이 아니라 의미가 보이는 상태 표현
- 다음 액션이 없는 버튼은 존재하지 않음
예를 들어, 기존에는 "주문 수정" 버튼이 항상 활성화되어 있었지만, 개편 이후에는 현재 단계에서 수정 가능한 항목만 노출되도록 변경되었다. 기술적으로는 권한 제어보다 훨씬 복잡한 작업이었다. 각 버튼의 활성화 조건은 단순 권한 체크가 아니라, 현재 주문 상태, 사용자 역할, 연결된 하위 객체들의 상태를 종합적으로 판단하는 로직이다. Next.js 프론트엔드에서 이 판단 로직을 컴포넌트마다 중복 작성하지 않기 위해, 상태 해석 레이어를 별도로 분리하고 서버 컴포넌트에서 미리 계산하여 클라이언트에 전달하는 구조를 택했다.
기술적 난관 1: 상태 의존 UI의 폭발
Draft 구조가 도입되면서, UI는 단순한 CRUD 화면이 될 수 없었다.
하나의 주문 화면이 다음 조건에 따라 다르게 렌더링되어야 했다.
- 현재 단계 (Draft / Confirmed / Locked)
- 사용자 역할 (Customer / Vendor / Forwarder)
- 연결된 하위 객체 상태 (Delivery Order, Quote)
이를 단순 조건문으로 처리하면 유지보수가 불가능해진다. 3가지 상태 x 3가지 역할 x 3가지 하위 객체 상태를 단순 조합하면 27가지 경우의 수가 나온다. 실제로는 하위 객체가 복수이고 각 객체의 상태도 독립적으로 변하기 때문에 경우의 수는 기하급수적으로 늘어난다. 그래서 UI 상태를 상태 머신 개념으로 재정의했고, 화면은 상태를 해석하는 역할만 가지도록 분리했다. 각 화면 컴포넌트는 "현재 상태에서 내 역할이 할 수 있는 액션 목록"을 받아서 렌더링하는 구조로 바뀌었다. 상태 해석 로직은 서버 사이드에서 처리되므로, 클라이언트 번들 크기에도 영향을 주지 않는다.
기술적 난관 2: "왜 버튼이 비활성화되었는지" 설명해야 했다
UI에서 가장 많이 받은 내부 피드백은 이것이었다.
"왜 이 버튼이 안 눌리는지 모르겠다."
그래서 버튼 비활성화는 단순히 disabled 처리하지 않았다.
- 비활성 사유를 명확히 표시
- 어떤 조건이 충족되면 활성화되는지 안내
- 내가 아닌 다른 주체의 액션이 필요한 경우 명시
이로 인해 UI는 복잡해졌지만, 운영 커뮤니케이션 비용은 급격히 줄어들었다. 구체적으로, "공급사의 납품 확인이 완료되면 이 버튼이 활성화됩니다" 같은 메시지가 버튼 옆에 표시된다. 이전에는 이런 안내가 없어서 고객사에서 운영팀에 전화를 걸어 "왜 진행이 안 되느냐"고 문의하는 일이 빈번했다. 비활성 사유 표시 이후 이런 문의가 체감상 절반 이하로 줄었다. 4개국에 법인을 운영하면서 언어도 한국어, 태국어, 영어, 중국어가 혼재되기 때문에, 비활성 사유 메시지는 사용자의 언어 설정에 따라 자동 번역되어 표시된다. 이 번역은 단순 사전 기반이 아니라, 업무 맥락에 맞는 번역을 적용하여 "Delivery Order confirmation is pending from vendor" 같은 형태로 출력된다.
AI는 UI 뒤에 숨어 있다
이번 UI 개편에서 AI는 전면에 등장하지 않는다. 대신 다음과 같은 지점에서 조용히 작동한다.
- 견적 입력 시 조건 누락 감지
- 공급사 상품 정보 기반 추천 값 제안
- 포워딩 견적 비교 시 판단 보조 정보 제공
중요한 점은 AI의 결과를 그대로 UI에 강제하지 않았다는 것이다. AI는 결정을 대신하지 않고, 선택지를 정리하는 역할만 맡았다. 예를 들어 포워딩 견적 비교 화면에서 AI는 과거 유사 노선의 평균 운임, 리드타임 범위, 선사별 정시율 같은 참고 데이터를 함께 표시한다. 하지만 "이 업체를 선택하세요"라는 추천은 하지 않는다. 25,000건 이상의 거래 데이터에서 추출한 통계가 판단 보조 자료로 활용될 뿐이다. 견적 입력 시 조건 누락 감지 역시 구체적으로 작동한다. 공급사가 견적서를 작성할 때 필수 항목인 Incoterms, 납기일, 통화 단위가 빠져 있으면 AI가 자동으로 감지하여 안내한다. 이 검증은 Cloudflare Workers에서 실시간으로 처리되어, 견적서 제출 전에 문제를 잡아낸다.
UI/UX 개편은 DVRP를 위한 준비였다
이번 UI/UX 개편은 단독 작업이 아니다.
3월 예정된 DVRP 베타를 연결하기 위한 전제 조건이었다.
주문과 물류가 연결되기 위해서는 "이 주문이 지금 어디까지 확정되었는가"를 모든 주체가 동일하게 이해해야 한다. DVRP는 국내 배송과 창고 운영을 담당하는데, 이 시스템이 제대로 작동하려면 "이 화물이 통관을 완료했고, 현재 창고 입고 대기 상태이며, 배송지는 확정되었다"는 정보가 정확해야 한다. 이전 UI에서는 이런 상태 인식이 역할마다 달랐기 때문에, DVRP 연동 전에 반드시 정리해야 할 과제였다.
UI는 그 이해를 강제하는 도구가 되었고, 그 결과 DVRP는 별도의 설명 없이도 자연스럽게 연결될 수 있는 구조가 되었다. 2026년 3월 DVRP 베타 출시와 4~5월 POP 베타 출시가 가능했던 것은, 이 UI/UX 개편에서 상태 해석 구조를 먼저 정리했기 때문이다.
마무리
이번 UI/UX 개편은 보기 좋게 만드는 작업이 아니었다.
플랫폼이 성장하면서 필연적으로 발생하는 해석의 차이, 책임의 모호함, 단계 충돌을 기술적으로 정리한 과정이었다. 4개국에 걸친 법인 운영과 4,300개 이상의 파트너가 사용하는 플랫폼에서, 상태의 의미가 역할마다 다르게 해석되는 것은 단순한 불편이 아니라 사업 리스크였다.
화면을 바꾼 것이 아니라, 플랫폼이 생각하는 방식을 바꾼 이야기다.








