급여 코드 모듈 레퍼런스
급여 시스템은 시트 기반 정산으로 수당과 공제를 계산합니다. 금액을 만드는 계산 자체는 @hereby/code-modules 패키지의 코드 모듈(소스 모듈당 순수 함수 compute(inputs, parameters) 하나)이 담당하고, 그 입력을 DB에서 읽어 열 단위로 실행하는 것은 시트 정산 로더(packages/api/src/routers/sheet-rows/compute.ts)입니다. 항목별 설정(항목 코드, 소스 모듈, value key, 요율/배수 파라미터)은 시트 컬럼 메타데이터 + 조직 파라미터 저장소에 보관되며, AllowanceRecord / DeductionRecord는 시트 커밋(commitSheet, ✓ 커밋) 시에만 삽입됩니다. 참고: Payroll Schema Refactor, 급여대장 데이터 프로비넌스.
예전
packages/api/src/calculators/의AllowancePipeline/DeductionPipeline계산기 파이프라인은 시트 정산으로 바뀐 뒤 급여를 만들지 않는 죽은 경로였고(Module Manager 메타데이터 조회에만 사용), 2026-09에 제거됐습니다. 이 문서는 현재 경로만 설명합니다.
아키텍처
같은 코드 모듈이 hr-system 브라우저(apps/hr-system/src/sheets/workbook/commit-compute.ts)에서도 실행돼 미리보기와 서버 커밋 결과가 구조적으로 일치합니다.
정산 흐름
- 시트 열의
sourceModule별로 입력 로드 —loadInputsByModule(ctx, sourceModule, rows, period)가 소스 테이블(근로계약,overtime_records등)을 시트 기간으로 조회해 행별 입력 맵을 만듭니다. - 행 × 모듈 열마다
compute(inputs, parameters)실행 — 파라미터는 열 메타데이터 + 조직 파라미터 저장소를mergeWithDefaults로 합친 값입니다. - 열의 value key로 출력 중 하나를 골라 셀에 기록합니다.
- ✓ 커밋 시
commitSheet가 셀 값을AllowanceRecord/DeductionRecord로 기록합니다(시트 계보sourceSheetId/sourceSheetRowId/sourceSheetColumnKey).
인터페이스 (packages/code-modules/src/types.ts)
CodeModule
| 필드 | 타입 | 설명 |
|---|---|---|
sourceModule | SourceModule | 레지스트리 키 (enum 값과 동일) |
parameterSchema | ParameterField[] | 설정 가능한 파라미터 정의 (설정 폼 렌더링·검증) |
defaultParameters | Parameters | 파라미터 기본값 |
keyDescriptions | KeyDescription[] | compute()가 돌려주는 출력 키 설명 |
compute(inputs, parameters) | function | 순수 계산 — Record<string, number> 반환 |
KeyDescription
시트 컬럼의 value key 설정 시 힌트로 사용됩니다.
| 필드 | 타입 | 설명 |
|---|---|---|
key | string | 값 키 식별자 |
label | string | 표시 라벨 |
description | string | 사람이 읽을 수 있는 설명 |
unit | string | 단위 ("원", "시간", "건", "%") |
ParameterField
| 필드 | 타입 | 설명 |
|---|---|---|
key | string | 파라미터 식별자 |
label | string | 표시 라벨 |
description | string | 설명 |
type | enum | number, string, boolean |
defaultValue | mixed | 기본값 |
min / max / step | number | 숫자형 제약 (선택) |
suffix | string | 입력란 뒤 단위 라벨 (예: "%", "시간", "원") |
코드 모듈 목록 (packages/code-modules/src/registry.ts)
수당
| 모듈 | 소스 모듈 | 입력 로드 소스 | 설명 |
|---|---|---|---|
employmentContractModule | employment_contract | employment_contracts | 근로계약 기반 기본급·호봉·근속 |
overtimeRecordModule | overtime_record | overtime_records + overtime_types | 승인된 연장근무 가산 (카테고리 배율 + 관리형 유형 배율) |
fixedIncentiveModule | fixed_incentive | fixed_incentives | 기간 내 승인된 고정 인센티브 |
educationSubsidyModule | education_subsidy | education_subsidies | 기간 내 승인된 교육보조금 |
resignationRecordModule | resignation_record | resignation_records 등 | 퇴직정산 |
yearEndSettlementModule | year_end_settlement | year_end_settlements | 연말정산 환급/추징 |
공제
| 모듈 | 소스 모듈 | 설명 |
|---|---|---|
insuranceModule | payroll_rate_config | 4대보험 (국민연금, 건강보험, 고용보험, 산재보험) |
taxBracketModule | tax_bracket_config | 근로소득세 + 지방소득세 |
수동 모듈
sourceModule = "manual" 열은 계산을 우회합니다. unitPrice x multiplier가 직접 금액으로 사용됩니다.
초과근무 버킷 매핑 (조용한 과소지급 가드)
loadInputsByModule의 overtime_record 분기가 OvertimeCategory를 모듈 입력 버킷으로 바꿉니다. 정본은 .claude/rules/payroll/korean-payroll-compliance.md입니다.
| 카테고리 | 채우는 버킷 | 유효 배율 (기본값) |
|---|---|---|
WEEKDAY | weekday | 1.5x |
NIGHT | weekday + night | 1.5x + 0.5x = 2.0x |
HOLIDAY | holiday | 1.5x |
HOLIDAY_NIGHT | holiday + night | 1.5x + 0.5x = 2.0x |
SATURDAY (deprecated) | weekend | 0.5x (구데이터 호환) |
- 관리형 유형(
typeId)이 지정된 기록은 카테고리 버킷 대신typeWeightedHours(시간 × 유형 배율)로만 가산합니다. 야간·휴일 일수(야간 식대 등)는 카테고리 기준으로 그대로 셉니다. - 정산은
approved·report_pending·report_approved·report_rejected상태만 집계합니다. - 소정 시간 내 야간·휴일(
attendances.nightHours/holidayRegularHours/holidayNightHours)은 이 모듈 입력에 넣지 않습니다. 시트에서는 근태(attendance) 소스 ref 열로 따로 참조합니다. - 회귀 가드:
packages/api/src/routers/sheet-rows/payroll-correctness.test.ts(모듈compute()고정). 로더 레벨 매핑은 DB가 필요해 아직 단위 테스트가 없습니다.
새 코드 모듈 추가 방법
packages/code-modules/src/modules/my-module.ts에CodeModule구현 (parameterSchema,defaultParameters,keyDescriptions,compute)packages/code-modules/src/registry.ts와index.ts에 등록/exportpackages/api/src/routers/sheet-rows/compute.tsloadInputsByModule에 입력 로드 분기 추가 (브라우저 미리보기가 필요하면 hr-systemcommit-compute.ts에도)- 새 소스 모듈에 바인딩된 시트 컬럼 추가 (항목 코드, value key, 파라미터는 컬럼 메타데이터 + 조직 파라미터 저장소)
keyDescriptions의 키가 시트 컬럼 설정 UI와 Module Manager에 노출됩니다
모듈 레지스트리 라우터
module-registry 라우터는 listCodeModules()를 읽어 모든 소스 모듈의 메타데이터를 노출합니다. Module Manager 앱이 이를 표시합니다.
const result = await client.moduleRegistry.list.query();
// 반환: { modules: [{ key, name, type, hasCalculator, sourceTables, targetTables,
// outputKeys, parameterSchema, defaultParameters, status, … }],
// summary: { total, withCalculator, withoutCalculator, … } }hasCalculator는 필드명만 유지된 호환 필드이며, 의미는 "해당 소스 모듈에 코드 모듈이 등록돼 있다"입니다.