CoreERP Frontend 구조 리팩토링 트러블슈팅 기록

최병현·2026년 3월 12일

coreerp project

목록 보기
31/44

이번 작업에서는 React Frontend 구조를 기존 pages 중심 구조에서 feature 기반 구조로 재정리했다.

CoreERP 프로젝트가 커지면서 inventory, inbound, outbound, purchaseOrder 같은 기능 단위로 화면을 나누는 것이 유지보수 측면에서 훨씬 유리하다고 판단했기 때문이다.

Spring Boot Backend가 inbound, outbound, item 같은 feature 패키지 구조로 설계되어 있기 때문에 Frontend도 동일한 기준으로 맞추는 것이 전체 Full-stack 구조를 이해하는 데 도움이 된다.


기존 구조

초기 구조는 대부분의 화면 파일이 pages 아래에 모여 있는 형태였다.

src
 ├ pages
 │   ├ Dashboard.tsx
 │   ├ InventoryCurrent.tsx
 │   ├ SafetyStock.tsx
 │   ├ LongTermStock.tsx
 │   ├ Inbound.tsx
 │   ├ InboundHistory.tsx
 │   ├ Outbound.tsx
 │   ├ OutboundHistory.tsx
 │   ├ PurchaseOrderCreate.tsx
 │   ├ PurchaseOrderHistory.tsx
 │   └ WarehouseTransferHistory.tsx
 │
 ├ components
 │   └ Layout.tsx
 │
 ├ styles
 │   ├ dashboard.css
 │   ├ inventory.css
 │   └ modal.css
 │
 ├ App.tsx
 └ main.tsx

이 구조에서는 기능별로 화면을 찾기 어렵고 파일이 계속 증가하면 관리가 어려워지는 문제가 있었다.


리팩토링 후 구조

기능 단위(feature)로 화면을 재구성했다.

src
 ├ features
 │   ├ inventory
 │   │   ├ InventoryCurrent.tsx
 │   │   ├ SafetyStock.tsx
 │   │   └ LongTermStock.tsx
 │   │
 │   ├ inbound
 │   │   ├ Inbound.tsx
 │   │   └ InboundHistory.tsx
 │   │
 │   ├ outbound
 │   │   ├ Outbound.tsx
 │   │   └ OutboundHistory.tsx
 │   │
 │   ├ purchaseOrder
 │   │   ├ PurchaseOrderCreate.tsx
 │   │   └ PurchaseOrderHistory.tsx
 │   │
 │   ├ item
 │   │   ├ ItemList.tsx
 │   │   └ ItemCreate.tsx
 │   │
 │   ├ vendor
 │   │   └ VendorsList.tsx
 │   │
 │   └ warehouse
 │       ├ WarehouseStatus.tsx
 │       ├ WarehouseTransferCreate.tsx
 │       └ WarehouseTransferHistory.tsx
 │
 ├ components
 │   └ layout
 │       └ Layout.tsx
 │
 ├ styles
 │   ├ dashboard.css
 │   ├ inventory.css
 │   └ modal.css
 │
 ├ auth
 │   ├ Login.tsx
 │   └ Signup.tsx
 │
 ├ pages
 │   └ Dashboard.tsx
 │
 ├ App.tsx
 └ main.tsx

이 구조는 Backend 패키지 구조와도 자연스럽게 대응된다.


문제 상황

파일을 features 폴더로 이동한 후 Vite에서 아래와 같은 오류가 발생했다.

Failed to resolve import "../styles/dashboard.css"

예를 들어 SafetyStock.tsx 파일에서는 다음과 같은 import를 사용하고 있었다.

import "../styles/dashboard.css";
import "../styles/inventory.css";

하지만 파일 위치가 src/features/inventory/SafetyStock.tsx 로 이동하면서 상대경로가 더 이상 유효하지 않게 되었다.


원인

기존 파일 위치에서는 다음과 같은 상대경로가 정상적으로 동작했다.

src/pages/SafetyStock.tsx

import "../styles/dashboard.css";

하지만 파일이 features 폴더로 이동하면 실제 경로 구조는 다음과 같다.

src/features/inventory/SafetyStock.tsx
src/styles/dashboard.css

이 경우 기존 상대경로는 아래 위치를 찾게 된다.

src/features/styles/dashboard.css

즉 실제 CSS 위치와 경로가 맞지 않아 Vite가 파일을 찾지 못하는 상황이었다.


해결 방법

1. Vite alias 설정

상대경로 대신 절대경로 alias를 사용하기 위해 vite.config.js에 alias 설정을 추가했다.

import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { fileURLToPath, URL } from "node:url";

export default defineConfig({
  plugins: [react()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  }
});

이 설정을 통해 @src 디렉토리를 가리키게 된다.


2. TypeScript 경로 설정

Vite만 설정하면 런타임에서는 동작하지만 TypeScript와 VSCode에서는 경로를 인식하지 못한다. 따라서 tsconfig.json에도 동일한 설정을 추가해야 한다.

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["src/*"]
    }
  }
}

3. CSS import 경로 수정

기존 상대경로 import를 alias 기반 경로로 변경했다.

수정 전

import "../styles/dashboard.css";
import "../styles/inventory.css";
import "../styles/modal.css";

수정 후

import "@/styles/dashboard.css";
import "@/styles/inventory.css";
import "@/styles/modal.css";

이 방식은 파일 위치가 어디로 이동해도 동일하게 사용할 수 있다.


결과

feature 기반 폴더 구조를 유지하면서도 모든 CSS와 내부 모듈 import 경로가 정상적으로 동작하게 되었다. 또한 import 경로가 단순해지면서 코드 가독성도 개선되었다.

현재 Frontend 구조는 다음과 같이 정리된 상태다.

src
 ├ components
 ├ features
 ├ styles
 ├ auth
 ├ pages
 └ App.tsx

이 구조는 Backend Spring Boot의 feature 패키지 구조와도 자연스럽게 대응되기 때문에 전체 시스템을 이해하기도 쉬워졌다.


정리

  • pages 기반 구조를 feature 기반 구조로 리팩토링했다.
  • 파일 이동으로 인해 상대경로 import가 깨지는 문제가 발생했다.
  • vite.config.js와 tsconfig.json에 alias 설정을 추가했다.
  • CSS 및 내부 모듈 import를 @ 기반 경로로 통일했다.
profile
Develop

0개의 댓글