ERP-node/docs/WACE_SYSTEM_WORKFLOW.md

32 KiB

WACE ERP 시스템 전체 워크플로우 문서

작성일: 2026-02-06 분석 방법: Multi-Agent System (Backend + Frontend + DB 전문가 병렬 분석)


목차

  1. 시스템 개요
  2. 기술 스택
  3. 전체 아키텍처
  4. 백엔드 아키텍처
  5. 프론트엔드 아키텍처
  6. 데이터베이스 구조
  7. 인증/인가 워크플로우
  8. 화면 디자이너 워크플로우
  9. 사용자 업무 워크플로우
  10. 플로우 엔진 워크플로우
  11. 데이터플로우 시스템
  12. 대시보드 시스템
  13. 배치/스케줄 시스템
  14. 멀티테넌시 아키텍처
  15. 외부 연동
  16. 배포 환경

1. 시스템 개요

WACE는 로우코드(Low-Code) ERP 플랫폼이다. 관리자가 코드 없이 드래그앤드롭으로 업무 화면을 설계하면, 사용자는 해당 화면으로 바로 업무를 처리할 수 있는 구조다.

핵심 컨셉

관리자 → 화면 디자이너로 화면 설계 → 메뉴에 연결
                  ↓
사용자 → 메뉴 클릭 → 화면 자동 렌더링 → 업무 수행

주요 특징

  • 드래그앤드롭 화면 디자이너: 코드 없이 UI 구성
  • 동적 컴포넌트 시스템: V2 통합 컴포넌트 10종으로 모든 UI 표현
  • 플로우 엔진: 워크플로우(승인, 이동 등) 자동화
  • 데이터플로우: 비즈니스 로직을 비주얼 다이어그램으로 설계
  • 멀티테넌시: 회사별 완벽한 데이터 격리
  • 다국어 지원: KR/EN/CN 다국어 라벨 관리

2. 기술 스택

영역 기술 비고
Frontend Next.js 15 (App Router) React 19, TypeScript
UI 라이브러리 shadcn/ui + Radix UI Tailwind CSS 4
상태 관리 React Context + Zustand React Query (서버 상태)
Backend Node.js + Express TypeScript
Database PostgreSQL Raw Query (ORM 미사용)
인증 JWT 자동 갱신, 세션 관리
빌드/배포 Docker dev/prod 분리
포트 FE: 9771(dev)/5555(prod) BE: 8080

3. 전체 아키텍처

┌─────────────────────────────────────────────────────────────────┐
│                        사용자 브라우저                            │
│  Next.js App (React 19 + shadcn/ui + Tailwind CSS)              │
│  ├── 인증: JWT + Cookie + localStorage                          │
│  ├── 상태: Context + Zustand + React Query                      │
│  └── API: Axios Client (lib/api/)                               │
└──────────────────────────┬──────────────────────────────────────┘
                           │ HTTP/JSON (JWT Bearer Token)
                           ↓
┌─────────────────────────────────────────────────────────────────┐
│                     Express Backend (Node.js)                    │
│  ├── Middleware: Helmet → CORS → RateLimit → Auth → Permission  │
│  ├── Routes: 60+ 모듈                                           │
│  ├── Controllers: 69개                                          │
│  ├── Services: 87개                                             │
│  └── Database: pg Pool (Raw Query)                              │
└──────────────────────────┬──────────────────────────────────────┘
                           │ TCP/SQL
                           ↓
┌─────────────────────────────────────────────────────────────────┐
│                     PostgreSQL Database                          │
│  ├── 시스템 테이블: 사용자, 회사, 메뉴, 권한, 화면              │
│  ├── 메타데이터: 테이블/컬럼 정의, 코드, 카테고리               │
│  ├── 비즈니스: 동적 생성 테이블 (화면별)                        │
│  └── 멀티테넌시: 모든 테이블에 company_code                     │
└─────────────────────────────────────────────────────────────────┘

4. 백엔드 아키텍처

