ERP-node/docs/backend-architecture-summar...

9.4 KiB
Raw Blame History

WACE ERP Backend - 아키텍처 요약

작성일: 2026-02-06
목적: 워크플로우 문서 통합용 백엔드 아키텍처 요약


1. 기술 스택

언어: TypeScript (Node.js 20.10.0+)
프레임워크: Express.js
데이터베이스: PostgreSQL (pg 라이브러리, Raw Query)
인증: JWT (jsonwebtoken)
스케줄러: node-cron
메일: nodemailer + IMAP
파일업로드: multer
외부DB: MySQL, MSSQL, Oracle 지원

2. 계층 구조

┌─────────────────┐
│   Controller    │ ← API 요청 수신, 응답 생성
└────────┬────────┘
         │
┌────────▼────────┐
│    Service      │ ← 비즈니스 로직, 트랜잭션 관리
└────────┬────────┘
         │
┌────────▼────────┐
│   Database      │ ← PostgreSQL Raw Query
└─────────────────┘

3. 디렉토리 구조

backend-node/src/
├── app.ts                 # Express 앱 진입점
├── config/                # 환경설정
├── controllers/           # 70+ 컨트롤러
├── services/              # 80+ 서비스
├── routes/                # 70+ 라우터
├── middleware/            # 인증/권한/에러핸들러
├── database/              # DB 연결 (pg Pool)
├── types/                 # TypeScript 타입 (26개)
└── utils/                 # 유틸리티 (JWT, 암호화, 로거)

4. 미들웨어 스택 순서

1. Process Level Exception Handlers (unhandledRejection, uncaughtException)
2. Helmet (보안 헤더)
3. Compression (Gzip)
4. Body Parser (JSON, URL-encoded, 10MB limit)
5. Static Files (/uploads)
6. CORS (credentials: true)
7. Rate Limiting (1 10000)
8. Token Auto Refresh (1시간 이내 만료  갱신)
9. API Routes (70+)
10. 404 Handler
11. Error Handler

5. 인증/인가 시스템

5.1 인증 흐름

로그인 요청
  ↓
AuthController.login()
  ↓
AuthService.processLogin()
  ├─ loginPwdCheck() → 비밀번호 검증 (bcrypt)
  ├─ getPersonBeanFromSession() → 사용자 정보 조회
  ├─ insertLoginAccessLog() → 로그인 이력 저장
  └─ JwtUtils.generateToken() → JWT 토큰 생성
  ↓
응답: { token, userInfo, firstMenuPath }

5.2 JWT Payload

{
  "userId": "user123",
  "userName": "홍길동",
  "companyCode": "ILSHIN",
  "userType": "COMPANY_ADMIN",
  "iat": 1234567890,
  "exp": 1234654290,
  "iss": "PMS-System"
}

5.3 권한 체계 (3단계)

권한 company_code userType 권한 범위
SUPER_ADMIN * SUPER_ADMIN 전체 회사, DDL 실행, 회사 생성/삭제
COMPANY_ADMIN ILSHIN COMPANY_ADMIN 자기 회사만, 사용자/설정 관리
USER ILSHIN USER 자기 회사만, 읽기/쓰기

6. 멀티테넌시 구현

핵심 원칙

// ✅ 올바른 패턴
const companyCode = req.user!.companyCode; // JWT에서 추출

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

// ❌ 잘못된 패턴 (보안 위험!)
const companyCode = req.body.companyCode; // 클라이언트에서 받음

슈퍼관리자 숨김 규칙

-- 일반 회사 사용자에게 슈퍼관리자(company_code='*')는 보이면 안 됨
SELECT * FROM user_info 
WHERE company_code = $1 
  AND company_code != '*'  -- 필수!

7. API 라우트 (70+개)

7.1 인증/관리자

  • POST /api/auth/login - 로그인
  • GET /api/auth/me - 현재 사용자 정보
  • POST /api/auth/switch-company - 회사 전환 (슈퍼관리자)
  • GET /api/admin/users - 사용자 목록
  • GET /api/admin/menus - 메뉴 목록

7.2 테이블/화면

  • GET /api/table-management/tables - 테이블 목록
  • POST /api/table-management/tables/:table/data - 데이터 조회
  • POST /api/table-management/multi-table-save - 다중 테이블 저장
  • GET /api/screen-management/screens - 화면 목록

7.3 플로우

  • GET /api/flow/definitions - 플로우 정의 목록
  • POST /api/flow/move - 데이터 이동 (단건)
  • POST /api/flow/move-batch - 데이터 이동 (다건)

7.4 외부 연동

  • GET /api/external-db-connections - 외부 DB 연결 목록
  • POST /api/external-db-connections/:id/test - 연결 테스트
  • POST /api/multi-connection/query - 멀티 DB 쿼리

7.5 배치

  • GET /api/batch-configs - 배치 설정 목록
  • POST /api/batch-management/:id/execute - 배치 즉시 실행

