Skip to content

급여 코드 모듈 레퍼런스 ​

급여 시스템은 시트 기반 정산으로 수당과 공제를 계산합니다. 금액을 만드는 계산 자체는 @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)에서도 실행돼 미리보기와 서버 커밋 결과가 구조적으로 일치합니다.

정산 흐름 ​

  1. 시트 열의 sourceModule별로 입력 로드 — loadInputsByModule(ctx, sourceModule, rows, period)가 소스 테이블(근로계약, overtime_records 등)을 시트 기간으로 조회해 행별 입력 맵을 만듭니다.
  2. 행 × 모듈 열마다 compute(inputs, parameters) 실행 — 파라미터는 열 메타데이터 + 조직 파라미터 저장소를 mergeWithDefaults로 합친 값입니다.
  3. 열의 value key로 출력 중 하나를 골라 셀에 기록합니다.
  4. ✓ 커밋 시 commitSheet가 셀 값을 AllowanceRecord / DeductionRecord로 기록합니다(시트 계보 sourceSheetId / sourceSheetRowId / sourceSheetColumnKey).

인터페이스 (packages/code-modules/src/types.ts) ​

CodeModule ​

필드타입설명
sourceModuleSourceModule레지스트리 키 (enum 값과 동일)
parameterSchemaParameterField[]설정 가능한 파라미터 정의 (설정 폼 렌더링·검증)
defaultParametersParameters파라미터 기본값
keyDescriptionsKeyDescription[]compute()가 돌려주는 출력 키 설명
compute(inputs, parameters)function순수 계산 — Record<string, number> 반환

KeyDescription ​

시트 컬럼의 value key 설정 시 힌트로 사용됩니다.

필드타입설명
keystring값 키 식별자
labelstring표시 라벨
descriptionstring사람이 읽을 수 있는 설명
unitstring단위 ("원", "시간", "건", "%")

ParameterField ​

필드타입설명
keystring파라미터 식별자
labelstring표시 라벨
descriptionstring설명
typeenumnumber, string, boolean
defaultValuemixed기본값
min / max / stepnumber숫자형 제약 (선택)
suffixstring입력란 뒤 단위 라벨 (예: "%", "시간", "원")

코드 모듈 목록 (packages/code-modules/src/registry.ts) ​

수당 ​

모듈소스 모듈입력 로드 소스설명
employmentContractModuleemployment_contractemployment_contracts근로계약 기반 기본급·호봉·근속
overtimeRecordModuleovertime_recordovertime_records + overtime_types승인된 연장근무 가산 (카테고리 배율 + 관리형 유형 배율)
fixedIncentiveModulefixed_incentivefixed_incentives기간 내 승인된 고정 인센티브
educationSubsidyModuleeducation_subsidyeducation_subsidies기간 내 승인된 교육보조금
resignationRecordModuleresignation_recordresignation_records 등퇴직정산
yearEndSettlementModuleyear_end_settlementyear_end_settlements연말정산 환급/추징

공제 ​

모듈소스 모듈설명
insuranceModulepayroll_rate_config4대보험 (국민연금, 건강보험, 고용보험, 산재보험)
taxBracketModuletax_bracket_config근로소득세 + 지방소득세

수동 모듈 ​

sourceModule = "manual" 열은 계산을 우회합니다. unitPrice x multiplier가 직접 금액으로 사용됩니다.

초과근무 버킷 매핑 (조용한 과소지급 가드) ​

loadInputsByModule의 overtime_record 분기가 OvertimeCategory를 모듈 입력 버킷으로 바꿉니다. 정본은 .claude/rules/payroll/korean-payroll-compliance.md입니다.

카테고리채우는 버킷유효 배율 (기본값)
WEEKDAYweekday1.5x
NIGHTweekday + night1.5x + 0.5x = 2.0x
HOLIDAYholiday1.5x
HOLIDAY_NIGHTholiday + night1.5x + 0.5x = 2.0x
SATURDAY (deprecated)weekend0.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가 필요해 아직 단위 테스트가 없습니다.

새 코드 모듈 추가 방법 ​

  1. packages/code-modules/src/modules/my-module.ts에 CodeModule 구현 (parameterSchema, defaultParameters, keyDescriptions, compute)
  2. packages/code-modules/src/registry.ts와 index.ts에 등록/export
  3. packages/api/src/routers/sheet-rows/compute.ts loadInputsByModule에 입력 로드 분기 추가 (브라우저 미리보기가 필요하면 hr-system commit-compute.ts에도)
  4. 새 소스 모듈에 바인딩된 시트 컬럼 추가 (항목 코드, value key, 파라미터는 컬럼 메타데이터 + 조직 파라미터 저장소)
  5. keyDescriptions의 키가 시트 컬럼 설정 UI와 Module Manager에 노출됩니다

모듈 레지스트리 라우터 ​

module-registry 라우터는 listCodeModules()를 읽어 모든 소스 모듈의 메타데이터를 노출합니다. Module Manager 앱이 이를 표시합니다.

typescript
const result = await client.moduleRegistry.list.query();
// 반환: { modules: [{ key, name, type, hasCalculator, sourceTables, targetTables,
//                     outputKeys, parameterSchema, defaultParameters, status, … }],
//         summary: { total, withCalculator, withoutCalculator, … } }

hasCalculator는 필드명만 유지된 호환 필드이며, 의미는 "해당 소스 모듈에 코드 모듈이 등록돼 있다"입니다.