๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

Front-end

Monorepo ๋„์ž…๊ธฐ: ํ”„๋ก ํŠธ์—”๋“œ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ์„ค๊ณ„ ์ •๋ฆฌ

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 ๋””์ž์ธ ์‹œ์Šคํ…œ ๋„์ž