Skip to content

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 (또는 시스템 관리자)
팀 삭제teamIdsdk.team.delete() (추정)team:write (추정)
멤버 배정employeeId · teamId · roleIdteam_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트리 EmptyState• 하위 팀 0건 시 루트 노드만 노출 (하위 목록 없음)TBU: 트리 Empty 문구
20팀 추가 (트리 버튼)Button• 트리 상단에서 새 팀을 생성하는 진입 버튼. 원문 "팀 추가"
• 클릭 시: "팀 추가" 모달 노출 (선택 노드가 상위 팀 default)
 - CASE01 [루트 선택 중]: 최상위 하위 팀 추가
 - CASE02 [팀 선택 중]: 해당 팀 하위 추가
teams.parentTeamId
25근무 설정 (진입 버튼)Button• 팀 관리 「전체 구성원」 필터 줄에서 「근무 설정」(유형·기준 관리) 팝업을 여는 진입 버튼. 줄 구성(실측): 전체 구성원 / 상태 선택 / 직무 선택 / 🔍 / [근무 설정] / [명단 다운로드] / [신규 직원 추가] / [팀 추가]
• 툴팁(원문): "근무 그룹·근무형태·직무 등 직원 설정을 관리합니다."
• 클릭 시: 「근무 설정」 탭이 선택된 상태로 유형·기준 관리 팝업 오픈(직원 관리·근태 현황과 같은 팝업). 좌측 탭 9종(원문): 근무 설정 / 직무 설정 / 근로형태 / 연장근무 유형 / 외근 유형 / 연차 부여 기준 / 휴가/연차 유형 / 연차 정책 / 공휴일
• 목적: 팀 대표 근무·직무 기본 근무를 팀 관리에서 이탈 없이 편집
[[HBAD260_근무 설정 (근무 그룹·유형)]] · [[HBAD200_직원 관리]]신설 (코드 반영: 07effb5, #806) · 라이브 실사 확인(2026-09-26 — 팝업 열람까지만)
30전체 구성원 (루트 선택)Grid• 루트 선택 시 우측에 조직 전체 구성원을 보여주는 그리드. 헤더 "전체 구성원" + "직원 추가" / "명단 다운로드" / "팀 추가". 컬럼: 사번 / 이름 / 이메일 / 팀 · 역할 / 상태 / 관리
• "명단 다운로드" 클릭 시: 즉시 실행(컨펌 없음), 성공: 파일 다운로드(화면 무변화)
team_members6컬럼 · 직원 추가 버튼 추가(코드 반영: 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으로 표기. 멀티 소속 시 다중 chipteam_members n:m
ㄴ32상태 셀Badge• 멤버 재직 상태 배지: CASE01 [재직] / CASE02 [비활성] / CASE03 [휴직] / CASE04 [퇴직]employees.statusTBU: 상태 값 목록
30-E전체 구성원 EmptyState• 구성원 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 stateState• 멤버 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_members7/10 확인
70저장Button• 입력값으로 팀을 생성/수정하는 확정 버튼
• 클릭 시: 즉시 실행
 - CASE01 [성공]: 토스트 "팀을 추가했습니다" + 모달 닫힘 + 트리 갱신
 - CASE02 [실패]: 실패 처리(토스트/무반응) 프로브 미확인
teams성공 토스트 7/10 확인 · 실패 TBU
80취소Button• 변경 없이 모달을 닫는 버튼. 원문 "취소"
• 클릭 시: 모달 닫힘(미저장). 미저장 이탈 가드 유무 프로브 미확인
TBU

총괄 팀장 지정 모달 사양표 ​

번호항목/기능명타입사양 및 기능 설명연관/영향 범위비고
00노출 조건-• (10/8, #1078 12da8faf, MED-946) 워크스페이스 헤더 연필 버튼(ㄴ30-4) 클릭 시 노출 — 열기 전에 서버 값을 다시 읽어 폼 프리필(다른 관리자가 바꾼 값을 덮어쓰지 않게). 모달 제목 원문 "총괄 팀장 지정", 폭 520team.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