Skip to content

설정 스코프 — 백엔드 참고 (프리셋/글로벌/로컬 + 전파 클래스)

정본 ADR: docs/decisions/SETTINGS-SCOPE-GLOBAL-LOCAL-PRESET-2026-06-22.md. 본 문서는 BE 계약·불변식 요약.

3계층 + 전파 클래스

preset(코드 불변 권장값) ──기본──▶ global(조직 기본값) ──생성 시 스냅샷──▶ local(콘솔별)
클래스resolve글로벌 변경 → 기존 콘솔로컬 override적용 예
frozen(기본)local(생성 시 materialize)불변(스냅샷)허용충당순서·인식기준·납기일·반올림
liveglobal ?? preset즉시 동기(버전 없음)금지세금구분·성격(BILLING_NATURE)·CoA
effective-datedversionAt(key, txDate)날짜로 공존(소급 없음)금지부가세율·연체 법정요율
notifylocal ?? global ?? preset + 배너opt-in허용(선택) 정책 롤아웃

구현 상태 (as-built)

  • frozen — 충당순서(lateFeePolicy.collectionPolicy): ✅ PRESET_COLLECTION_POLICY + globalCollectionPolicy(ref) + policy.collectionPolicy(로컬). setCollectionPolicy(partial, scope) / resetCollectionPolicy(scope). 빌링 엔진은 항상 로컬.
  • effective-dated — 부가세율(VAT): ✅ (2026-06-22). 아래 §부가세 계약.
  • effective-dated — rateSchedule(연체 법정요율): ✅ (2026-06-22). 아래 §연체요율 계약.
  • live — BILLING_NATURE/CoA: ❌ 예정(현재 코드 const).

effective-dated 인프라 — effectiveDated.js

  • 버전 모델: [{ effectiveFrom: 'YYYY-MM-DD', ...payload }]. 신·구 값이 날짜로 공존.
  • versionAt(versions, txDate) = effectiveFrom ≤ txDate 중 최신(전부 미래면 가장 이른 버전 폴백). YYYY-MM-DD 사전식 비교.
  • 불변식: 과거 거래는 과거 effectiveFrom 버전을 선택 → 이미 굴러간 계산은 소급 변경되지 않는다(감사 추적). 글로벌에 미래 버전을 추가해도 과거 전표 불변.

부가세 계약 (billingNature)

  • PRESET_VAT_SCHEDULE = [{ effectiveFrom: '1977-07-01', rate: 0.1 }] (한국 부가세 도입 후 10% 불변 → 단일 버전).
  • vatRateAt(txDate) = 거래일 유효 부가세율. 모든 VAT 산출이 이 함수 경유(공급대가 = 공급가액 + 공급가액×vatRateAt(거래일)).
    • 소비: withVat(byComponent, date), useBillingJournal(거래일 = 전기일 POSTING_DATE), useAllocations(세금계산서), useMoveOutSettlement·useProvisionalSettlement(정산).
    • VAT_RATE = 현재 기준 편의값(=vatRateAt()) — 표시·하위호환. 엔진 계산은 거래일 기준 vatRateAt(date).
  • setVatSchedule(versions) = 글로벌 개정(정규화). scope 인자 없음 = 로컬 override 불가(글로벌 전용).
  • BE 전환: txDate는 청구/전표 거래일. 부가세 개정 시 globalVatSchedule{effectiveFrom: 개정일, rate: 신율} 추가 → 개정일 이후 거래만 신율, 과거 무변. 멀티콘솔에서도 부가세는 콘솔별이 아닌 법정 단일(글로벌) — 콘솔 키 스토어에 두지 않는다.

연체요율 계약 (lateFeePolicy)

  • PRESET_RATE_SCHEDULE_VERSIONS = [{ effectiveFrom: '2000-01-01', schedule: [{fromMonths, annualRate}] }] (데모 단일 현행 버전 — 모든 데모 차수에 적용). globalRateScheduleVersions(ref·글로벌 전용).
  • rateScheduleAt(txDate) = 거래일 유효 tier-table. setRateSchedule(schedule, effectiveFrom?) = 글로벌 개정(effectiveFrom 미지정 = 현행 버전 교체). 로컬 override 없음.
  • 엔진 통합: interestEngine.lateFeeOfpolicy.rateScheduleVersions 있으면 차수 납기일(dueDate) 기준 버전 선택(versionAt) → 그 채무에 적용되는 요율표. 버전 미제공이면 flat policy.rateSchedule 폴백(레거시 호환). useLateFee{...policy.value, rateScheduleVersions} 주입.
  • policy.rateSchedule현재 청구기 유효 단계표로 동기(표시·rateScheduleRows·하위호환). 엔진 계산은 거래일 버전.
  • 불변식: 각 tier-table 첫 구간 fromMonths=0 필수. 데모는 단일 버전 → 결과 무회귀.
  • 후속: 달력 구간별 요율 선택(한 차수의 연체기간이 개정일을 걸치면 구간마다 다른 버전) — 현재는 납기일 단일 버전. 설정 UI 버전 이력(적용일 편집기)도 후속.

규칙3 (글로벌 변경 → 기존 콘솔 불변)

  • frozen: 글로벌·로컬 독립 ref(라이브 바인딩 X) — 글로벌 변경이 로컬 스냅샷에 영향 없음(단위 테스트).
  • effective-dated: 동기화가 아니라 거래일 버전 선택으로 과거 보존(force-sync 아님).
  • 빌링 엔진은 frozen은 로컬, effective-dated는 거래일 버전을 읽음 — 글로벌은 신규 콘솔 시드/법정 정본 표면.