"""설계서 구성표 — **법이 정한 목차와 우리가 내는 것을 맞대 보는 표** (2026-09-09). **왜 있나** — 「무엇을 내야 하나」가 법에 목록으로 박혀 있는데, 우리가 그중 무엇을 내고 무엇을 못 내는지가 **계획서에만** 있었다. 설계서를 묶는 사람이 화면에서 바로 봐야 한다. 산림자원법 시행규칙 [별표2] (5)(가) 「설계서는 **목차·공사설명서·일반시방서·특별시방서·예정공정표·예산내역서·일위대가표· 단가산출서·각종중기경비계산서·공종별 수량계산서·각종 소요자재총괄표·토적표·산출기초** 순으로 작성한다」 ⚠ **법이 목차를 정했다고 그 열셋을 다 프로그램이 만들 것은 아니다.** 시방서·예정공정표는 **설계자·발주청이 쓰는 문서**다. 그래서 줄마다 「누가 만드나」를 함께 적는다 — 못 내는 것과 **애초에 우리 몫이 아닌 것**을 갈라야 다음에 할 일이 달라진다. ⚠ **사방사업은 목록이 다르다** — 사방사업법 시행규칙 [별표0] 은 **위치도·관계지적조서· 공사원가계산서·설계도면**을 더 두고 예산내역서 대신 「설계내역서」라 적는다. 지금 이 표는 **임도(별표2)** 기준이다. """ from __future__ import annotations from typing import Any #: 상태 — 세 갈래. 「없음」과 「우리 몫 아님」을 **갈라 적는다.** STATUS_READY = "있음" STATUS_PARTIAL = "반쪽" STATUS_MISSING = "없음" OWNER_PROGRAM = "프로그램" OWNER_DESIGNER = "설계자·발주청" LAW_SOURCE = ( "산림자원의 조성 및 관리에 관한 법률 시행규칙 [별표2] 산림관리기반시설의 설계 및 시설기준" " (5)(가) — 설계서 작성 순서" ) #: 별표2 가 적은 **그 차례 그대로**. 순서를 바꾸지 않는다(법이 순서를 정한 목록이다). DESIGN_DOC_ITEMS: tuple[dict[str, Any], ...] = ( { "order": 1, "name": "목차", "status": STATUS_READY, "owner": OWNER_PROGRAM, "where": "이 표(설계서 구성)", "note": "법이 정한 차례대로 무엇이 서고 무엇이 안 서는지를 이 표가 그대로 보인다.", }, { "order": 2, "name": "공사설명서", "status": STATUS_MISSING, "owner": OWNER_PROGRAM, "where": "", "note": ( "값은 거의 다 우리가 갖고 있다 — 공사명·총공사비(원가계산서) · 유효폭·노견·설계속도·" "종단구배·최소곡선반경(설계 기준). 받아야 할 것은 서식과 설계하중 표기" "(실무 거창은 「DB-18(32.45T)」로 적었는데 우리 값이 아니다)." ), }, { "order": 3, "name": "일반시방서", "status": STATUS_MISSING, "owner": OWNER_DESIGNER, "where": "", "note": ( "표준시방서를 인용하는 문서다 — 프로그램이 지어낼 것이 아니다. " "원문도 아직 안 갖고 있다(실무 자료에 「임도시설공사 표준시방서」가 있으나 미보유)." ), }, { "order": 4, "name": "특별시방서", "status": STATUS_MISSING, "owner": OWNER_DESIGNER, "where": "", "note": "그 현장의 특기사항을 설계자가 쓴다 — 현장을 아는 사람만 쓸 수 있는 문서다.", }, { "order": 5, "name": "예정공정표", "status": STATUS_MISSING, "owner": OWNER_DESIGNER, "where": "", "note": ( "공기를 공종에 어떻게 나누는지는 설계 판단이다. 우리는 공사기간(일)만 받아 " "요율 구간에 쓴다 — 그것으로 공정표를 지어내지 않는다." ), }, { "order": 6, "name": "예산내역서", "status": STATUS_READY, "owner": OWNER_PROGRAM, "where": "원가계산 → 설계내역서", "note": "", }, { "order": 7, "name": "일위대가표", "status": STATUS_READY, "owner": OWNER_PROGRAM, "where": "원가계산 → 일위대가", "note": "", }, { "order": 8, "name": "단가산출서", "status": STATUS_READY, "owner": OWNER_PROGRAM, "where": "원가계산 → 단가산출근거", "note": "", }, { "order": 9, "name": "각종 중기경비계산서", "status": STATUS_PARTIAL, "owner": OWNER_PROGRAM, "where": "원가계산 → 중기(중기목록표)", "note": ( "기종별 시간당 사용료 3분할은 서 있고 줄을 누르면 무엇으로 이루어졌는지 " "파고들 수 있다. ⚠ 다만 실무 서식의 기종마다 한 장짜리 계산서" "(취득가·손료계수·상각비·정비비·관리비 + 운전경비 + 수송비)는 아직 없다." ), }, { "order": 10, "name": "공종별 수량계산서", "status": STATUS_READY, "owner": OWNER_PROGRAM, "where": "수량산출 → 토공집계·구조물 원단위", "note": "", }, { "order": 11, "name": "각종 소요자재총괄표", "status": STATUS_READY, "owner": OWNER_PROGRAM, "where": "수량산출 → 자재총괄", "note": "", }, { "order": 12, "name": "토적표", "status": STATUS_READY, "owner": OWNER_PROGRAM, "where": "수량산출 → 토적표", "note": "", }, { "order": 13, "name": "산출기초", "status": STATUS_PARTIAL, "owner": OWNER_PROGRAM, "where": "각 줄의 산출근거 문구", "note": ( "줄마다 어디서 온 값인지는 적혀 있으나 별도의 장으로 묶여 있지 않다 — " "설계서로 묶으려면 그 문구들을 한 장으로 모으는 자리가 필요하다." ), }, ) def design_doc_index() -> dict[str, Any]: """설계서 구성표 한 장 — 법 순서·상태·누가 만드나·어디서 나오나.""" counts = {STATUS_READY: 0, STATUS_PARTIAL: 0, STATUS_MISSING: 0} for item in DESIGN_DOC_ITEMS: counts[item["status"]] += 1 ours_missing = [ item["name"] for item in DESIGN_DOC_ITEMS if item["owner"] == OWNER_PROGRAM and item["status"] != STATUS_READY ] theirs = [item["name"] for item in DESIGN_DOC_ITEMS if item["owner"] == OWNER_DESIGNER] return { "law": LAW_SOURCE, "items": [dict(item) for item in DESIGN_DOC_ITEMS], "counts": counts, "summary": ( f"법이 정한 {len(DESIGN_DOC_ITEMS)} 가운데 {counts[STATUS_READY]} 이 서 있고," f" {len(theirs)} 은 설계자·발주청이 쓰는 문서이며," f" 우리가 더 내야 할 것은 {len(ours_missing)} 입니다" + (f" — {' · '.join(ours_missing)}." if ours_missing else ".") ), "notes": [ "⚠ 법이 목차를 정했다고 열셋을 다 프로그램이 만들 것은 아닙니다 —" " 시방서·예정공정표는 현장을 아는 사람이 쓰는 문서입니다.", "⚠ 사방사업은 목록이 다릅니다 — 사방사업법 [별표0] 은 위치도·관계지적조서·" "공사원가계산서·설계도면을 더 둡니다. 이 표는 임도(별표2) 기준입니다.", ], }