9.4 KiB
9.4 KiB
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