7.6 메일

  • POST /api/mail/send - 메일 발송
  • GET /api/mail/sent - 발송 이력

7.7 파일

  • POST /api/files/upload - 파일 업로드
  • GET /uploads/:filename - 정적 파일 서빙

8. 비즈니스 도메인 (8개)

도메인 컨트롤러 주요 기능
관리자 adminController 사용자/메뉴/권한 관리
테이블/화면 tableManagementController 메타데이터, 동적 화면 생성
플로우 flowController 워크플로우 엔진, 데이터 이동
데이터플로우 dataflowController ERD, 관계도
외부 연동 externalDbConnectionController 외부 DB/REST API
배치 batchController Cron 스케줄러, 데이터 동기화
메일 mailSendSimpleController 메일 발송/수신
파일 fileController 파일 업로드/다운로드

9. 데이터베이스 접근

Connection Pool 설정

{
  min: 2~5,          // 최소 연결 수
  max: 10~20,        // 최대 연결 수
  connectionTimeout: 30000,  // 30초
  idleTimeout: 600000,       // 10분
  statementTimeout: 60000    // 쿼리 실행 60초
}

Raw Query 패턴

// 1. 다중 행
const users = await query('SELECT * FROM user_info WHERE company_code = $1', [companyCode]);

// 2. 단일 행
const user = await queryOne('SELECT * FROM user_info WHERE user_id = $1', [userId]);

// 3. 트랜잭션
await transaction(async (client) => {
  await client.query('INSERT INTO table1 ...', [...]);
  await client.query('INSERT INTO table2 ...', [...]);
});

10. 외부 시스템 연동

지원 데이터베이스

  • PostgreSQL
  • MySQL
  • Microsoft SQL Server
  • Oracle

Connector Factory Pattern

DatabaseConnectorFactory
  ├── PostgreSQLConnector
  ├── MySQLConnector
  ├── MSSQLConnector
  └── OracleConnector

11. 배치/스케줄 시스템

Cron 스케줄러

// node-cron 기반
// 매일 새벽 2시: "0 2 * * *"
// 5분마다: "*/5 * * * *"
// 평일 오전 8시: "0 8 * * 1-5"

// 서버 시작 시 자동 초기화
BatchSchedulerService.initializeScheduler();

배치 실행 흐름

1. 소스 DB에서 데이터 조회
   ↓
2. 컬럼 매핑 적용
   ↓
3. 타겟 DB에 INSERT/UPDATE
   ↓
4. 실행 로그 기록 (batch_execution_logs)

12. 파일 처리

업로드 경로

uploads/
  └── {company_code}/
      └── {timestamp}-{uuid}-{filename}

Multer 설정

  • 최대 파일 크기: 10MB
  • 허용 타입: 이미지, PDF, Office 문서
  • 파일명 중복 방지: 타임스탬프 + UUID

13. 보안

암호화

  • 비밀번호: bcrypt (12 rounds)
  • 민감정보: AES-256-CBC (외부 DB 비밀번호 등)
  • JWT Secret: 환경변수 관리

보안 헤더

  • Helmet (CSP, X-Frame-Options)
  • CORS (credentials: true)
  • Rate Limiting (1분 10000회)

SQL Injection 방지

  • Parameterized Query 사용 (pg 라이브러리)
  • 동적 쿼리 빌더 패턴

14. 에러 핸들링

PostgreSQL 에러 코드 매핑

  • 23505 → "중복된 데이터"
  • 23503 → "참조 무결성 위반"
  • 23502 → "필수 입력값 누락"

프로세스 레벨

  • unhandledRejection → 로깅 (서버 유지)
  • uncaughtException → 로깅 (서버 유지, 주의)
  • SIGTERM/SIGINT → Graceful Shutdown

15. 로깅 (Winston)

로그 파일

  • logs/error.log - 에러만 (10MB × 5파일)
  • logs/combined.log - 전체 로그 (10MB × 10파일)

로그 레벨

error (0) → warn (1) → info (2) → debug (5)

16. 성능 최적화

Pool 모니터링

  • 5분마다 상태 체크
  • 대기 연결 5개 이상 시 경고

느린 쿼리 감지

  • 1초 이상 걸린 쿼리 자동 경고

캐싱 (Redis)

  • 메뉴 목록: 10분 TTL
  • 공통코드: 30분 TTL

Gzip 압축

  • 1KB 이상 응답만 압축 (레벨 6)

🎯 핵심 체크리스트

개발 시 반드시 지켜야 할 규칙

모든 쿼리에 company_code 필터 추가
JWT 토큰에서 company_code 추출 (클라이언트 신뢰 금지)
Parameterized Query 사용 (SQL Injection 방지)
슈퍼관리자 데이터 숨김 (company_code != '*')
비밀번호는 bcrypt, 민감정보는 AES-256
에러 핸들링 try/catch 필수
트랜잭션이 필요한 경우 transaction() 사용
파일 업로드는 회사별 디렉토리 분리


문서 버전: 1.0
마지막 업데이트: 2026-02-06