다크모드
BE 참고 — 빌링 메뉴 IA 통합이전 + CoA 공유 인프라화
독자: BE 개발자/AI. 정본 스펙:
docs/superpowers/specs/2026-06-20-billing-menu-ia-coa-consolidation-design.mdas-built 기준: 2026-06-20 (브랜치feature/billing-menu-ia-coa-consolidation, main 머지 예정)
이 문서는 CoA(계정과목) 3계층 소유권 모델, 활성 프리셋의 워크스페이스 엔티티 속성으로서의 의미(분개 영향 포함), CoA 데이터 SSOT 계약, always-open account-setting 게이팅 불변식, 구독 전이 회복력 규칙을 정의한다.
0. Workspace 메뉴 표시명 계약 (2026-07-16)
- 판매·구독 상품의 정본 이름은
PRODUCT_MODULES[].name = '관리비'다. - Workspace 업무 메뉴와 홈 업무 카드에서는 행위 범위를 명확히 하기 위해
menuLabel = '관리비관리'를 사용한다. - 상품명·가격표·계약 데이터와 라우트 키
service-charge는 바뀌지 않는다. 따라서 백엔드의 상품 코드, 권한, 구독 판정에는 영향이 없다. - 메뉴 표시명을 서버 데이터나 상품명으로 역해석하지 않는다. 서버 계약은 계속
service-charge키를 사용한다.
1. 3계층 소유권 모델
| 계층 | 소유 주체 | 가용성 조건 | 역할 |
|---|---|---|---|
데이터 SSOT (useChartOfAccounts + 활성 프리셋) | 워크스페이스(엔티티) | 항상 | 계정 데이터 정본. 어느 모듈 ON↔OFF에도 불변 |
| 계정과목 설정(저작 표면) | 회계 앱 account/general | always-open (account-setting만 ungated; 그 외 회계 메뉴는 accountingEnabled) | 계정과목 등록·열람·커스터마이즈의 단일 표면 |
| 관리비설정 · 퀵검침 | service-charge 앱 | 관리비 모듈 ON | service-charge 라인 config. 계정과목과 무관 |
핵심 원칙: CoA 저작은 관리비 분개(useBillingJournal)와 회계 장부(useGeneralLedger) 양쪽의 전제 인프라다. 회계 프리미엄으로 게이팅하면 분개 발생 전에 계정이 없어 무결성 오류가 생긴다. → always-open.
2. 활성 프리셋 — 워크스페이스 엔티티 속성
2-1. 무엇인가
useBillingPreset(싱글톤, localStorage leyve.billing.preset)이 관리하는 값. 현재 정의:
js
// 가능한 값
"공동주택"; // 국토부고시 2023-300
"집합건물"; // 법무부고시 2021-218
null; // 미선택(도메인 비활성 — 범용 계정만)데모 레포 기본 = '공동주택'.
2-2. 분개에 미치는 영향
useBillingJournal.vouchersInvoicing()이 componentCredit()을 읽어 성격별 대변 계정을 결정한다.
| 프리셋 | 장기수선충당금 대변 계정 | 예비비적립금 대변 계정 |
|---|---|---|
공동주택 | 9112 장기수선충당금 | 9201 예비비적립금 |
집합건물 | 9113 수선적립금 | 9201 예비비적립금(준용) |
null | 미매핑 안전 폴백(accountCode '') | 미매핑 안전 폴백 |
- 미매핑 폴백은 차대 균형을 유지한다(accountCode 공백, accountName '미매핑(프리셋 미선택)'). 다운스트림 GL은 accountCode 공백 방어 처리 필요.
- 프리셋은 분개 발생 시점의 값을 소비한다. 프리셋이 변경되면 이후 분개부터 적용된다(과거 분개 소급 없음 — 실서비스 주의).
2-3. 워크스페이스 소유의 의미
프리셋 = "이 단지(엔티티)가 공동주택인가 집합건물인가"라는 엔티티 고유 속성이다.
- 실서비스 BE 구현 시: 프리셋은 워크스페이스 엔티티 테이블(예:
workspace.billing_preset)에 저장한다. 현재 프로토는 localStorage에 저장하나 이는 단일 기기 데모 전용이다. - 어느 모듈(회계 OFF, 관리비 OFF)이 꺼져도 워크스페이스 엔티티에 붙어 있으므로 프리셋이 소멸하지 않는다.
- 도메인 계정(9112·9113·9201)은 프리셋을 통해 CoA 데이터 SSOT에서 파생된다. 모듈이 꺼져도 CoA 데이터는 유지된다.
2-4. 네이밍 메모(후속 후보)
useBillingPreset / leyve.billing.preset의 billing 스코핑은 워크스페이스 소유 의미와 어긋난다. 코드 리네임(useWorkspacePreset, leyve.workspace.preset 등)은 후속 작업으로 분류됨. 본 스펙 범위 밖.
3. CoA 데이터 SSOT — useChartOfAccounts
js
// src/composables/useChartOfAccounts.js
useChartOfAccounts(activePacks?: string[]) → accounts[]- 순수 함수(Vue import 0, 사이드 이펙트 없음).
CORE_ACCOUNTS(0xxx 범용 계정) ∪PACKS[팩코드](도메인 계정) 합산.activePacks가 없으면 코어만 반환한다.
팩 매핑 (현재 단일 팩, as-built)
js
// PRESET_PACK (as-built)
{
'공동주택': 'service-charge',
'집합건물': 'service-charge',
}
// → PACKS['service-charge'] = SERVICE_CHARGE_ACCOUNTS (9112·9113·9201 등 포함)- 현재 공동주택·집합건물이 단일
service-charge팩을 공유한다. 도메인 별도 팩 분할은 후속. - 회계 account-setting 화면은
useChartOfAccounts([PRESET_PACK[활성프리셋]])으로 소비한다. 프리셋 미선택 시 코어만 표시.
불변식
useChartOfAccounts함수 시그니처·반환 형태 무변경. 프리셋·팩 구조 변경은 이 함수 내부에서만.- 9xxx 도메인 계정의
coreMapping필드: null이면 GL에서 9xxx 그대로 사용(허용). coreMapping이 있는 9xxx는 0건(누수 불변식).
4. always-open 게이팅 불변식
4-1. 계정과목 설정(account/general)은 항상 접근 가능해야 한다
| 상태 | 계정과목 접근 | 그 외 회계 메뉴 접근 |
|---|---|---|
| 회계 ON | 가능 | 가능 |
| 회계 OFF | 가능 | 불가(게이팅) |
| 관리비 ON | 가능 | 가능(회계 ON이면) |
| 관리비 OFF | 가능 | 가능(회계 ON이면) |
4-2. 구현 위치 (as-built)
- 워크스페이스 런처 (
components/workspace/AppAsideOrg.vue): 회계 앱 그룹이 항상 노출됨. 그룹 내 서브메뉴 중 계정과목(account/general 딥링크)은 ungated. 그 외 서브메뉴는accountingEnabled로 게이팅. - 회계앱 내부 사이드바 (
components/accounting/AppSideNavMenuOrg.vue):account/general항목만 ungated. 나머지 섹션(전표·원장·재무제표 등)은accountingEnabled게이팅. - service-charge 사이드바 "계정과목" 그룹:
/service-charge/setting/account/general에서 같은 CoA SSOT를 소비한다. 관리비 셸을 유지하며 데이터·API 계약은 회계 계정과목과 동일하다.
4-3. 실서비스 구현 원칙
- account-setting ungated 원칙은 API·라우트 가드에도 적용해야 한다. 계정과목 조회·등록 API는 모듈 구독 없이도 접근 가능해야 한다.
- 세금계산서·전표·원장·재무제표 API는
accountingEnabled체크 후 접근.
5. 구독 전이 회복력 규칙
세 계층(데이터 SSOT · 저작 표면 · 관리비설정)이 서로 hard dependency가 없어 어느 표면이 사라져도 나머지가 잔존한다.
| 전이 시나리오 | 데이터 SSOT | 계정과목 저작 표면 | 관리비설정 표면 | 분개 |
|---|---|---|---|---|
| 회계 OFF → 회계 ON | 유지 | 유지(always-open) | 유지 | 복원 |
| 관리비 OFF → 관리비 ON | 유지 | 유지 | 유지 | 복원 |
| 회계+관리비 동시 ON → 회계만 ON | 유지 | 유지 | 불노출(관리비 OFF) | 유지(도메인 계정 포함) |
| 회계+관리비 동시 ON → 관리비만 ON | 유지 | always-open으로 유지 | 유지 | 분개 미리보기 불노출(accountingEnabled=false) |
핵심: 프리셋이 워크스페이스 소유이므로 "회계만 ON" 상태에서도 도메인 계정이 account-setting에 계속 보인다. 6뷰 편의 표면(구 /billing/accounting-account/*)은 관리비와 함께 사라졌으나, 데이터와 저작 표면(회계앱)은 잔존한다.
6. 제거된 구조 (as-built)
6-1. 계정과목 6뷰 제거
- 제거:
/billing/accounting-account/{building,housing,property}/{balance-sheet,income-statement}6라우트 - 제거:
views/billing/accounting-account/*·components/billing/accounting-account/* - 수렴: 회계 앱
account/general단일 화면(프리셋 인지 + BS/IS 탭)
6-2. 관리비설정 라우트 이전
- 이전 전:
/billing/setting/*(7라우트) — 빌링 우산 소유 - 이전 후:
/service-charge/setting/*(7라우트) — service-charge 라인 소유(buildLineRouteslineLevel 슬롯)
6-3. 빌링 우산 축소
components/billing/AppAsideOrg.vue: 대시보드·CMS·업무·관리비설정·계정과목 그룹 제거 → 빌링 타이틀 + hospitality 폴백만 잔존
7. 엣지케이스 / 주의사항
- 프리셋 미선택(null) + 도메인 성격 charge: 분개 대변에 미매핑 안전 폴백 라인(accountCode '')이 생긴다. 차대 균형은 유지되나 GL 전기 불가 상태. 데모 레포(공동주택 시드)에선 무발생. 실서비스는 워크스페이스 생성 시 프리셋 강제 선택 또는 null 방어 로직 필요.
- 프리셋 단일 팩: 현재
PRESET_PACK이 공동주택·집합건물을 모두'service-charge'팩으로 매핑한다. 도메인 별도 팩 분할(공동주택 팩/집합건물 팩) 시 이 매핑과PACKS객체를 함께 수정해야 한다. 엄격 도메인 필터(팩 분할 후 해당 단지 유형 계정만 표시)는 후속. - 연체료 기준:
useLateFee는period.outstanding(공급대가, VAT 포함)을 연체료 base로 사용. VAT 제외 base가 필요하면 G3b/G4에서 설정.
8. 관련 파일
| 레이어 | 파일 |
|---|---|
| CoA 데이터 SSOT | src/composables/useChartOfAccounts.js |
| 활성 프리셋 | src/composables/useBillingPreset.js |
| 분개 성격별 대변 | src/composables/useBillingJournal.js (vouchersInvoicing) |
| 성격·계정 매핑 | src/composables/billingNature.js (UNIVERSAL_COMPONENT_CREDIT) · src/data/billingPresets.js (BILLING_PRESETS[preset].domainCredit) |
| 라인 디스크립터 | src/data/billingLines.js (descriptor.sidebar 그룹 구조) |
| 라우트 팩토리 | src/router/buildLineRoutes.js (lineLevel 슬롯) |
| 게이팅 | src/composables/useModuleSubscription.js (accountingEnabled) |
| 런처 사이드바 | src/components/workspace/AppAsideOrg.vue (always-open 게이팅) |
| 회계앱 내부 nav | src/components/accounting/AppSideNavMenuOrg.vue (account-setting ungated) |
| 회계 CoA 화면 | src/components/accounting/.../basic-setting/account/general/blocks/DynamicTableOrg.vue |