diff options
| author | joonhoekim <26rote@gmail.com> | 2025-11-06 18:59:58 +0900 |
|---|---|---|
| committer | joonhoekim <26rote@gmail.com> | 2025-11-06 18:59:58 +0900 |
| commit | 1b843e0a7ea55c64992f55033b30037239ff67f5 (patch) | |
| tree | 7b64d320eebc7c540a82d1a74fb67ba682b7a6a5 | |
| parent | a4bf0d8376962c922da90cd08781893a3658ecc2 (diff) | |
(김준회) request context가 없는 한계에 따라 revalidate를 api 구조로 수정, API 시크릿 환경변수 추가, 공통 컴포넌트 생성, request context 요구하는 코드 수정
| -rw-r--r-- | .env.development | 5 | ||||
| -rw-r--r-- | .env.production | 5 | ||||
| -rw-r--r-- | lib/revalidation-utils.ts | 99 | ||||
| -rw-r--r-- | lib/vendors/service.ts | 31 |
4 files changed, 120 insertions, 20 deletions
diff --git a/.env.development b/.env.development index ea374be8..068a66e8 100644 --- a/.env.development +++ b/.env.development @@ -186,4 +186,7 @@ DOCUMENTUM_NFS="/mnt/nfs-documentum/" # 품질/운영 공통 POS_APP_CODE="SQ13" # 품질, 운영의 경우 SO13 # EDP 동기화 크론 설정 -EDP_MASTER_DATA_SYNC_CRON="0 23 * * *"
\ No newline at end of file +EDP_MASTER_DATA_SYNC_CRON="0 23 * * *" + +# request context 부재한 서버사이드 함수 호출시, api revalidate를 안전하게 호출하기 위한 키 추가 +REVALIDATION_SECRET="biwjeofijosdkfjoiwejfksdjf1"
\ No newline at end of file diff --git a/.env.production b/.env.production index acf8b43a..81f2e266 100644 --- a/.env.production +++ b/.env.production @@ -188,4 +188,7 @@ DOCUMENTUM_NFS="/mnt/nfs-documentum/" # 품질/운영 공통 POS_APP_CODE="SQ13" # 품질, 운영의 경우 SO13 # EDP 동기화 크론 설정 -EDP_MASTER_DATA_SYNC_CRON="0 23 * * *"
\ No newline at end of file +EDP_MASTER_DATA_SYNC_CRON="0 23 * * *" + +# request context 부재한 서버사이드 함수 호출시, api revalidate를 안전하게 호출하기 위한 키 추가 +REVALIDATION_SECRET="biwjeofijosdkfjoiwejfksdjf1"
\ No newline at end of file diff --git a/lib/revalidation-utils.ts b/lib/revalidation-utils.ts new file mode 100644 index 00000000..14c5bf01 --- /dev/null +++ b/lib/revalidation-utils.ts @@ -0,0 +1,99 @@ +/** + * Request Context가 없는 환경(cronjob, background worker 등)에서 + * 캐시를 무효화하기 위한 유틸리티 + * + * 사용 예시: + * ```ts + * // Cronjob에서 사용 + * await revalidateViaCronJob({ tags: ['vendors', 'users'] }); + * + * // 또는 개별 태그 + * await revalidateTagViaCronJob('vendors'); + * ``` + */ + +/** + * API를 통한 캐시 무효화 (cronjob 등에서 사용) + */ +export async function revalidateViaCronJob(options: { + tags?: string[]; +}): Promise<{ success: boolean; error?: string }> { + try { + const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'; + + const response = await fetch(`${baseUrl}/api/revalidate/approval`, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + tags: options.tags, + secret: process.env.REVALIDATION_SECRET, + }), + }); + + if (!response.ok) { + const error = await response.text(); + console.error('[Revalidation] API call failed:', error); + return { + success: false, + error: `Revalidation API failed: ${response.statusText}`, + }; + } + + const result = await response.json(); + console.log('[Revalidation] Cache invalidated:', options.tags); + + return { success: true }; + } catch (error) { + console.error('[Revalidation] Failed to revalidate cache:', error); + // 캐시 무효화 실패는 치명적이지 않으므로 경고만 출력 + return { + success: false, + error: error instanceof Error ? error.message : 'Unknown error', + }; + } +} + +/** + * 단일 태그 무효화 (cronjob에서 사용) + */ +export async function revalidateTagViaCronJob(tag: string) { + return revalidateViaCronJob({ tags: [tag] }); +} + +/** + * 벤더 관련 캐시 무효화 + */ +export async function revalidateVendorCaches() { + return revalidateViaCronJob({ + tags: ['vendors', 'vendor-status-counts'], + }); +} + +/** + * 유저 관련 캐시 무효화 + */ +export async function revalidateUserCaches() { + return revalidateViaCronJob({ + tags: ['users', 'roles', 'user-roles'], + }); +} + +/** + * 승인 프로세스에서 사용하는 모든 캐시 무효화 + */ +export async function revalidateApprovalRelatedCaches() { + return revalidateViaCronJob({ + tags: [ + 'vendors', + 'vendor-status-counts', + 'users', + 'roles', + 'user-roles', + 'approval-logs', + 'pending-actions', + ], + }); +} + diff --git a/lib/vendors/service.ts b/lib/vendors/service.ts index 76193eb9..6454bc7b 100644 --- a/lib/vendors/service.ts +++ b/lib/vendors/service.ts @@ -1772,10 +1772,8 @@ export async function approveVendors(input: ApproveVendorsInput & { userId: numb ? "[eVCP] 업체 승인 완료 - 계정 활성화" : "[eVCP] Vendor Approved - Account Activated"; - const headersList = await headers(); - const host = headersList.get('host') || 'localhost:3000'; - const protocol = headersList.get('x-forwarded-proto') || 'http'; - const baseUrl = `${protocol}://${host}`; + // ✅ Request Context가 없을 수 있으므로 환경변수 사용 + const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'; const loginUrl = `${baseUrl}/${userLang}/login`; const passwordSetupUrl = `${baseUrl}/${userLang}/auth/reset-password?token=${resetToken}`; // 패스워드 설정 URL @@ -1804,12 +1802,9 @@ export async function approveVendors(input: ApproveVendorsInput & { userId: numb return updated; }); - // 캐시 무효화 - revalidateTag("vendors"); - revalidateTag("vendor-status-counts"); - revalidateTag("users"); // 유저 캐시도 무효화 - revalidateTag("roles"); // 역할 캐시도 무효화 - revalidateTag("user-roles"); // 유저 역할 캐시도 무효화 + // ✅ 캐시 무효화 (cronjob에서도 작동하도록 API 사용) + const { revalidateApprovalRelatedCaches } = await import('@/lib/revalidation-utils'); + await revalidateApprovalRelatedCaches(); return { data: result, error: null }; } catch (err) { @@ -1933,10 +1928,8 @@ export async function rejectVendors(input: ApproveVendorsInput & { userId: numbe ? "[eVCP] 업체 등록 거절 안내" : "[eVCP] Vendor Registration Rejected"; - const headersList = await headers(); - const host = headersList.get('host') || 'localhost:3000'; - const protocol = headersList.get('x-forwarded-proto') || 'http'; - const baseUrl = `${protocol}://${host}`; + // ✅ Request Context가 없을 수 있으므로 환경변수 사용 + const baseUrl = process.env.NEXT_PUBLIC_BASE_URL || 'http://localhost:3000'; const loginUrl = `${baseUrl}/${userLang}/login`; await sendEmail({ @@ -1962,10 +1955,12 @@ export async function rejectVendors(input: ApproveVendorsInput & { userId: numbe return updated; }); - // 캐시 무효화 - revalidateTag("vendors"); - revalidateTag("vendor-status-counts"); - revalidateTag("users"); // 유저 캐시도 무효화 + // ✅ 캐시 무효화 (cronjob에서도 작동하도록 API 사용) + const { revalidateVendorCaches, revalidateUserCaches } = await import('@/lib/revalidation-utils'); + await Promise.all([ + revalidateVendorCaches(), + revalidateUserCaches(), + ]); return { data: result, error: null }; } catch (err) { |
