summaryrefslogtreecommitdiff
path: root/lib/vendor-document-list/sync-service.ts
diff options
context:
space:
mode:
Diffstat (limited to 'lib/vendor-document-list/sync-service.ts')
-rw-r--r--lib/vendor-document-list/sync-service.ts167
1 files changed, 97 insertions, 70 deletions
diff --git a/lib/vendor-document-list/sync-service.ts b/lib/vendor-document-list/sync-service.ts
index cdbf489f..c3ddfcca 100644
--- a/lib/vendor-document-list/sync-service.ts
+++ b/lib/vendor-document-list/sync-service.ts
@@ -101,7 +101,7 @@ class SyncService {
* 동기화할 변경사항 조회 (증분)
*/
async getPendingChanges(
- vendorId: number,
+ userId: number,
targetSystem: string = 'DOLCE',
limit?: number
): Promise<ChangeLog[]> {
@@ -109,7 +109,7 @@ class SyncService {
.select()
.from(changeLogs)
.where(and(
- eq(changeLogs.vendorId, vendorId),
+ eq(changeLogs.userId, userId),
eq(changeLogs.isSynced, false),
lt(changeLogs.syncAttempts, 3),
sql`(${changeLogs.targetSystems} IS NULL OR ${changeLogs.targetSystems} @> ${JSON.stringify([targetSystem])})`
@@ -176,10 +176,11 @@ class SyncService {
}
const vendorId = Number(session.user.companyId)
+ const userId = Number(session.user.id)
// 2. 대기 중인 변경사항 조회 (전체)
- const pendingChanges = await this.getPendingChanges(vendorId, targetSystem)
+ const pendingChanges = await this.getPendingChanges(userId, targetSystem)
if (pendingChanges.length === 0) {
return {
@@ -457,79 +458,105 @@ class SyncService {
.where(inArray(changeLogs.id, changeIds))
}
- /**
- * 동기화 상태 조회
- */
- async getSyncStatus(projectId: number, targetSystem: string = 'DOLCE') {
- try {
+/**
+ * 동기화 상태 조회 - entityType별 상세 통계 포함
+ */
+async getSyncStatus(projectId: number, targetSystem: string = 'DOLCE') {
+ try {
+ const session = await getServerSession(authOptions)
+ if (!session?.user?.companyId) {
+ throw new Error("인증이 필요합니다.")
+ }
- const session = await getServerSession(authOptions)
- if (!session?.user?.companyId) {
- throw new Error("인증이 필요합니다.")
+ const vendorId = Number(session.user.companyId)
+ const userId = Number(session.user.id)
+
+ // 기본 조건
+ const baseConditions = and(
+ eq(changeLogs.userId, userId),
+ sql`(${changeLogs.targetSystems} IS NULL OR ${changeLogs.targetSystems} @> ${JSON.stringify([targetSystem])})`
+ )
+
+ // entityType별 통계를 위한 쿼리
+ const entityStats = await db
+ .select({
+ entityType: changeLogs.entityType,
+ pendingCount: sql<number>`COUNT(*) FILTER (WHERE ${changeLogs.isSynced} = false AND ${changeLogs.syncAttempts} < 3)`,
+ syncedCount: sql<number>`COUNT(*) FILTER (WHERE ${changeLogs.isSynced} = true)`,
+ failedCount: sql<number>`COUNT(*) FILTER (WHERE ${changeLogs.isSynced} = false AND ${changeLogs.syncAttempts} >= 3)`,
+ totalCount: sql<number>`COUNT(*)`
+ })
+ .from(changeLogs)
+ .where(baseConditions)
+ .groupBy(changeLogs.entityType)
+
+ // 전체 통계 계산
+ const totals = entityStats.reduce((acc, stat) => ({
+ pendingChanges: acc.pendingChanges + Number(stat.pendingCount),
+ syncedChanges: acc.syncedChanges + Number(stat.syncedCount),
+ failedChanges: acc.failedChanges + Number(stat.failedCount),
+ totalChanges: acc.totalChanges + Number(stat.totalCount)
+ }), {
+ pendingChanges: 0,
+ syncedChanges: 0,
+ failedChanges: 0,
+ totalChanges: 0
+ })
+
+ // entityType별 상세 정보 구성
+ const entityTypeDetails = {
+ document: {
+ pending: 0,
+ synced: 0,
+ failed: 0,
+ total: 0
+ },
+ revision: {
+ pending: 0,
+ synced: 0,
+ failed: 0,
+ total: 0
+ },
+ attachment: {
+ pending: 0,
+ synced: 0,
+ failed: 0,
+ total: 0
}
-
- const vendorId = Number(session.user.companyId)
-
-
- // 대기 중인 변경사항 수 조회
- const pendingCount = await db.$count(
- changeLogs,
- and(
- eq(changeLogs.vendorId, vendorId),
- eq(changeLogs.isSynced, false),
- lt(changeLogs.syncAttempts, 3),
- sql`(${changeLogs.targetSystems} IS NULL OR ${changeLogs.targetSystems} @> ${JSON.stringify([targetSystem])})`
- )
- )
-
- // 동기화된 변경사항 수 조회
- const syncedCount = await db.$count(
- changeLogs,
- and(
- eq(changeLogs.vendorId, vendorId),
- eq(changeLogs.isSynced, true),
- sql`(${changeLogs.targetSystems} IS NULL OR ${changeLogs.targetSystems} @> ${JSON.stringify([targetSystem])})`
- )
- )
-
- // 실패한 변경사항 수 조회
- const failedCount = await db.$count(
- changeLogs,
- and(
- eq(changeLogs.vendorId, vendorId),
- eq(changeLogs.isSynced, false),
- sql`${changeLogs.syncAttempts} >= 3`,
- sql`(${changeLogs.targetSystems} IS NULL OR ${changeLogs.targetSystems} @> ${JSON.stringify([targetSystem])})`
- )
- )
-
- // 마지막 성공한 배치 조회
- const [lastSuccessfulBatch] = await db
- .select()
- .from(syncBatches)
- .where(and(
- eq(syncBatches.vendorId, vendorId),
- eq(syncBatches.targetSystem, targetSystem),
- eq(syncBatches.status, 'SUCCESS')
- ))
- .orderBy(desc(syncBatches.completedAt))
- .limit(1)
+ }
- return {
- vendorId,
- targetSystem,
- totalChanges: pendingCount + syncedCount + failedCount,
- pendingChanges: pendingCount,
- syncedChanges: syncedCount,
- failedChanges: failedCount,
- lastSyncAt: lastSuccessfulBatch?.completedAt?.toISOString() || null,
- syncEnabled: this.isSyncEnabled(targetSystem)
+ // 통계 데이터를 entityTypeDetails에 매핑
+ entityStats.forEach(stat => {
+ const entityType = stat.entityType as 'document' | 'revision' | 'attachment'
+ if (entityTypeDetails[entityType]) {
+ entityTypeDetails[entityType] = {
+ pending: Number(stat.pendingCount),
+ synced: Number(stat.syncedCount),
+ failed: Number(stat.failedCount),
+ total: Number(stat.totalCount)
+ }
}
- } catch (error) {
- console.error('Failed to get sync status:', error)
- throw error
+ })
+
+
+ return {
+ projectId,
+ vendorId,
+ targetSystem,
+ ...totals,
+ entityTypeDetails, // entityType별 상세 통계
+ syncEnabled: this.isSyncEnabled(targetSystem),
+ // 추가 메타데이터
+ hasPendingChanges: totals.pendingChanges > 0,
+ hasFailedChanges: totals.failedChanges > 0,
+ syncHealthy: totals.failedChanges === 0 && totals.pendingChanges < 100,
+ requiresSync: totals.pendingChanges > 0
}
+ } catch (error) {
+ console.error('Failed to get sync status:', error)
+ throw error
}
+}
/**
* 최근 동기화 배치 목록 조회