summaryrefslogtreecommitdiff
path: root/app/api
diff options
context:
space:
mode:
authorjoonhoekim <26rote@gmail.com>2025-11-05 19:28:49 +0900
committerjoonhoekim <26rote@gmail.com>2025-11-05 19:28:49 +0900
commite890fbae0c9c273b825ac808aa516de1f87fb218 (patch)
treec2b7bdacd22043a8b4781e9b4c6ea682468abd0f /app/api
parent35e373fe29a4145d0692ee35ff9e6b0c887df0eb (diff)
(김준회) 실사의뢰 결재 오류 수정, 결재 캐시 백그라운드 컨텍스트에서 패스로 무효화 처리, pm2 ecosystem 설정 변경 (npm 레이어 로그 문제), git 줄바꿈 문제 2건 커밋으로 처리
Diffstat (limited to 'app/api')
-rw-r--r--app/api/pos/download-on-demand-partners/route.ts1
-rw-r--r--app/api/revalidate/approval/route.ts101
2 files changed, 102 insertions, 0 deletions
diff --git a/app/api/pos/download-on-demand-partners/route.ts b/app/api/pos/download-on-demand-partners/route.ts
index d2941537..0e146c80 100644
--- a/app/api/pos/download-on-demand-partners/route.ts
+++ b/app/api/pos/download-on-demand-partners/route.ts
@@ -241,3 +241,4 @@ export async function GET(request: NextRequest) {
}
}
+
diff --git a/app/api/revalidate/approval/route.ts b/app/api/revalidate/approval/route.ts
new file mode 100644
index 00000000..ed4da139
--- /dev/null
+++ b/app/api/revalidate/approval/route.ts
@@ -0,0 +1,101 @@
+import { revalidateTag } from 'next/cache';
+import { NextRequest, NextResponse } from 'next/server';
+
+/**
+ * 결재 시스템 캐시 무효화 API
+ *
+ * 백그라운드 프로세스(폴링 서비스)에서 request 컨텍스트 없이
+ * 캐시를 무효화하기 위한 API 라우트
+ *
+ * 사용법:
+ * await fetch('/api/revalidate/approval', {
+ * method: 'POST',
+ * headers: { 'Content-Type': 'application/json' },
+ * body: JSON.stringify({ tags: ['approval-logs'] })
+ * });
+ */
+export async function POST(request: NextRequest) {
+ try {
+ const body = await request.json();
+ const { tags, secret } = body;
+
+ // 선택적 보안: 환경 변수로 시크릿 키 검증
+ // 내부 서버에서만 호출되므로 필수는 아님
+ if (process.env.REVALIDATION_SECRET && secret !== process.env.REVALIDATION_SECRET) {
+ return NextResponse.json(
+ { success: false, message: 'Invalid secret' },
+ { status: 401 }
+ );
+ }
+
+ // 캐시 태그 무효화
+ if (Array.isArray(tags)) {
+ for (const tag of tags) {
+ revalidateTag(tag);
+ console.log(`[Cache Revalidation] Tag revalidated: ${tag}`);
+ }
+ } else if (typeof tags === 'string') {
+ revalidateTag(tags);
+ console.log(`[Cache Revalidation] Tag revalidated: ${tags}`);
+ }
+
+ return NextResponse.json({
+ success: true,
+ revalidated: true,
+ tags: Array.isArray(tags) ? tags : [tags],
+ timestamp: new Date().toISOString(),
+ });
+ } catch (error) {
+ console.error('[Cache Revalidation] Error:', error);
+ return NextResponse.json(
+ {
+ success: false,
+ message: error instanceof Error ? error.message : 'Revalidation failed',
+ },
+ { status: 500 }
+ );
+ }
+}
+
+// GET 요청으로도 사용 가능 (개발/테스트용)
+export async function GET(request: NextRequest) {
+ const { searchParams } = new URL(request.url);
+ const tag = searchParams.get('tag');
+ const secret = searchParams.get('secret');
+
+ if (process.env.REVALIDATION_SECRET && secret !== process.env.REVALIDATION_SECRET) {
+ return NextResponse.json(
+ { success: false, message: 'Invalid secret' },
+ { status: 401 }
+ );
+ }
+
+ if (!tag) {
+ return NextResponse.json(
+ { success: false, message: 'Tag parameter is required' },
+ { status: 400 }
+ );
+ }
+
+ try {
+ revalidateTag(tag);
+ console.log(`[Cache Revalidation] Tag revalidated: ${tag}`);
+
+ return NextResponse.json({
+ success: true,
+ revalidated: true,
+ tag,
+ timestamp: new Date().toISOString(),
+ });
+ } catch (error) {
+ console.error('[Cache Revalidation] Error:', error);
+ return NextResponse.json(
+ {
+ success: false,
+ message: error instanceof Error ? error.message : 'Revalidation failed',
+ },
+ { status: 500 }
+ );
+ }
+}
+