diff options
Diffstat (limited to 'lib/vendor-document-list/sync-service.ts')
| -rw-r--r-- | lib/vendor-document-list/sync-service.ts | 265 |
1 files changed, 60 insertions, 205 deletions
diff --git a/lib/vendor-document-list/sync-service.ts b/lib/vendor-document-list/sync-service.ts index 1f2872c4..4c1f5786 100644 --- a/lib/vendor-document-list/sync-service.ts +++ b/lib/vendor-document-list/sync-service.ts @@ -1,4 +1,4 @@ -// lib/sync-service.ts (시스템별 분리 버전) +// lib/sync-service.ts (시스템별 분리 버전 - DOLCE 업로드 통합) import db from "@/db/db" import { changeLogs, @@ -29,8 +29,6 @@ export interface SyncResult { class SyncService { private readonly CHUNK_SIZE = 50 - - /** * 동기화 활성화 여부 확인 */ @@ -294,7 +292,7 @@ class SyncService { } /** - * DOLCE 시스템 전용 동기화 수행 + * DOLCE 시스템 전용 동기화 수행 - 실제 업로드 서비스 사용 */ private async performSyncDOLCE( changes: ChangeLog[], @@ -302,143 +300,72 @@ class SyncService { ): Promise<{ success: boolean; successCount: number; failureCount: number; errors?: string[]; endpointResults?: Record<string, any> }> { const errors: string[] = [] const endpointResults: Record<string, any> = {} - let overallSuccess = true - - // 변경사항을 DOLCE 시스템 형태로 변환 - const syncData = await this.transformChangesForDOLCE(changes) - - // DOLCE 엔드포인트 호출들을 직접 정의 - const endpointPromises = [] - - // 1. DOLCE 메인 엔드포인트 - const mainUrl = process.env.SYNC_DOLCE_URL - if (mainUrl) { - endpointPromises.push( - (async () => { - try { - console.log(`Sending to DOLCE main: ${mainUrl}`) - - const transformedData = { - contractId, - systemType: 'DOLCE', - changes: syncData, - batchSize: changes.length, - timestamp: new Date().toISOString(), - source: 'EVCP', - version: '1.0' - } - - // 헤더 구성 (토큰이 있을 때만 Authorization 포함) - const headers: Record<string, string> = { - 'Content-Type': 'application/json', - 'X-API-Version': process.env.SYNC_DOLCE_VERSION || 'v1', - 'X-System': 'DOLCE' - } - - if (process.env.SYNC_DOLCE_TOKEN) { - headers['Authorization'] = `Bearer ${process.env.SYNC_DOLCE_TOKEN}` - } - - const response = await fetch(mainUrl, { - method: 'POST', - headers, - body: JSON.stringify(transformedData) - }) - - if (!response.ok) { - const errorText = await response.text() - throw new Error(`DOLCE main: HTTP ${response.status} - ${errorText}`) - } - - const result = await response.json() - endpointResults['dolce_main'] = result - - console.log(`✅ DOLCE main sync successful`) - return { success: true, endpoint: 'dolce_main', result } - } catch (error) { - const errorMessage = `DOLCE main: ${error instanceof Error ? error.message : 'Unknown error'}` - errors.push(errorMessage) - overallSuccess = false - - console.error(`❌ DOLCE main sync failed:`, error) - return { success: false, endpoint: 'dolce_main', error: errorMessage } - } - })() - ) - } - - // 2. DOLCE 문서 전용 엔드포인트 (선택사항) - const docUrl = process.env.SYNC_DOLCE_DOCUMENT_URL - if (docUrl) { - endpointPromises.push( - (async () => { - try { - console.log(`Sending to DOLCE documents: ${docUrl}`) - - const documentData = { - documents: syncData.filter(item => item.entityType === 'document'), - source: 'EVCP_DOLCE', - timestamp: new Date().toISOString() - } - - // 헤더 구성 (토큰이 있을 때만 Authorization 포함) - const headers: Record<string, string> = { - 'Content-Type': 'application/json' - } - - if (process.env.SYNC_DOLCE_TOKEN) { - headers['Authorization'] = `Bearer ${process.env.SYNC_DOLCE_TOKEN}` - } - - const response = await fetch(docUrl, { - method: 'PUT', - headers, - body: JSON.stringify(documentData) - }) - - if (!response.ok) { - const errorText = await response.text() - throw new Error(`DOLCE documents: HTTP ${response.status} - ${errorText}`) - } + try { + // DOLCE 업로드 서비스 동적 임포트 + const { dolceUploadService } = await import('./dolce-upload-service') + + if (!dolceUploadService.isUploadEnabled()) { + throw new Error('DOLCE upload is not enabled') + } - const result = await response.json() - endpointResults['dolce_documents'] = result + // 변경사항에서 리비전 ID들 추출 + const revisionIds = changes + .filter(change => change.entityType === 'revision') + .map(change => change.entityId) - console.log(`✅ DOLCE documents sync successful`) - return { success: true, endpoint: 'dolce_documents', result } + if (revisionIds.length === 0) { + return { + success: true, + successCount: 0, + failureCount: 0, + endpointResults: { message: 'No revisions to upload' } + } + } - } catch (error) { - const errorMessage = `DOLCE documents: ${error instanceof Error ? error.message : 'Unknown error'}` - errors.push(errorMessage) - overallSuccess = false - - console.error(`❌ DOLCE documents sync failed:`, error) - return { success: false, endpoint: 'dolce_documents', error: errorMessage } - } - })() + // DOLCE 업로드 실행 + const uploadResult = await dolceUploadService.uploadToDoLCE( + contractId, + revisionIds, + 'system_user', // 시스템 사용자 ID + 'System Upload' ) - } - if (endpointPromises.length === 0) { - throw new Error('No DOLCE sync endpoints configured') - } + endpointResults['dolce_upload'] = uploadResult - // 모든 엔드포인트 요청 완료 대기 - const results = await Promise.allSettled(endpointPromises) - - // 결과 집계 - const successfulEndpoints = results.filter(r => r.status === 'fulfilled' && r.value.success).length - const totalEndpoints = endpointPromises.length + if (uploadResult.success) { + console.log(`✅ DOLCE upload successful: ${uploadResult.uploadedDocuments} documents, ${uploadResult.uploadedFiles} files`) + + return { + success: true, + successCount: changes.length, + failureCount: 0, + endpointResults + } + } else { + console.error(`❌ DOLCE upload failed:`, uploadResult.errors) + + return { + success: false, + successCount: 0, + failureCount: changes.length, + errors: uploadResult.errors, + endpointResults + } + } - console.log(`DOLCE endpoint results: ${successfulEndpoints}/${totalEndpoints} successful`) + } catch (error) { + const errorMessage = `DOLCE upload failed: ${error instanceof Error ? error.message : 'Unknown error'}` + errors.push(errorMessage) + console.error(`❌ DOLCE upload error:`, error) - return { - success: overallSuccess && errors.length === 0, - successCount: overallSuccess ? changes.length : 0, - failureCount: overallSuccess ? 0 : changes.length, - errors: errors.length > 0 ? errors : undefined, - endpointResults + return { + success: false, + successCount: 0, + failureCount: changes.length, + errors, + endpointResults + } } } @@ -560,78 +487,6 @@ class SyncService { } /** - * DOLCE 시스템용 데이터 변환 - */ - private async transformChangesForDOLCE(changes: ChangeLog[]): Promise<SyncableEntity[]> { - const syncData: SyncableEntity[] = [] - - for (const change of changes) { - try { - let entityData = null - - // 엔티티 타입별로 현재 데이터 조회 - switch (change.entityType) { - case 'document': - if (change.action !== 'DELETE') { - const [document] = await db - .select() - .from(documents) - .where(eq(documents.id, change.entityId)) - .limit(1) - entityData = document - } - break - - case 'revision': - if (change.action !== 'DELETE') { - const [revision] = await db - .select() - .from(revisions) - .where(eq(revisions.id, change.entityId)) - .limit(1) - entityData = revision - } - break - - case 'attachment': - if (change.action !== 'DELETE') { - const [attachment] = await db - .select() - .from(documentAttachments) - .where(eq(documentAttachments.id, change.entityId)) - .limit(1) - entityData = attachment - } - break - } - - // DOLCE 특화 데이터 구조 - syncData.push({ - entityType: change.entityType as any, - entityId: change.entityId, - action: change.action as any, - data: entityData || change.oldValues, - metadata: { - changeId: change.id, - changedAt: change.createdAt, - changedBy: change.userName, - changedFields: change.changedFields, - // DOLCE 전용 메타데이터 - dolceVersion: '2.0', - processingPriority: change.entityType === 'revision' ? 'HIGH' : 'NORMAL', - requiresApproval: change.action === 'DELETE' - } - }) - - } catch (error) { - console.error(`Failed to transform change ${change.id} for DOLCE:`, error) - } - } - - return syncData - } - - /** * SWP 시스템용 데이터 변환 */ private async transformChangesForSWP(changes: ChangeLog[]): Promise<SyncableEntity[]> { @@ -759,7 +614,7 @@ class SyncService { await db.update(revisions) .set({ revisionStatus: "SUBMITTED", - externalSentAt: new Date().toISOString().slice(0, 10) + submittedDate: new Date().toISOString().slice(0, 10) }) .where(inArray(revisions.id, revisionIds)) } |
