ERP-node/docs/backend-analysis-response.json

240 lines
10 KiB
JSON
Raw Permalink Normal View History

{
"status": "success",
"confidence": "high",
"result": {
"summary": "WACE ERP 백엔드 전체 아키텍처 분석 완료",
"details": "Node.js + Express + TypeScript + PostgreSQL Raw Query 기반 멀티테넌시 시스템. 70+ 라우트, 70+ 컨트롤러, 80+ 서비스로 구성된 계층형 아키텍처. JWT 인증, 3단계 권한 체계(SUPER_ADMIN/COMPANY_ADMIN/USER), company_code 기반 완전한 데이터 격리 구현.",
"files_affected": [
"docs/backend-architecture-detailed-analysis.md (상세 분석 문서)",
"docs/backend-architecture-summary.md (요약 문서)",
"docs/backend-api-route-mapping.md (API 라우트 전체 매핑)"
],
"key_findings": {
"architecture_pattern": "Layered Architecture (Controller → Service → Database)",
"tech_stack": {
"language": "TypeScript",
"runtime": "Node.js 20.10.0+",
"framework": "Express.js",
"database": "PostgreSQL (pg 라이브러리, Raw Query)",
"authentication": "JWT (jsonwebtoken)",
"scheduler": "node-cron",
"external_db_support": ["PostgreSQL", "MySQL", "MSSQL", "Oracle"]
},
"directory_structure": {
"controllers": "70+ 파일 (API 요청 수신, 응답 생성)",
"services": "80+ 파일 (비즈니스 로직, 트랜잭션 관리)",
"routes": "70+ 파일 (API 라우팅)",
"middleware": "4개 (인증, 권한, 슈퍼관리자, 에러핸들러)",
"types": "26개 (TypeScript 타입 정의)",
"utils": "유틸리티 함수 (JWT, 암호화, 로거)"
},
"middleware_stack": [
"1. Process Level Exception Handlers",
"2. Helmet (보안 헤더)",
"3. Compression (Gzip)",
"4. Body Parser (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"
],
"authentication_flow": {
"step1": "로그인 요청 → AuthController.login()",
"step2": "AuthService.processLogin() → loginPwdCheck() (bcrypt 검증)",
"step3": "getPersonBeanFromSession() → 사용자 정보 조회",
"step4": "insertLoginAccessLog() → 로그인 이력 저장",
"step5": "JwtUtils.generateToken() → JWT 토큰 생성",
"step6": "응답: { token, userInfo, firstMenuPath }"
},
"jwt_payload": {
"userId": "사용자 ID",
"userName": "사용자명",
"companyCode": "회사 코드 (멀티테넌시 키)",
"userType": "권한 레벨 (SUPER_ADMIN/COMPANY_ADMIN/USER)",
"exp": "만료 시간 (24시간)"
},
"permission_levels": {
"SUPER_ADMIN": {
"company_code": "*",
"userType": "SUPER_ADMIN",
"capabilities": [
"전체 회사 데이터 접근",
"DDL 실행",
"회사 생성/삭제",
"시스템 설정 변경"
]
},
"COMPANY_ADMIN": {
"company_code": "특정 회사 (예: ILSHIN)",
"userType": "COMPANY_ADMIN",
"capabilities": [
"자기 회사 데이터만 접근",
"자기 회사 사용자 관리",
"회사 설정 변경"
]
},
"USER": {
"company_code": "특정 회사",
"userType": "USER",
"capabilities": [
"자기 회사 데이터만 접근",
"읽기/쓰기 권한만"
]
}
},
"multi_tenancy": {
"principle": "모든 쿼리에 company_code 필터 필수",
"pattern": "JWT 토큰에서 company_code 추출 (클라이언트 신뢰 금지)",
"super_admin_visibility": "일반 회사 사용자에게 슈퍼관리자(company_code='*') 숨김",
"correct_pattern": "WHERE company_code = $1 AND company_code != '*'",
"wrong_pattern": "req.body.companyCode 사용 (보안 위험!)"
},
"api_routes": {
"total_count": "200+개",
"categories": {
"인증/관리자": "15개",
"테이블/화면": "40개",
"플로우": "15개",
"데이터플로우": "5개",
"외부 연동": "15개",
"배치": "10개",
"메일": "5개",
"파일": "5개",
"기타": "90개"
}
},
"business_domains": {
"관리자": {
"controller": "adminController.ts",
"service": "adminService.ts",
"features": ["사용자 관리", "메뉴 관리", "권한 그룹 관리", "시스템 설정"]
},
"테이블/화면": {
"controller": "tableManagementController.ts, screenManagementController.ts",
"service": "tableManagementService.ts, screenManagementService.ts",
"features": ["테이블 메타데이터", "화면 정의", "화면 그룹", "테이블 로그", "엔티티 관계"]
},
"플로우": {
"controller": "flowController.ts",
"service": "flowExecutionService.ts, flowDefinitionService.ts",
"features": ["워크플로우 설계", "단계 관리", "데이터 이동", "조건부 이동", "오딧 로그"]
},
"데이터플로우": {
"controller": "dataflowController.ts, dataflowDiagramController.ts",
"service": "dataflowService.ts, dataflowDiagramService.ts",
"features": ["테이블 관계 정의", "ERD", "다이어그램 시각화", "관계 실행"]
},
"외부 연동": {
"controller": "externalDbConnectionController.ts, externalRestApiConnectionController.ts",
"service": "externalDbConnectionService.ts, dbConnectionManager.ts",
"features": ["외부 DB 연결", "Connection Pool 관리", "REST API 프록시"]
},
"배치": {
"controller": "batchController.ts, batchManagementController.ts",
"service": "batchService.ts, batchSchedulerService.ts",
"features": ["Cron 스케줄러", "외부 DB → 내부 DB 동기화", "컬럼 매핑", "실행 이력"]
},
"메일": {
"controller": "mailSendSimpleController.ts, mailReceiveBasicController.ts",
"service": "mailSendSimpleService.ts, mailReceiveBasicService.ts",
"features": ["메일 발송 (nodemailer)", "메일 수신 (IMAP)", "템플릿 관리", "첨부파일"]
},
"파일": {
"controller": "fileController.ts, screenFileController.ts",
"service": "fileSystemManager.ts",
"features": ["파일 업로드 (multer)", "파일 다운로드", "화면별 파일 관리"]
}
},
"database_access": {
"connection_pool": {
"min": "2~5 (환경별)",
"max": "10~20 (환경별)",
"connectionTimeout": "30000ms",
"idleTimeout": "600000ms",
"statementTimeout": "60000ms"
},
"query_patterns": {
"multi_row": "query('SELECT ...', [params])",
"single_row": "queryOne('SELECT ...', [params])",
"transaction": "transaction(async (client) => { ... })"
},
"sql_injection_prevention": "Parameterized Query 사용 (pg 라이브러리)"
},
"external_integration": {
"supported_databases": ["PostgreSQL", "MySQL", "MSSQL", "Oracle"],
"connector_pattern": "Factory Pattern (DatabaseConnectorFactory)",
"rest_api": "axios 기반 프록시"
},
"batch_scheduler": {
"library": "node-cron",
"timezone": "Asia/Seoul",
"cron_examples": {
"매일 새벽 2시": "0 2 * * *",
"5분마다": "*/5 * * * *",
"평일 오전 8시": "0 8 * * 1-5"
},
"execution_flow": [
"1. 소스 DB에서 데이터 조회",
"2. 컬럼 매핑 적용",
"3. 타겟 DB에 INSERT/UPDATE",
"4. 실행 로그 기록"
]
},
"file_handling": {
"upload_path": "uploads/{company_code}/{timestamp}-{uuid}-{filename}",
"max_file_size": "10MB",
"allowed_types": ["이미지", "PDF", "Office 문서"],
"library": "multer"
},
"security": {
"password_encryption": "bcrypt (12 rounds)",
"sensitive_data_encryption": "AES-256-CBC (외부 DB 비밀번호)",
"jwt_secret": "환경변수 관리",
"security_headers": ["Helmet (CSP, X-Frame-Options)", "CORS (credentials: true)", "Rate Limiting (1분 10000회)"],
"sql_injection_prevention": "Parameterized Query"
},
"error_handling": {
"postgres_error_codes": {
"23505": "중복된 데이터",
"23503": "참조 무결성 위반",
"23502": "필수 입력값 누락"
},
"process_level": {
"unhandledRejection": "로깅 (서버 유지)",
"uncaughtException": "로깅 (서버 유지, 주의)",
"SIGTERM/SIGINT": "Graceful Shutdown"
}
},
"logging": {
"library": "Winston",
"log_files": {
"error.log": "에러만 (10MB × 5파일)",
"combined.log": "전체 로그 (10MB × 10파일)"
},
"log_levels": "error (0) → warn (1) → info (2) → debug (5)"
},
"performance_optimization": {
"pool_monitoring": "5분마다 상태 체크, 대기 연결 5개 이상 시 경고",
"slow_query_detection": "1초 이상 걸린 쿼리 자동 경고",
"caching": "Redis (메뉴: 10분 TTL, 공통코드: 30분 TTL)",
"compression": "Gzip (1KB 이상 응답, 레벨 6)"
}
},
"critical_rules": [
"✅ 모든 쿼리에 company_code 필터 추가",
"✅ JWT 토큰에서 company_code 추출 (클라이언트 신뢰 금지)",
"✅ Parameterized Query 사용 (SQL Injection 방지)",
"✅ 슈퍼관리자 데이터 숨김 (company_code != '*')",
"✅ 비밀번호는 bcrypt, 민감정보는 AES-256",
"✅ 에러 핸들링 try/catch 필수",
"✅ 트랜잭션이 필요한 경우 transaction() 사용",
"✅ 파일 업로드는 회사별 디렉토리 분리"
]
},
"needs_from_others": [],
"questions": []
}