summaryrefslogtreecommitdiff
path: root/lib/integration-log/db-logging.ts
diff options
context:
space:
mode:
author0-Zz-ang <s1998319@gmail.com>2025-07-10 15:56:13 +0900
committer0-Zz-ang <s1998319@gmail.com>2025-07-10 15:56:13 +0900
commit356929b399ef31a4de82906267df438cf29ea59d (patch)
treec353a55c076e987042f99f3dbf1eab54706f6829 /lib/integration-log/db-logging.ts
parent25d569828b704a102f681a627c76c4129afa8be3 (diff)
인터페이스 관련 파일 수정
Diffstat (limited to 'lib/integration-log/db-logging.ts')
-rw-r--r--lib/integration-log/db-logging.ts295
1 files changed, 295 insertions, 0 deletions
diff --git a/lib/integration-log/db-logging.ts b/lib/integration-log/db-logging.ts
new file mode 100644
index 00000000..990b1096
--- /dev/null
+++ b/lib/integration-log/db-logging.ts
@@ -0,0 +1,295 @@
+"use server";
+
+import { logIntegrationExecution } from "./service";
+
+/**
+ * DB 연동 로깅 래퍼 함수
+ *
+ * @description
+ * 데이터베이스 작업을 자동으로 로깅하는 래퍼 함수입니다.
+ * 동기화, 삽입, 수정, 삭제 등 다양한 DB 작업의 실행 시간과 결과를 기록합니다.
+ *
+ * @param integrationId 인터페이스 ID (추후 매핑 필요)
+ * @param tableName 테이블명
+ * @param operation 작업 유형 (sync, upsert, delete 등)
+ * @param processor 실제 DB 작업 함수
+ * @returns 처리 결과
+ *
+ * @example
+ * // 기본 DB 동기화 로깅
+ * const syncResult = await withDbLogging(
+ * 1, // 인터페이스 ID
+ * 'users',
+ * 'sync',
+ * async () => {
+ * // 외부 시스템에서 사용자 데이터 가져오기
+ * const externalUsers = await fetchExternalUsers();
+ *
+ * // 로컬 DB에 동기화
+ * const result = await syncUsersToLocalDb(externalUsers);
+ *
+ * return {
+ * totalProcessed: result.length,
+ * updated: result.filter(u => u.action === 'updated').length,
+ * created: result.filter(u => u.action === 'created').length
+ * };
+ * }
+ * );
+ *
+ * @example
+ * // 데이터 삽입/수정 로깅
+ * const upsertResult = await withDbLogging(
+ * 2,
+ * 'products',
+ * 'upsert',
+ * async () => {
+ * const productData = await getProductDataFromSap();
+ *
+ * // 기존 데이터 확인 후 삽입/수정
+ * const existingProduct = await db.products.findFirst({
+ * where: { sapId: productData.sapId }
+ * });
+ *
+ * if (existingProduct) {
+ * return await db.products.update({
+ * where: { id: existingProduct.id },
+ * data: productData
+ * });
+ * } else {
+ * return await db.products.create({
+ * data: productData
+ * });
+ * }
+ * }
+ * );
+ *
+ * @example
+ * // 에러 처리와 함께
+ * try {
+ * const deleteResult = await withDbLogging(
+ * 3,
+ * 'temp_data',
+ * 'cleanup',
+ * async () => {
+ * // 7일 이전 임시 데이터 삭제
+ * const cutoffDate = new Date();
+ * cutoffDate.setDate(cutoffDate.getDate() - 7);
+ *
+ * const result = await db.tempData.deleteMany({
+ * where: {
+ * createdAt: { lt: cutoffDate }
+ * }
+ * });
+ *
+ * return { deletedCount: result.count };
+ * }
+ * );
+ *
+ * console.log(`${deleteResult.deletedCount}개의 임시 데이터가 삭제됨`);
+ * } catch (error) {
+ * console.error('DB 정리 작업 실패:', error);
+ * }
+ *
+ * @example
+ * // 트랜잭션 내에서 사용
+ * const transactionResult = await withDbLogging(
+ * 4,
+ * 'orders',
+ * 'bulk_update',
+ * async () => {
+ * return await db.$transaction(async (tx) => {
+ * // 여러 테이블 업데이트
+ * const orders = await tx.orders.updateMany({
+ * where: { status: 'pending' },
+ * data: { status: 'processing' }
+ * });
+ *
+ * const orderItems = await tx.orderItems.updateMany({
+ * where: { order: { status: 'processing' } },
+ * data: { processedAt: new Date() }
+ * });
+ *
+ * return { ordersUpdated: orders.count, itemsUpdated: orderItems.count };
+ * });
+ * }
+ * );
+ */
+export async function withDbLogging<T>(
+ integrationId: number,
+ tableName: string,
+ operation: string,
+ processor: () => Promise<T>
+): Promise<T> {
+ const start = Date.now();
+
+ try {
+ // 실제 DB 작업 실행
+ const result = await processor();
+
+ const duration = Date.now() - start;
+
+ // 성공 로그 기록
+ await logIntegrationExecution({
+ integrationId,
+ status: 'success',
+ responseTime: duration,
+ requestMethod: 'DB',
+ requestUrl: `${operation}:${tableName}`,
+ correlationId: `db_${tableName}_${Date.now()}`,
+ });
+
+ return result;
+
+ } catch (error) {
+ const duration = Date.now() - start;
+
+ // 실패 로그 기록
+ await logIntegrationExecution({
+ integrationId,
+ status: 'failed',
+ responseTime: duration,
+ errorMessage: error instanceof Error ? error.message : 'Unknown error',
+ requestMethod: 'DB',
+ requestUrl: `${operation}:${tableName}`,
+ correlationId: `db_${tableName}_${Date.now()}`,
+ });
+
+ throw error;
+ }
+}
+
+/**
+ * nonsap 동기화 로깅 헬퍼 함수
+ *
+ * @description
+ * Non-SAP 시스템과의 데이터 동기화를 로깅하는 전용 헬퍼 함수입니다.
+ * 전체 동기화(full)와 증분 동기화(delta) 모두 지원합니다.
+ *
+ * @param tableName 테이블명
+ * @param syncType 동기화 유형 (full, delta)
+ * @param processor 동기화 작업 함수
+ * @returns 처리 결과
+ *
+ * @example
+ * // 전체 동기화 로깅
+ * const fullSyncResult = await withNonsapSyncLogging(
+ * 'vendors',
+ * 'full',
+ * async () => {
+ * // 외부 시스템에서 전체 벤더 데이터 가져오기
+ * const allVendors = await fetchAllVendorsFromExternalSystem();
+ *
+ * // 기존 데이터 모두 삭제 후 재생성
+ * await db.vendors.deleteMany({});
+ *
+ * // 새 데이터 삽입
+ * const created = await db.vendors.createMany({
+ * data: allVendors
+ * });
+ *
+ * return {
+ * syncType: 'full',
+ * totalProcessed: allVendors.length,
+ * created: created.count,
+ * updated: 0,
+ * deleted: 0
+ * };
+ * }
+ * );
+ *
+ * @example
+ * // 증분 동기화 로깅
+ * const deltaSyncResult = await withNonsapSyncLogging(
+ * 'purchase_orders',
+ * 'delta',
+ * async () => {
+ * // 마지막 동기화 이후 변경된 데이터만 가져오기
+ * const lastSync = await getLastSyncTimestamp('purchase_orders');
+ * const changedOrders = await fetchChangedOrdersSince(lastSync);
+ *
+ * let created = 0, updated = 0, deleted = 0;
+ *
+ * for (const order of changedOrders) {
+ * if (order.isDeleted) {
+ * // 삭제된 데이터 처리
+ * await db.purchaseOrders.delete({ where: { externalId: order.id } });
+ * deleted++;
+ * } else {
+ * // 삽입/수정 데이터 처리
+ * const result = await db.purchaseOrders.upsert({
+ * where: { externalId: order.id },
+ * create: order,
+ * update: order
+ * });
+ *
+ * if (result.createdAt === result.updatedAt) {
+ * created++;
+ * } else {
+ * updated++;
+ * }
+ * }
+ * }
+ *
+ * // 동기화 타임스탬프 업데이트
+ * await updateLastSyncTimestamp('purchase_orders', new Date());
+ *
+ * return {
+ * syncType: 'delta',
+ * totalProcessed: changedOrders.length,
+ * created,
+ * updated,
+ * deleted
+ * };
+ * }
+ * );
+ *
+ * @example
+ * // 에러 복구가 포함된 동기화
+ * const resilientSyncResult = await withNonsapSyncLogging(
+ * 'inventory',
+ * 'delta',
+ * async () => {
+ * let processedCount = 0;
+ * let errorCount = 0;
+ * const errors: string[] = [];
+ *
+ * const inventoryUpdates = await fetchInventoryUpdates();
+ *
+ * for (const update of inventoryUpdates) {
+ * try {
+ * await db.inventory.upsert({
+ * where: { productId: update.productId },
+ * create: update,
+ * update: { quantity: update.quantity, updatedAt: new Date() }
+ * });
+ * processedCount++;
+ * } catch (error) {
+ * errorCount++;
+ * errors.push(`Product ${update.productId}: ${error.message}`);
+ *
+ * // 개별 에러는 로그에 남기지만 전체 작업은 계속 진행
+ * console.warn(`재고 업데이트 실패 - ${update.productId}:`, error);
+ * }
+ * }
+ *
+ * return {
+ * totalItems: inventoryUpdates.length,
+ * processedCount,
+ * errorCount,
+ * errors: errors.slice(0, 10) // 최대 10개 에러만 반환
+ * };
+ * }
+ * );
+ */
+export async function withNonsapSyncLogging<T>(
+ tableName: string,
+ syncType: 'full' | 'delta',
+ processor: () => Promise<T>
+): Promise<T> {
+ return withDbLogging(
+ 2, // nonsap 동기화 인터페이스 ID (추후 매핑 필요)
+ tableName,
+ `nonsap_${syncType}_sync`,
+ processor
+ );
+} \ No newline at end of file