4.1 디렉토리 구조

backend-node/src/
├── app.ts                     # Express 앱 진입점
├── config/                    # 환경설정, Multer
├── controllers/               # 69개 컨트롤러
├── services/                  # 87개 서비스
├── routes/                    # 60+ 라우트 모듈
├── middleware/                # 인증, 권한, 에러 처리
│   ├── authMiddleware.ts      # JWT 인증
│   ├── permissionMiddleware.ts # 3단계 권한 체크
│   ├── superAdminMiddleware.ts # 슈퍼관리자 전용
│   └── errorHandler.ts       # 전역 에러 처리
├── database/                  # DB 연결, 커넥터 팩토리
│   ├── db.ts                  # PostgreSQL Pool
│   ├── DatabaseConnectorFactory.ts
│   ├── PostgreSQLConnector.ts
│   ├── MySQLConnector.ts
│   └── MariaDBConnector.ts
├── types/                     # TypeScript 타입 (26개)
└── utils/                     # 유틸리티 (16개)

4.2 미들웨어 스택 (실행 순서)

요청 → Helmet (보안 헤더)
     → Compression (응답 압축)
     → Body Parser (JSON/URLEncoded, 10MB)
     → CORS (교차 출처 허용)
     → Rate Limiter (10,000 req/min)
     → Token Refresh (자동 갱신)
     → Route Handlers (비즈니스 로직)
     → Error Handler (전역 에러 처리)

4.3 API 라우트 도메인별 분류

인증/사용자 관리

라우트 역할
/api/auth 로그인, 로그아웃, 토큰 갱신, 회사 전환
/api/admin/users 사용자 CRUD, 비밀번호 초기화, 상태 변경
/api/company-management 회사 CRUD
/api/departments 부서 관리
/api/roles 권한 그룹 관리

화면/메뉴 관리

라우트 역할
/api/screen-management 화면 정의 CRUD, 그룹, 파일, 임베딩
/api/admin/menus 메뉴 트리 CRUD, 화면 할당
/api/table-management 테이블 CRUD, 엔티티 조인, 카테고리
/api/common-codes 공통 코드/카테고리 관리
/api/multilang 다국어 키/번역 관리

데이터 관리

라우트 역할
/api/data 동적 테이블 CRUD, 조인 쿼리
/api/data/:tableName 특정 테이블 데이터 조회
/api/data/join 조인 쿼리 실행
/api/dynamic-form 동적 폼 데이터 저장
/api/entity-search 엔티티 검색
/api/entity-reference 엔티티 참조
/api/numbering-rules 채번 규칙 관리
/api/cascading-* 연쇄 드롭다운 관계

자동화

라우트 역할
/api/flow 플로우 정의/단계/연결/실행
/api/dataflow 데이터플로우 다이어그램/실행
/api/batch-configs 배치 작업 설정
/api/batch-management 배치 작업 관리
/api/batch-execution-logs 배치 실행 로그

대시보드/리포트

라우트 역할
/api/dashboards 대시보드 CRUD, 쿼리 실행
/api/reports 리포트 생성

외부 연동

라우트 역할
/api/external-db-connections 외부 DB 연결 (PostgreSQL, MySQL, MariaDB, MSSQL, Oracle)
/api/external-rest-api-connections 외부 REST API 연결
/api/mail 메일 발송/수신/템플릿
/api/tax-invoice 세금계산서

특수 도메인

라우트 역할
/api/delivery 배송/화물 관리
/api/risk-alerts 위험 알림
/api/todos 할일 관리
/api/bookings 예약 관리
/api/digital-twin 디지털 트윈 (야드 모니터링)
/api/schedule 스케줄 자동 생성
/api/vehicle 차량 운행
/api/driver 운전자 관리
/api/files 파일 업로드/다운로드
/api/ddl DDL 실행 (슈퍼관리자 전용)

4.4 서비스 레이어 패턴

