diff --git a/apps/as/docs/pwrk-cnsltn/개발가이드.md b/apps/as/docs/pwrk-cnsltn/개발가이드.md
new file mode 100644
index 000000000..bedc4ef3b
--- /dev/null
+++ b/apps/as/docs/pwrk-cnsltn/개발가이드.md
@@ -0,0 +1,800 @@
+# 실무협의문서 개발 가이드
+
+> **대상 앱**: `frontend/apps/as`
+> **작성일**: 2026-08-27
+> **버전**: 1.0
+> **SoT (백엔드)**:
+>
+> - `PwrkCnsltnDocCrtRsltController` — `/api/v1/pwrk-cnsltn-doc-crt-rslt`
+> - `PwrkCnsltnMngController` — `/api/v1/pwrk-cnsltn-mng`
+> - `DcRagApiToController` — `/api/v1/dcrag-to`
+> - 초안생성 데이터 설명 (`02.03.초안생성_데이터_설명.md`)
+>
+> **현재 프론트 상태**: `pwrk-cnsltn-`\* 엔티티·화면 **미구현**. 재원협의(`fnrs-cnsltn`)만 존재한다.
+
+---
+
+## 1. 문서 목적
+
+재원협의 접수자가 **자료 검증 → 실무협의서 초안 생성 → 한글 웹기안기 열람/다운로드 → 편집본 버전 저장**까지 구현할 때 사용하는 프론트엔드 개발 가이드이다.
+
+백엔드 컨트롤러·DTO를 **API source of truth**로 두고, 초안생성 데이터 설명의 업무 시퀀스를 화면 동작에 매핑한다.
+
+---
+
+## 2. 도메인 개요
+
+실무협의서(PWRK)는 재원협의서(FNRS)의 **하위 문서**이다. 문서번호 규칙:
+
+| 문서 | 번호 예시 | 필드 |
+| -------- | ----------------- | ----------------------------- |
+| 재원협의 | `F-20260824-0001` | `fnrsCnsltnDocNo` / `upDocNo` |
+| 실무협의 | `P-20260827-0001` | `pwrkCnsltnDocNo` |
+
+재원협의 1건당 실무협의서는 **1건만** 생성된다. `POST /pwrk-cnsltn-mng`는 `upDocNo`로 기존 문서를 재사용하고, 없으면 문서번호를 발급한다.
+
+### 2-1. 핵심 식별자
+
+| 필드 | 의미 | 비고 |
+| ----------------- | ------------------------------ | --------------------------------------------------------- |
+| `pwrkCnsltnDocNo` | 실무협의문서번호 | 문서 PK. `P-YYYYMMDD-NNNN` |
+| `upDocNo` | 상위문서번호(재원협의) | `upDocSeComCd = "FNRS"` |
+| `crtDmndUuid` | 생성요청 UUID | 초안 생성 작업·결과·다운로드의 키 |
+| `verSn` | 버전일련번호 | 복합 PK `(crtDmndUuid, verSn)`. 저장 시 서버가 `+1` |
+| `orgnlOtptDocCn` | 원본출력문서내용(HWP 바이너리) | **목록/상세 응답에서는 항상** `null`. 다운로드 API만 제공 |
+
+### 2-2. IIPBS 약어
+
+| 한글 | 약어 | 필드 예 |
+| -------- | ------ | ----------------------------- |
+| 실무 | PWRK | `pwrkCnsltnDocNo` |
+| 협의 | CNSLTN | `pwrk-cnsltn-mng` |
+| 관리 | MNG | `PwrkCnsltnMng` |
+| 문서 | DOC | `pwrkCnsltnDocNo` |
+| 생성 | CRT | `crtDmndUuid`, `crtSttsComCd` |
+| 요청 | DMND | `crtDmndUuid` |
+| 결과 | RSLT | `crtRslt` |
+| 버전 | VER | `verSn` |
+| 일련번호 | SN | `verSn` |
+| 원본 | ORGNL | `orgnlOtptDocCn` |
+| 출력 | OTPT | `orgnlOtptDocCn` |
+| 내용 | CN | `orgnlOtptDocCn` |
+| 완료 | CMPTN | `crtCmptnDt` |
+| 일시 | DT | `crtCmptnDt` |
+| 검증 | VRFC | `vrfcSttsComCd` |
+| 전송 | TRSM | `trsmFileList` |
+| 보완 | SPLMNT | `splmntDmndList` |
+| 요청자 | RQSTR | `rqstrUuid`, `rqstrNm` |
+
+---
+
+## 3. 전체 업무 흐름
+
+재원협의 **접수자**가 실무협의서 초안을 만드는 경로이다. 프론트는 DC RAG를 직접 호출하지 않고 **as-service**만 호출한다.
+
+```mermaid
+sequenceDiagram
+ autonumber
+ participant User as 재원협의 접수자
+ participant FE as AS Frontend
+ participant AS as as-service
+ participant RAG as DC RAG
+
+ User->>FE: [자료 검증 요청]
+ FE->>AS: POST /dcrag-to/documents/transfer
{ fnrsCnsltnDocNo }
+ AS->>RAG: 자료전송 (IF-01)
+ AS-->>FE: { resultCode: SUCCESS, requestId }
+ Note over FE: 재원협의 상세 재조회
+ AS-->>FE: esntlFileList / etcFileList 에
vrfcDt, vrfcRsltCn, vrfcSttsComCd
+
+ User->>FE: [초안 생성]
+ FE->>AS: POST /pwrk-cnsltn-mng
{ upDocNo, upDocSeComCd: FNRS, prgrsSttsComCd: DV }
+ alt 실무협의서 번호 없음
+ AS->>AS: P-번호 발급 + 문서 등록
+ else 이미 존재
+ AS->>AS: 기존 pwrkCnsltnDocNo 재사용
+ end
+ AS->>RAG: 초안생성 비동기 요청 (IF-03-1)
+ AS-->>FE: 201 { pwrkCnsltnDocNo, crtDmndUuid, crtSttsComCd: R, estimatedMinutes: 10 }
+
+ loop 약 10분, status !== COMPLETED/FAILED
+ FE->>AS: GET /dcrag-to/documents/draft/status/{crtDmndUuid}
+ AS-->>FE: { status, events[], progressPercent }
+ end
+
+ Note over FE: events 에 COMPLETED 가 있으면
웹기안기 열기 / 다운로드 가능
+
+ User->>FE: [문서 열기] 또는 [다운로드]
+ FE->>AS: GET /pwrk-cnsltn-doc-crt-rslt/{crtDmndUuid}/webhwp/open
또는 /download
+
+ User->>FE: 웹기안기 편집 후 [저장]
+ FE->>AS: POST /pwrk-cnsltn-doc-crt-rslt (multipart)
crtDmndUuid + file
+ AS-->>FE: 201 { verSn: N+1, ... }
+```
+
+### 3-1. 프론트가 호출하면 안 되는 API
+
+| API | 이유 |
+| ----------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
+| `POST /dcrag-to/documents/draft/generate` | 초안 생성은 `POST /pwrk-cnsltn-mng`가 문서번호 발급 + DC RAG 호출을 **한 트랜잭션**으로 처리한다. 프론트는 관리 API만 호출한다. |
+
+---
+
+## 4. 화면 데이터 흐름
+
+초안 생성은 **재원협의 상세**에서 시작하고, 실무협의 목록/상세는 별도 화면이다.
+
+```
+BEGIN
+
+ // ===== 재원협의 상세 (기존 fnrs-cnsltn view) =====
+ CALL findById(fnrsCnsltnDocNo)
+ DISPLAY 재원협의 상세 + 필수/기타 첨부
+
+ ON [자료 검증 요청] 버튼 CLICK DO
+ CALL requestDocumentTransfer({ fnrsCnsltnDocNo })
+ CALL findById(fnrsCnsltnDocNo) // 검증결과 필드 반영
+ DISPLAY 첨부 리스트 (vrfcSttsComCd: PASS | FAIL)
+ END ON
+
+ ON [초안 생성] 버튼 CLICK DO
+ CALL pwrkCnsltnMngService.save({
+ upDocNo: fnrsCnsltnDocNo,
+ upDocSeComCd: "FNRS",
+ prgrsSttsComCd: "DV"
+ })
+ // → pwrkCnsltnDocNo, crtDmndUuid, estimatedMinutes
+ START POLL getDraftGenerationStatus(crtDmndUuid)
+ DISPLAY 초안 생성 진행률 (약 10분)
+ END ON
+
+ ON POLL status = COMPLETED 또는 events.eventType 에 COMPLETED DO
+ ENABLE [웹기안기 열기] [다운로드]
+ END ON
+
+ ON [웹기안기 열기] 버튼 CLICK DO
+ CALL HwpCtrl.Open( webhwpOpenUrl(crtDmndUuid) ) // TBD: 컨트롤러 미구현
+ END ON
+
+ ON [다운로드] 버튼 CLICK DO
+ CALL downloadLatest(crtDmndUuid) // blob + Content-Disposition
+ SAVE 로컬 파일
+ END ON
+
+ // ===== 실무협의 목록 =====
+ CALL pwrkCnsltnMngService.findPage(searchDto + pageable)
+ DISPLAY 실무협의 문서 그리드
+
+ ON 행 CLICK DO
+ NAVIGATE 실무협의 상세 (pwrkCnsltnDocNo)
+ END ON
+
+ // ===== 실무협의 상세 / 재원협의에서 연계 조회 =====
+ CALL findById(pwrkCnsltnDocNo)
+ // 또는 재원협의 번호로: findByUpDocNo(fnrsCnsltnDocNo)
+ DISPLAY 마스터 + cnsltnList + pjtcoAjmtList + crtDmndList.crtRslt
+ // crtRslt.orgnlOtptDocCn 은 항상 null — 바이너리는 download API
+
+ ON 버전 이력 조회 DO
+ CALL pwrkCnsltnDocCrtRsltService.findPage({ crtDmndUuid, sort: "verSn,desc" })
+ DISPLAY 버전 목록
+ END ON
+
+ ON 웹기안기 편집 완료 [저장] DO
+ CALL saveMultipart({ crtDmndUuid, file }) // 서버가 verSn + 1
+ INVALIDATE 상세·버전 목록
+ END ON
+
+END
+```
+
+---
+
+## 5. API 명세
+
+### 5-1. 공통
+
+| 항목 | 값 |
+| ----------- | ----------------------------------------------------------------- |
+| Gateway | `/as-service` |
+| Base prefix | `ENDPOINT.AS_SERVICE.*` (`apps/as/src/shared/config/api.ts`) |
+| Auth 헤더 | `Authorization`, `X-Site-Id`, `token-id` (기존 `client` 인터셉터) |
+| 날짜 포맷 | `yyyy-MM-dd HH:mm:ss` |
+
+추가할 ENDPOINT:
+
+```ts
+AS_SERVICE: {
+ // 기존 …
+ PWRK_CNSLTN_MNG: "/as-service/api/v1/pwrk-cnsltn-mng",
+ PWRK_CNSLTN_DOC_CRT_RSLT: "/as-service/api/v1/pwrk-cnsltn-doc-crt-rslt",
+ DCRAG_TO: "/as-service/api/v1/dcrag-to",
+}
+```
+
+---
+
+### 5-2. DC RAG 연계 (`DcRagApiToController`)
+
+프론트 엔티티 슬라이스: `entities/dcrag-to/`
+
+| 기능 | Controller | Method | URL | Request | Response |
+| ----------------- | -------------------------- | ------ | ------------------------------------------------ | --------------------------------- | ------------------------------------- |
+| 자료전송요청 | `requestDocumentTransfer` | POST | `/dcrag-to/documents/transfer` | `DcRagDocumentTransferRequestDto` | `DcRagCommonResponseDto` |
+| 초안생성 진행상태 | `getDraftGenerationStatus` | GET | `/dcrag-to/documents/draft/status/{crtDmndUuid}` | path | `DcRagDraftStatusResponseDto` |
+| 금액검증요청 | `requestCostVerification` | POST | `/dcrag-to/documents/cost/verify` | `DcRagCostVerifyRequestDto` | `DcRagCommonResponseDto` (202) |
+| 초안생성요청 | `requestDraftGeneration` | POST | `/dcrag-to/documents/draft/generate` | `DcRagDraftGenerateRequestDto` | `DcRagDraftGenerateResponseDto` (202) |
+
+**화면에서 쓰는 것**: 자료전송 + 상태 폴링 (+ 추후 금액검증).
+초안생성요청은 5-3의 `pwrkCnsltnMngService.save`로 대체한다.
+
+#### 자료전송 Request / Response
+
+```json
+POST /as-service/api/v1/dcrag-to/documents/transfer
+{ "fnrsCnsltnDocNo": "F-20260824-0001" }
+```
+
+```json
+{
+ "resultCode": "SUCCESS",
+ "message": "자료전송요청 접수 완료",
+ "requestId": "F-20260824-0001"
+}
+```
+
+자료 검증이 **완료된 뒤** 재원협의 상세를 다시 조회하면, 필수첨부(`esntlFileList`)·기타첨부(`etcFileList`) 각 파일에 검증 결과가 붙는다.
+
+| 필드 | 예 | 의미 |
+| --------------- | ----------------------------- | ------------ |
+| `vrfcDt` | `2026-08-25 18:13:49` | 검증일시 |
+| `vrfcRsltCn` | `정상 확인 (재원협의 신청서)` | 검증결과내용 |
+| `vrfcSttsComCd` | `PASS` / `FAIL` | 검증상태 |
+
+프론트 `FnrsCnsltnMngDetResponseDto` / `AtflMngClientResponseDto` / `EsntlAtchFileMngTreeResponseDto`에 위 3필드가 **아직 없다**. 재원협의 상세 첨부 영역에 배지를 그리려면 타입을 확장해야 한다.
+
+#### 초안생성 상태 폴링
+
+```http
+GET /as-service/api/v1/dcrag-to/documents/draft/status/{crtDmndUuid}
+```
+
+| 필드 | 설명 |
+| ----------------------- | --------------------------------------------------------------------------------- |
+| `status` | `REQUESTED` / `DOWNLOADING` / `ANALYZING` / `GENERATING` / `COMPLETED` / `FAILED` |
+| `statusName` | 표시명 (예: `생성 완료`) |
+| `progressPercent` | 0~100 |
+| `events[]` | `{ eventType, eventMessage, occurredDt }` |
+| `startedDt` | 시작일시 |
+| `estimatedCompletionDt` | 예상 완료일시 |
+| `errorMessage` | 실패 시 메시지 |
+
+폴링 규칙:
+
+- 주기: **5~10초** (TBD, UX 확정).
+- 예상 소요: **약 10분** (`estimatedMinutes`).
+- 종료 조건: `status === "COMPLETED"` **또는** `events`에 `eventType === "COMPLETED"`.
+- 실패: `status === "FAILED"` → 폴링 중단, `errorMessage` 표시.
+- 완료 전에는 웹기안기 열기·다운로드 버튼을 **비활성**.
+
+이벤트 순서 예시:
+
+| eventType | eventMessage |
+| ------------- | --------------------------- |
+| `REQUESTED` | 요청을 접수했습니다. |
+| `DOWNLOADING` | 신청서를 수신하는 중입니다. |
+| `ANALYZING` | 자료 준비가 완료되었습니다. |
+| `GENERATING` | 문서 저장이 완료되었습니다. |
+| `COMPLETED` | 문서 생성이 완료되었습니다. |
+
+---
+
+### 5-3. 실무협의관리 (`PwrkCnsltnMngController`)
+
+프론트 엔티티 슬라이스: `entities/pwrk-cnsltn-mng/`
+
+| 기능 | Controller | Method | URL | Request | Response |
+| ------------------- | ---------------------- | ------ | ----------------------------------------------------- | ----------------------------------- | ------------------------------------ |
+| 페이징 조회 | `findPage` | GET | `/pwrk-cnsltn-mng` | `PwrkCnsltnMngSearchDto` + Pageable | `Page` |
+| 상세 (문서번호) | `findById` | GET | `/pwrk-cnsltn-mng/{pwrkCnsltnDocNo}` | path | `PwrkCnsltnMngDetResponseDto` |
+| 상세 (재원협의번호) | `findByUpDocNo` | GET | `/pwrk-cnsltn-mng/updocno/{upDocNo}` | path | `PwrkCnsltnMngDetResponseDto` |
+| 등록 + 초안생성 | `save` | POST | `/pwrk-cnsltn-mng` | `PwrkCnsltnMngSaveRequestDto` | `PwrkCnsltnMngSaveResponseDto` (201) |
+| 신청 통합 저장 | `saveApply` | POST | `/pwrk-cnsltn-mng/save-apply` | `PwrkCnsltnApplySaveRequestDto` | `string` (문서번호, 201) |
+| 수정 | `update` | PUT | `/pwrk-cnsltn-mng/{pwrkCnsltnDocNo}` | `PwrkCnsltnMngUpdateRequestDto` | `string` |
+| 삭제 | `delete` → `remove` | DELETE | `/pwrk-cnsltn-mng/{pwrkCnsltnDocNo}` | path | 204 |
+| 보완완료 제출 | `submitSupplement` | POST | `/pwrk-cnsltn-mng/{pwrkCnsltnDocNo}/submitsupplement` | `PwrkCnsltnApplySaveRequestDto` | `string` |
+| 보완요청 등록 | `submitReqSupplement` | POST | `/pwrk-cnsltn-mng/{pwrkCnsltnDocNo}/reqsupplement` | `PwrkCnsltnApplySaveRequestDto` | `string` |
+| 진행상태 수정 | `changePrgrsSttsComCd` | POST | `/pwrk-cnsltn-mng/doc/updatePrgrsStts` | `DocPrgrsUpdateRequestDto` | 200 |
+
+목록 기본 호출:
+
+```http
+GET /as-service/api/v1/pwrk-cnsltn-mng?page=0&size=10&sort=pwrkCnsltnDocNo,desc
+```
+
+#### 초안 생성 Request / Response (`save`)
+
+```json
+POST /as-service/api/v1/pwrk-cnsltn-mng
+{
+ "upDocNo": "F-20260824-0001",
+ "upDocSeComCd": "FNRS",
+ "prgrsSttsComCd": "DV"
+}
+```
+
+```json
+{
+ "pwrkCnsltnDocNo": "P-20260826-0001",
+ "upDocNo": "F-20260824-0001",
+ "upDocSeComCd": "FNRS",
+ "prgrsSttsComCd": "DV",
+ "resultCode": "ACCEPTED",
+ "message": "초안 생성 작업이 접수되었습니다.",
+ "crtDmndUuid": "382f2821-9231-42e6-8309-4a1718a2ead8",
+ "crtSttsComCd": "R",
+ "requestId": "382f2821-9231-42e6-8309-4a1718a2ead8",
+ "estimatedMinutes": 10
+}
+```
+
+백엔드 동작 (`PwrkCnsltnMngService.save`):
+
+1. `upDocNo`로 기존 실무협의서가 있으면 **그 번호를 재사용** (재원협의 1 : 실무협의 1).
+2. 없으면 `docNoMngService.issueDocNo(PWRK)`로 `P-` 번호 발급 후 insert.
+3. DC RAG 초안생성을 비동기로 호출하고 `crtDmndUuid`를 응답에 실어 반환.
+4. DC RAG 실패 시에도 **문서는 롤백하지 않고** 로그만 남긴다. 프론트는 `resultCode`가 `ACCEPTED`/`SUCCESS`가 아니면 토스트로 실패를 알린다.
+
+#### 상세 응답 구조 (`PwrkCnsltnMngDetResponseDto`)
+
+재원협의 상세에서 `GET .../updocno/{fnrsCnsltnDocNo}`로 연계 데이터를 한 번에 가져온다.
+
+```json
+{
+ "pwrkCnsltnDocNo": "P-20260827-0001",
+ "upDocNo": "F-20260824-0001",
+ "upDocSeComCd": "FNRS",
+ "prgrsSttsComCd": "DV",
+ "cnsltnList": [],
+ "pjtcoAjmtList": [],
+ "crtDmndList": [
+ {
+ "crtDmndUuid": "d0545bef-735f-4d7b-a781-88e96e03577a",
+ "pwrkCnsltnDocNo": "P-20260827-0001",
+ "rqstrUuid": "65a00f65-8460-49af-98ec-042977e56f4b",
+ "rqstrNm": "관리자",
+ "crtSttsComCd": "C",
+ "crtRslt": {
+ "crtDmndUuid": "d0545bef-735f-4d7b-a781-88e96e03577a",
+ "verSn": 1,
+ "rgtrUuid": "...",
+ "rgtrNm": "관리자",
+ "orgnlOtptDocCn": null,
+ "crtCmptnDt": "2026-08-27 10:47:01"
+ }
+ }
+ ],
+ "splmntDmndList": [],
+ "trsmFileList": []
+}
+```
+
+`crtRslt`는 최신 버전 메타만 포함한다. `orgnlOtptDocCn`은 절대 쓰지 말고 download API를 호출한다.
+
+마스터에 재원협의 사업정보가 조인된다: `bizNm`, `admdstCd`, `envoSeComCd`, `taskSeComCd`, `aplcntNm` 등.
+
+---
+
+### 5-4. 문서생성결과 (`PwrkCnsltnDocCrtRsltController`)
+
+프론트 엔티티 슬라이스: `entities/pwrk-cnsltn-doc-crt-rslt/`
+복합 PK: `crtDmndUuid` + `verSn`
+
+| 기능 | Controller | Method | URL | Request | Response |
+| ------------------ | ------------------------- | ------ | ---------------------------------- | ----------------------------------------------- | --------------------------------------- |
+| 버전 이력 페이징 | `findPage` | GET | `/pwrk-cnsltn-doc-crt-rslt` | `PwrkCnsltnDocCrtRsltSearchDto` + Pageable | `Page` |
+| 특정 버전 상세 | `findById` | GET | `/{crtDmndUuid}/{verSn}` | path | `PwrkCnsltnDocCrtRsltResponseDto` |
+| 최신 버전 상세 | `findLatestByCrtDmndUuid` | GET | `/{crtDmndUuid}/latest` | path | `PwrkCnsltnDocCrtRsltResponseDto` |
+| 특정 버전 다운로드 | `download` | GET | `/{crtDmndUuid}/{verSn}/download` | path | `byte[]` (attachment) |
+| 최신 버전 다운로드 | `downloadLatest` | GET | `/{crtDmndUuid}/download` | path | `byte[]` (attachment) |
+| 등록 (multipart) | `saveMultipart` | POST | `/` `multipart/form-data` | `PwrkCnsltnDocCrtRsltSaveRequestDto` + `file` | `PwrkCnsltnDocCrtRsltResponseDto` (201) |
+| 등록 (JSON) | `saveJson` | POST | `/` `application/json` | `PwrkCnsltnDocCrtRsltSaveRequestDto` | 201 |
+| 수정 (multipart) | `updateMultipart` | PUT | `/{crtDmndUuid}/{verSn}` multipart | `PwrkCnsltnDocCrtRsltUpdateRequestDto` + `file` | ResponseDto |
+| 수정 (JSON) | `updateJson` | PUT | `/{crtDmndUuid}/{verSn}` json | UpdateRequestDto | ResponseDto |
+| 삭제 | `delete` → `remove` | DELETE | `/{crtDmndUuid}/{verSn}` | path | 204 |
+
+Spring 매핑 주의: `/{crtDmndUuid}/latest` 와 `/{crtDmndUuid}/download` 는 `/{crtDmndUuid}/{verSn}` 보다 **구체 경로가 우선**한다. 프론트 path를 섞지 말 것.
+
+버전 이력 조회 예:
+
+```http
+GET /as-service/api/v1/pwrk-cnsltn-doc-crt-rslt?page=0&size=10&crtDmndUuid={uuid}&sort=verSn,desc
+```
+
+#### 다운로드 (attachment)
+
+화면 [다운로드] 버튼 → PC 저장.
+
+```http
+GET /as-service/api/v1/pwrk-cnsltn-doc-crt-rslt/{crtDmndUuid}/download
+GET /as-service/api/v1/pwrk-cnsltn-doc-crt-rslt/{crtDmndUuid}/{verSn}/download
+```
+
+- axios: `responseType: "blob"`.
+- 파일명: `Content-Disposition`의 `filename*=UTF-8''...` (`parseFilenameFromResponse` 재사용).
+- 서버 파일명 규칙: `재원협의 실무협의서({bizNm})_v{verSn}.hwp`.
+- **현재 컨트롤러 Content-Type**: `application/x-hwp`.
+ 데이터 설명 예시는 `application/haansofthwpx`. 프론트는 Content-Type에 의존하지 말고 blob으로 저장한다.
+
+기존 `attachService` 다운로드와 동일 패턴:
+
+```ts
+const response = await client.get(url, { responseType: "blob" });
+const filename = parseFilenameFromResponse(response);
+const objectUrl = window.URL.createObjectURL(response.data);
+```
+
+#### 웹기안기 열기 (inline) — TBD
+
+데이터 설명 기준 엔드포인트. **현재** `PwrkCnsltnDocCrtRsltController`**에는 없음.** 백엔드 추가 후 연결한다.
+
+```http
+GET /as-service/api/v1/pwrk-cnsltn-doc-crt-rslt/{crtDmndUuid}/webhwp/open
+GET /as-service/api/v1/pwrk-cnsltn-doc-crt-rslt/{crtDmndUuid}/{verSn}/webhwp/open
+```
+
+의도:
+
+- `Content-Disposition: inline`
+- 한컴 웹기안기 `HwpCtrl.Open(url)` 이 이 URL을 직접 호출
+- 브라우저 다운로드 창이 뜨지 않고 캔버스에 로드
+
+프론트는 **blob fetch 후 Object URL을 넘기지 않는다.** 인증 헤더가 필요한 절대 URL을 기안기에 전달하는 방식이므로, 쿠키/게이트웨이 인증 가능 여부를 백엔드와 확인한다 (TBD).
+
+#### 신규 버전 등록 (웹기안기 저장)
+
+서버가 최신 `verSn + 1`을 부여한다. 클라이언트가 `verSn`을 보내지 않는다.
+
+```http
+POST /as-service/api/v1/pwrk-cnsltn-doc-crt-rslt
+Content-Type: multipart/form-data
+
+crtDmndUuid: {uuid}
+file: 재원협의 실무협의서_v2.hwpx
+```
+
+화면에서는 **multipart만** 사용한다. JSON `saveJson`은 바이너리를 body에 넣는 경로라 UI에서 쓰지 않는다.
+
+`file` part 이름: `"file"`. DTO 필드는 `@ModelAttribute` 로 평문 필드(`crtDmndUuid`) 또는 `saveDto` part.
+
+---
+
+## 6. DTO 매핑 (프론트 타입명 = 백엔드 클래스명)
+
+### 6-1. `PwrkCnsltnDocCrtRslt*`
+
+| 계층 | 파일 | 정의 |
+| ------------------------------------ | -------------------------------------------- | ----------------------------------------------- |
+| Save Request | `pwrk-cnsltn-doc-crt-rslt-payload-schema.ts` | zod SSOT → `PwrkCnsltnDocCrtRsltSaveRequestDto` |
+| Response / Search / Update / Service | `pwrk-cnsltn-doc-crt-rslt-interface.ts` | `interface` |
+
+**Response**
+
+| 필드 | 타입 | 비고 |
+| ---------------- | -------- | --------------------- |
+| `crtDmndUuid` | `string` | UUID |
+| `verSn` | `number` | BigDecimal |
+| `rgtrUuid` | `string` | |
+| `rgtrNm` | `string` | 서버 enrich |
+| `orgnlOtptDocCn` | `null` | 목록/상세 미포함 |
+| `crtCmptnDt` | `string` | `yyyy-MM-dd HH:mm:ss` |
+
+**Search** (`PageableParams` 확장)
+
+| 필드 | 비고 |
+| ----------------- | ---------------------- |
+| `crtDmndUuid` | 버전 이력 조회 시 필수 |
+| `pwrkCnsltnDocNo` | |
+| `verSn` | |
+| `rgtrUuid` | |
+
+**Save Request (zod)**
+
+| 필드 | 필수 | 비고 |
+| ------------- | ---- | ------------------------------------ |
+| `crtDmndUuid` | Y | |
+| `rgtrUuid` | N | 미전송 시 서버가 로그인 사용자 사용 |
+| `file` | UI | multipart `file` part. DTO 필드 아님 |
+
+**Update Request**
+
+| 필드 | 비고 |
+| ------------ | --------- |
+| `rgtrUuid` | |
+| `crtCmptnDt` | |
+| `file` | multipart |
+
+### 6-2. `PwrkCnsltnMng*`
+
+**Search**
+
+`pwrkCnsltnDocNo`, `upDocNo`, `upDocSeComCd`, `prgrsSttsComCd`, `admdstCd`, `envoSeComCd`, `taskSeComCd`, `bizNm`
+
+**Save Request (초안 생성)** — 필드가 얇으므로 interface만으로도 가능. 권장은 zod.
+
+| 필드 | 필수 | 값 |
+| ----------------- | ---- | ----------------- |
+| `upDocNo` | Y | 재원협의 문서번호 |
+| `upDocSeComCd` | | `"FNRS"` |
+| `prgrsSttsComCd` | | `"DV"` (초안생성) |
+| `pwrkCnsltnDocNo` | N | 서버 발급 |
+
+**Save Response** — `save`만 이 DTO. `fnrsCnsltnMngService.save`가 `string`을 반환하는 것과 **다름**.
+
+| 필드 | 의미 |
+| ------------------ | --------------------------------- |
+| `pwrkCnsltnDocNo` | 발급/재사용 번호 |
+| `resultCode` | `ACCEPTED` / `SUCCESS` / 실패코드 |
+| `crtDmndUuid` | 폴링 키 |
+| `crtSttsComCd` | `R` 생성요청 |
+| `estimatedMinutes` | 기본 10 |
+
+**DetResponse 중첩**
+
+- `cnsltnList`: 협의내역 (`rvwOpnnSn`, `rvwOpnnClsfComCd`, `cnsltnCn`, `rfltYn`, …)
+- `pjtcoAjmtList`: 사업비조정
+- `crtDmndList[].crtRslt`: 생성요청 + 최신 결과
+- `splmntDmndList`: 보완요청
+- `sttsChgHstryList`: 상태변경이력
+- `trsmFileList`: 전송파일 (데이터 설명 기준. Det DTO Java 필드 확인 후 타입 반영)
+
+### 6-3. DC RAG
+
+```ts
+interface DcRagDocumentTransferRequestDto {
+ fnrsCnsltnDocNo: string;
+ taskSeComCd?: string;
+ taskSeCdNm?: string;
+}
+
+interface DcRagCommonResponseDto {
+ resultCode: string;
+ message?: string;
+ requestId?: string;
+}
+
+interface DcRagDraftStatusResponseDto {
+ crtDmndUuid: string;
+ status: DraftStatus;
+ statusName?: string;
+ progressPercent?: number;
+ events?: EventInfoDto[];
+ startedDt?: string;
+ estimatedCompletionDt?: string;
+ errorMessage?: string | null;
+}
+
+type DraftStatus =
+ | "REQUESTED"
+ | "DOWNLOADING"
+ | "ANALYZING"
+ | "GENERATING"
+ | "COMPLETED"
+ | "FAILED";
+```
+
+---
+
+## 7. 공통코드
+
+| 상위코드 | 필드 | 값 | 명칭 |
+| ----------------------- | ---------------- | --------------- | ------------- |
+| `ASDOCSE` | `upDocSeComCd` | `FNRS` | 재원협의 |
+| `ASDOCSE` | 문서구분 | `PWRK` | 실무협의 |
+| `PWRKSTTS` | `prgrsSttsComCd` | `DV` | 초안생성 |
+| `PWRKSTTS` | | `AR` | 검토자지정 |
+| `PWRKSTTS` | | `SV` | 작성중 |
+| `PWRKSTTS` | | `RB` | 검토회신 |
+| `PWRKSTTS` | | `RC` | 협의회신 |
+| `PWRKSTTS` | | `TR` | 검토결과 회신 |
+| `PWRKSTTS` | | `SL` | 보완요청 |
+| `PWRKSTTS` | | `AA` | 금액조정중 |
+| `AICRTSTTS` / `CRTSTTS` | `crtSttsComCd` | `R` | 생성요청 |
+| | | `I` | 생성중 |
+| | | `C` | 생성완료 |
+| | | `F` | 생성실패 |
+| (검증) | `vrfcSttsComCd` | `PASS` / `FAIL` | |
+
+`CrtDmndResponseDto`는 `@CodeName(upCd = "CRTSTTS")`, 생성요청 단건 DTO는 `AICRTSTTS`를 쓴다. 코드값이 `R/I/C/F`로 같으므로 UI는 코드값으로 분기하고, 표시명은 응답의 `*Nm` 필드를 쓴다.
+
+초안 생성 직후 `crtSttsComCd = R`, 폴링 `COMPLETED` 이후 상세의 `crtSttsComCd = C`.
+
+---
+
+## 8. 프론트엔드 구현 가이드
+
+### 8-1. 기술 스택·원칙
+
+- App Router + FSD (`app/` → `pages/` → `widgets/` → `entities/` → `shared/`)
+- React Query. ad-hoc `useQuery` + service 직접 호출 금지
+- `@common/components`, `useDataTable`, `@tanstack/react-table`
+- `'use client'`는 Web API(다운로드, 폴링, 웹기안기)가 있는 페이지만
+- 함수명 = Controller public 메서드명 (`delete` → `remove`)
+- 타입명 = 백엔드 DTO명. 프론트 전용 축약 금지
+- Save/Apply Request = zod SSOT. Response는 `interface`
+
+참조 슬라이스: `entities/fnrs-cnsltn/`, `entities/sewer-bsc-plan/`
+
+### 8-2. 모듈·파일 배치
+
+| 구분 | 경로 |
+| -------------------- | ------------------------------------------------------------------- |
+| ENDPOINT | `apps/as/src/shared/config/api.ts` |
+| 실무협의 관리 엔티티 | `entities/pwrk-cnsltn-mng/` |
+| 생성결과 엔티티 | `entities/pwrk-cnsltn-doc-crt-rslt/` |
+| DC RAG 엔티티 | `entities/dcrag-to/` |
+| 목록 라우트 | `app/(main)/(with-base-layout)/pwrk-cnsltn/page.tsx` |
+| 상세 라우트 | `app/(main)/(with-base-layout)/pwrk-cnsltn/[id]/page.tsx` |
+| 페이지 UI | `pages/pwrk-cnsltn/` |
+| 재원협의 상세 연계 | `pages/fnrs-cnsltn/ui/fnrs-view-page.tsx` (버튼·폴링·첨부 검증배지) |
+
+엔티티 내부:
+
+```
+entities/pwrk-cnsltn-mng/
+├── model/
+│ ├── pwrk-cnsltn-mng-interface.ts
+│ └── pwrk-cnsltn-mng-payload-schema.ts
+├── api/
+│ ├── pwrk-cnsltn-mng-service.ts
+│ └── queries.ts
+└── index.ts
+
+entities/pwrk-cnsltn-doc-crt-rslt/
+├── model/
+│ ├── pwrk-cnsltn-doc-crt-rslt-interface.ts
+│ └── pwrk-cnsltn-doc-crt-rslt-payload-schema.ts
+├── api/
+│ ├── pwrk-cnsltn-doc-crt-rslt-service.ts
+│ └── queries.ts
+└── index.ts
+```
+
+### 8-3. Service 시그니처 요지
+
+`pwrkCnsltnMngService.save` 반환 타입이 `string`이 아니라 `PwrkCnsltnMngSaveResponseDto` 인 점을 `fnrs-cnsltn`과 혼동하지 말 것.
+
+```ts
+export interface PwrkCnsltnMngService {
+ findPage(searchDto: PwrkCnsltnMngSearchDto): Promise>;
+ findById(pwrkCnsltnDocNo: string): Promise;
+ findByUpDocNo(upDocNo: string): Promise;
+ save(body: PwrkCnsltnMngSaveRequestDto): Promise;
+ saveApply(body: PwrkCnsltnApplySaveRequestDto): Promise;
+ update(pwrkCnsltnDocNo: string, body: PwrkCnsltnMngUpdateRequestDto): Promise;
+ submitSupplement(pwrkCnsltnDocNo: string, body: PwrkCnsltnApplySaveRequestDto): Promise;
+ submitReqSupplement(
+ pwrkCnsltnDocNo: string,
+ body: PwrkCnsltnApplySaveRequestDto,
+ ): Promise;
+ remove(pwrkCnsltnDocNo: string): Promise;
+ changePrgrsSttsComCd(body: DocPrgrsUpdateRequestDto): Promise;
+}
+
+export interface PwrkCnsltnDocCrtRsltService {
+ findPage(
+ searchDto: PwrkCnsltnDocCrtRsltSearchDto,
+ ): Promise>;
+ findById(crtDmndUuid: string, verSn: number): Promise;
+ findLatestByCrtDmndUuid(crtDmndUuid: string): Promise;
+ download(crtDmndUuid: string, verSn: number): Promise>;
+ downloadLatest(crtDmndUuid: string): Promise>;
+ saveMultipart(formData: FormData): Promise;
+ updateMultipart(
+ crtDmndUuid: string,
+ verSn: number,
+ formData: FormData,
+ ): Promise;
+ remove(crtDmndUuid: string, verSn: number): Promise;
+}
+```
+
+multipart `Content-Type`은 axios가 boundary를 붙이도록 **헤더를 수동 지정하지 않는다.**
+
+### 8-4. 폴링 훅
+
+`useQuery` + `refetchInterval`:
+
+```ts
+useQuery({
+ queryKey: [...dcragToKeys.draftStatus(crtDmndUuid)],
+ queryFn: () => dcragToService.getDraftGenerationStatus(crtDmndUuid),
+ enabled: Boolean(crtDmndUuid) && isPolling,
+ refetchInterval: (query) => {
+ const status = query.state.data?.status;
+ if (status === "COMPLETED" || status === "FAILED") return false;
+ return 5_000;
+ },
+});
+```
+
+`COMPLETED` 시 `pwrkCnsltnMng` 상세 쿼리를 invalidate 하여 `crtDmndList[].crtRslt`를 갱신한다.
+
+### 8-5. 재원협의 상세에 붙일 UI
+
+`pages/fnrs-cnsltn` 조회 모드:
+
+1. **자료 검증 요청** — `requestDocumentTransfer` → 상세 refetch → 첨부 행에 PASS/FAIL 배지 (`vrfcSttsComCd`, `vrfcRsltCn`, `vrfcDt`).
+2. **초안 생성** — 검증이 끝난 뒤 활성. `pwrkCnsltnMngService.save`.
+3. **진행 표시** — `progressPercent` + 이벤트 타임라인. `estimatedMinutes`(10)를 안내.
+4. **웹기안기 열기 / 다운로드** — `COMPLETED` 이후에만.
+
+`findByUpDocNo(fnrsCnsltnDocNo)`로 이미 초안이 있으면 `crtDmndUuid`를 복원해 폴링·열기를 이어간다.
+
+### 8-6. 실무협의 목록 컬럼 (권장)
+
+마스터 응답 + 재원협의 조인 필드 기준. 화면설계 확정 전 TBD.
+
+| 표시명 | Field |
+| ------------ | ------------------ |
+| 실무협의번호 | `pwrkCnsltnDocNo` |
+| 재원협의번호 | `upDocNo` |
+| 진행상태 | `prgrsSttsComCdNm` |
+| 사업명 | `bizNm` |
+| 시도/구군 | `sido` / `gugun` |
+| 신청자 | `aplcntNm` |
+| 등록일 | `regDt` |
+
+행 클릭 → `/pwrk-cnsltn/{pwrkCnsltnDocNo}`.
+
+---
+
+## 9. 구현 순서
+
+```
+Task Progress:
+- [ ] 1. ENDPOINT 3개 추가 (PWRK_CNSLTN_MNG, PWRK_CNSLTN_DOC_CRT_RSLT, DCRAG_TO)
+- [ ] 2. entities/dcrag-to (transfer + draft status)
+- [ ] 3. entities/pwrk-cnsltn-mng (findPage, findById, findByUpDocNo, save)
+- [ ] 4. entities/pwrk-cnsltn-doc-crt-rslt (findPage, downloadLatest, saveMultipart)
+- [ ] 5. 재원협의 상세: 검증결과 3필드 타입 확장 + 배지
+- [ ] 6. 재원협의 상세: 자료검증 / 초안생성 / 폴링 UI
+- [ ] 7. 실무협의 목록·상세 라우트
+- [ ] 8. 다운로드 (blob)
+- [ ] 9. 웹기안기 Open — 백엔드 webhwp/open 확인 후
+- [ ] 10. 웹기안기 저장 → saveMultipart (verSn + 1)
+```
+
+1~4는 엔티티 레이어만으로 먼저 닫는다. 화면은 5부터.
+
+---
+
+## 10. TBD · 백엔드 확인
+
+| 항목 | 내용 |
+| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
+| `webhwp/open` | 데이터 설명에는 있으나 **현재 Controller에 없음**. 추가 일정·인증 방식 확인 |
+| Content-Type | Controller `application/x-hwp` vs 설명 `application/haansofthwpx` |
+| 파일 확장자 | 다운로드 파일명이 `.hwp`로 고정. 실제 바이너리가 hwpx일 수 있음 |
+| 폴링 주기 | 5초 vs 10초, 탭 비활성 시 중단 여부 |
+| 검증 필드 타입 | `FnrsCnsltnMngDetResponseDto.esntlFileList` / `etcFileList` Java 타입이 아직 `FnrsCnsltnAtflResponseDto`가 아님. 런타임 JSON에 `vrfc*`가 오는지 확인 |
+| `trsmFileList` | 데이터 설명 상세 예시에는 있으나 Det DTO Java 선언과 불일치 가능 |
+| `crtSttsComCd` 상위코드 | `CRTSTTS` vs `AICRTSTTS` |
+| 웹기안기 라이선스 URL | `HwpCtrl.Open`에 넘길 게이트웨이 절대 경로 (쿠키 인증 가능 여부) |
+| 초안 생성 1회 제한 | `requestDraftGeneration` 주석에 “1회 제한”. 재클릭 UX (비활성 / 재요청 확인) |
+| 자료전송 허용 확장자 | `.doc .docx .hwp .hwpx .md .pdf .txt .xls .xlsm .xlsx`. 이미지 첨부 시 DC RAG 실패 |
+
+---
+
+## 11. 참고
+
+| 자료 | 위치 |
+| ---------------------- | ------------------------------------------------------------------------------ |
+| 생성결과 컨트롤러 | `backend/.../pwrkcnsltndoccrtrslt/PwrkCnsltnDocCrtRsltController.java` |
+| 실무협의관리 컨트롤러 | `backend/.../pwrkcnsltnmng/PwrkCnsltnMngController.java` |
+| DC RAG TO 컨트롤러 | `backend/.../dcrag/DcRagApiToController.java` |
+| 초안생성 데이터 설명 | `02.03.초안생성_데이터_설명.md` |
+| 엔티티 구현 스킬 | `frontend/.cursor/skills/backend-controller-to-entity/` |
+| 재원협의 엔티티 (패턴) | `apps/as/src/entities/fnrs-cnsltn/` |
+| IIPBS 단어목록 | `frontend/docs/IIPBS_단어목록.md` |
+| 진행상태 코드 | `backend/IIPBS_CS/docs/2026/05.행정지원/01.문서상태별_사용자_상태변경_이력.md` |