HBAD210_팀 관리
(Hereby) 관리자 패널 > 인사 관리 > 팀 관리
| 메타 | 앱: 관리자 패널 (포트 4001)대상 사용자: 조건1 [최고 관리자] / 조건2 [인사 관리자] (권한 "팀 관리" / "팀 조회")프로토타입: TBU관련 정책: [[POL_권한(RBAC)]] · [[POL_테넌트·조직]] · [[POL_팀 관리]]Status: reviewOwner: 카나 |
개요
팀 관리는 조직 팀 계층 트리(teams + parentTeamId)와 전체 구성원(team_members)을 관리한다. 좌측 팀 트리(조직 루트 노드 + 팀 계층, 각 노드 인원수) + 우측 구성원·팀 상세로 구성된다. 팀은 상위 팀·팀장(leader)·설명·상태(활성/비활성)를 가지며, 직원은 멀티 소속으로 여러 팀에 배정될 수 있다 (n:m). 좌측 트리 루트는 조직 루트 노드(조직명 + 전체 인원)이며, 그 아래에 팀 계층이 인원수와 함께 표시된다. 루트 선택 시 우측은 "전체 구성원", 팀 선택 시 해당 팀 상세를 표시한다.
문서 히스토리
- 2026-07-06 최초 작성 - 카나/콸
- 2026-07-10 라이브 기능 검토 반영 (7/10 diff) - 카나/콸
- 2026-07-13 버튼 행동 명세 보강 - 카나/콸
- 2026-07-21 GC700 깊이 재작성 - 카나/콸
- 2026-07-21 가독성 패스 (GUIDE §7) - 카나/PM
- 2026-07-21 셀 스타일 확정판 적용 (콸 승인) - 카나/PM
- 2026-07-22 코드 변경 반영(d522367·e0caa04) - 카나/콸
- 2026-09-17 일괄 적용이 각 멤버십 행의 소속 팀을 타겟(하위 조직 포함 뷰 오적용 수정)·부분 실패 허용 반영(67a3f13) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
- 2026-09-18 상태 일괄 변경 후 행이 실제 속한 팀 구성원 캐시 재조회(상태 배지·헤더 인원 즉시 갱신, CS-OKBEST-260917-0007)·같은 틱 배치 전송·부분 실패 안내 반영(8950d1b, #786) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
- 2026-09-21 필터 줄 「근무 설정」 팝업 진입 버튼 반영(07effb5, #806) — 커밋 근거, 라이브 실사 이월(TBU). 팀↔병동 분리 재설계는 이 날 커밋 없음(미랑은 시트 UX 브랜치 작업 중) - 카나/PM
- 2026-09-26 주간 정합 스윕 라이브 실사 — 필터 줄 「근무 설정」 버튼 위치·툴팁 원문·팝업 좌측 탭 9종 실측(25, TBU 해소, 열람만) - 카나/PM
- 2026-09-29 팀↔병동 화면 분리 반영(#833/#912, v0.14.0 운영) — 조직도 병동 노드·미연결 병동·팀 멤버 추가 팝업 병동 모드 제거, 「병동 현황」 기본 접힘 섹션(50)·직원 카드(60) 신설, 관련 OQ 해소 — 라이브 실사 확인 - 카나/PM
- 2026-09-30 팀 헤더 연결 병동 줄·병동 인력/스케줄러 미리보기 팝오버(ㄴ40-2~5) 신설 반영(#932, MED-97)·QA 수정(다른 팀 선택 시 닫힘·헤더 아래 배치·내용 높이, #941) + 라이브 실측 소진(연결 줄·팝오버 제목/부제/3열/Empty 원문, live-0930-team-*.png) - 카나/PM
- 2026-10-07 PR #1060(a5e31886, MED-914·917) 반영: 진입 로딩 team.roster 벌크 1콜(55)·팀원 목록 상태 필터 「필터」 라벨+서브탭 칩(56) · PR #1055(8f999781, MED-911) 반영: 「하위 팀 포함」 토글(57) — 커밋 근거, 라이브 실사 이월(TBU) - 카나/PM
- 2026-10-08 (10/7 머지분) PR #1078(b2a6cced·12da8faf, MED-946) 반영: 팀장 복수 지정(모달 50 칩+검색·대표 팀장, ㄴ40-6 헤더 「팀장 A, B」·배지 전원 기준)·총괄 팀장(ㄴ30-4 워크스페이스 헤더·ㄴ30-5 배지·「총괄 팀장 지정」 모달 신설) · PR #1087(34e5e5e, MED-947)·#1091(1acac4f) 반영: 두 모달 본문 스크롤·검색 목록 노출(51·총괄 모달 20) · PR #1088(876ec23, MED-953)·#1091 반영: 트리 팀 행 드래그로 형제 순서 변경(ㄴ12-1, 최상위 포함) · PR #1097(d51745b5, MED-955) 반영: 팀 관리 명단
team.read.team선택 가능(Data I/O) · CASE07·08·09·엔티티team_leaders·teams.sortOrder추가 — 커밋 근거 + 라이브 실사 확인(2026-10-08: 조직 헤더 "총괄 팀장 미지정"·총괄 모달 원문·트리 draggable), 팀 수정 모달 팀장 칩은 실사 이월(TBU) - 카나/PM - 2026-10-08 낮 스윕 라이브 실사 — 팀 수정 모달(간호부) 열람: 팀장 칩·placeholder·도움말 원문 실측(50 TBU 해소), 모달 본문 정상 노출(51), 진입 경로 = 트리 팀 선택 → 패널 헤더 「팀 편집」/「팀 삭제」, 모달 제목 "팀 수정"·푸터 〔취소〕/〔수정〕 - 카나/PM
- 2026-10-13 (10/11~12 머지분) PR #1154(MED-969) 팀 수정 모달 「허용 근무 유형」 섹션(ㄴ50-1 신설 — 10/13 실측 채록) · PR #1197 「하위 팀 포함」 기본 켬·조직/사용자별 기억(57 보강 — 10/13 실측 checked 확인) - 카나/PM
Data I/O
Server → Client
변수
| 메타 | ${team_tree} |
| 메타 | ${members} |
| 메타 | ${team_detail} |
Client → Server
| 액션 | 전달 값 | tRPC procedure | 권한 토큰 |
|---|---|---|---|
| 팀 추가/수정 | 상위 팀 / 팀명 / 설명 / 상태 / 팀장 — (10/8, #1078, MED-946) team.create/update 입력 leaderIds(대표 먼저, 최대 20) 추가, leaderId 만 오면 한 명으로(null 이면 전원 해제) 처리(호환). 새로 들어오는 팀장만 자격(같은 조직·재직) 확인 · team.list/getById 가 leaderIds 반환 | sdk.team.upsert() (추정) · 서버 setTeamLeaders(team_leaders 전원 + teams.leaderId = 첫 사람) | team:write (라벨 "팀 관리", 토큰 추정) |
| 총괄 팀장 조회/지정 | leaderIds[] | (10/8, #1078 12da8faf) team.orgLeaders / team.setOrgLeaders (sdk team.orgLeaders() / team.setOrgLeaders(ids)) — 퇴사자 지정 불가 | team:update.all (팀 수정과 같은 게이트) |
| 팀 순서 변경 (드래그) | parentTeamId(최상위면 null) · orderedIds[] | (10/8, #1088, MED-953) team.reorder — 팀 구조 잠금 안에서 전부 같은 상위 팀의 형제인지 확인 후 teams.sortOrder 를 0부터 다시 매김. 배열에 없는 형제(그 사이 다른 관리자가 추가)는 지금 순서로 뒤에 이어 붙임 | team:update (또는 시스템 관리자) |
| 팀 삭제 | teamId | sdk.team.delete() (추정) | team:write (추정) |
| 멤버 배정 | employeeId · teamId · roleId | team_members 생성 (추정) | team:write (추정) |
| 명단 다운로드 | 필터 조건 | export (추정) | team:read (추정) |
| 진입 로딩 (일괄) | — | team.roster — 직원·활성 소속·병동 배정 3개 벌크 질의 1콜(주소·주민번호·급여 열 없음) | team:read (추정) · 신설 (a5e31886, #1060, MED-914) · (10/8, #1097, MED-955) 라우터는 requireTeamOrWiderPermission(TEAM, READ)(명단·병동 요약)로 팀 범위를 이미 판정 — 카탈로그에 team.read.team「소속 팀 정보 조회」(팀장 지정 팀·소속 팀 + 하위 팀) 행이 생겨 역할 관리에서 팀 범위를 줄 수 있게 됨([[HBAD220_역할 관리·권한 트리]]) |
외부 통합
| 외부 시스템 | 데이터 | 방향 | 비고 |
|---|---|---|---|
| 전 앱 (HR·직원 앱·스케줄러) | teams / team_members 소속 소비 | Admin(원천) → 소비 | 팀은 조직 SoT |
메인 화면 사양표 (팀 관리)
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 노출 조건 | - | • 조건1 [팀 관리/조회 권한] 보유 시 사이드바 인사 관리 > "팀 관리" 노출. 권한 없으면 사이드바 항목 hide | [[HBAD100_App Shell·사이드바]] | 권한 미보유 시 진입 불가 |
| 01 | 초기 상태 | Output | • 좌측 팀 트리(조직 루트 선택 상태) + 우측 "전체 구성원" 표시 | ||
| 10 | 팀 트리 | Tree | • 조직 루트 노드 + 그 아래 팀 계층·각 노드 인원수를 표시하는 좌측 네비 • 클릭 시: 노드 선택으로 우측 패널 전환 - CASE01 [루트 선택]: 우측 "전체 구성원" - CASE02 [팀 선택]: 우측 팀 상세 | teams (parentTeamId) | |
| ㄴ11 | 조직 루트 노드 | Node | • 트리 최상단 조직명 + 전체 인원 (라이브 예: "분당베스트병원 update 295") • 클릭 시: 우측 "전체 구성원" 표시 | teams 루트 | 7/10 확인 |
| ㄴ12 | 팀 노드 | Node | • 팀명 + 인원수 표시 노드 • 클릭 시: 우측 팀 상세 전환. 값 없음: 하위 팀 0건이면 루트만 표시 | teams | |
| ㄴ12-1 | 팀 행 드래그 (형제 순서 변경) | Drag | • (10/8, #1088, MED-953) 트리의 팀 행을 마우스로 끌어 같은 상위 팀 안의 형제 사이(또는 최상위 팀끼리)에 놓으면 노출 순서가 바뀌고 저장(team.reorder → teams.sortOrder). 끌 수 있는 행에 툴팁(원문) "끌어서 같은 상위 팀 안의 순서를 바꿀 수 있어요"• 드래그 중: 끄는 행은 흐려지고, 같은 형제 위에서는 행 위/아래 가장자리에 2px 선으로 놓을 자리(위/아래 = 행 높이 절반 기준) 표시 - CASE01 [자기 자신·다른 상위 팀의 행 위]: 놓을 수 없음(금지 커서), 놓아도 변화 없음 — 다른 상위 팀으로 옮기기는 팀 수정의 「상위 팀」(모달 10)으로 - CASE02 [놓음]: 화면 먼저 반영(낙관적) 후 서버 저장 / 실패 시 이전 순서로 되돌리고 오류 토스트(서버 메시지, 없으면 원문 "팀 순서를 저장하지 못했어요.") 후 팀 목록 재조회 • 끌 수 있는 조건: 조건1 [team:update 권한 또는 시스템 관리자] + 트리 검색어 없음 — 그 외 끌리지 않음• 명단에서 직원을 팀으로 끌어 옮기는 기존 드래그와는 끄는 대상(팀/직원)으로 갈라 섞이지 않음 • 정렬 규칙(core compareTeamOrder): sortOrder 있는 팀 먼저(오름차순) → 없는(NULL) 팀은 예전 규칙(병동 연결 팀 먼저·병동 코드순, 나머지 이름순 — 한국어·숫자 인식). 기존 데이터는 전부 NULL 이라 한 번도 안 바꾼 병원은 이전과 같은 화면• (10/8, #1091) 최상위 팀(조직 바로 아래)도 저장 순서로 정렬 — 구버전은 저장은 됐으나 최상위 줄이 sortOrder 를 읽지 않아 서버 목록 순서로 보이던 결함 | teams.sortOrder(마이그레이션 1959, NULL 허용) · [[HBAD201_직원 추가·수정 모달]] 소속 팀 트리·드라이브 공유 대상 선택기 팀 탭도 같은 순서 | 신설 (876ec23, #1088 · 1acac4f, #1091) · 라이브 실사 확인(2026-10-08): 트리 팀 행 draggable=true 63개 실증 · TBU(실사 대기): 실제 끌어 놓기·저장은 미실행(조회만) |
| 10-E | 트리 Empty | State | • 하위 팀 0건 시 루트 노드만 노출 (하위 목록 없음) | TBU: 트리 Empty 문구 | |
| 20 | 팀 추가 (트리 버튼) | Button | • 트리 상단에서 새 팀을 생성하는 진입 버튼. 원문 "팀 추가" • 클릭 시: "팀 추가" 모달 노출 (선택 노드가 상위 팀 default) - CASE01 [루트 선택 중]: 최상위 하위 팀 추가 - CASE02 [팀 선택 중]: 해당 팀 하위 추가 | teams.parentTeamId | |
| 25 | 근무 설정 (진입 버튼) | Button | • 팀 관리 「전체 구성원」 필터 줄에서 「근무 설정」(유형·기준 관리) 팝업을 여는 진입 버튼. 줄 구성(실측): 전체 구성원 / 상태 선택 / 직무 선택 / 🔍 / [근무 설정] / [명단 다운로드] / [신규 직원 추가] / [팀 추가] • 툴팁(원문): "근무 그룹·근무형태·직무 등 직원 설정을 관리합니다." • 클릭 시: 「근무 설정」 탭이 선택된 상태로 유형·기준 관리 팝업 오픈(직원 관리·근태 현황과 같은 팝업). 좌측 탭 9종(원문): 근무 설정 / 직무 설정 / 근로형태 / 연장근무 유형 / 외근 유형 / 연차 부여 기준 / 휴가/연차 유형 / 연차 정책 / 공휴일 • 목적: 팀 대표 근무·직무 기본 근무를 팀 관리에서 이탈 없이 편집 | [[HBAD260_근무 설정 (근무 그룹·유형)]] · [[HBAD200_직원 관리]] | 신설 (코드 반영: 07effb5, #806) · 라이브 실사 확인(2026-09-26 — 팝업 열람까지만) |
| 30 | 전체 구성원 (루트 선택) | Grid | • 루트 선택 시 우측에 조직 전체 구성원을 보여주는 그리드. 헤더 "전체 구성원" + "직원 추가" / "명단 다운로드" / "팀 추가". 컬럼: 사번 / 이름 / 이메일 / 팀 · 역할 / 상태 / 관리 • "명단 다운로드" 클릭 시: 즉시 실행(컨펌 없음), 성공: 파일 다운로드(화면 무변화) | team_members | 6컬럼 · 직원 추가 버튼 추가(코드 반영: d522367·e0caa04) |
| ㄴ30-1 | 직원 추가 (조직 레벨) | Button | • 조직(팀) 탭에서 직원을 신규 등록하는 진입 버튼 (기존엔 직원 관리 메뉴에서만 가능) • 클릭 시: 직원 등록 위저드(HBAD201) 오픈 | [[HBAD201_직원 추가·수정 모달]] | 신설 · 7/21 베스트 실무진 요구("팀 관리 안에서 직원 추가") 당일 반영 (코드 반영: d522367·e0caa04) |
| ㄴ30-2 | 직원 수정 (조직 레벨) | Button | • 조직 탭 구성원 행에서 직원 정보를 수정하는 기능 (기존엔 직원 관리에서만) • 클릭 시: 직원 수정 모달(HBAD201) 오픈 | [[HBAD201_직원 추가·수정 모달]] | 신설 (코드 반영: d522367·e0caa04) |
| ㄴ30-3 | 일괄 적용 (역할 변경·팀 제외·팀 배정) | Button | • 구성원 다중 선택 후 일괄 역할 변경·팀에서 제외·팀 배정을 실행. 「하위 조직 멤버 포함」 뷰에서도 각 멤버십 행이 실제 속한 팀으로 처리(구버전은 하위 팀 행이 서버에서 "팀원을 찾을 수 없어요."로 누락되던 버그 수정) • 클릭 시: 확인 모달 "일괄 적용" → "{N}명에게 선택한 변경사항을 적용할까요?" (팀 배정 줄 "· 팀 배정 → {팀명} (기존 소속 팀은 그대로 유지돼요)") → "적용" - CASE01 [성공]: 토스트 "{N}명의 역할을 변경했습니다" / "{N}명을 팀에서 제외했습니다" / "{N}명을 팀에 배정했습니다" - CASE02 [부분 실패]: 성공분 반영 + 실패 인원 안내 "{키}: {N}명 중 {M}명을 제외하지 못했어요. {첫 실패 사유}" (직렬 처리 → Promise.allSettled 전환)• 상태 일괄 변경 후 명단 즉시 갱신(9/18): 변경 요청을 같은 틱에 묶어 보내고(httpBatchLink, 하나가 실패해도 나머지는 저장), 완료 후 직원 목록·전체 로스터에 더해 행이 실제 속한 팀(하위 조직 포함 뷰면 하위 팀)의 구성원 캐시까지 재조회 — 구버전은 팀 화면의 상태 배지·헤더 인원이 새로고침 전까지 옛 값에 머물던 문제(CS-OKBEST-260917-0007). 병동 연결 팀 배정으로 병동 열이 바뀌는 경우도 함께 반영 - CASE03 [상태 변경 부분 실패]: "상태 변경 실패: {N}명 중 {M}명의 상태를 바꾸지 못했어요. {첫 실패 사유}" | team_members · employees.status | 신설 (코드 반영: 67a3f13) · locale admin.status_change_failed "상태 변경 실패" 추가 · 상태 일괄 변경 후 팀 구성원 재조회(코드 반영: 8950d1b, #786) · TBU: 라이브 실사 이월 |
| ㄴ30-4 | 총괄 팀장 (워크스페이스 헤더) | Output/Button | • (10/8, #1078 12da8faf, MED-946) 루트(조직) 선택 시 우측 워크스페이스 헤더의 인원 요약 줄 끝에 「총괄 팀장 {A}, {B}」(지정 없으면 원문 "총괄 팀장 미지정") — 이름은 전체 명단에서 찾음 • 조직명 옆 연필 아이콘 버튼(툴팁 원문 "총괄 팀장 지정") 클릭 시: 서버 값을 다시 읽은 뒤 「총괄 팀장 지정」 모달 오픈(아래 별도 표) • 총괄 팀장 = 병원 전체를 맡는 팀장( team_leaders.teamId NULL 행). 팀장 권한 묶음을 조직 전체 범위(.all) 로 얻고, 팀장 앱에서 활성 팀 전부 관할, 팀장 묶음 리소스 결재 알림을 조직 전체에서 받음(팀·직책·설정 같은 관리 권한은 여전히 역할이 줌) · 퇴사 처리 시 총괄 지정도 해제 | team_leaders(teamId NULL) · team.orgLeaders · [[HBAD220_역할 관리·권한 트리]] | 신설 (12da8faf, #1078) · 권한 미보유·조회 실패 시 이전 값 유지 · 라이브 실사 확인(2026-10-08): 조직 헤더 원문 "34개 팀 • 전체 275명 • 재직 272명 • 휴직 3명 • 퇴직 13명 • 총괄 팀장 미지정" + 「총괄 팀장 지정」 버튼 |
| ㄴ30-5 | 총괄 팀장 배지 | Badge | • 전체 구성원·팀 명단의 사번 옆에 「총괄 팀장」 라벨(blue, 팀 화면 「팀장」과 같은 색) — 어느 팀 화면에서도 표시 | ㄴ30-4 · ㄴ40-6 | 신설 (12da8faf, #1078) |
| ㄴ31 | 팀 · 역할 셀 | Cell | • 멤버의 소속 팀·역할을 계층 chip으로 표기. 멀티 소속 시 다중 chip | team_members n:m | |
| ㄴ32 | 상태 셀 | Badge | • 멤버 재직 상태 배지: CASE01 [재직] / CASE02 [비활성] / CASE03 [휴직] / CASE04 [퇴직] | employees.status | TBU: 상태 값 목록 |
| 30-E | 전체 구성원 Empty | State | • 구성원 0건 시 Empty 표기 | TBU: Empty 원문 문구 | |
| 40 | 팀 상세 (팀 선택) | Detail | • 팀 노드 선택 시 우측에 표시되는 팀 상세. 헤더 "총 n명 • 팀장 {이름}" + "직원 추가" / "멤버 명단 다운로드" / "팀 멤버 추가" + 멤버 테이블(동일 6컬럼) + 팀 편집 / 팀 삭제 아이콘 • "멤버 명단 다운로드" 클릭 시: 즉시 실행, 성공: 파일 다운로드(화면 무변화) • "팀 멤버 추가" 클릭 시: 멤버 배정 팝업(검색·팀 선택·표 5열) 오픈 — 팝업의 병동 모드는 제거됨(#833 84b42eb, 병동 배정은 [[HBAD230_병동 관리]] 직원 배정 팝업으로 일원화) | teams · team_members | 직원 추가 버튼 추가(코드 반영: d522367·e0caa04) · 병동 모드 제거(코드 반영: #833) · 라이브 실사 확인(2026-09-29) |
| ㄴ40-1 | 직원 추가 (팀 레벨) | Button | • 팀 상세(팀 레벨 컨텍스트)에서 직원을 신규 등록하는 진입 버튼. "팀 멤버 추가"(기존 소속 배정)와 별개로 신규 직원 등록 • 클릭 시: 직원 등록 위저드(HBAD201) 오픈 | [[HBAD201_직원 추가·수정 모달]] | 신설 · 조직/팀 양쪽 컨텍스트 노출 (코드 반영: d522367·e0caa04) |
| ㄴ41 | 멤버 Empty state | State | • 멤버 0건 시 원문 "멤버가 없어요. + 팀 멤버 추가 로 시작해요." | team_members 부재 | 7/10 확인 |
| ㄴ42 | 팀 편집 아이콘 | Button | • 팀 상세 헤더의 title 아이콘 • 클릭 시: 팀 편집 폼 노출(상위 팀/팀명/설명/상태/팀장, 기존값 프리필) | teams | |
| ㄴ43 | 팀 삭제 아이콘 | Button | • 팀 상세 헤더의 title 아이콘 • 클릭 시: 컨펌 "팀을 삭제하시겠어요?" - CASE01 [하위/멤버 없음]: 삭제 실행 - CASE02 [하위 팀·멤버 존재]: 정책상 삭제 불가([[POL_팀 관리]]) — 라이브 실차단 문구 프로브 미확인 | teams | 삭제 컨펌 7/10 확인 |
| ㄴ40-2 | 연결 병동 줄 (팀 헤더) | Output | • 병동이 연결된 팀(teams.wardId)을 선택했을 때만 팀 헤더 아래에 한 줄 표시. 실측 원문 「연결 병동 {병동} · 배정 {N}명 · 수간호사 {이름 | 미지정} · 🗓 스케줄러 미리보기」 — 「배정 N명」·「스케줄러 미리보기」는 글자 버튼• 「배정 N명」 = 병동 배정 기준(겸임·상위 부서 소속 포함) 재직+휴직 인원 — 팀 명단 인원과 다를 수 있음(예: 팀 28명 / 병동 배정 31명) - CASE01 [수간호사 미지정]: 「수간호사 미지정」(회색) 표시 • CASE02 [화면 폭 768 미만]: 줄·팝오버 모두 미노출 • CASE03 [근무표( nurse-scheduler:read)·인력(schedule:read) 읽기 권한 모두 없음]: 「스케줄러 미리보기」 버튼 미노출 | team.wardSummary(team:read) · [[HBAD230_병동 관리]] | #932 (MED-97) · 라이브 실측 2026-09-30(live-0930-team-wardline.png) |
| ㄴ40-3 | 병동 인력 팝오버 | Popover | • 「배정 N명」 클릭 시 화면 오른쪽(페이지 헤더 바로 아래·오른쪽 24px)에 뜨는 읽기 전용 명단. 제목 원문 "{병동명} 인력" + 부제 "병동 배정 기준 · 재직+휴직 {N}명" • 상단 이름 검색(placeholder "이름 검색", 결과 없음: 「찾는 사람이 없어요.」) + 표 3열: "이름" / "직무" / "교대 형태" (직무 미입력 = "-"), 이름순 • 머리의 ↗ 아이콘 버튼 클릭 시: 병동 관리의 해당 병동으로 이동 · X 닫기 • 명단은 「배정 N명」을 센 서버 요약과 같은 출처(숫자와 줄 수 일치) | [[HBAD230_병동 관리]] | #932 · #941 · 라이브 실측 2026-09-30(live-0930-team-roster-pop.png) |
| ㄴ40-4 | 스케줄러 미리보기 팝오버 | Popover | • 「스케줄러 미리보기」 클릭 시 뜨는 읽기 전용 이번 달 근무표(병동 기본 스케줄러). 제목 원문 "{병동명} 스케줄러" + 부제 "{YYYY}년 {M}월 · 읽기 전용" • 스케줄러와 같은 칸 라벨·색 규칙, 필터·편집 없음, 가로·세로 스크롤. 주말만 색 표시(공휴일 색 없음) - Empty(-E): 스케줄러 없음 시 원문 "이번 달 스케줄러가 아직 없어요." • 머리의 ↗ 아이콘 버튼 클릭 시: 스케줄러의 해당 병동·이번 달로 이동(직원 카드 「스케줄러 보기」와 같은 이동) · X 닫기 • 근무 유형을 못 읽어도 근무표는 표시 | [[HBNS210_간호사 프로필 관리]] | #932 · #941 · 라이브 실측 2026-09-30(live-0930-team-sched-pop.png) |
| ㄴ40-5 | 연결 병동 팝오버 공통 규칙 | Rule | • 두 팝오버 중 한 번에 하나만 표시, 같은 버튼 재클릭 시 닫힘 • 닫힘 조건: ESC(화면 최상단 하나만) / 다른 팀·메뉴 이동 / 채팅·AI 어시스턴트 열기 / 헤더 알림·프로필 메뉴 클릭. 팝오버가 열리면 채팅·떠 있는 AI 창은 접힘 • 「불편·기능 신고」 버튼은 닫지 않음(신고 스크린샷에 팝오버가 찍히도록) • 높이 = 내용만큼, 인원이 많으면 화면 아래 24px 남기고 안쪽 스크롤 | [[HBAD100_App Shell·사이드바]] | #941 (MED-97 QA: 다른 팀 선택 시 팝오버 잔존 수정) |
| ㄴ40-6 | 팀장 표기 (복수) | Output/Badge | • (10/8, #1078, MED-946) 팀 헤더의 팀장 표기가 팀장 전원 기준: 「팀장 {A}, {B}」(원문 접두 "팀장 ", 쉼표 구분) / 없으면 "팀장 미지정" • 멤버 표의 「팀장」 배지도 공동 팀장 전원에게 표시(구버전 = leaderId 한 명만)• 판정 = team_leaders 표 ∪ teams.leaderId(기존 leaderId 는 표로 이관하지 않음 — 팀장 재지정 결정, 읽는 쪽이 합쳐 봐 끊기지 않음) | team_leaders · teams.leaderId · 모달 50 | 변경 (b2a6cced, #1078) · TBU: 라이브 실사 이월 |
| 50 | 병동 현황 (접힘 섹션) | Section | • 팀 트리 하단(또는 우측 패널 하단)의 병동 요약 섹션 — 기본 접힘, 펼치기/접기 버튼. 조직도(팀 트리)에는 병동 노드·「미연결 병동」 항목이 없음(#833에서 제거 — 병동은 [[HBAD230_병동 관리]] 전용 화면으로 분리) • 펼치기 클릭 시: 병동 현황표 노출. 요약 원문 "병동 N곳 · 인원은 전체(재직+휴직) 기준" + 「병동 관리로 이동 ›」 링크 - CASE01 [팀 노드 선택 중]: "하위 병동 N곳" 표기 - CASE02 [미연결 병동 행]: 툴팁 원문 "어느 팀에도 연결되지 않은 병동이에요. 누르면 연결할 팀을 설정할 수 있어요." • 「병동 관리로 이동 ›」 클릭 시: [[HBAD230_병동 관리]] 전환 | [[HBAD230_병동 관리]] · wards(teams 연결) | 재작성 (코드 반영: #833/#912, v0.14.0) · 라이브 실사 확인(2026-09-29) — 현장 피드백(9/21 "병동은 병동 탭에서") 반영으로 팀↔병동 화면 분리 확정 |
| 55 | 로딩 전략 (roster 벌크 1콜) | Rule | • (10/7, #1060, MED-914) 진입 때 직원 전체 목록(1000행 페이지)·팀 목록 2회·병동 요약을 부르고 팀 선택마다 하위 팀 수만큼 getComposition을 부르던 것을 team.roster 1콜로 교체 — 팀별 명단은 로스터에서 파생해 팀 선택 시 호출 0건, 병동 요약은 표를 펼칠 때만 조회 • 실측(데모 조직): 진입 4건 74KB → 2건 37KB, 팀 선택 20건 → 0건(scripts/perf/team-management-load.mjs) | team.roster · 50 병동 현황 | 신설 (a5e31886, #1060) |
| 56 | 팀원 목록 상태 필터 (칩) | Tab | • (10/7, #1060, MED-917) 팀원 목록의 상태 필터를 액션 버튼처럼 보이던 드롭다운 → **「필터」 라벨 + 서브탭 칩(전체·재직·휴직·퇴직 + 건수)**으로 교체. 액션 버튼은 우측 그룹에 그대로 | 40 팀 상세 · ㄴ32 상태 셀 | 신설 (a5e31886, #1060) · 칩 원문·건수 표기 TBU(실사 대기) |
| 57 | 하위 팀 포함 (표시 필터) | Checkbox | • (10/7, #1055, MED-911) 「팀 관리」 모달의 소속별 「하위 팀 포함」 토글(team_members.includeSubTeams)로 팀 범위 권한의 하위 팀 펼침을 소속마다 정했으나 • (10/7, MED-945) 토글 제거 — 소속·팀장 지정 모두 하위 팀을 항상 포함(마이그레이션 1955 가 열을 전부 true 로 고정, 코드는 읽지 않음). 팀원 목록 상단의 「하위 팀 포함」 체크는 표시 필터(기본 꺼짐 = 직속 팀원만)일 뿐 권한과 무관 • 팀장 지정은 소속과 독립(조직 전체 검색, 팀원으로 추가하지 않음) + 지정 팀(+하위)에 팀장 권한 묶음(TEAM_LEADER_GRANTS) 자동 부여 | team_members.includeSubTeams(폐기) · Team.leaderId · [[HBAD220_역할 관리·권한 트리]] | 변경 (MED-945) · (10/12 머지, #1197) 표시 필터 「하위 팀 포함」 기본 켬 + 바꾼 값은 조직·사용자별 localStorage(hereby:admin:teamRoster:includeSubteams:…) 기억 — 팀을 옮겨도 유지(종전엔 팀 전환마다 꺼짐). 10/13 실측: 간호부 선택 시 체크 켬·하위 병동1 인원 합산 확인 |
| ㄴ50-1 | 허용 근무 유형 (팀 수정 모달) | Checklist | • (10/11 머지, #1154, MED-969) 팀 수정 모달 「대표 근무」(부제 "직원 등록 시 기본으로 선택돼요" — 10/13 실측) 아래 「허용 근무 유형」 섹션: 부제 "소속 직원이 배정 그룹 밖에서도 고를 수 있는 근무" + 「그룹 · 근무」 라벨 체크 목록(이미 켠 비활성 근무는 유지 표시) + 안내 "아무것도 켜지 않으면 직원은 배정된 근무 그룹의 근무만 고를 수 있어요. 급여 근로형태는 바뀌지 않아요."(원문 10/13 실측) • 저장: teams.allowedShiftIds(jsonb, 마이그레이션 1971, 같은 조직 근무만·중복 정리). 직원 개인 목록은 [[HBAD201_직원 추가·수정 모달]], 효과는 [[HBEA510_내 정보·근무 설정]] 선택 범위 | teams.allowedShiftIds | 신설 (#1154) · 10/13 라이브 실측 |
| 60 | 직원 카드 (이름 클릭) | Popover | • 구성원 표에서 이름 클릭 시 직원 카드 노출 — 병동 배정 줄 + 「스케줄러 보기」 + 「직원 정보 수정」 버튼 • 「스케줄러 보기」 클릭 시: 스케줄러 화면 전환 • 「직원 정보 수정」 클릭 시: 직원 수정 모달([[HBAD201_직원 추가·수정 모달]]) 오픈 | [[HBAD201_직원 추가·수정 모달]] · [[HBNS210]] | 신설 (코드 반영: #833 — 직원 카드 5곳 공통) · 라이브 실사 확인(2026-09-29) |
팀 추가·편집 모달 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 노출 조건 | - | • "팀 추가"(트리/그리드) 또는 팀 편집 아이콘 클릭 시 노출 | 추가/편집 공용 | |
| 10 | 상위 팀 | Dropdown | • 팀 계층 부모를 지정하는 항목. 원문 "상위 팀" • 선택 시: 부모 팀 확정. CASE01 [트리에서 팀 선택 중]: 해당 팀 default | teams.parentTeamId | |
| 20 | 팀명 * | Input | • 팀 이름을 지정하는 필수 항목. 원문 "팀명 *" • 입력 시: 값 없음이면 저장 불가. 중복 시 처리(정책상 안내 문구)는 프로브 미확인 | teams.name | 필수 · 에러 TBU |
| 30 | 설명 | Input | • 팀 설명을 기록하는 선택 항목. 원문 "설명" • 입력 시: 설명 기록 | teams.description (추정) | |
| 40 | 상태 | Dropdown | • 팀 활성/비활성 상태를 지정하는 항목, 기본 "활성" • 선택 시: 상태 확정. 값 없음: 기본 활성 | teams.isActive (추정) | 값 없음: 기본 활성 |
| 50 | 팀장 | Picker | • 팀 리더를 지정하는 항목(이름/사번 검색). 원문 "팀장" • (10/8, #1078, MED-946) 복수 지정: 고른 팀장이 검색 칸 위 칩 목록으로 쌓임 — 첫 칩 = 대표 팀장(파란 칩, 툴팁 "대표 팀장 · {이름} 빼기"), 나머지 회색 칩. 칩 클릭 시 그 사람 빠짐(대표가 빠지면 다음 사람이 대표) • 검색 칸 placeholder(원문): 칩 0개 "이름 / 사번 — 조직 전체에서 검색" / 1개 이상 "팀장 추가 — 이름 / 사번". 포커스 시 후보 목록(이름 + 사번, 이미 고른 사람 제외), 결과 없음 "검색 결과가 없습니다." • 도움말(원문): "여러 명을 지정할 수 있고 팀원이 아니어도 됩니다. 첫 사람이 대표 팀장(팀 단톡방 방장)이며, 팀장은 모두 이 팀과 하위 팀 전체의 근태·휴가·명부를 보고 결재합니다." • 저장 결과: team_leaders(팀·직원·순서)에 전원, teams.leaderId = 대표(단톡방 방장·옛 화면이 읽음). 공동 팀장도 같은 팀 범위 권한(지정 팀 + 하위)·팀장 권한 묶음·팀장 앱 「내 팀」·결재 알림 대상- 팀 단톡방: 방장 = 대표 1명, 공동 팀장은 멤버로 입장, 입장 요청 알림은 팀장 전원에게(팀장 본인 요청은 종전처럼 바로 입장) - 퇴사 처리: 지정 해제, 대표였으면 다음 팀장이 대표 승계 • 구 「미지정」 메뉴 항목은 없어짐 — 전원 해제 = 칩을 모두 빼고 저장 | team_leaders(마이그레이션 1956) · teams.leaderId · ㄴ40-6 · ㄴ57 | 변경 (b2a6cced, #1078) · 라이브 실사 확인(2026-10-08 낮, 간호부 팀 수정 모달): 라벨 "팀장"·칩 "서영주 (bestrhrn81)"(버튼 접근성 이름 "서영주 (bestrhrn81) 빼기")·placeholder "팀장 추가 — 이름 / 사번"·도움말 원문 일치·푸터 〔취소〕/〔수정〕(변경 없으면 비활성) · TBU: 대표/일반 칩 색 구분(칩 1개 조직이라 미확인)·단톡방 멤버·입장 요청 알림 |
| 51 | 모달 본문 스크롤 | Rule | • (10/8, #1087, MED-947) 팀장 칩·검색 칸·도움말이 늘어나 800px 높이 화면에서 「팀장」 칸과 검색 목록이 모달 밖(하단 [취소]/[수정] 아래, 팀원 표 위)으로 넘치던 결함 수정 — 본문 overflow-y-visible → overflow-y-auto(모달 높이 상한 90vh 유지), 검색 목록이 열릴 때 scrollIntoView 로 본문을 끌어 올림. 큰 화면(1080px 이상)은 이전과 같음 | 50 | 수정 (34e5e5e, #1087) · 라이브 열람(2026-10-08 낮): 기본 화면에서 본문 정상 노출·팀장 칩/검색 칸 모달 안에 표시 — 800px 좁은 화면 재현은 TBU |
| 60 | 멤버 추가 안내 | Guide | • 원문 "팀에 직원을 추가하려면 생성된 팀 페이지의 팀 멤버 추가 버튼을 이용하거나, 직원 관리 메뉴에서 추가하세요." | team_members | 7/10 확인 |
| 70 | 저장 | Button | • 입력값으로 팀을 생성/수정하는 확정 버튼 • 클릭 시: 즉시 실행 - CASE01 [성공]: 토스트 "팀을 추가했습니다" + 모달 닫힘 + 트리 갱신 - CASE02 [실패]: 실패 처리(토스트/무반응) 프로브 미확인 | teams | 성공 토스트 7/10 확인 · 실패 TBU |
| 80 | 취소 | Button | • 변경 없이 모달을 닫는 버튼. 원문 "취소" • 클릭 시: 모달 닫힘(미저장). 미저장 이탈 가드 유무 프로브 미확인 | TBU |
총괄 팀장 지정 모달 사양표
| 번호 | 항목/기능명 | 타입 | 사양 및 기능 설명 | 연관/영향 범위 | 비고 |
|---|---|---|---|---|---|
| 00 | 노출 조건 | - | • (10/8, #1078 12da8faf, MED-946) 워크스페이스 헤더 연필 버튼(ㄴ30-4) 클릭 시 노출 — 열기 전에 서버 값을 다시 읽어 폼 프리필(다른 관리자가 바꾼 값을 덮어쓰지 않게). 모달 제목 원문 "총괄 팀장 지정", 폭 520 | team.orgLeaders | 신설 · 라이브 실사 확인(2026-10-08): 제목 원문 일치 |
| 10 | 총괄 팀장 | Picker | • 라벨 "총괄 팀장". 팀 수정 모달 50 과 같은 칩 + 검색 구성이나 대표 개념 없음(칩 전부 회색, 툴팁 "{이름} 빼기", 클릭 시 빠짐) • placeholder(원문): 0명 "이름 / 사번 — 조직 전체에서 검색" / 1명 이상 "총괄 팀장 추가 — 이름 / 사번". 결과 없음 "검색 결과가 없습니다." • 도움말(원문): "총괄 팀장은 모든 팀의 팀장과 같습니다. 직책과 무관하게 조직 전체의 명부·근태·휴가·초과근무·외근·인센티브·스케줄·급여·문서·자격증·교육을 보고, 근태·휴가·초과근무·외근·인센티브를 결재합니다. 팀장 앱에서는 모든 팀을 관할합니다." | team_leaders(teamId NULL, 조직당 같은 사람 1행) | 신설 · 라이브 실사 확인(2026-10-08): 라벨 "총괄 팀장"·도움말 원문 일치 · TBU(실사 대기): 칩·검색 목록(미지정 조직이라 칩 미노출) |
| 20 | 본문 스크롤·검색 목록 | Rule | • (10/8, #1087) 본문 overflow-y-auto + 목록 scrollIntoView• (10/8, #1091) 본문이 검색 칸·안내뿐이라 absolute 목록이 약 1행만 보이던 결함 → 목록을 흐름 안에 배치해 본문이 목록 높이(최대 12rem)만큼 자람, 모달 max-h 를 넘으면 본문 스크롤 | 10 | 수정 (34e5e5e · 1acac4f) · TBU: 라이브 실사 이월 |
| 30 | 저장 | Button | • 원문 "저장". 저장 중이거나 변경 없음이면 비활성 • 클릭 시: team.setOrgLeaders- CASE01 [성공]: 모달 닫힘 + 토스트 "총괄 팀장을 저장했습니다" + 헤더 이름 갱신 - CASE02 [실패]: 오류 토스트(서버 메시지, 없으면 "총괄 팀장을 저장하지 못했습니다") — 퇴사자 지정 불가 등 | team:update.all | 신설 · 라이브 실사 확인(2026-10-08): 버튼 「저장」 존재 · TBU(실사 대기): 저장 동작·토스트(저장 미실행) |
| 40 | 취소 / 닫기 | Button | • "취소"·X·ESC — 변경이 있으면 공통 이탈 가드(closeGuard) 거쳐 닫힘 | 신설 · 라이브 실사 확인(2026-10-08): 「취소」 존재, ESC 로 닫힘 |
팀 계층 · 소속 관계
| 엔티티 | 역할 | 관계 |
|---|---|---|
teams | 팀 마스터 (팀명/상위 팀/설명/상태/팀장) | self-ref (parentTeamId), leader → employees (leaderId = 대표 팀장, #1078) · sortOrder(형제 노출 순서, NULL = 지정 안 함, #1088) |
team_leaders | 팀장 전원 (팀·직원·순서) — teamId NULL 행 = 총괄 팀장 (#1078, 마이그레이션 1956) | 팀 n : 직원 m · 읽기/쓰기 단일 통로 utils/team-leaders.ts |
team_members | 직원-팀 소속 (역할 포함) | n:m (employeeId × teamId × roleId) |
권한·상태 분기 요약
| 시나리오 | 트리거 | 결과 화면 | 비고 |
|---|---|---|---|
CASE01 [팀 트리 조회] | 화면 진입 | 조직 루트 노드 + 계층·인원수 트리 | 권한 "팀 조회" |
CASE02 [전체 구성원] | 루트 노드 선택 | 우측 전체 구성원 Grid | |
CASE03 [팀 상세] | 팀 노드 선택 | 우측 팀 상세 (멤버 테이블) | |
CASE04 [팀 추가] | 상위 팀·팀명*·팀장 입력 → 저장 | teams 생성, 토스트 "팀을 추가했습니다" | 권한 "팀 관리" |
CASE05 [팀 삭제] | 팀 삭제 아이콘 | 컨펌 "팀을 삭제하시겠어요?" → 삭제 | 하위/멤버 존재 시 차단(정책) |
CASE06 [멤버 추가] | "팀 멤버 추가" | team_members 생성 (n:m) | |
CASE07 [팀장 복수 지정] | 팀 수정 → 팀장 칩 추가 → 저장 | team_leaders 전원 + 대표 = 첫 칩, 헤더 「팀장 A, B」 | #1078 |
CASE08 [총괄 팀장 지정] | 워크스페이스 헤더 연필 → 모달 → 저장 | 토스트 "총괄 팀장을 저장했습니다", 헤더 「총괄 팀장 A, B」 | team:update.all · #1078 |
CASE09 [팀 순서 변경] | 트리 팀 행 드래그 → 형제 위/아래 놓기 | 즉시 반영 + team.reorder, 실패 시 되돌림·토스트 | team:update · 검색 중 불가 · #1088/#1091 |
트리 노드 인터랙션 규칙 (#680, v0.7.0 — CS-LOC-260914-0003 대응, 2026-09-15 라이브 실증)
- 팀명 첫 클릭 = 선택·이동만 (펼침 상태 불변) / 선택된 팀 재클릭 = 펼침 토글 / 화살표(▾) 아이콘 직접 클릭 = 이동 없이 펼침 토글만
- 선택 하이라이트와 펼침 상태는 독립 — 접힌 팀도 선택 가능, 선택 유지된 채 접기 가능
- (10/8, #1088·#1091) 형제 순서 = 저장 순서(
sortOrder) 우선 → 없으면 예전 규칙(병동 연결 팀 먼저·병동 코드순, 나머지 이름순). 팀 행 드래그로 변경 — 상세 ㄴ12-1
Open Question
- 팀 삭제 시 하위 팀·소속 구성원 실차단 UI/문구 (정책은 삭제 불가 규정) = TBU
- 팀 추가 저장 실패·팀명 중복 에러 동작 (라이브 프로브 없음) = TBU
- 트리 Empty·전체 구성원 Empty 원문 문구 = TBU
- 멤버 명단·전체 명단 다운로드 포맷(엑셀/CSV)·컬럼 셋 = TBU
- 내부 권한 토큰 실제 key (라벨 "팀 관리"/"팀 조회"만 확인) = TBU
- 노드 선택 시 조상 자동 펼침 여부 (UP-011 이관) = TBU
- 트리 키보드 접근(방향키·Enter) 지원 범위 (UP-011 이관) = TBU
방향 재검토 중 — 팀 관리 내 병동 표시(#711 반영분)→ 해소(2026-09-28): 팀↔병동 화면 분리가 #833/#912(v0.14.0)로 운영 반영. 조직도 병동 노드·「미연결 병동」·팀 멤버 추가 팝업 병동 모드 제거, 「병동 현황」은 기본 접힘 섹션으로 존치(행 50). 병동 관리 상세는 [[HBAD230_병동 관리]]- 병동 현황 섹션 Empty(병동 0곳) 문구 = TBU