summaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
authordujinkim <dujin.kim@dtsolution.co.kr>2025-08-04 09:36:14 +0000
committerdujinkim <dujin.kim@dtsolution.co.kr>2025-08-04 09:36:14 +0000
commit92eda21e45d902663052575aaa4c4f80bfa2faea (patch)
tree8483702edf82932d4359a597a854fa8e1b48e94b /app
parentf0213de0d2fb5fcb931b3ddaddcbb6581cab5d28 (diff)
(대표님) 벤더 문서 변경사항, data-table 변경, sync 변경
Diffstat (limited to 'app')
-rw-r--r--app/[lng]/partners/(partners)/settings/layout.tsx4
-rw-r--r--app/[lng]/partners/(partners)/settings/page.tsx2
-rw-r--r--app/api/revision-attachment/route.ts16
-rw-r--r--app/api/revision-upload/route.ts18
-rw-r--r--app/api/sync/batches/route.ts6
-rw-r--r--app/api/sync/config/route.ts12
-rw-r--r--app/api/sync/import/route.ts6
-rw-r--r--app/api/sync/import/status/route.ts6
-rw-r--r--app/api/sync/status/route.ts18
-rw-r--r--app/api/sync/trigger/route.ts6
-rw-r--r--app/api/sync/workflow/action/route.ts6
-rw-r--r--app/api/sync/workflow/status/route.ts6
-rw-r--r--app/globals.css33
13 files changed, 86 insertions, 53 deletions
diff --git a/app/[lng]/partners/(partners)/settings/layout.tsx b/app/[lng]/partners/(partners)/settings/layout.tsx
index f3cea7d2..3b8f48a3 100644
--- a/app/[lng]/partners/(partners)/settings/layout.tsx
+++ b/app/[lng]/partners/(partners)/settings/layout.tsx
@@ -4,7 +4,7 @@ import { Separator } from "@/components/ui/separator"
import { SidebarNav } from "@/components/layout/sidebar-nav"
export const metadata: Metadata = {
- title: "설정",
+ title: "Setting",
// description: "Advanced form example using react-hook-form and Zod.",
}
@@ -46,7 +46,7 @@ export default async function SettingsLayout({
<section className="overflow-hidden rounded-[0.5rem] border bg-background shadow">
<div className="hidden space-y-6 p-10 pb-16 md:block">
<div className="space-y-0.5">
- <h2 className="text-2xl font-bold tracking-tight">설정</h2>
+ <h2 className="text-2xl font-bold tracking-tight">Setting</h2>
{/* <p className="text-muted-foreground">
Manage your account settings and preferences.
</p> */}
diff --git a/app/[lng]/partners/(partners)/settings/page.tsx b/app/[lng]/partners/(partners)/settings/page.tsx
index 412597a5..727be46b 100644
--- a/app/[lng]/partners/(partners)/settings/page.tsx
+++ b/app/[lng]/partners/(partners)/settings/page.tsx
@@ -149,7 +149,7 @@ export default function SettingsAccountPage() {
<div>
<div className="flex items-center justify-between">
<div>
- <h3 className="text-lg font-medium">계정</h3>
+ <h3 className="text-lg font-medium">Account</h3>
{/* <p className="text-sm text-muted-foreground">
Update your account settings and manage your profile information.
</p> */}
diff --git a/app/api/revision-attachment/route.ts b/app/api/revision-attachment/route.ts
index 12834085..092eed8d 100644
--- a/app/api/revision-attachment/route.ts
+++ b/app/api/revision-attachment/route.ts
@@ -10,6 +10,7 @@ import {
documents,
revisions,
documentAttachments,
+ issueStages,
} from "@/db/schema/vendorDocu"
import { eq } from "drizzle-orm"
@@ -50,10 +51,11 @@ export async function POST(request: NextRequest) {
usage: revisions.usage,
usageType: revisions.usageType,
issueStageId: revisions.issueStageId,
- contractId: documents.contractId,
+ projectId: documents.projectId,
})
.from(revisions)
- .leftJoin(documents, eq(documents.id, revisions.issueStageId))
+ .innerJoin(issueStages, eq(revisions.issueStageId, issueStages.id))
+ .innerJoin(documents, eq(issueStages.documentId, documents.id))
.where(eq(revisions.id, revisionId))
.limit(1)
@@ -95,7 +97,7 @@ export async function POST(request: NextRequest) {
// change_logs: attachment CREATE
await logAttachmentChange(
- revisionInfo.contractId,
+ revisionInfo.projectId,
att.id,
"CREATE",
att,
@@ -117,16 +119,16 @@ export async function POST(request: NextRequest) {
usage: revisionInfo.usage,
usageType: revisionInfo.usageType,
uploadedFiles,
- contractId: revisionInfo.contractId
+ projectId: revisionInfo.projectId
}
})
// 캐시 무효화
try {
- // revalidateTag(`enhanced-documents-${result.contractId}`)
- revalidateTag(`sync-status-${result.contractId}`)
+ // revalidateTag(`enhanced-documents-${result.projectId}`)
+ revalidateTag(`sync-status-${result.projectId}`)
- console.log(`✅ Cache invalidated for contract ${result.contractId}`)
+ console.log(`✅ Cache invalidated for contract ${result.projectId}`)
} catch (cacheError) {
console.warn('⚠️ Cache invalidation failed:', cacheError)
}
diff --git a/app/api/revision-upload/route.ts b/app/api/revision-upload/route.ts
index b171b89a..bd75e0b5 100644
--- a/app/api/revision-upload/route.ts
+++ b/app/api/revision-upload/route.ts
@@ -56,7 +56,7 @@ export async function POST(request: NextRequest) {
/* ------- 계약 ID 확보 ------- */
const [docInfo] = await db
- .select({ contractId: documents.contractId })
+ .select({ projectId: documents.projectId })
.from(documents)
.where(eq(documents.id, docId))
.limit(1)
@@ -124,7 +124,7 @@ export async function POST(request: NextRequest) {
// change_logs: CREATE
await logRevisionChange(
- docInfo.contractId,
+ docInfo.projectId,
revisionId,
"CREATE",
newRev,
@@ -157,7 +157,7 @@ export async function POST(request: NextRequest) {
revisionId = revRow.id
await logRevisionChange(
- docInfo.contractId,
+ docInfo.projectId,
revisionId,
"UPDATE",
updated,
@@ -215,7 +215,7 @@ export async function POST(request: NextRequest) {
// change_logs: attachment CREATE
await logAttachmentChange(
- docInfo.contractId,
+ docInfo.projectId,
att.id,
"CREATE",
att,
@@ -247,7 +247,7 @@ export async function POST(request: NextRequest) {
revision,
uploadedFiles,
mode,
- contractId: docInfo.contractId,
+ projectId: docInfo.projectId,
usage,
usageType,
securityFailures // 보안 실패 정보 포함
@@ -257,12 +257,12 @@ export async function POST(request: NextRequest) {
// 캐시 무효화 - 트랜잭션 완료 후에 실행
try {
// enhanced documents 캐시 무효화
- revalidateTag(`enhanced-documents-${result.contractId}`)
+ revalidateTag(`enhanced-documents-${result.projectId}`)
// sync status 관련 캐시도 무효화 (필요시)
- revalidateTag(`sync-status-${result.contractId}`)
+ revalidateTag(`sync-status-${result.projectId}`)
- console.log(`✅ Cache invalidated for contract ${result.contractId}`)
+ console.log(`✅ Cache invalidated for contract ${result.projectId}`)
} catch (cacheError) {
console.warn('⚠️ Cache invalidation failed:', cacheError)
// 캐시 무효화 실패해도 업로드는 성공으로 처리
@@ -288,7 +288,7 @@ export async function POST(request: NextRequest) {
uploadedFiles: result.uploadedFiles,
filesCount: result.uploadedFiles.length,
securityFailures: result.securityFailures, // 클라이언트에 보안 실패 정보 전달
- contractId: result.contractId,
+ projectId: result.projectId,
},
})
} catch (e) {
diff --git a/app/api/sync/batches/route.ts b/app/api/sync/batches/route.ts
index a1ef8d26..7a72530d 100644
--- a/app/api/sync/batches/route.ts
+++ b/app/api/sync/batches/route.ts
@@ -4,11 +4,11 @@ import { NextRequest, NextResponse } from "next/server"
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
- const contractId = searchParams.get('contractId')
+ const projectId = searchParams.get('projectId')
const targetSystem = searchParams.get('targetSystem') || 'SHI'
const limit = parseInt(searchParams.get('limit') || '10')
- if (!contractId) {
+ if (!projectId) {
return NextResponse.json(
{ error: 'Contract ID is required' },
{ status: 400 }
@@ -16,7 +16,7 @@ export async function GET(request: NextRequest) {
}
const batches = await syncService.getRecentSyncBatches(
- parseInt(contractId),
+ parseInt(projectId),
targetSystem,
limit
)
diff --git a/app/api/sync/config/route.ts b/app/api/sync/config/route.ts
index e54762fc..db5d17ca 100644
--- a/app/api/sync/config/route.ts
+++ b/app/api/sync/config/route.ts
@@ -6,10 +6,10 @@ import { authOptions } from "@/app/api/auth/[...nextauth]/route"
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
- const contractId = searchParams.get('contractId')
+ const projectId = searchParams.get('projectId')
const targetSystem = searchParams.get('targetSystem') || 'SHI'
- if (!contractId) {
+ if (!projectId) {
return NextResponse.json(
{ error: 'Contract ID is required' },
{ status: 400 }
@@ -17,7 +17,7 @@ export async function GET(request: NextRequest) {
}
const config = await syncService.getSyncConfig(
- parseInt(contractId),
+ parseInt(projectId),
targetSystem
)
@@ -48,7 +48,7 @@ export async function POST(request: NextRequest) {
}
const body = await request.json()
const {
- contractId,
+ projectId,
targetSystem,
endpointUrl,
authToken,
@@ -57,7 +57,7 @@ export async function POST(request: NextRequest) {
maxBatchSize
} = body
- if (!contractId || !targetSystem || !endpointUrl) {
+ if (!projectId || !targetSystem || !endpointUrl) {
return NextResponse.json(
{ error: 'Contract ID, target system, and endpoint URL are required' },
{ status: 400 }
@@ -65,7 +65,7 @@ export async function POST(request: NextRequest) {
}
await syncService.upsertSyncConfig({
- contractId,
+ projectId,
targetSystem,
endpointUrl,
authToken,
diff --git a/app/api/sync/import/route.ts b/app/api/sync/import/route.ts
index a6496578..f32a99e2 100644
--- a/app/api/sync/import/route.ts
+++ b/app/api/sync/import/route.ts
@@ -11,9 +11,9 @@ export async function POST(request: NextRequest) {
}
const body = await request.json()
- const { contractId, sourceSystem = 'DOLCE' } = body
+ const { projectId, sourceSystem = 'DOLCE' } = body
- if (!contractId) {
+ if (!projectId) {
return NextResponse.json(
{ error: 'Contract ID is required' },
{ status: 400 }
@@ -21,7 +21,7 @@ export async function POST(request: NextRequest) {
}
const result = await importService.importFromExternalSystem(
- contractId,
+ projectId,
sourceSystem
)
diff --git a/app/api/sync/import/status/route.ts b/app/api/sync/import/status/route.ts
index c5b4b0bd..ddb202e4 100644
--- a/app/api/sync/import/status/route.ts
+++ b/app/api/sync/import/status/route.ts
@@ -12,10 +12,10 @@ export async function GET(request: NextRequest) {
}
const { searchParams } = new URL(request.url)
- const contractId = searchParams.get('contractId')
+ const projectId = searchParams.get('projectId')
const sourceSystem = searchParams.get('sourceSystem') || 'DOLCE'
- if (!contractId) {
+ if (!projectId) {
return NextResponse.json(
{ error: 'Contract ID is required' },
{ status: 400 }
@@ -23,7 +23,7 @@ export async function GET(request: NextRequest) {
}
const status = await importService.getImportStatus(
- Number(contractId),
+ Number(projectId),
sourceSystem
)
diff --git a/app/api/sync/status/route.ts b/app/api/sync/status/route.ts
index 886c14df..b4b18577 100644
--- a/app/api/sync/status/route.ts
+++ b/app/api/sync/status/route.ts
@@ -33,22 +33,22 @@ function serializeForJSON(obj: any): any {
export async function GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url)
- const contractId = searchParams.get('contractId')
+ const projectId = searchParams.get('projectId')
const targetSystem = searchParams.get('targetSystem') || 'SHI'
-
- if (!contractId) {
+
+ if (!projectId) {
return NextResponse.json(
- { error: 'Contract ID is required' },
+ { error: 'Project ID is required' },
{ status: 400 }
)
}
-
+
let status
try {
// 실제 데이터베이스에서 조회 시도
status = await syncService.getSyncStatus(
- parseInt(contractId),
+ parseInt(projectId),
targetSystem
)
} catch (error) {
@@ -56,7 +56,7 @@ export async function GET(request: NextRequest) {
// ✅ 데이터베이스 조회 실패시 임시 목업 데이터 반환
status = {
- contractId: parseInt(contractId),
+ projectId: parseInt(projectId),
targetSystem,
totalChanges: 15,
pendingChanges: 3, // 3건 대기 중 (빨간 뱃지 표시용)
@@ -67,10 +67,10 @@ export async function GET(request: NextRequest) {
syncEnabled: true
}
}
-
+
// JSON 직렬화 가능한 형태로 변환
const serializedStatus = serializeForJSON(status)
-
+
return NextResponse.json(serializedStatus)
} catch (error) {
console.error('Failed to get sync status:', error)
diff --git a/app/api/sync/trigger/route.ts b/app/api/sync/trigger/route.ts
index 3393365d..3fe58849 100644
--- a/app/api/sync/trigger/route.ts
+++ b/app/api/sync/trigger/route.ts
@@ -13,9 +13,9 @@ export async function POST(request: NextRequest) {
}
const body = await request.json()
- const { contractId, targetSystem = 'SHI' } = body
+ const { projectId, targetSystem = 'SHI' } = body
- if (!contractId) {
+ if (!projectId) {
return NextResponse.json(
{ error: 'Contract ID is required' },
{ status: 400 }
@@ -23,7 +23,7 @@ export async function POST(request: NextRequest) {
}
const result = await syncService.syncToExternalSystem(
- contractId,
+ projectId,
targetSystem,
true // manual trigger
)
diff --git a/app/api/sync/workflow/action/route.ts b/app/api/sync/workflow/action/route.ts
index b6b1a94f..8e311c86 100644
--- a/app/api/sync/workflow/action/route.ts
+++ b/app/api/sync/workflow/action/route.ts
@@ -12,9 +12,9 @@ export async function POST(request: NextRequest) {
}
const body = await request.json()
- const { contractId, targetSystem = 'SWP', action, documents } = body
+ const { projectId, targetSystem = 'SWP', action, documents } = body
- if (!contractId || !action) {
+ if (!projectId || !action) {
return NextResponse.json(
{ error: 'Contract ID and action are required' },
{ status: 400 }
@@ -22,7 +22,7 @@ export async function POST(request: NextRequest) {
}
const result = await workflowService.executeWorkflowAction(
- contractId,
+ projectId,
targetSystem,
action,
documents || [],
diff --git a/app/api/sync/workflow/status/route.ts b/app/api/sync/workflow/status/route.ts
index a4c5d1d0..1274f049 100644
--- a/app/api/sync/workflow/status/route.ts
+++ b/app/api/sync/workflow/status/route.ts
@@ -12,10 +12,10 @@ export async function GET(request: NextRequest) {
}
const { searchParams } = new URL(request.url)
- const contractId = searchParams.get('contractId')
+ const projectId = searchParams.get('projectId')
const targetSystem = searchParams.get('targetSystem') || 'SWP'
- if (!contractId) {
+ if (!projectId) {
return NextResponse.json(
{ error: 'Contract ID is required' },
{ status: 400 }
@@ -23,7 +23,7 @@ export async function GET(request: NextRequest) {
}
const status = await workflowService.getWorkflowStatus(
- Number(contractId),
+ Number(projectId),
targetSystem
)
diff --git a/app/globals.css b/app/globals.css
index fa510ec4..a4ee4734 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -218,4 +218,35 @@ th[data-read-only="true"] {
.tbl-compact tbody tr { @apply hover:bg-muted/40; } /* 선택 */
/* 필요시 행 높이 제한 */
.tbl-compact tbody tr > * { @apply h-8; } /* 32 px 정도 */
-} \ No newline at end of file
+}
+
+/* 그룹 컬럼 구분선 스타일 */
+.group-column-border {
+ position: relative;
+}
+
+.group-column-border::before,
+.group-column-border::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 2px;
+ background-color: #e2e8f0;
+}
+
+.group-column-border::before {
+ left: -1px;
+}
+
+.group-column-border::after {
+ right: -1px;
+}
+
+/* 그룹 헤더 스타일 */
+.group-header {
+ background-color: #f8fafc;
+ font-weight: 600;
+ border-left: 2px solid #cbd5e1;
+ border-right: 2px solid #cbd5e1;
+}