1. 개요

본 문서에서는 Legacy Web과 Mobile을 모노레포 프로젝트로 통합하는 설계와 전환 전략을 제시한다.


2. 현재 상황 & 문제점

기술 스택

  • Next.js 12.3.6 + JavaScript(ES6)
  • MobX 6.5.0, Material-UI v4
  • React Query v3, Axios, npm

주요 문제

  1. 개발 환경 복잡
    • Express 기반 커스텀 서버(500+줄), API 프록시 중복
    • 환경 변수 관리 난이도 높음
  2. 폴더 구조 비표준화
    • v1/v2 혼재, Atomic Design 일부 적용
    • 컴포넌트 재사용성 낮음
  3. 코드 및 의존성 중복
    • 동일 로직·UI를 두 프로젝트에 중복 구현
    • 의존성 100% 중복 설치
  4. 기술 부채
    • Next.js 12, React 17, MUI v4 등 구버전
    • JavaScript → TypeScript 필요

더보기

# 문제점에 대한 자세한 설명

Express 기반 커스텀 서버(500+줄), API 프록시 중복

// server/index.js (27-50행)
server.post("/api/v2/*/upload", upload.single("file"), async (req, res) => {
  // 동일한 헤더 처리 로직이 10번 이상 반복됨
  const headers = { ...req.headers };
  delete headers["content-length"];
  delete headers.host;
  // ...
});

// server/index.js (52-86행) - 거의 동일한 코드 패턴
server.post("/api/v2/*", async (req, res) => {
  // 동일한 헤더 처리 로직 반복
  const headers = { ...req.headers };
  delete headers["content-length"];
  delete headers.host;
  // ...
});
  • server/index.js: 985줄의 거대한 파일
  • 동일한 헤더 처리 로직이 10번 이상 반복
  • API 프록시 로직 중복 (axiosUrl, axiosFileUrl)

환경 변수 관리 난이도 높음

// Dockerfile에서 22개의 환경변수 ARG/ENV 정의
ARG ENV_ALB_URL
ARG ENV_ALB_PORT
ARG ENV_API_VERSION
// ... 22개 변수

// server/server.utils.js - 환경별 분기 로직
const axiosUrl = (req) => {
  return process.env.NODE_ENV === "local" ? 
    `${process.env.ENV_LOCAL_API_HOST}:${process.env.ENV_LOCAL_API_PORT}${req.url}`:
    process.env.NODE_ENV === "development" ?
      `${process.env.ENV_DEV_API_HOST}:${process.env.ENV_DEV_API_PORT}${req.url}` :
      `${process.env.ENV_ALB_URL}:${process.env.ENV_ALB_PORT}${req.url}`;
};
  • Dockerfile에 22개 이상의 환경변수 정의
  • 환경별 분기 로직이 여러 파일에 분산

동일한 페이지에서 v1/v2 컴포넌트 혼재

// pages/inventory/center/search/product/index.js (69줄)
import MuiTableSelectOneV2 from "/components/common/MuiTable/MuiTableSelectOneV2";  // V2 사용
import MuiTableTitle from "/components/common/MuiTable/MuiTableTitle";              // V1 사용  
import MuiTableWrapper from "/components/common/MuiTable/MuiTableWrapper";          // V1 사용
import AgGrid from "/components/common/AgGrid";                                      // V1 사용

// 1163줄에서 V2 컴포넌트 사용
<MuiTableSelectOneV2
  name={"userSelectConnectSubAccountListSelect"}
  columns={USER_SELECT_CONNECT_SUB_ACCOUNT_LIST_SELECT_COLUMNS}
  // V2 방식의 props
/>

// 하지만 동일 페이지에서 V1 컴포넌트도 사용
<MuiTableTitle titleText={getLang("WD000183")} />  // V1 방식
<MuiTableWrapper>                                   // V1 방식
  • components/common/ (v1) + components/v2/ 혼재
  • v1, v2 컴포넌트의 차이점 파악에 개발 시간 소요
  • 스타일링 방식 및 props 구조 다름 → 일관성 없는 UX

컴포넌트 재사용성 낮음

components/common/MuiTable/
├── MuiTable/                    # 기본 테이블
├── MuiTable2/                   # 기본 테이블 변형
├── MuiTableSelectOne/           # V1 단일 선택
├── MuiTableSelectOneV2/         # V2 단일 선택  
├── MuiTableForSelectedRows/     # V1 선택된 행 표시
├── MuiTableForSelectedRowsV2/   # V2 선택된 행 표시
├── MuiTableSelectV2/            # V2 다중 선택
├── MuiCustomTable/              # 커스텀 테이블
├── MuiTableExpand/              # 확장 가능 테이블
├── MuiTableWithpaging/          # 페이징 포함 테이블
└── ... 15개 더
  • 25개 이상의 테이블 컴포넌트 - 기본 기능이 같은데도 불구하고 중복 구현
  • 7개의 모달 컴포넌트: Modal, MuiTableClickModal, CommonAlertModal 등 유사 기능 중복
  • 공통화 없이 페이지별로 컴포넌트 코드를 복사 붙여넣기하여 사용

