다크모드
FE 메인테이너 — 도출근거 중첩 시트 패턴 (숫자 클릭 → 분개/T계정·계산 표)
정본 패턴(SSOT): leysys-design
docs/decisions/PATTERN-DERIVATION-NESTED-SHEET-2026-06-21.md. 오너 결정(2026-06-21): 파생 숫자의 근거는 인라인 펼침·서술이 아니라 클릭 → 중첩 시트에 표로. 차변=좌·대변=우. 전 도메인 1패턴.
무엇을 푸는가
ERP 상세에서 파생 숫자(원금·연체료·미수·세액)의 "왜 이 값?"을 보여주던 두 방식이 거부됨:
- 인라인 펼침 테이블(메인과 동일 크기 → 위계 구분 불가, 무엇의 근거인지 직관 안 됨)
- 서술식 행("원금 세구분 — 과세 4,000 · 부가세 400 …" → 스캔 불가)
- 부수적으로 펼침 쉐브론이 카드마다 좌/우 불일치.
→ 파생 숫자를 <button>(클릭 어포던스)로, 클릭 시 중첩 시트에 표로 근거 표시. 쉐브론·인라인 펼침·서술 전부 폐기.
핵심 파일
| 파일 | 역할 |
|---|---|
src/composables/useDerivation.js | 공유 상태 selectedDerivation(ref) + openDerivation(model) + 모델 빌더 periodPrincipalDerivation(period)(분개 T계정)·periodLateFeeDerivation(period)(계산+결과분개). 도메인 비의존. |
src/components/billing/_core/console/overlays/SheetDerivationArt.vue | 중첩 도출근거 시트(id="sheet-derivation-art"). kind:'journal'→차/대 2단 T계정, kind:'computation'→계산표+결과분개. |
…/collecting/detail/blocks/AllocationStatusOrg.vue | 충당현황 — 원금/연체료 셀이 data-derive-principal/data-derive-latefee 버튼. |
…/collecting/detail/blocks/CarriedInstallmentsOrg.vue | 이월미납 — 동일. 인라인 펼침·쉐브론 컬럼 제거. |
…/collecting/detail/blocks/SheetCollectingDetailArt.vue | 부모 시트. <SheetDerivationArt /> 1개 마운트(DialogCollectingCancelArt 옆). |
…/late-fee/overview/overlays/SheetLateFeeDetailArt.vue | 연체료 드릴다운 — 차수 연체료 클릭 → 계산표. <SheetDerivationArt /> 마운트. |
모델 계약 (useDerivation)
js
// 분개/T계정 — 회계 잔액(원금·미수·세액)의 근거
{ kind:'journal', title, subtitle?, debit:[{label,amount}], credit:[{label,amount}] }
// 계산 — 공식 파생(연체료 등). journal 있으면 결과 분개로 덧붙임
{ kind:'computation', title, subtitle?, columns:[{key,label,align?}], rows:[{...}],
resultLabel, result, journal?:{debit,credit} }periodPrincipalDerivation(period):period.byComponent(없으면principalByTax) → 대변 구성. 차변 = 미수관리비(합). 계정 라벨 맵CREDIT_ACCOUNT(과세원금→용역매출(과세) 등).periodLateFeeDerivation(period):period.lateFee.breakdown(구간·요율·일수·금액) → 계산표 + 결과분개(DR 미수 / CR 연체료수입).Math.round로 소수 표시 정정.
새 도메인에 적용하는 법 (전파 가이드)
- 근거 있는 숫자 셀을
<button class="font-medium cursor-pointer hover:underline" command="show-modal" commandfor="sheet-derivation-art" @click="openDerivation(model)">로. 0/근거없음은<span>. - 모델은 빌더 재사용 또는 직접 구성(분개면
{kind:'journal',debit,credit}, 계산이면{kind:'computation',columns,rows,result,journal?}). - 부모 시트 안에
<SheetDerivationArt />1개 마운트. - 차변 좌·대변 우 규약 준수(빌더가 보장). 신규 CSS 금지(sheet/table/card 조합).
전파 체크리스트 (전 도메인)
- [x] 수납 상세 — 이월미납(CarriedInstallmentsOrg) 원금·연체료
- [x] 수납 상세 — 충당현황(AllocationStatusOrg) 원금·연체료
- [x] 연체료 현황 드릴다운(SheetLateFeeDetailArt) 차수 연체료
- [ ] 회계 전표 상세(SheetReadBillingVoucherArt) — 분개 라인 → T계정/세구분
- [ ] 세금계산서 — 과세/면세/영세 구분 도출
- [ ] 결산·예산(budget MainOrg) — 집계 과목 → 구성 도출근거
- [ ] 청구/수납 리스트 DynamicTableOrg(invoicing·collecting) 행 펼침 → 패턴 통일 검토(현 toggleExpand 잔존)
- [ ] CollectingActionOrg 충당결과 세구분 행 — 패턴 통일 검토
테스트
__tests__/CarriedInstallmentsOrg.spec.js·AllocationStatusOrg.spec.js: 클릭 →selectedDerivation모델(kind·debit/credit·rows) 검증. jsdom은 Invoker Commands 미구현이라 시트는 안 열리나@click핸들러는 실행 → 모델 단언으로 검증.- 시각:
scripts/probe-derivation-sheet.mjs(Playwright) — 모바일 뷰포트로 원금→T계정·연체료→계산표 캡처.
주의
- 중첩
<dialog showModal>스택(부모 시트 위) — 콘솔 선례(DialogCollectingCancelArt). top-layer 자동 스택. - 도출근거 시트 폭 =
sheet-width-md(부모 3xl보다 좁게 — 데스크톱서 뒤 시트 비침). 모바일은 전체 덮음(정상). SheetDerivationArt는 빌링 overlays에 위치하나 도메인 비의존 — 전파 시 공용 위치로 승격 가능.
2026-06-21 라이브 리뷰 갱신 (운영관점 재설계 + 시간축 + 충당내역 + 용어)
오너 라이브 리뷰로 수납 상세를 운영관점으로 재설계. 회계 분개(T계정)는 수납 화면에서 제거(회계 전표 도메인 전용으로 유보).
- 도출근거 운영 kind:
useDerivation빌더 재작성 —periodPrincipalDerivation→kind:'breakdown'(부과액−기납부−감면=미수 + 미수 세구분 + 충당내역(payments) + 법정충당 안내),periodLateFeeDerivation→kind:'latefee'(구간별 대상원금 컬럼 + 연이율 + 산식, 분개 제거).SheetDerivationArt가 두 kind 렌더(journal/computation 미사용). - 단일 차수별 표:
CarriedInstallmentsOrg삭제,AllocationStatusOrg= "차수별 미수·수납"(월분·납기·부과액·수납·미수금·연체료·받을금액). 표w-max(콘텐츠 폭) + 카드overflow-x-auto(모바일 가로 스크롤). 부과액/연체료 숫자 클릭 → 도출근거. - 시간축 케이스:
useForwarding확장 — 당기 부과 없는 계약(이월만)도 행 생성(hasCurrent플래그, prior-only 계약 append, 3축 대칭). 상태 배지 정상/정산대기(detail.identity.billingStatus). 데모: 정산대기 세대(c-end, 당기 없음·장기연체 3단계), 중단·재개 세대(c-gap, 차수 공백). - 차수별 납기: 납기 = 익월
dueDay일(기본 5, 시드period.dueDay로 차수별 변동). 연체료는 각 차수 납기 기준.useForwarding.nextMonthDay. - 부분납부 연체료 정합:
useLateFee가 영수증(appliedBreakdown일자별)을 연체료 엔진payments로 전달 → 납부일 기준 구간 분할(대상원금 변동). 원금 = 부과액−감면. - E3 정합:
vouchersLateFeeAccrual이forwardingByContract기반(정산대기 연체료도 GL 반영). - 용어 툴팁:
composables/glossary.js(용어집) +components/common/TermTip.vue(DS.tooltiphover). 표 헤더·합계 라벨에 적용.
2026-06-22 갱신 — 세구분 분류 레이어(매출/비매출:부채·자본)
오너 지적: 장기수선충당금·예비비적립금을 세구분 표에 단독 항목으로 노출하면 범용성이 떨어진다(각각 부채·자본의 한 인스턴스). → 분류(매출/부채/자본) 롤업 레이어 추가. 특정 항목을 성격 카테고리로 묶어 표시.
billingNature.js분류 레이어(신규, GL·componentOf불변):componentGroup(component)→'매출'|'부채'|'자본'. 매출 세분(과세/면세/영세·부가세)은 매출, 그 외 성격명 키는BILLING_NATURE[component].group. 미등록은 매출 폴백.groupByComponentNature(items)→[{group, label, rows, billed, paid, outstanding}](COMPONENT_GROUP_ORDER 순, 빈 그룹 제외).COMPONENT_GROUP_ORDER=['매출','부채','자본'],COMPONENT_GROUP_LABELS={매출:'매출', 부채:'비매출 · 부채', 자본:'비매출 · 자본'}.- ⚠ 부가세는 본질상 예수금(부채)이나 공급대가 관례로 매출 그룹에 묶어 표시(오너 멘탈모델 일치). GL은 별도 0255 예수금 계정.
useDerivation.js:periodPrincipalDerivation이components(평면, 각 항목에component키)에 더해componentGroups(분류 롤업) 방출.SheetDerivationArt.vue: 세구분 표를 분류별<tbody>섹션으로 — 그룹 헤더 행(라벨+소계,bg-neutral-subtle font-medium) + 항목 행(pl-4들여쓰기). 헤더 안내 "세구분 — 부과 → 충당 → 미수 (매출 / 비매출)".- 범용성: 새 부과항목(예: 하자보수충당금 group:부채)이 등록되면 코드 변경 없이 비매출·부채로 자동 분류·롤업. 검증:
scripts/probe-derivation-sheet.mjs(당기 차수 → 매출+비매출·부채 그룹 + 장기수선충당금 항목). - 테스트:
billingNature.spec.js에componentGroup/groupByComponentNature/COMPONENT_GROUP_ORDER단언 추가.
잔여(전파)
- 충당순서 설정 UI(setting/collecting)도 동일 분류로 그룹핑 + 정책 구간 드래그 정렬(법정 연체료→원금 잠금) — 다음 트랙(오너 ②).
- 연체요율 설정(12/24/36/48%) ↔ 엔진(3/4/5%) 목업 불일치 와이어링 — 별도 트랙.
- 회계 전표(분개 T계정 archetype)·세금계산서·결산 근거에 도출근거 패턴 전파.
- 정산대기 unit/member 축은 contract 축과 동일 확장 완료(3축). 신규 콘솔/이관 정산(전기이월)은 별도 트랙.
- 매뉴얼(collecting-cases) 예시 숫자·스크린샷 단지 규모 리프레시(누적 미반영).