다크모드
HR 급여 페이지 (FE 메인테이너)
2026-07-18 as-built. payroll-owned input snapshot → 급여 확정 v2 서버 seam까지 연결했다. 근태는 선택 provider다.
라우트와 컴포넌트
/human-capital/compensation/payroll/general: 월별 run 목록과 상태 배지./human-capital/compensation/payroll/general/console/wage-salary: 직원별 지급·공제·실지급 표.- 양쪽
MainOrg.vue가useAccountContext()의 Company/Office를configurePayrollRunScope()에 전달한다.
콘솔 오버레이:
DialogConfirmPayrollArt: 입력 출처·revision과 합계를 확인하고, 필요하면 수동 입력을 준비한 뒤 비동기 confirm.DialogRevertPayrollArt: 5자 이상 사유를 받고 비동기 revert.DialogPaidPayrollArt: 비동기 mark-paid.SheetTransferPayrollArt: snapshot 기반 이체 목록과 CSV.SheetWithholdingPayrollArt: snapshot 기반 원천세 요약.
데이터 흐름
text
useAccountContext Company/Office
├─ payrollRepo.loadInputReadiness ─▶ payrollInputReadiness
└─ payrollRepo.loadAll ────────────▶ usePayrollRun state
│
payrollMock liveLines ──draft──────────────┤
server/local snapshot ──confirmed/paid────┘draft:employees × payslip()live 계산.confirmed/paid: 확정 당시 snapshot만 사용한다.linesOf,totalsOf,transferRows,transferCsv,withholdingSummary가 같은 snapshot을 소비한다.PAYROLL_CALCULATION_VERSION을 confirm payload와 snapshot에 함께 보낸다.
저장소 seam
payrollRepo.js:
- local adapter:
leyve.payroll.runslocalStorage, 비동기 인터페이스. - Supabase adapter: payroll input readiness/capture +
payroll_runsread +confirm_payroll_run_v2,revert_payroll_run,mark_payroll_run_paidRPC. - 서버 adapter는 table upsert를 하지 않는다. authenticated direct write가 막혀 있기 때문이다.
normalizePayrollRun()이 snake_case run과 nested snapshot을 기존 UI shape로 변환한다.- 오류는
payrollErrorMessage()에서 사용자 문구로 변환한다.
usePayrollRun.js:
- scope/hydration:
configurePayrollRunScope,refreshPayrollInputReadiness. - input:
captureManualPayrollInput,payrollInputReadiness. - state:
statusOf,runOf,linesOf,totalsOf. - transition: async
confirmRun,revertRun,markPaid. - derived:
transferRows,transferCsv,withholdingSummary. - test only:
resetRuns,setPayrollInputReadinessForTest.
UI 게이트
| 상태 | 입력 | 허용 UI |
|---|---|---|
| draft | missing | 급여 입력 필요, 수동 입력 준비 가능 |
| draft | ready | 급여 확정 가능, 출처·선택 provider revision 표시 |
| draft | invalidated | 입력 갱신 필요, 새 수동/연동 입력 준비 |
| confirmed | snapshot 고정 | 확정 취소·이체 의뢰·원천세 |
| paid | snapshot 고정 | 이체 내역·원천세; 취소 불가 |
확정 버튼을 누를 때 payroll 입력 준비도를 다시 조회하고, confirm-v2 RPC도 scope·hash·무효화 여부를 DB에서 재검사한다. UI 배지는 안내이고 DB가 최종 권위다. usePayrollRun.js는 time repo를 import하지 않는다.
확장 시 주의
- 서버 path의 employeeId는 UUID여야 한다. 현재 데모
contractMock문자열 ID는 local Prototype 전용이다. - 상용 계산 엔진이 서버로 이동하면
liveLines()를 서버 draft preview로 교체하되 line shape와 snapshot 소비자는 유지한다. - 계좌 마스킹, export 권한, 재인증, 조회 감사 UI는 별도 보안 slice로 추가한다.
- 급여 회계 분개는 paid 이벤트 소비자로 붙이고 급여 화면에서 직접 전표를 만들지 않는다.
테스트
usePayrollRun.test.js: async 전이, missing/invalidated reject, manual capture, snapshot clone, paid 불가역, CSV/원천세.payrollRepo.test.js: local roundtrip, nested snapshot normalize, RPC payload.payrollInputSnapshotMigration.spec.js: schema/RLS/entitlement/time 무참조/immutable history 계약.payroll_local_input_snapshots_smoke.sql,time_payroll_input_provider_smoke.sql: 실제 Postgres rollback smoke.