diff --git a/docs/raw/M01_쉬운단가/로직판_A_설계초안.md b/docs/raw/M01_쉬운단가/로직판_A_설계초안.md new file mode 100644 index 000000000..3b105749a --- /dev/null +++ b/docs/raw/M01_쉬운단가/로직판_A_설계초안.md @@ -0,0 +1,205 @@ +# 로직 만들기 판 시험판 A(세 칸 판) — 조사 · 설계 초안 (35-2 · sub7) + +조사 · 초안만 · 코드 · git · docs 안 건드림. 셈은 `resources/master_data/로직_*.json` 1,469개 · 표 3,033개(시험 해석기 = 저장소 밖 scratch `lb/survey.ts` · 엔진 `master_formula._Parser` 와 같은 문법). + +## 0. 한눈에 + +| 물음 | 답 | +| --- | --- | +| ① 블록으로 읽고 다시 쓰기 | **됨** — 6개 모두 다 읽힘 · 다시 쓰기 같음. 마스터 **1,396 / 1,469(95%)** 가 ①~⑤ 블록으로 다 읽힘 · 식 하나하나가 문장 틀(값 · 곱나눔 · 할증 · 조건 목록 · 최소최대 · 올림)로 읽히는 것 1,299(88%) | +| ② 표 칸 고치면 시험 계산에 바로 | **지금 안 됨** — `/calc` 에 표 덮어쓰기 길 없음 · 현장(자체) 표 키 없음(QF · QC · CF · CC 뿐) → 서버 두 가지 필요(⬜) | +| ③ 단계 안내로 새로 만들기 | **거의 됨** — `/sections` · `/tables?section=` · `/table` · `/table/options` · `/logic/new` 다 있음 · 「로직에 안 이어진 표」 거름 칸만 없음(절 단위 `logics` 수로 대신 가능) | +| ④ 해당 없음/중복 · 빈틈 · 기대값 시험표 | 해당 없음/중복 = `/calc` 줄 까닭 글로 지금 됨(글 해석) · 빈틈 = 길 없음(서버 하나 ⬜) · 기대값 시험표 = `/calc` 여러 번으로 지금 됨 · 저장 자리는 정할 것 | +| ⑤ 파일 나누기 | 7절 — 6 파일 + 서버 3 길(⬜) · 창 다섯 | + +## 1. 블록 구조 — 로직 한 벌을 ①~⑤ 로 + +### 1-1 블록 모양 + +| 블록 | 지금 로직 칸 | 블록이 쥘 것 | +| --- | --- | --- | +| ① 입력값 | `입력` | 이름 · 단위 · 선택 목록(`고르기`) · 범위 · 설명 · 출처 — 선택 목록은 표 조건 칸에서 저절로(`/table/options`) | +| ② 표 조회 | 식 속 `찾기(표, 조건=값 …).결과칸` | 표 키 · 조건 칸마다 **입력값 / 고정값 / 계산값** · 결과 칸 · 쓰인 자리(중간 · 수량 · 비율 · 결과) | +| ③ 계산 | `중간` + 수량 · 비율 · 결과 식의 나머지 | 이름 붙은 값 · 틀: 값 · 곱나눔(사슬) · 할증(`× (1 + p/100)`) · 더하기 · 조건 목록(만약 사슬) · 최소/최대 · 올림/버림/반올림 | +| ④ 항목 연결 | `호표` · `덧줄` | 종류(노무 · 재료 · 장비 · 일위대가 · 비율) · 요소 · 수량 출처(② · ③ · 숫자) · 비목 · 비율은 바탕(비목 · 사람 줄 노임 합) × 율 | +| ⑤ 결과값 | `결과단위` · `결과` · `끝수` | 금액(원/…) 또는 값(㎥/시간 — `결과` 식) · 다른 로직이 부르는 자리(`로직(키, 넘길 값)`) | + +다시 쓰기 = **글 갈아끼우기** — 고친 조각의 자리만 새 글로 바꾸고 나머지 글자는 그대로(Cond `writeRead` · Table `replaceFinds` 와 같은 길). 안 고친 로직은 바이트까지 같음. + +### 1-2 대상 6개 + +| 로직 | ① | ② | ③ | ④ | ⑤ | 읽기 | +| --- | --- | --- | --- | --- | --- | --- | +| GF000208 암거이음받침 채움재 | 없음 | 없음 | 없음 | 재료 1(검색어 JOINT FILLER · 1㎡) | 원/㎡ | 다 읽힘 | +| GF000219 돌쌓기 메쌓기(인력) | 뒷길이 · 돌 · 쌓기(선택) · 높이 · 초과증가율(범위 80~100) | QF000421(조건 셋 → 석공 · 보통인부) · QF000422(높이 범위 → 증가율) | 증가율 = 조건 목록(높이 ≤3 → 0 · ≤7.5 → 표 · 그 외 → 초과증가율) · 수량 = 표 × 할증 | 노무 2 | 원/㎡ | 다 읽힘 | +| GF000025 떼붙임(재배잔디) | 품(숫자) · 비탈구배(선택) | QF000099(구분 고정 → 값) | 품 × (1 + 조건 목록(해당 없음 → 0 · 그 외 → 표) / 100) | 노무 1 | 원/100㎡ | 다 읽힘 | +| GF000249 다짐(플레이트콤펙터 1.5ton) | 지역(선택) | 없음 | 작업량 = 다른 로직 결과값(GF000114) · 수량 = 1 ÷ 작업량 | 장비 1(기계경비 GC000272 · 넘길 값 기계 고정 · 지역 입력값) | 원/㎥ | 다 읽힘 | +| GF000114 다짐 시간당 작업량 | 없음 | QF000289 여섯 번(기호 고정 A · N · H · f · E · P → 적용) | 결과 = 반올림(A×N×H×f×E÷P, 3) | 없음 | 값 ㎥/시간 | 다 읽힘 | +| GF000133 덤프트럭 시간당 작업량 | qt · f · E · Cm(숫자) | 없음 | 결과 = 반올림(60×qt×f×E÷Cm, 3) | 없음 | 값 ㎥/시간 | 다 읽힘 | +| GC000051 보행자 안전통로 | 없음 | QC000115(구분 고정 → 수량) · QC000116(구분 고정 → 값) | 비계공 = 표 | 노무 1 · 비율 1(사람 줄 노임 × 표 값 %) | 원/m | 다 읽힘 | + +- 6개 모두 왕복 같음 · Model(EasyCalc) 은 GC000051 의 비율을 「잠금」으로 봄(율이 숫자 아님) — 블록에서는 율 = ② 표 조회로 읽힘. +- 다짐은 두 로직(작업량 GF000114 → 금액 GF000249) — ⑤ 결과값 넘기기의 견본. + +### 1-3 마스터 전체 + +| 셈 | 수 | +| --- | --- | +| 식 자리(중간 · 수량 · 장비 요소 · 비율 · 결과) | 10,179 · 블록으로 읽힘 10,037(98.6%) | +| 로직 — 모든 식이 블록으로 읽힘 | **1,396 / 1,469(95.0%)** | +| 로직 — 모든 식이 문장 틀(칸 안 한 겹 묶음까지) | 1,299(88.4%) · 나머지 97개는 「여러 단계」 식이 섞임(단계 목록으로 펼쳐 보임 — 선택은 되나 김) | +| 다시 쓰기(해석 → 글) 같음 | 1,464(99.7%) · 다른 5개는 따옴표 · 빈칸 꼴 차이(글 갈아끼우기면 영향 없음) | +| 못 읽는 까닭 | 표 조건 칸에 계산(`최소(시공높이m, 7.2)` · `만약(…)` 등) 68 식 · 그리고/또는 69 식 · 로직 넘길 값에 계산 5 식 | +| 식 틀 갈래(식 수) | 값 5,362 · 곱나눔 2,655 · 묶음 사슬 1,231 · 조건 목록 515 · 여러 단계 168 · 할증 108 · 더하기 91 · 올림 43 · 최소최대 6 | +| 항목 종류(호표 줄) | 인력 3,462 · 로직(장비 · 일위대가) 1,075 · 재료 723 | + +### 1-4 EasyCalc 해석기 다시 쓰기 + +| 부품 | 쓰임 | 그대로? | +| --- | --- | --- | +| Model `toDoc · toRow` | ④ 항목 카드 · ⑤ 금액 · 왕복 100%(1,469) | 그대로 — 비율 율이 표 조회인 꼴만 블록 쪽에서 덧읽음 | +| Table `readFinds · writeFind · replaceFinds · literalValue` | ② 표 조회 읽기 · 조건 값 바꾸기 | 그대로 | +| Cond `readCond · writeRead · writeCond` | ③ 조건 목록 · 최소최대 · 올림 | 그대로(식 속 덩어리까지 · 줄 자체 조건 93%) | +| Api `calcLater · copyEasy · editEasy · newEasy · usesOf · listMachines · machineCall` | 예시값 계산 · 저장 · 장비 잇기 | 그대로 | +| Cards · Sheet | 오른쪽 결과 칸 | 그대로(읽기 · 고치기 둘 다) | +| 없는 것 | 사칙 사슬(곱나눔 · 할증 · 더하기 · 단계) 읽기 · 중간 값 그래프(어느 값이 어느 값을 씀) · 결과 식 로직 | LogicBuilder `Blocks` 가 새로 — 문법은 Cond 해석기와 같은 엔진 문법 | + +## 2. 표 칸 고치기 + +- **`/calc` 에 표 덮어쓰기 길 없음** — 몸 = `key · inputs · row · file · 고름` · 로직 줄만 메모리에서 바꿔 셈(`Store._swap`). 표는 언제나 파일 것. +- **현장(자체) 표 키 없음** — 표 ID 는 QF · QC(소요량) · CF · CC(계수)뿐 · `소요량_자체.json` 같은 자리 없음. M01 표 편집(칸 눌러 고침)은 `/save` 로 **표준 파일을 바로 고침** — 시험판은 부르지 않음. +- 서버가 가볍게 받을 수 있는 까닭 — `cm.load` 가 부를 때마다 파일을 새로 읽음(캐시 없음) → 메모리 사본에 표를 바꿔 끼워도 다른 요청에 안 번짐. + +최소로 필요한 것(⬜ 서버 · 폴더 밖): + +1. **`CalcBody.tables`** — `[{키, …표 통째}]` · `calc` · `text` 가 `_swap` 처럼 메모리 사본의 그 키 표를 바꿈(약 15줄) → 왼쪽 칸에서 고친 숫자가 저장 전 금액에 바로. +2. **현장 표** — 표 ID `QX`(소요량 자체) 하나 · 파일 `소요량_자체.json` · `master_keys.TABLES[("소요량", "자체")] = "QX"` · 길 `/table/copy · /table/edit · /table/delete`(현장 파일만 · `logic_*` 와 같은 틀 · 409 · 422) · 검사(`check_master` 틀 · 본문 대조에서 「자체」 표는 본문 대조 뺌). +3. 저장 차례 — 표준 로직을 연 채 표 칸을 고치면: 로직 복사 편집(GX) → 그 표 사본(QX) → GX 의 `찾기(QF…)` 머리를 `찾기(QX…)` 로 바꿈 → 한 번에 저장. **표준 표 · 로직은 안 고침**. + +정할 것 — 현장 표 사본을 로직마다 따로 둘지(간단 · 표가 늘어남) · 같은 표를 여러 현장 로직이 함께 쓸지(개정 한 번에 반영 · 사용처 관리 필요). + +## 3. 새로 만들기 — 단계 안내 6단계와 서버 길 + +| 단계 | 쓰는 길 | 있나 | +| --- | --- | --- | +| 1 절 찾기 | `GET /sections?book=산림품셈|건설품셈&q=` — 절마다 `tables` · `logics` 수 | 있음 · `logics = 0` 이고 `tables > 0` 인 절 = 새로 만들 자리 | +| 1 그 절의 표 | `GET /tables?group=소요량|계수§ion=13-4-1` | 있음 · 단 목록 머리에 `용도`(이어진 로직) 없음 — 「안 이어진 표」 거름은 절 수로 대신 · 꼭 필요하면 `_TABLE_HEADS` 에 `용도` 한 칸(⬜) | +| 2 칸 역할 | `GET /table`(통째) · `/table/options`(조건 칸 값) | 있음 — 조건 · 값칸 · 범위규칙 · 주 | +| 3 결과 단위 | 표 `기준`(「1㎡」) | 있음 | +| 4 계산 | 화면(Cond 틀 · 할증 · 곱나눔) | 서버 길 필요 없음 | +| 5 항목 연결 | `GET /pick?kind=job&q=석공` · `/materials` · Api `listMachines · machineCall` · `/logics` | 있음 — 값 칸 이름 = 직종 이름이면 저절로 | +| 6 이름 · 저장 | `POST /logic/new`(GX · 원문번호 · 출처 「산림품셈 13-4-1」 꼴 허용) · 저장 전 `/calc`(`key ""` + `row`) | 있음 | + +- 표가 아직 없는 절(엑셀 붙여넣기)은 2절 현장 표 길(⬜)이 있어야 저장됨 — 시험판 1차는 「표가 있는 절」만. +- 안 이어진 표 1,010개(용도.로직키 빈 것 · 제안서 1,018 과 8 차이 — 그 사이 이어짐). + +## 4. 조사로 더할 것 셋 + +| 것 | 지금 API | 판정 | +| --- | --- | --- | +| 표 조회 해당 없음 / 중복 | `/calc` 줄이 비고 `까닭` 「표 QF…에 뒷길이 25 · 돌 견치돌 인 줄이 없음」 / 「… 인 줄이 2개」(엔진 `find` → `NoRow`) | **지금 됨** — 글로 갈라 읽음(약함) · 단단히 하려면 까닭에 `종류: 없음|중복` 칸(⬜ 작음) | +| 빈틈 검사(입력값 조합 중 표에 없는 것) | 길 없음 · `/calc` 를 조합마다 부르면 됨(메쌓기 7×4×2 = 56번 · 빈틈 16) — 느림 | **서버 길 하나(⬜)** `/table/gaps?key=` — `master_auto._uses`(어느 입력이 어느 조건으로 가나) + `mf.find` 로 조합을 돌려 「없음 · 중복」 목록 · 판정이 엔진과 같아야 해서 화면 짝 구현(범위규칙 네 가지)보다 서버 단독이 맞음 | +| 기대값 시험표 | `/calc` 를 줄마다(입력값 → `lines[i].수량` · 결과값) 부르면 됨 | **지금 됨**(계산) · 저장 자리 정할 것 — 현장 로직 줄의 새 칸(`시험표` · `check_master` 가 로직의 모르는 칸을 막지는 않음 · `_clean` 이 칸 차례 밖 칸을 뒤에 붙여 둠) 또는 따로 파일 · 시험판 1차는 저장 없이 화면에만 | + +## 5. 표준 · 현장 규칙 (화면 한 줄) + +- 표준(품셈 원문 · 로직 GF · GC · 표 QF · QC · CF · CC) = 읽기 · 예시값 계산 · 복사 편집만. +- 현장(로직 GX · 표 QX⬜) = 고치기 · 지우기 · `로직_자체.json`(+ `소요량_자체.json`⬜) 만 씀. +- 「품셈이 개정돼도 현장 일위대가는 안 바뀜」 — 저장 화면 머리에 한 줄. + +## 6. 화면 세 칸과 부품 + +``` +┌ 원문(Source) ─────────┐┌ 산출근거(Steps) ───────────────┐┌ 결과(Result) ──────┐ +│ 표 머리 역할 칩 ││ ① 입력값 선택 목록 칩 ││ EasyCalc Cards │ +│ 조건 · 고정 · 결과 · 주 ││ ② 표 조회 조건 칸 ← 입력값/고정 ││ (읽기 · 고치기) │ +│ 걸린 줄 노랑 ││ · 해당 없음/중복 표시 ││ 큰 합계 · 일위대가표 │ +│ 칸 눌러 고침(사본만) ││ ③ 계산 Cond 문장 · 할증 · 곱나눔 ││ 예시값 띠 │ +│ 빈틈 · 시험표 단추 ││ ④ 항목 연결 노무 · 재료 · 장비 … ││ 기대값 시험표 │ +│ ││ ⑤ 결과값 금액 / 값 · 넘기기 ││ │ +└─────────────────────────┘└────────────────────────────────┘└────────────────────┘ +처음 만들 때 = 가운데 칸이 단계 안내(물음 하나씩) · 답할 때마다 한 줄씩 채워짐 +``` + +## 7. 파일 나누기 초안 (`M01_MasterData/LogicBuilder/` · 파일마다 700줄 안 · 글 [한, 영] 짝은 파일 머리) + +| 파일 | 하는 일 | DOM | 맡을 창(안) | +| --- | --- | --- | --- | +| `M01_LB_Blocks.ts` | 로직 줄 ↔ 블록(①~⑤) 읽기 · 글 갈아끼우기 쓰기 · 사칙 사슬 · 중간 값 그래프 · 결과 식 — EasyCalc Model · Table · Cond 해석기를 가져다 씀 | 없음 | A(Model 쓴 창) | +| `M01_LB_Source.ts` + css | 왼쪽 원문 — 표(`/table`) · 칸 역할 칩 · 주 · 걸린 줄(`/text` 표 조각 `참조.줄`) · 칸 고치기(메모리 사본) · 해당 없음/중복/빈틈 표시 | 있음 | B(Table 쓴 창) | +| `M01_LB_Steps.ts` + css | 가운데 산출근거 ①~⑤ 카드 — 모두 선택 · Cond 문장 · 할증 · 곱나눔 · 항목 연결(Pick 다시 씀) | 있음 | C(Cond · Cards 쓴 창) | +| `M01_LB_Wizard.ts` + css | 단계 안내 6단계 — 절 찾기 → 표 · 칸 역할 → 단위 → 계산 → 항목 → 이름 · 답을 Blocks 에 쌓음 | 있음 | D | +| `M01_LB_Check.ts` | 기대값 시험표 · 빈틈 결과 정리 · `/calc` 여러 번(최신만) | 거의 없음 | D 또는 B | +| `M01_LB_Entry.ts` + css | 단추(「로직 만들기(시험)」 · 쉬운 단가산출 옆) · 세 칸 틀 · 오른쪽 결과(EasyCalc Cards · Sheet 붙임) · 열기 · 복사 편집 · 저장(EasyCalc Api) · 실행 취소 · 저장 안 함 표시 | 있음 | E(Entry 잇기 창) | +| 서버(폴더 밖 · ⬜) | `CalcBody.tables` · 현장 표 QX 길 셋 · `/table/gaps` · (작음) 까닭 종류 칸 · `/tables` 머리에 `용도` | — | 브레인 지명 한 창 | + +### 7-1 서로 맞출 모양 (안) + +```ts +// Blocks (A) +export type LbRef = + | { k: "input"; name: string } // ① 입력값 + | { k: "fixed"; value: number | string } // 고정값 + | { k: "lookup"; id: string } // ② 표 조회 결과 + | { k: "calc"; name: string } // ③ 이름 붙은 계산값(중간) + | { k: "logic"; key: string; field: string | null } // 다른 로직 결과값(.노무비 등) + | { k: "cost"; name: "노무비" | "재료비" | "경비" | "사람줄합" }; +export interface LbLookup { + id: string; // 화면 번호 · 저장 안 함 + table: string; // QF000421 · 현장 사본이면 QX… + conds: { col: string; from: LbRef | { k: "expr"; text: string } }[]; + col: string; // 결과 칸 + at: { part: "중간" | "수량" | "비율" | "결과" | "요소"; index: number; start: number; end: number }[]; +} +export type LbCalcKind = "값" | "곱나눔" | "할증" | "더하기" | "조건목록" | "최소최대" | "올림" | "단계"; +export interface LbCalc { + name: string | null; // 중간 이름 · 수량 자리면 null + kind: LbCalcKind; + parts: LbRef[]; // 곱나눔 · 더하기 · 할증(바탕 · 율) + ops?: ("*" | "/" | "+" | "-")[]; + cond?: CondRead; // 조건목록 · 최소최대 · 올림 — Cond 것 그대로 + at: { part: "중간" | "수량" | "비율" | "결과"; index: number }; + text: string; // 원래 글(안 고치면 그대로 씀) +} +export interface LbLogic { + doc: EasyDoc; // ④ 항목 · ⑤ 금액 — Model 것 그대로 + inputs: LogicInput[]; // ① + lookups: LbLookup[]; // ② + calcs: LbCalc[]; // ③ + result: { kind: "금액"; unit: string } | { kind: "값"; unit: string; calc: LbCalc }; // ⑤ + blocked: string[]; // 못 읽은 까닭(쉬운 말) — 비면 다 읽힘 +} +readLogic(row: LogicRow, meta): LbLogic +writeLogic(lb: LbLogic): LogicRow // 고친 조각 자리만 글 갈아끼우기 +setCond(lb, lookupId, col, from): LbLogic · setCalc(lb, calc, patch) · setLookupTable(lb, id, newKey) + +// Source (B) +export interface TableEdit { table: string; row: number; col: string; value: number | string | [number | null, number | null] } +renderSource(host, lb, tables: Record, hits: Record, on: { edit(e: TableEdit): void; role(table: string, col: string, role: "조건" | "고정" | "결과"): void }) + +// Steps (C) +renderSteps(host, lb, ans: CalcAnswer | null, on: { change(lb: LbLogic): void }) + +// Wizard (D) +openWizard(): Promise +// Check (D|B) +runExpect(lb, rows: { inputs: Record; expect: Record }[]): Promise<{ ok: boolean; got: Record }[]> +gaps(lb): Promise<{ table: string; conds: Record; kind: "없음" | "중복" }[]> // ⬜ /table/gaps + +// Entry (E) +createLogicBuilderButton(): HTMLButtonElement +// 예시값 계산 = EasyCalc Api calcLater(row, trial, …) + 고친 표(⬜ CalcBody.tables) +``` + +### 7-2 차례(제안서 「나눠 만드는 차례」와 맞춤) + +1. **확인** — Blocks(A) + Entry 틀(E) + Source 읽기(B) + Steps 읽기(C) — 6개 로직을 세 칸으로 열어 읽기만 · 서버 변경 없이 됨. +2. **고치기** — Steps 선택 고치기(C) · Source 칸 고치기(B · ⬜ `CalcBody.tables` · 현장 표 QX) · 복사 편집 저장(E). +3. **만들기** — Wizard(D) — 표가 있는 절부터. +4. **넘기기 · 검사** — 결과값 넘기기 · 장비 잇기(C) · Check(D · ⬜ `/table/gaps`). + +## 8. ⬜ 브레인 답 필요 + +1. 서버 변경(폴더 밖) 허락 — `CalcBody.tables`(표 덮어 시험 계산) · 현장 표 QX(파일 · 키 · 길 셋 · 검사) · `/table/gaps` · (작음) 까닭 종류 칸 · `/tables` 머리 `용도`. 없으면 시험판은 「표 칸 고치기」 · 「빈틈 검사」를 뺀 범위. +2. 현장 표 사본 — 로직마다 따로 / 여러 현장 로직이 함께. +3. 기대값 시험표 저장 자리 — 현장 로직 줄 새 칸 / 따로 파일 / 화면에만(1차). diff --git a/docs/raw/M01_쉬운단가/로직판_A_정함.md b/docs/raw/M01_쉬운단가/로직판_A_정함.md new file mode 100644 index 000000000..b5f7a099b --- /dev/null +++ b/docs/raw/M01_쉬운단가/로직판_A_정함.md @@ -0,0 +1,40 @@ +# 로직 만들기 판 시험판 A — 정함 (PLAN 35-2 · 브레인 · 10-01) + +근거 = 같은 폴더 `로직판_A_설계초안.md`(sub7 · 블록 구조 · 파일 나누기 7절 · 맞출 모양 7-1) · `로직판_엑셀로직_지도.md`(sub4 · A 대 B) · `로직판_조사_A · B`(인터넷) · 제안서 https://claude.ai/artifact/U4rkgpYWL4Em5VKBEVa4oY. + +## 목적 (모든 창이 이것으로 판단) + +사용자가 브레인 · 코딩 없이 품셈 원문을 보며 단가산출 로직을 직접 ① 원문 대조로 확인 ② 품셈 숫자가 바뀌면 직접 고침(예: 인원 2~3 → 3~4) ③ 혼자 새로 만듦(초등학생도) ④ 많은 수를 검증 ⑤ 서버 엔진과 같은 값. + +## 정함 + +1. 갈래 = A 세 칸 판(왼쪽 원문 표 · 가운데 산출근거 · 오른쪽 결과). B 엑셀 시트형은 따로 안 만듦(단가 붙이기 · 표 사본 · 엔진 둘에서 막힘) — 엑셀 부품(격자 · 단계 값 · 선택 목록)만 빌림. +2. 복수 시험 = 가운데 칸 보기 둘 — **문장 보기**(Steps) · **격자 보기**(Grid · 엑셀처럼 줄 · 칸 · 칸마다 선택 · 값 · 식 없음) · 위 단추로 바꿔 봄 · 같은 LbLogic · 같은 on.change. +3. 폴더 `M01_MasterData/LogicBuilder/` · 단추 「로직 만들기(시험)」 = 「쉬운 단가산출(시험)」 옆 · 폴더째 지우면 끝. EasyCalc(유지 확정) 파일은 가져다 쓰기만 · 안 고침. +4. 서버 — 기존 서버 파일은 안 고침. 표 칸 고친 값으로 시험 계산은 폴더 안 새 파이썬 모듈(`M01_LB_Calc.py` · `POST /api/m01/lb/calc {row, inputs, tables}`)이 엔진을 같은 방식으로 부르되 전역 캐시를 바꾸지 않고 사본으로 셈 · 등록은 한 줄. 엔진에 고리가 꼭 필요하면 기본값 있는 선택 인자 하나만(지워도 안 깨짐) — 그 경우 보고에 적음. +5. 표 칸 고치기 = 메모리 사본 + 예시값 즉시 재계산 + 영향 보기(그 표를 쓰는 로직 · `용도.로직키`) · **저장 안 함**(표준 표 고치기 · 현장 표 사본은 사용자 결정 뒤) · 화면에 「표 고침은 미리 보기 — 저장은 결정 뒤」 한 줄. +6. 로직 저장 = 현장 일위대가(`/logic/new · edit` · GX)만 · 표준은 「복사 편집」 뒤. +7. 빈틈 검사 = 브라우저에서(입력값 선택 목록 조합 × 표 줄) · 해당 없음 / 중복 = `/calc` 까닭 + 표 줄 대조 · 기대값 시험표 = 화면 초안(sessionStorage)만 · 저장 안 함. +8. 오른쪽 결과 = 큰 합계 + 일위대가표(EasyCalc Sheet renderSheet) + LB 자체 예시값 띠(새 용어) — EasyCalc Cards 는 안 붙임(옛 낱말). +9. 용어 = 제안서 2판 「용어 — 단어로」 제안 그대로: 입력값 · 고정값 · 결과(값) · 조건/고정/결과(표 칸 역할) · 선택 · 표 조회 · 계산 · 산출근거 · 항목 연결 · 노무/재료/장비/일위대가/비율/기타 · 노무비/재료비/경비 · 조건/그 외 · 무관 · 해당 없음/중복 · 표준/현장 · 복사 편집 · 자동 · 직접 입력 · 조건 편집 · 예시값 · 단계 안내 · 변경/실행 취소/삭제/추가 · 규격/사용처/출처 · 일위대가표 · 적용 품셈. +10. 시험 로직 6개 — GF000208 암거이음받침 채움재 · GF000219 돌쌓기 메쌓기(인력) · GF000025 떼붙임(재배잔디) · GF000249 다짐(플레이트콤펙터) · GF000133 덤프트럭 시간당 작업량 · GC000051 보행자 안전통로 — 시작 화면에 이 6개를 먼저 보이고 찾기로 다른 것도 엶. + +## 파일 · 창 + +| 파일 | 창 | 하는 일 | +| --- | --- | --- | +| `M01_LB_Blocks.ts` | sub7 | 로직 ↔ 블록(①~⑤) · 설계초안 7-1 타입 · 먼저 타입 올림 | +| `M01_LB_Calc.py` + 등록 한 줄 · `M01_LB_Api.ts` | sub4 | 표 덮어 시험 계산 서버 길 · 화면 부르기(calcLater 꼴 · 최신만) · 영향 보기(표 → 로직) | +| `M01_LB_Source.ts` + css · `M01_LB_Check.ts` | sub8 | 왼쪽 원문(격자 · 칸 역할 · 주 · 걸린 줄 · 칸 고치기 · 해당 없음/중복/빈틈) · 빈틈 · 기대값 시험표 | +| `M01_LB_Steps.ts` + css | sub2 | 가운데 문장 보기 | +| `M01_LB_Grid.ts` + css | sub5 | 가운데 격자 보기 | +| `M01_LB_Wizard.ts` + css | sub3 | 단계 안내 6단계 | +| `M01_LB_Entry.ts` + css | sub1 | 단추 · 세 칸 틀 · 보기 바꿈 · 열기 · 복사 편집 · 저장 · 실행 취소 · 오른쪽 결과 · 잇기 · 끝 검증(목적 다섯) | + +## 맞출 모양 + +설계초안 7-1 그대로 + 더함: +- Grid: `renderGrid(host, lb, ans, on: { change(lb): void })` — Steps 와 같은 꼴. +- Source: `renderSource(host, lb, tables, hits, on: { edit(e: TableEdit); role(table, col, role) })` — tables = 표 키 → 표 사본(고친 값 포함). +- Api(sub4): `lbCalcLater(row, inputs, tables, onDone(ans | null, plain | null))` · `tableUsers(tableKey): Promise<{ key; 이름 }[]>` · `fetchLbTable(key)`. +- Check: `gaps(lb, tables)` 는 브라우저 셈 · `runExpect(lb, tables, rows)`. diff --git a/docs/raw/M01_쉬운단가/로직판_엑셀로직_지도.md b/docs/raw/M01_쉬운단가/로직판_엑셀로직_지도.md new file mode 100644 index 000000000..554843ff2 --- /dev/null +++ b/docs/raw/M01_쉬운단가/로직판_엑셀로직_지도.md @@ -0,0 +1,161 @@ +# 로직판 조사 — 「엑셀(스프레드시트)로 만드는 로직」 지도 (35-2 · sub4) + +조사만 · 코드 · git · docs 안 건드림 · 근거 = sub_laptop_4 작업 트리(2026-10-01 · 안 받은 dev 28 커밋은 스프레드시트 파일을 안 건드림 — `git log HEAD..origin/dev` 로 확인). +`ss/` = `A00_Common/spreadsheet/`. + +## 결론 셋 + +1. **시트가 계산 규칙으로 쓰이는 곳은 한 곳뿐** — M02 구조물 「면적산출 · 재료산출」 통합문서. 칸 → 알약(입력값 키) 연결까지는 저장되지만 **그다음(일위대가 입력값 · 금액)으로 이어지는 코드가 없음** — 단가 계산은 `면적.json` · `재료.json` · `계산값` 을 읽지 않음. B08 · B09 는 빈 화면. +2. **자체 엔진은 엑셀 기본기를 거의 갖춤** — IF · IFS · IFERROR · VLOOKUP · XLOOKUP · INDEX/MATCH · SUMIFS · MINIFS · ROUND 계열 · 이름 정의 · 시트 사이 참조 · 선택 목록(데이터 유효성) · 계산 단계 보기 · 선행/종속 화살표. 서버는 저장 때 **같은 TS 엔진을 Node 로 다시 셈**(계산 자리 ②). 없는 것 — 다른 통합문서 참조 · LAMBDA/LET · INDIRECT/OFFSET · 마스터(노임 · 자재 · 기계 · 다른 로직)를 읽는 함수. +3. **B(시트로 로직) 는 「표 찾기 · 조건 · 할증 · 비율」 은 시트로 옮길 수 있으나 「단가 붙이기(노임 · 자재 검색 · 기계경비 로직 부르기)」 와 「여러 로직이 한 원문 표를 함께 씀」 에서 막힘** — 시트 엔진 고침 + 새 연결 없이는 로직 ↔ 시트 왕복이 안 되고, 엔진이 둘(파이썬 정본 · TS 시트)이 되어 같은 값 보장이 새 짐. **판단: A(세 칸 판)를 본 갈래로 · B 는 「원문 표 보기 · 계산 단계 보기」 같은 부품만 빌려 씀.** B 시험판을 만들면 「제한된 시트(찾기 · 단가 함수를 엔진에 더함)」 꼴로 범위를 좁혀야 함. + +--- + +## 1. 스프레드시트가 로직(계산 규칙)으로 쓰이는 곳 + +| # | 자리 | 하는 일 | 핵심 코드 | 저장 | 화면 | +| --- | --- | --- | --- | --- | --- | +| 1 | M02 구조물 면적산출 | 집계표 열(꼴 「수」) 하나마다 면적 셈 시트 | `M02_MasterTemplete_Store.py:66-72`(PARTS · `SHEETS = ("area","material")`) · `:282-301`(빈 통합문서) · `:169-170`(저장 때 서버 셈) | 층: `resources/master_template/area/<열id>.json` · 회사 · 개인 층도 같은 자리 · 프로젝트: `templates/structures/<구조물id>/면적.json`(옛 `templates/items/…`) | 큰 편집기 `M02_MasterTemplete_UI_Main.ts:273-361`(수식 입력 줄 · 주소 칸 = `ss/spreadsheet_editor.ts`) · 카드 미리보기 읽기 `M02_MasterTemplete_ItemCards.ts:314-317` · 관리자 카드 편집 `M02_MasterTemplete_Structure.ts:305-359,417-422` + 저장 단추 `M02_MasterTemplete_CardShell.ts:69-120` · 프로젝트 사본 편집 `ui_template/ui_template_item_picker_edit.ts:103-129` | +| 2 | M02 재료산출 | 같은 열의 재료 수량 시트 | 위와 같음(`material/<열id>.json` · 프로젝트 `재료.json`) | 연결 칸에 `자재: {코드: MT…}` 가 더 붙음 | 위와 같음 + 자재 찾기 알약 | +| 3 | 알약 줄(칸 ↔ 입력값 연결) | 시트 아래 알약 막대 · 알약을 칸에 놓으면 「이 칸 값 = 이 입력값」 | `ss/spreadsheet_links.ts:1-9,124-381` · 늦게 불러옴 `ss/spreadsheet.ts:151-163` | `Sheet.연결: [{키, 이름?, 단위?, 칸: "O6", 자재?}]`(`ss/spreadsheet_types.ts:200,211-219`) | 알약 = 조합 물량 `GET /combos/key/{key}/inputs`(`M02_MasterTemplete_Router_Combos.py:99-123` ← `M01_MasterData_Store_Combo.py:168-191`, 키 「로직이름|단위」) + 입력 알약 `GET /layers/{layer}/items/{key}/pills`(`M02_MasterTemplete_Router_Items.py:169` ← `M02_MasterTemplete_Inputs.py:190-218`, 키 「입력|로직|입력」) | +| 4 | 입력 자리 정하기(입력연결) | 일위대가 입력값마다 받는 자리 = 면적 · 재료 · 선택 | `M02_MasterTemplete_Inputs.ts:4-10` · `M02_MasterTemplete_Inputs.py:8-10,144-184` | `inputs/<열id>.json` = `{판, 줄: [{로직, 입력, 자리, 알약?}]}` · 프로젝트 `입력연결.json` | 「선택 입력」 카드 | +| — | (다른 엔진) 구조물집계표 표 수식 | 집계표 칸 수식(설계 값 채우기) | `ui_template/sheet/ui_template_sheet_recalc.ts` · 서버 `common_util/common_util_sheet_recalc.py:30-40` ← `M02_Table_Fill.py:654-660` | 표 템플릿 | 집계표 화면 — **이 갈래 엔진은 스프레드시트 엔진과 따로임** | +| — | 자재조합 | 자재 목록뿐 · 수량 · 단가 없음(「재료산출 몫」) | `M02_MasterTemplete_Matset.py:1-4` | `자재조합.json` | M02 자재 조합 | +| — | B08 수량 · B09 견적 | 빈 화면(다시 짓는 중) | `B08_Quantity/B08_Quantity_UI_Page.ts:3-6` · `B09_Estimation/B09_Estimation_UI_Shell.ts:3-6` | — | — | + +실제 프로젝트 사본 한 벌(`storage/1/3/…/templates/items/system_none_SS000002/면적.json`): + +```json +"칸": {"M6": {"값": 2}, "N6": {"값": 3}, "O6": {"식": "N6*M6"}, "M8": {"식": "O6/M6*0.2"}}, +"연결": [{"키": "GF000222", "이름": "돌쌓기 찰쌓기", "칸": "O6", "단위": "㎡"}], +"계산값": {"s1": {"O6": {"수": "6"}, "M8": {"수": "0.6"}}} +``` + +### 1-1. 값 흐름 — 어디서 끊기나 + +1. 시트 칸(수식) → 알약 키 연결(`Sheet.연결`) — **저장됨**. +2. 브라우저 `getLinkedValues()`(`ss/spreadsheet.ts:275-283`) — 부르는 곳은 시험 하네스뿐(`resources/tester/spreadsheet/harness_links.ts:3`). +3. 프로젝트 단가 계산 `POST /api/projects/{id}/items/{folder}/calc` → `M02_Item_Copy.py:326-337` → `M02_Item_Prices.calc`(`:211`) — 읽는 것 = `입력값.json` · `고른자재.json` · `단가.json` · `일위대가.json` 뿐. 면적 · 재료 자리 입력은 `missing_inputs`(`:195-208`)에서 「입력 없음」 으로 멈춤 · 값 카드는 「선택」 자리 입력만 받음(`M02_MasterTemplete_Inputs.ts:291-295`). + - 주의: `M02_Item_Prices.py:81` 의 `연결` 은 품셈재료 연결(마스터 줄 칸)이지 시트 칸 연결이 아님. + +→ **「시트 칸 → 일위대가 입력값 → 금액」 은 아직 안 이어짐.** 시트는 지금 「구조물 물량 계산기」 이지 단가산출 로직이 아님. + +### 1-2. 계약 어긋남(덤) + +- 형식 · 실제 파일은 `시트[i].연결`(시트마다) · `resources/tester/spreadsheet/test_spreadsheet_store.py:54,92,111` 와 `M02_MasterTemplete_Store.py:158,306` 설명은 문서 머리 `연결` 이라 적음. +- 데이터 유효성 규칙이 행 · 열 넣기/지우기 때 안 옮겨짐(`remapValidationRanges` 부르는 곳 없음) · 붙여넣기 · 채우기는 검사 안 거침 · 서버는 유효성 검사 안 함. + +--- + +## 2. 자체 스프레드시트 엔진이 되는 것 + +### 2-1. 함수 (`ss/spreadsheet_functions.ts:16-21` 에서 네 파일을 합침 · 모르는 이름 `#NAME?` · 인자 수는 풀이 때 검사) + +| 갈래 | 있음 (파일:줄) | +| --- | --- | +| 논리 | IF(misc 160) · AND 170 · OR 179 · NOT 188 · IFERROR 196 · IFS(lookup 471) · SWITCH 482 | +| 찾기 · 참조 | VLOOKUP(lookup 132) · HLOOKUP 166 · INDEX 200 · MATCH 233 · CHOOSE 269 · XLOOKUP 496 | +| 조건 집계 | COUNT · COUNTA · COUNTIF · SUMIF 319 · SUMIFS 345 · COUNTIFS · AVERAGEIF(S) · MAXIFS · MINIFS | +| 수학 · 끝수 | SUM 189 · PRODUCT · SUMPRODUCT 205 · ROUND 232 · ROUNDUP 243 · ROUNDDOWN 254 · INT 265 · TRUNC · CEILING 285 · FLOOR 300 · MIN 393 · MAX 401 · MROUND · ABS · MOD · POWER · SQRT · 삼각 · LOG · EXP | +| 글 | CONCATENATE · TEXT · TEXTJOIN · LEFT/RIGHT/MID · SUBSTITUTE · FIND/SEARCH … | +| 정보 · 날짜 · 통계 | ISNUMBER · ISBLANK · ISERROR · NA · DATE 계열 · MEDIAN · STDEV · RANK · LARGE/SMALL … | +| **없음** | XMATCH · LET · LAMBDA · INDIRECT · OFFSET · CONCAT · IFNA · ROW/COLUMN · 다른 통합문서 참조 · 마스터 자료를 읽는 함수 | + +연산 — `- + % ^ * / & = <> < <= > >=` · 범위 `A1:B5` `A:A` `$` · 합집합 `(A1,B1)` · 교차(빈칸) · 계산된 범위는 없음(`ss/spreadsheet_parser.ts:4-5,20-24,125,226-269`). 오류값에 엑셀에 없는 `#CYCLE!`. + +### 2-2. 이름 정의 · 시트 사이 참조 · 선택 목록 + +- **이름 정의** — `Sheet.이름정의: [{이름, 범위}]`(`ss/spreadsheet_types.ts:193,553-556`) · 범위만(상수 · 식 이름 없음) · 제 시트 먼저 → 다른 시트 · 대소문자 무시(`ss/spreadsheet_names.ts:47-60` · `ss/spreadsheet_graph.ts:87-113,150`) · 이름 상자 · 이름 관리자(`ss/spreadsheet_editor.ts:556-568` · `ss/spreadsheet_data_menu.ts:183`) — 계산에 실제로 붙음(형식 파일의 「안 이음」 설명은 낡음). +- **시트 사이 참조** — `Sheet2!A1` · `'시트 이름'!A1:B3` 됨(`ss/spreadsheet_parser.ts:21,39-42` · `ss/spreadsheet_eval.ts:252-254`) · 이름 바꾸면 다른 수식도 고침 · 3D(`S1:S3!`) · 다른 통합문서(`[Book]`) 없음. +- **선택 목록(데이터 유효성)** — `Sheet.유효성: [{범위, 규칙: {종류: "목록", 값들} | {종류: "수범위", 아래, 위}, 어기면: 막음 | 경고}]`(`ss/spreadsheet_types.ts:540-550`) · 칸 옆 ▼ 목록(`ss/spreadsheet_data_menu.ts:225-255`) · 들어갈 때 검사(`ss/spreadsheet_editor.ts:420-424`). +- **확인 도구** — 계산 단계 보기(`ss/spreadsheet_eval_steps.ts` — 엑셀 「수식 계산」 처럼 한 조각씩 값으로 바꿈 · IF 는 조건부터) · 선행/종속 화살표(`ss/spreadsheet_trace.ts`) · 오류 검사 ⚠(`ss/spreadsheet_errcheck.ts`) · 수식 칸 참조 색 테두리. + +### 2-3. 계산 · 크기 + +- 의존 그래프 · 바뀐 칸과 딸린 칸만 다시 셈 · 순환은 그 칸들만 `#CYCLE!`(`ss/spreadsheet_graph.ts:3-5,131-136,204-227,277-325,350-378`). +- 수 = BigInt 분수(`@ui/sheet/ui_template_sheet_frac` — 집계표와 끝수 한 벌 · `ss/spreadsheet_types.ts:7-9`) · 파이썬 단가 엔진은 `Decimal` — **같은 식이라도 두 엔진의 끝자리가 다를 수 있음**(대조 시험 필요). +- 파일 모양 — `Workbook {종류: "통합문서", 판, 열, 서식[], 시트[{id, 이름, 칸: {A1: {값 | 식, 서식}}, 병합, 열, 행, 유효성, 이름정의, 연결 …}], 계산값}`(`ss/spreadsheet_types.ts:95-102,198-242`) · 수식은 「=」 없이 · `계산값` 은 서버만 씀(브라우저 것은 버림). +- **128 KB 는 시트 파일 한도가 아님** — 브라우저가 M02 시트를 열 때 받는 코드 조각의 gzip 예산(엔진 48 + 화면 72 + css 8 KB · `ss/spreadsheet_types.ts:15-16` · 재는 곳 `resources/tester/spreadsheet/test_spreadsheet_size.py:19,41-45`). 시트 파일 크기 한도는 없음(행 1,048,576 · 열 16,384 만). +- 더할 수 있는 것(예산 안) — 함수 하나는 수십 줄 · 수 KB 미만이라 `찾기(표, 조건…)` · `단가(키)` 같은 자체 함수 몇 개는 엔진 48 KB 안에 들어갈 여지가 큼(지금 빌드 크기는 이번 조사에서 안 잼 — F 시험으로 잼). 단 `spreadsheet_types.ts` 머리 규칙상 엔진 · 계약은 「0 계약 주인」 만 고침 · 외부 라이브러리 0. + +--- + +## 3. 시트 계산을 누가 하나 + +| 때 | 누가 | 근거 | +| --- | --- | --- | +| 화면에서 고칠 때 | 브라우저 TS 엔진(보이기용) | `ss/spreadsheet.ts:199-214,269` | +| [저장](마스터 · 회사 · 개인 층) | **서버 — 파이썬이 같은 TS 엔진 Node 묶음을 부름** · 브라우저 `계산값` 은 버리고 서버 값으로 | `common_util/common_util_spreadsheet.py:17-57`(묶음 `config/spreadsheet_node/…` · 낡으면 `npm run build:spreadsheet` 로 다시 묶음 `:27-34`) · `common_util/common_util_node_bundle.py:60-93` · 부르는 곳 `M02_MasterTemplete_Store.py:169-170,462` · `M02_MasterTemplete_Router_Layers.py:318-324` | +| 프로젝트 사본 저장 | 서버 Node | `M02_Project_Items_Router.py:139-155` → `M02_Item_Copy.py:200-201` | +| 층 안 열 사이 복사 · 개인 층 저장 · 항목 복사 | 서버 Node | `M02_MasterTemplete_Store.py:316,364` · `M02_Item_Personal.py:107` · `M02_MasterTemplete_Items.py:155` | +| 프로젝트로 복사(templates/apply · seed · reset · 스냅숏) | **다시 안 셈** — 바이트 그대로(따라온 `계산값` 을 믿음) | `M02_MasterTemplete_Router_Layers.py:412-454` · `M02_Template_Layers.py:305,345,368` · `M02_Item_Snapshot.py:97-102,180-210` | +| B08 · B09 | 없음(빈 화면) | 위 1절 | +| 실패 | Node 실패 = `RecalcError` → 503 · 저장 막힘 · 묶기 300 초 · 돌리기 600 초 한도 | `common_util_node_bundle.py:27-28` | + +CLAUDE.md 5장과 대조: + +- 시트 자체는 **② 「TS 를 서버 Node 로」** 에 맞음(화면과 같은 코드 · 저장 때 서버가 다시 셈 · 브라우저 값 안 받아 적음). +- 프로젝트 복사 때 안 다시 셈 — 「초기값은 서버가 한 번 계산해 영구저장」 과는 맞으나, 마스터 쪽 단가가 바뀌어도 시트 `계산값` 은 그대로 따라감(시트는 마스터를 안 읽으니 지금은 문제 없음). +- 단가산출 로직은 **③ 서버 단독(파이썬 `master_formula`)** · 시트로 로직을 만들면 같은 값을 두 엔진(파이썬 정본 · TS 시트)이 내게 되어 「코드는 한 벌」 에 어긋남 → B 를 하려면 ① 「짝 + 거울 시험」 이거나, 시트는 편집기일 뿐 저장 때 로직 형식으로 바꿔 파이썬이 셈(시트 → 로직 변환이 필수). + +--- + +## 4. B 갈래 — 단가산출 로직 한 벌을 시트로 + +꼴(가정): 시트 ① 원문 표(표마다 한 시트) · ② 입력값 칸(선택 목록) · ③ 산출근거 칸(이름 붙은 수식) · ④ 항목 칸(종류 · 이름 · 단위 · 수량 · 단가 · 금액 · 비목). + +### 4-1. 로직 → 시트 (지금 형식 하나하나) + +| 로직 구성 | 시트로 | 됨? | 막힘 · 까닭 | +| --- | --- | --- | --- | +| 입력 · 고르기 | 입력 칸 + 선택 목록 | 됨 | 서버가 유효성 검사 안 함 · 붙여넣기는 검사 안 거침 | +| 입력 · 범위 | 수범위 유효성 | 됨 | 같음 | +| 입력 · 수 | 빈 칸 | 됨 | — | +| 중간(이름 = 식) | 이름 정의한 칸 + 수식 | 됨 | 이름은 범위만 · 칸 이름이 한글이면 엔진 이름 규칙 확인 필요 | +| 찾기 · 같음 조건 | `SUMIFS`/`MAXIFS`(수 값) 또는 `XLOOKUP`(묶은 열쇠 열) | 반쯤 | 「맞는 줄 없음 · 둘 이상」 을 엔진은 멈춤으로 알리는데 SUMIFS 는 0 을 조용히 냄 → 틀린 금액이 숨음 · 「빈 조건 칸 = 무관」 은 조건마다 `(칸="" 또는 칸=값)` 을 더 써야 함 | +| 찾기 · 범위 조건 | 아래 · 위 두 열 + MINIFS 등 | 어렵 | 범위규칙 다섯 가지(초과·이하 · 이상·미만 + 「마지막 칸은 이하 포함」 · 이하 = 위 끝 가장 작은 줄 · 이상·이하)(`master_formula.py:331-384`)를 수식마다 손으로 흉내 | +| 찾기 · 값 칸이 식 글(「L/V×2×60」) · 범위 값 [아래, 위] | 열 둘로 펴기 · 식 글은 따로 | 어렵 | 표 모양을 시트로 바꾸는 규칙이 새로 필요 | +| 만약 · 비교 · 그리고/또는 | IF · AND · OR | 됨 | — | +| 최소 · 최대 · 올림 · 버림 · 반올림(자리) | MIN · MAX · ROUNDUP · ROUNDDOWN · ROUND | 됨 | 수 표현(분수 대 Decimal) 끝자리 대조 필요 | +| 할증 `(1 + 율/100)` · % | 수식 · `%` | 됨 | — | +| 호표 수량 | 항목 칸 수량 = 수식 | 됨 | — | +| **호표 단가 — 인력 노임(LB)** | 단가 칸을 마스터에서 채워야 함 | **막힘** | 시트에 마스터를 읽는 함수 없음 · 다른 통합문서 참조 없음 → 서버가 칸을 채워 주는 새 연결(또는 `단가()` 함수) 필요 | +| **호표 단가 — 재료 검색어 고르기** | 〃 | **막힘** | 자동값 차례 · 단위 환산 · 지역 · 계약종별(`master_pick`)을 시트가 못 함 | +| **호표 — 기계(기계경비 로직 부름)** · 다른 로직 부름(1,075 줄 · 506 로직) | 〃 | **막힘** | 인자를 넘겨 다른 로직을 부르는 길 없음(LAMBDA · 다른 통합문서 없음) | +| 틀 키 `EQ:{기계}.가격` · `LB:{직종}` | 기계 · 인력 표 사본 + INDEX/MATCH | 막힘에 가까움 | 마스터 654 기계 줄을 시트마다 복사 | +| 덧줄 · 비목 합 × 비율 | `SUMIF(비목 열, "노무비", 금액 열) * 율` | 됨 | — | +| 덧줄 `줄.'이름'` | 칸 참조 | 됨 | — | +| 끝수 묶음 | 계 칸 ROUNDDOWN | 됨 | — | +| 돈 아닌 결과 식(작업량) | 결과 칸 하나 | 됨 | 다른 로직이 그 결과를 부르는 길은 위 「로직 부름」 과 같이 막힘 | + +### 4-2. 시트 → 로직 (거꾸로) + +- 자유 수식(A1 참조 · SUMIFS · INDEX · TEXT …)은 로직 식 문법(`_틀.md` 8장 — `+ - * /` · 비교 · 그리고/또는 · 찾기 · 로직 · 만약 · 올림/버림/반올림 · 최소/최대)에 짝이 없음 → **아무 시트나 로직으로 바꿀 수는 없음**. +- 되는 꼴 = 「제한된 시트」 — 칸 자리(입력 · 산출근거 · 항목)를 틀로 고정하고, 수식은 로직 문법 안의 함수만 · 표 찾기는 자체 함수 `찾기(표, 조건=…)` 하나로 → 이러면 사실상 「시트 옷을 입은 로직 식」 이고, 사용자는 여전히 식을 씀. +- 원문 표가 시트 안에 사본으로 들어가면 표 3,033개(로직이 부르는 것 2,015 · 한 표를 여러 로직이 씀)가 로직마다 복사 → 품셈 숫자가 바뀌면 사본마다 고쳐야 함. 피하려면 원문 표 시트를 「마스터 표를 비추는 읽기 시트」 로 두는 새 기능 필요(다른 통합문서 참조에 해당). + +### 4-3. B 를 하려면 새로 필요한 것 + +1. 엔진에 자체 함수 — `찾기(표키, 조건…)`(범위규칙 · 무관 · 해당 없음/중복 멈춤까지 파이썬과 같게) · `단가(키 또는 검색어)` · `로직(키, 인자…)` — 엔진 · 계약 주인의 고침 + 마스터 자료를 엔진에 넣는 길(브라우저 · Node 둘 다). +2. 시트 → 로직 변환기(저장 때) + 로직 → 시트 생성기(열 때) + 왕복 시험 1,469 개. +3. 또는 시트를 정본으로 두면 파이썬 엔진과 TS 시트 엔진의 거울 시험(분수 대 Decimal). +4. 알약 → 입력값 → 금액 사슬 잇기(지금 끊김 — 1-1). + +--- + +## 5. A 대 B 판단 거리 + +| 목적 | A 세 칸 판(원문 표 · 산출근거 · 결과 · 고르기) | B 엑셀 시트형 | +| --- | --- | --- | +| ① 원문 대조 확인 | **좋음** — 왼쪽에 마스터 표 그대로(사본 아님) · 걸린 줄 칠함 · 출처 칩 · 산출근거는 문장. 걱정: 원문 「주」 글은 표 밖이라 연결 표시를 따로 만들어야 함 | 좋음 · 걱정 — 표는 엑셀처럼 보이나 규칙은 칸 수식 속에 숨음(A1 참조) · 계산 단계 보기 · 화살표로 따라갈 수는 있음(`ss/spreadsheet_eval_steps.ts` · `ss/spreadsheet_trace.ts`) | +| ② 품셈 숫자 바뀜 직접 고침 | **좋음** — 마스터 표 칸 하나 고치면 그 표를 쓰는 모든 로직에 반영(표는 한 벌 · `용도.로직키` 로 영향 보기) | **걱정 큼** — 표가 로직마다 시트 사본이면 사본마다 고침 · 피하려면 「마스터 표를 비추는 시트」 새 기능 | +| ③ 혼자 새로 만들기(초등학생) | 좋음 — 단계 안내 · 선택 · 문장 틀(할증 · 나누기 · 조건 목록) · 식 안 씀. 걱정: 틀 밖 규칙(드문 식 10 %)은 「직접 입력 식」 으로 남음 | **걱정 큼** — 결국 수식 쓰기(SUMIFS · 무관 · 범위규칙) · 9-21 「식으로 새로 만들기」 와 같은 벽 · 엑셀 아는 어른에게만 쉬움 | +| ④ 많은 수 검증 | 좋음 — 표 조회 「해당 없음 / 중복」 검사 · 기대값 시험표 · 진행표 · 서버 일괄(`check_master 계산전부`)을 그대로 씀 | 반쯤 — 시트 하나씩은 단계 보기가 좋으나 1,469 개를 시트로 바꾸는 일 자체가 큼 · SUMIFS 가 0 을 조용히 내면 틀림을 놓침 | +| ⑤ 서버 엔진과 같은 값 | **좋음** — 저장은 지금 로직 형식 · 계산은 파이썬 정본 한 벌(③) · 판은 편집기일 뿐 | **걱정 큼** — 시트 값(TS · 분수)과 정본(파이썬 · Decimal) 두 엔진 · 단가 붙이기(노임 · 자재 · 기계경비)는 시트가 못 해 서버 칸 채우기 필요 · 거울 시험 새 짐 | + +### 5-1. 정리 + +- **본 갈래 = A.** 정본 형식 · 엔진 · 마스터 표를 그대로 두고 화면만 바꿈 — 다섯 목적 모두 「좋음」 쪽. 오늘 만든 쉬운 단가산출(Api · 카드 · 일위대가표)이 오른쪽 「결과」 칸으로 그대로 들어감. +- **B 에서 빌려 올 것(작게)** — ① 왼쪽 원문 표를 스프레드시트 격자(읽기 · 칸 눌러 고침)로 보이기 ② 계산 단계 보기처럼 「산출근거 한 줄씩 값으로 풀기」 ③ 입력값 선택 목록(데이터 유효성 모양) ④ 선행/종속 화살표 → 「이 값이 어디서 왔나」. +- **B 시험판을 꼭 만든다면** — 범위를 「제한된 시트」 로: 원문 표 시트(마스터 표 비춤 · 읽기) + 입력 칸 + 산출근거 칸(로직 문법 함수만 + `찾기()` 자체 함수) + 항목 칸(단가는 서버가 채움) · 저장은 로직 형식으로 바꿔 파이썬이 셈. 필요한 엔진 고침(자체 함수 · 마스터 자료 주입)은 「0 계약 주인」 몫이라 브레인 결정 필요. +- **따로 알릴 것** — M02 면적 · 재료 시트의 「알약 → 입력값 → 금액」 사슬이 끊겨 있음(1-1) · B 와 상관없이 B08 · B09 다시 지을 때 이을 자리.