summaryrefslogtreecommitdiff
path: root/lib/sedp/sync-projects.ts
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-04-08 03:08:19 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-04-08 03:08:19 +0000
commit9ceed79cf32c896f8a998399bf1b296506b2cd4a (patch)
treef84750fa6cac954d5e31221fc47a54c655fc06a9 /lib/sedp/sync-projects.ts
parent230ce796836c25df26c130dbcd616ef97d12b2ec (diff)
로그인 및 미들웨어 처리. 구조 변경
Diffstat (limited to 'lib/sedp/sync-projects.ts')
-rw-r--r--lib/sedp/sync-projects.ts194
1 files changed, 194 insertions, 0 deletions
diff --git a/lib/sedp/sync-projects.ts b/lib/sedp/sync-projects.ts
new file mode 100644
index 00000000..1094b55f
--- /dev/null
+++ b/lib/sedp/sync-projects.ts
@@ -0,0 +1,194 @@
+// 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<Project[]> {
+ try {
+ // 토큰(API 키) 가져오기
+ const apiKey = await getSEDPToken();
+
+ const response = await fetch(
+ `${SEDP_API_BASE_URL}/Project/Get`,
+ {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json',
+ 'accept': '*/*',
+ 'ApiKey': apiKey
+ },
+ body: JSON.stringify({
+ ContainDeleted: true
+ })
+ }
+ );
+
+ 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<number> {
+ 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<SyncResult> {
+ 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()
+ };
+ }
+} \ No newline at end of file