문제
같은 인증 흐름을 여러 앱에서 따로 고쳐야 하는 상황
Notiiv는 어드민, 오너 대시보드, 서비스 상태와 고객지원 네 앱을 13개 공통 패키지와 함께 운영하는 회사 제품입니다. 저는 공통 BFF·Query 기반의 유지보수와 운영 화면, 인증·공유·웹뷰의 경계 조건 개선을 담당했습니다.
앱마다 BFF 프록시가 별도로 있으면 경로 검증, 인증 쿠키 주입, 토큰 재발급, 오류 변환을 비슷하게 구현하게 됩니다. 한 앱에서 실패 처리를 고쳐도 다른 앱은 이전 동작을 유지할 수 있습니다. 반대로 모든 앱을 하나의 고정 처리에 맞추면 로그인 응답이나 파일 업로드처럼 앱마다 다른 정책이 공통 코드 안에 뒤섞입니다.
운영 화면과 공유 페이지에서도 정상 경로만으로는 설명되지 않는 문제가 있었습니다. FAQ 미리보기와 실제 화면의 차이, 소수 고객을 추가할 때도 Excel을 거쳐야 하는 입력 흐름, 모바일 웹뷰의 다운로드 제한, PDF 확대 중 페이지가 넘어가는 동작을 각각 다뤄야 했습니다.
선택한 방법
1. 공통 프록시는 처리 순서를, 앱은 응답 정책을 소유
경로 검증, 백엔드 URL 조합, 인증 주입과 재발급 후 재시도는 공통 createSimpleBffProxy가 담당하도록 정리했습니다. 오너 앱에 남아 있던 별도 요청·응답 파이프라인도 공통 프록시로 옮겼습니다. 여러 앱에서 같은 경계를 수정할 수 있도록 처리 순서를 한곳에 모은 변경입니다.
로그인·가입 성공 응답에서 토큰을 쿠키로 옮기는 일은 앱의 응답 훅으로 남겼습니다. 공개 경로에는 이전 세션 토큰을 싣지 않고 재발급도 시도하지 않도록 구분했습니다. 일반 JSON과 파일 업로드는 같은 프록시를 사용하되 본문 크기, 허용 타입과 타임아웃 설정을 나눴습니다. 앱의 차이를 없애기보다 공통 처리와 제품 정책의 경계를 정리했습니다.
예를 들어 보호된 요청이 401을 받으면 재발급 성공 후 원래 요청을 다시 보낼 수 있지만, 로그인 실패의 401까지 같은 흐름으로 처리하면 의도하지 않은 인증 복구가 개입합니다. 또 쿠키 주입만 켜고 재발급을 설정하지 않으면 만료 쿠키가 남아 로그인과 보호 화면 사이를 오가는 원인이 될 수 있습니다. 함께 필요한 옵션은 생성 시점에 검사해 잘못된 조합을 일찍 드러내도록 했습니다.
2. 실패 응답뿐 아니라 백엔드 호출 여부를 확인
프록시의 허용 경로와 입력 세그먼트를 검사하고, 상태를 바꾸는 요청의 출처도 확인합니다. 테스트는 잘못된 경로에 400, 허용 목록 밖 경로에 404, 다른 출처의 상태 변경에 403을 반환하는지와 함께 이 경우 백엔드 요청이 실행되지 않는지를 확인합니다. 사용자에게 오류만 반환하고 내부 요청은 이미 수행하는 구현을 구분하기 위한 기준입니다.
외부 redirect 방어에서는 /로 시작하는지만 확인하지 않았습니다. //외부호스트도 슬래시로 시작하지만 브라우저는 외부 주소로 해석하기 때문에 이를 별도로 거부했습니다. 모든 미래 호출자가 안전한 값을 전달한다고 가정하지 않고, 공통 경계에 제약과 회귀 테스트를 남겼습니다.
QueryClient도 공통 factory로 추출하되 앱별 설정은 덮어쓸 수 있게 했습니다. API 응답은 Zod로 런타임 검증하고, WebAuthn에서 예상되는 인증 실패는 전역 401 이동과 구분했습니다. 타입이 맞는 코드와 실제 서버 응답이 맞는 상황을 별개로 다룬 작업입니다.
3. 운영자가 완료해야 하는 작업을 기준으로 화면 개선
FAQ 작성 화면은 미리보기와 고객지원 렌더링의 규칙을 맞추고, 편집기의 오류 표시와 키보드 포커스를 보강했습니다. 저장 전 이탈 경고는 form state와 연결해 정상 저장 후 이동까지 막지 않도록 했습니다.
고객 등록에는 직접 입력하는 경로를 추가하고, 빈 행 검증과 전화번호 포맷을 처리했습니다. 명함 이미지 삭제 등에는 낙관적 갱신을 적용했습니다. 많은 화면을 추가했다는 설명보다, 운영자가 하던 입력과 확인 작업을 제품 안에서 끝내도록 한 기여입니다.
4. 공유와 모바일 환경을 별도의 실패 조건으로 검증
미팅 후속 일정은 백엔드가 제공하는 이벤트 목록을 공유 화면에 표시하고 하나의 캘린더 파일로 내보내도록 연결했습니다. 문자열을 파일로 만드는 데서 끝내지 않고 시간대, 잘못된 날짜, 텍스트 escaping과 긴 줄 처리를 다뤘습니다. 제목에서 일정을 추측하던 구현을 명시적인 이벤트 데이터로 옮긴 변경도 기록되어 있습니다.
카카오톡 인앱 브라우저에는 외부 브라우저 전환 안내를 제공하고, 다운로드와 브라우저 API에는 지원 여부에 따른 대체 흐름을 두었습니다. PDF 뷰어에서는 확대 중 swipe가 페이지 넘김으로 해석되지 않게 하고, 한국어 IME의 키 이벤트 차이도 처리했습니다.
확인한 결과
앱과 공통 패키지의 책임 정리
오너 BFF의 독립 파이프라인을 제거하고 공통 프록시를 사용하도록 바뀌었습니다. 로그인·가입 응답 정책은 앱에 남겨 두면서 경로, 요청 제한과 재발급 처리는 공통 패키지에서 유지합니다. QueryClient, 공유 경로와 런타임 응답 검증도 공통 경계를 통해 관리하도록 정리했습니다.
운영 화면에서는 FAQ 미리보기와 실제 렌더링, 직접 고객 입력, 저장 전 이탈과 이미지 삭제 상태를 다뤘습니다. 공유 기능에서는 명시적인 일정 데이터와 브라우저별 실패 조건을 처리했습니다.
앱별 운영 배포
admin·owner·support는 앱별 버전 태그와 production 배포 기록으로 관리됩니다. 공통 패키지는 함께 유지하면서 각 앱의 배포 단위를 나눠, 같은 모노레포의 변경을 제품별 릴리스로 이어가는 환경에서 작업했습니다.
인증과 요청 경계의 회귀 검사
경로 검증 테스트는 거절 상태와 백엔드 호출 차단을, 재발급 테스트와 오너 route 테스트는 공통화 이후의 인증 동작을 다룹니다. 입력 검증, 토큰 갱신과 응답 처리를 같은 테스트 기준으로 유지해 앱별 예외가 공통 처리에 섞이지 않도록 했습니다.
근거
- 4 Frontend Apps
- 하나의 제품 모노레포
- 13 packages
- API · Query · Schema · UI 등 공통 기반
- Shared BFF
- 요청 검증·인증·재발급 공통 처리