Files
frontend/docs/st/04.아키텍처패턴.md
T

6.5 KiB

04. 아키텍처 패턴

ST 앱이 채택한 FSD(Feature-Sliced Design) 아키텍처 및 전체 데이터 흐름을 설명합니다.


1. FSD(Feature-Sliced Design) 아키텍처

FSD는 레이어(Layer) 계층 간 단방향 의존성을 강제하는 프론트엔드 아키텍처 방법론입니다.
"하위 레이어는 상위 레이어를 참조할 수 없다" 는 규칙이 핵심입니다.

┌─────────────────────────────────────────┐
│          app / pages (라우팅)            │  ← 최상위 (조합)
├─────────────────────────────────────────┤
│          components (업무 UI)            │
├─────────────────────────────────────────┤
│          entities (도메인 엔티티)         │  ← API 서비스 + 타입
├─────────────────────────────────────────┤
│          shared (공통 기반)              │  ← 최하위 (재사용)
└─────────────────────────────────────────┘

각 레이어는 내부적으로 슬라이스(Slice)와 세그먼트(Segment)로 세분화됩니다.

레이어/슬라이스/세그먼트
예시: entities/statistics/api/
     entities/statistics/model/

2. 레이어별 역할과 의존성 방향

🔷 shared - 공통 기반 레이어

  • 역할: 모든 레이어에서 공유 가능한 순수 유틸리티, API 클라이언트, 타입, 훅, 스토어 정의
  • 의존성: 다른 레이어를 참조하지 않음 (최하위)
  • 주요 내용: client.ts, use-mutation-wrapper, Zustand 스토어 정의, 환경변수 설정

🔶 entities - 비즈니스 도메인 레이어

  • 역할: 하나의 비즈니스 도메인(auth, menu, statistics 등)을 API 서비스와 타입으로 캡슐화
  • 의존성: shared만 참조 가능
  • 주요 내용: API 서비스 함수, 요청/응답 인터페이스 타입

🟩 components - UI 컴포넌트 레이어

  • 역할: 업무 화면을 구성하는 React 컴포넌트. 서버 데이터 페칭 로직 포함
  • 의존성: shared, entities 참조 가능
  • 주요 내용: 화면별 컴포넌트, module 공통 컴포넌트(DataGrid, SearchForm 등)

🟦 app / pages - 라우팅 레이어

  • 역할: Next.js 라우팅 연결. 컴포넌트를 조합하여 최종 페이지 구성
  • 의존성: 모든 하위 레이어 참조 가능

3. 미들웨어 기반 API 프록시 아키텍처

클라이언트가 백엔드 API를 직접 호출하지 않고 Next.js Middleware를 통해 프록시합니다.

Browser
  │
  │  요청: /server/st-management-service/...
  ▼
Next.js Middleware (middleware.ts)
  │
  ├─ /server/st-management-service/* → ST 전용 백엔드 서버
  ├─ /server/st-input-service/*      → ST 입력 서비스 서버
  ├─ /server/*                       → 일반 백엔드 서버 (Spring Boot 등)
  ├─ /attach-service/*               → 파일 첨부 서비스
  └─ /api/link/*                     → 외부 링크 백엔드 API

핵심 동작:

  1. 요청 URL 경로(pathname)를 패턴 매칭
  2. 쿠키에서 JWT 토큰(CLAIM_NAME)과 사용자 ID(AUTH_USER_ID) 추출
  3. 해당 값을 요청 헤더에 주입 후 실제 백엔드로 URL 재작성(NextResponse.rewrite)
  4. 응답에 CSP 보안 헤더 추가

4. 멀티 백엔드 분리 구조

┌─────────────────────────────────────────────────────────┐
│                    ST 프론트엔드 앱                       │
│                                                         │
│  src/shared/api/client.ts                               │
│  ┌──────────────────┐   ┌──────────────────────────┐   │
│  │   client         │   │   stClient                │   │
│  │  (일반 API)       │   │  (ST 서비스 전용 API)     │   │
│  └──────────────────┘   └──────────────────────────┘   │
└─────────────────────────────────────────────────────────┘
         │                           │
         ▼                           ▼
 일반 백엔드 (Spring)          ST 전용 백엔드 서비스
 BASE_URL                      ST_SERVICE_BASE_URL

5. 컴포넌트 데이터 흐름

통계 화면을 예시로 데이터 흐름을 설명합니다.

app/(with-base-layout)/...              ← 라우팅 진입
         │
         ▼
components/statistics/input/
  StatsInputStatusInp.tsx               ← 페이지 컴포넌트
         │
         ├── [검색 이벤트] handleSearch()
         │          │
         │          ▼
         │   entities/statistics/api/
         │     statistics-input-status-service.ts   ← API 서비스
         │          │
         │          ▼
         │   shared/api/client.ts (stClient)         ← Axios 인스턴스
         │          │
         │          ▼
         │   middleware.ts                           ← Next.js 프록시
         │          │
         │          ▼
         │   ST 백엔드 API 서버
         │
         ├── [상태 관리] useSWR / useTabStore / useAlertStore
         │
         └── [렌더링] SearchForm + DataGrid(RealGrid) + 버튼

6. 탭 기반 네비게이션 패턴

ST 앱은 메뉴를 클릭하면 새 페이지로 이동하는 것이 아니라, 탭(Tab)을 추가하는 방식으로 내비게이션이 동작합니다.

메뉴 클릭
   │
   ▼
useTabStore.addTab()
   │
   ├── 이미 열린 탭이면 → 해당 탭 활성화 전환만
   └── 새 탭이면 → 탭 목록에 추가 (최대 10개 제한)
          │
          ▼
   activeTabId 변경
          │
          ▼
   각 화면 컴포넌트:
   useEffect([activeTabId]) → 탭 포커스 감지 → mutate() 데이터 갱신