"use server"; /* eslint-disable @typescript-eslint/no-explicit-any */ /** * SWP 문서 관리 시스템 사용 예제 * * 이 파일은 실제 사용 시나리오를 보여주는 예제입니다. */ import { fetchSwpProjectData, analyzeSwpData, getSwpFileDownloadUrl, } from "./api-client"; import { syncSwpProject, getProjectDocumentsHierarchy, getDocumentRevisions, getRevisionFiles, getProjectSyncStatus, } from "./sync-service"; import db from "@/db/db"; import { sql } from "drizzle-orm"; // ============================================================================ // 예제 1: 프로젝트 전체 동기화 // ============================================================================ export async function example1_FullProjectSync(projectNo: string) { console.log("=== 예제 1: 프로젝트 전체 동기화 ===\n"); // 1. API에서 데이터 조회 console.log(`📡 API 호출 중...`); const { documents, files } = await fetchSwpProjectData(projectNo, "V"); // 2. 데이터 분석 const stats: Awaited> = await analyzeSwpData(projectNo, documents, files); console.log(`📊 데이터 분석:`); console.log(` - 문서: ${stats.documentCount}개`); console.log(` - 리비전: ${stats.revisionCount}개`); console.log(` - 파일: ${stats.fileCount}개`); console.log(` - 평균 파일/문서: ${stats.avgFilesPerDoc.toFixed(2)}개`); console.log( ` - 총 용량: ${(stats.totalFileSize / 1024 / 1024).toFixed(2)} MB` ); console.log(` - 스테이지:`, stats.stages); console.log(` - 파일 타입:`, stats.fileTypes); // 3. 동기화 실행 console.log(`\n💾 동기화 시작...`); const syncResult = await syncSwpProject(projectNo, documents, files); if (syncResult.success) { console.log(`✅ 동기화 완료 (${syncResult.duration}ms)`); console.log(` - 문서: +${syncResult.stats.documents.inserted}개`); console.log(` - 리비전: +${syncResult.stats.revisions.inserted}개`); console.log(` - 파일: +${syncResult.stats.files.inserted}개`); } else { console.error(`❌ 동기화 실패:`); syncResult.errors.forEach((err) => console.error(` - ${err}`)); } return syncResult; } // ============================================================================ // 예제 2: 계층 구조 조회 및 UI 렌더링 // ============================================================================ export async function example2_HierarchyView(projectNo: string) { console.log("=== 예제 2: 계층 구조 조회 ===\n"); // 1. 계층 뷰 조회 const result = await getProjectDocumentsHierarchy(projectNo); const documents = result.rows as any[]; console.log(`📁 문서 ${documents.length}개 조회됨\n`); // 2. 첫 3개 문서만 출력 (예제) documents.slice(0, 3).forEach((doc) => { console.log(`📄 ${doc.doc_no}`); console.log(` 제목: ${doc.doc_title}`); console.log(` 최신 리비전: ${doc.ltst_rev_no}`); console.log(` 리비전 수: ${doc.revision_count}개`); const revisions = JSON.parse(doc.revisions || "[]"); revisions.slice(0, 2).forEach((rev: any) => { console.log(` 📋 REV ${rev.revNo} (${rev.stage})`); console.log(` 파일: ${rev.fileCount}개`); const files = rev.files || []; files.forEach((file: any) => { console.log(` 📎 ${file.fileNm} (${file.fileSz} bytes)`); }); }); console.log(); }); return documents; } // ============================================================================ // 예제 3: 특정 문서의 리비전 조회 // ============================================================================ export async function example3_DocumentRevisions(docNo: string) { console.log("=== 예제 3: 문서 리비전 조회 ===\n"); // 1. 리비전 목록 조회 const revisions = await getDocumentRevisions(docNo); console.log(`📄 문서: ${docNo}`); console.log(`📋 리비전: ${revisions.length}개\n`); // 2. 각 리비전별 파일 조회 for (const rev of revisions) { const files = await getRevisionFiles(rev.id); console.log(`REV ${rev.REV_NO} (${rev.STAGE})`); console.log(` 파일: ${files.length}개`); console.log(` Activity: ${rev.ACTV_NO || "N/A"}`); console.log(` OFDC: ${rev.OFDC_NO}`); console.log(` 동기화: ${rev.sync_status} (${rev.last_synced_at})`); files.forEach((file) => { console.log(` 📎 ${file.FILE_NM}`); console.log(` 크기: ${file.FILE_SZ} bytes`); console.log(` 경로: ${file.FLD_PATH}`); console.log(` 상태: ${file.STAT_NM}`); }); console.log(); } return revisions; } // ============================================================================ // 예제 4: 파일 검색 (플랫 뷰 활용) // ============================================================================ export async function example4_SearchFiles( projectNo: string, fileNamePattern: string ) { console.log("=== 예제 4: 파일 검색 ===\n"); // 1. 플랫 뷰에서 검색 const result = await db.execute(sql` SELECT "DOC_NO", "DOC_TITLE", "REV_NO", "STAGE", "FILE_NM", "FILE_SZ", "FLD_PATH", "STAT_NM" FROM swp.v_swp_documents_flat WHERE "PROJ_NO" = ${projectNo} AND "FILE_NM" ILIKE ${`%${fileNamePattern}%`} ORDER BY "DOC_NO", "REV_NO" DESC LIMIT 20 `); console.log(`🔍 검색어: "${fileNamePattern}"`); console.log(`📊 결과: ${result.rowCount}개\n`); result.rows.forEach((row: any) => { console.log(`📄 ${row.DOC_NO} (${row.DOC_TITLE})`); console.log(` REV ${row.REV_NO} (${row.STAGE})`); console.log(` 📎 ${row.FILE_NM} (${row.FILE_SZ} bytes)`); console.log(` 상태: ${row.STAT_NM}`); console.log(); }); return result.rows; } // ============================================================================ // 예제 5: 파일 다운로드 URL 생성 // ============================================================================ export async function example5_FileDownload(revisionId: number) { console.log("=== 예제 5: 파일 다운로드 ===\n"); // 1. 리비전의 파일 조회 const files = await getRevisionFiles(revisionId); console.log(`📋 리비전 ID: ${revisionId}`); console.log(`📎 파일: ${files.length}개\n`); // 2. 다운로드 URL 생성 const fileUrls = await Promise.all( files .filter((file) => file.FLD_PATH && file.FILE_NM) .map(async (file) => ({ fileName: file.FILE_NM, downloadUrl: await getSwpFileDownloadUrl({ FLD_PATH: file.FLD_PATH!, FILE_NM: file.FILE_NM, }), size: file.FILE_SZ, })) ); fileUrls.forEach((item) => { console.log(`📎 ${item.fileName}`); console.log(` URL: ${item.downloadUrl}`); console.log(` 크기: ${item.size} bytes`); console.log(); }); return fileUrls; } // ============================================================================ // 예제 6: 동기화 상태 모니터링 // ============================================================================ export async function example6_SyncMonitoring(projectNo: string) { console.log("=== 예제 6: 동기화 상태 모니터링 ===\n"); // 1. 프로젝트 동기화 상태 조회 const result = await getProjectSyncStatus(projectNo); const status = result.rows[0] as any; console.log(`📊 프로젝트: ${status.proj_no} (${status.proj_nm})`); console.log(`\n📈 통계:`); console.log(` - 문서: ${status.total_documents}개`); console.log(` - 리비전: ${status.total_revisions}개`); console.log(` - 파일: ${status.total_files}개`); console.log(`\n✅ 동기화 상태:`); console.log(` - 문서: ${status.docs_synced}개 완료`); console.log(` - 대기: ${status.docs_pending}개`); console.log(` - 오류: ${status.docs_error}개`); console.log(`\n🕐 마지막 동기화: ${status.last_sync_time}`); return status; } // ============================================================================ // 예제 7: 스테이지별 문서 통계 // ============================================================================ export async function example7_StageStatistics(projectNo: string) { console.log("=== 예제 7: 스테이지별 통계 ===\n"); const result = await db.execute(sql` SELECT "STAGE", COUNT(DISTINCT "DOC_NO")::int as doc_count, COUNT(DISTINCT "REV_NO")::int as rev_count, COUNT(*)::int as file_count FROM swp.v_swp_documents_flat WHERE "PROJ_NO" = ${projectNo} AND "STAGE" IS NOT NULL GROUP BY "STAGE" ORDER BY "STAGE" `); console.log(`📊 프로젝트: ${projectNo}\n`); result.rows.forEach((row: any) => { console.log(`📌 ${row.STAGE}`); console.log(` 문서: ${row.doc_count}개`); console.log(` 리비전: ${row.rev_count}개`); console.log(` 파일: ${row.file_count}개`); console.log(); }); return result.rows; } // ============================================================================ // 예제 8: 증분 동기화 (변경된 항목만) // ============================================================================ export async function example8_IncrementalSync(projectNo: string) { console.log("=== 예제 8: 증분 동기화 ===\n"); // 1. 마지막 동기화 시간 확인 const lastSyncResult = await db.execute(sql` SELECT MAX(last_synced_at) as last_sync FROM swp.swp_documents WHERE "PROJ_NO" = ${projectNo} `); const lastSync = lastSyncResult.rows[0] as any; console.log(`🕐 마지막 동기화: ${lastSync.last_sync || "없음"}`); // 2. 전체 동기화 (API는 증분 제공 안하므로) console.log(`📡 전체 데이터 조회 중...`); const { documents, files } = await fetchSwpProjectData(projectNo, "V"); // 3. 동기화 (upsert로 변경된 항목만 업데이트됨) console.log(`💾 동기화 시작...`); const syncResult = await syncSwpProject(projectNo, documents, files); console.log(`\n📊 결과:`); console.log( ` - 신규 문서: ${syncResult.stats.documents.inserted}개 (기존: ${syncResult.stats.documents.updated}개)` ); console.log( ` - 신규 리비전: ${syncResult.stats.revisions.inserted}개 (기존: ${syncResult.stats.revisions.updated}개)` ); console.log( ` - 신규 파일: ${syncResult.stats.files.inserted}개 (기존: ${syncResult.stats.files.updated}개)` ); return syncResult; } // ============================================================================ // 전체 시나리오 실행 // ============================================================================ export async function runAllExamples(projectNo: string = "SN2190") { console.log("╔═══════════════════════════════════════════╗"); console.log("║ SWP 문서 관리 시스템 사용 예제 ║"); console.log("╚═══════════════════════════════════════════╝\n"); try { // 예제 1: 전체 동기화 await example1_FullProjectSync(projectNo); console.log("\n" + "=".repeat(50) + "\n"); // 예제 2: 계층 구조 조회 await example2_HierarchyView(projectNo); console.log("\n" + "=".repeat(50) + "\n"); // 예제 6: 동기화 상태 await example6_SyncMonitoring(projectNo); console.log("\n" + "=".repeat(50) + "\n"); // 예제 7: 스테이지별 통계 await example7_StageStatistics(projectNo); console.log("\n✅ 모든 예제 실행 완료!"); } catch (error) { console.error("\n❌ 오류 발생:", error); throw error; } }