fix: complete feedback confirmation flow
Deploy EG-BIM QA Gateway / deploy (push) Successful in 40s

This commit is contained in:
root committed 2026-09-29 20:35:48 +09:00
1 parent a332ed0d8e
commit efd1bf2e3c
6 files changed
+122 -24

No files matched your search

+46
View File
@@ -14,6 +14,7 @@ export default {
if (request.method === 'GET') return listFeedbacks(request, env, url);
return createFeedback(request, env);
}
if (/^\/api\/feedbacks\/[^/]+\/completion-confirmation$/.test(url.pathname)) return completionConfirmation(request, env, url);
if (/^\/api\/feedbacks\/[^/]+\/comments$/.test(url.pathname)) return feedbackComments(request, env, url);
if (/^\/api\/feedbacks\/[^/]+$/.test(url.pathname)) return feedbackDetail(request, env, url);
@@ -484,6 +485,51 @@ async function listFeedbacks(request, env, url) {
return json({ items: Array.isArray(items) ? items : [], meta });
}
async function completionConfirmation(request, env, url) {
if (request.method !== "POST") return json({ error: "method_not_allowed" }, 405, { allow: "POST" });
const user = await getSession(request, env);
if (!user) return json({ error: "unauthenticated" }, 401);
if (!env.ABC_API_KEY) return json({ error: "feedback_api_not_configured" }, 503);
if (!env.ABC_PROJECT_ID || !env.ABC_CHANNEL_ID) return json({ error: "feedback_target_not_configured" }, 503);
const feedbackId = decodeURIComponent(url.pathname.split("/")[3] || "");
if (!isUuidv7(feedbackId)) return json({ error: "invalid_feedback_id" }, 400);
const requesterId = String(user.requesterId || user.ssoSubject || user.userUuid || "");
const requesterTenantId = String(user.requesterTenantId || user.tenantId || "");
if (!requesterId || !requesterTenantId) return json({ error: "requester_identity_missing" }, 422);
const apiBaseUrlValue = String(env.ABC_API_BASE_URL || "https://feedback.hmac.kr");
const apiBaseUrl = apiBaseUrlValue.endsWith("/") ? apiBaseUrlValue.slice(0, -1) : apiBaseUrlValue;
const endpoint = apiBaseUrl + "/api/projects/" + encodeURIComponent(env.ABC_PROJECT_ID) + "/channels/" + encodeURIComponent(env.ABC_CHANNEL_ID) + "/feedbacks/" + encodeURIComponent(feedbackId) + "/completion-confirmation";
const idempotencyConsumer = env.ABC_IDEMPOTENCY_CONSUMER || env.ABC_SOURCE_NAMESPACE || "EGBIM_QA";
const headers = {
accept: "application/json",
"content-type": "application/json",
"x-api-key": env.ABC_API_KEY,
"x-requester-id": requesterId,
"x-requester-tenant-id": requesterTenantId,
"x-idempotency-consumer": idempotencyConsumer,
"idempotency-key": feedbackId,
"x-source-namespace": idempotencyConsumer,
"x-source-record-id": feedbackId
};
const body = JSON.stringify({ requester_id: requesterId, requester_tenant_id: requesterTenantId });
let response;
try {
response = await fetch(endpoint, { method: "POST", headers, body });
} catch (error) {
console.error("feedback_completion_confirmation_request_failed", error instanceof Error ? error.message : "unknown");
return json({ error: "feedback_api_unreachable" }, 502);
}
const result = await response.json().catch(() => ({}));
if (!response.ok) {
const upstreamMessage = String(result.message || result.error || result.code || "").slice(0, 240);
return json({ error: "feedback_completion_confirmation_rejected", message: upstreamMessage || "문의 완료 확인에 실패했습니다.", status: response.status }, response.status >= 500 ? 502 : response.status);
}
return json({ ok: true, feedback: result.feedback || result.data || result });
}
async function feedbackComments(request, env, url) {
if (request.method !== 'GET' && request.method !== 'POST') return json({ error: 'method_not_allowed' }, 405, { allow: 'GET, POST' });
const user = await getSession(request, env);