2026-06-10 세션 — 견적 페이즈 B 10건 원문 재진단 (코드·운영/테스트 DB 실측)
논의·대안
견적(estimate) 후속 보완 페이즈 B에 착수. 시작 시 handoff 축약본의 페이즈 B 목록을 그대로 쓰려 했으나, 페페가 "축약돼서 오해가 많다, 최초 사용자 요청 원문을 가져오겠다"고 지적. 원문 10건을 1차 근거로 삼아 관련 문서(schema-estimate, design-estimate-copy, traps, 과거 세션 4건)와 실제 코드·운영/테스트 RDS를 전수 대조했다.
진행에 앞서 페이즈 A의 운영 반영 상태를 실측: deploy-live에 03b9583 없음(git merge-base --is-ancestor NO), 운영 라이브 field-types API 404 → 페이즈 A는 운영 미반영(테스트만). 페페 지시 = 페이즈 A 화면 확인은 완료로 보고 B를 먼저 진행, 운영 배포는 나중에. 따라서 B는 master(테스트) 기준으로 작업하고 운영 배포(A+B 묶음)는 별도 승인 위험작업으로 분리.
원문 10건 (사용자 최초 요청)
- 타입 이름 수정 기능. 이름이 수정돼도 기존 데이터 관계 안 깨지게.
- 타입 순서 드래그(오름차순 좌>우), 타입 앞에
1. 2.번호로 순서 표기, 이름과 분리, 수정은 이름만. - 항목 마진율이 수동 입력돼 있을 때 재로드 시 수동값 우선 표시.
- 전체마진은 업체 기준=자동. '자동' 버튼으로 표시.
- (중요) 항목 컬럼 순서·가로폭을 운영서버 기준으로.
- 항목 순서 변경 드래그 기능이 죽었음. 확인하고 살리기.
- 운영 서버 항목 컬럼에서 마감재 컬럼 숨기기.
- 복사 모달에서 현재 복사하는 행들을 다이어그램 밑에 표시(수정 불가).
- 복사 모달 미리보기가 위치 순서만 표시됨. 복사하는 계층의 항목을 간단히 보이게.
- 복사 후 해당 위치로 이동은 되나 하이라이트가 잘 안 보임. 보완.
결정 (페페 확정)
- 범위: 10건 전부 1회 진행.
- 1·2번 저장 시점: 저장 버튼에 통합(autosave 폐지 원칙과 일관). 신규 백엔드 포함.
- 5번: 테스트 DB
ui_column_setting을 운영 배열로 맞춤. - 7번: 이번 묶음에 포함(운영 DB UPDATE 승인됨).
결정 — 항목별 실측 현황 (재진단 결과)
| # | 원문 | 실측 | 작업 |
|---|---|---|---|
| 1 | 타입 rename | 타입탭에 복사(⎘)·삭제(×)만, rename UI 없음. 타입=estimate_detail.type_name 문자열, A에서 field_type SSOT 생김 | 신규: 인라인 편집 → detail.type_name 일괄 + field_type.name 동기, 저장 시 반영 |
| 2 | 타입 순서 드래그 + 번호 | 순서 UI 없음. field_type.display_order 컬럼만 존재(A). renderTypeTabs는 type_name 문자열 기반 | 신규: 탭 드래그 → field_type.display_order, 1. 번호 표시전용(이름과 분리) |
| 3 | 마진 수동값 재로드 | loadEstimate(410~)가 details를 매핑할 때 행별 _marginMode 미복원 → renderDetailTable이 _marginMode\|\|'auto'로 전부 auto. 재진입 시 수동 마진 유실. 전역(renderTotalCard 562)은 hasSavedMargin 복원됨 |
수정: loadEstimate에서 저장 margin_percent≠전역이면 행 _marginMode='manual' 복원 |
| 4 | 전체마진 자동 버튼 | 이미 구현 — marginModeLabel(자동/수동 배지)·applyGlobalMargin(532)·quickMarginInp·업체마진 자동반영(1750) |
미세 확인만(거의 완료) |
| 5 | 컬럼 순서·폭 운영기준 | 운영≠테스트 순서 자체가 다름. 컬럼은 DB(ui_column_setting)에서 loadColumnSettings(349)로 로드, defaultColumns()는 fallback. defaultColumns()=운영 배열과 동일(size 13뒤, act 폭만 150 vs 운영105). 운영: drag·twirl·no·cat·name·finish(vis1)·price·qty·unitsum·margin·marginAmt·total·size·note·act(105). 테스트: …cat·finish(vis0)·name·size(7)·price… → size가 앞, finish 숨김. + JS saveColumnOrderToServer(2482)가 payload에 width 없이 보내 모든 폭을 null로 덮는 버그 | 테스트 DB UPDATE(운영 배열·폭 복제) + width 저장 버그 수정 |
| 6 | 행 드래그 | main-row dragstart/drop 바인딩 전무(grep 0). drag 셀은 핸들 ≡ 아이콘만(704). 컬럼 헤더 드래그(2441~)는 별개로 동작. "죽었다"기보다 처음부터 미구현 | 신규 구현(행 재정렬 + display_order 반영) |
| 7 | 운영 마감재 숨김 | 운영 finish is_visible=1(미숨김), 테스트는 0 | 운영 DB UPDATE 1→0(되돌리기=1) |
| 8 | 복사 대상 행 목록 | renderCopyPreview(3007)는 대상 위치/병합 안내만, 복사 소스 행 목록 없음 | 신규: 다이어그램 밑 복사 소스행 목록(수정불가) |
| 9 | 미리보기 항목 표시 | sub 모드 대상 항목명(product_name)은 표시, 복사 소스 항목은 미표시 | 8번과 함께 복사 소스 항목 보강 |
| 10 | 하이라이트 약함 | css 240행 .new-row td{background:#fff8d8 !important;transition:.4s} + JS 1956 addClass 후 1.5초 제거. 색 옅음 |
색 강화 + 지속 연장 |
작업 묶음 (확정)
- 프론트 JS/CSS 코디 .md 1묶음: 1·2·3·4·6·8·9·10 + 5의 width 저장 버그 수정.
- 5번 테스트 DB UPDATE(ui_column_setting 운영 배열·폭): 분리.
- 7번 운영 DB UPDATE(finish 1→0): 위험작업·분리.
- 신규 백엔드: 1·2번 타입 이름/순서 동기화 — 저장 시 (B)
_upsert_field_types_from_details헬퍼 확장 또는 신규 동기화 API. field_type엔 PUT/type/<no>(단건)·POST/type만 있고 일괄 rename/순서 저장 API 부재. estimate 컨트롤러엔 타입 동기화 전용 경로 없음 → 지시문 작성 전 방식 확정 필요.
산출물·커밋
- 페이즈 A 검증(채티 독립 재확인): 코드 4파일 마커, Actions 27220897590 success, DB(SSM 읽기) display_order 컬럼·still_missing=0·표본현장 1..N 연속·1066/1337 count=2, 라이브 field-types?field_no=428 200(1~4순)·type-suggest 폴백 200. 시드 전 MAX(type_no)=1501→현재 3376. 별도 세션 = session-2026-06-10-type-ssot-phaseA.md.
- 페이즈 A 운영 미반영 실측: deploy-live에 03b9583 없음·운영 field-types 404.
- 운영/테스트 ui_column_setting 실측(SSM 읽기): 위 표 5번.
- 시드: projects/pfs/handoff.md(페이즈 B 10건 원문 재진단·작업 구조·운영 미반영 2.5절), 이 세션 문서.
- 진단만 수행, 코드/DB 변경 없음(읽기 전용 SSM·grep·git).
다음
- 1·2번 타입 이름/순서 동기화 백엔드 방식 확정(저장 시 헬퍼 확장 vs 신규 API).
- 프론트 묶음(1·2·3·4·6·8·9·10 + 5 width버그) 코디 .md 지시문 작성 → 테스트 배포·검증.
- 5번 테스트 DB ui_column_setting 운영 배열 정렬(테스트 DB UPDATE) — 되돌리기 SQL 포함.
- 7번 운영 finish is_visible 1→0(운영 DB UPDATE·위험작업 분리 승인).
- A+B 검증 후 운영 동일 적용(deploy-live 머지 + 운영 DB A시드 + finish 숨김) 별도 승인.
관계
- 주제: domain:estimate · svc:pfs-estimate
- 관련 문서: pfs-schema-estimate, session-2026-06-10-type-ssot-phaseA, pfs-design-estimate-copy
후속 (2026-06-10, 같은 날) — 백엔드 방식 확정 + 코디 지시문 작성
페페 지시: "전체 다 진행. 1·2번도 추천안으로 결정해 코디 지시문 1묶음으로. DB 업데이트·수정 모두 승인. 완료 후 텔레그램 보고." → 진단 마무리(코드 전수 + RDS 재실측) 후 지시문 1건 작성.
코드 전수 확인 (estimate_regist_v2.js 3114줄 + dao + service + html)
loadEstimate매핑:_marginMode미복원 확정(#3).renderTotalCard가 loadEstimate.then 직전 호출돼globalMarginPct세팅됨 → 매핑 시점 비교 가능.renderTypeTabs(595~): fieldTypes(div 필터) ∪ details 등장순. 순서/번호/드래그 없음. typetab HTML에 typetab-copy·x span(stopPropagation).margin-mode-btn핸들러(1594~): 클릭으로만 manual 됨 → loadEstimate 복원 필요 재확인.saveColumnOrderToServer(2482~): 진단 정정 — null이 아니라column_width: th.offsetWidth || null. 즉 NULL(자동폭) 컬럼이 드래그 한 번에 렌더폭으로 박제. → 기존 폭(State.columnSettings) 보존으로 수정.- main-row 드래그: 바인딩 전무(#6 신규).
.drag-handle(≡) span만. → mousedown으로 draggable 켜고 같은 그룹 내 재정렬. renderCopyPreview(3006~): 대상 위치/병합만. 소스(CopyModal.details/subs) 미표시(#8·#9).saveEstimate(2714~): masterPayload + detailList(stripDetail, subList). 타입 메타 동봉 지점 확정.addNewItemRow: new-row 1.5초. copy 함수들(copyItemsDirect/copyType/applyCopy)은 하이라이트 없음(#10).- 백엔드:
_upsert_field_types_from_details(estimate_dao 321~)가 insert/update 양쪽 commit 직전 호출되는 단일 지점. service_normalize_master는 화이트리스트 아님(None만 제거) → master에 임의 키 동봉 시 dao까지 통과. - field_type 컨트롤러: PUT/POST 단건만, 일괄 rename/순서 API 없음.
백엔드 방식 확정 (추천안 = 헬퍼 확장, 신규 API 없음)
저장 트랜잭션 안에서 3단계: _rename_field_types(rename 먼저 — field_type.name + 같은 field_no 견적들의 estimate_detail.type_name JOIN UPDATE로 관계 보존) → _upsert_field_types_from_details(새 이름 기준 멱등) → _reorder_field_types(표시순서대로 display_order 1..N). 프론트는 masterPayload에 field_type_renames[{from,to}]·field_type_order[name] 동봉. service 무수정(키 보존 통과). 근거: 저장 버튼 통합(autosave 폐지 원칙) + 단일 트랜잭션·단일 커밋 + 정합성 포인트 최소.
RDS 재실측 (SSM 읽기, env=/home/ubuntu/env/pfs-{test,live}.env)
- 테스트 ui_column_setting: drag(44) twirl(45) no(36) cat(221) finish(259,vis0) name(135) size(300) price(80) qty(90) unitsum(103) margin(109) marginAmt(103) total(106) note(276) act(105). → finish가 cat 뒤·숨김, size가 name 뒤(앞쪽).
- 운영 ui_column_setting: drag(30) twirl(30) no(36) cat(NULL) name(NULL) finish(NULL,vis1) price(NULL) qty(NULL) unitsum(NULL) margin(NULL) marginAmt(NULL) total(NULL) size(NULL) note(NULL) act(105). → name→finish→price 순, size는 note 앞(order13), 대부분 width NULL(자동), chk 컬럼은 DB에 없음(JS ensureChkColumn 주입).
- 진단 정정: ⑦ 운영 finish = vis1(노출 중) 확정 → 1→0 UPDATE 필요(세션 표의 "운영 finish vis1" 맞음).
- field_type 컬럼: type_no(PK) field_no name(varchar50) type_div(varchar5) display_order(int) body_comment door_comment imos_type remove_yn(char1) regist/modify — rename/순서 동기화 컬럼 전부 존재.
산출물
- 코디 지시문 =
C:\dev\pfs\CODI_estimate_phaseB_bundle.md(577줄). 구성: A 프론트JS(A-1~A-9: rename·순서드래그+번호·마진복원·width버그·행드래그·복사소스·하이라이트) / B CSS(B-1~B-4) / C 백엔드(C-1 헬퍼2개·C-2 호출교체) / D 테스트DB(ui_column_setting 운영배열 재INSERT, finish vis0) / E 운영DB(finish 1→0 위험작업). 검증·되돌리기·완료보고형식 포함. 선행확인 1건 명시(bulk_save가 delete-then-insert인지 → A-6 숨김컬럼 보정 분기). - 코디 미전달/미실행 — 채티 진단·지시문까지. 다음 = 코디 전달·실행.
- 진단만 수행, 코드/DB 변경 없음(읽기 SSM·grep·git·지시문 .md 작성).
다음
- 코디에
CODI_estimate_phaseB_bundle.md전달·실행 → 테스트 배포(master)·검증. - D(테스트 DB ui_column_setting 운영배열·finish vis0) → E(운영 finish 1→0) 순차(승인됨).
- A+B 검증 후 운영 동일 적용(deploy-live 머지 + 운영 DB A시드 + finish 숨김) 별도 승인.