HBHR270_전자서명 발송·eCount 연동 시트 (2섹션)
(Hereby) HR 급여 관리 > 시트 워크스페이스 > 전자서명 발송·eCount 연동 시트
| 앱 | HR 급여 관리 (hr-system, 포트 4000) |
| 대상 사용자 | 조건1 [HR_ADMIN] / 조건2 [SUPER_ADMIN] |
| 프로토타입 | TBU |
| 관련 정책 | [[POL_급여정본경계]] |
| Status | review |
| Owner | 카나 |
| 부모 | [[HBHR100_시트 워크스페이스 (공통 Shell)]] |
개요
- 이 문서는 문서·서명 및 eCount 연동의 두 시트 유형을 한 문서에 2개 섹션으로 정의한다.
- 전자서명 발송 시트(🔒잠금)는 명세서 문서의 발송·서명·수신 상태를 기록하는 교부 입증층으로, 근로기준법 §48(임금대장·명세서 교부) 입증 근거이며 e_sign_records를 근거로 한다.
- eCount 코드 시트는 수당/공제 항목을 이카운트 회계 코드에 매핑하는 export 마스터로, allowance_item_codes / deduction_item_codes를 근거로 한다.
- 전자서명 발송은 급여 확정 후 명세서 생성에서 시작하는 정본 후행 교부층이며, 시트=작업공간 vs 정본=commit 경계를 따른다 ([[POL_급여정본경계]]).
문서 히스토리
| 날짜 | 작성자 | 팀 | 변경 내용 |
|---|---|---|---|
| 2026-07-06 | 카나 | PM | 최초 작성 |
| 2026-07-10 | 카나 | 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-09-05 | 카나 | PM | 발송 리스트 새로고침 시 Sign 상태 동기화·최신순 정렬 반영(#614 머지 9/4) — 세부 UI 실사 대기 |
| 2026-10-01 | 카나 | PM | 이카운트 내보내기 스탬프(payroll_records.exportedAt·exportedBy, 마이그레이션 1923) + 응답 exportedAt + 정산 7단계 ⑦ 판정 반영(ee1d73d4, #885) — 커밋 근거, 라이브 실사 이월(TBU) |
| 2026-10-02 | 카나 | PM | eCount 수당·공제 코드 시트 읽기 전용 열 「연결된 열」 신설(섹션 B 6, 423969a6, #987, MED-850)·그 태그로 코드 시트 레이아웃 저장이 전부 거절되던 회귀 수정(690fe6c1, #1007, MED-860)·템플릿 재적용 시 코드 시트 카탈로그 재시드(d5e564c9, #988, MED-851) 반영 — 커밋 근거, 라이브 실사 이월(TBU) |
| 2026-10-07 | 카나 | PM | PR #1062 반영(MED-934, 433b49f7·9dae561d): 「이카운트 Export (XLSX)」가 바로 파일을 내리지 않고 이카운트 내보내기 모달(섹션 C 신설)을 엶 — 집계 열 그대로 표시·체크 선택·기본급 계열 기본 제외·선택 기억(열 key, payroll_records.exportOptions / settings.ecount.exportExcludedColumnKeys)·payroll.ecountExportPreview 신설. 모달 HTML 원문 카피, 라이브 실사 이월(TBU) |
Data I/O
Server → Client
| 변수 | DB 엔티티.컬럼 | 값 없을 때 | 비고 |
|---|---|---|---|
${sign.rows} | e_sign_records[] | 0건 시 빈 그리드 | 시트 🔒잠금(sheet_views.lockedAt/lockedBy) |
${sign.status} | 서명 상태 (발송/서명완료/미서명 등) | 미발송 시 공란 | enum = TBU |
${allowCode.rows} | allowance_item_codes[] (code(4)·name·displayOrder·isActive) | 0건 시 빈 그리드 | 수당 코드 |
${dedCode.rows} | deduction_item_codes[] (code(4)·name·displayOrder·isActive) | 0건 시 빈 그리드 | 공제 코드 |
${row.mappedColumns} | 리졸버 loadECountMappedColumns — 같은 조직·같은 년월 급여대장(이름에 「급여대장」 포함 또는 직원 소스 시트)의 집계 열 중 allowanceItemCodeId/deductionItemCodeId가 이 코드인 열 (셀 저장 없음) | 연결 열 없으면 빈칸 | 「연결된 열」(#987) · 다른 달 급여대장 연결은 세지 않음 |
Client → Server
| 액션 | 전달 값 | tRPC procedure | 권한 토큰 |
|---|---|---|---|
| 이카운트 export | year, month | payroll.exportEcount(year, month) (TC 라이브 확인) → { filename(~"ecount"), data, employeeCount≥N, excludedRecords:{allowance, deduction}, exportedAt } | payroll:confirm (추정) |
payroll.exportEcount(year,month)는 성공 시filename·data·employeeCount(대상 직원 수)를 반환한다. 급여대장 집계 컬럼에 앵커되지 않은(self-target) record는 export에서 제외되고excludedRecords.{allowance, deduction}카운트로 보고된다 — 커밋 target 페어가 실 급여대장 슬러그가 아니면 export 대상에서 빠진다. (TC 확정: 03:3.5 exports to eCount / 10:10.6 excludedRecords)
내보내기 스탬프 (#885, ee1d73d4): xlsx 생성 시 대상 급여 기록(그 기간의 확정·지급 상태 기록)에
payroll_records.exportedAt(파일 생성 시각)·exportedBy(실행자)를 찍고 응답에exportedAt을 함께 돌려준다. 재내보내기 시 덮어쓴다(기존 행은 null). 브라우저의 실제 파일 저장 여부는 알 수 없어 「파일을 만든 시각」 기준. 정산 7단계 ⑦ 「명세서 발송 · 이카운트 내보내기」가 이 스탬프로 판정 — 발송·내보내기 둘 다 0 = 할 일, 어느 한쪽이라도 확정 건수 미만 = 일부, 둘 다 채움 = 완료. detail 문구 "이카운트 내보내기 {N}건 (마지막 YYYY-MM-DD HH:mm)" / "이카운트 내보내기 아직 없음". 트리거 UI 안내 문구(서버 howTo): 「데이터 ▾ › 이카운트 Export (XLSX)」. 이카운트 Export 메뉴 옆 마지막 시각 표시는 미구현(정산 진행 드로어 ⑦ detail로 대체).
연동 방향
| 흐름 | 계산·경로 | 산출 | 비고 |
|---|---|---|---|
| 전자서명 | 급여 확정([[HBHR201_전체 확정 (commit)]]) → 명세서 생성(payroll_records.sentBy/sentAt) → 전자서명 발송 → 서명 상태 기록 | 교부 입증(§48) | 🔒잠금 |
| eCount | 확정 급여 항목(allowance_records/deduction_records) → 항목 코드 매핑 → 이카운트 export | 코드/부서코드/사원명/금액 | export 실 데이터 [[HBHR203_재계산 diff 뷰]] |
| 코드 활성 | isActive=false(미사용) 코드 | export 대상 제외(추정) | boolean |
화면 플로우 (Mermaid)
전자서명 발송 시트는 🔒잠금 교부 입증층으로 편집 불가. eCount export 실 데이터는 [[HBHR203_재계산 diff 뷰]] 공통 컬럼군에서 정의.
섹션 A. 전자서명 발송 시트 (🔒잠금, e_sign_records)
컬럼 순서·명칭은 기본 템플릿 기준(# / 사번 / 성명 / 팀 / 문서 / 발송일시 / 서명일시 / 상태 / 수신 이메일 / 수신 휴대전화, 행 이동 탭: 기본/인사). 내부 fieldKey: employeeNumber / employeeName / team / templateName / sentAt / signedAt / status / recipientEmail / recipientPhone.
| # | 컬럼 | 타입 | 설명 (용도·형식) | 연관 (ERD/calculator/타 앱) | 비고 |
|---|---|---|---|---|---|
| 1 | # | Index | • 행 순번 (read-only) | sheet_rows.sortOrder | read-only |
| 2 | 사번 | Text (system) | • 직원 사번 (read-only 시스템 컬럼) | employees.employeeNumber / fieldKey=employeeNumber | 시스템 컬럼 |
| 3 | 성명 | Text (system) | • 직원 성명 (read-only 시스템 컬럼) | employees.name / fieldKey=employeeName | 시스템 컬럼 |
| 4 | 팀 | Text (system) | • 소속 팀 (read-only 시스템 컬럼) | teams / fieldKey=team | 시스템 컬럼 |
| 5 | 문서 | Text/Link | • 발송 문서명(예: 급여명세서 YYYY-MM) · 시트 🔒잠금 • 클릭 시: TBU (발송 문서 열람 링크, 목적지 미확인) | e_sign_records.documentName(추정) / fieldKey=templateName · payroll_records | — |
| 6 | 발송일시 | Output/DateTime | • 문서 발송 일시. §48 교부 시점 입증 (read-only 잠금) | e_sign_records.sentAt(추정) / fieldKey=sentAt · payroll_records.sentAt | read-only(잠금) |
| 7 | 서명일시 | Output/DateTime | • 수신자 서명 완료 일시. 미서명 시 공란 (read-only 잠금) | e_sign_records.signedAt(추정) / fieldKey=signedAt | read-only(잠금) |
| 8 | 상태 | Badge | • 발송/서명완료/미서명/실패 등 | e_sign_records.status(추정) / fieldKey=status | TBU: enum 값 |
| 9 | 수신 이메일 | Text | • 수신자 이메일 주소 | e_sign_records.recipientEmail(추정) / fieldKey=recipientEmail | — |
| 10 | 수신 휴대전화 | Text | • 수신자 휴대전화 번호 | e_sign_records.recipientPhone(추정) / fieldKey=recipientPhone | — |
시트는 🔒잠금 — 발송·서명 이력은 교부 입증층으로 편집 불가(read-only). 행 이동 탭: 기본/인사.
섹션 B. eCount 수당/공제 코드 시트 (allowance/deduction_item_codes)
컬럼 순서·명칭은 기본 템플릿 기준(# / 코드 / 항목명 / 표시 순서 / 사용 / 연결된 열). 되쓰기 eCountField 4종: code / name / displayOrder / isActive + 읽기 전용 표식 mappedColumns(되쓰기 제외, #987·#1007).
| # | 컬럼 | 타입 | 설명 (용도·형식) | 연관 (ERD/calculator/타 앱) | 비고 |
|---|---|---|---|---|---|
| 1 | # | Index | • 행 순번 (read-only) | sheet_rows.sortOrder | read-only |
| 2 | 코드 | Text | • 이카운트 매핑 코드(4자리), 수당/공제 구분 • 입력 시: code 저장(4자리) | allowance_item_codes.code(4) / deduction_item_codes.code(4) / fieldKey=code | varchar(4) |
| 3 | 항목명 | Text | • 수당/공제 항목 명칭 • 입력 시: name 저장 | allowance_item_codes.name / deduction_item_codes.name / fieldKey=name | — |
| 4 | 표시 순서 | Number | • 정렬 순서 • 입력 시: displayOrder 세팅 | allowance_item_codes.displayOrder / deduction_item_codes.displayOrder / fieldKey=displayOrder | 정렬 순서 |
| 5 | 사용 | Badge/Checkbox | • 코드 활성 여부(boolean) • 입력 시: isActive 토글. 미사용(false) 시 export 대상 제외(추정) | allowance_item_codes.isActive / deduction_item_codes.isActive / fieldKey=isActive | boolean |
| 6 | 연결된 열 | Computed (read-only) | • 이 코드를 고른 같은 달 급여대장 집계 열을 "{시트 이름} · {열 이름}"으로 표시, 여러 개는 쉼표(예: "급여대장 · 기본급, 급여대장 (사본) · 식대") • 편집 불가 — 머리글 안내(원문): "같은 달 급여대장의 집계 열 가운데 이 코드를 고른 열이에요. 바꾸려면 그 열의 열 설정 › eCount 항목코드에서 골라요." - CASE01 [연결 없음]: 빈칸 - CASE02 [이름 빈 시트·열]: "(이름 없는 시트)" / "(이름 없는 열)" | eCountField=mappedColumns (kind computed, 폭 260) · 급여대장 열 설정 eCount 항목코드 ([[HBHR107_컬럼 헤더 컨트롤]]) · [[HBHR200_급여대장 시트]] | 신설 (코드 반영: 423969a6, #987, MED-850) · 기존 코드 시트는 마이그레이션 1944로 열 추가 · TBU: 라이브 실사 이월 |
공통 우측 컬럼군(재계산 diff + eCount 매핑: 코드/부서코드/사원명/금액)은 [[HBHR203_재계산 diff 뷰]] 참조 — export 실 데이터는 [[HBHR203_재계산 diff 뷰]]에서 정의.
섹션 C. 이카운트 내보내기 모달 (신설 — PR #1062, MED-934)
급여대장 데이터 ▾ › "이카운트 Export (XLSX)"가 바로 파일을 내리지 않고 이 모달을 먼저 연다. 급여대장의 집계 열을 시트 순서·열 이름 그대로 한 줄씩 보여 주고(시트에서 보는 것과 모달이 같아야 함 — 시트에 없는 것이 보이거나 시트에 있는 것이 빠지면 안 됨), 체크한 열만 파일에 넣는다. 금액 집계는 미리보기와 파일이 같은 ecount-export.service를 쓴다.
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 노출 조건 | - | 데이터 ▾ → "이카운트 Export (XLSX)" 클릭 시 (급여대장 + 전 행 확정 상태: isPayrollLedger && allLedgerRowsConfirmed) | [[HBHR106_데이터 메뉴]] · [[HBHR200_급여대장 시트]] | DS 일반 모달 760px |
| 01 | 초기 상태 | - | 로딩 "이 급여대장의 집계 열과 금액을 읽고 있어요…" → payroll.ecountExportPreview가 초기 체크 상태를 정함. 우선순위: ①이 달의 지난 내보내기 선택(payroll_records.exportOptions.excludedColumnKeys 스탬프) → ②조직 설정 저장 선택(settings.ecount.exportExcludedColumnKeys) → ③항목 이름으로 추정한 기본급 계열 꺼짐 | payroll.ecountExportPreview · PayrollRecord.exportOptions(jsonb, 마이그레이션 1954) | 기억·스탬프는 열 key 기준(열 이름은 바뀔 수 있음) · 옛 excludeConfigIds(코드 id)는 그 코드가 붙은 열로 풀어 호환 |
| 10 | 모달 헤더 | Text | • 제목 "이카운트 내보내기" + 부제 "{year}년 {month}월 · {시트명} · 확정 {N}명" | activeSheet | X 버튼·Esc 닫힘(내보내는 중 비활성) |
| 11 | 안내 노티스 | Info | • "이 급여대장의 집계 열이 시트 순서대로 보여요. 체크한 열만 파일에 들어가요. 이카운트가 직원별 산정 방식으로 직접 계산하는 기본급 계열은 보내면 이중 반영되니 체크를 끄세요." | ||
| 20 | 집계 열 목록 | Table | • 열 = 체크박스 / "열"(열 이름 + 「기본급 계열」 라벨) / "이카운트 코드"(코드 + 코드명) / "인원"(우측 정렬) / "금액"(우측 정렬, 없으면 "—") • 행·체크박스 클릭 → 포함 토글(코드 없는 열은 토글 불가) • 상단 "모두 선택" / "모두 해제" - CASE01 [기본급 계열]: 라벨 "기본급 계열"(툴팁 "이카운트가 직원별 산정 방식으로 계산하는 항목") — 기본 체크 꺼짐(기본급·본봉·호봉·근속·월급여 등, 이중 반영 방지) - CASE02 [코드 없는 집계 열]: "코드 없음 · 내보내지 않음"(툴팁 "열 설정에서 eCount 항목코드를 고르면 내보낼 수 있어요") — 보이되 선택 불가 | 열 설정 eCount 항목코드([[HBHR107_컬럼 헤더 컨트롤]]) | 열 조회는 지정한 시트 한 장으로 좁힘 — slug는 달마다 같은 양식이 재사용돼 slug로 걸면 다른 달의 열이 겹쳐 나옴(실측, 9dae561d) |
| 20-E | Empty | Text | • "이 급여대장에 집계 열이 없어요. 수당·공제를 모으는 집계 열을 만들고 열 설정에서 「eCount 항목코드」를 골라 주세요." | ||
| 21 | 미연결 레코드 경고 | Info | • excludedRecords 합 > 0일 때: "코드가 있는 집계 열에 연결되지 않은 레코드 {N}건은 어떤 열에도 들어가지 않아요 (수당 {A}건 · 공제 {D}건)." | excludedRecords | |
| 30 | 이 선택을 기본값으로 저장 | Checkbox | • 켜져 있으면 내보낼 때 제외 목록을 조직 설정(settings.ecount.exportExcludedColumnKeys)에 남겨 다음 달 기본값으로 씀 | payroll.exportEcount(rememberSelection) | |
| 31 | 기본값으로 | Button | • 클릭 → 선택을 서버가 정한 기본값으로 리셋 | ||
| 32 | 선택 요약 | Text | • "내보낼 열 {N}개 · 제외 {M}개 (· 코드 없음 {K}개) · 합계 {합}원" | ||
| 40 | 취소 | Button | • 클릭 → 모달 닫힘 (내보내는 중 비활성) | ||
| 41 | 내보내기 | Button | • 클릭 → XLSX 생성·다운로드. 진행 중 라벨 "파일 만드는 중…" • 비활성 조건: 내보내는 중 / 로딩 중 / 미리보기 없음 / 내보낼 열 0개 | payroll.exportEcount · exportedAt 스탬프(상단 「내보내기 스탬프」 절) |
연동·플로우
- 전자서명 흐름: 급여 확정([[HBHR201_전체 확정 (commit)]]) → 명세서 생성 → 전자서명 발송(e_sign_records) → 서명/수신 상태 기록 → §48 교부 입증층으로 보존(🔒잠금).
- eCount 흐름: 확정 allowance_records/deduction_records → 항목 코드(allowance/deduction_item_codes) 매핑 → 이카운트 export(
payroll.exportEcount(year,month), 반환 filename·data·employeeCount, [[HBHR203_재계산 diff 뷰]] 공통 컬럼군). 급여대장 aggregate 컬럼 미앵커(self-target) record는excludedRecords.{allowance,deduction}카운트로 제외 보고. (TC 확정: 03:3.5 / 10:10.6) - 코드 마스터는 isActive=false(미사용) 시 export 대상 제외(추정).
- 레이아웃 저장(#1007): 「연결된 열」 태그를 공용 스키마가 몰라 코드 시트의 열 삭제·폭·이름 변경·AI 열 구성 제안이 모두 저장 거절(새로고침 시 되살아남)되던 회귀 수정. 되쓰기 열·「연결된 열」 삭제는 계속 거절, 손으로 추가한 일반 열 삭제는 허용.
- 템플릿 재적용(#988): 같은 달에 이미 코드 시트가 있을 때 「eCount 수당 코드」·「eCount 공제 코드」 템플릿을 다시 적용하면 시드를 다시 돌려 카탈로그와 맞춤(값 갱신·새 코드 행 추가·사라진 코드 행 정리, 같은 시트 id 유지). 보호·작업 완료(lockedAt) 시트는 건드리지 않음.
권한·상태 분기 요약
| 시나리오 | 트리거 | 결과 | 비고 |
|---|---|---|---|
CASE01 [전자서명 시트] | 발송·서명 이력 셀 편집 시도 | 차단 (🔒잠금, read-only 교부 입증층) | 편집 불가 |
CASE02 [미사용 코드] | isActive=false 코드 | 이카운트 export 대상 제외 (추정) | boolean |
CASE03 [명세서 발송] | 급여 확정 후 명세서 생성·발송 | e_sign_records에 sentAt 기록 (§48 교부 시점) | payroll_records.sentAt |
Open Question
- e_sign_records 엔티티/컬럼명 확정 — 02·03 ERD 미노출, 문서·서명 도메인 ERD 필요. TBU.
- 전자서명 상태 enum 전체 값(발송/서명완료/미서명/만료/실패 등). TBU.
- 행 이동 탭 "기본/인사"의 의미(문서 분류 vs 대상 구분). TBU.
- eCount export procedure =
payroll.exportEcount(year,month)확정 (반환 filename·data·employeeCount·excludedRecords).트리거 UI(수동/자동) = TBU→ 해소(10/7, #1062): 트리거 = 데이터 ▾ › "이카운트 Export (XLSX)" → 이카운트 내보내기 모달(섹션 C). 부서코드 원천 = TBU 유지. (TC 확정: 03:3.5 / 10:10.6) - 수당/공제 코드가 단일 시트 2탭인지 별도 시트인지(census는 "eCount 수당/공제 코드" 단일 언급). TBU. — 코드상 별도 시트 2장(slug
ecount_allowance_codes·ecount_deduction_codes)으로 확인(#987), 라이브 확인 시 해소.