From 2bfe653ac0ef026ed208882e487a65f1806f7249 Mon Sep 17 00:00:00 2001 From: bicochan Date: Fri, 4 Sep 2026 15:18:32 +0900 Subject: [PATCH] =?UTF-8?q?[as]=20feat:=20'dcrag-to'=20API=20=EA=B5=AC?= =?UTF-8?q?=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../entities/dcrag-to/api/dcrag-to-service.ts | 54 ++++++++++++++ apps/as/src/entities/dcrag-to/api/queries.ts | 70 +++++++++++++++++++ apps/as/src/entities/dcrag-to/index.ts | 27 +++++++ .../dcrag-to/model/dcrag-to-interface.ts | 52 ++++++++++++++ .../dcrag-to/model/dcrag-to-payload-schema.ts | 45 ++++++++++++ apps/as/src/shared/config/api.ts | 1 + 6 files changed, 249 insertions(+) create mode 100644 apps/as/src/entities/dcrag-to/api/dcrag-to-service.ts create mode 100644 apps/as/src/entities/dcrag-to/api/queries.ts create mode 100644 apps/as/src/entities/dcrag-to/index.ts create mode 100644 apps/as/src/entities/dcrag-to/model/dcrag-to-interface.ts create mode 100644 apps/as/src/entities/dcrag-to/model/dcrag-to-payload-schema.ts diff --git a/apps/as/src/entities/dcrag-to/api/dcrag-to-service.ts b/apps/as/src/entities/dcrag-to/api/dcrag-to-service.ts new file mode 100644 index 000000000..16c2ccdbd --- /dev/null +++ b/apps/as/src/entities/dcrag-to/api/dcrag-to-service.ts @@ -0,0 +1,54 @@ +import { client } from "@/shared/api"; +import { ENDPOINT } from "@/shared/config"; + +import type { + DcRagApiToService, + DcRagCommonResponseDto, + DcRagDraftGenerateResponseDto, + DcRagDraftStatusResponseDto, +} from "../model/dcrag-to-interface"; +import type { + DcRagCostVerifyRequestDto, + DcRagDocumentTransferRequestDto, + DcRagDraftGenerateRequestDto, +} from "../model/dcrag-to-payload-schema"; + +const BASE = ENDPOINT.AS_SERVICE.DCRAG_TO; + +async function requestDocumentTransfer( + body: DcRagDocumentTransferRequestDto, +): Promise { + const response = await client.post(`${BASE}/documents/transfer`, body); + return response.data; +} + +async function requestDraftGeneration( + body: DcRagDraftGenerateRequestDto, +): Promise { + const response = await client.post( + `${BASE}/documents/draft/generate`, + body, + ); + return response.data; +} + +async function getDraftGenerationStatus(crtDmndUuid: string): Promise { + const response = await client.get( + `${BASE}/documents/draft/status/${crtDmndUuid}`, + ); + return response.data; +} + +async function requestCostVerification( + body: DcRagCostVerifyRequestDto, +): Promise { + const response = await client.post(`${BASE}/documents/cost/verify`, body); + return response.data; +} + +export const dcRagApiToService = { + requestDocumentTransfer, + requestDraftGeneration, + getDraftGenerationStatus, + requestCostVerification, +} satisfies DcRagApiToService; diff --git a/apps/as/src/entities/dcrag-to/api/queries.ts b/apps/as/src/entities/dcrag-to/api/queries.ts new file mode 100644 index 000000000..4e9fc4483 --- /dev/null +++ b/apps/as/src/entities/dcrag-to/api/queries.ts @@ -0,0 +1,70 @@ +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; + +import { ENDPOINT } from "@/shared/config"; + +import type { DcRagDraftStatusResponseDto } from "../model/dcrag-to-interface"; +import type { + DcRagCostVerifyRequestDto, + DcRagDocumentTransferRequestDto, + DcRagDraftGenerateRequestDto, +} from "../model/dcrag-to-payload-schema"; + +import { dcRagApiToService } from "./dcrag-to-service"; + +export const dcRagApiToBaseKey = [ENDPOINT.AS_SERVICE.DCRAG_TO] as const; + +const DRAFT_STATUS_POLL_INTERVAL_MS = 5_000; + +function isDraftGenerationSettled(data: DcRagDraftStatusResponseDto | undefined): boolean { + if (!data) return false; + if (data.status === "COMPLETED" || data.status === "FAILED") return true; + return data.events?.some((event) => event.eventType === "COMPLETED") ?? false; +} + +export function useDraftGenerationStatus(crtDmndUuid: string | null | undefined) { + return useQuery({ + queryKey: [...dcRagApiToBaseKey, "getDraftGenerationStatus", crtDmndUuid], + queryFn: () => dcRagApiToService.getDraftGenerationStatus(crtDmndUuid!), + enabled: Boolean(crtDmndUuid), + refetchInterval: (query) => + isDraftGenerationSettled(query.state.data) ? false : DRAFT_STATUS_POLL_INTERVAL_MS, + }); +} + +export function useRequestDocumentTransfer() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (body: DcRagDocumentTransferRequestDto) => + dcRagApiToService.requestDocumentTransfer(body), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: dcRagApiToBaseKey }); + }, + }); +} + +export function useRequestDraftGeneration() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (body: DcRagDraftGenerateRequestDto) => + dcRagApiToService.requestDraftGeneration(body), + onSuccess: (_data, body) => { + queryClient.invalidateQueries({ queryKey: dcRagApiToBaseKey }); + if (body.crtDmndUuid) { + queryClient.invalidateQueries({ + queryKey: [...dcRagApiToBaseKey, "getDraftGenerationStatus", body.crtDmndUuid], + }); + } + }, + }); +} + +export function useRequestCostVerification() { + const queryClient = useQueryClient(); + return useMutation({ + mutationFn: (body: DcRagCostVerifyRequestDto) => + dcRagApiToService.requestCostVerification(body), + onSuccess: () => { + queryClient.invalidateQueries({ queryKey: dcRagApiToBaseKey }); + }, + }); +} diff --git a/apps/as/src/entities/dcrag-to/index.ts b/apps/as/src/entities/dcrag-to/index.ts new file mode 100644 index 000000000..2944e98c6 --- /dev/null +++ b/apps/as/src/entities/dcrag-to/index.ts @@ -0,0 +1,27 @@ +export { dcRagApiToService } from "./api/dcrag-to-service"; +export { dcRagApiToBaseKey } from "./api/queries"; +export { + useDraftGenerationStatus, + useRequestCostVerification, + useRequestDocumentTransfer, + useRequestDraftGeneration, +} from "./api/queries"; +export type { + DcRagApiToService, + DcRagCommonResponseDto, + DcRagDraftGenerateResponseDto, + DcRagDraftStatusResponseDto, + EventInfoDto, +} from "./model/dcrag-to-interface"; +export type { + DcRagCostVerifyRequestDto, + DcRagDocumentTransferRequestDto, + DcRagDraftGenerateRequestDto, + DcRagFileInfoDto, +} from "./model/dcrag-to-payload-schema"; +export { + dcRagCostVerifyRequestSchema, + dcRagDocumentTransferRequestSchema, + dcRagDraftGenerateRequestSchema, + dcRagFileInfoSchema, +} from "./model/dcrag-to-payload-schema"; diff --git a/apps/as/src/entities/dcrag-to/model/dcrag-to-interface.ts b/apps/as/src/entities/dcrag-to/model/dcrag-to-interface.ts new file mode 100644 index 000000000..d80f91049 --- /dev/null +++ b/apps/as/src/entities/dcrag-to/model/dcrag-to-interface.ts @@ -0,0 +1,52 @@ +import type { + DcRagCostVerifyRequestDto, + DcRagDocumentTransferRequestDto, + DcRagDraftGenerateRequestDto, +} from "./dcrag-to-payload-schema"; + +/** 백엔드 DcRagCommonResponseDto */ +export interface DcRagCommonResponseDto { + resultCode?: string; + message?: string; + requestId?: string; +} + +/** 백엔드 DcRagDraftGenerateResponseDto */ +export interface DcRagDraftGenerateResponseDto { + resultCode?: string; + message?: string; + crtDmndUuid?: string; + /** R:생성요청, I:생성중, C:생성완료, F:생성실패 */ + crtSttsComCd?: "R" | "I" | "C" | "F"; + requestId?: string; + estimatedMinutes?: number; +} + +/** 백엔드 DcRagDraftStatusResponseDto.EventInfoDto */ +export interface EventInfoDto { + eventType?: string; + eventMessage?: string; + occurredDt?: string; +} + +/** 백엔드 DcRagDraftStatusResponseDto */ +export interface DcRagDraftStatusResponseDto { + crtDmndUuid?: string; + status?: "REQUESTED" | "DOWNLOADING" | "ANALYZING" | "GENERATING" | "COMPLETED" | "FAILED"; + statusName?: string; + progressPercent?: number; + events?: EventInfoDto[]; + startedDt?: string; + estimatedCompletionDt?: string; + errorMessage?: string; +} + +/** Controller public 메서드명·시그니처와 동일 */ +export interface DcRagApiToService { + requestDocumentTransfer(body: DcRagDocumentTransferRequestDto): Promise; + requestDraftGeneration( + body: DcRagDraftGenerateRequestDto, + ): Promise; + getDraftGenerationStatus(crtDmndUuid: string): Promise; + requestCostVerification(body: DcRagCostVerifyRequestDto): Promise; +} diff --git a/apps/as/src/entities/dcrag-to/model/dcrag-to-payload-schema.ts b/apps/as/src/entities/dcrag-to/model/dcrag-to-payload-schema.ts new file mode 100644 index 000000000..7ad5827c2 --- /dev/null +++ b/apps/as/src/entities/dcrag-to/model/dcrag-to-payload-schema.ts @@ -0,0 +1,45 @@ +import { z } from "zod"; + +/** 백엔드 DcRagFileInfoDto */ +export const dcRagFileInfoSchema = z.object({ + fileId: z.string().optional(), + fileGroupId: z.string().optional(), + fileName: z.string().optional(), + physicalPath: z.string().optional(), + downloadUrl: z.string().optional(), + fileSize: z.number().optional(), + esntlAtchFileId: z.string().optional(), + esntlAtchFileNm: z.string().optional(), +}); + +/** 백엔드 DcRagDocumentTransferRequestDto */ +export const dcRagDocumentTransferRequestSchema = z.object({ + fnrsCnsltnDocNo: z.string(), + taskSeComCd: z.string().optional(), + taskSeCdNm: z.string().optional(), + essentialFiles: z.array(dcRagFileInfoSchema).optional(), + etcFiles: z.array(dcRagFileInfoSchema).optional(), + callbackUrl: z.string().optional(), +}); + +/** 백엔드 DcRagDraftGenerateRequestDto */ +export const dcRagDraftGenerateRequestSchema = z.object({ + fnrsCnsltnDocNo: z.string(), + pwrkCnsltnDocNo: z.string(), + crtDmndUuid: z.string().optional(), + essentialFiles: z.array(dcRagFileInfoSchema).optional(), + etcFiles: z.array(dcRagFileInfoSchema).optional(), + rqstrUuid: z.string().optional(), + callbackUrl: z.string().optional(), +}); + +/** 백엔드 DcRagCostVerifyRequestDto */ +export const dcRagCostVerifyRequestSchema = z.object({ + fnrsCnsltnDocNo: z.string(), + pwrkCnsltnDocNo: z.string(), +}); + +export type DcRagFileInfoDto = z.infer; +export type DcRagDocumentTransferRequestDto = z.infer; +export type DcRagDraftGenerateRequestDto = z.infer; +export type DcRagCostVerifyRequestDto = z.infer; diff --git a/apps/as/src/shared/config/api.ts b/apps/as/src/shared/config/api.ts index 3dc97907d..fcceff141 100644 --- a/apps/as/src/shared/config/api.ts +++ b/apps/as/src/shared/config/api.ts @@ -25,6 +25,7 @@ export const ENDPOINT = { DESIGN_CNSTN_RVW_OPNN: "/as-service/api/v1/design-cnstn-rvw-opnn", SEWER_BSC_PLAN: "/as-service/api/v1/sewer-bsc-plans", DASHBOARD: "/as-service/api/v1/dashboard", + DCRAG_TO: "/as-service/api/v1/dcrag-to", }, USER_SERVICE: { LOGIN: "/user-service/login",