
이번 작업에서는 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가 파일을 찾지 못하는 상황이었다.
상대경로 대신 절대경로 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 디렉토리를 가리키게 된다.
Vite만 설정하면 런타임에서는 동작하지만 TypeScript와 VSCode에서는 경로를 인식하지 못한다. 따라서 tsconfig.json에도 동일한 설정을 추가해야 한다.
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/*": ["src/*"]
}
}
}
기존 상대경로 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 패키지 구조와도 자연스럽게 대응되기 때문에 전체 시스템을 이해하기도 쉬워졌다.
@ 기반 경로로 통일했다.