시스템 개요
대규모 배송 서비스는 수천 명의 라이더가 동시에 수만 건의 배송을 처리하며, 각 배송 건은 실시간으로 추적되어야 합니다. 배송 시스템은 세 가지 역할로 구분되며, 이 중 라이더와 주문자만 모바일 앱으로 구현합니다. 배송 관리자는 다수의 물량을 모니터링하기 때문에 데스크톱 환경이 더 적합하므로 이 설계에서는 제외합니다. 라이더 앱은 위치를 전송하는 송신자이며, 주문자 앱은 위치를 받는 수신자입니다. 이러한 역할 차이는 아키텍처 설계의 근본적인 차이로 이어집니다.
역할별 요구사항 비교
| 구분 | 라이더 앱 | 주문자 앱 |
|---|---|---|
| 핵심 기능 | 위치 수집 및 전송, 배송 관리 | 위치 수신 및 표시, 상태 모니터링 |
| 데이터 흐름 | 디바이스 → 서버 (송신) | 서버 → 디바이스 (수신) |
| 백그라운드 동작 | 필수 (하루 종일 실행) | 선택적 (추적 화면에서만) |
| 배터리 중요도 | 매우 높음 (8시간+ 실행) | 보통 (간헐적 사용) |
| 네트워크 패턴 | 업로드 중심, 배치 처리 | 다운로드 중심, 실시간 스트림 |
| 오프라인 대응 | 필수 (로컬 저장 후 동기화) | 부분적 (캐시된 데이터 표시) |
| 주요 채널 | MethodChannel + EventChannel | EventChannel 중심 |
라이더 앱 아키텍처
라이더 앱의 핵심은 안정적인 위치 수집과 백그라운드 동작입니다. 네이티브 레이어에서 백그라운드 서비스를 실행하여 위치를 수집하고, EventChannel을 통해 Flutter로 스트리밍합니다. Flutter는 받은 위치를 서버로 전송하며, 전송 실패 시 로컬 데이터베이스에 저장했다가 나중에 재시도합니다. 배송 시작, 픽업 완료, 배송 완료 같은 명령은 MethodChannel로 네이티브에 전달하여 백그라운드 서비스의 동작 모드를 제어합니다.
| 레이어 | 책임 | 핵심 기술 |
|---|---|---|
| 네이티브 | 위치 수집, 백그라운드 서비스 관리 | Android Foreground Service, iOS Background Location |
| Platform Channel | 네이티브-Flutter 연결 | MethodChannel (명령), EventChannel (위치 스트림) |
| Flutter | UI, 비즈니스 로직, 서버 통신 | State Management, HTTP Client, Local Database |
위치 수집 주기는 상황에 따라 동적으로 조정됩니다. 배송 중일 때는 10-15초마다 높은 정확도로 수집하고, 대기 중일 때는 30-60초 주기로 낮은 정확도를 사용합니다. 이동 속도가 빠를수록 더 자주 업데이트하여 지도에서 부드러운 움직임을 보장합니다. GPS는 전력 소모가 크므로 Wi-Fi와 셀룰러 기반 위치를 우선 사용하고, 필요할 때만 GPS를 활성화합니다.
주문자 앱 아키텍처
주문자 앱은 실시간 데이터 수신에 집중합니다. 네이티브 레이어에서 WebSocket이나 Server-Sent Events로 서버와 연결하고, 받은 데이터를 EventChannel을 통해 Flutter로 전달합니다. Flutter는 Stream으로 데이터를 받아 즉시 UI에 반영하며, 위젯 생명주기와 연동하여 화면이 보이지 않을 때는 자동으로 구독을 해제합니다. 라이더 위치 업데이트가 10초마다 오더라도, AnimationController를 사용하여 마커가 부드럽게 이동하도록 보간 처리합니다.
| EventChannel 종류 | 전달 데이터 | 업데이트 주기 | 화면 반영 |
|---|---|---|---|
| 위치 채널 | 라이더 위도/경도, 방향 | 10-15초 | 지도 마커 위치 |
| 상태 채널 | 배송 단계 (픽업중/배송중/완료) | 상태 변경 시 | 상태 표시 바, 텍스트 |
| ETA 채널 | 예상 도착 시간 | 30-60초 또는 경로 변경 시 | 남은 시간 표시 |
| 알림 채널 | 중요 이벤트 (배송 시작/완료) | 이벤트 발생 시 | 푸시 알림, 인앱 메시지 |
Platform Channels 설계 전략
Platform Channels는 역할에 따라 명확하게 분리해야 합니다. 라이더 앱은 MethodChannel로 명령을 전달하고 EventChannel로 위치를 받는 양방향 구조입니다. 주문자 앱은 EventChannel만으로 충분하며, 서버에서 푸시되는 모든 정보를 스트림으로 받습니다. 각 채널은 하나의 도메인만 담당하여 코드를 이해하고 유지보수하기 쉽게 만듭니다.
| 앱 종류 | MethodChannel 용도 | EventChannel 용도 |
|---|---|---|
| 라이더 앱 | 배송 시작/완료, 위치 수집 설정 변경 | 네이티브에서 수집한 위치 스트림 수신 |
| 주문자 앱 | 거의 사용하지 않음 | 라이더 위치, 배송 상태, ETA 스트림 수신 |
네이티브에서 서버 연결을 관리하면 여러 장점이 있습니다. 앱이 백그라운드로 가더라도 연결이 유지되며, 네이티브의 효율적인 네트워크 스택을 활용할 수 있습니다. 연결이 끊어졌을 때 자동 재연결 로직을 네이티브에서 처리하면, Flutter 레이어는 항상 안정적인 데이터 스트림을 받을 수 있습니다. 또한 플랫폼별 최적화를 네이티브에서 수행하여 배터리와 네트워크 효율성을 극대화합니다.
성능 최적화
| 최적화 영역 | 전략 | 효과 |
|---|---|---|
| 배터리 | 상황별 위치 정확도 조정, GPS 사용 최소화, 네트워크 배치 처리 | 하루 8시간 사용 가능 |
| 메모리 | 오래된 경로 제거, 이미지 캐싱, 스트림 데이터 제한 | 안정적인 장시간 실행 |
| 네트워크 | 데이터 압축, 델타 업데이트, 적절한 하트비트 간격 | 데이터 사용량 50% 절감 |
| 렌더링 | 위치 업데이트 쓰로틀링, 백그라운드 시 UI 중단 | 부드러운 60fps 유지 |
위치 데이터는 매번 개별적으로 전송하는 대신 여러 개를 모아서 한 번에 전송하면 네트워크 라디오가 켜지는 횟수를 줄일 수 있습니다. 실시간성이 중요한 데이터는 즉시 전송하고, 덜 중요한 통계 데이터는 배치 처리합니다. 지도에 표시되는 마커는 초당 업데이트 횟수를 제한하여 렌더링 부하를 줄이며, 화면이 백그라운드에 있을 때는 UI 업데이트를 완전히 중단합니다.
데이터 일관성
분산 시스템에서 데이터 일관성을 유지하기 위해 여러 전략을 적용합니다. 라이더가 배송 완료를 표시하면 서버 응답을 기다리지 않고 즉시 UI를 변경하는 낙관적 업데이트를 사용하여 사용자 경험을 개선합니다. 서버 요청이 실패하면 UI를 이전 상태로 되돌리고 사용자에게 알립니다. 오프라인 상태에서도 앱은 계속 동작하며, 중요한 데이터는 로컬 데이터베이스에 저장했다가 네트워크 복구 시 자동으로 동기화합니다.
| 일관성 전략 | 구현 방법 | 적용 시나리오 |
|---|---|---|
| 낙관적 업데이트 | UI 즉시 변경 후 서버 요청, 실패 시 롤백 | 배송 완료, 상태 변경 |
| 충돌 해결 | 서버의 타임스탬프 우선, 클라이언트는 서버 상태 수용 | 동시 상태 변경 |
| 이벤트 순서 보장 | 시퀀스 번호로 순서 검증 | 배송 상태 전이 |
| 상태 머신 | 유효하지 않은 전이 거부 | 잘못된 상태 변경 방지 |
보안과 테스트
위치 정보는 민감한 데이터이므로 전송과 저장 시 모두 암호화합니다. HTTPS로 전송 중 데이터를 보호하고, JWT 기반 인증으로 권한을 관리합니다. 라이더는 자신의 배송 건만, 주문자는 자신의 주문만 접근할 수 있도록 엄격히 제한합니다. 배송 완료 후에는 상세한 위치 히스토리를 삭제하여 불필요한 데이터를 보관하지 않습니다. 네이티브 코드에 API 키를 하드코딩하지 않으며, 코드 난독화를 적용하여 리버스 엔지니어링을 방지합니다.
| 테스트 영역 | 방법 | 검증 항목 |
|---|---|---|
| Platform Channels | 모의 객체 사용 | 채널 통신, 에러 처리, 구독 취소 |
| 위치 추적 | 시뮬레이터로 경로 재현 | 빠른 이동, 정지, 방향 전환 처리 |
| 네트워크 장애 | 연결 끊김 시뮬레이션 | 재시도 로직, 데이터 손실 방지 |
| 성능 | 실제 디바이스 장시간 실행 | 배터리 소모, 메모리 안정성 |
| 통합 | 라이더-주문자 동시 실행 | 실시간 반영, 엔드투엔드 시나리오 |
마무리
엔터프라이즈급 배송 추적 시스템은 라이더와 주문자의 서로 다른 요구사항을 이해하고, Platform Channels를 효과적으로 활용하여 구축할 수 있습니다. 라이더 앱은 네이티브 백그라운드 서비스로 안정적인 위치 수집을 보장하고, MethodChannel과 EventChannel을 조합하여 명령 전달과 데이터 스트리밍을 분리합니다. 주문자 앱은 EventChannel 중심으로 설계하여 실시간 업데이트를 받고, 화면 생명주기와 연동하여 리소스를 효율적으로 관리합니다. 성능 최적화와 데이터 일관성, 보안까지 고려한 종합적인 설계가 성공적인 배송 시스템의 기반이 됩니다.