diff --git a/A00_Common/main.ts b/A00_Common/main.ts index 8f218420..26d914b8 100644 --- a/A00_Common/main.ts +++ b/A00_Common/main.ts @@ -26,6 +26,7 @@ const FOOTERLESS_ROUTES: readonly RoutePath[] = [ ROUTES.B09_ESTIMATION, ROUTES.B10_PAYMENT, ROUTES.B11_STATUS, + ROUTES.Z01_MASTER_DATA, ]; function bootstrap(): void { diff --git a/A00_Common/router.ts b/A00_Common/router.ts index a3c56318..b6c99652 100644 --- a/A00_Common/router.ts +++ b/A00_Common/router.ts @@ -59,6 +59,8 @@ const routeTable: Partial Promise>> = { (await import("../B11_Status/B11_Status_UI_Page")).renderB11Status, [ROUTES.B11_LOADING]: async () => (await import("../B11_Status/B11_Status_UI_Loading")).renderB11Loading, + [ROUTES.Z01_MASTER_DATA]: async () => + (await import("../Z01_MasterData/Z01_MasterData_UI_Page")).renderZ01MasterData, }; /** 로그인 여부 (토큰 존재 확인) */ diff --git a/B01_Dashboard/B01_Dashboard_UI_Page.ts b/B01_Dashboard/B01_Dashboard_UI_Page.ts index 6b445015..9f675b88 100644 --- a/B01_Dashboard/B01_Dashboard_UI_Page.ts +++ b/B01_Dashboard/B01_Dashboard_UI_Page.ts @@ -130,6 +130,19 @@ async function loadRoleData(state: DashboardState): Promise { } } +function buildSystemSettingsPanel(): HTMLElement { + const wrap = document.createElement("div"); + wrap.className = "b01-dashboard__actions"; + wrap.append( + createButton({ + label: L("B01_Dashboard_MasterData"), + variant: "ghost", + onClick: () => navigateTo(ROUTES.Z01_MASTER_DATA), + }), + ); + return wrap; +} + function buildPage(state: DashboardState): HTMLElement { // 제목·여백은 공용 템플릿을 따른다 (2026-09-06 사용자 지시) — B02 등 다른 화면과 같은 모양. const page = document.createElement("div"); @@ -138,8 +151,15 @@ function buildPage(state: DashboardState): HTMLElement { grid.className = "b01-dashboard__grid"; if (state.user.role === "SYSTEM_ADMIN") { + // 리소스 현황 오른쪽에 시스템 설정 — 앞으로 다른 설정 단추도 이 칸에 듦 (2026-09-15 브레인 Z01). + const topRow = document.createElement("div"); + topRow.className = "b01-dashboard__top-row"; + topRow.append( + section(L("B01_Dashboard_Resources"), buildResourcePanel(state.resources)), + section(L("B01_Dashboard_SystemSettings"), buildSystemSettingsPanel()), + ); grid.append( - section(L("B01_Dashboard_Resources"), buildResourcePanel(state.resources), true), + topRow, section(L("B01_Dashboard_Projects"), projectTable(state.allProjects, state.user), true, [ createButton({ label: "+", onClick: () => navigateTo(ROUTES.B02_PROJ_REGISTER) }), ]), diff --git a/B01_Dashboard/B01_Dashboard_UI_Style.css b/B01_Dashboard/B01_Dashboard_UI_Style.css index 35f94502..ceab81c6 100644 --- a/B01_Dashboard/B01_Dashboard_UI_Style.css +++ b/B01_Dashboard/B01_Dashboard_UI_Style.css @@ -31,6 +31,14 @@ grid-column: 1 / -1; } +/* 리소스 현황 | 시스템 설정 — 설정 칸은 단추만 들어 좁게. */ +.b01-dashboard__top-row { + grid-column: 1 / -1; + display: grid; + grid-template-columns: minmax(0, 3fr) minmax(0, 1fr); + gap: var(--spacing-24); +} + .b01-dashboard__actions { display: flex; flex-wrap: wrap; @@ -280,7 +288,8 @@ @media (max-width: 860px) { .b01-dashboard__header, - .b01-dashboard__grid { + .b01-dashboard__grid, + .b01-dashboard__top-row { display: block; } diff --git a/Z01_MasterData/Z01_MasterData_Api_Fetch.ts b/Z01_MasterData/Z01_MasterData_Api_Fetch.ts new file mode 100644 index 00000000..ca287649 --- /dev/null +++ b/Z01_MasterData/Z01_MasterData_Api_Fetch.ts @@ -0,0 +1,63 @@ +/* ============================================================================= + * Z01_MasterData_Api_Fetch.ts + * 마스터 데이터 읽기 — 서버 `Z01_MasterData_Router.py`(랩탑 메인) · 시스템 관리자만 + * + * 응답 모양은 2026-09-15 브레인이 못박은 약속 그대로. 읽기 전용 — 고치기는 다음 차례. + * ========================================================================== */ + +import { API_BASE_URL } from "@config/config_frontend"; +import type { MasterColumn } from "./Z01_MasterData_UI_Cells"; + +export interface MasterTable { + id: string; + label: string; + key: string; + row_count: number; +} + +export interface MasterFile { + id: string; + label: string; + key: string; + tables: MasterTable[]; +} + +export interface MasterGroup { + key: "logic" | "base" | "byproduct" | "seed"; + label: string; + files: MasterFile[]; +} + +export interface MasterRows { + columns: MasterColumn[]; + rows: Record[]; + total: number; +} + +async function request(path: string): Promise { + const response = await fetch(`${API_BASE_URL}${path}`, { credentials: "include" }); + const data = (await response.json()) as { detail?: string } & T; + if (!response.ok) throw new Error(data.detail ?? "Request failed"); + return data; +} + +export async function fetchMasterTree(): Promise { + return (await request<{ groups: MasterGroup[] }>("/master-data/tree")).groups; +} + +export function fetchMasterRows(query: { + file: string; + table: string; + page: number; + size: number; + q: string; +}): Promise { + const params = new URLSearchParams({ + file: query.file, + table: query.table, + page: String(query.page), + size: String(query.size), + q: query.q, + }); + return request(`/master-data/rows?${params}`); +} diff --git a/Z01_MasterData/Z01_MasterData_UI_Cells.ts b/Z01_MasterData/Z01_MasterData_UI_Cells.ts new file mode 100644 index 00000000..7669fe5e --- /dev/null +++ b/Z01_MasterData/Z01_MasterData_UI_Cells.ts @@ -0,0 +1,38 @@ +/* ============================================================================= + * Z01_MasterData_UI_Cells.ts + * 마스터 표 칸 글자 — 숨김 열 · 열 제목 · 칸 값 · 쪽 수 (import 없음 · 시험이 그대로 돌림) + * + * 한글 이름은 API 가 `label` 로 줌(이름표 파일 `resources/data_master_labels/`) — 화면은 + * 사전을 두지 않고 받은 대로 보임. 두 벌이 되면 어긋나기 때문(2026-09-15 브레인 Z01 ①). + * ========================================================================== */ + +export interface MasterColumn { + key: string; + label: string; + unit?: string | null; + /** 내부 id · sha · 생성시각 — 기본으로 안 보임 */ + hidden?: boolean; +} + +export function shownColumns(columns: MasterColumn[], showHidden: boolean): MasterColumn[] { + return showHidden ? columns : columns.filter((column) => !column.hidden); +} + +export function columnTitle(column: MasterColumn): string { + return column.unit ? `${column.label} (${column.unit})` : column.label; +} + +/** 단위가 붙은 수만 쉼표 — 연도·코드 같은 수(단위 없음)에 쉼표가 끼면 틀린 값처럼 보임. */ +export function cellText(value: unknown, unit?: string | null): string { + if (value === null || value === undefined) return ""; + if (typeof value === "boolean") return value ? "예" : "아니오"; + if (typeof value === "number" && unit) { + return value.toLocaleString("ko-KR", { maximumFractionDigits: 10 }); + } + if (typeof value === "object") return JSON.stringify(value); + return String(value); +} + +export function pageCount(total: number, size: number): number { + return Math.max(1, Math.ceil(total / size)); +} diff --git a/Z01_MasterData/Z01_MasterData_UI_Page.ts b/Z01_MasterData/Z01_MasterData_UI_Page.ts new file mode 100644 index 00000000..7d8fd84c --- /dev/null +++ b/Z01_MasterData/Z01_MasterData_UI_Page.ts @@ -0,0 +1,266 @@ +/* ============================================================================= + * Z01_MasterData_UI_Page.ts + * 마스터 데이터 — 좌 트리(갈래 → 파일 → 표) / 우 고른 표의 실제 줄(쪽 나누기 · 검색) + * + * 시스템 관리자만(서버도 require_system_admin 으로 다시 막음) · 읽기 전용부터 + * (2026-09-15 브레인 Z01 — 마스터를 사람이 보고 고칠 수 있게 먼저 만들고 그 위에 일위대가 재조립). + * ========================================================================== */ + +import { ROUTES } from "@config/config_frontend"; +import { + createButton, + createInputField, + el, + hideLoadingOverlay, + showLoadingOverlay, + showToast, +} from "@ui/ui_template_elements"; +import { createGeneralLayout } from "@ui/ui_template_general_layout"; +import { t as L } from "@ui/ui_template_locale"; +import { navigateTo } from "../A00_Common/router"; +import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch"; +import { + fetchMasterRows, + fetchMasterTree, + type MasterFile, + type MasterGroup, + type MasterRows, + type MasterTable, +} from "./Z01_MasterData_Api_Fetch"; +import { cellText, columnTitle, pageCount, shownColumns } from "./Z01_MasterData_UI_Cells"; +import "./Z01_MasterData_UI_Style.css"; + +const PAGE_SIZE = 50; +const SEARCH_DELAY_MS = 300; + +export async function renderZ01MasterData(root: HTMLElement): Promise { + const user = await fetchSessionUser().catch(() => null); + if (user?.role !== "SYSTEM_ADMIN") { + showToast(L("Z01_MasterData_AdminOnly"), "error"); + navigateTo(ROUTES.B01_ACCOUNT); + return; + } + showLoadingOverlay(); + let groups: MasterGroup[] = []; + try { + groups = await fetchMasterTree(); + } catch (error) { + showToast(error instanceof Error ? error.message : L("Z01_MasterData_LoadFailed"), "error"); + } finally { + hideLoadingOverlay(); + } + root.innerHTML = ""; + root.append(buildPage(groups)); +} + +function buildPage(groups: MasterGroup[]): HTMLElement { + const view = buildRowsView(); + const tree = buildTree(groups, view.pick); + const content = el("div", { className: "z01-master__content", children: [tree, view.root] }); + return createGeneralLayout({ + pageClass: "z01-master", + title: L("Z01_MasterData_Title"), + subtitle: L("Z01_MasterData_Subtitle"), + content, + }).root; +} + +function buildTree( + groups: MasterGroup[], + pick: (file: MasterFile, table: MasterTable) => void, +): HTMLElement { + const nav = el("nav", { className: "z01-master__tree" }); + for (const group of groups) { + const groupBox = folder("z01-master__group", group.label, String(group.files.length)); + groupBox.open = true; + // 부산물은 계산이 남긴 기록 — 고칠 정본이 아님(2026-09-15 브레인 갈래 나눔표). + if (group.key === "byproduct") { + groupBox.append( + el("p", { className: "z01-master__note", text: L("Z01_MasterData_Byproduct") }), + ); + } + for (const file of group.files) { + const fileBox = folder( + "z01-master__file", + file.label, + file.label === file.key ? "" : file.key, + ); + for (const table of file.tables) { + const button = el("button", { + className: "z01-master__table", + attrs: { type: "button", title: table.key }, + children: [ + el("span", { text: table.label }), + el("span", { + className: "z01-master__key", + text: table.row_count.toLocaleString("ko-KR"), + }), + ], + }); + button.addEventListener("click", () => { + nav.querySelector(".z01-master__table.is-active")?.classList.remove("is-active"); + button.classList.add("is-active"); + pick(file, table); + }); + fileBox.append(button); + } + groupBox.append(fileBox); + } + nav.append(groupBox); + } + return nav; +} + +/** 접는 칸 — 브라우저 기본
로 둠. */ +function folder(className: string, label: string, aside: string): HTMLDetailsElement { + const summary = el("summary", { + children: [ + el("span", { text: label }), + el("span", { className: "z01-master__key", text: aside }), + ], + }); + return el("details", { className, children: [summary] }); +} + +interface RowsView { + root: HTMLElement; + pick: (file: MasterFile, table: MasterTable) => void; +} + +function buildRowsView(): RowsView { + const state = { + file: null as MasterFile | null, + table: null as MasterTable | null, + page: 1, + q: "", + }; + let showHidden = false; + let last: MasterRows | null = null; + let requestSeq = 0; + let searchTimer = 0; + + const title = el("h2", { className: "z01-master__title", text: L("Z01_MasterData_PickTable") }); + const titleKey = el("span", { className: "z01-master__key" }); + const search = createInputField({ + type: "search", + placeholder: L("Z01_MasterData_Search"), + onInput: (value) => { + window.clearTimeout(searchTimer); + searchTimer = window.setTimeout(() => { + state.q = value.trim(); + state.page = 1; + void load(); + }, SEARCH_DELAY_MS); + }, + }); + const hiddenToggle = el("input", { attrs: { type: "checkbox" } }); + hiddenToggle.addEventListener("change", () => { + showHidden = hiddenToggle.checked; + draw(); + }); + const hiddenLabel = el("label", { + className: "z01-master__check", + children: [hiddenToggle, L("Z01_MasterData_ShowHidden")], + }); + const grid = el("div", { className: "z01-master__grid-wrap" }); + const pageInfo = el("span", { className: "z01-master__page-info" }); + const prev = createButton({ + label: L("Z01_MasterData_Prev"), + variant: "ghost", + onClick: () => turn(-1), + }); + const next = createButton({ + label: L("Z01_MasterData_Next"), + variant: "ghost", + onClick: () => turn(1), + }); + const toolbar = el("div", { + className: "z01-master__toolbar", + children: [search.root, hiddenLabel], + }); + const pager = el("div", { className: "z01-master__pager", children: [prev, pageInfo, next] }); + const root = el("section", { + className: "z01-master__panel", + children: [el("div", { children: [title, titleKey] }), toolbar, grid, pager], + }); + toolbar.hidden = true; + pager.hidden = true; + + function turn(step: number): void { + state.page += step; + void load(); + } + + async function load(): Promise { + if (!state.file || !state.table) return; + const mine = ++requestSeq; + grid.classList.add("is-loading"); + try { + const data = await fetchMasterRows({ + file: state.file.id, + table: state.table.id, + page: state.page, + size: PAGE_SIZE, + q: state.q, + }); + if (mine !== requestSeq) return; + last = data; + draw(); + } catch (error) { + if (mine === requestSeq) { + showToast(error instanceof Error ? error.message : L("Z01_MasterData_LoadFailed"), "error"); + } + } finally { + if (mine === requestSeq) grid.classList.remove("is-loading"); + } + } + + function draw(): void { + if (!last) return; + const columns = shownColumns(last.columns, showHidden); + const headRow = el("tr"); + for (const column of columns) { + const th = el("th", { children: [el("span", { text: columnTitle(column) })] }); + if (column.label !== column.key) { + th.append(el("span", { className: "z01-master__key", text: column.key })); + } + headRow.append(th); + } + const body = el("tbody"); + for (const row of last.rows) { + const tr = el("tr"); + for (const column of columns) { + const text = cellText(row[column.key], column.unit); + tr.append(el("td", { text, attrs: { title: text } })); + } + body.append(tr); + } + grid.replaceChildren( + last.rows.length + ? el("table", { + className: "z01-master__grid", + children: [el("thead", { children: [headRow] }), body], + }) + : el("p", { className: "z01-master__note", text: L("Z01_MasterData_NoRows") }), + ); + const pages = pageCount(last.total, PAGE_SIZE); + pageInfo.textContent = `${state.page} / ${pages} ${L("Z01_MasterData_Page")} · ${last.total.toLocaleString("ko-KR")} ${L("Z01_MasterData_Rows")}`; + prev.disabled = state.page <= 1; + next.disabled = state.page >= pages; + } + + function pick(file: MasterFile, table: MasterTable): void { + state.file = file; + state.table = table; + state.page = 1; + title.textContent = `${file.label} › ${table.label}`; + titleKey.textContent = `${file.key} / ${table.key}`; + toolbar.hidden = false; + pager.hidden = false; + last = null; + grid.replaceChildren(); + void load(); + } + + return { root, pick }; +} diff --git a/Z01_MasterData/Z01_MasterData_UI_Style.css b/Z01_MasterData/Z01_MasterData_UI_Style.css new file mode 100644 index 00000000..7a37171a --- /dev/null +++ b/Z01_MasterData/Z01_MasterData_UI_Style.css @@ -0,0 +1,167 @@ +/* Z01 마스터 데이터 — 좌 트리 / 우 표 */ +.z01-master [hidden] { + display: none !important; +} + +.z01-master__content { + display: grid; + grid-template-columns: minmax(220px, 300px) minmax(0, 1fr); + gap: var(--spacing-24); + align-items: start; +} + +.z01-master__tree { + position: sticky; + top: var(--spacing-16); + max-height: calc(100vh - 160px); + overflow-y: auto; + padding: var(--spacing-8); + border: 1px solid var(--color-border); + border-radius: var(--radius-cards); + background: var(--color-surface); + font-size: var(--text-body-sm); +} + +.z01-master__tree summary { + display: flex; + justify-content: space-between; + gap: var(--spacing-8); + padding: var(--spacing-4) var(--spacing-8); + cursor: pointer; + color: var(--color-text-body); +} + +.z01-master__group > summary { + font-weight: var(--font-weight-bold); + color: var(--color-text); +} + +.z01-master__file { + margin-left: var(--spacing-12); +} + +.z01-master__key { + margin-left: var(--spacing-4); + color: var(--color-text-muted); + font-size: var(--text-caption); + font-weight: var(--font-weight-regular); +} + +.z01-master__note { + margin: 0 var(--spacing-8) var(--spacing-4); + color: var(--color-text-muted); + font-size: var(--text-caption); +} + +.z01-master__table { + display: flex; + justify-content: space-between; + gap: var(--spacing-8); + width: 100%; + padding: var(--spacing-4) var(--spacing-8) var(--spacing-4) var(--spacing-24); + border: 0; + border-radius: var(--radius-sm); + background: transparent; + color: var(--color-text-body); + font: inherit; + text-align: left; + cursor: pointer; +} + +.z01-master__table:hover { + background: var(--color-surface-raised); +} + +.z01-master__table.is-active { + background: var(--color-mist-violet); + color: var(--color-accent); +} + +.z01-master__panel { + display: flex; + flex-direction: column; + gap: var(--spacing-16); + min-width: 0; +} + +.z01-master__title { + display: inline; + color: var(--color-text); + font-size: var(--text-body); +} + +.z01-master__toolbar { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: var(--spacing-16); +} + +.z01-master__check { + display: flex; + align-items: center; + gap: var(--spacing-4); + color: var(--color-text-secondary); + font-size: var(--text-body-sm); +} + +.z01-master__grid-wrap { + max-height: calc(100vh - 300px); + overflow: auto; + border: 1px solid var(--color-border); + border-radius: var(--radius-cards); +} + +.z01-master__grid-wrap.is-loading { + opacity: 0.5; +} + +.z01-master__grid { + border-collapse: collapse; + font-size: var(--text-body-sm); +} + +.z01-master__grid th, +.z01-master__grid td { + max-width: 320px; + padding: var(--spacing-8) var(--spacing-12); + overflow: hidden; + border-bottom: 1px solid var(--color-border); + text-align: left; + text-overflow: ellipsis; + white-space: nowrap; +} + +.z01-master__grid th { + position: sticky; + top: 0; + z-index: 1; + background: var(--color-surface); + color: var(--color-text-secondary); + font-weight: var(--font-weight-medium); +} + +.z01-master__grid th .z01-master__key { + display: block; + margin-left: 0; +} + +.z01-master__pager { + display: flex; + align-items: center; + justify-content: flex-end; + gap: var(--spacing-12); + color: var(--color-text-secondary); + font-size: var(--text-body-sm); +} + +@media (max-width: 860px) { + .z01-master__content { + display: block; + } + + .z01-master__tree { + position: static; + margin-bottom: var(--spacing-24); + } +} diff --git a/config/config_frontend.ts b/config/config_frontend.ts index bdd275a1..277a9238 100644 --- a/config/config_frontend.ts +++ b/config/config_frontend.ts @@ -116,6 +116,8 @@ export const ROUTES = { B11_STATUS: "b11-status", // 대시보드에서 B그룹으로 처음 들어갈 때 3D·등고선을 미리 받아 두는 준비 화면. B11_LOADING: "b11-loading", + // 시스템 관리자 전용 — 로직·기초값 마스터 보기 (2026-09-15 브레인 Z01). + Z01_MASTER_DATA: "z01-master-data", } as const; export type RouteKey = keyof typeof ROUTES; @@ -138,6 +140,7 @@ export const PROTECTED_ROUTES: readonly RoutePath[] = [ ROUTES.B10_PAYMENT, ROUTES.B11_STATUS, ROUTES.B11_LOADING, + ROUTES.Z01_MASTER_DATA, ]; /* ----------------------------------------------------------------------------- diff --git a/resources/data_master_labels/labels_2026-01-01.json b/resources/data_master_labels/labels_2026-01-01.json new file mode 100644 index 00000000..6875d5b8 --- /dev/null +++ b/resources/data_master_labels/labels_2026-01-01.json @@ -0,0 +1,6404 @@ +{ + "schema_version": "1.0", + "dataset_id": "data_master_labels", + "effective_date": "2026-01-01", + "generated_at": "2026-09-15T18:55:59+09:00", + "note": "마스터 자료의 **사람이 읽을 이름표**. 값이 아니라 이름만 담는다 — 여기를 고쳐도 계산은 안 바뀐다. Z01 마스터 관리 화면이 표·열 이름을 여기서 읽는다.", + "policy": { + "labels_only": "값·수식·단가를 담지 않는다. 마스터 파일은 손대지 않는다.", + "no_invented_meaning": "뜻을 모르는 열은 name_ko 를 비우고 unknown 에 사유를 적는다. 지어내지 않는다.", + "unit_is_label_only": "unit 은 이름표에서만 정한다. 자료에 없는 단위를 만들어 붙이지 않는다.", + "counting_rule": "표 = 화면이 표로 그릴 마디(줄이 여럿인 마디). 값 묶음 = 표가 아닌 마디(설명·방침·한 값짜리 요율 따위).", + "brain_kind_table": "갈래는 2026-09-15 브레인 갈래 나눔표를 그대로 따른다(로직 17 · 기초값 9 · 부산물 4 · 씨앗 1).", + "out_of_31": "폴더 장부(_manifest.json) 셋은 브레인 31 밖이라 부산물로 둔다.", + "excluded": "강우 IDF 캐시(resources/data_rainfall_idf_cache, 96 파일)는 배수용이라 뺀다." + }, + "lookup_order": { + "column": [ + "column_overrides['/<열key>']", + "columns['<열key>']", + "영문 키 그대로" + ], + "value_group": [ + "value_overrides['::']", + "value_keys['<마지막 조각>']", + "영문 키 그대로" + ] + }, + "kinds": { + "logic": { + "name_ko": "로직", + "summary": "규칙과 표 — 법령·품셈이 정해 둔 것. 값이 바뀌는 자리가 아니라 셈이 굴러가는 방식이다." + }, + "base_value": { + "name_ko": "기초값", + "summary": "때가 되면 바뀌는 값 — 노임·자재·기계·시세·요율. 판을 갈아 끼우는 자리다." + }, + "byproduct": { + "name_ko": "부산물", + "summary": "다른 벌에서 나온 기록. ⚠ 정본이 아니다 — 고쳐도 정본이 안 바뀐다." + }, + "seed": { + "name_ko": "씨앗", + "summary": "앞으로 늘려 갈 첫 벌. 모양을 잡아 두려고 먼저 놓은 것이다." + } + }, + "counts": { + "files": 34, + "tables": 91, + "columns": 447, + "value_groups": 172, + "unknown": 0 + }, + "files": [ + { + "file_id": "pum_forest", + "path": "resources/data_cost_input_value/pum_forest_2026.json", + "name_ko": "산림사업 표준품셈 표 원문", + "summary": "산림청고시 제2025-82호의 표를 줄·칸 그대로 옮긴 벌. 모든 품과 소요량의 뿌리다.", + "kind": "logic", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "읽어 들인 산림품셈 원문 파일.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/pum/tables", + "name_ko": "산림품셈 표", + "summary": "표 하나가 한 줄. 머리와 줄을 원문 그대로 담는다.", + "shape": "list", + "rows": 476, + "columns": [ + { + "key": "table_id", + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + { + "key": "line", + "name_ko": "원문 줄 번호", + "unit": "", + "visible": false + }, + { + "key": "headers", + "name_ko": "표 머리", + "unit": "", + "visible": true + }, + { + "key": "rows", + "name_ko": "표 줄", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "variables/pum/normalization_status", + "name_ko": "정돈 상태", + "summary": "자원 코드 정돈이 끝났는지." + }, + { + "key": "variables/pum/representation", + "name_ko": "담은 꼴", + "summary": "원문 표를 어떤 꼴로 담았는지." + } + ] + }, + { + "file_id": "pum_const", + "path": "resources/data_cost_input_value/pum_const_2026.json", + "name_ko": "건설공사 표준품셈 표 원문", + "summary": "산림품셈에 없는 공종을 메우는 보완 벌. 산림품셈이 1차, 이쪽이 2차다.", + "kind": "logic", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "읽어 들인 건설품셈 원문 파일 목록.", + "shape": "list", + "rows": 45, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/pum/tables", + "name_ko": "건설품셈 표", + "summary": "표 하나가 한 줄. 머리와 줄을 원문 그대로 담는다.", + "shape": "list", + "rows": 2192, + "columns": [ + { + "key": "table_id", + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + { + "key": "line", + "name_ko": "원문 줄 번호", + "unit": "", + "visible": false + }, + { + "key": "headers", + "name_ko": "표 머리", + "unit": "", + "visible": true + }, + { + "key": "rows", + "name_ko": "표 줄", + "unit": "", + "visible": true + }, + { + "key": "source_file", + "name_ko": "원문 파일", + "unit": "", + "visible": false + } + ] + } + ], + "value_groups": [ + { + "key": "variables/pum/normalization_status", + "name_ko": "정돈 상태", + "summary": "자원 코드 정돈이 끝났는지." + }, + { + "key": "variables/pum/representation", + "name_ko": "담은 꼴", + "summary": "원문 표를 어떤 꼴로 담았는지." + } + ] + }, + { + "file_id": "work_item_master", + "path": "resources/data_work_item_master/work_item_master_2026-01-01.json", + "name_ko": "공종 마스터", + "summary": "품셈 목차를 공종코드(FP-…) 나무로 세운 벌. 수량 줄이 붙는 자리다.", + "kind": "logic", + "tables": [ + { + "key": "orphan_tables", + "name_ko": "공종에 못 붙인 표", + "summary": "목차 어디에도 못 붙인 품셈 표.", + "shape": "list", + "rows": 17, + "columns": [ + { + "key": "pum_table_id", + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + } + ] + }, + { + "key": "work_items", + "name_ko": "공종", + "summary": "공종코드·이름·단계와 딸린 품셈 표. 마스터의 뼈대다.", + "shape": "list", + "rows": 477, + "columns": [ + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + }, + { + "key": "number", + "name_ko": "품셈 번호", + "unit": "", + "visible": true + }, + { + "key": "name", + "name_ko": "이름", + "unit": "", + "visible": true + }, + { + "key": "level", + "name_ko": "단계", + "unit": "", + "visible": true + }, + { + "key": "parent_code", + "name_ko": "상위 공종코드", + "unit": "", + "visible": true + }, + { + "key": "sort_order", + "name_ko": "정렬 차례", + "unit": "", + "visible": false + }, + { + "key": "tables", + "name_ko": "딸린 품셈 표", + "unit": "", + "visible": true + }, + { + "key": "parent_mode", + "name_ko": "하위 고르는 방식", + "unit": "", + "visible": true + }, + { + "key": "variant_keys", + "name_ko": "갈래 키", + "unit": "", + "visible": true + }, + { + "key": "steps", + "name_ko": "단계 합산 구성", + "unit": "", + "visible": true + }, + { + "key": "steps_basis", + "name_ko": "단계 합산 근거", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "stats", + "name_ko": "집계", + "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것." + } + ] + }, + { + "file_id": "coef", + "path": "resources/data_cost_input_value/coef_2026.json", + "name_ko": "품셈 계수 — 할증·토량환산", + "summary": "재료·노무 할증표, 토량환산계수 L·C, 공구손료율.", + "kind": "logic", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 2, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/coef_soil_C/records", + "name_ko": "토량환산계수 C", + "summary": "다진 흙이 줄어드는 비(다져진 상태 ÷ 자연 상태). 토질마다 하한·상한.", + "shape": "list", + "rows": 17, + "columns": [ + { + "key": "soil_type", + "name_ko": "토질", + "unit": "", + "visible": true + }, + { + "key": "min", + "name_ko": "계수 하한", + "unit": "", + "visible": true + }, + { + "key": "max", + "name_ko": "계수 상한", + "unit": "", + "visible": true + }, + { + "key": "rule", + "name_ko": "별도 규정", + "unit": "", + "visible": true + }, + { + "key": "duplicate_group", + "name_ko": "원문 중복 묶음", + "unit": "", + "visible": true + }, + { + "key": "duplicate_index", + "name_ko": "중복 차례", + "unit": "", + "visible": true + }, + { + "key": "selection", + "name_ko": "채택 여부", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/coef_soil_L/records", + "name_ko": "토량환산계수 L", + "summary": "판 흙이 부푸는 비(흐트러진 상태 ÷ 자연 상태). 토질마다 하한·상한.", + "shape": "list", + "rows": 17, + "columns": [ + { + "key": "soil_type", + "name_ko": "토질", + "unit": "", + "visible": true + }, + { + "key": "min", + "name_ko": "계수 하한", + "unit": "", + "visible": true + }, + { + "key": "max", + "name_ko": "계수 상한", + "unit": "", + "visible": true + }, + { + "key": "duplicate_group", + "name_ko": "원문 중복 묶음", + "unit": "", + "visible": true + }, + { + "key": "duplicate_index", + "name_ko": "중복 차례", + "unit": "", + "visible": true + }, + { + "key": "selection", + "name_ko": "채택 여부", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/surcharge_labor/tables", + "name_ko": "노무 할증표 원문", + "summary": "작업시기·경과연수·집단화정도처럼 품을 올리고 내리는 표를 원문 그대로 실은 벌.", + "shape": "list", + "rows": 26, + "columns": [ + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + { + "key": "line", + "name_ko": "원문 줄 번호", + "unit": "", + "visible": false + }, + { + "key": "headers", + "name_ko": "표 머리", + "unit": "", + "visible": true + }, + { + "key": "rows", + "name_ko": "표 줄", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/surcharge_mat/tables", + "name_ko": "재료 할증표 원문", + "summary": "품셈 1-3-1 재료의 할증을 원문 표째로 실은 벌.", + "shape": "list", + "rows": 5, + "columns": [ + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + { + "key": "line", + "name_ko": "원문 줄 번호", + "unit": "", + "visible": false + }, + { + "key": "headers", + "name_ko": "표 머리", + "unit": "", + "visible": true + }, + { + "key": "rows", + "name_ko": "표 줄", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "variables/coef_soil_C/duplicate_note", + "name_ko": "원문 중복 비고", + "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리." + }, + { + "key": "variables/coef_soil_C/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + }, + { + "key": "variables/coef_soil_L/duplicate_note", + "name_ko": "원문 중복 비고", + "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리." + }, + { + "key": "variables/coef_soil_L/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + }, + { + "key": "variables/rate_tool", + "name_ko": "공구손료율", + "summary": "주요 재료비에 곱하는 공구손료 율(하한·상한). 어느 값을 쓸지는 고름이 필요하다." + }, + { + "key": "variables/surcharge_labor/application_status", + "name_ko": "적용 상태", + "summary": "쓰려면 무엇이 더 정해져야 하는지." + }, + { + "key": "variables/surcharge_labor/representation", + "name_ko": "담은 꼴", + "summary": "원문 표를 어떤 꼴로 담았는지." + }, + { + "key": "variables/surcharge_labor/unit", + "name_ko": "값 단위", + "summary": "할증은 %다." + }, + { + "key": "variables/surcharge_mat/duplicate_application_prohibited", + "name_ko": "중복 적용 금지", + "summary": "두 자리에 걸면 두 번 세게 된다는 표시." + }, + { + "key": "variables/surcharge_mat/representation", + "name_ko": "담은 꼴", + "summary": "원문 표를 어떤 꼴로 담았는지." + }, + { + "key": "variables/surcharge_mat/unit", + "name_ko": "값 단위", + "summary": "할증은 %다." + } + ] + }, + { + "file_id": "material_surcharge", + "path": "resources/data_material_surcharge/material_surcharge_2026-01-01.json", + "name_ko": "재료 할증률", + "summary": "자재마다 몇 %를 더 사는지. 산림품셈 1-3-1 이 정본이고 건설품셈은 보완이다.", + "kind": "logic", + "tables": [ + { + "key": "candidates_pending_user/items", + "name_ko": "사용자 확정 대기 후보", + "summary": "원문에 이름은 있으나 쓰임이 달라 아직 안 쓰는 줄.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "material", + "name_ko": "자재명", + "unit": "", + "visible": true + }, + { + "key": "rate", + "name_ko": "할증률", + "unit": "%", + "visible": true + }, + { + "key": "pumsem", + "name_ko": "어느 품셈", + "unit": "", + "visible": true + }, + { + "key": "listed_in", + "name_ko": "실린 자리", + "unit": "", + "visible": true + }, + { + "key": "listed_condition", + "name_ko": "원문이 못박은 조건", + "unit": "", + "visible": true + }, + { + "key": "our_usage", + "name_ko": "우리 쓰임", + "unit": "", + "visible": true + }, + { + "key": "why_not_applied", + "name_ko": "안 쓰는 사유", + "unit": "", + "visible": true + } + ] + }, + { + "key": "rates_pct", + "name_ko": "재료 할증률", + "summary": "자재마다 할증률과 그 조건. 조건이 갈리면 다른 조건 칸에 함께 둔다.", + "shape": "list", + "rows": 19, + "columns": [ + { + "key": "material", + "name_ko": "자재명", + "unit": "", + "visible": true + }, + { + "key": "rate", + "name_ko": "할증률", + "unit": "%", + "visible": true + }, + { + "key": "condition", + "name_ko": "조건", + "unit": "", + "visible": true + }, + { + "key": "alt_rate", + "name_ko": "다른 조건 할증률", + "unit": "%", + "visible": true + }, + { + "key": "alt_condition", + "name_ko": "다른 조건", + "unit": "", + "visible": true + }, + { + "key": "pumsem", + "name_ko": "어느 품셈", + "unit": "", + "visible": true + } + ] + }, + { + "key": "source", + "name_ko": "출처", + "summary": "할증률표가 어느 품셈에서 왔는지.", + "shape": "map", + "rows": 2, + "columns": [ + { + "key": "doc", + "name_ko": "문서", + "unit": "", + "visible": true + }, + { + "key": "via", + "name_ko": "거쳐 온 자리", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "candidates_pending_user/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "not_found", + "name_ko": "못 찾은 것", + "summary": "두 품셈을 다 뒤졌으나 이름이 없는 것." + }, + { + "key": "observed_practice", + "name_ko": "실무 관측", + "summary": "실무 집계에서 본 할증률. 참고이지 기본값이 아니다." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + } + ] + }, + { + "file_id": "formwork_reuse", + "path": "resources/data_formwork/formwork_reuse_2026-01-01.json", + "name_ko": "거푸집 사용횟수", + "summary": "구조물 종류마다 거푸집을 몇 번 쓰는지. 품셈 1-7-1 이 정한 값이라 실무값으로 갈음하지 않는다.", + "kind": "logic", + "tables": [ + { + "key": "euroform_type/classes", + "name_ko": "유로폼 갈래별 1일 시공량", + "summary": "유로폼 설치·해체 품이 갈리는 갈래와 하루 시공 면적.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "key", + "name_ko": "키", + "unit": "", + "visible": true + }, + { + "key": "examples", + "name_ko": "원문 예시", + "unit": "", + "visible": true + }, + { + "key": "daily_area_m2", + "name_ko": "1일 시공량", + "unit": "㎡", + "visible": true + } + ] + }, + { + "key": "euroform_type/type_map", + "name_ko": "구조물 종류 ↔ 유로폼 갈래", + "summary": "우리 구조물 종류 키를 유로폼 갈래에 잇는 줄.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "class", + "name_ko": "갈래", + "unit": "", + "visible": true + }, + { + "key": "matched", + "name_ko": "걸린 원문 예시", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + } + ] + }, + { + "key": "reuse_by_class", + "name_ko": "구조 복잡도별 사용횟수", + "summary": "품셈 1-7-1 이 구조 갈래마다 정한 거푸집 사용횟수.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "reuse_count", + "name_ko": "사용횟수", + "unit": "회", + "visible": true + }, + { + "key": "class", + "name_ko": "갈래", + "unit": "", + "visible": true + }, + { + "key": "examples", + "name_ko": "원문 예시", + "unit": "", + "visible": true + } + ] + }, + { + "key": "type_map", + "name_ko": "구조물 종류 ↔ 사용횟수", + "summary": "우리 구조물 종류 키를 위 갈래에 잇는 줄.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "reuse_count", + "name_ko": "사용횟수", + "unit": "회", + "visible": true + }, + { + "key": "matched_example", + "name_ko": "걸린 원문 예시", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + }, + { + "key": "basis", + "name_ko": "근거", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "euroform_type/material_unit_note", + "name_ko": "자재 밑수 비고", + "summary": "자재 환산을 어느 창이 하는지." + }, + { + "key": "euroform_type/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "euroform_type/reuse_note", + "name_ko": "사용횟수 비고", + "summary": "닮은 두 사용횟수를 하나로 잇지 않는 까닭." + }, + { + "key": "euroform_type/source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "reuse_ratio_pct", + "name_ko": "사용횟수별 기준수량 비율", + "summary": "품셈 12-4 — 일위대가 재료비에 걸린다. B08 이 곱하면 이중계상이다." + }, + { + "key": "shoring", + "name_ko": "동바리", + "summary": "강관동바리가 어느 구조물에 서는지." + }, + { + "key": "source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + } + ] + }, + { + "file_id": "rebar_complexity", + "path": "resources/data_rebar/rebar_complexity_2026-01-01.json", + "name_ko": "철근 가공·조립 갈래", + "summary": "구조물 형식이 간단·보통·복잡 어디인지. 품셈 12-3 [주]① 이 예시로 가른다.", + "kind": "logic", + "tables": [ + { + "key": "classes", + "name_ko": "철근 갈래", + "summary": "간단·보통·복잡·매우복잡과 원문 예시.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "key", + "name_ko": "키", + "unit": "", + "visible": true + }, + { + "key": "examples", + "name_ko": "원문 예시", + "unit": "", + "visible": true + } + ] + }, + { + "key": "form_map", + "name_ko": "구조물 형식 ↔ 철근 갈래", + "summary": "우리 구조물 형식을 위 갈래에 잇는 줄.", + "shape": "list", + "rows": 6, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "form", + "name_ko": "형식", + "unit": "", + "visible": true + }, + { + "key": "class", + "name_ko": "갈래", + "unit": "", + "visible": true + }, + { + "key": "matched", + "name_ko": "걸린 원문 예시", + "unit": "", + "visible": true + }, + { + "key": "why", + "name_ko": "까닭", + "unit": "", + "visible": true + }, + { + "key": "basis", + "name_ko": "근거", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "price_hint_krw_per_ton", + "name_ko": "단가 참고값", + "summary": "표시 전용 — 갈래 차이를 사람이 보라고 둔 값. 계산에 안 들어간다." + }, + { + "key": "source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + } + ] + }, + { + "file_id": "timber_structure_class", + "path": "resources/data_timber/timber_structure_class_2026-01-01.json", + "name_ko": "목재공작물 구조 갈래", + "summary": "통나무 구조물의 품이 갈리는 자리. 품셈 13-13-1 [주]③.", + "kind": "logic", + "tables": [ + { + "key": "classes", + "name_ko": "목재 구조 갈래별 품", + "summary": "갈래마다 목재 채적 1㎥에 드는 건축목공·보통인부.", + "shape": "list", + "rows": 6, + "columns": [ + { + "key": "key", + "name_ko": "키", + "unit": "", + "visible": true + }, + { + "key": "carpenter", + "name_ko": "건축목공", + "unit": "인/㎥", + "visible": true + }, + { + "key": "laborer", + "name_ko": "보통인부", + "unit": "인/㎥", + "visible": true + }, + { + "key": "examples", + "name_ko": "원문 예시", + "unit": "", + "visible": true + } + ] + }, + { + "key": "type_map", + "name_ko": "구조물 종류 ↔ 목재 갈래", + "summary": "우리 구조물 종류 키를 위 갈래에 잇는 줄.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "class", + "name_ko": "갈래", + "unit": "", + "visible": true + }, + { + "key": "matched", + "name_ko": "걸린 원문 예시", + "unit": "", + "visible": true + }, + { + "key": "provisional", + "name_ko": "잠정 여부", + "unit": "", + "visible": true + }, + { + "key": "why", + "name_ko": "까닭", + "unit": "", + "visible": true + }, + { + "key": "compare", + "name_ko": "견줌", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "basis_unit", + "name_ko": "밑수", + "summary": "값이 무엇 하나당인지." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "pending_user", + "name_ko": "사용자 확정 대기", + "summary": "아직 사람이 답해야 닫히는 물음." + }, + { + "key": "source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + } + ] + }, + { + "file_id": "masonry_class", + "path": "resources/data_masonry/masonry_class_2026-01-01.json", + "name_ko": "돌쌓기 규격 갈래", + "summary": "저장 제원으로 자동 판정하는 축 — 뒷길이·돌 직경·전면 기울기·쌓기 방식.", + "kind": "logic", + "tables": [ + { + "key": "back_length/classes", + "name_ko": "뒷길이 갈래", + "summary": "돌쌓기 뒷길이를 품셈 규격 칸으로 가르는 상한.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "max_cm", + "name_ko": "상한", + "unit": "㎝", + "visible": true + }, + { + "key": "key", + "name_ko": "키", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "back_length/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "back_length/option_key", + "name_ko": "고르개 키", + "summary": "화면 고르개가 쓰는 저장 칸 이름." + }, + { + "key": "back_length/source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + }, + { + "key": "bond", + "name_ko": "쌓기 방식", + "summary": "메쌓기·찰쌓기로 공종코드가 갈린다." + }, + { + "key": "boulder_diameter", + "name_ko": "돌 직경 갈래", + "summary": "큰돌쌓기 — 저장 제원 stone_cm 으로 갈린다." + }, + { + "key": "face_slope", + "name_ko": "전면 기울기", + "summary": "형식마다 정해진 1:n. 코드 기본 0.3 이 여기서 왔다." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + } + ] + }, + { + "file_id": "masonry_slope", + "path": "resources/data_masonry/masonry_slope_2026-01-01.json", + "name_ko": "돌쌓기 표준경사", + "summary": "직고·메찰·성절토 셋으로 갈리는 전면 기울기. 품셈 13-4-4 [주]⑪.", + "kind": "logic", + "tables": [ + { + "key": "table", + "name_ko": "표준경사 표", + "summary": "메·찰마다 성토·절토 기울기 줄. 직고 칸은 steps_m 이 정한다.", + "shape": "map", + "rows": 2, + "columns": [ + { + "key": "성토", + "name_ko": "성토부 경사", + "unit": "1:n", + "visible": true + }, + { + "key": "절토", + "name_ko": "절토부 경사", + "unit": "1:n", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "not_here", + "name_ko": "이 표가 안 다루는 것", + "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + }, + { + "key": "steps_m", + "name_ko": "직고 칸", + "summary": "표가 갈리는 높이 경계(m)." + } + ] + }, + { + "file_id": "masonry_back_length", + "path": "resources/data_masonry/masonry_back_length_2026-01-01.json", + "name_ko": "돌쌓기 뒷길이 표준", + "summary": "높이와 메·찰로 갈리는 뒷길이 범위. 품셈 13-4-4 [주]⑩.", + "kind": "logic", + "tables": [], + "value_groups": [ + { + "key": "not_here", + "name_ko": "이 표가 안 다루는 것", + "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + }, + { + "key": "steps_m", + "name_ko": "직고 칸", + "summary": "표가 갈리는 높이 경계(m)." + }, + { + "key": "table_cm", + "name_ko": "뒷길이 범위표", + "summary": "메·찰마다 직고 칸별 뒷길이 하한·상한(㎝)." + } + ] + }, + { + "file_id": "stone_kind", + "path": "resources/data_masonry/stone_kind_2026-01-01.json", + "name_ko": "돌 종류별 소요량", + "summary": "고임돌·채움 콘크리트·뒤채움이 돌 종류로 갈리는 자리.", + "kind": "logic", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "돌 종류 계수가 어느 원문에서 왔는지.", + "shape": "map", + "rows": 4, + "columns": [ + { + "key": "doc", + "name_ko": "문서", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + }, + { + "key": "quote", + "name_ko": "원문 인용", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "back_lengths_cm", + "name_ko": "뒷길이 규격", + "summary": "표가 값을 주는 뒷길이 일곱 칸." + }, + { + "key": "backfill_ratio_of_back_length", + "name_ko": "뒤채움 몫", + "summary": "뒷길이 가운데 뒤채움이 차지하는 비. 나머지가 잡석이다." + }, + { + "key": "fallback", + "name_ko": "미지정일 때", + "summary": "사용자가 안 고른 경우 쓰는 한 벌." + }, + { + "key": "fill_concrete_m3_per_m2", + "name_ko": "채움 콘크리트 원단위", + "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. 원문이 두 줄뿐이다." + }, + { + "key": "kinds", + "name_ko": "돌 종류", + "summary": "야면석·호박돌 / 깬잡석 / 깬돌 / 견치돌 네 줄." + }, + { + "key": "no_folding", + "name_ko": "접지 않음 규칙", + "summary": "표에 없는 뒷길이를 가까운 칸으로 접지 않는다 — 접으면 값이 조용히 틀린다." + }, + { + "key": "not_here", + "name_ko": "이 표가 안 다루는 것", + "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "option_key", + "name_ko": "고르개 키", + "summary": "화면 고르개가 쓰는 저장 칸 이름." + }, + { + "key": "option_note", + "name_ko": "고르개 비고", + "summary": "고르개를 만들 때 챙길 것." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "wedge_stone_m3_per_m2", + "name_ko": "고임돌 원단위", + "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. null 은 원문 「-」다." + }, + { + "key": "why", + "name_ko": "까닭", + "summary": "이 벌을 왜 따로 두는지." + } + ] + }, + { + "file_id": "revetment_sabang", + "path": "resources/data_masonry/revetment_sabang_2026-01-01.json", + "name_ko": "기슭막이 치수(사방)", + "summary": "독립 기슭막이의 높이·계획비탈·둑마루 두께·뒷채움을 한 자리에 둔 벌.", + "kind": "logic", + "tables": [], + "value_groups": [ + { + "key": "items", + "name_ko": "항목", + "summary": "이 벌이 담는 항목 묶음." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "rank", + "name_ko": "우선순위", + "summary": "원문끼리 어긋날 때 어느 쪽을 먼저 보는지." + }, + { + "key": "scope", + "name_ko": "걸치는 범위", + "summary": "어디까지 쓰는 값인지." + } + ] + }, + { + "file_id": "structure_unit_observed", + "path": "resources/data_structure_unit/structure_unit_observed_2026-01-01.json", + "name_ko": "구조물 관측 원단위", + "summary": "품셈에 표준 물량표가 없는 콘크리트 구조물을 실무 설계원본에서 뽑은 벌.", + "kind": "logic", + "tables": [ + { + "key": "double_count_rules/rules", + "name_ko": "이중계상 방지 규칙", + "summary": "같은 것을 두 번 세게 되는 자리와 우리가 고른 쪽.", + "shape": "list", + "rows": 2, + "columns": [ + { + "key": "key", + "name_ko": "규칙·물음 키", + "unit": "", + "visible": true + }, + { + "key": "where", + "name_ko": "어디서 갈리나", + "unit": "", + "visible": true + }, + { + "key": "quote", + "name_ko": "원문 인용", + "unit": "", + "visible": true + }, + { + "key": "our_choice", + "name_ko": "우리가 고른 쪽", + "unit": "", + "visible": true + }, + { + "key": "why", + "name_ko": "까닭", + "unit": "", + "visible": true + }, + { + "key": "scope", + "name_ko": "걸치는 범위", + "unit": "", + "visible": true + }, + { + "key": "guard", + "name_ko": "가드", + "unit": "", + "visible": true + } + ] + }, + { + "key": "entries", + "name_ko": "구조물 원단위", + "summary": "구조물 종류·규격마다 개소당(또는 m당) 물량 구성.", + "shape": "list", + "rows": 10, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "spec", + "name_ko": "제원", + "unit": "", + "visible": true + }, + { + "key": "unit", + "name_ko": "단위", + "unit": "", + "visible": true + }, + { + "key": "source", + "name_ko": "원천", + "unit": "", + "visible": true + }, + { + "key": "source_note", + "name_ko": "원천 비고", + "unit": "", + "visible": true + }, + { + "key": "section", + "name_ko": "원본 절", + "unit": "", + "visible": true + }, + { + "key": "components", + "name_ko": "구성 물량", + "unit": "", + "visible": true + }, + { + "key": "notes", + "name_ko": "비고 묶음", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + } + ] + }, + { + "key": "not_found/items", + "name_ko": "못 찾은 원단위", + "summary": "원본에 값이 없어 못 세운 자리와 무엇이 있어야 열리는지.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "why", + "name_ko": "까닭", + "unit": "", + "visible": true + }, + { + "key": "needs", + "name_ko": "있어야 열리는 것", + "unit": "", + "visible": true + }, + { + "key": "spec", + "name_ko": "제원", + "unit": "", + "visible": true + }, + { + "key": "about", + "name_ko": "무엇에 대한 것인가", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + } + ] + }, + { + "key": "pending_choices/items", + "name_ko": "사용자 확정 대기", + "summary": "갈래가 갈리는데 아직 안 고른 물음과 고르면 생기는 차이.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "key", + "name_ko": "규칙·물음 키", + "unit": "", + "visible": true + }, + { + "key": "label", + "name_ko": "칸 이름", + "unit": "", + "visible": true + }, + { + "key": "default", + "name_ko": "기본값", + "unit": "", + "visible": true + }, + { + "key": "where", + "name_ko": "어디서 갈리나", + "unit": "", + "visible": true + }, + { + "key": "effect", + "name_ko": "바뀌면 생기는 차이", + "unit": "", + "visible": true + }, + { + "key": "scope", + "name_ko": "걸치는 범위", + "unit": "", + "visible": true + } + ] + }, + { + "key": "sources", + "name_ko": "출처", + "summary": "관측 원단위가 어느 실무 원본에서 왔는지.", + "shape": "map", + "rows": 2, + "columns": [ + { + "key": "doc", + "name_ko": "문서", + "unit": "", + "visible": true + }, + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + } + ] + }, + { + "key": "原文_뒷받침/items", + "name_ko": "원문 뒷받침", + "summary": "관측값이 품셈 원문과 맞는지 대 본 기록.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "item", + "name_ko": "항목", + "unit": "", + "visible": true + }, + { + "key": "observed", + "name_ko": "관측값", + "unit": "", + "visible": true + }, + { + "key": "source", + "name_ko": "원천", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "double_count_rules/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "not_found/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "pending_choices/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "原文_뒷받침/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + } + ] + }, + { + "file_id": "work_item_mapping", + "path": "resources/data_work_item_mapping/work_item_mapping_2026-01-01.json", + "name_ko": "수량 줄 ↔ 공종코드 잇기", + "summary": "B08 이 낸 수량 줄을 공종 마스터 코드에 잇는 다리. 발주처 골격이 바뀌어도 코드를 안 고치려고 데이터로 둔다.", + "kind": "logic", + "tables": [ + { + "key": "ancillary", + "name_ko": "부대공 잇기", + "summary": "가설창고 같은 부대공 줄.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "group", + "name_ko": "묶음", + "unit": "", + "visible": true + }, + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + }, + { + "key": "basis_unit", + "name_ko": "밑수 단위", + "unit": "", + "visible": true + }, + { + "key": "basis_source", + "name_ko": "밑수 근거", + "unit": "", + "visible": true + }, + { + "key": "master_name", + "name_ko": "마스터 공종명", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + } + ] + }, + { + "key": "composite/items", + "name_ko": "묶음 공종", + "summary": "품셈에 그 공종이 없어 여러 공종을 묶어 한 줄로 세우는 것(옹벽·BOX암거·포장).", + "shape": "list", + "rows": 11, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "when", + "name_ko": "서는 조건", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + }, + { + "key": "outside_note", + "name_ko": "묶음 밖 비고", + "unit": "", + "visible": true + }, + { + "key": "parts", + "name_ko": "조각", + "unit": "", + "visible": true + }, + { + "key": "why", + "name_ko": "까닭", + "unit": "", + "visible": true + }, + { + "key": "needs", + "name_ko": "있어야 열리는 것", + "unit": "", + "visible": true + }, + { + "key": "placing_note", + "name_ko": "타설 비고", + "unit": "", + "visible": true + }, + { + "key": "parts_note", + "name_ko": "조각 비고", + "unit": "", + "visible": true + } + ] + }, + { + "key": "earthwork", + "name_ko": "토공 잇기", + "summary": "흙깎기·쌓기·면고르기 같은 토공 줄을 공종코드에 잇는다.", + "shape": "list", + "rows": 22, + "columns": [ + { + "key": "group", + "name_ko": "묶음", + "unit": "", + "visible": true + }, + { + "key": "ground", + "name_ko": "지반 갈래", + "unit": "", + "visible": true + }, + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + }, + { + "key": "basis_unit", + "name_ko": "밑수 단위", + "unit": "", + "visible": true + }, + { + "key": "basis_source", + "name_ko": "밑수 근거", + "unit": "", + "visible": true + }, + { + "key": "master_name", + "name_ko": "마스터 공종명", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + }, + { + "key": "variant_axis", + "name_ko": "갈래 축", + "unit": "", + "visible": true + }, + { + "key": "variant_from", + "name_ko": "갈래 원본 칸", + "unit": "", + "visible": true + }, + { + "key": "variant_note", + "name_ko": "갈래 비고", + "unit": "", + "visible": true + }, + { + "key": "mismatch_reason", + "name_ko": "어긋남 사유", + "unit": "", + "visible": true + }, + { + "key": "mismatch_kind", + "name_ko": "어긋남 갈래", + "unit": "", + "visible": true + }, + { + "key": "variant_missing_reason", + "name_ko": "갈래 미선택 사유", + "unit": "", + "visible": true + }, + { + "key": "leaf_from", + "name_ko": "잎 원본 칸", + "unit": "", + "visible": true + }, + { + "key": "leaf_codes", + "name_ko": "잎 코드", + "unit": "", + "visible": true + }, + { + "key": "leaf_note", + "name_ko": "잎 비고", + "unit": "", + "visible": true + }, + { + "key": "item", + "name_ko": "항목", + "unit": "", + "visible": true + }, + { + "key": "variant_value", + "name_ko": "갈래 값", + "unit": "", + "visible": true + }, + { + "key": "variant_template", + "name_ko": "갈래 틀", + "unit": "", + "visible": true + } + ] + }, + { + "key": "haul", + "name_ko": "운반 잇기", + "summary": "운반 수단마다 공종코드. 무대(20m 이내)는 내역 줄이 아니다.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "equipment", + "name_ko": "운반 수단", + "unit": "", + "visible": true + }, + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + }, + { + "key": "basis_unit", + "name_ko": "밑수 단위", + "unit": "", + "visible": true + }, + { + "key": "basis_source", + "name_ko": "밑수 근거", + "unit": "", + "visible": true + }, + { + "key": "master_name", + "name_ko": "마스터 공종명", + "unit": "", + "visible": true + }, + { + "key": "payload_density_note", + "name_ko": "적재 단위중량 비고", + "unit": "", + "visible": true + }, + { + "key": "in_bill", + "name_ko": "내역에 싣나", + "unit": "", + "visible": true + }, + { + "key": "reason", + "name_ko": "사유", + "unit": "", + "visible": true + } + ] + }, + { + "key": "pending_user/items", + "name_ko": "사용자 확정 대기", + "summary": "어느 공종으로 볼지 아직 안 정한 줄.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "group", + "name_ko": "묶음", + "unit": "", + "visible": true + }, + { + "key": "candidates", + "name_ko": "후보", + "unit": "", + "visible": true + }, + { + "key": "why", + "name_ko": "까닭", + "unit": "", + "visible": true + }, + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "name", + "name_ko": "이름", + "unit": "", + "visible": true + }, + { + "key": "needs", + "name_ko": "있어야 열리는 것", + "unit": "", + "visible": true + } + ] + }, + { + "key": "structure", + "name_ko": "구조물 잇기", + "summary": "구조물 종류를 공종코드에 잇고 내역 성분·밑수 단위를 못박는다.", + "shape": "list", + "rows": 9, + "columns": [ + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + { + "key": "secondary_axes", + "name_ko": "둘째 갈래 축", + "unit": "", + "visible": true + }, + { + "key": "secondary_axes_note", + "name_ko": "둘째 갈래 비고", + "unit": "", + "visible": true + }, + { + "key": "billing_component", + "name_ko": "내역 성분", + "unit": "", + "visible": true + }, + { + "key": "billing_note", + "name_ko": "내역 비고", + "unit": "", + "visible": true + }, + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + }, + { + "key": "master_name", + "name_ko": "마스터 공종명", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + }, + { + "key": "class_note", + "name_ko": "갈래 비고", + "unit": "", + "visible": true + }, + { + "key": "variant_axis", + "name_ko": "갈래 축", + "unit": "", + "visible": true + }, + { + "key": "class_from", + "name_ko": "갈래 원본 칸", + "unit": "", + "visible": true + }, + { + "key": "form_codes", + "name_ko": "형식별 공종코드", + "unit": "", + "visible": true + }, + { + "key": "basis_unit_note", + "name_ko": "밑수 비고", + "unit": "", + "visible": true + }, + { + "key": "bond_codes", + "name_ko": "쌓기 방식별 공종코드", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "composite/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "composite/unit_conversion", + "name_ko": "단위 환산", + "summary": "단가 단위와 원단위 단위가 달라 맞추는 값." + }, + { + "key": "concrete_placing", + "name_ko": "콘크리트 타설 잇기", + "summary": "타설 방식 × 구조물 종류로 공종이 갈리는 자리." + }, + { + "key": "ground_aliases_moved_to", + "name_ko": "갈래 별칭 옮긴 자리", + "summary": "갈래 이름 별칭은 별칭표로 옮겼다. 여기 다시 두지 않는다." + }, + { + "key": "masonry_class_reference", + "name_ko": "돌쌓기 갈래 참고 자리", + "summary": "돌쌓기 갈래는 이제 참고용이고 어긋나면 그것이 신호다." + }, + { + "key": "master", + "name_ko": "마스터 자리", + "summary": "공종 코드를 읽어 오는 마스터 파일." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "pending_user/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "pipe", + "name_ko": "배수관 잇기", + "summary": "관종으로 공종이 갈린다. 관 정본은 pipe_points 다." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "variant_contract", + "name_ko": "갈래 키 계약", + "summary": "갈래 키 문자열을 두 창이 각자 조립하지 않기로 한 약속." + } + ] + }, + { + "file_id": "aliases", + "path": "resources/data_aliases/aliases_2026-01-01.json", + "name_ko": "별칭표", + "summary": "자원·갈래 이름이 달라도 같은 것으로 잇는 한 벌.", + "kind": "logic", + "tables": [ + { + "key": "aliases", + "name_ko": "별칭 줄", + "summary": "원래 이름 하나를 표준 코드 하나에 잇는 줄. 범위(scope)와 품셈 판까지 달아 어디에 걸리는지 못박는다.", + "shape": "list", + "rows": 20, + "columns": [ + { + "key": "axis", + "name_ko": "축", + "unit": "", + "visible": true + }, + { + "key": "from", + "name_ko": "원래 이름", + "unit": "", + "visible": true + }, + { + "key": "to", + "name_ko": "이을 코드", + "unit": "", + "visible": true + }, + { + "key": "scope", + "name_ko": "걸치는 범위", + "unit": "", + "visible": true + }, + { + "key": "pum_edition", + "name_ko": "품셈 판", + "unit": "", + "visible": true + }, + { + "key": "basis", + "name_ko": "근거", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + } + ] + }, + { + "file_id": "resource_catalog_ext", + "path": "resources/data_resource_catalog/resource_catalog_ext_2026-01-01.json", + "name_ko": "추가 자원 카탈로그", + "summary": "노임·기계·관급 카탈로그에 없는 자원의 이름·규격·단위. 단가 칸은 없다.", + "kind": "logic", + "tables": [ + { + "key": "entries", + "name_ko": "추가 자원", + "summary": "카탈로그에 없던 자원의 코드·이름·규격·단위.", + "shape": "list", + "rows": 40, + "columns": [ + { + "key": "code", + "name_ko": "자원코드", + "unit": "", + "visible": true + }, + { + "key": "kind", + "name_ko": "갈래", + "unit": "", + "visible": true + }, + { + "key": "name", + "name_ko": "이름", + "unit": "", + "visible": true + }, + { + "key": "spec", + "name_ko": "규격", + "unit": "", + "visible": true + }, + { + "key": "unit", + "name_ko": "단위", + "unit": "", + "visible": true + }, + { + "key": "source", + "name_ko": "어디서 왔나", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + } + ] + }, + { + "file_id": "labor_const", + "path": "resources/data_cost_input_value/labor_const_2026-01-01.json", + "name_ko": "건설업 노임단가", + "summary": "대한건설협회가 공표하는 시중노임 — 직종마다 하루 얼마.", + "kind": "base_value", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/labor_rate/records", + "name_ko": "건설업 직종별 노임", + "summary": "직종마다 하루 노임. 일위대가의 품값이 여기서 온다.", + "shape": "list", + "rows": 132, + "columns": [ + { + "key": "occupation_code", + "name_ko": "직종코드", + "unit": "", + "visible": true + }, + { + "key": "occupation_name", + "name_ko": "직종명", + "unit": "", + "visible": true + }, + { + "key": "unit", + "name_ko": "단위", + "unit": "", + "visible": true + }, + { + "key": "hours_per_day", + "name_ko": "1일 근로시간", + "unit": "시간", + "visible": true + }, + { + "key": "daily_wage_krw", + "name_ko": "일 노임", + "unit": "원", + "visible": true + }, + { + "key": "status", + "name_ko": "공표 상태", + "unit": "", + "visible": true + }, + { + "key": "reliability", + "name_ko": "신뢰도 기호", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "variables/aliases", + "name_ko": "노임 별칭", + "summary": "코드 대신 쓰는 별칭 이름표(labor_1002 = 보통인부)." + }, + { + "key": "variables/labor_rate/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + }, + { + "key": "variables/labor_rate/reliability_note", + "name_ko": "신뢰도 기호 뜻풀이", + "summary": "노임 표의 * · ** 가 무엇을 뜻하는지." + } + ] + }, + { + "file_id": "labor_mfg", + "path": "resources/data_cost_input_value/labor_mfg_2026-07-01.json", + "name_ko": "제조업 노임단가", + "summary": "중소기업중앙회가 공표하는 중소제조업 직종별 임금.", + "kind": "base_value", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/labor_mfg/records", + "name_ko": "제조업 직종별 노임", + "summary": "중소제조업 직종마다 하루 임금.", + "shape": "list", + "rows": 129, + "columns": [ + { + "key": "occupation_code", + "name_ko": "직종코드", + "unit": "", + "visible": true + }, + { + "key": "occupation_name", + "name_ko": "직종명", + "unit": "", + "visible": true + }, + { + "key": "unit", + "name_ko": "단위", + "unit": "", + "visible": true + }, + { + "key": "industry", + "name_ko": "업종", + "unit": "", + "visible": true + }, + { + "key": "daily_wage_krw", + "name_ko": "일 노임", + "unit": "원", + "visible": true + }, + { + "key": "status", + "name_ko": "공표 상태", + "unit": "", + "visible": true + }, + { + "key": "variation_coefficient", + "name_ko": "변동계수", + "unit": "%", + "visible": true + }, + { + "key": "source_flag", + "name_ko": "원문 표시", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "variables/labor_mfg/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + } + ] + }, + { + "file_id": "mach_base", + "path": "resources/data_cost_input_value/mach_base_2026.json", + "name_ko": "건설기계 기초값", + "summary": "취득가·시간당 손료계수·연료소모량·운전원 직종 네 벌.", + "kind": "base_value", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/mach_fuel_rate/parsed_records", + "name_ko": "기계 연료소모량·운전경비", + "summary": "기계마다 한 시간에 쓰는 연료량과 잡재료비 비율, 운전원 수.", + "shape": "list", + "rows": 214, + "columns": [ + { + "key": "machine_code", + "name_ko": "기계코드", + "unit": "", + "visible": true + }, + { + "key": "machine_name", + "name_ko": "기계명", + "unit": "", + "visible": true + }, + { + "key": "fuel_type", + "name_ko": "연료 종류", + "unit": "", + "visible": true + }, + { + "key": "fuel_rate_l_per_hour", + "name_ko": "시간당 연료량", + "unit": "L", + "visible": true + }, + { + "key": "specification", + "name_ko": "규격", + "unit": "", + "visible": true + }, + { + "key": "misc_material_percent_of_fuel", + "name_ko": "잡재료비", + "unit": "연료비의 %", + "visible": true + }, + { + "key": "operator_person_per_day", + "name_ko": "운전원", + "unit": "인/일", + "visible": true + }, + { + "key": "parse_method", + "name_ko": "읽은 방법", + "unit": "", + "visible": false + } + ] + }, + { + "key": "variables/mach_fuel_rate/source_tables", + "name_ko": "운전경비 원문 표", + "summary": "위 값을 읽어 낸 건설품셈 8-4 표를 원문 그대로 실은 벌.", + "shape": "list", + "rows": 21, + "columns": [ + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + { + "key": "line", + "name_ko": "원문 줄 번호", + "unit": "", + "visible": false + }, + { + "key": "headers", + "name_ko": "표 머리", + "unit": "", + "visible": true + }, + { + "key": "rows", + "name_ko": "표 줄", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/mach_loss_coef/records", + "name_ko": "기계 시간당 손료계수", + "summary": "취득가에 곱해 한 시간 손료를 내는 계수와 그 속을 이루는 상각·정비·관리 몫.", + "shape": "list", + "rows": 387, + "columns": [ + { + "key": "machine_code", + "name_ko": "기계코드", + "unit": "", + "visible": true + }, + { + "key": "machine_name", + "name_ko": "기계명", + "unit": "", + "visible": true + }, + { + "key": "specification", + "name_ko": "규격", + "unit": "", + "visible": true + }, + { + "key": "loss_coefficient_per_hour", + "name_ko": "시간당 손료계수", + "unit": "", + "visible": true + }, + { + "key": "source_coefficient_1e_minus_7", + "name_ko": "원문 손료계수", + "unit": "10^-7", + "visible": false + }, + { + "key": "economic_life_hours", + "name_ko": "내용시간", + "unit": "시간", + "visible": true + }, + { + "key": "annual_standard_hours", + "name_ko": "연간표준가동시간", + "unit": "시간", + "visible": true + }, + { + "key": "depreciation_ratio", + "name_ko": "상각비율", + "unit": "", + "visible": true + }, + { + "key": "maintenance_ratio", + "name_ko": "정비비율", + "unit": "", + "visible": true + }, + { + "key": "annual_management_ratio", + "name_ko": "연간관리비율", + "unit": "", + "visible": true + }, + { + "key": "depreciation_coefficient_1e_minus_7", + "name_ko": "원문 상각비계수", + "unit": "10^-7", + "visible": false + }, + { + "key": "maintenance_coefficient_1e_minus_7", + "name_ko": "원문 정비비계수", + "unit": "10^-7", + "visible": false + }, + { + "key": "management_coefficient_1e_minus_7", + "name_ko": "원문 관리비계수", + "unit": "10^-7", + "visible": false + } + ] + }, + { + "key": "variables/mach_operator_map/explicit_mappings", + "name_ko": "기계별 운전원 직종", + "summary": "기계 하나하나에 붙은 운전원 직종코드.", + "shape": "list", + "rows": 121, + "columns": [ + { + "key": "machine_code", + "name_ko": "기계코드", + "unit": "", + "visible": true + }, + { + "key": "occupation_code", + "name_ko": "직종코드", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/mach_operator_map/rules", + "name_ko": "기계 ↔ 운전원 규칙", + "summary": "기계 계열로 운전원 직종을 정하는 규칙.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "occupation_code", + "name_ko": "직종코드", + "unit": "", + "visible": true + }, + { + "key": "alias", + "name_ko": "별칭 키", + "unit": "", + "visible": true + }, + { + "key": "rule_id", + "name_ko": "규칙 키", + "unit": "", + "visible": true + }, + { + "key": "source_section", + "name_ko": "원문 절", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/mach_price/records", + "name_ko": "기계 취득가", + "summary": "기계·규격마다 새로 살 때 값(천원). 손료 계산의 밑수다.", + "shape": "list", + "rows": 613, + "columns": [ + { + "key": "machine_code", + "name_ko": "기계코드", + "unit": "", + "visible": true + }, + { + "key": "machine_name", + "name_ko": "기계명", + "unit": "", + "visible": true + }, + { + "key": "price_thousand_krw", + "name_ko": "취득가", + "unit": "천원", + "visible": true + }, + { + "key": "specification", + "name_ko": "규격", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/mach_rock_adj/rules", + "name_ko": "암 작업 손료 할증", + "summary": "암을 다룰 때 기계 손료를 몇 % 올리는지.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "machine_group", + "name_ko": "기계 묶음", + "unit": "", + "visible": true + }, + { + "key": "rock_work", + "name_ko": "암 작업 할증", + "unit": "%", + "visible": true + }, + { + "key": "boulder_mixed_soil", + "name_ko": "호박돌 섞인 토사 할증", + "unit": "%", + "visible": true + }, + { + "key": "exclusion", + "name_ko": "제외", + "unit": "", + "visible": true + }, + { + "key": "exception", + "name_ko": "예외", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "parse_audit", + "name_ko": "읽기 점검", + "summary": "취득가 표에서 못 읽은 줄이 있는지 적어 둔 자리." + }, + { + "key": "variables/mach_fuel_rate/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + }, + { + "key": "variables/mach_fuel_rate/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "variables/mach_fuel_rate/unit", + "name_ko": "값 단위", + "summary": "연료량은 L/시간이다." + }, + { + "key": "variables/mach_loss_coef/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + }, + { + "key": "variables/mach_loss_coef/unit", + "name_ko": "값 단위", + "summary": "손료계수는 1/시간이다." + }, + { + "key": "variables/mach_operator_map/note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "variables/mach_price/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + }, + { + "key": "variables/mach_price/unit", + "name_ko": "값 단위", + "summary": "취득가는 천원 단위다." + }, + { + "key": "variables/mach_rock_adj/unit", + "name_ko": "값 단위", + "summary": "할증은 %다." + } + ] + }, + { + "file_id": "machine_operating", + "path": "resources/data_cost_machine_operating/machine_operating_2026.json", + "name_ko": "기계 운전경비", + "summary": "건설품셈 8-4 에서 뽑은 운전경비 벌. mach_fuel_rate 가 다 차면 걷어낼 자리다.", + "kind": "base_value", + "tables": [ + { + "key": "records", + "name_ko": "기계 운전경비", + "summary": "기계마다 연료 종류·시간당 연료량·잡재료비·운전원.", + "shape": "list", + "rows": 92, + "columns": [ + { + "key": "fuel_kind", + "name_ko": "연료 종류", + "unit": "", + "visible": true + }, + { + "key": "fuel_liters_per_hour", + "name_ko": "시간당 연료량", + "unit": "L", + "visible": true + }, + { + "key": "machine_code", + "name_ko": "기계코드", + "unit": "", + "visible": true + }, + { + "key": "machine_name", + "name_ko": "기계명", + "unit": "", + "visible": true + }, + { + "key": "misc_material_percent", + "name_ko": "잡재료비", + "unit": "연료비의 %", + "visible": true + }, + { + "key": "operator_mapping_is_provisional", + "name_ko": "운전원 매칭 잠정 여부", + "unit": "", + "visible": true + }, + { + "key": "operator_occupation_code", + "name_ko": "운전원 직종코드", + "unit": "", + "visible": true + }, + { + "key": "operator_person_days", + "name_ko": "운전원", + "unit": "인/일", + "visible": true + }, + { + "key": "specification", + "name_ko": "규격", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "derived_from", + "name_ko": "무엇에서 나왔나", + "summary": "어느 벌을 풀어 만든 파생본인지." + }, + { + "key": "dropped_tables", + "name_ko": "못 읽어 버린 표", + "summary": "칸 수가 안 맞아 못 읽고 버린 원문 표." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "stats", + "name_ko": "집계", + "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것." + } + ] + }, + { + "file_id": "mat_price_public", + "path": "resources/data_cost_input_value/mat_price_public_2026-08-14.json", + "name_ko": "관급자재 단가", + "summary": "나라장터 시설공통자재 단가 벌. 마스터에서 가장 큰 표다.", + "kind": "base_value", + "tables": [ + { + "key": "excluded_named_groups", + "name_ko": "제외한 자재 묶음", + "summary": "이 벌에 안 실은 자재 묶음과 그 사유(철근·레미콘·아스콘).", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "group", + "name_ko": "묶음", + "unit": "", + "visible": true + }, + { + "key": "reason", + "name_ko": "사유", + "unit": "", + "visible": true + } + ] + }, + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/mat_price/records", + "name_ko": "관급자재 단가", + "summary": "물품마다 규격·단위·단가. 마스터에서 가장 큰 표다.", + "shape": "list", + "rows": 6999, + "columns": [ + { + "key": "item_code", + "name_ko": "물품코드", + "unit": "", + "visible": true + }, + { + "key": "classification_code", + "name_ko": "물품분류번호", + "unit": "", + "visible": true + }, + { + "key": "classification_name", + "name_ko": "물품분류명", + "unit": "", + "visible": true + }, + { + "key": "specification", + "name_ko": "규격", + "unit": "", + "visible": true + }, + { + "key": "unit", + "name_ko": "단위", + "unit": "", + "visible": true + }, + { + "key": "price_krw", + "name_ko": "단가", + "unit": "원", + "visible": true + }, + { + "key": "notice_datetime", + "name_ko": "공고 일시", + "unit": "", + "visible": true + }, + { + "key": "notice_number", + "name_ko": "공고번호", + "unit": "", + "visible": false + }, + { + "key": "business_division_code", + "name_ko": "사업구분 코드", + "unit": "", + "visible": false + }, + { + "key": "business_division_name", + "name_ko": "사업구분", + "unit": "", + "visible": true + }, + { + "key": "vat_basis", + "name_ko": "부가세 기준", + "unit": "", + "visible": true + }, + { + "key": "price_type", + "name_ko": "가격 종류", + "unit": "", + "visible": true + }, + { + "key": "delivery_condition", + "name_ko": "납품 조건", + "unit": "", + "visible": true + }, + { + "key": "field", + "name_ko": "분야", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "selection_policy", + "name_ko": "고르는 방침", + "summary": "같은 물품이 여러 번 공고되면 어느 것을 쓰는지." + }, + { + "key": "source_row_count", + "name_ko": "원천 줄 수", + "summary": "걸러 내기 전 원본 줄 수." + }, + { + "key": "variables/mat_price/key", + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + } + ] + }, + { + "file_id": "oil", + "path": "resources/data_cost_input_value/oil_2026-08-14.json", + "name_ko": "유가 — 전국평균", + "summary": "휘발유·경유 전국평균 단가.", + "kind": "base_value", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables", + "name_ko": "전국평균 유가", + "summary": "휘발유·경유 전국평균 단가. 키가 곧 유종이다.", + "shape": "map", + "rows": 2, + "columns": [ + { + "key": "value", + "name_ko": "단가", + "unit": "원/L", + "visible": true + }, + { + "key": "unit", + "name_ko": "단위", + "unit": "", + "visible": true + }, + { + "key": "scope", + "name_ko": "범위", + "unit": "", + "visible": true + }, + { + "key": "date", + "name_ko": "기준일", + "unit": "", + "visible": true + }, + { + "key": "source_product_code", + "name_ko": "원천 제품코드", + "unit": "", + "visible": false + }, + { + "key": "source_product_name", + "name_ko": "원천 제품명", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [] + }, + { + "file_id": "oil_regional", + "path": "resources/data_cost_input_value/oil_regional_2026-09-09.json", + "name_ko": "유가 — 시도별", + "summary": "품셈 8-1-7 5호 「유류가격은 해당지역의 가격으로 한다」를 따르려고 둔 시도별 단가.", + "kind": "base_value", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/oil_diesel/records", + "name_ko": "시도별 경유 단가", + "summary": "시도마다 경유 단가. 코드 00 은 전국이다.", + "shape": "list", + "rows": 17, + "columns": [ + { + "key": "sido_code", + "name_ko": "시도코드", + "unit": "", + "visible": true + }, + { + "key": "sido_name", + "name_ko": "시도명", + "unit": "", + "visible": true + }, + { + "key": "value", + "name_ko": "단가", + "unit": "원/L", + "visible": true + } + ] + }, + { + "key": "variables/oil_gasoline/records", + "name_ko": "시도별 휘발유 단가", + "summary": "시도마다 휘발유 단가. 코드 00 은 전국이다.", + "shape": "list", + "rows": 17, + "columns": [ + { + "key": "sido_code", + "name_ko": "시도코드", + "unit": "", + "visible": true + }, + { + "key": "sido_name", + "name_ko": "시도명", + "unit": "", + "visible": true + }, + { + "key": "value", + "name_ko": "단가", + "unit": "원/L", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "variables/oil_diesel/date", + "name_ko": "기준일", + "summary": "값이 선 날." + }, + { + "key": "variables/oil_diesel/scope", + "name_ko": "걸치는 범위", + "summary": "어디까지 쓰는 값인지." + }, + { + "key": "variables/oil_diesel/source_product_code", + "name_ko": "원천 제품코드", + "summary": "원천이 쓰는 제품 코드." + }, + { + "key": "variables/oil_diesel/source_product_name", + "name_ko": "원천 제품명", + "summary": "원천이 쓰는 제품 이름." + }, + { + "key": "variables/oil_diesel/unit", + "name_ko": "값 단위", + "summary": "단가는 원/L 이다." + }, + { + "key": "variables/oil_gasoline/date", + "name_ko": "기준일", + "summary": "값이 선 날." + }, + { + "key": "variables/oil_gasoline/scope", + "name_ko": "걸치는 범위", + "summary": "어디까지 쓰는 값인지." + }, + { + "key": "variables/oil_gasoline/source_product_code", + "name_ko": "원천 제품코드", + "summary": "원천이 쓰는 제품 코드." + }, + { + "key": "variables/oil_gasoline/source_product_name", + "name_ko": "원천 제품명", + "summary": "원천이 쓰는 제품 이름." + }, + { + "key": "variables/oil_gasoline/unit", + "name_ko": "값 단위", + "summary": "단가는 원/L 이다." + } + ] + }, + { + "file_id": "fx", + "path": "resources/data_cost_input_value/fx_2026-08-14.json", + "name_ko": "환율", + "summary": "한국은행 ECOS 일별 환율.", + "kind": "base_value", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables", + "name_ko": "환율", + "summary": "화폐마다 원으로 얼마인지. 키가 곧 화폐다(fx_usd·fx_jpy100…).", + "shape": "map", + "rows": 5, + "columns": [ + { + "key": "value", + "name_ko": "환율", + "unit": "원", + "visible": true + }, + { + "key": "unit", + "name_ko": "단위", + "unit": "", + "visible": true + }, + { + "key": "date", + "name_ko": "기준일", + "unit": "", + "visible": true + }, + { + "key": "source_item_code", + "name_ko": "원천 항목코드", + "unit": "", + "visible": false + } + ] + } + ], + "value_groups": [] + }, + { + "file_id": "rates", + "path": "resources/data_cost_input_value/rates_2026.json", + "name_ko": "제비율", + "summary": "법정경비·일반관리비·이윤·부가세 요율. 법이 정하고 해마다 바뀐다.", + "kind": "base_value", + "tables": [ + { + "key": "sources", + "name_ko": "출처", + "summary": "이 벌이 어느 원문을 읽어 섰는지.", + "shape": "list", + "rows": 2, + "columns": [ + { + "key": "path", + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "role", + "name_ko": "구실", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/rate_environment/all_work_types", + "name_ko": "환경보전비 요율 — 공사 종류별", + "summary": "원문이 주는 공사 종류 전 줄.", + "shape": "list", + "rows": 14, + "columns": [ + { + "key": "work_type", + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_environment/forest_road_candidates", + "name_ko": "환경보전비 요율 — 임도 후보", + "summary": "임도에 어느 줄을 쓸지 아직 안 고른 후보 둘.", + "shape": "list", + "rows": 2, + "columns": [ + { + "key": "work_type", + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_equipment_payment_guarantee/general_construction", + "name_ko": "건설기계 대여대금 지급보증 수수료율 — 종합건설", + "summary": "공사 종류마다.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "work_type", + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_equipment_payment_guarantee/specialty_construction", + "name_ko": "건설기계 대여대금 지급보증 수수료율 — 전문건설", + "summary": "공사 종류마다.", + "shape": "list", + "rows": 5, + "columns": [ + { + "key": "work_type", + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_goyong/brackets", + "name_ko": "고용보험료 요율", + "summary": "추정금액 등급마다 노무비에 곱하는 율.", + "shape": "list", + "rows": 8, + "columns": [ + { + "key": "grade", + "name_ko": "등급", + "unit": "", + "visible": true + }, + { + "key": "estimated_amount_bracket", + "name_ko": "추정금액 구간", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_indirect_labor/brackets", + "name_ko": "간접노무비 요율", + "summary": "직접공사비 구간 × 공사기간 × 공사 종류.", + "shape": "list", + "rows": 60, + "columns": [ + { + "key": "direct_cost_bracket", + "name_ko": "직접공사비 구간", + "unit": "", + "visible": true + }, + { + "key": "duration_bracket", + "name_ko": "공사기간 구간", + "unit": "", + "visible": true + }, + { + "key": "work_type", + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_other_expense/brackets", + "name_ko": "기타경비 요율", + "summary": "직접공사비 구간 × 공사기간 × 공사 종류.", + "shape": "list", + "rows": 60, + "columns": [ + { + "key": "direct_cost_bracket", + "name_ko": "직접공사비 구간", + "unit": "", + "visible": true + }, + { + "key": "duration_bracket", + "name_ko": "공사기간 구간", + "unit": "", + "visible": true + }, + { + "key": "work_type", + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_overhead/civil_landscape_industrial", + "name_ko": "일반관리비율 — 토목·조경·산업설비", + "summary": "추정가격 구간마다.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "estimated_price_bracket", + "name_ko": "추정가격 구간", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_overhead/specialty_electric_communication_fire_other", + "name_ko": "일반관리비율 — 전문·전기·통신·소방·기타", + "summary": "추정가격 구간마다.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "estimated_price_bracket", + "name_ko": "추정가격 구간", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_pension/annual_rates", + "name_ko": "국민연금 요율", + "summary": "연도마다 정해진 율.", + "shape": "list", + "rows": 8, + "columns": [ + { + "key": "year", + "name_ko": "연도", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_performance_guarantee_fee/brackets", + "name_ko": "공사이행보증 수수료", + "summary": "구간마다 율이 아니라 산식으로 준다.", + "shape": "list", + "rows": 5, + "columns": [ + { + "key": "direct_cost_bracket", + "name_ko": "직접공사비 구간", + "unit": "", + "visible": true + }, + { + "key": "formula", + "name_ko": "산식", + "unit": "", + "visible": true + } + ] + }, + { + "key": "variables/rate_profit/brackets", + "name_ko": "이윤율", + "summary": "추정가격 구간마다.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "estimated_price_bracket", + "name_ko": "추정가격 구간", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + }, + { + "key": "variables/rate_safety_pct/brackets", + "name_ko": "산업안전보건관리비 요율", + "summary": "대상액 구간 × 공사 종류마다 율과 기초액.", + "shape": "list", + "rows": 16, + "columns": [ + { + "key": "target_amount_bracket", + "name_ko": "대상액 구간", + "unit": "", + "visible": true + }, + { + "key": "work_type", + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + }, + { + "key": "base_amount_krw", + "name_ko": "기초액", + "unit": "원", + "visible": true + } + ] + }, + { + "key": "variables/rate_subcontract_payment_guarantee/brackets", + "name_ko": "하도급대금 지급보증 수수료율", + "summary": "추정가격 구간마다.", + "shape": "list", + "rows": 6, + "columns": [ + { + "key": "estimated_price_bracket", + "name_ko": "추정가격 구간", + "unit": "", + "visible": true + }, + { + "key": "rate_percent", + "name_ko": "요율", + "unit": "%", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "processing_rules", + "name_ko": "셈 규칙", + "summary": "요율만으로는 금액이 안 나온다 — 밑수를 어떻게 만들고 어디서 자르는지 적은 자리. 코드와 어긋나면 거울 시험이 잡는다." + }, + { + "key": "variables/rate_asbestos_contribution", + "name_ko": "석면피해구제 분담금", + "summary": "노무비에 곱하는 율." + }, + { + "key": "variables/rate_care", + "name_ko": "노인장기요양보험료", + "summary": "건강보험료 금액에 곱하는 율." + }, + { + "key": "variables/rate_environment/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_environment/forest_road_selection_status", + "name_ko": "임도 줄 고름 상태", + "summary": "임도에 어느 줄을 쓸지 고름이 끝났는지." + }, + { + "key": "variables/rate_environment/minimum_estimated_amount_krw", + "name_ko": "적용 하한 — 추정금액", + "summary": "이 금액에 못 미치면 줄이 안 선다(원)." + }, + { + "key": "variables/rate_equipment_payment_guarantee/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_equipment_payment_guarantee/base_note", + "name_ko": "밑수 비고", + "summary": "밑수를 그렇게 적은 까닭." + }, + { + "key": "variables/rate_goyong/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_health", + "name_ko": "건강보험료", + "summary": "직접노무비에 곱하는 율." + }, + { + "key": "variables/rate_indirect_labor/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_other_expense/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_overhead/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_pension/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_pension/rate_from_2033_percent", + "name_ko": "2033년 이후 요율", + "summary": "표 밖으로 나가는 해부터 쓰는 율(%)." + }, + { + "key": "variables/rate_performance_guarantee_fee/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_performance_guarantee_fee/typical_forest_road_applicability", + "name_ko": "임도에 걸리는지", + "summary": "보통 임도 규모에서 이 항목이 서는지." + }, + { + "key": "variables/rate_profit/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_retirement_mutual_aid", + "name_ko": "퇴직공제부금비", + "summary": "직접노무비에 곱하는 율. 추정금액 하한이 있다." + }, + { + "key": "variables/rate_safety_base", + "name_ko": "산업안전보건관리비 기초액", + "summary": "요율표 안에 함께 든 기초액이 걸리는 구간." + }, + { + "key": "variables/rate_safety_pct/base_rule", + "name_ko": "밑수 규칙", + "summary": "밑수를 고르는 방식." + }, + { + "key": "variables/rate_safety_pct/base_with_owner_supplied_material", + "name_ko": "대상액 — 관급자재 있을 때", + "summary": "고시가 준 두 식 가운데 작은 쪽." + }, + { + "key": "variables/rate_safety_pct/base_without_owner_supplied_material", + "name_ko": "대상액 — 관급자재 없을 때", + "summary": "재료비 + 직접노무비." + }, + { + "key": "variables/rate_safety_pct/manager_thresholds", + "name_ko": "안전관리자 선임 기준액", + "summary": "안전관리자를 둬야 하는 금액 문턱." + }, + { + "key": "variables/rate_safety_pct/minimum_total_construction_amount_krw", + "name_ko": "적용 하한 — 총공사금액", + "summary": "이 금액에 못 미치면 줄이 안 선다(원)." + }, + { + "key": "variables/rate_sanjae", + "name_ko": "산재보험료", + "summary": "노무비에 곱하는 율." + }, + { + "key": "variables/rate_subcontract_payment_guarantee/base", + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + { + "key": "variables/rate_vat", + "name_ko": "부가가치세", + "summary": "공급가액에 곱하는 율." + }, + { + "key": "variables/rate_wage_claim_contribution", + "name_ko": "임금채권보장 부담금", + "summary": "노무비에 곱하는 율." + } + ] + }, + { + "file_id": "basis_missing", + "path": "resources/data_work_item_master/basis_missing_2026-01-01.json", + "name_ko": "밑수 못 찾은 표", + "summary": "「10㎡당」 같은 기준 수량을 못 읽은 품셈 표 기록. 정본이 아니다.", + "kind": "byproduct", + "tables": [ + { + "key": "items", + "name_ko": "밑수 못 찾은 표", + "summary": "기준 수량을 못 읽은 품셈 표. 1 단위당으로 단정하면 곱셈이 틀린다.", + "shape": "list", + "rows": 115, + "columns": [ + { + "key": "pum_table_id", + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + { + "key": "pum_form", + "name_ko": "품셈 표 형태", + "unit": "", + "visible": true + }, + { + "key": "line", + "name_ko": "원문 줄 번호", + "unit": "", + "visible": false + } + ] + } + ], + "value_groups": [ + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + } + ] + }, + { + "file_id": "form_undetermined", + "path": "resources/data_work_item_master/form_undetermined_2026-01-01.json", + "name_ko": "형태 못 정한 표", + "summary": "품·소요량·계수 어느 형태인지 못 정한 품셈 표 기록. 정본이 아니다.", + "kind": "byproduct", + "tables": [ + { + "key": "items", + "name_ko": "형태 못 정한 표", + "summary": "품·소요량·계수 어느 형태인지 사람이 봐야 하는 표.", + "shape": "list", + "rows": 14, + "columns": [ + { + "key": "pum_table_id", + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + { + "key": "section", + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + { + "key": "headers", + "name_ko": "표 머리", + "unit": "", + "visible": true + }, + { + "key": "first_rows", + "name_ko": "첫 줄들", + "unit": "", + "visible": true + }, + { + "key": "reason", + "name_ko": "사유", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + } + ] + }, + { + "file_id": "resource_axis", + "path": "resources/data_cost_resource_axis/resource_axis_2026-01-01.json", + "name_ko": "공종별 자원 소요량(자원 축)", + "summary": "품셈 표에서 뽑아 낸 자원 줄. 정본은 품셈 원문이고 이것은 기록이다.", + "kind": "byproduct", + "tables": [ + { + "key": "rows", + "name_ko": "공종별 자원 줄", + "summary": "공종 하나에 드는 자원(품·기계) 한 줄씩. 품셈 표에서 뽑아 낸 기록이다.", + "shape": "list", + "rows": 418, + "columns": [ + { + "key": "alternative_amount", + "name_ko": "조건 시공 시 소요량", + "unit": "", + "visible": true + }, + { + "key": "amount", + "name_ko": "소요량", + "unit": "", + "visible": true + }, + { + "key": "amount_unit", + "name_ko": "소요량 단위", + "unit": "", + "visible": true + }, + { + "key": "group_ratio_pct", + "name_ko": "분류 딱지 배분율", + "unit": "%", + "visible": true + }, + { + "key": "pum_form", + "name_ko": "품셈 표 형태", + "unit": "", + "visible": true + }, + { + "key": "pum_table_id", + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + { + "key": "raw_row_index", + "name_ko": "원문 줄 차례", + "unit": "", + "visible": false + }, + { + "key": "resource_code", + "name_ko": "자원코드", + "unit": "", + "visible": true + }, + { + "key": "resource_kind", + "name_ko": "자원 갈래", + "unit": "", + "visible": true + }, + { + "key": "resource_name", + "name_ko": "자원명", + "unit": "", + "visible": true + }, + { + "key": "resource_spec", + "name_ko": "자원 규격", + "unit": "", + "visible": true + }, + { + "key": "variant", + "name_ko": "갈래", + "unit": "", + "visible": true + }, + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + { + "key": "stats", + "name_ko": "집계", + "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것." + } + ] + }, + { + "file_id": "unmatched", + "path": "resources/data_cost_resource_axis/unmatched_2026-01-01.json", + "name_ko": "못 맞춘 자원 이름", + "summary": "카탈로그에서 못 찾은 자원 이름 기록. 빈칸으로 두지 않으려고 모은다.", + "kind": "byproduct", + "tables": [ + { + "key": "rows", + "name_ko": "못 맞춘 줄", + "summary": "카탈로그에서 이름을 못 찾은 자원 줄과 그 사유.", + "shape": "list", + "rows": 497, + "columns": [ + { + "key": "cell", + "name_ko": "원문 칸", + "unit": "", + "visible": true + }, + { + "key": "pum_table_id", + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + { + "key": "reason", + "name_ko": "사유", + "unit": "", + "visible": true + }, + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + } + ] + }, + { + "file_id": "masonry_wet", + "path": "resources/library_structure/masonry_wet.json", + "name_ko": "돌쌓기(찰) 구조물 양식", + "summary": "구조물도 양식형 항목 첫 벌. 제원 칸·계수표·수량 줄·일위대가 틀이 한 벌로 있다.", + "kind": "seed", + "tables": [ + { + "key": "rows", + "name_ko": "수량 산출 줄", + "summary": "식 한 줄이 물량 하나. 갈 곳(일위대가·자재·참고)까지 줄마다 적는다.", + "shape": "list", + "rows": 15, + "columns": [ + { + "key": "seq", + "name_ko": "차례", + "unit": "", + "visible": true + }, + { + "key": "name", + "name_ko": "줄 이름", + "unit": "", + "visible": true + }, + { + "key": "spec", + "name_ko": "규격", + "unit": "", + "visible": true + }, + { + "key": "formula", + "name_ko": "산식", + "unit": "", + "visible": true + }, + { + "key": "formula_text", + "name_ko": "식 풀이", + "unit": "", + "visible": true + }, + { + "key": "unit", + "name_ko": "수량 단위", + "unit": "", + "visible": true + }, + { + "key": "destination", + "name_ko": "갈 곳", + "unit": "", + "visible": true + }, + { + "key": "rounding", + "name_ko": "반올림", + "unit": "", + "visible": true + }, + { + "key": "source", + "name_ko": "값이 오는 자리", + "unit": "", + "visible": true + }, + { + "key": "refs", + "name_ko": "참조 줄", + "unit": "", + "visible": true + }, + { + "key": "when", + "name_ko": "서는 조건", + "unit": "", + "visible": true + } + ] + }, + { + "key": "tables", + "name_ko": "계수표", + "summary": "뒷길이·돌 종류로 찾아 쓰는 원단위표 세 벌(고임돌·채움 콘크리트·돌 중량).", + "shape": "map", + "rows": 3, + "columns": [ + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + }, + { + "key": "keys", + "name_ko": "찾는 키", + "unit": "", + "visible": true + }, + { + "key": "columns", + "name_ko": "열", + "unit": "", + "visible": true + } + ] + }, + { + "key": "unit_price/rows", + "name_ko": "일위대가 줄", + "summary": "위 수량 줄 가운데 일위대가로 가는 것과 그 공종코드.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "seq", + "name_ko": "차례", + "unit": "", + "visible": true + }, + { + "key": "name", + "name_ko": "줄 이름", + "unit": "", + "visible": true + }, + { + "key": "from_row", + "name_ko": "가져오는 수량 줄", + "unit": "", + "visible": true + }, + { + "key": "work_item_code", + "name_ko": "공종코드", + "unit": "", + "visible": true + }, + { + "key": "variant_from", + "name_ko": "갈래 원본 칸", + "unit": "", + "visible": true + } + ] + }, + { + "key": "vars", + "name_ko": "제원 칸", + "summary": "사용자가 넣거나 고르는 값. 여기 값이 바뀌면 아래 수량 줄이 다시 선다.", + "shape": "map", + "rows": 15, + "columns": [ + { + "key": "label", + "name_ko": "칸 이름", + "unit": "", + "visible": true + }, + { + "key": "source", + "name_ko": "값이 오는 자리", + "unit": "", + "visible": true + }, + { + "key": "note", + "name_ko": "비고", + "unit": "", + "visible": true + }, + { + "key": "option", + "name_ko": "고르개 키", + "unit": "", + "visible": true + }, + { + "key": "default", + "name_ko": "기본값", + "unit": "", + "visible": true + }, + { + "key": "default_from", + "name_ko": "기본값이 오는 자리", + "unit": "", + "visible": true + }, + { + "key": "candidates", + "name_ko": "후보", + "unit": "", + "visible": true + }, + { + "key": "setting", + "name_ko": "프로젝트 설정 키", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "code", + "name_ko": "항목 코드", + "summary": "라이브러리 항목 코드." + }, + { + "key": "differs_from_engine", + "name_ko": "전개와 다른 자리", + "summary": "지금 돌아가는 전개와 이 양식이 갈리는 곳을 적어 둔 자리." + }, + { + "key": "item_kind", + "name_ko": "항목 갈래", + "summary": "양식형(form)인지 고정형인지." + }, + { + "key": "library_tier", + "name_ko": "라이브러리 단", + "summary": "프로그램·회사·개인 가운데 어느 단의 항목인지." + }, + { + "key": "name", + "name_ko": "항목 이름", + "summary": "화면에 보이는 이름." + }, + { + "key": "note", + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + { + "key": "type_id", + "name_ko": "구조물 종류 키", + "summary": "어느 구조물 종류에 붙는 양식인지." + }, + { + "key": "unit_price/note", + "name_ko": "일위대가 틀 설명", + "summary": "일위대가 줄을 어떻게 세우는지 적은 글." + } + ] + }, + { + "file_id": "manifest_cost_input_value", + "path": "resources/data_cost_input_value/_manifest.json", + "name_ko": "원가 입력변수 — 파일 장부", + "summary": "실린 파일·적용일·지문 목록. 브레인 갈래표 31 밖의 장부다.", + "kind": "byproduct", + "tables": [ + { + "key": "deferred", + "name_ko": "미확보 변수", + "summary": "원천을 아직 못 받아 비워 둔 변수와 그 사유.", + "shape": "list", + "rows": 4, + "columns": [ + { + "key": "variable", + "name_ko": "변수 키", + "unit": "", + "visible": true + }, + { + "key": "reason", + "name_ko": "사유", + "unit": "", + "visible": true + }, + { + "key": "source_group", + "name_ko": "원천 묶음", + "unit": "", + "visible": true + }, + { + "key": "source_needed", + "name_ko": "있어야 할 원천", + "unit": "", + "visible": true + }, + { + "key": "knowledge_ref", + "name_ko": "지식DB 자리", + "unit": "", + "visible": false + } + ] + }, + { + "key": "files", + "name_ko": "실린 파일", + "summary": "이 폴더에 든 파일과 적용 시작일·지문.", + "shape": "list", + "rows": 11, + "columns": [ + { + "key": "file", + "name_ko": "파일 이름", + "unit": "", + "visible": true + }, + { + "key": "dataset_id", + "name_ko": "자료 키", + "unit": "", + "visible": true + }, + { + "key": "effective_date", + "name_ko": "적용 시작일", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "size_bytes", + "name_ko": "파일 크기", + "unit": "byte", + "visible": false + } + ] + }, + { + "key": "program_entry", + "name_ko": "프로그램 입력 몫", + "summary": "자료로 못 받고 사용자나 프로그램이 넣어야 하는 원천.", + "shape": "list", + "rows": 2, + "columns": [ + { + "key": "source_group", + "name_ko": "원천 묶음", + "unit": "", + "visible": true + }, + { + "key": "responsibility", + "name_ko": "맡는 자리", + "unit": "", + "visible": true + } + ] + }, + { + "key": "selection_pending", + "name_ko": "채택 대기", + "summary": "원문이 여러 줄을 주어 어느 것을 쓸지 아직 안 고른 자리.", + "shape": "list", + "rows": 2, + "columns": [ + { + "key": "variable", + "name_ko": "변수 키", + "unit": "", + "visible": true + }, + { + "key": "detail", + "name_ko": "내용", + "unit": "", + "visible": true + }, + { + "key": "candidates", + "name_ko": "후보", + "unit": "", + "visible": true + } + ] + } + ], + "value_groups": [ + { + "key": "policy", + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + } + ] + }, + { + "file_id": "manifest_material_surcharge", + "path": "resources/data_material_surcharge/_manifest.json", + "name_ko": "재료 할증률 — 파일 장부", + "summary": "실린 파일·지문 목록. 브레인 갈래표 31 밖의 장부다.", + "kind": "byproduct", + "tables": [ + { + "key": "files", + "name_ko": "실린 파일", + "summary": "이 폴더에 든 파일과 지문.", + "shape": "list", + "rows": 1, + "columns": [ + { + "key": "file", + "name_ko": "파일 이름", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "size_bytes", + "name_ko": "파일 크기", + "unit": "byte", + "visible": false + } + ] + } + ], + "value_groups": [ + { + "key": "built_by", + "name_ko": "만든 자리", + "summary": "이 벌을 지은 코드나 사람." + } + ] + }, + { + "file_id": "manifest_work_item_master", + "path": "resources/data_work_item_master/_manifest.json", + "name_ko": "공종 마스터 — 파일 장부", + "summary": "실린 파일·지문 목록. 브레인 갈래표 31 밖의 장부다.", + "kind": "byproduct", + "tables": [ + { + "key": "files", + "name_ko": "실린 파일", + "summary": "이 폴더에 든 파일과 지문.", + "shape": "list", + "rows": 3, + "columns": [ + { + "key": "file", + "name_ko": "파일 이름", + "unit": "", + "visible": true + }, + { + "key": "sha256", + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + { + "key": "size_bytes", + "name_ko": "파일 크기", + "unit": "byte", + "visible": false + } + ] + } + ], + "value_groups": [ + { + "key": "built_by", + "name_ko": "만든 자리", + "summary": "이 벌을 지은 코드나 사람." + }, + { + "key": "source", + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + } + ] + } + ], + "columns": { + "about": { + "name_ko": "무엇에 대한 것인가", + "unit": "", + "visible": true + }, + "alias": { + "name_ko": "별칭 키", + "unit": "", + "visible": true + }, + "alt_condition": { + "name_ko": "다른 조건", + "unit": "", + "visible": true + }, + "alt_rate": { + "name_ko": "다른 조건 할증률", + "unit": "%", + "visible": true + }, + "alternative_amount": { + "name_ko": "조건 시공 시 소요량", + "unit": "", + "visible": true + }, + "amount": { + "name_ko": "소요량", + "unit": "", + "visible": true + }, + "amount_unit": { + "name_ko": "소요량 단위", + "unit": "", + "visible": true + }, + "annual_management_ratio": { + "name_ko": "연간관리비율", + "unit": "", + "visible": true + }, + "annual_standard_hours": { + "name_ko": "연간표준가동시간", + "unit": "시간", + "visible": true + }, + "axis": { + "name_ko": "축", + "unit": "", + "visible": true + }, + "base_amount_krw": { + "name_ko": "기초액", + "unit": "원", + "visible": true + }, + "basis": { + "name_ko": "근거", + "unit": "", + "visible": true + }, + "basis_source": { + "name_ko": "밑수 근거", + "unit": "", + "visible": true + }, + "basis_unit": { + "name_ko": "밑수 단위", + "unit": "", + "visible": true + }, + "basis_unit_note": { + "name_ko": "밑수 비고", + "unit": "", + "visible": true + }, + "billing_component": { + "name_ko": "내역 성분", + "unit": "", + "visible": true + }, + "billing_note": { + "name_ko": "내역 비고", + "unit": "", + "visible": true + }, + "bond_codes": { + "name_ko": "쌓기 방식별 공종코드", + "unit": "", + "visible": true + }, + "boulder_mixed_soil": { + "name_ko": "호박돌 섞인 토사 할증", + "unit": "%", + "visible": true + }, + "business_division_code": { + "name_ko": "사업구분 코드", + "unit": "", + "visible": false + }, + "business_division_name": { + "name_ko": "사업구분", + "unit": "", + "visible": true + }, + "candidates": { + "name_ko": "후보", + "unit": "", + "visible": true + }, + "carpenter": { + "name_ko": "건축목공", + "unit": "인/㎥", + "visible": true + }, + "cell": { + "name_ko": "원문 칸", + "unit": "", + "visible": true + }, + "class": { + "name_ko": "갈래", + "unit": "", + "visible": true + }, + "class_from": { + "name_ko": "갈래 원본 칸", + "unit": "", + "visible": true + }, + "class_note": { + "name_ko": "갈래 비고", + "unit": "", + "visible": true + }, + "classification_code": { + "name_ko": "물품분류번호", + "unit": "", + "visible": true + }, + "classification_name": { + "name_ko": "물품분류명", + "unit": "", + "visible": true + }, + "code": { + "name_ko": "자원코드", + "unit": "", + "visible": true + }, + "columns": { + "name_ko": "열", + "unit": "", + "visible": true + }, + "compare": { + "name_ko": "견줌", + "unit": "", + "visible": true + }, + "components": { + "name_ko": "구성 물량", + "unit": "", + "visible": true + }, + "condition": { + "name_ko": "조건", + "unit": "", + "visible": true + }, + "daily_area_m2": { + "name_ko": "1일 시공량", + "unit": "㎡", + "visible": true + }, + "daily_wage_krw": { + "name_ko": "일 노임", + "unit": "원", + "visible": true + }, + "dataset_id": { + "name_ko": "자료 키", + "unit": "", + "visible": true + }, + "date": { + "name_ko": "기준일", + "unit": "", + "visible": true + }, + "default": { + "name_ko": "기본값", + "unit": "", + "visible": true + }, + "default_from": { + "name_ko": "기본값이 오는 자리", + "unit": "", + "visible": true + }, + "delivery_condition": { + "name_ko": "납품 조건", + "unit": "", + "visible": true + }, + "depreciation_coefficient_1e_minus_7": { + "name_ko": "원문 상각비계수", + "unit": "10^-7", + "visible": false + }, + "depreciation_ratio": { + "name_ko": "상각비율", + "unit": "", + "visible": true + }, + "destination": { + "name_ko": "갈 곳", + "unit": "", + "visible": true + }, + "detail": { + "name_ko": "내용", + "unit": "", + "visible": true + }, + "direct_cost_bracket": { + "name_ko": "직접공사비 구간", + "unit": "", + "visible": true + }, + "doc": { + "name_ko": "문서", + "unit": "", + "visible": true + }, + "duplicate_group": { + "name_ko": "원문 중복 묶음", + "unit": "", + "visible": true + }, + "duplicate_index": { + "name_ko": "중복 차례", + "unit": "", + "visible": true + }, + "duration_bracket": { + "name_ko": "공사기간 구간", + "unit": "", + "visible": true + }, + "economic_life_hours": { + "name_ko": "내용시간", + "unit": "시간", + "visible": true + }, + "effect": { + "name_ko": "바뀌면 생기는 차이", + "unit": "", + "visible": true + }, + "effective_date": { + "name_ko": "적용 시작일", + "unit": "", + "visible": true + }, + "entries": { + "name_ko": "줄 묶음", + "unit": "", + "visible": true + }, + "equipment": { + "name_ko": "운반 수단", + "unit": "", + "visible": true + }, + "estimated_amount_bracket": { + "name_ko": "추정금액 구간", + "unit": "", + "visible": true + }, + "estimated_price_bracket": { + "name_ko": "추정가격 구간", + "unit": "", + "visible": true + }, + "examples": { + "name_ko": "원문 예시", + "unit": "", + "visible": true + }, + "exception": { + "name_ko": "예외", + "unit": "", + "visible": true + }, + "exclusion": { + "name_ko": "제외", + "unit": "", + "visible": true + }, + "field": { + "name_ko": "분야", + "unit": "", + "visible": true + }, + "file": { + "name_ko": "파일 이름", + "unit": "", + "visible": true + }, + "first_rows": { + "name_ko": "첫 줄들", + "unit": "", + "visible": true + }, + "form": { + "name_ko": "형식", + "unit": "", + "visible": true + }, + "form_codes": { + "name_ko": "형식별 공종코드", + "unit": "", + "visible": true + }, + "formula": { + "name_ko": "산식", + "unit": "", + "visible": true + }, + "formula_text": { + "name_ko": "식 풀이", + "unit": "", + "visible": true + }, + "from": { + "name_ko": "원래 이름", + "unit": "", + "visible": true + }, + "from_row": { + "name_ko": "가져오는 수량 줄", + "unit": "", + "visible": true + }, + "fuel_kind": { + "name_ko": "연료 종류", + "unit": "", + "visible": true + }, + "fuel_liters_per_hour": { + "name_ko": "시간당 연료량", + "unit": "L", + "visible": true + }, + "fuel_rate_l_per_hour": { + "name_ko": "시간당 연료량", + "unit": "L", + "visible": true + }, + "fuel_type": { + "name_ko": "연료 종류", + "unit": "", + "visible": true + }, + "grade": { + "name_ko": "등급", + "unit": "", + "visible": true + }, + "ground": { + "name_ko": "지반 갈래", + "unit": "", + "visible": true + }, + "group": { + "name_ko": "묶음", + "unit": "", + "visible": true + }, + "group_ratio_pct": { + "name_ko": "분류 딱지 배분율", + "unit": "%", + "visible": true + }, + "guard": { + "name_ko": "가드", + "unit": "", + "visible": true + }, + "headers": { + "name_ko": "표 머리", + "unit": "", + "visible": true + }, + "hours_per_day": { + "name_ko": "1일 근로시간", + "unit": "시간", + "visible": true + }, + "in_bill": { + "name_ko": "내역에 싣나", + "unit": "", + "visible": true + }, + "industry": { + "name_ko": "업종", + "unit": "", + "visible": true + }, + "item": { + "name_ko": "항목", + "unit": "", + "visible": true + }, + "item_code": { + "name_ko": "물품코드", + "unit": "", + "visible": true + }, + "items": { + "name_ko": "항목 묶음", + "unit": "", + "visible": true + }, + "key": { + "name_ko": "키", + "unit": "", + "visible": true + }, + "keys": { + "name_ko": "찾는 키", + "unit": "", + "visible": true + }, + "kind": { + "name_ko": "갈래", + "unit": "", + "visible": true + }, + "knowledge_ref": { + "name_ko": "지식DB 자리", + "unit": "", + "visible": false + }, + "label": { + "name_ko": "칸 이름", + "unit": "", + "visible": true + }, + "laborer": { + "name_ko": "보통인부", + "unit": "인/㎥", + "visible": true + }, + "leaf_codes": { + "name_ko": "잎 코드", + "unit": "", + "visible": true + }, + "leaf_from": { + "name_ko": "잎 원본 칸", + "unit": "", + "visible": true + }, + "leaf_note": { + "name_ko": "잎 비고", + "unit": "", + "visible": true + }, + "level": { + "name_ko": "단계", + "unit": "", + "visible": true + }, + "line": { + "name_ko": "원문 줄 번호", + "unit": "", + "visible": false + }, + "listed_condition": { + "name_ko": "원문이 못박은 조건", + "unit": "", + "visible": true + }, + "listed_in": { + "name_ko": "실린 자리", + "unit": "", + "visible": true + }, + "loss_coefficient_per_hour": { + "name_ko": "시간당 손료계수", + "unit": "", + "visible": true + }, + "machine_code": { + "name_ko": "기계코드", + "unit": "", + "visible": true + }, + "machine_group": { + "name_ko": "기계 묶음", + "unit": "", + "visible": true + }, + "machine_name": { + "name_ko": "기계명", + "unit": "", + "visible": true + }, + "maintenance_coefficient_1e_minus_7": { + "name_ko": "원문 정비비계수", + "unit": "10^-7", + "visible": false + }, + "maintenance_ratio": { + "name_ko": "정비비율", + "unit": "", + "visible": true + }, + "management_coefficient_1e_minus_7": { + "name_ko": "원문 관리비계수", + "unit": "10^-7", + "visible": false + }, + "master_name": { + "name_ko": "마스터 공종명", + "unit": "", + "visible": true + }, + "matched": { + "name_ko": "걸린 원문 예시", + "unit": "", + "visible": true + }, + "matched_example": { + "name_ko": "걸린 원문 예시", + "unit": "", + "visible": true + }, + "material": { + "name_ko": "자재명", + "unit": "", + "visible": true + }, + "max": { + "name_ko": "상한", + "unit": "", + "visible": true + }, + "max_cm": { + "name_ko": "상한", + "unit": "㎝", + "visible": true + }, + "min": { + "name_ko": "하한", + "unit": "", + "visible": true + }, + "misc_material_percent": { + "name_ko": "잡재료비", + "unit": "연료비의 %", + "visible": true + }, + "misc_material_percent_of_fuel": { + "name_ko": "잡재료비", + "unit": "연료비의 %", + "visible": true + }, + "mismatch_kind": { + "name_ko": "어긋남 갈래", + "unit": "", + "visible": true + }, + "mismatch_reason": { + "name_ko": "어긋남 사유", + "unit": "", + "visible": true + }, + "name": { + "name_ko": "이름", + "unit": "", + "visible": true + }, + "needs": { + "name_ko": "있어야 열리는 것", + "unit": "", + "visible": true + }, + "note": { + "name_ko": "비고", + "unit": "", + "visible": true + }, + "notes": { + "name_ko": "비고 묶음", + "unit": "", + "visible": true + }, + "notice_datetime": { + "name_ko": "공고 일시", + "unit": "", + "visible": true + }, + "notice_number": { + "name_ko": "공고번호", + "unit": "", + "visible": false + }, + "number": { + "name_ko": "품셈 번호", + "unit": "", + "visible": true + }, + "observed": { + "name_ko": "관측값", + "unit": "", + "visible": true + }, + "occupation_code": { + "name_ko": "직종코드", + "unit": "", + "visible": true + }, + "occupation_name": { + "name_ko": "직종명", + "unit": "", + "visible": true + }, + "operator_mapping_is_provisional": { + "name_ko": "운전원 매칭 잠정 여부", + "unit": "", + "visible": true + }, + "operator_occupation_code": { + "name_ko": "운전원 직종코드", + "unit": "", + "visible": true + }, + "operator_person_days": { + "name_ko": "운전원", + "unit": "인/일", + "visible": true + }, + "operator_person_per_day": { + "name_ko": "운전원", + "unit": "인/일", + "visible": true + }, + "option": { + "name_ko": "고르개 키", + "unit": "", + "visible": true + }, + "our_choice": { + "name_ko": "우리가 고른 쪽", + "unit": "", + "visible": true + }, + "our_usage": { + "name_ko": "우리 쓰임", + "unit": "", + "visible": true + }, + "outside_note": { + "name_ko": "묶음 밖 비고", + "unit": "", + "visible": true + }, + "parent_code": { + "name_ko": "상위 공종코드", + "unit": "", + "visible": true + }, + "parent_mode": { + "name_ko": "하위 고르는 방식", + "unit": "", + "visible": true + }, + "parse_method": { + "name_ko": "읽은 방법", + "unit": "", + "visible": false + }, + "parts": { + "name_ko": "조각", + "unit": "", + "visible": true + }, + "parts_note": { + "name_ko": "조각 비고", + "unit": "", + "visible": true + }, + "path": { + "name_ko": "원문 자리", + "unit": "", + "visible": true + }, + "payload_density_note": { + "name_ko": "적재 단위중량 비고", + "unit": "", + "visible": true + }, + "placing_note": { + "name_ko": "타설 비고", + "unit": "", + "visible": true + }, + "price_krw": { + "name_ko": "단가", + "unit": "원", + "visible": true + }, + "price_thousand_krw": { + "name_ko": "취득가", + "unit": "천원", + "visible": true + }, + "price_type": { + "name_ko": "가격 종류", + "unit": "", + "visible": true + }, + "provisional": { + "name_ko": "잠정 여부", + "unit": "", + "visible": true + }, + "pum_edition": { + "name_ko": "품셈 판", + "unit": "", + "visible": true + }, + "pum_form": { + "name_ko": "품셈 표 형태", + "unit": "", + "visible": true + }, + "pum_table_id": { + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + "pumsem": { + "name_ko": "어느 품셈", + "unit": "", + "visible": true + }, + "quote": { + "name_ko": "원문 인용", + "unit": "", + "visible": true + }, + "rate": { + "name_ko": "할증률", + "unit": "%", + "visible": true + }, + "rate_percent": { + "name_ko": "요율", + "unit": "%", + "visible": true + }, + "raw_row_index": { + "name_ko": "원문 줄 차례", + "unit": "", + "visible": false + }, + "reason": { + "name_ko": "사유", + "unit": "", + "visible": true + }, + "refs": { + "name_ko": "참조 줄", + "unit": "", + "visible": true + }, + "reliability": { + "name_ko": "신뢰도 기호", + "unit": "", + "visible": true + }, + "resource_code": { + "name_ko": "자원코드", + "unit": "", + "visible": true + }, + "resource_kind": { + "name_ko": "자원 갈래", + "unit": "", + "visible": true + }, + "resource_name": { + "name_ko": "자원명", + "unit": "", + "visible": true + }, + "resource_spec": { + "name_ko": "자원 규격", + "unit": "", + "visible": true + }, + "responsibility": { + "name_ko": "맡는 자리", + "unit": "", + "visible": true + }, + "reuse_count": { + "name_ko": "사용횟수", + "unit": "회", + "visible": true + }, + "rock_work": { + "name_ko": "암 작업 할증", + "unit": "%", + "visible": true + }, + "role": { + "name_ko": "구실", + "unit": "", + "visible": true + }, + "rounding": { + "name_ko": "반올림", + "unit": "", + "visible": true + }, + "rows": { + "name_ko": "표 줄", + "unit": "", + "visible": true + }, + "rule": { + "name_ko": "별도 규정", + "unit": "", + "visible": true + }, + "rule_id": { + "name_ko": "규칙 키", + "unit": "", + "visible": true + }, + "scope": { + "name_ko": "걸치는 범위", + "unit": "", + "visible": true + }, + "secondary_axes": { + "name_ko": "둘째 갈래 축", + "unit": "", + "visible": true + }, + "secondary_axes_note": { + "name_ko": "둘째 갈래 비고", + "unit": "", + "visible": true + }, + "section": { + "name_ko": "품셈 절", + "unit": "", + "visible": true + }, + "selection": { + "name_ko": "채택 여부", + "unit": "", + "visible": true + }, + "seq": { + "name_ko": "차례", + "unit": "", + "visible": true + }, + "setting": { + "name_ko": "프로젝트 설정 키", + "unit": "", + "visible": true + }, + "sha256": { + "name_ko": "파일 지문(SHA-256)", + "unit": "", + "visible": false + }, + "sido_code": { + "name_ko": "시도코드", + "unit": "", + "visible": true + }, + "sido_name": { + "name_ko": "시도명", + "unit": "", + "visible": true + }, + "size_bytes": { + "name_ko": "파일 크기", + "unit": "byte", + "visible": false + }, + "soil_type": { + "name_ko": "토질", + "unit": "", + "visible": true + }, + "sort_order": { + "name_ko": "정렬 차례", + "unit": "", + "visible": false + }, + "source": { + "name_ko": "출처", + "unit": "", + "visible": true + }, + "source_coefficient_1e_minus_7": { + "name_ko": "원문 손료계수", + "unit": "10^-7", + "visible": false + }, + "source_file": { + "name_ko": "원문 파일", + "unit": "", + "visible": false + }, + "source_flag": { + "name_ko": "원문 표시", + "unit": "", + "visible": true + }, + "source_group": { + "name_ko": "원천 묶음", + "unit": "", + "visible": true + }, + "source_item_code": { + "name_ko": "원천 항목코드", + "unit": "", + "visible": false + }, + "source_needed": { + "name_ko": "있어야 할 원천", + "unit": "", + "visible": true + }, + "source_note": { + "name_ko": "원천 비고", + "unit": "", + "visible": true + }, + "source_product_code": { + "name_ko": "원천 제품코드", + "unit": "", + "visible": false + }, + "source_product_name": { + "name_ko": "원천 제품명", + "unit": "", + "visible": true + }, + "source_section": { + "name_ko": "원문 절", + "unit": "", + "visible": true + }, + "sources": { + "name_ko": "출처", + "unit": "", + "visible": true + }, + "spec": { + "name_ko": "규격", + "unit": "", + "visible": true + }, + "specification": { + "name_ko": "규격", + "unit": "", + "visible": true + }, + "status": { + "name_ko": "공표 상태", + "unit": "", + "visible": true + }, + "steps": { + "name_ko": "단계 합산 구성", + "unit": "", + "visible": true + }, + "steps_basis": { + "name_ko": "단계 합산 근거", + "unit": "", + "visible": true + }, + "table_id": { + "name_ko": "품셈 표 번호", + "unit": "", + "visible": true + }, + "tables": { + "name_ko": "딸린 품셈 표", + "unit": "", + "visible": true + }, + "target_amount_bracket": { + "name_ko": "대상액 구간", + "unit": "", + "visible": true + }, + "to": { + "name_ko": "이을 코드", + "unit": "", + "visible": true + }, + "type_id": { + "name_ko": "구조물 종류 키", + "unit": "", + "visible": true + }, + "unit": { + "name_ko": "단위", + "unit": "", + "visible": true + }, + "value": { + "name_ko": "값", + "unit": "", + "visible": true + }, + "variable": { + "name_ko": "변수 키", + "unit": "", + "visible": true + }, + "variant": { + "name_ko": "갈래", + "unit": "", + "visible": true + }, + "variant_axis": { + "name_ko": "갈래 축", + "unit": "", + "visible": true + }, + "variant_from": { + "name_ko": "갈래 원본 칸", + "unit": "", + "visible": true + }, + "variant_keys": { + "name_ko": "갈래 키", + "unit": "", + "visible": true + }, + "variant_missing_reason": { + "name_ko": "갈래 미선택 사유", + "unit": "", + "visible": true + }, + "variant_note": { + "name_ko": "갈래 비고", + "unit": "", + "visible": true + }, + "variant_template": { + "name_ko": "갈래 틀", + "unit": "", + "visible": true + }, + "variant_value": { + "name_ko": "갈래 값", + "unit": "", + "visible": true + }, + "variation_coefficient": { + "name_ko": "변동계수", + "unit": "%", + "visible": true + }, + "vat_basis": { + "name_ko": "부가세 기준", + "unit": "", + "visible": true + }, + "via": { + "name_ko": "거쳐 온 자리", + "unit": "", + "visible": true + }, + "when": { + "name_ko": "서는 조건", + "unit": "", + "visible": true + }, + "where": { + "name_ko": "어디서 갈리나", + "unit": "", + "visible": true + }, + "why": { + "name_ko": "까닭", + "unit": "", + "visible": true + }, + "why_not_applied": { + "name_ko": "안 쓰는 사유", + "unit": "", + "visible": true + }, + "work_item_code": { + "name_ko": "공종코드", + "unit": "", + "visible": true + }, + "work_type": { + "name_ko": "공사 종류", + "unit": "", + "visible": true + }, + "year": { + "name_ko": "연도", + "unit": "", + "visible": true + }, + "성토": { + "name_ko": "성토부 경사", + "unit": "1:n", + "visible": true + }, + "절토": { + "name_ko": "절토부 경사", + "unit": "1:n", + "visible": true + } + }, + "column_overrides": { + "coef/max": { + "name_ko": "계수 상한", + "unit": "", + "visible": true + }, + "coef/min": { + "name_ko": "계수 하한", + "unit": "", + "visible": true + }, + "fx/value": { + "name_ko": "환율", + "unit": "원", + "visible": true + }, + "masonry_wet/name": { + "name_ko": "줄 이름", + "unit": "", + "visible": true + }, + "masonry_wet/source": { + "name_ko": "값이 오는 자리", + "unit": "", + "visible": true + }, + "masonry_wet/unit": { + "name_ko": "수량 단위", + "unit": "", + "visible": true + }, + "oil/scope": { + "name_ko": "범위", + "unit": "", + "visible": true + }, + "oil/value": { + "name_ko": "단가", + "unit": "원/L", + "visible": true + }, + "oil_regional/value": { + "name_ko": "단가", + "unit": "원/L", + "visible": true + }, + "resource_catalog_ext/source": { + "name_ko": "어디서 왔나", + "unit": "", + "visible": true + }, + "structure_unit_observed/key": { + "name_ko": "규칙·물음 키", + "unit": "", + "visible": true + }, + "structure_unit_observed/section": { + "name_ko": "원본 절", + "unit": "", + "visible": true + }, + "structure_unit_observed/source": { + "name_ko": "원천", + "unit": "", + "visible": true + }, + "structure_unit_observed/spec": { + "name_ko": "제원", + "unit": "", + "visible": true + } + }, + "value_keys": { + "application_status": { + "name_ko": "적용 상태", + "summary": "쓰려면 무엇이 더 정해져야 하는지." + }, + "base": { + "name_ko": "밑수", + "summary": "이 요율을 곱하는 대상." + }, + "base_note": { + "name_ko": "밑수 비고", + "summary": "밑수를 그렇게 적은 까닭." + }, + "base_rule": { + "name_ko": "밑수 규칙", + "summary": "밑수를 고르는 방식." + }, + "base_with_owner_supplied_material": { + "name_ko": "대상액 — 관급자재 있을 때", + "summary": "고시가 준 두 식 가운데 작은 쪽." + }, + "base_without_owner_supplied_material": { + "name_ko": "대상액 — 관급자재 없을 때", + "summary": "재료비 + 직접노무비." + }, + "basis_unit": { + "name_ko": "밑수", + "summary": "값이 무엇 하나당인지." + }, + "built_by": { + "name_ko": "만든 자리", + "summary": "이 벌을 지은 코드나 사람." + }, + "date": { + "name_ko": "기준일", + "summary": "값이 선 날." + }, + "derived_from": { + "name_ko": "무엇에서 나왔나", + "summary": "어느 벌을 풀어 만든 파생본인지." + }, + "duplicate_application_prohibited": { + "name_ko": "중복 적용 금지", + "summary": "두 자리에 걸면 두 번 세게 된다는 표시." + }, + "duplicate_note": { + "name_ko": "원문 중복 비고", + "summary": "원문이 같은 줄을 두 번 실어 어느 줄을 쓸지 남은 자리." + }, + "fallback": { + "name_ko": "미지정일 때", + "summary": "사용자가 안 고른 경우 쓰는 한 벌." + }, + "forest_road_selection_status": { + "name_ko": "임도 줄 고름 상태", + "summary": "임도에 어느 줄을 쓸지 고름이 끝났는지." + }, + "items": { + "name_ko": "항목", + "summary": "이 벌이 담는 항목 묶음." + }, + "key": { + "name_ko": "줄을 가르는 칸", + "summary": "이 표에서 줄 하나를 집는 칸 이름." + }, + "manager_thresholds": { + "name_ko": "안전관리자 선임 기준액", + "summary": "안전관리자를 둬야 하는 금액 문턱." + }, + "master": { + "name_ko": "마스터 자리", + "summary": "공종 코드를 읽어 오는 마스터 파일." + }, + "material_unit_note": { + "name_ko": "자재 밑수 비고", + "summary": "자재 환산을 어느 창이 하는지." + }, + "minimum_estimated_amount_krw": { + "name_ko": "적용 하한 — 추정금액", + "summary": "이 금액에 못 미치면 줄이 안 선다(원)." + }, + "minimum_total_construction_amount_krw": { + "name_ko": "적용 하한 — 총공사금액", + "summary": "이 금액에 못 미치면 줄이 안 선다(원)." + }, + "normalization_status": { + "name_ko": "정돈 상태", + "summary": "자원 코드 정돈이 끝났는지." + }, + "not_found": { + "name_ko": "못 찾은 것", + "summary": "두 품셈을 다 뒤졌으나 이름이 없는 것." + }, + "not_here": { + "name_ko": "이 표가 안 다루는 것", + "summary": "헷갈리기 쉬운 이웃 값을 여기 안 둔다고 적어 둔 자리." + }, + "note": { + "name_ko": "설명", + "summary": "이 벌이 무엇이고 어떻게 쓰는지 적은 글." + }, + "option_key": { + "name_ko": "고르개 키", + "summary": "화면 고르개가 쓰는 저장 칸 이름." + }, + "option_note": { + "name_ko": "고르개 비고", + "summary": "고르개를 만들 때 챙길 것." + }, + "pending_user": { + "name_ko": "사용자 확정 대기", + "summary": "아직 사람이 답해야 닫히는 물음." + }, + "policy": { + "name_ko": "방침", + "summary": "이 벌을 다룰 때 지킬 것 — 지어내지 않기·빈칸 안 두기 같은 것." + }, + "rank": { + "name_ko": "우선순위", + "summary": "원문끼리 어긋날 때 어느 쪽을 먼저 보는지." + }, + "rate_from_2033_percent": { + "name_ko": "2033년 이후 요율", + "summary": "표 밖으로 나가는 해부터 쓰는 율(%)." + }, + "reliability_note": { + "name_ko": "신뢰도 기호 뜻풀이", + "summary": "노임 표의 * · ** 가 무엇을 뜻하는지." + }, + "representation": { + "name_ko": "담은 꼴", + "summary": "원문 표를 어떤 꼴로 담았는지." + }, + "reuse_note": { + "name_ko": "사용횟수 비고", + "summary": "닮은 두 사용횟수를 하나로 잇지 않는 까닭." + }, + "scope": { + "name_ko": "걸치는 범위", + "summary": "어디까지 쓰는 값인지." + }, + "source": { + "name_ko": "출처", + "summary": "어느 원문에서 왔는지." + }, + "source_product_code": { + "name_ko": "원천 제품코드", + "summary": "원천이 쓰는 제품 코드." + }, + "source_product_name": { + "name_ko": "원천 제품명", + "summary": "원천이 쓰는 제품 이름." + }, + "stats": { + "name_ko": "집계", + "summary": "몇 줄이 섰고 몇 줄이 빠졌는지 센 것." + }, + "steps_m": { + "name_ko": "직고 칸", + "summary": "표가 갈리는 높이 경계(m)." + }, + "typical_forest_road_applicability": { + "name_ko": "임도에 걸리는지", + "summary": "보통 임도 규모에서 이 항목이 서는지." + }, + "unit": { + "name_ko": "값 단위", + "summary": "이 벌의 값이 무엇 단위인지." + }, + "unit_conversion": { + "name_ko": "단위 환산", + "summary": "단가 단위와 원단위 단위가 달라 맞추는 값." + }, + "why": { + "name_ko": "까닭", + "summary": "이 벌을 왜 따로 두는지." + } + }, + "value_overrides": { + "coef::variables/rate_tool": { + "name_ko": "공구손료율", + "summary": "주요 재료비에 곱하는 공구손료 율(하한·상한). 어느 값을 쓸지는 고름이 필요하다." + }, + "coef::variables/surcharge_labor/unit": { + "name_ko": "값 단위", + "summary": "할증은 %다." + }, + "coef::variables/surcharge_mat/unit": { + "name_ko": "값 단위", + "summary": "할증은 %다." + }, + "formwork_reuse::reuse_ratio_pct": { + "name_ko": "사용횟수별 기준수량 비율", + "summary": "품셈 12-4 — 일위대가 재료비에 걸린다. B08 이 곱하면 이중계상이다." + }, + "formwork_reuse::shoring": { + "name_ko": "동바리", + "summary": "강관동바리가 어느 구조물에 서는지." + }, + "fx::variables/fx_cny": { + "name_ko": "환율 — 중국 위안", + "summary": "1 CNY 가 몇 원인지." + }, + "fx::variables/fx_eur": { + "name_ko": "환율 — 유로", + "summary": "1 EUR 가 몇 원인지." + }, + "fx::variables/fx_gbp": { + "name_ko": "환율 — 영국 파운드", + "summary": "1 GBP 가 몇 원인지." + }, + "fx::variables/fx_jpy100": { + "name_ko": "환율 — 일본 엔 100", + "summary": "100 JPY 가 몇 원인지." + }, + "fx::variables/fx_usd": { + "name_ko": "환율 — 미국 달러", + "summary": "1 USD 가 몇 원인지." + }, + "labor_const::variables/aliases": { + "name_ko": "노임 별칭", + "summary": "코드 대신 쓰는 별칭 이름표(labor_1002 = 보통인부)." + }, + "mach_base::parse_audit": { + "name_ko": "읽기 점검", + "summary": "취득가 표에서 못 읽은 줄이 있는지 적어 둔 자리." + }, + "mach_base::variables/mach_fuel_rate/unit": { + "name_ko": "값 단위", + "summary": "연료량은 L/시간이다." + }, + "mach_base::variables/mach_loss_coef/unit": { + "name_ko": "값 단위", + "summary": "손료계수는 1/시간이다." + }, + "mach_base::variables/mach_price/unit": { + "name_ko": "값 단위", + "summary": "취득가는 천원 단위다." + }, + "mach_base::variables/mach_rock_adj/unit": { + "name_ko": "값 단위", + "summary": "할증은 %다." + }, + "mach_price::unit": { + "name_ko": "값 단위", + "summary": "취득가는 천원 단위다." + }, + "machine_operating::dropped_tables": { + "name_ko": "못 읽어 버린 표", + "summary": "칸 수가 안 맞아 못 읽고 버린 원문 표." + }, + "masonry_back_length::table_cm": { + "name_ko": "뒷길이 범위표", + "summary": "메·찰마다 직고 칸별 뒷길이 하한·상한(㎝)." + }, + "masonry_class::bond": { + "name_ko": "쌓기 방식", + "summary": "메쌓기·찰쌓기로 공종코드가 갈린다." + }, + "masonry_class::boulder_diameter": { + "name_ko": "돌 직경 갈래", + "summary": "큰돌쌓기 — 저장 제원 stone_cm 으로 갈린다." + }, + "masonry_class::face_slope": { + "name_ko": "전면 기울기", + "summary": "형식마다 정해진 1:n. 코드 기본 0.3 이 여기서 왔다." + }, + "masonry_wet::code": { + "name_ko": "항목 코드", + "summary": "라이브러리 항목 코드." + }, + "masonry_wet::differs_from_engine": { + "name_ko": "전개와 다른 자리", + "summary": "지금 돌아가는 전개와 이 양식이 갈리는 곳을 적어 둔 자리." + }, + "masonry_wet::item_kind": { + "name_ko": "항목 갈래", + "summary": "양식형(form)인지 고정형인지." + }, + "masonry_wet::library_tier": { + "name_ko": "라이브러리 단", + "summary": "프로그램·회사·개인 가운데 어느 단의 항목인지." + }, + "masonry_wet::name": { + "name_ko": "항목 이름", + "summary": "화면에 보이는 이름." + }, + "masonry_wet::type_id": { + "name_ko": "구조물 종류 키", + "summary": "어느 구조물 종류에 붙는 양식인지." + }, + "masonry_wet::unit_price/note": { + "name_ko": "일위대가 틀 설명", + "summary": "일위대가 줄을 어떻게 세우는지 적은 글." + }, + "mat_price_public::selection_policy": { + "name_ko": "고르는 방침", + "summary": "같은 물품이 여러 번 공고되면 어느 것을 쓰는지." + }, + "mat_price_public::source_row_count": { + "name_ko": "원천 줄 수", + "summary": "걸러 내기 전 원본 줄 수." + }, + "material_surcharge::observed_practice": { + "name_ko": "실무 관측", + "summary": "실무 집계에서 본 할증률. 참고이지 기본값이 아니다." + }, + "oil::variables/oil_diesel": { + "name_ko": "경유 단가", + "summary": "전국평균 경유 값(원/L)." + }, + "oil::variables/oil_gasoline": { + "name_ko": "휘발유 단가", + "summary": "전국평균 휘발유 값(원/L)." + }, + "oil_regional::variables/oil_diesel/unit": { + "name_ko": "값 단위", + "summary": "단가는 원/L 이다." + }, + "oil_regional::variables/oil_gasoline/unit": { + "name_ko": "값 단위", + "summary": "단가는 원/L 이다." + }, + "rates::processing_rules": { + "name_ko": "셈 규칙", + "summary": "요율만으로는 금액이 안 나온다 — 밑수를 어떻게 만들고 어디서 자르는지 적은 자리. 코드와 어긋나면 거울 시험이 잡는다." + }, + "rates::variables/rate_asbestos_contribution": { + "name_ko": "석면피해구제 분담금", + "summary": "노무비에 곱하는 율." + }, + "rates::variables/rate_care": { + "name_ko": "노인장기요양보험료", + "summary": "건강보험료 금액에 곱하는 율." + }, + "rates::variables/rate_health": { + "name_ko": "건강보험료", + "summary": "직접노무비에 곱하는 율." + }, + "rates::variables/rate_retirement_mutual_aid": { + "name_ko": "퇴직공제부금비", + "summary": "직접노무비에 곱하는 율. 추정금액 하한이 있다." + }, + "rates::variables/rate_safety_base": { + "name_ko": "산업안전보건관리비 기초액", + "summary": "요율표 안에 함께 든 기초액이 걸리는 구간." + }, + "rates::variables/rate_sanjae": { + "name_ko": "산재보험료", + "summary": "노무비에 곱하는 율." + }, + "rates::variables/rate_vat": { + "name_ko": "부가가치세", + "summary": "공급가액에 곱하는 율." + }, + "rates::variables/rate_wage_claim_contribution": { + "name_ko": "임금채권보장 부담금", + "summary": "노무비에 곱하는 율." + }, + "rebar_complexity::price_hint_krw_per_ton": { + "name_ko": "단가 참고값", + "summary": "표시 전용 — 갈래 차이를 사람이 보라고 둔 값. 계산에 안 들어간다." + }, + "stone_kind::back_lengths_cm": { + "name_ko": "뒷길이 규격", + "summary": "표가 값을 주는 뒷길이 일곱 칸." + }, + "stone_kind::backfill_ratio_of_back_length": { + "name_ko": "뒤채움 몫", + "summary": "뒷길이 가운데 뒤채움이 차지하는 비. 나머지가 잡석이다." + }, + "stone_kind::fill_concrete_m3_per_m2": { + "name_ko": "채움 콘크리트 원단위", + "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. 원문이 두 줄뿐이다." + }, + "stone_kind::kinds": { + "name_ko": "돌 종류", + "summary": "야면석·호박돌 / 깬잡석 / 깬돌 / 견치돌 네 줄." + }, + "stone_kind::no_folding": { + "name_ko": "접지 않음 규칙", + "summary": "표에 없는 뒷길이를 가까운 칸으로 접지 않는다 — 접으면 값이 조용히 틀린다." + }, + "stone_kind::wedge_stone_m3_per_m2": { + "name_ko": "고임돌 원단위", + "summary": "돌 종류 × 뒷길이마다 ㎥/㎡. null 은 원문 「-」다." + }, + "work_item_mapping::concrete_placing": { + "name_ko": "콘크리트 타설 잇기", + "summary": "타설 방식 × 구조물 종류로 공종이 갈리는 자리." + }, + "work_item_mapping::ground_aliases_moved_to": { + "name_ko": "갈래 별칭 옮긴 자리", + "summary": "갈래 이름 별칭은 별칭표로 옮겼다. 여기 다시 두지 않는다." + }, + "work_item_mapping::masonry_class_reference": { + "name_ko": "돌쌓기 갈래 참고 자리", + "summary": "돌쌓기 갈래는 이제 참고용이고 어긋나면 그것이 신호다." + }, + "work_item_mapping::pipe": { + "name_ko": "배수관 잇기", + "summary": "관종으로 공종이 갈린다. 관 정본은 pipe_points 다." + }, + "work_item_mapping::variant_contract": { + "name_ko": "갈래 키 계약", + "summary": "갈래 키 문자열을 두 창이 각자 조립하지 않기로 한 약속." + } + }, + "unknown": [] +} diff --git a/resources/tester/test_master_labels_cover.py b/resources/tester/test_master_labels_cover.py new file mode 100644 index 00000000..e10346b7 --- /dev/null +++ b/resources/tester/test_master_labels_cover.py @@ -0,0 +1,273 @@ +"""마스터 이름표(`resources/data_master_labels/labels_2026-01-01.json`) 덮임 시험. + +이름표는 **값을 안 담고 이름만 담는다** — 그래서 마스터가 늘거나 열이 바뀌면 +이름표가 조용히 뒤처진다. 이 시험이 그 어긋남을 잡는다. + +- 마스터에 있는데 이름표에 없는 표·열 → 빨강 +- 이름표에 있는데 마스터에 없는 표·열(묵은 이름표) → 빨강 +- 갈래 나눔은 2026-09-15 브레인 갈래표(로직 17 · 기초값 9 · 부산물 4 · 씨앗 1)와 대조 +""" + +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[2] +LABELS_PATH = ROOT / "resources" / "data_master_labels" / "labels_2026-01-01.json" + +#: 브레인 갈래 나눔표(2026-09-15). 폴더 장부(_manifest)는 그 31 밖이라 따로 센다. +BRAIN_KIND_COUNTS = {"logic": 17, "base_value": 9, "byproduct": 4, "seed": 1} +MANIFEST_PREFIX = "manifest_" + +META_KEYS = { + "schema_version", + "dataset_id", + "effective_date", + "generated_at", + "publication_date", + "survey_month", + "pum_edition", + "dataset_version", + "source_master_file", + "source_dataset_version", +} + + +@pytest.fixture(scope="module") +def labels() -> dict: + return json.loads(LABELS_PATH.read_text(encoding="utf-8")) + + +def _is_table(node) -> str | None: + """이름표 생성기와 **같은 잣대** — 화면이 표로 그릴 마디인가.""" + if isinstance(node, list) and node and all(isinstance(r, dict) for r in node): + return "list" + if isinstance(node, dict): + values = list(node.values()) + dicts = [v for v in values if isinstance(v, dict)] + if ( + len(values) >= 2 + and len(dicts) == len(values) + and not any( + isinstance(v.get("records"), list) or isinstance(v.get("rows"), list) for v in dicts + ) + ): + keysets = [frozenset(v.keys()) for v in dicts] + if len(set(keysets)) <= max(2, len(keysets) // 3 + 1): + return "map" + return None + + +def _has_table(node, depth: int = 0) -> bool: + if _is_table(node): + return True + if depth > 5 or not isinstance(node, dict): + return False + return any(_has_table(v, depth + 1) for v in node.values()) + + +def _collect(node, path, tables, values, depth: int = 0) -> None: + shape = _is_table(node) + if shape: + tables.append(("/".join(path), shape, node)) + return + if depth <= 5 and isinstance(node, dict) and any(_has_table(v) for v in node.values()): + for key, value in node.items(): + _collect(value, path + [key], tables, values, depth + 1) + return + values.append("/".join(path)) + + +def _scan(path: Path) -> tuple[list, list]: + doc = json.loads(path.read_text(encoding="utf-8")) + tables, values = [], [] + for key, value in doc.items(): + if key in META_KEYS: + continue + if key == "variables" and isinstance(value, dict) and not _is_table(value): + for sub_key, sub in value.items(): + _collect(sub, ["variables", sub_key], tables, values) + else: + _collect(value, [key], tables, values) + return tables, values + + +def _columns_of(node, shape: str) -> list[str]: + records = node if shape == "list" else list(node.values()) + seen: list[str] = [] + for record in records: + if not isinstance(record, dict): + continue + for key in record: + if key not in seen: + seen.append(key) + return seen + + +def test_이름표_파일이_읽힌다(labels): + assert labels["dataset_id"] == "data_master_labels" + assert labels["files"], "이름표에 파일이 하나도 없다" + + +def test_이름표가_가리키는_파일이_다_있다(labels): + missing = [f["path"] for f in labels["files"] if not (ROOT / f["path"]).is_file()] + assert not missing, f"이름표가 없는 파일을 가리킨다: {missing}" + + +def test_갈래_나눔이_브레인_표와_같다(labels): + counted: dict[str, int] = {} + for entry in labels["files"]: + if entry["file_id"].startswith(MANIFEST_PREFIX): + continue + counted[entry["kind"]] = counted.get(entry["kind"], 0) + 1 + assert counted == BRAIN_KIND_COUNTS + assert sum(counted.values()) == 31 + + +def test_갈래_이름이_다_풀려_있다(labels): + known = set(labels["kinds"]) + used = {f["kind"] for f in labels["files"]} + assert used <= known, f"뜻을 안 적은 갈래: {sorted(used - known)}" + + +def test_마스터의_표가_이름표에_다_있다(labels): + missing = [] + for entry in labels["files"]: + tables, _ = _scan(ROOT / entry["path"]) + labelled = {t["key"] for t in entry["tables"]} + for key, _shape, _node in tables: + if key not in labelled: + missing.append(f"{entry['file_id']}::{key}") + assert not missing, f"이름표에 없는 표: {missing}" + + +def test_이름표의_표가_마스터에_다_있다(labels): + stale = [] + for entry in labels["files"]: + tables, _ = _scan(ROOT / entry["path"]) + actual = {key for key, _s, _n in tables} + for table in entry["tables"]: + if table["key"] not in actual: + stale.append(f"{entry['file_id']}::{table['key']}") + assert not stale, f"마스터에 없는 묵은 이름표: {stale}" + + +def test_마스터의_값_묶음이_이름표에_다_있다(labels): + missing = [] + for entry in labels["files"]: + _tables, values = _scan(ROOT / entry["path"]) + labelled = {v["key"] for v in entry["value_groups"]} + for key in values: + if key not in labelled: + missing.append(f"{entry['file_id']}::{key}") + assert not missing, f"이름표에 없는 값 묶음: {missing}" + + +def test_표_이름이_비지_않았다(labels): + blank = [ + f"{entry['file_id']}::{table['key']}" + for entry in labels["files"] + for table in entry["tables"] + if not table["name_ko"].strip() + ] + assert not blank, f"한글 이름이 빈 표: {blank}" + + +def test_값_묶음_이름이_비지_않았다(labels): + blank = [ + f"{entry['file_id']}::{group['key']}" + for entry in labels["files"] + for group in entry["value_groups"] + if not group["name_ko"].strip() + ] + assert not blank, f"한글 이름이 빈 값 묶음: {blank}" + + +def test_마스터의_열이_이름표에_다_있다(labels): + missing = [] + for entry in labels["files"]: + tables, _ = _scan(ROOT / entry["path"]) + by_key = {t["key"]: t for t in entry["tables"]} + for key, shape, node in tables: + table = by_key.get(key) + if table is None: + continue + labelled = {c["key"] for c in table["columns"]} + for column in _columns_of(node, shape): + if column not in labelled: + missing.append(f"{entry['file_id']}::{key}/{column}") + assert not missing, f"이름표에 없는 열: {missing}" + + +def test_이름표의_열이_마스터에_다_있다(labels): + stale = [] + for entry in labels["files"]: + tables, _ = _scan(ROOT / entry["path"]) + actual = {key: _columns_of(node, shape) for key, shape, node in tables} + for table in entry["tables"]: + known = set(actual.get(table["key"], ())) + for column in table["columns"]: + if column["key"] not in known: + stale.append(f"{entry['file_id']}::{table['key']}/{column['key']}") + assert not stale, f"마스터에 없는 묵은 열 이름표: {stale}" + + +def test_열_이름은_붙었거나_사유가_있다(labels): + bad = [] + for entry in labels["files"]: + for table in entry["tables"]: + for column in table["columns"]: + if column["name_ko"].strip(): + continue + if not column.get("unknown_reason", "").strip(): + bad.append(f"{entry['file_id']}::{table['key']}/{column['key']}") + assert not bad, f"이름도 사유도 없는 열: {bad}" + + +def test_이름_없는_열은_unknown_에도_적혀_있다(labels): + listed = {u["where"] for u in labels["unknown"]} + for entry in labels["files"]: + for table in entry["tables"]: + for column in table["columns"]: + if column["name_ko"].strip(): + continue + where = f"{entry['file_id']}::{table['key']}/{column['key']}" + assert where in listed, f"unknown 에 안 적힌 빈 열: {where}" + + +def test_찾는_차례가_적혀_있다(labels): + order = labels["lookup_order"]["column"] + assert order[0].startswith("column_overrides") + assert order[1].startswith("columns") + + +def test_덮어쓰기_이름표가_다_쓰인다(labels): + """`column_overrides` 는 「파일id/열key」 꼴이고 그 파일에 실제로 그 열이 있어야 한다.""" + by_file = {} + for entry in labels["files"]: + cols = set() + for table in entry["tables"]: + cols |= {c["key"] for c in table["columns"]} + by_file[entry["file_id"]] = cols + dangling = [] + for key in labels["column_overrides"]: + file_id, _, column = key.partition("/") + if column not in by_file.get(file_id, set()): + dangling.append(key) + assert not dangling, f"쓰이지 않는 열 덮어쓰기: {dangling}" + + +def test_세어_둔_수가_실제와_같다(labels): + counts = labels["counts"] + assert counts["files"] == len(labels["files"]) + assert counts["tables"] == sum(len(f["tables"]) for f in labels["files"]) + assert counts["columns"] == sum(len(t["columns"]) for f in labels["files"] for t in f["tables"]) + assert counts["value_groups"] == sum(len(f["value_groups"]) for f in labels["files"]) + assert counts["unknown"] == len(labels["unknown"]) + + +def test_강우_IDF_캐시는_안_담았다(labels): + assert not [f for f in labels["files"] if "rainfall" in f["path"]] diff --git a/resources/tester/test_z01_master_cells.py b/resources/tester/test_z01_master_cells.py new file mode 100644 index 00000000..82c485e1 --- /dev/null +++ b/resources/tester/test_z01_master_cells.py @@ -0,0 +1,82 @@ +"""Z01 마스터 데이터 표 칸 — 숨김 열 · 열 제목(한글 label + 단위) · 칸 글자 · 쪽 수 (2026-09-15 브레인 Z01). + + ① 한글 이름은 API 가 `label` 로 줌 — 화면은 사전을 안 가짐(받은 대로 보임) + ② `hidden` 열(내부 id · sha · 생성시각)은 기본 숨김 · 「숨긴 열 보기」면 보임 + ③ 단위가 있는 열의 수는 천 단위 쉼표(소수 자리는 자르지 않음) · 단위 없는 수(연도 등)는 그대로 + ④ 쪽 수는 줄이 없어도 1 +TS 를 실제로 돌린다(`test_b06_berm_review_info` 와 같은 방식). +""" + +from __future__ import annotations + +import json +import subprocess +from pathlib import Path + +PROJECT_ROOT = Path(__file__).resolve().parents[2] +TSC = PROJECT_ROOT / "config" / "node_modules" / "typescript" / "bin" / "tsc" +SOURCE = PROJECT_ROOT / "Z01_MasterData" / "Z01_MasterData_UI_Cells.ts" + +_RUNNER = """ +import { writeFileSync } from "node:fs"; +import { cellText, columnTitle, pageCount, shownColumns } from "./Z01_MasterData_UI_Cells.js"; + +const columns = [ + { key: "id", label: "id", unit: null, hidden: true }, + { key: "occupation_name", label: "직종명", unit: null, hidden: false }, + { key: "daily_wage_krw", label: "일 노임", unit: "원", hidden: false }, +]; +writeFileSync(process.argv[2], JSON.stringify({ + shown: shownColumns(columns, false).map((c) => c.key), + shownAll: shownColumns(columns, true).map((c) => c.key), + titles: columns.map(columnTitle), + cells: [ + cellText(null, null), + cellText(250000, "원"), + cellText(1.23456, "㎥"), + cellText(2026, null), + cellText({ a: 1 }, null), + cellText(true, null), + cellText("보통인부", null), + ], + pages: [pageCount(0, 50), pageCount(6999, 50), pageCount(50, 50)], +})); +""" + + +def test_칸_글자와_숨김_열(tmp_path: Path) -> None: + out = tmp_path / "js" + subprocess.run( # noqa: S603 — 고정 실행 파일 + [ + "node", + str(TSC), + str(SOURCE), + "--outDir", + str(out), + "--module", + "esnext", + "--target", + "es2022", + "--ignoreConfig", + "--noCheck", + "--noResolve", + ], + cwd=str(PROJECT_ROOT), + check=True, + capture_output=True, + ) + (out / "runner.mjs").write_text(_RUNNER, encoding="utf-8") + result = tmp_path / "output.json" + subprocess.run( # noqa: S603 + ["node", str(out / "runner.mjs"), str(result)], + cwd=str(PROJECT_ROOT), + check=True, + capture_output=True, + ) + got = json.loads(result.read_text(encoding="utf-8")) + + assert got["shown"] == ["occupation_name", "daily_wage_krw"] + assert got["shownAll"] == ["id", "occupation_name", "daily_wage_krw"] + assert got["titles"] == ["id", "직종명", "일 노임 (원)"] + assert got["cells"] == ["", "250,000", "1.23456", "2026", '{"a":1}', "예", "보통인부"] + assert got["pages"] == [1, 140, 1] diff --git a/tsconfig.json b/tsconfig.json index 3c703b96..4b9da6ad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -32,6 +32,6 @@ "maplibre-gl": ["config/node_modules/maplibre-gl"], } }, - "include": ["A00_Common", "A0*", "B0*", "B1*", "ui_template", "config/**/*", "common_util"], + "include": ["A00_Common", "A0*", "B0*", "B1*", "Z0*", "ui_template", "config/**/*", "common_util"], "exclude": ["0_old", "node_modules", "venv", "dist"] } diff --git a/ui_template/ui_template_locale_b3.ts b/ui_template/ui_template_locale_b3.ts index f5bd2680..67183d6a 100644 --- a/ui_template/ui_template_locale_b3.ts +++ b/ui_template/ui_template_locale_b3.ts @@ -136,4 +136,29 @@ export const ui_locales_b3 = { "법령 별표2 Ⅰ.2.바.(2) 가 요구하는 구간만 자동 — 종단 8% 초과 사질·점토(우리 프리셋은 토사 하나라 토사 전부) · 8% 이하 연약·습윤은 칸(판정 근거 없음). 교본 3-2 는 「콘크리트 포장 구간 이외」 전부라 고르면 넓힘. 두께 제안 0.10(교본) · C·L 제안 소광 관측(원문 표에 혼합석 줄 없음 · 역 C 와 방향이 반대)", "Only the stations required by the forest act table 2 are automatic — grade > 8% sandy/clay soil (our preset has one soil class) and ≤ 8% soft/wet ranges you enter. Manual 3-2 covers all non-concrete stations. Suggested thickness 0.10 (manual) · C·L from practice (no gravel row in the standard table)", ], + /* --- B01 시스템 설정 · Z01 마스터 데이터 (2026-09-15 브레인 Z01) --- */ + B01_Dashboard_SystemSettings: ["시스템 설정", "System Settings"], + B01_Dashboard_MasterData: ["마스터 데이터", "Master Data"], + Z01_MasterData_Title: ["마스터 데이터", "Master Data"], + Z01_MasterData_Subtitle: [ + "로직·기초값을 표로 봄 — 읽기 전용", + "Browse logic and base values — read only", + ], + Z01_MasterData_AdminOnly: ["시스템 관리자만 볼 수 있음", "System administrators only"], + Z01_MasterData_LoadFailed: ["마스터 데이터를 못 읽음", "Failed to load master data"], + Z01_MasterData_PickTable: ["왼쪽에서 표를 고를 것", "Pick a table on the left"], + Z01_MasterData_Search: ["검색", "Search"], + Z01_MasterData_ShowHidden: [ + "숨긴 열 보기(내부 id · sha · 생성시각)", + "Show hidden columns (id · sha · created)", + ], + Z01_MasterData_Byproduct: [ + "정본 아님 — 계산이 남긴 기록", + "Not source data — calculation records", + ], + Z01_MasterData_NoRows: ["줄 없음", "No rows"], + Z01_MasterData_Prev: ["이전", "Prev"], + Z01_MasterData_Next: ["다음", "Next"], + Z01_MasterData_Page: ["쪽", "pages"], + Z01_MasterData_Rows: ["줄", "rows"], } as const;