// 배치관리 컨트롤러 // 작성일: 2024-12-24 import { Request, Response } from "express"; import { BatchService } from "../services/batchService"; import { BatchSchedulerService } from "../services/batchSchedulerService"; import { BatchConfigFilter, CreateBatchConfigRequest, UpdateBatchConfigRequest } from "../types/batchTypes"; export interface AuthenticatedRequest extends Request { user?: { userId: string; username: string; companyCode: string; }; } export class BatchController { /** * 배치 설정 목록 조회 * GET /api/batch-configs */ static async getBatchConfigs(req: AuthenticatedRequest, res: Response) { try { const { page = 1, limit = 10, search, isActive } = req.query; const filter: BatchConfigFilter = { page: Number(page), limit: Number(limit), search: search as string, is_active: isActive as string }; const result = await BatchService.getBatchConfigs(filter); res.json({ success: true, data: result.data, pagination: result.pagination }); } catch (error) { console.error("배치 설정 목록 조회 오류:", error); res.status(500).json({ success: false, message: "배치 설정 목록 조회에 실패했습니다." }); } } /** * 사용 가능한 커넥션 목록 조회 * GET /api/batch-configs/connections */ static async getAvailableConnections(req: AuthenticatedRequest, res: Response) { try { const result = await BatchService.getAvailableConnections(); if (result.success) { res.json(result); } else { res.status(500).json(result); } } catch (error) { console.error("커넥션 목록 조회 오류:", error); res.status(500).json({ success: false, message: "커넥션 목록 조회에 실패했습니다." }); } } /** * 테이블 목록 조회 (내부/외부 DB) * GET /api/batch-configs/connections/:type/tables * GET /api/batch-configs/connections/:type/:id/tables */ static async getTablesFromConnection(req: AuthenticatedRequest, res: Response) { try { const { type, id } = req.params; if (!type || (type !== 'internal' && type !== 'external')) { return res.status(400).json({ success: false, message: "올바른 연결 타입을 지정해주세요. (internal 또는 external)" }); } const connectionId = type === 'external' ? Number(id) : undefined; const result = await BatchService.getTablesFromConnection(type, connectionId); if (result.success) { return res.json(result); } else { return res.status(500).json(result); } } catch (error) { console.error("테이블 목록 조회 오류:", error); return res.status(500).json({ success: false, message: "테이블 목록 조회에 실패했습니다." }); } } /** * 테이블 컬럼 정보 조회 (내부/외부 DB) * GET /api/batch-configs/connections/:type/tables/:tableName/columns * GET /api/batch-configs/connections/:type/:id/tables/:tableName/columns */ static async getTableColumns(req: AuthenticatedRequest, res: Response) { try { const { type, id, tableName } = req.params; if (!type || !tableName) { return res.status(400).json({ success: false, message: "연결 타입과 테이블명을 모두 지정해주세요." }); } if (type !== 'internal' && type !== 'external') { return res.status(400).json({ success: false, message: "올바른 연결 타입을 지정해주세요. (internal 또는 external)" }); } const connectionId = type === 'external' ? Number(id) : undefined; const result = await BatchService.getTableColumns(type, connectionId, tableName); if (result.success) { return res.json(result); } else { return res.status(500).json(result); } } catch (error) { console.error("컬럼 정보 조회 오류:", error); return res.status(500).json({ success: false, message: "컬럼 정보 조회에 실패했습니다." }); } } /** * 특정 배치 설정 조회 * GET /api/batch-configs/:id */ static async getBatchConfigById(req: AuthenticatedRequest, res: Response) { try { const { id } = req.params; const batchConfig = await BatchService.getBatchConfigById(Number(id)); if (!batchConfig) { return res.status(404).json({ success: false, message: "배치 설정을 찾을 수 없습니다." }); } return res.json({ success: true, data: batchConfig }); } catch (error) { console.error("배치 설정 조회 오류:", error); return res.status(500).json({ success: false, message: "배치 설정 조회에 실패했습니다." }); } } /** * 배치 설정 생성 * POST /api/batch-configs */ static async createBatchConfig(req: AuthenticatedRequest, res: Response) { try { const { batchName, description, cronSchedule, mappings } = req.body; if (!batchName || !cronSchedule || !mappings || !Array.isArray(mappings)) { return res.status(400).json({ success: false, message: "필수 필드가 누락되었습니다. (batchName, cronSchedule, mappings)" }); } const batchConfig = await BatchService.createBatchConfig({ batchName, description, cronSchedule, mappings } as CreateBatchConfigRequest); // 생성된 배치가 활성화 상태라면 스케줄러에 등록 if (batchConfig.data && batchConfig.data.is_active === 'Y' && batchConfig.data.id) { await BatchSchedulerService.updateBatchSchedule(batchConfig.data.id); } return res.status(201).json({ success: true, data: batchConfig, message: "배치 설정이 성공적으로 생성되었습니다." }); } catch (error) { console.error("배치 설정 생성 오류:", error); return res.status(500).json({ success: false, message: "배치 설정 생성에 실패했습니다." }); } } /** * 배치 설정 수정 * PUT /api/batch-configs/:id */ static async updateBatchConfig(req: AuthenticatedRequest, res: Response) { try { const { id } = req.params; const { batchName, description, cronSchedule, mappings, isActive } = req.body; if (!batchName || !cronSchedule) { return res.status(400).json({ success: false, message: "필수 필드가 누락되었습니다. (batchName, cronSchedule)" }); } const batchConfig = await BatchService.updateBatchConfig(Number(id), { batchName, description, cronSchedule, mappings, isActive } as UpdateBatchConfigRequest); if (!batchConfig) { return res.status(404).json({ success: false, message: "배치 설정을 찾을 수 없습니다." }); } // 스케줄러에서 배치 스케줄 업데이트 (활성화 시 즉시 스케줄 등록) await BatchSchedulerService.updateBatchSchedule(Number(id)); return res.json({ success: true, data: batchConfig, message: "배치 설정이 성공적으로 수정되었습니다." }); } catch (error) { console.error("배치 설정 수정 오류:", error); return res.status(500).json({ success: false, message: "배치 설정 수정에 실패했습니다." }); } } /** * 배치 설정 삭제 (논리 삭제) * DELETE /api/batch-configs/:id */ static async deleteBatchConfig(req: AuthenticatedRequest, res: Response) { try { const { id } = req.params; const result = await BatchService.deleteBatchConfig(Number(id)); if (!result) { return res.status(404).json({ success: false, message: "배치 설정을 찾을 수 없습니다." }); } return res.json({ success: true, message: "배치 설정이 성공적으로 삭제되었습니다." }); } catch (error) { console.error("배치 설정 삭제 오류:", error); return res.status(500).json({ success: false, message: "배치 설정 삭제에 실패했습니다." }); } } }