summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-06 18:59:58 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-06 18:59:58 +0900
commit1b843e0a7ea55c64992f55033b30037239ff67f5 (patch)
tree7b64d320eebc7c540a82d1a74fb67ba682b7a6a5
parenta4bf0d8376962c922da90cd08781893a3658ecc2 (diff)
(김준회) request context가 없는 한계에 따라 revalidate를 api 구조로 수정, API 시크릿 환경변수 추가, 공통 컴포넌트 생성, request context 요구하는 코드 수정
-rw-r--r--.env.development5
-rw-r--r--.env.production5
-rw-r--r--lib/revalidation-utils.ts99
-rw-r--r--lib/vendors/service.ts31
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) {