HBHR201_전체 확정 (commit)
(Hereby) HR 급여 관리 > 시트 워크스페이스 > 급여대장 시트 > 전체 확정 (commit)
| 앱 | HR 급여 관리 (hr-system, 포트 4000) |
| 대상 사용자 | 조건1 [HR_ADMIN] / 조건2 [SUPER_ADMIN] |
| 프로토타입 | TBU |
| 관련 정책 | [[POL_급여정본경계]] |
| Status | review |
| Owner | 카나 |
| 부모 | [[HBHR200_급여대장 시트]] |
개요
- 급여대장 시트의 💰 전체 확정 액션은 시트(작업공간)의 계산 결과를
allowance_records/deduction_records정본 record로 생성하는 정본 생성 경계 — destructive 액션이다. 커밋은 AR/DR record만 생성하며 급여대장 정본(payroll_records)은 만들지 않는다 — PayrollRecord는 별도 절차payroll.generateForPeriod(year, month)가 AR/DR을 집계해 생성한다 ([[POL_급여정본경계]] — 이중 경로, TC 확정: 03:3.3 / 07 / 08). - 시트 우상단 "전체 확정" 버튼의 title 속성 원문은 **"이 급여대장 전체 행을 PayrollRecord 로 확정합니다"**이다. ⚠ 이 카피는 실제 동작(커밋=AR/DR 생성, PayrollRecord는 generateForPeriod 별도)과 어긋난다 — UI 카피 정정 후보.
- 4대보험 공제는 자동 생성되지 않는다 — insurance calculator 파이프라인은 제거되었고,
generateForPeriod는 순수 집계다. 공제 record는 오직 시트 커밋으로만 생성된다 (TC 확정: 08:8.2totalDeductions >= 0, auto-insurance 없음). - 확정은 **DS 모달(2단계: confirm → result)**을 거치며, 확인 단계 안내 문구에는 "지급액·공제액 합계가 0인 행과 이미 확정된 행은 자동으로 건너뜁니다." 가 포함된다. 즉 합계 0 행과 기확정(already committed) 행은 자동 스킵된다. (기존 네이티브 confirm()/alert() 쌍을 하나의 DS 모달로 합침 — 코드 반영: 9912ef4. 실행 중에는 X·취소·Esc 잠금, 실패는 result 단계 오류 문구로 표시)
- 확정 실행 후 확정된 행은 회색으로 처리 표시되어 미확정 행과 시각적으로 구분된다.
- commit(레코드 생성)과 confirm(정본 잠금)은 분리된 별개 procedure다 —
sheetView.commitToRecords(시트 커밋 = record 생성) ↔payroll.confirm(year, month)(기간 정본 잠금)은 별도 호출이다.sheet_views.lastCommittedAt/lockedAt및sheet_rows.lockedAt가 확정/잠금 시각 근거로 존재한다. (TC 확정: 03:3.5 confirms the payroll period) - 시트 단위 "작업 완료"(workDoneAt)와 "시트 잠금(보호)"(lockedAt)은 분리된 별개 상태다 — 작업 완료 = workDoneAt + lockedAt(완료는 잠금 포함), 보호 = lockedAt만. 작업 완료는 시트 [[HBHR100_시트 워크스페이스 (공통 Shell)]] 반영(커밋) 게이트의 disabled 사유("작업 완료된 시트는 반영할 수 없어요") 중 하나이며, 시트 보호와는 별개다. (코드 반영: dbca988)
문서 히스토리
| 날짜 | 작성자 | 팀 | 변경 내용 |
|---|---|---|---|
| 2026-07-06 | 카나 | PM | 최초 작성 |
| 2026-07-12 | 카나 | PM | 실행 검증 반영 (콸 승인) |
| 2026-07-13 | 카나 | PM | 버튼 행동 명세 보강 |
| 2026-07-21 | 카나 | PM | GC700 깊이 재작성 |
| 2026-07-21 | 카나 | PM | 가독성 패스 + 액션 표기 (GUIDE §7·§8) |
| 2026-07-21 | 카나 | PM | 셀 스타일 확정판 적용 (콸 승인) |
| 2026-07-21 | 카나 | PM | TC 크로스체크 확정분 반영 (🟡) |
| 2026-07-21 | 카나 | PM | 🔴 정정: 커밋=AR/DR만(payroll_records 미생성)·4대보험 자동공제 폐지·record lineage 모델 (TC 정본, 콸 승인) |
| 2026-07-28 | 카나 | PM | 코드 변경 반영(9912ef4) |
Data I/O
Client → Server
| 액션 | 전달 값 | tRPC procedure | 권한 토큰 |
|---|---|---|---|
| 시트 커밋 (record 생성) | sheetViewId | sheetView.commitToRecords (TC 라이브 확인) | payroll:confirm (추정) |
| 기간 검증 | year, month | payroll.validate(year, month) (TC 라이브 확인) | payroll:confirm (추정) |
| 기간 확정 (정본 잠금) | year, month | payroll.confirm(year, month) (TC 라이브 확인) | payroll:confirm (추정) |
커밋(record 생성)과 확정(기간 정본 잠금)은 분리 procedure다:
sheetView.commitToRecords(시트 → allowance/deduction records) ↔payroll.confirm(year,month)(기간 정본 잠금).payroll.validate(year,month)는 확정 전 기간 검증 procedure로 라이브 존재(단 시트 commit preflight와 동일물인지 = OQ). (TC 확정: 03:3.5 validates/confirms the payroll period)
Server side 효과 (확정 파이프라인)
| 대상 | 효과 | 비고 |
|---|---|---|
allowance_records / deduction_records | 스킵 대상 제외 행 → record 생성, status=approved로 즉시 확정(별도 승인 단계 없음) | isAutoGenerated=true, sourceSheetId/sourceSheetRowId/sourceSheetColumnKey 채움 · (TC 확정: 03:3.2.5 / 07:7.8) |
payroll_records | 커밋은 건드리지 않음 — PayrollRecord(grossPay/totalDeductions/netPay)는 별도 payroll.generateForPeriod(year,month)가 AR/DR 집계로 생성 (초기 status=draft) | 🔴 정정 (구 서술 "커밋 시 갱신" 폐기) · (TC 확정: 03:3.3 / payroll.test.ts) |
sheet_views.lastCommittedAt / lastCommittedBy | commit 타임스탬프·주체 기록 | |
sheet_rows.lockedAt / lockedBy · sheet_views.lockedAt / lockedBy | 확정 행/시트 잠금 (재편집 방지) | |
| record lineage | 생성 record가 sourceSheetId/sourceSheetRowId/sourceSheetColumnKey + isAutoGenerated=true 스탬프 보유, 급여대장 앵커는 targetSheetSlug+targetColumnKey 페어 (item-code FK 없음 — migration 1816) | audit trail · 🔴 정정 (구 sheet_rows.sourceRecordId/sheet_cells.refRecordId 모델 폐기) |
| 재커밋(멱등) | 동일 시트 재확정 시 sourceSheetId 단위로 기존 record soft-delete 후 재삽입 | 멱등 보장 · (TC 확정: 커밋 파이프라인 sheet-fixtures) |
화면 플로우 (💰 → confirm → records → Ledger)
확인 = destructive 경계. preflight/AI는 경고·차단까지만, record 생성은 사람의 "확인"으로만 실행 ([[POL_급여정본경계]]).
전체 확정 모달 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 노출 조건 | - | 조건1 [HR_ADMIN]/조건2 [SUPER_ADMIN] 이 급여대장 시트 우상단 "💰 전체 확정" 버튼 클릭 시 | [[HBHR200_급여대장 시트]] | |
| 01 | 초기 상태 | - | confirm 모달 오픈 전 = 시트 작업공간(미확정). 버튼 hover 시 title 툴팁 노출 | ||
| 10 | 전체 확정 버튼 | Button | • 시트 우상단 "💰 전체 확정" 버튼. title 속성 원문 "이 급여대장 전체 행을 PayrollRecord 로 확정합니다" • 클릭 시: DS 모달(confirm 단계) 오픈 — 문구 "모든 행을 확정하시겠습니까?" + "지급액·공제액 합계가 0인 행과 이미 확정된 행은 자동으로 건너뜁니다." → "확인" 시 확정 실행("확정 중..."), result 단계에 요약(확정 N건 / 이미 확정 / 이미 지급 / 건너뜀) 표시, 확정 행 회색 | [[HBHR200_급여대장 시트]] · 11 전체 확정 취소 | DS 모달 (코드 반영: 9912ef4) |
| 11 | 전체 확정 취소 버튼 | Button | • "전체 확정 취소" 버튼. 확정된 행을 취소하는 companion 액션으로 10과 같은 DS 모달을 mode로 나눠 씀 • 클릭 시: DS 모달(confirm 단계) 오픈 — 문구 "확정된 모든 행을 취소하시겠습니까?" → "확인" 시 취소 실행("취소 중..."), result 단계에 요약 표시 | [[HBHR200_급여대장 시트]] · 10 전체 확정 | 신규 (코드 반영: 9912ef4) · 10과 모달 공유(mode 분기) |
| 20 | 안내 문구 | Alert | • 확정 confirm 단계 문구에 "지급액·공제액 합계가 0인 행과 이미 확정된 행은 자동으로 건너뜁니다." 포함 (고정 문구). 지급(PAID) 처리 행은 취소 시 "이미 지급(PAID) 처리된 행은 자동으로 건너뜁니다." | 원문 카피 | |
| 30 | 스킵 규칙 | - | • 확정 대상에서 자동 제외되는 행을 판정한다 (멱등 보장) - CASE01 [합계 0 행]: 지급액·공제액 합계 0 → 자동 제외 - CASE02 [기확정 행]: 이미 확정된 행(lockedAt 존재) → 자동 제외 | sheet_rows.lockedAt | 멱등 보장 |
| 40 | 확인 | Button | • 확정을 실행하는 destructive 버튼 • 클릭 시: 즉시 실행 → 스킵 제외 행 → allowance/deduction records 생성(status=approved) → lastCommittedAt/lockedAt 기록. payroll_records는 생성하지 않음(별도 generateForPeriod) | 정본 레코드 생성 | payroll:confirm (추정) |
| 50 | 취소 | Button | • 확정을 중단하는 비파괴 버튼 • 클릭 시: 확정 중단, 작업공간 유지·변경 없음 | ||
| 60 | 확정 행 표시 | Output | • 확정 실행 후 확정된 행은 회색으로 처리 표시되어 미확정 행과 구분된다 | sheet_rows.lockedAt | 회색 행 |
| 70 | 값 없음 처리 | - | • 확정 대상 행 전부가 합계 0/기확정이면 신규 생성 record 0건 (멱등) | 무변화 | |
| 80 | 에러·실패 | - | • 확정 파이프라인 실패 시 "승인 행 모두 지급 처리"(HBHR106)의 무음 실패 선례 존재 | [[HBHR106_데이터 메뉴]] | TBU: 확정 파이프라인 실패 피드백 UI (라이브 미검증) |
확정 preflight (P1)
[[POL_급여정본경계]]에 따라 **확정 직전 검증(commit preflight)**을 P1로 정의한다. 검증/AI는 경고·차단까지만 수행하고 record 생성은 사람의 확인으로만 실행한다. 구현 여부 = TBU. 단 기간 단위 검증 procedure payroll.validate(year,month)는 라이브 존재 확정(시트 commit preflight와 동일물인지는 OQ). (TC 확정: 03:3.5 validates the payroll period)
| 검증 항목 | 조건 | 동작 | 안전 경계 |
|---|---|---|---|
| 음수 금액 | 지급/공제/실수령 < 0 | 경고 배지 | 차단·경고만 |
| 이상치 | ±3σ 초과 항목 | 경고 + diff 링크([[HBHR203_재계산 diff 뷰]]) | 읽기 전용 |
| 4대보험 config | payroll_rate_config "미사용"(요율 코드 내장) | 경고 (요율 config화 필요). ⚠ 경고일 뿐 4대보험 공제 자동 생성은 없음 — insurance calculator 파이프라인 제거됨, 공제는 시트 커밋 산출뿐 (TC 확정: 08:8.2) | 차단·경고만 |
권한·상태 분기 요약
| 시나리오 | 트리거 | 결과 | 비고 |
|---|---|---|---|
CASE01 [정상 확정] | 💰 → 확인 | 스킵 제외 행 records 생성 → Ledger, lastCommittedAt 기록 | destructive |
CASE02 [합계 0 행] | 💰 → 확인 | 해당 행 자동 스킵 (record 미생성) | 안내 문구 명시 |
CASE03 [기확정 행] | 💰 → 확인 | 해당 행 자동 스킵 (재확정 없음) | lockedAt 존재 |
CASE04 [취소] | 💰 → 취소 | 작업공간 유지, 변경 없음 | 비파괴 |
Open Question
commit vs confirm 단일/분리 액션→ 분리 확정:sheetView.commitToRecords↔payroll.confirm(year,month)별도 procedure (TC 확정: 03:3.5)- 확정 preflight 구현 여부 = TBU (P1 정의) — 단 기간 검증
payroll.validate(year,month)는 라이브 존재 확정. 이것이 시트 commit preflight와 동일물인지 = OQ 유지 (TC 확정: 03:3.5 validates) - 확정 후 재편집/재확정(unlock) 동선 = TBU
- 확정 파이프라인 실패 시 피드백 UI = TBU
status enum(confirmed/published) ↔ commit 모델 매핑→ 확정: PayrollStatus = draft→approved→confirmed→paid (published 미사용), 커밋 산출 AR/DR record는 즉시approved(TC 확정: payroll.test.ts / 03:3.2.5)- "전체 확정" 버튼 title 카피("PayrollRecord로 확정합니다")와 실동작(AR/DR 생성) 불일치 — UI 카피 정정 백로그 후보