// 표준 서비스 패턴
class ExampleService {
  // 목록 조회 (멀티테넌시 적용)
  async findAll(companyCode: string, filters?: any) {
    if (companyCode === "*") {
      // 슈퍼관리자: 전체 데이터
      return await db.query("SELECT * FROM table ORDER BY company_code");
    } else {
      // 일반 사용자: 자기 회사 데이터만
      return await db.query(
        "SELECT * FROM table WHERE company_code = $1", 
        [companyCode]
      );
    }
  }
}

4.5 에러 처리 전략

// 전역 에러 핸들러 (errorHandler.ts)
- PostgreSQL 에러: 중복키(23505), 외래키(23503),  제약(23502) 
- JWT 에러: 만료, 유효하지 않은 토큰
- 일반 에러: 500 Internal Server Error
- 개발 환경: 상세 에러 스택 포함
- 운영 환경: 일반적인 에러 메시지만 반환

5. 프론트엔드 아키텍처

5.1 디렉토리 구조

frontend/
├── app/                          # Next.js App Router
│   ├── (auth)/                   # 인증 (로그인)
│   ├── (main)/                   # 메인 앱 (인증 필요)
│   ├── (pop)/                    # 모바일/팝업
│   └── (admin)/                  # 특수 관리자
├── components/                   # React 컴포넌트
│   ├── screen/                   # 화면 디자이너 & 뷰어
│   ├── admin/                    # 관리 기능
│   ├── dashboard/                # 대시보드 위젯
│   ├── dataflow/                 # 데이터플로우 디자이너
│   ├── v2/                       # V2 통합 컴포넌트
│   ├── ui/                       # shadcn/ui 기본 컴포넌트
│   └── report/                   # 리포트 디자이너
├── lib/
│   ├── api/                      # API 클라이언트 (57개 모듈)
│   ├── registry/                 # 컴포넌트 레지스트리 (482개)
│   ├── utils/                    # 유틸리티
│   └── v2-core/                  # V2 코어 로직
├── contexts/                     # React Context (인증, 메뉴, 화면 등)
├── hooks/                        # Custom Hooks
├── stores/                       # Zustand 상태관리
└── middleware.ts                 # Next.js 인증 미들웨어

5.2 페이지 라우팅 구조

/login                             → 로그인
/main                              → 메인 대시보드
/screens/[screenId]                → 동적 화면 뷰어 (사용자)

