사장이지 Back-office Application이란?
Back-Office Application을 구성하면서
'사장이지' Back-Office Appilcation은 상담원이 사용자 데이터를 기반으로 사용자의 화면을 보면서 상담을 하는 어플리케이션이다 보니 몇가지 제약 조건을 갖고 있습니다.
서비스를 구성하면서 생긴 제약 조건
-
폐쇄망 환경
-
시스템은 외부 인터넷과 분리된 폐쇄망 환경에서 동작해야 함
-
외부 API, 외부 CDN, Third-party 서비스 등에 대한 의존이 제한되며, 필요한 리소스는 내부망에서 직접 제공하거나 별도 전환 작업이 필요함
-
-
사용자별 상이한 앱 버전
-
고객의 앱 버전은 사용자마다 서로 다를 수 있음
-
특정 시점에 여러 버전이 동시에 운영되는 멀티 버전 환경을 고려해야 하며, 상담원 앱은 이 다양한 버전을 적절히 매핑/처리할 수 있는 구조가 요구됨
제약 조건을 해결하기 위한 방향
제약 조건(폐쇄망, 사용자별 상이한 앱 버전, 디바이스 특성 등)을 고려하여, 상담원을 위한 Back-Office Application을 어떤 형태로 제공할지 두 가지 방향을 검토했습니다.
Emulator Application (Virtual Device 기반)
먼저 출시된 실제 어플리케이션을 가상 머신(Virtual Device)에 설치하여, 상담원이 에뮬레이터 상에서 고객 환경을 재현하는 방식을 후보로 검토했습니다.
그러나 어플리케이션의 특성상, ‘하나의 디바이스에 앱설치는 하나의 버전만 설치 가능하다.’ 는 제약이 있었습니다. 이로 인해 다음과 같은 문제가 예상되었습니다.
-
여러 버전의 앱을 동시에 지원하기 어려움.
-
상담 고객별 앱을 실시간으로 설치 및 삭제를 반복해야 함.
이러한 이유로, Emulator 기반 Back-Office 구성은 현실적인 운영성 및 확장성 측면에서 적합하지 않다고 판단했습니다.
Emulator 를 통해서도 버전 별 앱을 재설치 하는 방법으로 여러 버전을 대응할 수 있지만,
재설치 하는 시간과 재설치 하는 과정에서 휴먼에러 발생에 여지가 있었습니다.
Web Application
위와 같은 제약을 해소하기 위해, 최종적으로 Web Application 형태의 Back-Office를 선택했습니다.
-
브라우저 기반 접근이 가능하여, 디바이스/에뮬레이터에 직접 앱을 설치할 필요가 없음.
-
서버 사이드에서 버전별 화면/로직을 제어할 수 있어, 여러 앱 버전을 보다 유연하게 지원할 수 있음.
-
폐쇄망 환경에서도 내부 인프라에 Web Application을 배포하는 형태로 구성할 수 있어, 보안 요구사항을 충족하면서도 운영이 용이함.
버전별 hosting 예시
version 1.2 : https://{통화비서-도메인}/emulator/sajangeasy/v1.2/index.html?{query params}
version 1.3 : https://{통화비서-도메인}/emulator/sajangeasy/v1.3/index.html?{query params}
결론적으로, Back-Office는 Web Application 방식으로 상담원을 지원하는 방향으로 설계·구현하였습니다.
Web Application 개발 중 이슈 사항
웹 어플리케이션 형태로 Back-Office Appication 을 제공하는 과정에서 여러 기술적인 이슈가 발생했습니다.
1. 폐쇄망 이슈
기존 사장이지 서비스는 Material Design 기반으로 구성되어 있으며, Material System에서 사용하는 폰트(font) 등을 Google CDN으로부터 내려받는 구조였습니다.
또한 Flutter Web Application이 WASM(WebAssembly)를 사용하고 있었고, 이 역시 Google CDN에서 가져오도록 구성되어 있었습니다.
WASM(Web Assembly)
브라우저에서 고성능의 바이너리 코드를 실행하기 위한 표준 웹 브라우저에서 C/C++/Rust/Dart 같은 언어로 작성된 코드를 “기계어 수준”으로 실행할 수 있게 하는 기술
그러나 Back-Office가 동작하는 서버는 외부 인터넷과 분리된 폐쇄망 환경에 있기 때문에, Google CDN에 접근할 수 없고, 그 결과 폰트나 WASM 리소스를 정상적으로 로드하지 못하는 문제가 발생했습니다.
해결 방안
폐쇄망 이슈는, Application 패키징 과정에서 필요한 리소스를 모두 사전 로드(pre-load) 하는 방식으로 해결할 수 있었습니다.-
Material System에서 사용하는 폰트 파일을 내부 리소스로 포함
-
Flutter Web에서 사용하는 WASM 파일 역시 외부 CDN이 아닌, 내부 서버에서 직접 제공하도록 빌드/배포 파이프라인을 수정
build option 을 통한 WASM 포함 방법:
flutter build web --release --no-web-resources-cdnwasm pre-load build output
2. Cross Domain Issue (SOP)
또 다른 문제점은, Back-Office Web Application과 실제 Web element(WebView)를 제공하는 서버의 도메인이 서로 달라, 브라우저의 동일 출처 정책(Same Origin Policy, SOP)에 의해 접근이 차단되는 문제점이었습니다.
-
Back-Office Application을 호스팅하는 서버: 기존 통화비서 서버
-
Web element들을 호스팅하는 서버: 사장이지 서버
Back-Office에서 사장이지 서버의 Web element에 접근하는 과정에서 SOP가 적용되며, 스크립트 접근 및 리소스 로딩 등의 제약이 생겼던 것입니다.
SOP(Same Origin Policy): 웹 보안의 가장 기본적인 원칙 중 하나로,브라우저가 서로 다른 출처(origin)의 리소스 접근을 기본적으로 차단하는 규칙.
해결 방안
SOP 정책으로 인한 문제점을 해결하기 위해, Web Application에서 사장이지 서버가 제공하던 Web element를, Back-Office가 호스팅되는 서버를 거쳐서 가져오는 구조로 변경했습니다.
-
Web Application이 호출하는 Web element의 URL을 Back-Office 호스팅 서버 도메인 기준의 경로로 변경
-
Back-Office 호스팅 서버에서, 1)
특정 패턴(사전에 정의된 endpoint)으로 들어오는 요청을 감지하고, 2) 이 요청을 내부에서 사장이지 도메인으로 프록시(Proxy) 포워딩하여 실제 Web element를 요청
이 같은 방식으로 브라우저 관점에서는 하나의 동일 출처(origin)만 바라보게 되고, 서버 측에서만 실제 사장이지 서버로 라우팅하도록 하여 SOP 이슈를 우회할 수 있었습니다.
<그림1. infra image >
<그림2. framework 별 process flow >
3. Bridge Issue (iFrame 환경)
이 과정에서, Web element와 Application 간에 통신을 담당하는 Bridge Channel 구조가 문제가 되었습니다.
-
Mobile(WebView) 환경:
-
web
window객체에 channel name을 갖는 instance가 생성되는 방식 -
예:
instance.postMessage(param)형태로 통신
-
-
Web(iFrame) 환경:
-
동일한 채널이 instance가 아닌 function 형태로 주입되는 구조
-
즉,
window[channelName]이 객체가 아니라 함수로 제공됨
-
기존 Web element 코드는 모바일 WebView 기준으로 개발되어 있었기 때문에, iFrame 환경에서는 instance.postMessage(param) 호출 시, instance가 함수이기 때문에 에러가 발생하거나, 메시지가 전달되지 않는 문제가 생겼습니다.
해결 방안
Bridge 이슈 해결을 위해, iFrame 환경에서 Bridge Channel이 function 형태로 주입된다는 점에 맞춰, Web element 쪽 코드를instance.postMessage(param)에서instance(param) 형태로 변경했습니다.
즉, 아래와 같이 구분했습니다.
-
모바일 WebView:
bridgeInstance.postMessage(param) -
iFrame(Web):
bridgeFunction(param)
이 차이를 코드에서 조건 분기 또는 어댑터 레이어로 처리하여, Web element가 두 환경(WebView / iFrame) 모두에서 동일한 기능을 수행하도록 정리했습니다.
ex) iframe의 window 상태 중 일부를 capture한 상태로, receiveStoreId 가 기존에 정의된 채널명입니다.
이렇게 폐쇄망, Cross Domain, Bridge 이슈를 정리·해결함으로써, Web 기반 Back-Office Application이 실제 운영 환경에서 안정적으로 동작할 수 있는 기반을 마련할 수 있었습니다.
Modular Architecture가 만든 빠른 서비스 확장
서비스 개발 당시, 통화비서 서비스에 포함된 모든 기능을 완전히 파악하지 못한 상태에서, Web Application(상담원 앱)을 병렬로 개발해야 하는 상황이었습니다.
이때 서비스의 아키텍처가 Feature First / 모듈러(modular) 구조였다는 점이 큰 도움이 되었습니다.
만약 통화비서 서비스가 Layer First 구조로 구현되어 있었다면, 통화비서 서비스에서 필요로 하는 외부 기능들을 찾기 위해 공통 레이어, 도메인 레이어, 인프라 레이어 등을 광범위하게 추적해야 했을 것이고, 실제로 어떤 레포지토리/서비스가 통화비서와 직접 관련 있는지 판단하는 데 상당한 시간이 소요되었을 것입니다.
반면, 통화비서 서비스는 모듈러 아키텍처로 구성되어 있어, 통화비서 도메인에서 필요한 기능을 모듈 내부에서 자체적으로 처리하고 있었고, 외부 기능 의존성은 명시적인 의존성 주입(Dependency Injection)을 통해서만 연결되고 있었습니다.
이 덕분에, 현재 사장이지 서비스가 약 40여 개의 비즈니스 로직(Domain)을 수용하고 있음에도 이 모든 Repository를 일일이 분석할 필요 없이, 통화비서 모듈에서 명시적으로 주입받는 6개의 Domain만 확인하면 아래와 같은 내용들을 빠르게 파악할 수 있었습니다.
즉, Feature First / 모듈러 구조 덕분에 '전체를 다 이해해야만 시작할 수 있는' 상황을 피할 수 있었고, 통화비서 모듈을 중심으로 국소적인 이해만으로도 개발을 진행할 수 있었습니다.
결과적으로 Feature First / 모듈러 구조로 인해, 기능 파악 및 설계에 들어가는 시간을 크게 줄일 수 있었습니다.
부가적인 Flutter Web 개발 과정에서의 어려움
1. 서비스 내부에서 사용되는 모바일 환경 전용 API들에 대한 제한
기존 통화비서 서비스 feature 내부에서 사용자의 device api 를 기반으로 특정 동작을 지원하는 기능이 있었습니다.
web 환경에서는 device api를 접근할 수 없어서, 해당 기능들에 대한 처리 방식을 외부에서 주입 받는 방식으로 변경하여 처리했습니다.
추가로 device permission을 요청하는 기능도 있었으나, Web환경에서 제공 할 수 없어서 해당 기능은 권한이 동의된 상태를 가정하도록 주입해 주었습니다.
2. import 과정에서의 web과 mobile 간 구분
공통 코드가 모바일과 웹에서 같이 동작해야 하는 이슈가 발생했습니다.
가장 큰 예시로 서비스 전반적으로 사용하는 WebView가 그에 해당되는데, WebView를 사용하는 측에서 web인지 여부(*kISWeb)를 검사하여 구분하게 되면, 모바일 환경에서 발생할 수 있는 side-effect가 많을 것으로 판단하여 Facade pattern(GOF design pattern) 방식을 채용했습니다.
Facade pattern 방식
-
interface class를 구성
-
해당 interface를 구현하는 파일을 웹 과 모바일 환경을 구분하여 구성
-
interface class를 export하는 파일을 구성하여 웹 과 웹이 아닌 경우를 구분
TypeScript/// interface export file export 'package:webview_core/src/iframe_widget/view/iframe_webview_widget.dart' if (dart.library.html) 'webview_web_widget.dart'; /// webview_web_widget 와 iframe_webview_widget 두 file 모두다 IFrameWebViewWidget 에 대한 구현부를 갖고 있어서 /// 사용하는 측에서 별도 분기 없이 platform 에 따라 자동 구분되어 import 및 사용이 된다.
12345
3. 인증 및 암복호화 관련 이슈
인증 시스템 이슈 및 해결
다행히도, 통화비서 시스템은 모듈화(Modular Architecture)되어 있었고, 외부 시스템에서 인증을 처리할 수 있도록 설계되어 있었습니다.
이 덕분에, 외부에서 인증 키(Token)를 전달받아 해당 인증 키를 사용하는 방식으로 Web Application에서도 인증 문제를 비교적 수월하게 해결할 수 있었습니다.
암복호화(Encryption) 이슈 및 해결
일부 기능에서는 대칭키 암호화 방식을 사용하고 있었는데, 이 경우에는 Web 환경에서도 별다른 문제 없이 처리가 가능했습니다.이렇게 인증 및 암복호화 관련 이슈를 모듈화된 인증 구조를 활용하여 인증 문제를 해결하고, 비대칭키 기반 암호화 기능은 Web Application에서 제외하는 방식으로 안정적으로 마무리할 수 있었습니다.
🤗 함께한 사람들: P-App개발팀
모바일 앱 개발자로 구성되어 있으며 특정 플랫폼 제약 없이 iOS, Android, Flutter, Kotlin Multiplatform 등 내재화 개발 가능하며 프로젝트 특성을 고려하여 최적화된 플랫폼을 채택하고 있습니다.