3. 모노레포 전환 필요성

  1. 통합 개발 환경
    • 단일 저장소·개발 서버 → Turbo 병렬 빌드 & Hot Reload 최적화
  2. 코드 재사용 극대화
    • @repo/ui, @repo/shared, @repo/react-query 등 패키지화
  3. 최신 스택 적용
    • Next.js 15 App Router, TypeScript, Zustand, TanStack Query v5, Zod
  4. DX 향상
    • ESLint/Prettier/Husky/Lint-staged 도입
    • 통합 스크립트: pnpm dev:web, pnpm dev:admin
AS-IS TO-BE 전환 이유 / 기대 효과
JavaScript TypeScript 타입 안정성 확보, 대규모 코드베이스 유지보수 용이, 런타임 오류 사전 방지
Next.js 12 + Page Router Next.js 15 + App Router Next.js 12는 장기 지원 종료 예정, App Router로 성능·데이터 패칭 방식 개선
Material-UI v4 커스텀 디자인 시스템 MUI v4는 유지보수 중단, 디자인 일관성 강화 및 불필요한 의존성 제거로 번들 사이즈 감소
MobX Zustand MobX TS 지원 미흡, 경량·간단한 API 제공, TypeScript 친화적
React Query v3 TanStack Query v5 v3는 Maintenance Mode, 최신 버전에서 캐싱·동기화 성능 및 DevTool 개선
npm pnpm 디스크 공간 절약, 설치 속도 향상, 모노레포 환경 최적화
npm run build Turbo build 빌드 캐싱·병렬 처리 지원, 증분 빌드로 빌드 시간 단축

4. 점진적 배포 및 라우팅 전략

ECS 서비스 구성

ECS Cluster: (서비스명)-cluster
├── (서비스명)-web-service (NEW)    - 모노레포 Web App
├── (서비스명)-mobile-service (NEW)    - 모노레포 Mobile App
├── (서비스명)-admin-ui-service (NEW)  - 모노레포 Admin App
├── (서비스명)-ui-service (LEGACY)     - 레거시 Web
└── (서비스명)-mobile-ui-service (LEGACY) - 레거시 Mobile

ALB 라우팅 규칙

Application Load Balancer
├── Listener :443 (HTTPS)
│   ├── Path /*        → (서비스명)-ui-service (Legacy Web)
│   └── Path /v2/*     → (서비스명)-web-service (Monorepo Web)
│
├── Listener :8443 (HTTPS)
│   └── Path /*        → (서비스명)-mobile-ui-service (Legacy Mobile)
│   └── Path /v2/*     → (서비스명)-mobile-service (Monorepo Mobile)
│
└── Listener :9443 (HTTPS)
    └── Path /*        → (서비스명)-admin-ui-service (Monorepo Admin)

전환 방식

  • 기존 경로(/) 요청 → 레거시 서비스로 라우팅
  • 신규 개발 페이지(/v2/*) 요청 → 신규 web-service, mobile-service로 라우팅
  • Admin 서비스는 독립 포트(9443)에서 신규 모노레포 버전 운영

목적

  • 신규 개발된 페이지는 /v2/* 경로를 통해 제공
  • 기존 서비스와 신규 서비스 동시 운영하여 안정적인 마이그레이션 가능
  • 기능별/페이지별 점진적 전환으로 리스크 최소화
  • 최종적으로 / 경로를 신규 환경으로 전환

5. 새로운 아키텍처

(서비스명)_frontend/
├── apps/
│   ├── admin/   # 관리자 서비스
│   ├── mobile/  # Mobile
│   └── web/     # Web
├── packages/
│   ├── ui/        # 디자인 시스템
│   ├── shared/    # 비즈니스 로직
│   ├── react-query/
│   ├── zustand/
│   ├── zod/
│   ├── configs/
│   └── eslint-config/
  • packages 관리(패키지화)를 통해 코드 재사용 극대화

6. 마이그레이션 단계

Phase 1: 기반 구조 구축 (pnpm, Turbo, 공통 패키지, CI/CD)

Phase 2: UI 라이브러리 구축 (TS 전환, Atomic Design, Storybook, 디자인 토큰)

Phase 3: Web, Mobile App 마이그레이션 (커스텀 서버 제거, 반응형·성능 최적화)

Phase 4: 운영 최적화 (번들 최적화, 모니터링·로그 통합, 문서화)


7. 기대 효과

개발 생산성

  • 병렬 빌드 및 Turbo 캐시로 빌드 시간 60~70% 단축
  • 공통 코드 90% 이상 재사용, 수정·배포 횟수 절반으로 감소

코드 품질

  • 타입 안정성·자동완성·안전한 리팩토링
  • ESLint + Prettier로 스타일 일관성 확보

운영 효율성

  • 변경된 앱만 배포

UI/UX 개선

  • 2.0 디자인 시스템 도입