/admin/screenMng/screenMngList     → 화면 관리
/admin/screenMng/dashboardList     → 대시보드 관리
/admin/screenMng/reportList        → 리포트 관리
/admin/systemMng/tableMngList      → 테이블 관리
/admin/systemMng/commonCodeList    → 공통코드 관리
/admin/systemMng/dataflow          → 데이터플로우 관리
/admin/systemMng/i18nList          → 다국어 관리
/admin/userMng/userMngList         → 사용자 관리
/admin/userMng/companyList         → 회사 관리
/admin/userMng/rolesList           → 권한 관리
/admin/automaticMng/flowMgmtList   → 플로우 관리
/admin/automaticMng/batchmngList   → 배치 관리
/admin/automaticMng/mail/*         → 메일 시스템
/admin/menu                        → 메뉴 관리

/dashboard/[dashboardId]           → 대시보드 뷰어
/pop/work                          → 모바일 작업 화면

5.3 V2 통합 컴포넌트 시스템

"하나의 컴포넌트, 여러 모드" 철학으로 설계된 10개 통합 컴포넌트:

컴포넌트 모드 역할
V2Input text, number, password, slider, color 텍스트/숫자 입력
V2Select dropdown, radio, checkbox, tag, toggle 선택 입력
V2Date date, datetime, time, range 날짜/시간 입력
V2List table, card, kanban, list 데이터 목록 표시
V2Layout grid, split-panel, flex 레이아웃 구성
V2Group tab, accordion, section, modal 그룹 컨테이너
V2Media image, video, audio, file 미디어 표시
V2Biz flow, rack, numbering-rule 비즈니스 로직
V2Hierarchy tree, org-chart, BOM, cascading 계층 구조
V2Repeater inline-table, modal, button 반복 데이터

5.4 API 클라이언트 규칙

// 절대 금지: fetch 직접 사용
const res = await fetch('/api/flow/definitions'); // ❌

// 반드시 사용: lib/api/ 클라이언트
import { getFlowDefinitions } from '@/lib/api/flow';
const res = await getFlowDefinitions(); // ✅

환경별 URL 자동 처리:

환경 프론트엔드 백엔드 API
로컬 개발 localhost:9771 localhost:8080/api
운영 v1.vexplor.com api.vexplor.com/api

5.5 상태 관리 체계

전역 상태
├── AuthContext          → 인증/세션/토큰
├── MenuContext          → 메뉴 트리/권한
├── ScreenPreviewContext → 프리뷰 모드
├── ScreenMultiLangContext → 다국어 라벨
├── TableOptionsContext  → 테이블 옵션
└── ActiveTabContext     → 활성 탭

로컬 상태
├── Zustand Stores       → 화면 디자이너 상태, 사용자 상태
└── React Query          → 서버 데이터 캐시 (5분 stale, 30분 GC)

5.6 레지스트리 시스템

// 컴포넌트 등록 (482개 등록됨)
ComponentRegistry.registerComponent({
  id: "v2-input",
  name: "통합 입력",
  category: ComponentCategory.V2,
  component: V2Input,
  configPanel: V2InputConfigPanel,
  defaultConfig: { inputType: "text" }
});

// 동적 렌더링
<DynamicComponentRenderer
  component={componentData}
  formData={formData}
  onFormDataChange={handleChange}
/>

6. 데이터베이스 구조

6.1 테이블 도메인별 분류

사용자/인증/회사

테이블 역할
company_mng 회사 마스터
user_info 사용자 정보
user_info_history 사용자 변경 이력
user_dept 사용자-부서 매핑
dept_info 부서 정보
authority_master 권한 그룹 마스터
authority_sub_user 사용자-권한 매핑
login_access_log 로그인 로그

메뉴/화면

테이블 역할
menu_info 메뉴 트리 구조
screen_definitions 화면 정의 (screenId, 테이블명 등)
screen_layouts_v2 V2 레이아웃 (JSON)
screen_layouts V1 레이아웃 (레거시)
screen_groups 화면 그룹 (계층구조)
screen_group_screens 화면-그룹 매핑
screen_menu_assignments 화면-메뉴 할당
screen_field_joins 화면 필드 조인 설정
screen_data_flows 화면 데이터 플로우
screen_table_relations 화면-테이블 관계

메타데이터

테이블 역할
table_type_columns 테이블 타입별 컬럼 정의 (회사별)
table_column_category_values 컬럼 카테고리 값
code_category 공통 코드 카테고리
code_info 공통 코드 값
category_column_mapping 카테고리-컬럼 매핑
cascading_relation 연쇄 드롭다운 관계
numbering_rules 채번 규칙
numbering_rule_parts 채번 규칙 파트

플로우/자동화

테이블 역할
flow_definition 플로우 정의
flow_step 플로우 단계
flow_step_connection 플로우 단계 연결
node_flows 노드 플로우 (버튼 액션)
dataflow_diagrams 데이터플로우 다이어그램
batch_definitions 배치 작업 정의
batch_schedules 배치 스케줄
batch_execution_logs 배치 실행 로그

외부 연동

테이블 역할
external_db_connections 외부 DB 연결 정보
external_rest_api_connections 외부 REST API 연결

다국어

테이블 역할
multi_lang_key_master 다국어 키 마스터

기타

테이블 역할
work_history 작업 이력
todo_items 할일 목록
file_uploads 파일 업로드
ddl_audit_log DDL 감사 로그

6.2 동적 테이블 생성 패턴

관리자가 화면 생성 시 비즈니스 테이블이 동적으로 생성된다:

CREATE TABLE "dynamic_table_name" (
  "id" VARCHAR(500) PRIMARY KEY DEFAULT gen_random_uuid()::text,
  "created_date" TIMESTAMP DEFAULT now(),
  "updated_date" TIMESTAMP DEFAULT now(),
  "writer" VARCHAR(500),
  "company_code" VARCHAR(500),    -- 멀티테넌시 필수!
  -- 사용자 정의 컬럼들 (모두 VARCHAR(500))
  "product_name" VARCHAR(500),
  "price" VARCHAR(500),
  ...
);
CREATE INDEX idx_dynamic_company ON "dynamic_table_name"(company_code);

6.3 테이블 관계도

company_mng (company_code PK)
    │
    ├── user_info (company_code FK)
    │       ├── authority_sub_user (user_id FK)
    │       └── user_dept (user_id FK)
    │
    ├── menu_info (company_code)
    │       └── screen_menu_assignments (menu_objid FK)
    │
    ├── screen_definitions (company_code)
    │       ├── screen_layouts_v2 (screen_id FK)
    │       ├── screen_groups → screen_group_screens (screen_id FK)
    │       └── screen_field_joins (screen_id FK)
    │
    ├── authority_master (company_code)
    │       └── authority_sub_user (master_objid FK)
    │
    ├── flow_definition (company_code)
    │       ├── flow_step (flow_id FK)
    │       └── flow_step_connection (flow_id FK)
    │
    └── [동적 비즈니스 테이블들] (company_code)

7. 인증/인가 워크플로우

7.1 로그인 프로세스

┌─── 사용자 ───┐     ┌─── 프론트엔드 ───┐     ┌─── 백엔드 ───┐     ┌─── DB ───┐
│              │     │                  │     │              │     │          │
│ ID/PW 입력   │────→│ POST /auth/login │────→│ 비밀번호 검증 │────→│ user_info│
│              │     │                  │     │              │     │ 조회     │
│              │     │                  │     │ JWT 토큰 생성 │     │          │
│              │     │                  │←────│ 토큰 반환     │     │          │
│              │     │                  │     │              │     │          │
│              │     │ localStorage 저장│     │              │     │          │
│              │     │ Cookie 저장      │     │              │     │          │
│              │     │ /main 리다이렉트 │     │              │     │          │
└──────────────┘     └──────────────────┘     └──────────────┘     └──────────┘

7.2 JWT 토큰 관리

토큰 저장: localStorage (주 저장소) + Cookie (SSR 미들웨어용)

자동 갱신:
├── 10분마다 만료 시간 체크
├── 만료 30분 전: 백그라운드 자동 갱신
├── 401 응답 시: 즉시 갱신 시도
└── 갱신 실패 시: /login 리다이렉트

세션 관리:
├── 데스크톱: 30분 비활성 → 세션 만료 (5분 전 경고)
└── 모바일: 24시간 비활성 → 세션 만료 (1시간 전 경고)

7.3 권한 체계 (3단계)

SUPER_ADMIN (company_code = "*")
├── 모든 회사 데이터 접근 가능
├── DDL 실행 가능
├── 시스템 설정 변경
└── 다른 회사로 전환 (switch-company)

COMPANY_ADMIN (userType = "COMPANY_ADMIN")
├── 자기 회사 데이터만 접근
├── 사용자 관리 가능
└── 메뉴/화면 관리 가능

USER (일반 사용자)
├── 자기 회사 데이터만 접근
├── 권한 그룹에 따른 메뉴 접근
└── 할당된 화면만 사용 가능

8. 화면 디자이너 워크플로우

8.1 관리자: 화면 설계

Step 1: 화면 생성
  └→ /admin/screenMng/screenMngList
  └→ "새 화면" 클릭 → 화면명, 설명, 메인 테이블 입력

Step 2: 화면 디자이너 진입 (ScreenDesigner.tsx)
  ├── 좌측 패널: 컴포넌트 팔레트 (V2 컴포넌트 10종)
  ├── 중앙 캔버스: 드래그앤드롭 영역
  └── 우측 패널: 선택된 컴포넌트 속성 설정

Step 3: 컴포넌트 배치
  └→ V2Input 드래그 → 캔버스 배치 → 속성 설정:
       ├── 위치: x, y 좌표
       ├── 크기: width, height
       ├── 데이터 바인딩: columnName = "product_name"
       ├── 라벨: "제품명"
       ├── 조건부 표시: 특정 조건에서만 보이기
       └── 플로우 연결: 버튼 클릭 시 실행할 플로우

Step 4: 레이아웃 저장
  └→ screen_layouts_v2 테이블에 JSON 형태로 저장
  └→ Zod 스키마 검증 → V2 형식 우선, V1 호환 저장

Step 5: 메뉴에 화면 할당
  └→ /admin/menu → 메뉴 트리에서 "제품 관리" 선택
  └→ 화면 연결 (screen_menu_assignments)

8.2 화면 레이아웃 저장 구조 (V2)

{
  "version": "v2",
  "components": [
    {
      "id": "comp-1",
      "componentType": "v2-input",
      "position": { "x": 100, "y": 50 },
      "size": { "width": 200, "height": 40 },
      "config": {
        "inputType": "text",
        "columnName": "product_name",
        "label": "제품명",
        "required": true
      }
    },
    {
      "id": "comp-2",
      "componentType": "v2-list",
      "position": { "x": 100, "y": 150 },
      "size": { "width": 600, "height": 400 },
      "config": {
        "listType": "table",
        "tableName": "products",
        "columns": ["product_name", "price", "quantity"]
      }
    }
  ]
}

9. 사용자 업무 워크플로우

9.1 전체 흐름

사용자 로그인
    ↓
메인 대시보드 (/main)
    ↓
좌측 메뉴에서 "제품 관리" 클릭
    ↓
/screens/[screenId] 라우팅
    ↓
InteractiveScreenViewer 렌더링
    ├── screen_definitions에서 화면 정보 로드
    ├── screen_layouts_v2에서 레이아웃 JSON 로드
    ├── V2 → Legacy 변환 (호환성)
    └── 메인 테이블 데이터 자동 로드
    ↓
컴포넌트별 렌더링
    ├── V2Input → formData 바인딩
    ├── V2List → 테이블 데이터 표시
    ├── V2Select → 드롭다운/라디오 선택
    └── Button → 플로우/액션 연결
    ↓
사용자 인터랙션
    ├── 폼 입력 → formData 업데이트
    ├── 테이블 행 선택 → selectedRowsData 업데이트
    └── 버튼 클릭 → 플로우 실행
    ↓
플로우 실행 (nodeFlowButtonExecutor)
    ├── Step 1: 데이터 검증
    ├── Step 2: API 호출 (INSERT/UPDATE/DELETE)
    ├── Step 3: 성공/실패 처리
    └── Step 4: 테이블 자동 새로고침

9.2 조건부 표시 워크플로우

관리자 설정:
  "특별 할인 입력" 컴포넌트
  └→ 조건: product_type === "PREMIUM" 일 때만 표시

사용자 사용:
  1. 화면 진입 → evaluateConditional() 실행
  2. product_type ≠ "PREMIUM" → "특별 할인 입력" 숨김
  3. 사용자가 product_type을 "PREMIUM"으로 변경
  4. formData 업데이트 → evaluateConditional() 재평가
  5. product_type === "PREMIUM" → "특별 할인 입력" 표시!

10. 플로우 엔진 워크플로우

10.1 플로우 정의 (관리자)

/admin/automaticMng/flowMgmtList
    ↓
플로우 생성:
  ├── 이름: "제품 승인 플로우"
  ├── 테이블: "products"
  └── 단계 정의:
       Step 1: "신청" (requester)
       Step 2: "부서장 승인" (manager)
       Step 3: "최종 승인" (director)
       연결: Step 1 → Step 2 → Step 3

10.2 플로우 실행 (사용자)

1. 사용자: 제품 신청
   └→ "저장" 버튼 클릭
   └→ flowApi.startFlow() → 상태: "부서장 승인 대기"

2. 부서장: 승인 화면
   └→ V2Biz (flow) 컴포넌트 → 현재 단계 표시
   └→ [승인] 클릭 → flowApi.approveStep()
   └→ 상태: "최종 승인 대기"

3. 이사: 최종 승인
   └→ [승인] 클릭 → flowApi.approveStep()
   └→ 상태: "완료"
   └→ products.approval_status = "APPROVED"

10.3 데이터 이동 (moveData)

플로우의 핵심 동작: 데이터를 한 스텝에서 다음 스텝으로 이동

Step 1 (접수) → Step 2 (검토) → Step 3 (완료)
   ├── 단건 이동: moveData(flowId, dataId, fromStep, toStep)
   └── 배치 이동: moveBatchData(flowId, dataIds[], fromStep, toStep)

11. 데이터플로우 시스템

11.1 개요

데이터플로우는 비즈니스 로직을 비주얼 다이어그램으로 설계하는 시스템이다.

/admin/systemMng/dataflow
    ↓
React Flow 기반 캔버스
    ├── InputNode: 데이터 입력 (폼 데이터, 테이블 데이터)
    ├── TransformNode: 데이터 변환 (매핑, 필터링, 계산)
    ├── DatabaseNode: DB 조회/저장
    ├── RestApiNode: 외부 API 호출
    ├── ConditionNode: 조건 분기
    ├── LoopNode: 반복 처리
    ├── MergeNode: 데이터 합치기
    └── OutputNode: 결과 출력

11.2 데이터플로우 실행

버튼 클릭 → 데이터플로우 트리거
    ↓
InputNode: formData 수집
    ↓
TransformNode: 데이터 가공
    ↓
ConditionNode: 조건 분기 (가격 > 10000?)
    ├── Yes → DatabaseNode: INSERT INTO premium_products
    └── No  → DatabaseNode: INSERT INTO standard_products
    ↓
OutputNode: 결과 반환 → toast.success("저장 완료")

12. 대시보드 시스템

12.1 구조

관리자: /admin/screenMng/dashboardList
    └→ 대시보드 생성 → 위젯 추가 → 레이아웃 저장

사용자: /dashboard/[dashboardId]
    └→ 위젯 그리드 렌더링 → 실시간 데이터 표시

12.2 위젯 종류

카테고리 위젯 역할
시각화 CustomMetricWidget 커스텀 메트릭 표시
StatusSummaryWidget 상태 요약
리스트 CargoListWidget 화물 목록
VehicleListWidget 차량 목록
지도 MapTestWidget 지도 표시
WeatherMapWidget 날씨 지도
작업 TodoWidget 할일 목록
WorkHistoryWidget 작업 이력
알림 BookingAlertWidget 예약 알림
RiskAlertWidget 위험 알림
기타 ClockWidget 시계
CalendarWidget 캘린더

13. 배치/스케줄 시스템

13.1 구조

관리자: /admin/automaticMng/batchmngList
    ↓
배치 작업 생성:
    ├── 이름: "일일 재고 집계"
    ├── 실행 쿼리: SQL 또는 데이터플로우 ID
    ├── 스케줄: Cron 표현식 ("0 0 * * *" = 매일 자정)
    └── 활성화/비활성화
    ↓
배치 스케줄러 (batch_schedules)
    ↓
자동 실행 → 실행 로그 (batch_execution_logs)

13.2 배치 실행 흐름

Cron 트리거 → 배치 정의 조회 → SQL/데이터플로우 실행
    ↓
성공: execution_log에 "SUCCESS" 기록
실패: execution_log에 "FAILED" + 에러 메시지 기록

14. 멀티테넌시 아키텍처

14.1 핵심 원칙

모든 비즈니스 테이블: company_code 컬럼 필수
모든 쿼리: WHERE company_code = $1 필수
모든 JOIN: ON a.company_code = b.company_code 필수
모든 집계: GROUP BY company_code 필수

14.2 데이터 격리

회사 A (company_code = "COMPANY_A"):
  └→ 자기 데이터만 조회/수정/삭제 가능

회사 B (company_code = "COMPANY_B"):
  └→ 자기 데이터만 조회/수정/삭제 가능

슈퍼관리자 (company_code = "*"):
  └→ 모든 회사 데이터 조회 가능
  └→ 일반 회사는 "*" 데이터를 볼 수 없음

중요: company_code = "*"는 공통 데이터가 아니라 슈퍼관리자 전용 데이터!

14.3 코드 패턴

// 백엔드 표준 패턴
const companyCode = req.user!.companyCode;

if (companyCode === "*") {
  // 슈퍼관리자: 전체 데이터
  query = "SELECT * FROM table ORDER BY company_code";
} else {
  // 일반 사용자: 자기 회사만, "*" 제외
  query = "SELECT * FROM table WHERE company_code = $1 AND company_code != '*'";
  params = [companyCode];
}

15. 외부 연동

15.1 외부 DB 연결

지원 DB: PostgreSQL, MySQL, MariaDB, MSSQL, Oracle

관리: /api/external-db-connections
    ├── 연결 정보 등록 (host, port, database, credentials)
    ├── 연결 테스트
    ├── 쿼리 실행
    └── 데이터플로우에서 DatabaseNode로 사용

15.2 외부 REST API 연결

관리: /api/external-rest-api-connections
    ├── API 엔드포인트 등록 (URL, method, headers)
    ├── 인증 설정 (Bearer, Basic, API Key)
    ├── 테스트 호출
    └── 데이터플로우에서 RestApiNode로 사용

15.3 메일 시스템

관리: /admin/automaticMng/mail/*
    ├── 메일 템플릿 관리
    ├── 메일 발송 (개별/대량)
    ├── 수신 메일 확인
    └── 발송 이력 조회

16. 배포 환경

16.1 Docker 구성

개발 환경 (Mac):
├── docker/dev/docker-compose.backend.mac.yml  (BE: 8080)
└── docker/dev/docker-compose.frontend.mac.yml (FE: 9771)

운영 환경:
├── docker/prod/docker-compose.backend.prod.yml  (BE: 8080)
└── docker/prod/docker-compose.frontend.prod.yml (FE: 5555)

16.2 서버 정보

환경 서버 포트 DB
개발 39.117.244.52 FE:9771, BE:8080 39.117.244.52:11132
운영 211.115.91.141 FE:5555, BE:8080 211.115.91.141:11134

16.3 백엔드 시작 시 자동 작업

서버 시작 (app.ts)
    ├── 마이그레이션 실행 (DB 스키마 업데이트)
    ├── 배치 스케줄러 초기화
    ├── 위험 알림 캐시 로드
    └── 메일 정리 Cron 시작

부록: 업무 진행 요약

새로운 업무 화면을 만드는 전체 프로세스

1. [DB] 테이블 관리에서 비즈니스 테이블 생성
   └→ 컬럼 정의, 타입 설정

2. [화면] 화면 관리에서 새 화면 생성
   └→ 메인 테이블 지정

3. [디자인] 화면 디자이너에서 UI 구성
   └→ V2 컴포넌트 배치, 데이터 바인딩

4. [로직] 데이터플로우 설계 (필요시)
   └→ 저장/수정/삭제 로직 다이어그램

5. [플로우] 플로우 정의 (승인 프로세스 필요시)
   └→ 단계 정의, 연결

6. [메뉴] 메뉴에 화면 할당
   └→ 사용자가 접근할 수 있게 메뉴 트리 배치

7. [권한] 권한 그룹에 메뉴 할당
   └→ 특정 사용자 그룹만 접근 가능하게

8. [사용] 사용자가 메뉴 클릭 → 업무 시작!