HBAD201_직원 추가·수정 모달
(Hereby) 관리자 패널 > App Shell > 인사 관리 > 직원 관리 > 직원 추가·수정 모달
| 메타 | 앱: 관리자 패널 (App Shell)대상 사용자: 조건1 [직원 관리 권한 보유 역할]프로토타입: TBU관련 정책: [[POL_급여정본경계]] · [[POL_권한(RBAC)]]Status: reviewOwner: 카나 |
개요
직원 추가·수정은 단일 모달 + 4단계 스텝(① 기본정보 / ② 인사정보 / ③ 자격증/면허 등록 / ④ 근로계약)이다. 1회 저장으로 4개 생성물이 동시 생성된다: ① Employee ② 소속(팀·역할 n:m) ③ 근로계약·급여 seed ④ 자격증 요건. 하단 버튼은 "취소" / "미리보기" / "등록"(저장 중 "등록 중..." disabled). 기본 상태는 비활성이다 (activation gate — 안내 "비활성 상태로 등록돼요. 사용하기 위해서는 재직으로 변경해 주세요."). 전화번호 입력 시 SMS 임시비밀번호 안내가 발송된다. 자격증/면허 요구를 선택하면 자격증 화면에 "파일 미제출" 상태로 등록된다. 급여 seed는 계약·호봉·수당·근무시간을 급여 원천으로 넘긴다 (POL_급여정본경계 — 정본 변환은 HR 시트 commit에서).
문서 히스토리
- 2026-07-06 최초 작성 - 카나/콸
- 2026-07-10 라이브 기능 검토 반영 - 카나/콸
- 2026-07-13 버튼 행동 명세 보강 - 카나/콸
- 2026-07-17 코드 변경 반영(de57b65·0125f00) - 카나/콸
- 2026-07-21 GC700 깊이 재작성 (라이브 재검증 7/20 — 4단계 전 필드·안내 원문·이탈 가드·등록 중 상태) - 카나/콸
- 2026-07-21 가독성 패스 (GUIDE §7) - 카나/PM
- 2026-07-21 셀 스타일 확정판 적용 (콸 승인) - 카나/PM
- 2026-07-24 코드 변경 반영(c1b2158) - 카나/콸
- 2026-09-16 병동 이중 배정 수정(팀 이동 시 한 줄로 합침·teamIds auto→move) 반영(#711 리뷰 후속, 1fce4e2) - 카나/콸
- 2026-09-16 급여 제외 플래그(비급여 계정 대장 제외) 반영(#722, b8a8c77) - 카나/콸
- 2026-09-18 직무 필드 마스터 연동 전환(직무 마스터 목록 선택 + 기본 근무 자동 채움 「직무 기본 → 팀 대표」 순서, 허용 근무형태 우선 노출, 직군 기본값) 반영(7f63a4b, #791) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
- 2026-09-21 소속 피커 활성 전용화+검색 줄(공용 패널 동일 규칙, 65daef2 #809)·직무 기본 근무 안내 문구 플레이스홀더 치환 수정(d216f26 #802)·근무 배정 출처(shiftAssignedVia) 기록 반영(c4eb0f9 #804) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
- 2026-09-23 직무 기본 근무와의 차이 표시(「≠ 직무 기본」·「기본」) + 기본 근무 재적용 규칙(33948ca, #851, MED-693)·직원 등록/수정 패널 「근로형태」(workPatternName) 항목 신설(73c0cb4, #823) 반영 — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
- 2026-09-25 낮 스윕 라이브 실사 — 직원 정보 수정 = 5탭 모달(기본정보/인사정보/자격증·면허/근로계약/계정·보안) 실측. 인사정보 탭 구성: 입사일 · 출근 기록 방식(조직 기본값/앱/지문 단말기(Secom)/관리자 수동 입력) · 소속(팀·역할) · 병동 배정 · 직무 · 근로형태(ㄴ50-4 원문 채록·TBU 해소) · 상태 · 근무 그룹(+「근무 유형 전체 보기」 링크) · 급여 지급 대상 토글 · 시스템 관리자 토글. 소속 피커 검색 줄(ㄴ30-1) 실측. info 안내 원문 "근무 형태는 근태 현황의 근무 설정에서 추가/수정 가능해요." - 카나/PM
- 2026-10-01 「고정 수당」 탭 신설(반복 고정 수당 정의 — 목록·상태 배지·종료일 저장·금액 정정·추가)(dea7be96, #969)·계정·보안 「직접 설정」 임시 비밀번호 형식 허용(01d3cc5b, #948)·퇴직 취소(재직 복귀) 흐름(기본정보 안내·상태 드롭다운 항목·사유 필수·정산 완료 거절)(25e9ddfa, #959)·신규 입사자 시트 자동 추가 미리보기/완료 안내(6ea0ac58, #908) 반영 — 커밋 근거 + 라이브 실측 2026-10-01(#959 퇴직 취소 안내·상태 드롭다운·사유 입력, #969 고정 수당 탭 구성·원문, #880 사번 도움말) / #948·#908 라이브 실사 이월(TBU) - 카나/PM
- 2026-10-02 ④ 근로계약 「수습 종료 후」 블록 신설 — 수습 종료 다음 날 시행 계약 변경 예약(50~ㄴ52, 미리보기 한 줄)(fa1b1d8a, #965, MED-823)·#995 비밀번호 최소 길이 병원 설정 연동 — repo 직접 수정 역수용 — 커밋 근거 + 라이브 실사 확인(10/2: 섹션명·안내·필드 3개 원문) / 유효성 안내·미리보기 줄·예약 생성은 라이브 실사 이월(TBU) - 카나/PM
- 2026-10-07 PR #1059(3e90dfbd, MED-925·924·923) 반영: 주 소속 지정 출처 MANUAL 전환+당일 근태 재판정(ㄴ50-2)·부 그룹 줄 ×·effectiveShift 표시(ㄴ50-5) · PR #1050(515ac04b, MED-926) 반영: 역할 변경 = 폼 변경, 저장 시 team.updateMember(ㄴ50-6) · PR #1067(0a071d0b, MED-937) 반영: 「등록된 직무가 없어요」 템플릿 미닫힘으로 근로형태·근무 배정 영역 소실되던 결함 수정(ㄴ50-7) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
- 2026-10-08 (10/7 머지분) PR #1084(bee9679·3d441c2, MED-951 계열) 반영: 수습 종료 후 계약 예약 = 같은 직원·같은 시행일 계약 변경 예약 중복 차단(Data I/O·50·CASE07) + 예약 목록 열람 = 급여 조회(전체) 권한 · PR #1088(876ec23, MED-953) 반영: 소속 팀 트리 순서 = 팀 관리 저장 순서(
compareTeamOrder, ㄴ30-1) · OQ 「예약된 변경」 채번 제안(HBAD275) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM - 2026-10-13 (10/11 머지분) PR #1154(MED-969) 반영: 직원 수정 패널 근무 배정 아래 「허용 근무 유형」 체크 목록(50 보강) — 커밋 근거, 실사 TBU - 카나/PM
- 2026-10-14 (10/13 머지분, #1227 d35e4e3) 계정·보안 탭에 「패스키·기기 키로만 로그인」 해제 추가(20 신설) — 직원이 켠 패스키 전용 로그인을 관리자가 끄는 복구 동선(기기 분실 대비). 관리자는 해제만 가능, 켜는 것은 키 보유 직원 본인만(employees.passkeyOnlyLogin · security.setPasskeyOnly) — 커밋 근거, 10/14 실사는 패널 DOM 중첩으로 탭 내부 미도달(탭 존재는 실측, TBU) - 카나/PM
Data I/O
Client → Server
액션
| 메타 | 직원 추가 (1회, 4 생성물) |
| 메타 | ㄴ ① employees |
| 메타 | ㄴ ② team_members |
| 메타 | ㄴ ③ employment_contracts |
| 메타 | ㄴ ④ employee_certifications |
| 메타 | 미리보기 |
Server side 효과
| 효과 | 엔티티.컬럼 | 값 없을 때 | 비고 |
|---|---|---|---|
| SMS 임시비밀번호 발송 | login_otp_codes 계열 (추정) + mustChangePassword=true | 전화번호 미입력 시 미발송 | 안내 "전화번호를 입력해야, 임시 비밀번호를 SMS로 발송을 할 수 있어요." |
| 기본 상태 비활성 | employees.status = 비활성 | - | activation gate |
| 출근 기록 방식 | employees.attendanceMethod | 조직 기본값 사용 | 앱/Secom/수동 4옵션 |
| 신규 입사자 시트 자동 추가 | sdk.employee.previewNewEmployeeSheets(hireDate)(저장 전 대상 시트) · employee.create 응답 sheetAutoAdd {enabled, added:[{id,name}]} | 조직 설정 꺼짐 시 enabled:false(안내 미노출) · 자동 추가 실패 시 null(등록은 유지) | 조직 토글 [[HBAD270_설정 (조직 설정·내 정보)]] ㄴ33 · 코드 반영: 6ea0ac58, #908 |
| 퇴직 취소 | sdk.employee.cancelTermination({id, reason}) — 퇴사 기록 메모에 사유 남기고 무효화 · employees.status=재직 · 활성 소속 팀 단톡방 복귀 (한 트랜잭션) | 정산 끝난 퇴사 기록이면 아무것도 바꾸지 않고 거절 | 권한 employee:update · 팀장 지정·세션은 복구 안 함 · 코드 반영: 25e9ddfa, #959 |
| 수습 종료 후 계약 예약 | employee.create 입력 probation { endDate, baseSalary?, hourlyRate? } → 같은 트랜잭션에서 scheduled_actions(kind contract_change, 시행일 = 종료일 + 1일, 소유자 = 등록자, 요구 권한 employee:update, 출처 probation/직원 id, 메모 "수습 종료({endDate}) 후 조건") | 블록 비우면 예약 안 함 · 종료일 < 입사일이면 서버 거부 "수습 종료일은 입사일 이후여야 해요." | 시행일 잡이 소유자 권한으로 계약 기간 분할(#960) · 코드 반영: fa1b1d8a, #965 · (10/8, #1084) 수습 예약도 공용 createScheduledAction 경유 → 같은 직원·같은 시행일 계약 변경 예약이 이미 있으면 거부(CONFLICT, 동시 생성도 하나만) — 원문 "같은 시행일({date})의 계약 변경 예약이 이미 있어요. 「예약된 변경」에서 기존 예약을 확인하고, 바꾸려면 기존 예약을 취소한 뒤 다시 만들어 주세요." · 예약 목록·요약·상세 열람 = 급여 조회(조직 전체) 권한 필요 (bee9679·3d441c2) |
| 반복 고정 수당 정의 | recurring_allowance_definitions(코드·이름·월 금액·시작일·종료일·메모, append-only chainId·version) · sdk.recurringAllowance.list/create/correct | 0건 시 "정의된 고정 수당이 없어요." | 권한 employee:read/employee:update · 급여대장 열 원천 recurring_allowance · 코드 반영: dea7be96, #969 |
① 기본정보 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 노출 조건 | - | • 목록에서 이 모달을 여는 두 진입 경로 - CASE01 [직원 추가]: "직원 추가" 클릭 → "직원 추가" 모달 - CASE02 [편집]: 목록 행 "편집" 클릭 → "직원 정보 수정" 모달 | [[HBAD200_직원 관리]] | |
| 01 | 초기 상태 | - | • STEP1 [기본정보] 섹션 노출 | employees | |
| 05 | 퇴직자 안내 | Notice | • 퇴직 처리된 직원(status=TERMINATED)의 수정 모달 기본정보 탭 상단 경고 안내(원문): "퇴직 처리된 직원이에요. 실수라면 「퇴직 취소」로 재직으로 되돌릴 수 있어요." • "퇴직 취소하러 가기" 클릭 → 인사정보 탭 전환 + 상태(40)에 "퇴직 취소(재직 복귀)" 선택된 상태 - CASE01 [퇴직자 아님]: 미노출 | employees.status · ② 40 상태 ㄴ40-1 | 신설 (코드 반영: 25e9ddfa, #959) · 라이브 실측 2026-10-01(안내·버튼·탭 전환 원문 일치, 스샷 live-1001-hbad201-cancel-termination.png) |
| 10 | 성 * / 이름 * / 사번 * | Input | • 성·이름·사번 입력. 사번에 "자동 생성" 체크박스 • 입력 시: 각 값 반영 - CASE01 [자동 생성 체크]: 사번 자동 채움 • 사번 도움말(원문): "사번은 입력한 대로 저장돼요. 로그인·검색·중복 확인은 대소문자를 가리지 않아요." | employees.employeeNumber | 사번 자동 생성 · 대소문자 규칙(8ced12cd, #880) · 라이브 실측 2026-10-01(도움말 원문) |
| 11 | 이메일 / 생년월일 | Input | • 이메일 / 생년월일 입력 ("음력" 체크박스) | employees | |
| 12 | 주민등록번호 | Input | • 마스킹 입력(password) - CASE01 [생년월일 선입력 게이트]: 생년월일 입력 후 활성 | employees | 마스킹 · 선입력 게이트 |
| 13 | 전화번호 | Input | • 국가코드 선택(+82 / +1 / +81 / +86 / +44) + 번호 입력. 안내 "전화번호를 입력해야, 임시 비밀번호를 SMS로 발송을 할 수 있어요." - CASE01 [값 없음]: 미입력 시 SMS 미발송 | SMS 임시비밀번호 | |
| 14 | 주소 | Search | • 주소 검색(도로명·지번) + 상세주소 입력 • 입력 시: 선택 주소 반영 | employees |
② 인사정보 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 섹션 | Section | • 헤더 "인사정보" — "필수 인사정보" + "기타 인사정보" 그룹 • 연차 자격 판정이 그룹 근무형태까지 확장(mergeGroupShiftsToWorkPattern) — 그룹 배정 시 그룹 근무형태가 자격 산정에 병합 (코드 반영: c1b2158) | employees · team_members · 연차 자격 판정 | 자격 판정 그룹 확장(c1b2158) |
| 10 | 입사일 * | Date | • "입사일 *" 날짜 입력 ("오늘" 단축 버튼). 필수 • 입력 시: 선택 날짜 반영 | employees.joinedAt | 필수 |
| 20 | 출근 기록 방식 | Dropdown | • 근태 원천 방식 선택 (안내 "조직 기본값 또는 개별 설정"). 옵션 4종: "조직 기본값 사용" / "앱 (Web/Mobile)" / "지문 단말기 (Secom)" / "관리자 수동 입력" • 선택 시: 해당 방식 반영 - CASE01 [미선택]: 조직 기본값 사용 | employees.attendanceMethod | 근태 원천 |
| 30 | 소속 (팀 · 역할) | Button | • "소속 (팀 · 역할)" + "소속 추가" 버튼. 팀·역할 멀티 배정. 모달(large)에서는 "+ 소속 추가" 라벨 버튼 유지 (7/16 변경 유지) • 클릭 시: 소속(팀·역할) 배정 행 추가 • 병동 이중 배정 방지(코드 반영: 1fce4e2): 수정 모달에서 팀을 병동이 연결된 다른 팀으로 옮길 때, 서버 병동 배정과 저장 전 줄이 같은 병동이면 한 줄로 합쳐 저장 버튼이 꺼지던 문제 수정(claimSameWardRows/mergeServerWardRows). 팀 이동 시 이전 병동 배정을 새 병동으로 옮겨(teamIds 처리 auto→move) 같은 병동이 두 줄로 남지 않게 함. 병동 배정 줄(병동·교대형태·수간호사 한 줄)이 같은 병동으로 두 줄이면 저장 버튼 비활성 | team_members · 간호 프로필 · [[HBAD210_팀 관리]] 구성원별 팀 관리 팝업 | n:m · 이중 배정 수정(#711 리뷰 후속, 1fce4e2) · 회귀 테스트 5건(ward-assignment-rows.test.ts) |
| ㄴ30-1 | 소속 피커 활성 전용 + 검색 | Picker | • 공용 직원 수정 패널(EditEmployeePanel)·추가 패널이 관리자 직원 관리와 같은 피커 규칙을 사용 - 팀 트리 피커: 비활성 팀을 하위까지 숨김 / 역할 피커: 비활성 역할 제외 - 예외: 지금 배정된 값은 비활성이어도 유지(선택 표시 보존) - 메뉴 상단 고정 검색 줄( .ds-menu__search), 팀 검색 중에는 계층·접기 무시하고 평면 표시 | [[HBAD200_직원 관리]] · teams.isActive · roles.isActive · [[HBAD210_팀 관리]] ㄴ12-1 | 신설 (코드 반영: 65daef2, #809) · (10/8, #1088, MED-953) 팀 트리 형제 순서 = 팀 관리에서 끌어 저장한 순서(core compareTeamOrder — sortOrder 먼저, 없으면 이름순) — 직원 추가·수정 패널 공통, TBU(실사 대기) · 라이브 실사(2026-09-25): 인사정보 탭 「소속 추가」 피커 오픈 시 상단 고정 검색 줄(.ds-menu__search, placeholder 팀 검색) + 팀 트리 노출 실측 |
| 40 | 상태 | Radio | • "재직" / "비활성" 선택. 안내 "비활성 상태로 등록돼요. 사용하기 위해서는 재직으로 변경해 주세요." • 선택 시: 해당 상태 반영 - CASE01 [비활성(기본)]: activation gate | employees.status | activation gate |
| ㄴ40-1 | 퇴직 취소(재직 복귀) | Dropdown | • 퇴직자에게만 상태 드롭다운에 "퇴직 취소(재직 복귀)" 항목 노출(실측 옵션: 재직 / 비활성 / 휴직 / 퇴직 / 퇴직 취소(재직 복귀)). "재직"을 직접 골라도 같은 흐름 • 선택 시: 안내 박스 + "취소 사유" 입력(필수, 최대 500자, placeholder "예: 퇴직 처리를 잘못 눌렀어요") 노출 - 안내(원문): "퇴직 취소하면 퇴사 기록이 무효 처리되고(정산 이력은 보존) 상태가 재직으로 돌아오며, 팀 단톡방에도 다시 들어가요. 팀장 지정은 자동으로 되살아나지 않으니 팀 관리에서 다시 지정하고, 직원은 앱에 다시 로그인해야 해요." | sdk.employee.cancelTermination() · resignation · 팀 단톡방 · [[HBAD200_직원 관리]] | 신설 (코드 반영: 25e9ddfa, #959, MED-834) · 라이브 실측 2026-10-01(옵션·안내·사유 placeholder 원문 일치, 아래 "휴직/퇴직 이력" 목록 노출) · 저장 동작(ㄴ40-2)은 미실행 |
| ㄴ40-2 | 퇴직 취소 저장 | Action | • 저장 클릭 → 즉시 실행(cancelTermination), 성공: 모달 닫힘 + 토스트 "{name} 님의 퇴직을 취소했어요. 상태가 재직으로 돌아왔어요." - CASE01 [사유 없음]: 경고 "퇴직 취소 사유를 입력해 주세요." (저장 안 됨) - CASE02 [정산 끝난 퇴사 기록]: 거절 "퇴직 정산이 끝난 기록이라 취소할 수 없어요. 정산을 먼저 되돌려 주세요." - CASE03 [기타 실패]: "퇴직 취소 실패: {오류}" | employee:update | 코드 반영: 25e9ddfa, #959 |
| 45 | 급여 제외 | Toggle | • 직원을 급여 대장(대상)에서 빼는 급여 제외 플래그(직원 관리 employees-content 화면에도 표시). 켜면 이 직원의 계정이 비급여 계정으로 처리돼 급여 대장 집계에서 제외됨 • 선택 시: 플래그 반영 | employees(급여 제외 플래그) · 급여 대장(HBHR) | 신규 (코드 반영: #722, b8a8c77) |
| 47 | 직무 | Dropdown | • 직무를 직무 마스터 목록에서 선택하는 드롭다운(9/18 — 자유 텍스트에서 마스터 연동 선택으로 전환). placeholder "직무를 선택하세요" • 선택 시: 그 직무의 기본 근무(그룹 › 형태)가 근무 배정(50)에 자동 선택되고 안내 노출 — 원문 "직무 「{name}」의 기본 근무가 선택됐어요. 다르면 바꿔 주세요." (기본값일 뿐 제한 아님 — 팀 대표 근무보다 먼저 적용, 등록할 때 변경 가능). 직무에 허용 근무형태가 있으면 근무형태 목록에서 그 형태들이 먼저 노출. 직군을 따로 고르지 않으면 직무의 직군이 기본값 - -E [직무 마스터 0건]: "등록된 직무가 없어요. 설정 › 근무 설정 › 직무에서 먼저 등록해 주세요." | employees.jobDutyId (FK job_duties) · [[HBAD260_근무 설정 (근무 그룹·유형)]] 직무 사양표 · 50 근무 배정 | 신설 (코드 반영: 7f63a4b, #791) · 자동 근무 채움 순서 = 직무 기본 근무 → 팀 대표 근무 · 라이브 실사(2026-09-25): 인사정보 탭 「직무」 드롭다운 + placeholder "직무를 선택하세요" 실측(직무 0건 조직이라 선택 동작·안내 문구는 미실증) |
| ㄴ47-1 | 직무 기본 근무 안내 문구 | Fix | • 직무를 고르면 기본 근무를 채운 뒤 안내를 띄우는데, 패널 _t 래퍼가 치환 값을 스토어로 넘기지 않아 플레이스홀더가 그대로 보이던 문제 수정- 오류 표기(수정 전): "직무 「{name}」의 기본 근무가 선택됐어요." - 수정 후: 직무명이 치환되어 표시 | job_duties.defaultShiftId · i18n t(key, vars) | 수정 (코드 반영: d216f26, #802) · TBU: 라이브 실사 이월 |
| 50 | 근무 배정 (근무 그룹 → 근무형태) | Dropdown | • 근무 배정을 '근무 그룹 → 근무형태' 2단계로 개편 (코드 반영: c1b2158) - STEP1 [근무 그룹]: 근무 그룹 선택 — employees.shiftGroupId(FK shift_groups, nullable). 근무형태 없이 그룹만 배정 가능- STEP2 [근무형태]: 근무형태 필드는 그룹 선택 시에만 노출(폭 50%). 근무 유형 목록 연동 선택 (예: "미지정" / "일반근무" / "3교대 주간" / "3교대 오후" / "3교대 야간" / "스케줄 근무" 등 — junk 데이터 관찰) • 선택 시: 그룹·근무형태 반영. 안내 문구 "추가/수정 가능"으로 갱신. 직무(47) 선택 시 그 직무의 기본 근무가 자동 선택됨(직무 기본 → 팀 대표 순서, 변경 가능) | employees.shiftGroupId (FK shift_groups, nullable) · employment_contracts · 47 직무 · employees.allowedShiftIds | 2단계 개편 (코드 반영: c1b2158) · junk 데이터 존재 · 직무 기본 근무 자동 채움(7f63a4b, #791) · (10/11 머지, #1154, MED-969) 근무 배정 아래 「허용 근무 유형」 체크 목록(「그룹 · 근무」 라벨) — 이 직원이 배정 그룹 밖에서도 앱 「근무 시간 설정」에서 스스로 고를 수 있는 근무(employees.allowedShiftIds, 마이그레이션 1971). 팀 단위 목록([[HBAD210_팀 관리]] ㄴ50-1)과 합집합, 급여 근로형태 불변 — 커밋 근거, 실사 TBU |
| ㄴ50-2 | 근무 배정 출처 기록 | Field | • 근무 배정이 어떤 경로로 정해졌는지를 함께 저장(shiftAssignedVia)- 값: 직접 선택 / 직무 기본 / 팀 대표 / 일괄 배정 / 엑셀 / 시트 / 직원 앱 자기 선택 • 주 소속 지정 시 출처 = 직접 선택(MANUAL)로 전환(10/7, #1059, MED-925) — 종전엔 새 주 소속 줄의 출처(직무 기본·팀 대표)가 그대로 복사돼 다음 기본 근무 재적용이 방금 고른 근무를 되돌렸음. 주 소속 변경 뒤 당일 근태를 다시 판정(attendance-shift-recompute.service — 마감·퇴근·수동 수정·휴가/휴일/결근·off_day는 건너뜀) • 저장된 출처는 직원 정보 수정·직원 목록·근태 현황·직원 앱 근태 홈에 표시 | employees.shiftAssignedVia · team_members.shiftAssignedVia (마이그레이션 1917) | 신설 (코드 반영: c4eb0f9, #804) · TBU: 라이브 실사 이월 |
| ㄴ50-3 | 직무 기본 근무와의 차이 표시 | Label | • 직원 수정 패널이 근무 배정과 그 직원 직무의 기본 근무가 같은지를 표시 — 「≠ 직무 기본」(다름) / 「기본」(기본에서 온 값). 직원 목록([[HBAD200_직원 관리]] ㄴ46-3)과 같은 표기 • 직무·근로형태만 바꿔 저장하면 기본 근무 재적용 규칙(decideDefaultShiftReapply)으로 근무가 직무 기본 근무에 맞춰짐 - 맞추는 대상: 비었음 · 그룹만 배정 · 비활성 값 · 기본에서 온 값 - CASE01 [직접 고른 값]: 바꾸지 않고 유지 - 배경: 직무는 있는데 근무형태가 비었거나 직무와 무관한 옛 값이 남아 「미지정」으로 보이던 결함(MED-693) | job_duties.defaultShiftId · [[HBAD200_직원 관리]] · [[HBAD260_근무 설정 (근무 그룹·유형)]] 40-5 기본 근무 재적용 | 신설 (코드 반영: 33948ca, #851, MED-693) · TBU: 라이브 실사 이월 |
| ㄴ50-4 | 근로형태 (workPatternName) | Field | • 직원 등록/수정 패널에 「근로형태」 항목 추가 — 설정 › 「근로형태」 탭(근로형태 마스터)에 등록된 값을 직원에게 지정 • 대량 업로드 템플릿에도 같은 「근로형태」 열이 추가됨([[HBAD200_직원 관리]] ㄴ33) - 근로형태 마스터 화면 = 신규 탭 · 전용 사양서 미작성(신규 화면 후보) - 필드 실측(2026-09-25 실사): 인사정보 탭, 「직무」 바로 아래 배치. 라벨 "근로형태" + placeholder "근로형태를 선택하세요 (선택)" — 선택 항목(필수 아님). 도움말 원문 "근로형태를 지정하면 월 근로시간·연장·야간·포괄시간·통상시급이 근로형태 기준으로 채워져요. 직접 고친 값은 수동으로 남아요." | employees.workPatternId · [[HBAD260_근무 설정 (근무 그룹·유형)]] 탭 목록 ㄴ02-1 | 신설 (코드 반영: 73c0cb4, #823) · 라이브 실사 확인(2026-09-25 — 필드 위치·선택 항목·도움말 원문 채록, TBU 해소) |
| ㄴ50-5 | 부 그룹 제거 (줄 ×) · effectiveShift | Field | • (10/7, #1059, MED-924·923) 수정 화면에서 부 근무 그룹 줄에 ×(제거) — 주 소속 줄은 안내로 거절 • 직원 상세에 effectiveShift(판정에 쓰는 근무·출처)를 돌려주고 개인 설정에 한 줄로 표시 — 직원 앱 근무 화면에는 판정 순서(스케줄 → 직원 근무 → 근로형태/직무 기본값)를 표시 | employee.clearSecondaryShiftGroups · [[HBAD200_직원 관리]] ㄴ26 | 신설 (3e90dfbd, #1059) · 표시 원문 TBU(실사 대기) |
| ㄴ50-6 | 역할 변경 = 폼 변경 (저장 시 반영) | Rule | • (10/7, #1050, MED-926) 소속 역할 선택을 다른 입력과 같은 폼 변경으로만 잡음 — 저장 때 persistBasicEdits의 역할 루프가 team.updateMember로 보냄(종전: 고르면 바로 서버 저장 + 기준선 재설정으로 저장 버튼이 안 켜지고, onSaved 미호출로 닫은 뒤 직원 목록·팀 명단에 옛 역할이 남던 버그) | team.updateMember · 30 소속 | 신설 (515ac04b, #1050) |
| ㄴ50-7 | 「등록된 직무가 없어요」 템플릿 렌더 수정 | Rule | • (10/7, #1067, MED-937) 직무가 1개 이상 등록된 조직에서 직원 추가 › 인사정보의 「근로형태」·「근무 배정」 영역이 통째로 렌더되지 않아 등록 버튼이 영구 비활성이던 결함 수정 — 「등록된 직무가 없어요」 x-if의 닫는 태그가 근무 배정 블록 아래에 있던 것을 경고 한 줄 뒤에서 닫음 | 50 근무 배정 · ㄴ50-4 근로형태 | 신설 (0a071d0b, #1067) |
| ㄴ51 | 근무 유형 전체 보기 (참고 팝업) | Button | • 위저드에서 그룹별 등록 근무 유형을 열람하는 "근무 유형 전체 보기" 참고 팝업 • 클릭 시: 그룹별 등록 유형 목록 팝업 오픈(참고용) | shift_groups · 근무 유형 | 신규 (코드 반영: c1b2158) |
③ 자격증/면허 등록 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 섹션 | Section | • 헤더 "자격증/면허 등록" — "자격 유형 선택" | employee_certifications | 신설 섹션 · 생성물 ④ |
| 10 | 안내 문구 | Info | • 자격증 등록 안내 (원문 카피): "직원이 제출해야 할 자격증/면허를 선택해 주세요." / "선택한 항목은 자격증/면허 화면에 '파일 미제출' 상태로 등록돼요." / "입사 후 '문서 결재' > '자격증/면허' 탭에서 자격 정보를 등록할 수 있어요." | 원문 카피 | |
| 20 | 자격 유형 선택 | Checkbox | • 자격 15종 + 커스텀 체크 선택: "테스트" / "ㅁㄴㅇㄹㅁㄴㅇㄹㅁㄴ"(커스텀/junk) / "간호사" / "간호조무사" / "물리치료사" / "작업치료사" / "언어치료사" / "방사선사" / "임상병리사" / "약사" / "영양사" / "사회복지사" / "의사" / "치과의사" / "응급구조사" / "요양보호사" - CASE01 [선택]: 해당 자격 "파일 미제출" 등록 | employee_certifications | 15종+커스텀 |
| 30 | 자격증 요청 안함 | Option | • "자격증 제출을 요청하지 않아요." 옵션 - CASE01 [선택]: 자격증 요건 미생성 | employee_certifications |
④ 근로계약 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 섹션 | Section | • 헤더 "근로계약" — "계약 정보" / "급여 기준" / "근무 시간" | employment_contracts (급여 원천) | POL_급여정본경계 |
| 10 | 계약유형 | Dropdown | • 계약 유형 선택: "정규직" / "임시직" / "계약직" / "인턴" / "파트타임" (5종) • 선택 시: 해당 유형 반영 | employment_contracts | |
| 20 | 급여형태 | Dropdown | • 급여 형태 선택: "월급" / "시급" / "일급" / "연봉" (4종) • 선택 시: 해당 형태 반영 | employment_contracts | |
| 30 | 급여 기준 | Input | • 급여 원천 6필드 입력: "기본급 (원)" / "호봉 (원)" / "근속수당 (원)" / "식대 (원)" / "교통비 (원)" / "직책수당 (원)" | employment_contracts (급여 원천) | |
| 40 | 근무 시간 | Input | • 근무 시간 2필드 입력: "주당 기본근무시간" / "주당 최대근무시간" | standardWeeklyHours / maxWeeklyHours | 52h 한도 |
| 50 | 수습 종료 후 | Section | • (직원 추가) 근로계약 하단 선택 블록 — 수습 종료 다음 날부터 적용될 새 계약을 예약 • 안내(원문): "종료일 다음 날부터 적용되는 새 계약을 예약해요. 수습 기간의 시트는 위 계약 값으로, 그 뒤는 여기 값으로 계산돼요. 비우면 예약하지 않아요." | scheduled_actions(contract_change) · [[HBHR210_계약급여내역 시트]] 예약 목록 | 신설 (코드 반영: fa1b1d8a, #965, MED-823) · 라이브 실사 확인(10/2 — 섹션명·안내 원문) · 대량 업로드는 범위 밖(계약 열 없음) |
| ㄴ51 | 수습 종료일 / 수습 후 기본급 / 수습 후 통상시급 | Input | • "수습 종료일"(날짜, 입사일 이전 선택 불가) / "수습 후 기본급" / "수습 후 통상시급"(숫자) — 금액 2칸은 종료일 입력 전 비활성 • 입력 시: 종료일이 있으면 「예약한다」로 간주, 금액 중 하나 이상 필수 - CASE01 [종료일 < 입사일 또는 금액 둘 다 없음]: 블록 아래 오류(원문) "수습 종료일은 입사일 이후여야 하고, 수습 후 기본급이나 통상시급 중 하나는 입력해야 해요." + 근로계약 카테고리 빨간 점 + "등록" 비활성 - CASE02 [종료일 비움]: 예약 안 함(통과) | createEmployee.probation · 90 등록 | 라이브 실사 확인(10/2 — 필드 3개 라벨) · TBU: 오류 노출·등록 비활성 라이브 미실증 |
| ㄴ52 | 미리보기 수습 줄 | Text | • "미리보기" 검토 화면 근로계약 영역에 라벨 "수습 종료 후" + 값(원문 형식) "{date} 까지 수습 · 다음 날부터 {values}" — {values} 예 "기본급 3,000,000원 · 수습 후 통상시급 14,000원" - CASE01 [블록 비움]: 줄 미노출 | 90 미리보기 | TBU: 라이브 실사 이월 |
⑤ 고정 수당 사양표 (직원 정보 수정 — 반복 고정 수당 정의)
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 고정 수당 탭 | Tab | • 직원 수정 패널 카테고리 "고정 수당"(근로계약과 계정·보안 사이). 매달 반복되는 고정 수당을 「이 직원에게 이 기간 동안」 정의로 관리 • 안내(원문): "매달 반복되는 고정 수당(자격 수당·직책 수당 등)을 기간으로 정의해요. 시트는 그 달에 유효한 정의를 읽으므로 종료일이 지나면 다음 달부터 자동으로 빠지고, 지난달 시트 값은 그대로예요." | recurring_allowance_definitions · [[HBHR200_급여대장 시트]] 열 원천 recurring_allowance | 신설 (코드 반영: dea7be96, #969, MED-824) · 수정 모달 탭 5→6 · 라이브 실측 2026-10-01(탭 순서 기본정보/인사정보/자격증/면허/근로계약/고정 수당/계정·보안, 안내·섹션·필드·placeholder 원문 일치, 월 금액 기본 0, 스샷 live-1001-hbad201-fixed-allowance.png) · 목록 행·종료일 저장·금액 정정은 정의 0건이라 미실증 |
| 10 | 정의된 고정 수당 목록 | List | • 제목 "정의된 고정 수당". 행 = 상태 배지 · 수당 이름 · 코드 · 월 금액(원) / 시작일 ~ 종료일(없으면 "무기한") · 메모 - 상태 배지: "적용 중"(초록) / "예정"(파랑) / "종료"(회색) — 종료된 정의도 포함 표시 | sdk.recurringAllowance.list({employeeId, includeEnded:true}) | 로딩 중 스피너 |
| 10-E | Empty | Text | • "정의된 고정 수당이 없어요." | ||
| ㄴ11 | 종료일 저장 | Button | • 행별 "종료일" 날짜 입력(시작일 이후만) + "종료일 저장" • 클릭 → 즉시 실행(correct validUntil), 성공: 목록 재조회. 종료일 다음 달부터 시트에서 빠지고 지난달 시트는 그대로. 비우고 저장하면 무기한 - CASE01 [값 변화 없음·저장 중]: 버튼 비활성 | sdk.recurringAllowance.correct() | 실패: "고정 수당 저장 실패: {오류}" |
| ㄴ12 | 금액 정정 | Button | • 행별 "월 금액" 입력 + "금액 정정" • 클릭 → 컨펌 "금액을 정정할까요? 이 정의가 걸친 아직 확정하지 않은 달에 모두 반영돼요. 특정 날부터 바꾸려면 종료일을 넣고 새로 추가해 주세요." → 실행(같은 정의 v+1) - CASE01 [금액 변화 없음·저장 중]: 버튼 비활성 | sdk.recurringAllowance.correct() · 미커밋 달 시트 값 | 실패: "고정 수당 저장 실패: {오류}" |
| 20 | 고정 수당 추가 | Form | • 제목 "고정 수당 추가". 입력: "수당 이름"(최대 100자) / "코드"(placeholder "license_bonus", 최대 64자) / "월 금액" / "메모 (선택)" / "시작일" / "종료일 (선택 · 비우면 무기한)" • 코드 도움말(원문): "시트 열 설정의 「반복 고정 수당」 원천에서 이 코드로 거를 수 있어요(영문 소문자·숫자·밑줄)." | recurring_allowance_definitions | 미래 시작일 정의도 즉시 저장("예정") |
| ㄴ21 | 추가 | Button | • 클릭 → 즉시 실행(create), 성공: 폼 초기화 + 목록 재조회 - CASE01 [필수 누락·금액 0 이하]: 알림 "수당 이름·코드·시작일을 채우고 금액을 0보다 크게 입력해 주세요." - CASE02 [실패]: "고정 수당 저장 실패: {오류}" | sdk.recurringAllowance.create() | 코드는 소문자로 정규화 |
⑥ 계정·보안 사양표 (부분 — 비밀번호 직접 설정)
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 10 | 비밀번호 변경 › 직접 설정 | Radio | • "직접 설정"(설명 "관리자가 새 비밀번호를 직접 입력합니다.") 선택 시 새 비밀번호·확인 입력 + "비밀번호 변경" 버튼 • 규칙 안내(원문): "{min}자 이상, 또는 임시 비밀번호 형식({format})으로 입력할 수 있어요." — {min} = 병원 설정 일반 비밀번호 최소 길이(4~20, 기본 8), {format} 예 "고정값 0000" / "숫자 4자" • 입력칸 안내: "새 비밀번호 ({min}자 이상)" · 문자 구성(대문자·숫자 등)은 직원이 바꿀 때 검사하고 직접 설정은 길이만 본다 | employees · 조직 임시 비밀번호 정책 [[HBAD270_설정 (조직 설정·내 정보)]] | 규칙 확장 (코드 반영: 01d3cc5b, #948, CS-OKBEST-260929-0001) · 최소 길이 병원 설정 연동(#995) · TBU: 라이브 실사 이월 |
| ㄴ11 | 임시 형식 판정 | Rule | • {min}자 이상 → 종전처럼 저장(변경 강제 없음) - CASE01 [{min}자 미만 + 조직 임시 형식 일치]: 안내 "임시 비밀번호 형식이에요. 저장하면 직원이 첫 로그인 때 비밀번호를 바꿔야 해요." + 확인 "임시 비밀번호 형식으로 설정할까요? 직원은 첫 로그인 때 비밀번호를 바꿔야 해요." → 저장, mustChangePassword=true - CASE02 [형식 불일치]: 오류 "{min}자 이상이거나 조직의 임시 비밀번호 형식과 같아야 해요." + 버튼 비활성(서버도 같은 문구로 거부) | employees.mustChangePassword · core matchesTemporaryPasswordPolicy | 확인 문구 노출 시점 TBU |
| 20 | 패스키·기기 키 전용 로그인 해제 | Button | • (10/13, #1227 d35e4e3) 직원이 인증/보안 설정에서 「패스키·기기 키로만 로그인」을 켠 경우, 계정·보안 탭에서 관리자가 해제할 수 있음(overview.passkeyOnly) — 해제하면 비밀번호·SMS 로그인 복구 - CASE01 [직원 미설정]: 해제 컨트롤 비활성/미노출(관리자가 켤 수는 없음) | employees.passkeyOnlyLogin · security.setPasskeyOnly · [[HBEA100_로그인]] ㄴ63 | 신설 (#1227) · TBU: 라이브 실사(패널 탭 내부 미도달) |
공통 하단·이탈 가드 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 90 | 하단 버튼 | Button | • 모달 하단 액션 버튼 묶음: "취소" / "미리보기" / "등록" • "취소" 클릭 시: 이탈 가드 후 모달 닫기 • "미리보기" 클릭 시: 등록 내용 미리보기 • "등록" 클릭 시: "등록 중..." 표기 + 버튼 disabled → 4 생성물 트랜잭션, 기본 상태 비활성(activation gate) - CASE01 [저장 실패]: 트랜잭션 실패 시 처리(토스트/롤백) | sdk.employee.create() | 권한 "직원 관리" · TBU: 저장 실패 동작 |
| ㄴ90-1 | 시트 자동 추가 미리보기 안내 | Notice | • (직원 추가) 조직 설정 「신규 입사자 시트 자동 추가」가 켜져 있을 때만 미리보기(검토) 모달에 안내. 입사일이 바뀌면 다시 계산 - CASE01 [대상 있음]: "저장하면 이 직원 행이 다음 시트에 자동으로 추가돼요: {시트명 (YYYY.MM)} · …"(상시 시트는 이름만) - CASE02 [대상 없음]: "「신규 입사자 시트 자동 추가」가 켜져 있지만 지금 입사일로 들어갈 시트가 없어요." (+ 입사일 가드 해당 시 "(입사일이 시트 기간 이후인 시트는 제외돼요)") | sdk.employee.previewNewEmployeeSheets() · [[HBAD270_설정 (조직 설정·내 정보)]] ㄴ33 | 신설 (코드 반영: 6ea0ac58, #908) · 설정 꺼짐 시 미노출 · TBU: 라이브 실사 이월 |
| ㄴ90-2 | 시트 자동 추가 결과 (완료 화면) | Notice | • 등록 완료 화면에 결과 표시(설정 켜짐일 때만) - CASE01 [추가됨]: "시트 {N}개에 이 직원 행을 추가했어요: {시트명} · …" - CASE02 [0건]: "신규 입사자 시트 자동 추가가 켜져 있지만 이번에 행이 들어간 시트는 없어요." | employee.create 응답 sheetAutoAdd · [[HBHR202_직원 추가]] | 코드 반영: 6ea0ac58, #908 · 엑셀 대량 추가는 결과 미표시 |
| 91 | 미저장 이탈 가드 | Alert | • 변경 후 취소/닫기 시 노출되는 확인 얼럿 (원문 카피): "변경된 내용을 저장하지 않고 나가시겠어요?" (버튼 "계속 편집" / "나가기") | 원문 카피 |
4 생성물 · activation gate
| 생성물 | 엔티티 | 초기 상태 |
|---|---|---|
| ① Employee | employees | 비활성 (activation gate) |
| ② 소속·역할 | team_members (n:m) | 팀·역할 배정 |
| ③ 근로계약·급여 seed | employment_contracts | 급여 원천 (정본 아님) |
| ④ 자격증 요건 | employee_certifications | 파일 미제출 |
권한 / 상태 요약
| 시나리오 | 트리거 | 결과 | 비고 |
|---|---|---|---|
| CASE01 [직원 생성] | "등록" | "등록 중..." → 4 생성물 트랜잭션, 상태 비활성 | activation gate |
| CASE02 [전화번호 입력] | 저장 (전화번호 有) | SMS 임시비밀번호 발송 | mustChangePassword |
| CASE03 [자격증 요구] | 자격증/면허 요구 선택 | 자격증 화면 "파일 미제출" 등록 | |
| CASE04 [미저장 이탈] | 변경 후 취소/닫기 | "변경된 내용을 저장하지 않고 나가시겠어요?" (계속 편집/나가기) | |
| CASE05 [퇴직 취소] | 퇴직자 → 상태 "퇴직 취소(재직 복귀)"/"재직" + 사유 → 저장 | 퇴사 기록 무효(사유 기록) · 재직 · 팀 단톡방 복귀 | 정산 완료 기록이면 거절 (#959) |
| CASE06 [임시 형식 비밀번호] | 직접 설정에 조직 임시 형식 값 | 저장 + 첫 로그인 변경 강제 | #948 |
| CASE07 [수습 종료 후 입력] | 직원 추가 ④ 수습 종료일 + 수습 후 금액 → 등록 | 계약 v1 생성 + 종료일+1일 시행 계약 변경 예약(SCHEDULED) — 수습 달 시트는 등록 계약 값, 다음 달부터 예약 값 | #965 · 예약 목록은 계약급여내역 행 메뉴 「계약 시행일 변경…」에서 확인 · (10/8, #1084) 같은 시행일 계약 변경 예약이 이미 있으면 등록 거부(원문은 Data I/O 「수습 종료 후 계약 예약」 행) — 등록 트랜잭션 전체 롤백 여부 TBU(실사 대기) |
Open Question
| 구분 | 미확인 항목 |
|---|---|
| 하단·저장 | 저장 실패(트랜잭션 실패) 시 처리(토스트/롤백) 동작 |
| 수습 예약 | 직원 수정(편집) 모달에도 「수습 종료 후」 블록이 있는지 — 코드상 추가 패널(AddEmployeePanel)만 확인. 조직 전체 예약 확인처 admin 「급여 관리 › 예약된 변경」(#980, 10/7 #1084 로 상태별 서브탭·전→후 표·상세 창 재구성, 열람 = 급여 조회(전체)) = 신규 화면 채번 대기(제안 HBAD275, 10/8) |