물류 플랫폼의 주문 탭 분리: 산업과 생활 사용자의 도메인 경계 설정
복잡한 도메인 로직을 UI로 직결할 때, 산업/생활 사용자 요구를 탭으로 분리하여 API 축과 도메인 모델을 정렬한 결정과 그 대가.
물류 플랫폼에서 '주문'은 단순한 데이터가 아니라, 배출·운반·처리라는 물리적 흐름과 계약·정산이라는 금융 흐름이 중첩된 복합 객체다. 이 객체를 하나의 화면으로 관리하려다 보면, 사용자 역할에 따라 필요한 정보의 축이 완전히 달라진다는 문제가 발생한다. 산업 사용자는 계약 규칙과 배차 상태를 봐야 하지만, 생활 사용자는 단순한 수거 일정만 알면 된다. 두 그룹의 요구사항을 하나의 API 스펙과 UI 컴포넌트에 억지로 담으려다 시스템은 복잡도가 기하급수적으로 증가했다.
제약
- 사용자 역할의 이질성: 산업 사용자는 다중 사업자, 계약 유형, 정산 상대를 고려해야 한다. 생활 사용자는 '내 물건'의 수거 일정만 필요하다.
- 도메인 모델의 비대칭성: 산업용 주문은 계약(terms)과 정산(settlement)이 분리되어 있고, 생활용 주문은 단순한 상태(State) 위주다.
- 운영 비용: 두 그룹의 필터, 정렬, 상세 정보 구조를 각각 유지하려면 유지보수 비용이 2배가 된다.
선택지
1. 단일 화면 + 조건부 렌더링 장점: 코드 중복이 적고, 새로운 탭 추가 시 코드가 분산되지 않는다. 단점: 조건문(if-else)이 컴포넌트 깊숙이 파고들어 가독성이 떨어지며, API 응답이 두 사용자를 모두 만족하도록 무거워진다.
2. URL 파라미터 기반 동적 필터링 장점: URL로 상태를 관리하므로 공유와 딥링크가 쉽다. 단점: 필터 조합이 복잡해지면 URL이 길어지고, 백엔드 쿼리 파라미터가 사용자의 '의도'와 '도메인 모델'을 혼재시킨다.
3. 물리적 탭 분리 (산업/생활) 장점: 각 탭마다 독립적인 API 스펙, 컴포넌트, 도메인 로직을 가질 수 있다. 사용자가 '어떤 도메인'에 있는지 명확히 구분된다. 단점: 초기 구현 비용이 높고, 공통 컴포넌트 재사용이 어려워진다.
결정
우리는 물리적 탭 분리를 선택했다. '주문 관리' 화면을 산업 사용자 전용의 '자체/받은/보낸 주문' 3탭과, 생활 사용자 전용의 기존 화면으로 완전히 분리했다.
이 결정의 핵심 기준은 **'API 스펙의 명확성'**과 **'도메인 모델의 정렬'**이다. 산업 탭에서는 계약 유형(termsType)을 기준으로 조회하고, 정산 내역(settlement)을 별도의 축으로 분리하여 제공한다. 반면 생활 탭은 봉투(Inbox) 개념을 도입해, 발송/수신 상태를 중심으로 단순화된 엔벨로프(Envelope) API를 사용한다.
버린 대안: 단일 화면에서 isIndustry 플래그로 분기하던 방식은 폐기했다. 이는 백엔드에서 두 가지 다른 도메인 로직을 하나의 엔드포인트에 합쳐야 하므로, 장애 반경을 넓히고 디버깅을 어렵게 만들기 때문이다.
구현의 뉘앙스:
- 산업 탭의 '받은 주문'은 실제 데이터베이스의 운영자 주문 테이블를 직조회하는 것이 아니라, '나를 수신자로 발행된 봉투'라는 도메인 객체로 재정의했다. 이는 발송 시점의 스냅샷(명세)과 현재 운행 상태(라이브)를 분리하여 처리하기 위함이다.
- 생활 탭은 딥링크(
?tab=)를 무시하고 기존 UI를 유지한다. 이는 생활 사용자의 진입 경로가 단순해야 한다는 원칙에 따른 것이다.
결과와 한계
- 얻은 것: 산업 탭의 API 스펙이 계약과 정산의 도메인 모델과 완벽히 일치하게 되었다. 생활 탭은 불필요한 계약 로직에서 해방되어 가벼워졌다.
- 잃은 것: 두 탭 간에 중복되는 UI 컴포넌트(예: 날짜 필터, 정렬 버튼)의 유지보수가 분리되어, 스타일 변경 시 두 곳을 수정해야 한다.
- 되돌릴 조건: 산업 탭의 API 호출 빈도가 생활 탭과 비교해 3배 이상 증가하거나, 두 도메인 모델의 교집합이 50% 이상이라면 단일 화면으로 회귀해야 한다.
다른 시스템에 적용할 때는 '사용자의 업무 흐름'이 아닌 '데이터의 물리적 흐름'을 기준으로 탭을 나누어야 한다. 업무 흐름은 변하지만 물리적 흐름(예: 입고/출고, 발신/수신)은 비교적 안정적이다.
팀 규칙
- 규칙: 도메인 모델이 다른 경우, UI의 탭은 API의 엔드포인트 경계와 일치해야 한다.
- 되돌림 조건: 두 탭의 API 응답 구조가 80% 이상 유사해지면 통합을 검토한다.