- Deleted the following files as they are no longer relevant to the current project structure: - 결재 시스템 구현 현황 - 결재 시스템 v2 사용 가이드 - WACE 시스템 문제점 분석 및 개선 계획 - Agent Pipeline 한계점 분석 - AI 기반 화면 자동 생성 시스템 설계서 - WACE ERP Backend - 분석 문서 인덱스 These deletions help streamline the documentation and remove obsolete information, ensuring that only current and relevant resources are maintained.
32 KiB
32 KiB
WACE ERP 시스템 전체 워크플로우 문서
작성일: 2026-02-06 분석 방법: Multi-Agent System (Backend + Frontend + DB 전문가 병렬 분석)
목차
- 시스템 개요
- 기술 스택
- 전체 아키텍처
- 백엔드 아키텍처
- 프론트엔드 아키텍처
- 데이터베이스 구조
- 인증/인가 워크플로우
- 화면 디자이너 워크플로우
- 사용자 업무 워크플로우
- 플로우 엔진 워크플로우
- 데이터플로우 시스템
- 대시보드 시스템
- 배치/스케줄 시스템
- 멀티테넌시 아키텍처
- 외부 연동
- 배포 환경
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. [사용] 사용자가 메뉴 클릭 → 업무 시작!