// src/lib/cron/syncProjects.ts import db from "@/db/db"; import { projects } from '@/db/schema'; import { eq } from 'drizzle-orm'; import { getSEDPToken } from "./sedp-token"; // 환경 변수 const SEDP_API_BASE_URL = process.env.SEDP_API_BASE_URL || 'http://sedpwebapi.ship.samsung.co.kr/dev/api'; // 인터페이스 정의 interface Project { PROJ_NO: string; DESC: string; TYPE?: string; DELETED?: boolean; DEL_USER?: string | null; DEL_DTM?: string | null; CRTER_NO?: string; CRTE_DTM?: string; CHGER_NO?: string | null; CHGE_DTM?: string | null; _id?: string; } interface SyncResult { success: number; failed: number; items: number; timestamp: string; } // 프로젝트 데이터 가져오기 async function getProjects(): Promise { try { // 토큰(API 키) 가져오기 const apiKey = await getSEDPToken(); const response = await fetch( `${SEDP_API_BASE_URL}/Project/Get`, { method: 'GET', headers: { 'Content-Type': 'application/json', 'accept': '*/*', 'ApiKey': apiKey } } ); if (!response.ok) { throw new Error(`프로젝트 요청 실패: ${response.status} ${response.statusText}`); } const data = await response.json(); // 결과가 배열인지 확인 if (Array.isArray(data)) { return data; } else { // 단일 객체인 경우 배열로 변환 return [data]; } } catch (error) { console.error('프로젝트 목록 가져오기 실패:', error); throw error; } } // 데이터베이스에 프로젝트 저장 async function saveProjectsToDatabase(projectsData: Project[]): Promise { try { // 기존 프로젝트 조회 const existingProjects = await db.select().from(projects); // 코드 기준으로 맵 생성 const existingProjectMap = new Map( existingProjects.map(project => [project.code, project]) ); // 새로 추가할 항목 const toInsert = []; // 업데이트할 항목 const toUpdate = []; // API에 있는 코드 목록 const apiProjectCodes = new Set(projectsData.map(project => project.PROJ_NO)); // 삭제할 코드 목록 const codesToDelete = [...existingProjectMap.keys()] .filter(code => !apiProjectCodes.has(code)); // 프로젝트 데이터 처리 for (const project of projectsData) { // 삭제된 프로젝트는 건너뜀 if (project.DELETED) continue; // 프로젝트 레코드 준비 const projectRecord = { code: project.PROJ_NO, name: project.DESC || project.PROJ_NO, type: project.TYPE || 'ship', updatedAt: new Date() }; // 이미 존재하는 코드인지 확인 if (existingProjectMap.has(project.PROJ_NO)) { // 업데이트 항목에 추가 toUpdate.push(projectRecord); } else { // 새로 추가할 항목에 추가 toInsert.push({ ...projectRecord, createdAt: new Date() }); } } // 트랜잭션 실행 let totalChanged = 0; // 1. 새 프로젝트 삽입 if (toInsert.length > 0) { await db.insert(projects).values(toInsert); totalChanged += toInsert.length; console.log(`${toInsert.length}개의 새 프로젝트 추가 완료`); } // 2. 기존 프로젝트 업데이트 for (const item of toUpdate) { await db.update(projects) .set({ name: item.name, type: item.type, updatedAt: item.updatedAt }) .where(eq(projects.code, item.code)); totalChanged += 1; } if (toUpdate.length > 0) { console.log(`${toUpdate.length}개 프로젝트 업데이트 완료`); } // 3. 더 이상 존재하지 않는 프로젝트 삭제 if (codesToDelete.length > 0) { for (const code of codesToDelete) { await db.delete(projects) .where(eq(projects.code, code)); } console.log(`${codesToDelete.length}개의 프로젝트 삭제 완료`); totalChanged += codesToDelete.length; } return totalChanged; } catch (error) { console.error('프로젝트 저장 실패:', error); throw error; } } // 메인 동기화 함수 export async function syncProjects(): Promise { try { console.log('프로젝트 동기화 시작:', new Date().toISOString()); // 1. 프로젝트 데이터 가져오기 const projectsData = await getProjects(); console.log(`${projectsData.length}개의 프로젝트 정보를 가져왔습니다.`); // 2. 데이터베이스에 저장 const totalItems = await saveProjectsToDatabase(projectsData); console.log(`프로젝트 동기화 완료: 총 ${totalItems}개 항목 처리됨`); return { success: 1, // 단일 작업이므로 성공은 1 failed: 0, items: totalItems, timestamp: new Date().toISOString() }; } catch (error) { console.error('프로젝트 동기화 중 오류 발생:', error); return { success: 0, failed: 1, items: 0, timestamp: new Date().toISOString() }; } }