변경 이력
운영 규칙
디자인 시스템(토큰 · 컴포넌트 · 패턴 문서)이 변경되면 같은 작업에서 이 페이지에 항목을 추가합니다. 문서만 고치고 이력을 비워두지 않습니다.
2026-10-21 — 스켈레톤 3차 적용 (P3 5곳) (design/admin-uiux-detail-improve)
적용
- 스켈레톤 admin 예약된 변경 · 직원 앱 도입 · 결재선(팀별) — 기존 링은 작게 남기고 그 아래 표 · 카드 · 단계 자리를 잡아요.
- 전자 서명 — 연동 상태 초깃값이 「미연동」이라 연동된 병원에도 「전자서명 연동이 필요합니다」가 먼저 떴어요. 상태를 받기 전에는 안내 대신 목록 머리 + 표 스켈레톤을 그리고, 목록을 받기 전엔 표 행 스켈레톤을 그려요.
- 직원 정보 수정 모달(공용
EditEmployeePanel) — 「편집」을 누르면 참조 데이터(팀 · 역할 · 근무 · 직무)를 다 받은 뒤에야 열려 반응이 없었어요. 누른 즉시 같은 크기의 모달 껍데기와 메뉴 · 입력칸 자리를 띄우고, 준비되면 실제 패널로 바뀌어요. 껍데기를 닫으면 열기가 취소돼요(폼은 그리지 않아 이전 직원 값이 비치지 않음).
규칙
- 스켈레톤 요소에
hidden md:block을 직접 붙이면display: block(레이어 밖)이 이겨 숨겨지지 않아요 — 반응형 숨김은 감싸는 요소에.
2026-10-21 — 스켈레톤 2차 적용 (P2 18곳) (design/admin-uiux-detail-improve)
적용
- 스켈레톤 admin 목록 화면 — 역할 관리(줄 카드) · 병동 관리(좌측 목록 · 요약 숫자 · 표) · 근태 현황 외근 / 근로시간 마감 / 정정 요청 · 설정 직무 / 근무 그룹 / 근로형태. 모두 로딩 플래그 없이 「등록된 … 없어요」를 먼저 그리던 곳이라, 목록별 「첫 응답이 왔다」 상태(
loadedOnce)를 새로 두고 빈 상태는 그 뒤에만 그려요. 설정이 다 된 병원에서 「등록된 직무가 없어요」가 잠깐 보이던 문제도 함께 없어졌어요. - admin 조직 설정 · 스케줄러 · 연차 잔여 상세 모달 — 기존 「불러오는 중」 · 링은 그대로 두고 그 아래 실제 모양(설정 카드 · 근무표 격자 · 표)의 자리를 잡아요.
- 직원 앱 근무 기록 · 팀 근태 · 공지 · 드라이브 · 알림 — 월 합계의 「0시간」 대신 숫자 자리, 링 아래 목록 줄 자리. 알림은 회색 셸이라
--on-sunken. - 결재선 패널(공용) — 「결재 단계를 불러오는 중이에요」 아래 단계 줄 3개.
변경
- 「내 정보」를 먼저 열어요(공용
MyInfoForm.openMyInfo) — 직원 정보를 다 받은 뒤에야 열려 누른 뒤 반응이 없었어요(급여명세서와 같은 문제). 이제 화면 · 모달을 먼저 열고 본문 자리를 스켈레톤으로 잡으며, 실패하면 닫고 안내해요. 직원 앱 2depth 와 웹 앱(hr-system · team-manager 등) 내 정보 모달에 같이 적용돼요.
2026-10-21 — 스켈레톤 신설 · P1 9곳 적용 (design/admin-uiux-detail-improve)
신규
- 스켈레톤
.ds-skeleton— 데이터가 오기 전에 표 · 목록 · 카드의 자리를 회색 면으로 미리 잡아, 들어갈 때 내용이 덜컹거리지 않게 해요. 기존 스피너 · 「불러오는 중…」을 대체하지 않고 함께 씁니다. 모양은 줄(기본 12) ·--title(18) ·--block(44) ·--circle(지름 변수) ·--box(체크 칸)와 표 행tr.ds-skeleton-row(칸 · 행마다 폭이 달라짐). 움직임은 페이드 한 가지(1.6초), 동작 줄이기 설정이면 멈춰요. 높이 · 모서리 · 지름은 변수(--ds-skeleton-h·-radius·-size)로만 바꿔요. - 색 토큰
--color-skeleton·-sunken·-elevated— 라이트는 neutral-75(사용자 지정), 회색 면 위는 neutral-100, 떠 있는 면은 75. 다크는 면보다 한 단계 밝게(차이 약 15): 카드 면 위 600 40% + 800(≈#343434), 회색 면 위 neutral-700, 떠 있는 면 위 600 50% + 700(≈#3b3b3b). 700 그대로면 카드 면과 7 차이라 거의 안 보였어요..ds-menu·.ds-modal· 데스크톱 채팅 창 안은 자동으로 elevated 색을 써요. 근거 표: 라이트 · 다크 테마 컴포넌트 표. - 로딩 스피너 문서의 「스켈레톤은 아직 DS에 없다」 두 곳을 이 페이지 링크로 바꿨어요.
적용 (P1 — 진입마다 겪는 큰 덜컹)
- admin 직원 관리 — 첫 응답 전 「직원 데이터가 없어요」 한 줄 대신 표 12행 스켈레톤, 통계 핀 숫자(전체 · 재직 · 팀 · 역할)는 다 센 뒤에 보여요(전엔 「0」이 먼저 보였음).
- admin 팀 관리 — 팀 트리 8줄 · 구성원 표 10행(조직 전체 · 팀 두 표). 명단 요청이 실패해도 스켈레톤이 남지 않게 「한 번은 답이 왔다」 상태를 따로 둬요.
- admin 근태 현황 › 연차 — 표 10행 · 요약 숫자 3개. 「데이터가 없어요」는 로딩이 끝난 뒤에만.
- 직원 카드 팝오버(admin · team-manager · 직원 앱 공용) — 링 + 「불러오는 중…」은 그대로 두고 아래 소속 팀 · 병동 배정 자리를 잡아요. 카드가 한 줄 높이로 떴다가 커지던 덜컹이 없어요.
- 직원 앱 홈 — 「지금 할 일」 카드가 둘째 자리에 끼어들며 아래 카드를 밀던 문제. 지난번 홈에 할 일이 있던 계정만 그 자리를 스켈레톤으로 잡아요(없는 사람에게 그리면 떴다 사라지는 새 덜컹이 생김).
- 직원 앱 결재 — 연차현황 카드(회색 면,
--on-sunken) 자리를 먼저 잡아 아래 신청 메뉴가 밀리지 않아요. 「내 신청 · 결재 현황」은 첫 응답 전 「검토 중인 신청이 없어요」 대신 묶음 스켈레톤. - 메신저 대화 목록(직원 앱 · 채팅 위젯 공용) — 로딩 표시 없이 흰 면이던 자리에 대화 줄 8개.
- 직원 앱 급여명세서 — 목록을 다 받은 뒤에야 화면이 열려 누른 뒤 반응이 없었어요. 화면을 먼저 열고 목록 자리를 스켈레톤으로 잡으며, 실패하면 닫고 안내해요(메뉴는 아직 「준비 중」이라 열리면 적용).
2026-10-21 — 임베드 모달 채움 옵션 data-embed-fill (design/admin-uiux-detail-improve)
신규
- 모달 임베드 채움
data-embed-fill— admin iframe 안 모달은 화면 전체 가운데에 서려고 헤더 높이만큼 키가 깎여(화면 760 에서 428px), 문서 결재 미리보기처럼 긴 내용이 좁은 칸에서 스크롤됐어요. 카드에data-embed-fill을 달면 가운데 대신 iframe 세로를 위아래 24px 씩 남기고 채워요(같은 화면 550px, 화면 90vh 상한 안 — 처음엔 4px 였는데 화면 바닥에 붙어 보여 24 로).computeFillMaxHeight단위 테스트 3건. - 문서 결재 미리보기 높이를 늘 최대로 — 내용 길이와 상관없이
h-[90vh](standalone) · 채움 높이(admin 임베드)로 고정했어요(사용자 요청). 제목 아래 정보행(신청자 · 구분 · 문서 · 신청일 · 상태)은 왼쪽 「문서 정보」 카드로 옮기고, 본문은 왼쪽 정보(320) · 오른쪽 문서 뷰어로 나눠 뷰어가 본문 세로를 다 쓰고, 폭은 768 → 1000(상세 모달 가이드 예시 폭)으로 넓혔어요. 제목 「미리보기」도 비노출해 헤더 줄을 없앴어요(이름은aria-label로만, 사용자 요청).
수정
- 문서 결재 미리보기를 열면 뒤 목록이 틀어지던 문제 — 증명서 HTML(인쇄용 문서)을
x-html로 페이지에 붙여, 그 안<style>의body { padding: 40px }·th { width: 25% }·td { width: 75% }가 dim 아래 목록 표 칸 폭과 화면 여백까지 바꿨어요(칸 폭 165·143·214… → 588·208·88…). 미리보기를 격리된<iframe srcdoc sandbox>로 바꿔 스타일이 새지 않아요.
2026-10-21 — 바 노티스 버튼 색은 띠 색을 따라감 (design/admin-uiux-detail-improve)
변경
- 바 노티스 주 동작 버튼 색 primary(주황) → purple — 띠 안의 버튼은
ds-btn--purple(테두리ds-btn--line· 채움ds-btn--solid)을 쓰고ds-btn--primary는 쓰지 않아요(사용자 결정). 새 CSS 없이 기존 버튼 색 변형을 씁니다. 보조 버튼(line dark) · 닫기(X,icon muted)는 그대로예요. - 주 동작 버튼 색이 띠 색을 따라가요 — info 보라 · warning 노랑 · success 초록 · danger 빨강(테두리 · 채움, 사용자 결정). Playground 에서 색을 바꾸면 버튼 색도 함께 바뀌고, 모아보기 갤러리 설명의 「info 와 warning 은 색이 같다」(10-13 이후 틀린 문구)도 고쳤어요.
- 적용 화면 — admin 대시보드 「직원 앱 도입」 배너 〔이어서 하기〕(line primary → line purple), 직원 앱 「불편·기능 신고」 띠 〔불편·기능 신고〕(solid primary → solid purple). 문서 Playground · 마크업 예시 · 테마 화면 데모의 같은 배너도 맞췄어요.
2026-10-20 — 입력칸 · 라인 버튼 테두리를 연하게 (라이트 #e5e5e5 · 다크 #5e5e5e) (design/admin-uiux-detail-improve)
변경
- 폼 컨트롤 입력칸 · 셀렉트 기본 테두리(라이트)
--ds-textfield-border→line-normal(#e5e5e5) — 라이트 · 다크 테마 D6 에서line-field(neutral-450 #707070)로 올린 뒤 입력칸이 너무 진하게 읽혔고, hover 테두리(#c1c1c1)보다 기본이 더 진한 역전도 생겼어요(사용자 결정). 다크는 아래 항목처럼 한 단계 내렸어요. - 버튼 라인 normal(
ds-btn--line ds-btn--normal) 테두리(라이트)--color-action-outline-border→line-normal(#e5e5e5) — 같은 D6 변경으로 #707070 이 되어 「이전 월 가져오기」 · 「직원 추가」 같은 기본 라인 버튼이 진해졌어요(사용자 결정). muted · assistive 등 다른 라인 버튼은 원래 바뀌지 않았어요. - 다크
--color-line-fieldneutral-450(#707070) → neutral-500(#5e5e5e) — 다크 입력칸 · 셀렉트 · 라인 버튼(normal) 테두리가 너무 밝게 읽혔어요(사용자 결정). 카드 면 위 대비는 3.10 → 2.36 으로, D6 의 「경계 3:1」 기준은 이 컨트롤들에서 내려놓았어요. 카드 · 구분선(line-normal)은 그대로예요.
2026-10-20 — 상태 틴트 · 문서 사이트 다크 (design/color-theme)
변경
- 문서 사이트의 다크 모드가 DS 테마를 따릅니다 — 오른쪽 위 VitePress 라이트/다크 토글이 이제
<html data-theme>를 함께 바꿔 본문 · 표 · 데모가 DS 다크 값으로 그려져요(전엔 메뉴 · 사이드바만 어두워지고 본문은 흰색). 첫 페인트 전 값은config.mtshead 스크립트가, 이후 전환은 레이아웃의watch(isDark)가 답니다. - Playground 미리보기 테마는 사이트 테마의 「같게 · 반대로」 — 저장하는 값이 라이트/다크가 아니라 사이트와의 관계라서, 사이트를 다크로 바꾸면 라이트로 보던 미리보기는 다크로, 다크로 보던 미리보기는 라이트로 뒤집혀요. 늘 「사이트 테마」와 「반대 테마」 두 케이스를 오가며 비교합니다. 툴바 · 속성 패널은 사이트 테마를 따라요.
- 다크 페이지 안의 라이트 프레임 — docs 브리지(
ds-token-bridge.css)가[data-theme="dark"]블록이 바꾸는 토큰 155개를 라이트 값으로 되돌리는[data-theme="light"]블록을 생성해요(문서 전용, 앱에는 없음). Playground 「라이트」 · 나란히 비교의 라이트 쪽 · 토큰 표의 라이트 열이 이걸 씁니다. 근무표(Table 2) 데모는 관리자 앱 마크업 그대로라 라이트로 고정해요. - 문서 데모의 사이트 고정 색 정리 — 아이콘 갤러리 · 브랜드 · 브레이크포인트 · 데이터 표 · 모달 푸터 갤러리 · 간격/투명도 표의 팔레트 면 · 글자(
#666포함)를 라이트 값이 같은 시멘틱 토큰으로, 앱 헤더 · 하단 내비 · 모바일 대화 · 모바일 입력 데모의 VitePress 색(--vp-c-*, 사이트 테마를 따라 미리보기와 어긋남)을 DS 토큰으로 바꿨어요. 앱 헤더 · 하단 내비 · 메신저 문서의 코드 예시도 현재 값(bg-container)으로 맞췄어요. - 관리자 앱이 직원 앱의 테마 선택을 따라가지 않아요 — 운영에서 두 앱은 같은 출처라 localStorage 를 함께 써서, Works 에서 다크를 고른 브라우저로 관리자 앱을 열면 전환 기능도 없이 다크로 떴어요. 관리자 앱은 이제 QA 전용 키
hereby.theme.admin-qa만 읽어요(ADMIN_THEME_QA_STORAGE_KEY, 단위 테스트 3건). - 하단 내비 분리형 캡슐이 다크에서 화면과 구분돼요 — 캡슐 유리 면이 다크 화면 바탕(neutral-800)과 같아 경계가 사라졌어요. 다크에서만 캡슐을 neutral-900 으로 가라앉히고 흰 잉크 10% 테두리를 두며, 선택 유리는 neutral-700 으로 밝혔어요(
--ds-bottom-nav-capsule-bg·-edge·-highlight·-solid·--ds-bottom-nav-glow-bg신설, 라이트 값은 기존과 같음). 문서 데모의 그라데이션 끝 색도 프레임 바탕(bg-alternative)과 맞췄어요(고정hr-gray-50이라 라이트에선 회색 띠, 다크에선 밝은 회색으로 번졌음). - 직원 앱에 남은 고정 상태 면 7곳이 테마를 따라요 — 메신저 연결 상태 띠(연결 중 · 끊김), 단톡방 방장 나가기 경고 원, 「나가기」 hover, 공지 목록 중요도 타일(긴급 · 보통), 필수(부서) 대화방 썸네일, 오늘의 축하 「입사 기념일」 아이콘 타일, 조기 퇴근 확인 시트 원, 출퇴근 정정 요청 완료 원. 연한 팔레트 50단계 면이라 다크에서 파스텔 면으로 튀었어요. 상태색 쌍(
status-*-bg·-fg·-icon)과 새 토큰--color-secondary-purple-bg(라이트 purple-50, 다크 보라 16%)로 바꿨고 라이트 값은 같아요(보통 공지 타일 아이콘만 yellow-600 → 500). - 흰 라벨이 다크에서 흰 면으로 튀지 않아요 — 칩 면을
--ds-label-white-bg로 분리해 다크에서는bg-elevated(neutral-700). 공지 상세 「일반」 칩 등. 라이트 같음. - 검정 라벨이 다크에서 읽혀요 — 칩 면이
--ds-label-black(= label-normal)이라 다크에서 밝아져 흰 글자와 겹쳐 글자가 사라졌어요. 다크에서만 짙은 채움 + 흰 글자 + 가는 경계(--ds-label-black-bg·-fg신설, 라이트 같음). - 문서 데모의 고정 흰색 정리(2차) — 툴팁 데모의 행 · 버튼 · 입력칸, 날짜/시간 데모의 드롭다운, 월 선택 피커의 트리거 · 월 칸(
--color-label-white고정), 그림자 · 모서리 페이지의 예시 상자가#fff·#f5f5f5고정이라 다크 사이트에서 흰 섬으로 남거나 글자가 사라졌어요. 라이트 값이 같은 시멘틱 토큰으로 바꿨어요. 라이트로 고정한 근무표 데모 설명 속 인라인 코드도 프레임 토큰으로 되돌렸어요(사이트 다크의 코드 색이 비쳐 흐렸음). - 공지 상세 「확인 완료」가 다크에서 차분한 초록 틴트 —
bg-green-50 text-green-600고정이라 다크에서 밝은 연두 면으로 튀었어요. 상태색 성공 쌍(bg-status-success-bg·text-status-success·-icon)으로 바꿨고 라이트 값은 같아요. - 토큰 표에서 투명 값이 검정으로 보이던 것 — 라이트 · 다크 테마 → 토큰 표가 완전 투명(
transparent)을 hex 로 바꾸며#000000으로 적었어요(라이트--color-action-strong-border등). 이제 「transparent」로 적어요. - 문서 사이트 상단 메뉴가 좁은 창에서 가로로 스크롤돼요 — 창을 줄이면 「핵심 기능들 … 사양서」 메뉴가 오른쪽 밖으로 잘려 보이지 않았어요(VitePress 는 768 미만에서만 햄버거로 접음). 메뉴 줄만 가로 스크롤(트랙패드 · 마우스 휠 · 얇은 스크롤바)하고, 페이지를 열면 지금 섹션 메뉴가 보이는 곳으로 옮겨져요(
nav-scroll.css·nav-scroll.ts). - 상태 틴트가 다크에서 차분해집니다 —
--color-status-{success,warning,error,info}-bg다크 값을 900 에서 상태색 500 을 표면에 16% 섞은 색으로,-border를 700 에서 40% 섞은 색으로 바꿨어요. 파랑 · 보라 배지 틴트(--ds-secondary-blue/purple-bg)도 같아요. 출근 완료 안내(초록) · 상태 배지(외근 · 연장 · 반려 · 휴가) · 바 notice 가 진한 덩어리로 튀던 문제예요. 글자(200) · 아이콘(400)은 그대로이고 라이트는 바뀌지 않아요. - 직원 앱 강조 글자 · 근무 기록 숫자 · 메신저 하단 그라데이션 — 「지금 할 일」의 「결재」 · 「작성」 · 「반려」, 근무 기록 「연장」 · 「외근」 숫자를 팔레트에서
text-secondary-purple·text-label-danger·text-secondary-blue로, 메신저 탭 하단 내비 그라데이션 끝 색을 고정 흰색에서--color-bg-container로 바꿨어요.
문서
- DS 문서 누락분 전수 점검(10-20) — 브랜치에서 바뀐 토큰 89개 신설 · 158개 변경과 색이 바뀐 정본 셀렉터 243개(컴포넌트 66)를 문서와 대조했어요. 색상에
Action·Static표와 bg/label/line 새 토큰 · 상태 쌍 16행 ·--ds-*다크 열 · 테마 작업으로 생긴--ds-*표를, 토큰 표 Playground에 행 24개를, 컴포넌트별 다크 값에 10행을 더하고, notice · 바 notice · 하단 내비 · 대화 UI · AI 어시스턴트 · 검색 입력 · 페이지네이션 · 모달 · 툴팁 · 데이터 테이블 · 모바일 대화(정본 CSS 변경분)와 로그인 · 가입 · 비밀번호 찾기/변경 폼 · 메신저 공용 · 내 정보 폼 · 직원 추가/수정 패널 · 권한 모달 · 스피너 · 결재선 · 근무표 · 게이트 화면 · 페이지 인터랙션(공용 파셜 · 앱 CSS 변경분) 페이지의 「규칙 (강제)」에 다크 동작을 적었어요. 남은 이관 보류:my-info-form.html25곳(테마 옵트인 앱이 안 씀 — team-manager 의.sched-grid복사본은 10-20 스케줄러 통합으로 제거). 구동 확인: DS 문서 58페이지 죽은 앵커 0 · 스크립트 오류 0 · Playground 32개 다크 전환 정상. Playground 가 없어 다크 미리보기가 안 되는 페이지(데이터 테이블 · 페이지네이션 · 검색 입력 · 모바일 대화)는 규칙에 확인 경로를 적었어요. - 테마 전환 기능은 hereby Works(직원 앱)만 제공 — 관리자 앱은 다크 스타일은 대응하되 사용자에게 전환 기능을 주지 않고, 다른 앱도 만들지 않아요(2026-10-19 결정). 관리자 앱 기본은 늘 라이트이고, 다크는 개발 · QA 때 localStorage
hereby.theme.admin-qa=dark로 확인해요. 테마 켜기.
2026-10-19 — 직원 앱 다크 모드 전 화면 적용 (design/color-theme)
신규
- 서브 탭
isActive옵션 — 여러 개를 고르는 칩 묶음도 같은 컴포넌트로 그려요. 직원 앱 「주말 당직 세션 신청」의 당직 인원이 손으로 만든 칩(모서리 12) 대신 사유 칩과 같은 서브 탭(테두리형 · 고르면 주황)을 써요. - Playground 「미리보기 테마」(라이트 · 다크) — 모든 컴포넌트 페이지의 Playground 툴바에서 다크를 고르면 그 페이지의 미리보기 · 모아보기가 다크로 바뀌어요(미리보기 영역에만
data-theme="dark", 고른 값은 기억). 컴포넌트 페이지 31곳 · Playground 136개를 다크로 찍어 확인했어요. 라이트 · 다크 테마 참고. - 정적 흰 잉크 토큰
--ds-ink-white-04/08/10/18/30/55/60/70— 늘 어두운 면 위의 흰 글자 · 선 · 틴트. LNB 사이드바 · 워크스페이스 전환 ·ds-label--gray-dark/--light-gray-dark가--ds-glass-*를 쓰고 있어 다크에서 메뉴 글자가 사라지던 문제를 고쳤어요(라이트 값 같음). - 브랜드 틴트 면 토큰
--color-bg-brand-tint·--color-bg-brand-tint-soft— 사람 이니셜 · 아이콘 썸네일 · 강조 칸의 연한 주황 면. 라이트는 orange-100 · orange-50 그대로이고, 다크는 주황 500 을 표면(neutral-800)에 22% · 14% 섞은 불투명 색이에요. 선택 상태 면(primary-bg, 다크 orange-900)과 나눈 이유는 썸네일이 그 진한 적갈색을 따르면 어두운 화면에서 가장 무거운 점이 되기 때문이에요(다크 틴트 900 규칙의 예외). 글자는--color-label-brand. 앱 헤더 아바타(.ds-app-header__avatar)가 이 토큰을 읽어요.
변경
- 정본 컴포넌트 면이 테마를 따릅니다 —
.ds-list-card·.ds-tab-nav__arrow·.ds-tab-nav-row__actions·.ds-member-chip·.ds-member-seg--team·.ds-lnb__toggle·.ds-page-header(+__team-select·__back·__refresh) ·.ds-filter-bar__nav·.ds-filter-search__toggle의 고정 흰색(--ds-bw-white)을--color-bg-container, 떠 있는.ds-lnb__flyout·.ws-dropdown은--color-bg-elevated로(라이트 #fff 같음). - 문서 데모도 테마를 따릅니다 — 데모 전용 CSS · 데모 마크업의 팔레트 면 · 글자 · 선을 쓰임새대로 시멘틱 토큰으로 옮기고,
ds-tailwind-shim.css에 시멘틱 유틸(bg-bg-hover·-selected·-sunken·-brand-tint·text-label-body·-brand·border-line-alternative·-strong등)을 더했어요. 테마 해설용 팔레트 견본(DemoTheme*)은 그대로예요. - 앱 헤더 뒤로(<) 버튼 색이
--color-label-normal— 팔레트hr-gray-800이라 다크의 유리 원 안에서 보이지 않았어요. 라이트는 #1f2937 → #1b1b1b 로 눈으로 구분되지 않아요. - 직원 앱 전 화면이 테마를 따릅니다 — 결재 · 신청서 5종 · 보고서 · 내 정보 · 공지 · 드라이브 · 근무 기록 · 팀 근태 · 알림 설정 · 앱 정보 · 메신저(목록 · 연락처 · 대화방 · 공지 상세) · 로그인과, 직원 앱이 불러오는 공용 파셜(
messenger-content·security-settings-body·ai-assistant-conversation·notification-bell·ds-dialog·cs-report·loading· 로그인 폼 4종)의 팔레트 면 · 글자 · 선을 이관 매핑대로 시멘틱으로 바꿨어요. 로그인 전 화면도 기기에 저장된 테마를 따르고, 관리자 앱 로그인 바깥 카드도 같이 맞췄어요. 라이트는 같은 값의 토큰(neutral 계열은 완전히 같고,hr-gray는 푸른 기가 빠지는 정도)이에요. 다크 · 라이트 41화면을 찍어 대비를 계산해 확인했어요. - D6 재결정 —
--color-label-muted다크 값 500 → 400 — 보조 문구 · 비활성 탭 · 서브 탭 숫자 · 텍스트 버튼 · 입력 도움말 · 앱 헤더 날짜가 다크에서 2.36 으로 읽히지 않았어요(→ 4.7). 라이트는 그대로예요. 그래서 직원 앱 · 공용 파셜 · 문서 데모의hr-gray/neutral400 글자도label-muted로 옮겼어요. 300 단계(label-disable, 다크 600)는 원래 클래스로 둡니다. - 다크 값을 DS 문서 전체에 반영 — 라이트 · 다크 테마에 「다크 값」(점검에서 바뀐 토큰 · 신설 토큰) · 「컴포넌트별 다크 값」 표와 규칙 2줄(자리별 전용 토큰 · 간격은 gap)을 추가했어요. 색상 시멘틱 표 전부에 「다크」 열(정본 CSS 에서 읽은 값)과 새 토큰 3종(
bg-brand-tint·-soft·line-section)을 넣고,bg-elevated라이트 값(#ffffff) ·label-muted의미(보조 글자)를 바로잡았어요. 앱 헤더 · 탭 바 · 배지 · 버튼 · 폼 컨트롤 · 필터 바 · LNB · 워크스페이스 전환 · 페이지 헤더 · 서브 탭 페이지의 「규칙 (강제)」에 다크 동작을 한 줄씩 적었고, 토큰 표에 정적 흰 잉크 행을, 설계 문서에 §13 「다크 점검 반영」을 더했어요. - 관리자 앱 다크 이관 — 화면 HTML 100개 · 앱
main.css· 관리자 앱이 불러오는 공용 파셜(직원 추가/수정 패널 · LNB · 페이지 헤더 · 결재선 · 직원 카드 · 날짜/시간 피커 등)의 팔레트 면 · 글자 · 선과 인라인style색을 같은 매핑으로 시멘틱으로 옮겼어요. 클래스를 선택자로 쓰던main.css규칙 5곳(.bg-white.border-b select등)도 새 이름으로 맞췄어요. 18개 탭 + 직원 추가 패널을 찍어 라이트는 픽셀 비교로 같음을, 다크는 대비 부족 글자 483 → 43 · 밝게 남은 면 184 → 12(남은 것은 상태 알약 · 배지의 상태색)를 확인했어요. .ds-filter-bar__title글자label-alternative· 라인 위험 버튼(ds-btn--line.ds-btn--danger) 글자--color-secondary-red— 팔레트 neutral-600 · 채움용 action-danger 라 다크에서 묻혔어요(라이트 값 같음).- 비활성 글자 · 비활성 버튼 글자가 다크에서 읽힙니다 —
--color-label-disable다크 값 neutral-600 → 450(container 위 1.73 → 3.1, 보조 400 보다 한 단계 옅어 위계 유지),--color-action-disabled-fg500 → 450(비활성 버튼 바탕 700 위 2.0 → 2.8). 회색 배지 틴트(--ds-tint-light-*)도 따라 조금 밝아져요. 라이트는 그대로예요. 직원 앱 · 관리자 앱 · 공용 파셜 · 문서 데모의hr-gray/neutral300 글자도label-disable로 옮겼어요. - 구획 띠 토큰
--color-line-section신설 — 목록 묶음 사이 화면 끝까지의 두꺼운 틈(border-t-8). 라이트는 neutral-100 그대로, 다크는 neutral-900 으로 카드보다 가라앉아요.line-normal을 쓰던 직원 앱 결재 탭 · 나의 결재선의 띠 8곳이 다크에서 밝은 회색으로 떠 보이던 문제예요. - 입력칸 hover 테두리(다크)
--ds-textfield-border-hover→line-alternative—line-strong(300) 이라 흰선에 가까웠어요(모바일은 탭 뒤 hover 가 남아 실제로 보임). 설계 문서의 다크 매핑대로예요. 라이트는 그대로예요. - 탭 바 비활성 글자 · 회색 배지 글자(다크) —
--ds-tab-inactive-fg다크 500 →label-disable(450, 2.36 → 3.1),--ds-label-fg-assistive다크 →label-alternative(회색 배지ds-label--gray가 틴트 위 2.4 였음). 라이트는 그대로예요. - 선택 상태 · 연한 주요 버튼이 다크에서 차분해집니다 —
--color-primary-bg(선택된 옵션 면) 다크 값 orange-900 →bg-brand-tint-soft(주황 14%),--color-action-primary-soft(보기 · 작성 · 단체 채팅 · AI 추천 버튼) orange-900 →bg-brand-tint(주황 22%, 글자 orange-300 대비 6.6). 선택은 테두리(primary) · 체크가 알려요. 라이트는 그대로예요.
2026-10-13 — 라이트 · 다크 테마와 표면 맥락 (design/color-theme)
신규
- 라이트 · 다크 테마와 표면 맥락 페이지 — 사례 6 · 버튼 × 표면 맥락 × 상태 × 테마 매트릭스 · 대표 화면 4종 · 토큰 표 · 마이그레이션을 라이트/다크 나란히 보여 줍니다. 대비 수치는 추정이 아니라 페이지가 렌더한 색을 읽어 계산하고(반투명·오버레이·유리는 뒤 면까지 합성), 스크린샷 픽셀과 대조해 최대 채널 차 1 로 검증했습니다.
- 테마 장치 —
design-system.css「테마 — 다크」 블록([data-theme="dark"], 시멘틱 값만 바꾸고 팔레트는 불변)과@hereby/components의applyThemePreference/readStoredThemePreference/persistThemePreference/onThemeChange(이벤트hereby:theme-change). 옵트인이라 앱main.ts가 첫 페인트 전에 부르기 전엔 어떤 화면도 어두워지지 않습니다. admin · 직원 앱은 부팅 적용을 넣었고, 직원 앱 「더보기 → 화면 설정」에 「화면 테마」(라이트 · 다크 · 시스템 설정 따르기) 선택이 생겼습니다(직원 앱 화면은hr-*유틸이 남아 부분 적용). - 표면 맥락 클래스
.ds-surface--card·--brand·--inverse— 컨테이너에 달면 면을 칠하고 안쪽 시멘틱 토큰(--color-action-*·label·line)을 재정의합니다. 카드 위에서 사라지던 흰 3차 버튼(사례 ①), 주황 띠 위 주황 버튼(사례 ②)을 화면별 색 지정 없이 풉니다. - 시멘틱 토큰 신설 —
--color-action-*(primary · primary-soft · strong · muted · assistive · tertiary · outline · danger · danger-soft · disabled · overlay, 각각-fg/-border짝), 상태 쌍--color-status-{k}-bg/-fg/-border/-icon,--color-bg-elevated/-inverse/-glass/-hover/-selected/-sunken,--color-label-body/-danger/-inverse,--color-line-strong/-inverse,--color-focus-ring,--color-static-white/-black,--color-primary-fg. - 버튼 역할 클래스
ds-btn--strong(= dark) ·--tertiary(= white-bk) ·--primary-soft(= lightor) ·--danger(= red) ·--danger-soft(= lightred). 외형 이름은 같은 규칙을 공유하는 별칭으로 남아 수정 없이 테마를 탑니다. - 대안 비교 탭 — 보류한 결정(D7 다크 경계용 neutral 단계 · D6 라이트 대비 미달 7항목 · D5 notice info 파랑)의 후보를 현재안과 나란히, 라이트/다크 모두 실측 대비와 함께 보여 줍니다. 후보는 미리보기 안에서만 토큰을 덮어쓴 것이라 정본은 그대로이고, 고르면 「코드」 탭의 선언을 옮기면 됩니다.
- 토큰 표 다크 매핑 표시 — 토큰마다 라이트 팔레트 단계 → 다크 단계와 그 성격(1:1 · 합침 · 역할별 · 불변)을 적고, 「다크 1:1 매핑만 보기」 필터와 팔레트 단계별 매핑 표(전체 토큰)를 두었습니다.
변경
- 색상 시멘틱 블록이
@theme inline→@theme static— 유틸리티가var(--color-label-normal)을 참조해 런타임 변수 교체가 통합니다.tokens.css의 팔레트·시멘틱 113개 중복 재선언(「KEEP IN SYNC」)은 삭제했습니다. docs 브리지 ·tokens.ts· Figma 토큰 생성기가 새 블록을 읽도록 고쳤고,tokens.ts의dsHex는 별칭 + 팔레트 + 시멘틱(라이트 값)으로 넓어졌습니다(기존 키·값 전부 유지). - 정본 안 하드코딩 색 제거 — 입력칸
#fff·.ds-selecthover#c1c1c1· 스위치 손잡이#ffffff· 하단 내비white· 배지white·.ds-label회색rgb(193 193 193/…)· 포커스 링…, white)· 미니 모달#ffffff· 레거시--ds-*literal 50여 개 → 전부 토큰(값 동일). 셸 컴포넌트(탭 바 · 서브 탭 · 페이지 헤더 · LNB 메뉴 · 페이지네이션 · 체크박스/라디오 · 소속 칩 · AI 사이드바 · 날짜 피커)의 팔레트 직접 참조 130곳도 시멘틱으로. 라이트는 바뀌지 않았습니다 — 전환 전후 Playwright 16장(관리자 5 · 직원 앱 3 · docs 8) 픽셀 비교 0 차이. .ds-modal카드 면을 CSS 가 칠합니다(--color-bg-elevated, 라이트#ffffff) — 마크업의bg-white177곳은 무해해졌고 지워도 됩니다.--color-bg-elevated라이트 값은#fdfdfd→#ffffff(쓰는 곳 없음, 결정 D4).- 색상 「고르는 순서」가 시멘틱 1순위 — 원시 Tailwind 팔레트 유틸은 글자·면·경계에 쓰지 않습니다(테마를 모름).
- 바 notice
--info가 info 쌍 토큰을 읽습니다 — 값은 아직 warning 과 같은 노랑이라 화면은 그대로이고, D5 로 info 쌍을 바꾸면 notice 와 바 notice 가 함께 따라옵니다.
결정 반영(같은 날)
- notice · 바 notice
--info가 파랑 —--color-status-info-bg/-fg/-border/-icon= blue-50/700/200/500(다크 900/200/700/300). 라이트 시각 변화(info 189곳): warning(노랑)과 색으로 구분됩니다. 실측 8.04(라이트) · 9.16(다크). - 팔레트
neutral-450#707070추가 — 다크의line-normal(카드 · 구분선 · strong 경계)과 양 테마의 새 토큰--color-line-field(입력칸 · 셀렉트 테두리 · 라인 버튼 경계)가 이 단계를 읽어 경계 3:1 이상(라이트 4.99 · 다크 3.10). 라이트 시각 변화: 입력칸·라인 버튼 테두리가 neutral-100 에서 진해졌습니다. 카드·구분선은 그대로. - orange 주요 버튼과 짙은 색 버튼은 다크에서도 흰 글자·아이콘 —
action-primary다크 = orange-500 + 흰 글자(브랜드 동일, 3.18 양 테마),action-strong다크 = neutral-900 + 흰 글자 + neutral-450 경계,action-danger다크 = red-600 + 흰 글자. 의미색 솔리드 버튼(green · blue · purple · aquablue · yellow)은 새--color-action-{hue}+-fg를 읽어 테마 불변(라인·아이콘 의미색은--color-secondary-*로 다크에서 밝아짐). - 아이콘 버튼 muted 잉크
--color-action-icon-muted— label-muted(400)가 아이콘으로는 너무 옅어 500(다크 400)으로. 라이트 시각 변화: 알림벨 · 새로고침 같은 muted 아이콘 버튼이 진해졌습니다. label-muted 자체(플레이스홀더)는 그대로. - 상태 잉크(600/400/600) · notice 글자(700) · 연한 주요(orange-600 글자)는 현재 유지로 결정 — 대안과 실측은 「대안 비교」 탭에 기록.
- 모바일(hereby Works) 테마 적용 — 정본의 앱 헤더 · 하단 내비 · 채팅 입력줄 · FAB · 신고 버튼이 정적 흰색 대신
bg-container·bg-elevated·bg-glass토큰을 읽고(라이트 동일), 앱 헤더 제목(hr-gray-900)과 날짜 줄(hr-gray-400)이label-normal·label-muted가 됐습니다. 직원 앱은 셸 CSS(헤더·하단 내비 면 · 시트 · 풀레이어 푸터)와 근무(홈) · 더보기 · 화면 설정 뷰의hr-gray유틸 216곳을 토큰으로 이관해 「화면 설정 → 화면 테마 → 다크」가 그 화면들에서 실제로 적용됩니다(hr-gray 는 푸른 기가 있어 라이트가 미세하게 바뀜). 새 토큰--color-label-brand(orange-600 · 다크 300) 는 강조 숫자 · 인사말용. docs 「대표 화면」에 모바일 화면(앱 헤더 · 홈 카드 · 하단 내비)이 추가됐습니다. 결재 · 모달류 화면은 이관 대상으로 남아 있습니다.
2026-10-12 — 앱 헤더 글자 버튼 · 직원 앱 「새로운 공지」 (design/employee-ui-detail-check)
신규
- 앱 헤더 글자 버튼
.ds-app-header__text-action—getActions항목에text를 주면 아이콘 대신 그 글자를 오른쪽 유리 캡슐 안에 캡슐과 같은 높이(44)의 알약으로 그립니다. 글자 색 · 눌림은ds-btn-text--dark --lg, 좌우 12 · 600 · 알약 모서리(--ds-btn-radius: 9999px). 첫 사용처는 직원 앱 홈 「새로운 공지」 2depth(카드 「더 보기」 로 열고 헤더 제목 「새로운 공지」)의 「모든 공지」 — 최근 공지 전체 목록(헤더 「모든 공지」)을 열고, 거기서 뒤로 가면 「새로운 공지」 으로 돌아옵니다.
2026-10-12 — 직원 앱 화면 배율 「기본」= ×1.0 (design/employee-ui-detail-check)
변경
- 모바일 화면 배율 단계를 작게 ×0.9 · 기본 ×1.0 · 크게 ×1.2 로 — 예전 1.0 · 1.2 · 1.4 라 디폴트 「기본」이 이미 1.2배 확대된 크기였습니다. 이제 「기본」에서 본문 · 버튼 · 입력칸이 디자인 값 그대로 그려집니다. 헤더 · 하단 내비 · 앱 안 상단 배너 · 레이어 팝업 제목은 단계와 무관한 ×1.2 고정이라 보이는 크기가 바뀌지 않습니다. 예전에 「작게」를 고른 사용자는 ×0.9, 「크게」를 고른 사용자는 ×1.2(예전 기본 크기)로 보입니다.
- 직원 앱 xl 버튼(근무 「출근하기 / 퇴근하기」 · 내 프로필 시트 「닫기」)을 lg(48)로 — 직원 앱에서 xl(52) 글자 버튼은 이 두 개뿐이었습니다(원형 FAB 제외).
2026-10-12 — 직원 앱 AI 어시스턴트 이전 대화 서랍이 헤더 위까지 (design/employee-ui-detail-check)
변경
모바일 대화 화면 — 이전 대화 서랍 · 딤이 앱 헤더 위까지 덮음 — 헤더 오른쪽 목록 아이콘으로 여는 서랍과 그 뒤 딤이 예전엔 앱 헤더 아래부터 덮어 「<」 · 목록 아이콘이 그대로 보였는데, 이제 화면 맨 위(상태 표시줄 뒤)부터 화면 전체를 덮습니다(사용자 결정). 서랍 머리는 상태 표시줄 높이만큼 내려 「새 대화」 가 시계 밑에 깔리지 않습니다. 닫는 길에서 앱 헤더 「<」 가 빠지고 딤 탭(헤더 자리 포함)이 그 자리를 맡습니다. 대화 화면을 감싼 스크롤 영역이 겹침 층을 만들어 제자리에서는 헤더 위로 못 올라가서(iOS 실기기), 서랍 · 딤 마크업을 body 로 옮겨(
x-teleport) 새 층.ds-ai-drawer-layer(fixed · 헤더보다 한 층 위) 안에 그립니다..ds-chat-panel--page의z-index: 0은 걷었습니다.「새 대화」 버튼을 서랍 바닥에 고정 · 한 단계 크게 — 맨 위
.ds-ai-drawer__head(md 32)를 없애고 바닥.ds-ai-drawer__foot(구분선 없음, 홈 인디케이터 여백 포함)로 옮기고, 버튼은 solid · muted · ml(40) · 모서리 16(ds-r-16)으로 바꿨습니다. 목록만 스크롤됩니다.숫자 배지 글자 크기 통일 — c1(11px) — 하단 내비게이션
.ds-bottom-nav__badgeb4(14) → c1(11), 앱 헤더 알림 벨 숫자 배지 b6(12) → c1(11). 두 자리의 숫자 배지는 같은 크기다.
2026-10-12 — 직원 앱 앱 안 상단 배너 (design/employee-ui-detail-check)
신규
앱 안 상단 배너 — 직원 앱 — 앱이 앞에 떠 있는 동안 보고 있지 않은 대화방의 새 메시지 · 새 알림(알림함)을 OS 배너 대신 앱이 상단 카드 한 장으로 그립니다(디자이너 결정). 흰 면 · 모서리 16 · 안쪽 12 · 좌우 12 ·
--ds-shadow-lg, 썸네일app-thumb+ 제목 + 「지금」 + 한 줄 본문, 헤더처럼 화면 설정과 무관한 고정 크기(zoom: var(--app-nav-zoom)), 층--ds-z-fab(44). 4초 뒤 올라가고, 연달아 오면 최신으로 갈아 끼웁니다. 누르면 그 방 · 그 알림 화면으로, 위로 밀면 닫힙니다. 휴대폰 알림 설정(푸시 · 전체 알림 받기 · 종류 · 방해 금지 · 메신저 알림 표시)을 서버 푸시와 같은 규칙으로 따릅니다. 앱이 앞에 있을 때 OS 배너는 끕니다(네이티브presentationOptions— 네이티브 재빌드 필요 · 웹 서비스 워커). 직원 앱 전용이며design-system.css는 바뀌지 않았습니다. 토스트 규칙 요약에 「배너는 토스트가 아니다」 한 줄을 더했습니다.직원 앱 스크롤 유리층 맨 위 12px 을 면 색 100% 로 시작 — 휴대폰 브라우저(Safari)의 불투명 상태 표시줄 띠와 헤더가 경계 없이 이어지게. 그 아래 82% → 56% 는 그대로(앱 헤더 · 직원 앱 적용값).
2026-10-12 — 직원 앱 상태 표시줄과 헤더를 한 면으로 (design/employee-ui-detail-check)
변경
- 앱 헤더 · 상태 표시줄 — iOS · 안드로이드 모두 상태 표시줄은 투명, 웹이 그 뒤까지 그림 — 상태 표시줄 띠와 페이지 상단 배경이 끊겨 보이던 문제(디자이너 보고)를 고쳤습니다. 안드로이드 14 이하는 예전에 띠를 불투명한 「맨 위 면 색」으로 칠해, 바텀시트 · 다이얼로그 딤이 떠도 띠만 밝게 남고 스크롤 유리 헤더와도 어긋났습니다 — 이제 투명이라 헤더 · 딤이 그대로 비칩니다. 웹이 상태 표시줄 아래로 내려간 경우(안드로이드 WebView 139 이하)만 딤까지 합성한 색으로 칠합니다. 아이콘 색은 고정 「어두운 아이콘」에서 맨 위 합성색의 밝기로 고르게 바뀌었습니다(휘도 0.179 경계). 직원 앱은 다크 모드를 지원하지 않으므로 네이티브도 라이트로 고정했고(iOS
UIUserInterfaceStyle· 안드로이드 테마 ·SystemBars.style), 첫 실행에 흰 바탕 위 흰 아이콘(StatusBar.style: "DARK")이던 것과 안드로이드 첫 프레임의 띠(initialViewportFitValueHint)도 고쳤습니다. DSdesign-system.css값은 바뀌지 않았고, 네이티브 설정은 앱 재빌드가 필요합니다.
2026-10-12 — 메신저 「새 메시지 n개」 알약 (design/employee-ui-detail-check)
신규
- 대화 UI 「새 메시지 n개」 알약
.ds-chat-new-messages신설 — 메신저 대화방에서 위로 올려 예전 대화를 보는 중에 상대 메시지가 오면, 목록을 끌어내리지 않고 입력줄 바로 위 가운데에 「새 메시지 n개」 + 아래 화살표(ic-chevron-down) 알약이 뜹니다. 흰 면 ·label-normal글자 · b5 600 · 높이 36 ·--shadow-popover(떠 있는 것들과 같은 높이) · 알약 모서리는--ds-btn-radius(blanket 버튼 강제를 변수로 이김)입니다. 누르면 맨 아래로 부드럽게 내려가고(움직임 줄이기 설정이면 바로) 사라지며, 직접 맨 아래까지 스크롤해도 사라집니다. 맨 아래 근처(160px)에서 받으면 예전처럼 따라 내려가고, 내가 보낸 메시지는 세지 않으며, 99 를 넘으면 「99+」 입니다. 자리는 목록과 입력줄 사이의 높이 0 앵커(.ds-chat-new-messages-anchor)라 키보드가 열려 입력줄이 올라가면 같이 올라갑니다. 직원 앱 · 채팅 위젯 공통(messenger-content.html·Messenger.ts)이고, 맨 아래 판정은isChatNearBottom한 벌로 묶었습니다. 모바일 대화 화면에 안내 한 줄을 더했습니다.
2026-10-12 — 직원 앱 헤더 크기 고정 · 상단 여백 · 레이어 팝업 제목 (design/employee-ui-detail-check)
모두 직원 앱 덮어쓰기(앱 main.css · directives/header-overlay.ts)이고 design-system.css 의 DS 기본값은 바뀌지 않았습니다. 수치는 직원 앱 「기본」 화면 설정 기준입니다.
신규
- 페이지 인터랙션 — 모바일 앱 페이지 신설 — 2depth · 풀레이어 팝업을 한곳에 — 모바일 앱(직원 앱) 전용이고 웹 앱은 대상이 아닙니다. 화면 위에 화면 한 장을 여는 두 방법(「뒤로(<)」 2depth · 「닫기(X)」 풀레이어 팝업)의 쓰임 · 구조 · 제목 줄 · 여백 · 하단 버튼 · 닫기를 모았고, 모달 · 앱 헤더에 흩어져 있던 직원 앱 풀레이어 규격(예전 값 여백 20 · X -12 포함)은 이 페이지를 가리키게 정리했습니다. 움직임은 두 종류뿐입니다 — 「뒤로(<)」 2depth 페이지는 우 → 좌 슬라이드 인/아웃(
x-depth-page), 「닫기(X)」 레이어 팝업은 아래 → 위 슬라이드 업/아웃(시트만 움직이고 딤은 함께 짙어지고 옅어짐). 둘 다 260ms ·cubic-bezier(0.32, 0.72, 0, 1), 모션 줄이기 설정이면 바로 열고 닫습니다. 직원 앱 풀레이어 팝업 11종(휴가 · 연장근무 · 외근 · 주말 당직 세션 신청, 두 보고서, 출퇴근 정정, 서류 제출, 인센티브 등록, 결재자 지정, 급여명세서 상세)은 그동안 애니메이션 없이 툭 뜨고 사라졌는데,x-if→x-layer-if로 바꿔 올라오고 내려갑니다(열 때마다 새로 그리는 동작은 같음). 공용 불편 · 오류 신고의 풀레이어 모드는x-layer-page="fullLayer"로 같은 전환을 탑니다(다른 앱의 카드 모드는 그대로). 엣지 스와이프(왼쪽 가장자리를 밀어 뒤로)는 2depth 에만, iOS 네이티브 앱에만 적용합니다 → 엣지 스와이프. 페이지는 「공통 · 2depth 페이지 · 풀레이어 팝업 · 적용·출처」 탭으로 나뉘고, 2depth · 풀레이어 팝업 탭 맨 위에 각각 폰 프레임 Playground 가 있습니다(2depth 는 플랫폼 · 엣지 스와이프, 둘 다 속도 · 모션 줄이기 전환 —DemoPageInteractionPlayground kind="depth2|layer"). - 앱 헤더 「직원 앱 적용값」 표 — DS 기본값과 직원 앱 값이 다른 항목(크기 고정 · 버튼 · 상단/하단 여백 · 유리층 · 접힘 전환 · 레이어 팝업 제목 줄)을 한곳에 모았습니다.
- 앱 헤더 2depth 의 두 종류 — 뒤로형(<) · 레이어 팝업형(X) — 레이어 팝업 제목은 2depth 제목과 같은 규격(
text-b3· semibold ·hr-gray-900· 한 줄 말줄임 · 화면 설정과 무관한 고정 크기)입니다. 직원 앱 풀레이어 팝업 전부(휴가 · 연장근무 · 외근 신청, 출퇴근 정정, 서류 제출/요청, 인센티브 등록, 주말 당직 세션 신청, 결재자 지정, 연장근무 · 외근 보고서)가<div role="heading" aria-level="3" class="modal-full__title">를 쓰고, 두 보고서도.modal-full__header줄을 갖게 됐습니다. 공용 풀레이어 모달(불편 · 오류 신고)의 제목도 같은 크기 · 굵기 · 한 줄 규칙이고 색은 DSlabel-normal그대로입니다. 팝업 헤더의 「도움」 글자 버튼도 크기 고정입니다. 닫기(X)는 아직 32 투명 버튼이라 뒤로 유리 원(44)과 다릅니다.
변경
- 앱 헤더 크기가 화면 설정(작게 · 기본 · 크게)과 무관 — 하단 내비 분리형과 같은 방식으로 헤더에
zoom: var(--app-nav-zoom)을 걸어 늘 「기본」 크기로 그립니다. zoom 이 걸린 요소의offsetHeight는 배율 전 값이라(Chromium · WebKit 동일),header-overlay.ts가 잰 높이에 zoom 을 곱해--app-header-h·--ds-app-header-row-h에 넣습니다. - 앱 헤더 버튼이 화면에서 44 — 뒤로 유리 원 44 · 오른쪽 유리 캡슐 높이 44(안쪽 4) · 캡슐 안 아이콘 버튼 36 · 글리프 24 · 아바타 44 · 메신저 헤더 검색칸 44. 예전엔 DS 44 가 배율을 타 52.8 로 그려졌습니다(앱이 DS 값을 ÷1.2 로 넘김).
- 앱 헤더 상단 여백 = 상태바 + 8 — 예전 DS 값
max(safe-area, 12px)는 기기에서 12 가 쓰이지 않고 safe-area 가 배율을 타 상태바 밑에 9~12px 빈칸이 남았습니다. 상태바가 없는 브라우저에서는 8 입니다. 탭 줄이 있는 접는 헤더(결재 · 메신저)는 접히는 만큼 이 8 이 0 까지 줄어, 다 접히면 탭 줄이 상태바 바로 아래에 붙습니다. 풀레이어 팝업 제목 줄도 같은 위치(--app-header-top-in-body)에 맞춥니다. - 앱 헤더 스크롤 유리층 색 단계 — 직원 앱은 면 색 82% → 56% 로 고르게 옅어지고(DS 는 60% 지점 56% 를 거쳐 0%), 헤더 줄이 다 접혀 탭 줄만 남으면 100% → 70% 입니다. 흐림 · 아래쪽 마스크 · 투명도 줄이기 설정의 값은 DS 그대로입니다.
- 앱 헤더 메신저 목록이 탭 줄 뒤로도 지나감 — 결재처럼 대화 · 연락처 목록이 헤더 전체(탭 줄 포함) 뒤로 지나가 다 접힌 탭 줄의 유리가 보입니다. 목록 위에 서는 줄(연결 상태 띠 · 그룹 채팅 선택 줄 · 미리보기 차단 안내)은 훅 클래스
.messenger-above-list를 달아, 보이면 그 줄이 헤더 높이만큼 내려갑니다(messenger-content.html). 메신저 1depth 헤더(solid+ 탭 줄)의 하단 여백은 4 → 0 이라 탭 밑줄이 본문에 바로 붙습니다. - 앱 헤더 탭을 바꾸면 접힘을 다시 판정 · 280ms 로 부드럽게 — 「대화」를 내린 뒤 「연락처」를 누르면 맨 위인 목록 위에 헤더가 접힌 채 빈칸이 남던 문제를 고쳤습니다(
header-overlay.ts가[data-app-scroll-root]를 ResizeObserver 로 지켜봄). 스크롤이 아닌 이유로 접힘이 바뀔 때만.is-collapse-animating(280ms) 전환이 걸리고, 스크롤 연동은 그대로 손가락을 따라가며 모션 줄이기 설정이면 즉시 바뀝니다. - 하단 내비게이션 직원 앱 선택 탭 바탕이 회색 평면 — 분리형의 선택 유리(흰 78% · 윗선 하이라이트 · 안쪽 그늘 · 바깥/들림 그림자 · 윗면 광택)를 걷고
neutral-75알약 하나만 둡니다. 미끄러짐 · 들림(1.08) · 눌림 · 아이콘 튕김은 그대로입니다. - 직원 앱 더보기 1depth 본문 위 여백 4(
pt-1, 근무와 같음) — 헤더 하단 4 + 본문 4 = 8. 앱 헤더 「직원 앱 적용값」에 적었습니다.
2026-10-08 — AI 어시스턴트 대화 UI · 위치 안내 툴팁 (desgin/chat-ui-improve)
신규
- 툴팁 위치 안내 툴팁 케이스 — admin AI 어시스턴트 「기능 바로가기」가 대상 옆에 띄우는 안내가 노란 notice + 「닫기」 텍스트 버튼에서 툴팁 모양으로 바뀌었습니다. 배경
--color-purple-500· 제목/설명 글자 white · 닫기는 아이콘 버튼ds-btn--icon ds-btn--white ds-btn--xs(ic-close) · 화살표 마름모와 등장 인터랙션(opacity + 4px 슬라이드 120ms)은 hover 툴팁과 같습니다. hover 툴팁의 세 번째 종류가 아니라 별개 케이스이고(닫기형 · 싱글톤 아님),createGuidanceHighlight()만 만듭니다. 색은--ds-guidance-bg/--ds-guidance-fg/--ds-guidance-line세 변수로만 읽어.ds-guidance--<이름>+tone옵션으로 변형을 추가할 수 있습니다(아직 기본 purple 하나).
변경
- 버튼 아이콘 버튼
white의 hover 배경이 반투명 흰색 — 다른 아이콘 버튼처럼 회색 원(neutral-100/200)이 깔리던 것을 흰색 20%(hover · focus) · 30%(pressed)로 바꿨습니다.white는 색 면 위에 놓이는 변형이라 회색 원이 보라 툴팁 위에서 이질적으로 떠 보였습니다. 다른 아이콘 색은 그대로입니다. - 대화 UI 말풍선을 감싸는 상자는
w-full— AI 어시스턴트의 보낸 말풍선 · 실패 말풍선이 「자기 글자 폭의 85%」에서 꺾여 마지막 단어가 늘 다음 줄로 넘어가던 것을 고쳤습니다. 말풍선 최대 폭(%)은 감싸는 상자 기준이라, 상자가 글자 폭으로 줄어 있으면 생기는 함정입니다. 규칙(강제)에 추가했습니다. - 모바일 대화 화면 AI 말풍선 규칙은 PC 와 한 벌 — 직원 앱 AI 어시스턴트도 같은 마크업이라 꼬리표 아이콘 버튼 · 숨김 항목 · 시간 표시 · 대기 상태 줄이 똑같이 적용됨을 규칙에 적었습니다.
- AI 어시스턴트 답변 대기 상태 줄은 글자만 — 「질문을 이해하고 계획하는 중 · 3초」와 생각 과정이 회색 말풍선 없이 글자로만 보이고, 답변이 흐르기 시작하면 말풍선이 됩니다. admin · 직원 앱 공통이며, 이 페이지의 말풍선 폭 · 꼬리표 버튼 · 코드 숨김 · 시간 표시 변경도 직원 앱에 똑같이 적용됩니다(같은 마크업).
- AI 어시스턴트 입력 중 기능 팝오버(admin) — 입력줄에 「휴가」 · 「직원 추가」 처럼 기능과 맞는 말을 치면 직원 앱과 같은 「바로 갈 수 있는 화면」 팝오버가 입력줄 위에 뜨고, 누르면 그 화면으로 가서 대상을 하이라이트합니다. 목록은 시스템 어드민 「문서 안내」 설정이 켜진 조직에서만 나오는 기능 바로가기와 같습니다.
- AI 어시스턴트 admin 대화 중 「기능 바로가기」 버튼 제거 — 기능은 새 대화 첫 화면에서만 고릅니다. 인사 시트는 「열 위치 보기」가 필요해 버튼을 그대로 둡니다.
- AI 어시스턴트 대화 중 「기능 바로가기」 패널도 모바일 모양(인사 시트) — 회색 테두리 버튼 목록이던 패널을 첫 화면 · 직원 앱 업무 바로가기와 같은 칩(연한 주황 · 모서리 12 · 아이콘)으로 바꾸고, 처음 3개 + 「기능 전체 보기」로 맞췄습니다. admin 첫 화면 맨 위에 master 심볼 + 「AI」를 두었습니다.
- 대화 UI AI 어시스턴트 입력칸 32 → 40 — 떠 있는 패널 · 도크의 입력칸이 메신저와 같은
ds-input--40(40px · 14px 글자 · 다섯 줄까지)이 됐습니다. - AI 어시스턴트 처음 열면 새 대화 — 페이지를 띄운 뒤 처음 열 때 마지막 대화를 이어 열지 않고 새 대화(기능 바로가기 첫 화면)로 시작합니다. 이전 대화는 왼쪽 사이드바에서 엽니다. 직원 앱도 같이 새 대화로 시작하고, 이전 대화는 오른쪽 서랍에서 엽니다.
- 앱 헤더 헤더 버튼 36 → 44 — 뒤로 유리 원 · 아이콘 유리 캡슐 · 대화방 검색칸 · 아바타가
--ds-app-header-btn(44) 하나로 함께 커졌습니다. 캡슐 안 액션 · 알림벨은md(30 · 글리프 20)에서lg(36 · 글리프 24)로, 아바타 이니셜은 b4 → b3. 탭 줄 오른쪽 액션은 캡슐 밖이라 그대로입니다. - 모바일 대화 화면 모바일 채팅 검색칸
.ds-chat-search-field신설 · 아이콘ic-document-search추가 — 대화방 검색칸이 전역 입력칸 규칙을 받아 포커스 때 검은 테두리가 생기던 것을, 입력칸 모양을 쓰지 않는 전용 부품(유리 알약 · 포커스 선 없음)으로 바꿨습니다. 검색 막대 왼쪽 버튼 아이콘은 사람(ic-user)에서 문서 + 돋보기(ic-document-search, 새로 그림)가 됐습니다. - 앱 헤더 스크롤 겹침 라이브 데모 · 흐림 변수 — 문서에서 프레임 안을 직접 스크롤해 본문이 헤더 뒤로 지나가며 그라데이션 유리층이 켜지는 것을 볼 수 있습니다(1depth 목록 · 2depth 대화방 · 대화방 검색,
DemoAppHeaderScroll). 헤더 흐림은--ds-app-header-blur(정본 4px) 변수가 되었고 데모의 슬라이더로 비교합니다. - 모바일 대화 화면 메신저 대화방 검색이 카카오톡 방식 — 헤더 검색이 유리 검색칸(돋보기 · 입력 · 지우기) + 「취소」 가 되고, 「검색」 버튼 대신 키보드 검색 키로 찾습니다. 결과를 헤더 아래 목록으로 펼치던 것을 없애고, 입력줄 자리의 유리 검색 막대(「내가 보낸 메시지만」 · 「2/7」 · ▲▼)로 이 방 안의 일치 메시지를 가장 최근 것부터 하나씩 짚습니다. 검색 중에도 대화가 헤더 뒤로 지나갑니다. 검색칸 안내 문구는 「대화 내용 검색」.
- 앱 헤더 그라데이션 유리 헤더 · 유리 버튼 — 모바일 앱 헤더(1depth · 2depth 공통)가 스크롤되면 면 한 장 + 아래 선 대신, 흐림 위에 위에서 아래로 옅어지는 그라데이션 유리층(
::before)이 깔리고 아래 경계가 사라집니다(iOS 26 메신저 앱 헤더). 뒤로(<)는 36 유리 원, 오른쪽 아이콘(액션 · 알림벨)은 유리 캡슐 하나(.ds-app-header__glass)에 담깁니다 — 재질은 하단 내비 캡슐과 같습니다. 직원 앱 메신저 대화방 · AI 어시스턴트는 대화 목록이 헤더 뒤까지 올라가 말풍선이 유리 밑으로 지나갑니다. 급여명세서 팝업의 뒤로 버튼도 같은 유리 원입니다. - 모바일 대화 화면 대화 목록 가장자리 페이드 — 직원 앱 메신저 대화방 · AI 어시스턴트에서 스크롤하면 말풍선이 앱 헤더 밑 · 입력줄 위에서 잘려 보이던 것을, 20px 그라데이션으로 흐려지며 사라지게 했습니다(
.ds-chat-scroll-fade— 스크롤 상자 마스크 + 같은 폭의 위·아래 패딩). 입력줄 캡슐의 위 여백(8)을 없애 페이드가 캡슐 윗선에서 바로 끝납니다. - 모바일 대화 화면 직원 앱 Enter 가 보내기 — 휴대폰 키보드에서도 Enter 는 보내기, Shift+Enter 는 줄바꿈입니다(PC 와 같은
shouldSendOnEnter). 입력칸에enterkeyhint="send"를 달아 키보드 Enter 키가 「보내기」로 보입니다. 메신저 · AI 어시스턴트 공통입니다. - 모바일 대화 화면 직원 앱 이전 대화가 오른쪽 서랍 — 대화 화면을 통째로 목록으로 바꾸던 것을 Claude · ChatGPT 모바일 앱처럼 대화 위로 밀려 나오는 서랍(
.ds-ai-drawer+ 딤)으로 바꿨습니다. 앱 헤더 왼쪽이 「뒤로(<)」 자리라 오른쪽에서 나옵니다. 헤더 아이콘(시계 →ic-menu)이나 대화를 왼쪽으로 밀어 열고, 딤 탭 · 오른쪽으로 밀기 · 대화 고르기 · 뒤로 가기로 닫습니다. 서랍이 손가락을 따라 움직이고, 손을 떼면 튕긴 방향 · 절반 기준으로 자리를 잡습니다. 행은 제목 한 줄(44px)이고 날짜는 숨깁니다. - AI 어시스턴트 이전 대화가 왼쪽 사이드바 — 헤더 오른쪽의 「이전 대화 목록」(시계) 버튼을 없애고, 타이틀 왼쪽 패널 아이콘(
ic-panel)으로 켜고 끄는 사이드바(.ds-ai-history)를 두었습니다. 늘 펼친 상태로 시작합니다(접어도 기억하지 않음). 폭은 최소 80 · 최대 150, 제목은 한 줄 말줄임이고 날짜는 숨깁니다. 떠 있는 패널·도크(admin · 인사 시트)에 적용되고, 직원 앱(페이지 모드)은 오른쪽 서랍입니다(위 항목). - AI 어시스턴트 admin 첫 화면이 기능 바로가기 목록 — 빈 대화(대화가 없거나 「새 대화」)에서 직원 앱 업무 바로가기와 같은 모양으로 「현재 앱에서 사용할 기능」을 처음 3개 보여 주고, 4개 이상이면 그 아래 「기능 전체 보기」로 모두 펼칩니다(
guidanceStartScreen옵션). 이 화면이 떠 있는 동안 위쪽 「기능 바로가기」 버튼은 숨깁니다. - AI 어시스턴트 답변 꼬리표 버튼이 아이콘 버튼 xs — 복사 · 문제 신고가 글자 버튼(line · muted · xs)에서
ds-btn--icon ds-btn--muted ds-btn--xs로 바뀌었습니다. 문제 신고는 불편·기능 신고와 같은ic-megaphone이고, 이름은 툴팁으로 보입니다. 실패 말풍선의 문제 신고와 보낸 메시지 복사도 같습니다. 토큰 사용량과 👍/👎, 답변 위 「답변 소요 ○초」, 실패 말풍선 아래 「오류 코드 …」는 숨겼습니다(마크업은x-if="false"로 남김, 오류 코드는 문제 신고에 그대로 첨부). - AI 어시스턴트 대상 강조선 orange 500 → purple 400, 가장자리에서 잘리지 않음 — 강조선은 대상 바깥 4px 에 그리되, 대상이 화면 끝이나 열린 AI 도크(
--ds-ai-dock-w)에 닿으면 상자를 화면 안으로 줄여 네 변이 모두 보입니다. 도크 폭만큼 화면에서 빼고 계산하므로 말풍선도 도크 밑으로 들어가지 않습니다.
2026-10-08 — 이름 칸 직원 카드 (feat/employee-card-everywhere)
신규
- 데이터 표 — 이름 칸 = 직원 카드 — 표에 사람 이름이 나오면 이름을 눌러 그 사람의 카드(이름 · 상태 · 사번 · 직무 · 소속 팀 · 병동 배정)를 봅니다. admin 의 팀 관리 · 병동 · 직원 관리 · 근무표에만 있던 카드를
@hereby/components(employee-card.html+$store.employeeCard+ 매직$employeeCard)로 옮기고, admin · team-manager · hr-system · 총무 · 경영 대시보드 · 드라이브의 목록 표에 붙였습니다. 새 표도 기본으로 이렇게 만듭니다(팝업 안의 표는 따로 요청이 있을 때만). .ds-name-trigger— 이름 칸 트리거. 칸의 글자를 그대로 물려받고 hover · 카드가 열린 동안에만 회색 칩이 생깁니다.- 카드의 버튼은 앱이
registerEmployeeCardActions로 등록한 것만 나옵니다 — admin 은 직원 정보 수정 · 팀/병동/스케줄러로 건너뛰기, hr-system 은 직원 정보 수정, 나머지 앱은 보기 전용.
2026-10-07 — 대상 선택기 순서 조정 ▲▼ · 직원 앱 「나의 결재선」 (feat/approval-line)
변경
- 대상 선택기 (entityPicker)
ordered칩에 ▲▼ — 고른 순서가 뜻을 가질 때(결재 단계) 칩마다 앞으로 · 뒤로 버튼(.ds-entity-chip__move, 해제 버튼과 같은 20px ·moveSelection(s, ±1))이 붙습니다. 첫 칩의 ▲ 와 마지막 칩의 ▼ 는 흐리게(--ds-opacity-35) 비활성. 끌어서 옮기기는 두지 않습니다(모바일 스크롤과 겹침).ordered가 아닌 드라이브 · 시트 공유는 그대로입니다. 첫 쓰임새는 직원 앱 나의 결재선 편집 시트(이름 · 종류 · 결재자 1~5명 · 기본 지정, 종류별 여러 개)입니다.
2026-10-07 — 결재선 패널 「바꾸기」 · 결재자 바꾸기 모달 (feat/approval-line)
신규
- 결재선 패널 결재자 바꾸기 — 패널 옵션
onReplace를 주면 아직 처리되지 않은 단계(확인 중 · 대기) 줄 끝에 「바꾸기」(.ds-approval-steps__replace,ds-btn--xs)가 뜹니다. 서버approvalFlow.steps가canReplace(그 종류 조직 전체 범위 승인자 · 시스템 관리자)를 실어 주고, 패널은 그 값과 coreapprovalStepReplaceable로만 버튼을 정합니다. 바뀐 단계는 상태 줄 아래 「최급여 님에서 바뀜 · 김관리 님 · 시각」(.ds-approval-steps__replaced) 한 줄. 공용 모달approvalReplace(approval-replace-modal.html·ApprovalReplace.ts)는 일반 모달 한 벌로 후보(approvalFlow.replaceCandidates)를 대상 선택기에 넣어 한 명 고르고, 확인창 문구는 coreapprovalReplaceHint, 성공 문구는approvalReplaceMessage입니다. 호스트(팀장 앱 상세 4종 · 관리자 연차 · 외근 상세)는requestApprovalReplace·bindApprovalReplaceHost로 창 이벤트로만 잇습니다 — 루트에 믹스인으로 펼치면 TS 가this게터를 순환으로 판정해 빌드가 깨지는 함정 때문입니다. 상세 모달의 ESC 는 호스트 플래그approvalReplaceOpen을 먼저 봅니다.
2026-10-07 — 결재선 메뉴 아이콘 ic-tree (feat/approval-line)
신규
- 아이콘
ic-tree추가 — 줄기 하나에서 가지 두 개가 뻗어 끝마다 둥근 네모가 붙은 트리 모양(24 viewBox · 아웃라인 · 2px round). 관리자 왼쪽 메뉴 인사 관리 › 결재선(병원 기본 결재선 · 직접 고르기 정책 화면)이 처음 씁니다. 같은 메뉴 안에서ic-list-check(직원 앱 도입)·ic-approval(문서 결재)과 겹치지 않게 새로 그렸고,pnpm icons:build로packages/static/icons/ic-tree.svg파생본을 함께 만들었습니다.
2026-10-07 — 앱 헤더 탭 점 · 직원 앱 결재함 (feat/approval-line)
변경
- 앱 헤더 탭 줄에
updateDot—AppHeaderTab에 웹 TabNav · SubTab 과 같은 「새로 생긴 것이 있다」 점(.ds-tab-dot)을 더했습니다. 첫 쓰임새는 직원 앱 「신청·결재 현황」 탭(안 본 반려). 배지(badge)와 함께 쓸 수 있습니다. - 결재선 패널 직원 앱 적용 — 내 신청 상세(휴가는 진행 상황 대신, 근무는 아래)와 결재할 문서 상세가
size: 'lg'·labelSize: 'md'로 include 합니다. 결재할 문서 목록·결재한 문서 목록은 「내 신청」 칸과 같은 행 마크업(.ds-label--md)이고, 상세 하단 버튼은 앱의.page-footer-cta--flow입니다.
2026-10-07 — 결재선 패널 신설 (feat/approval-line)
신규
- 결재선 패널 페이지 신설 (패턴) — 휴가 · 연장근무 · 외근 · 인센티브 결재 단계를 보여 주는 공용 부품
approvalSteps(packages/components/html/approval-steps.html·.ds-approval-steps*)입니다. 번호 · 이름 · 당시 직책 · 상태 칩(.ds-label, 대기 light-gray · 확인 중 yellow · 승인 green · 반려 red · 건너뜀 gray) · 처리 시각 · 「○○○ 님이 대신 처리」 · 반려 사유를 세로 타임라인으로 그리고, 단계 줄이 없는 예전 신청은 한 줄 안내로 대신합니다. 목록 칸용 compact 한 줄, 직원 앱용size: 'lg'(13px 하한)가 있습니다. 화면 공통 규칙(행 상태approvalRowState· 결재 열 라벨approvalProgressLabel· 확인창 문구approvalDecisionHint등,@hereby/core/constants)과 승인·반려 결과 · 오류 공용 처리(decisionResultMessage·handleDecisionError,@hereby/components)를 같은 페이지에 정리했습니다. 팀장 앱 · 관리자 · 직원 앱 상세가 다음 단계에서 이 부품을 include 합니다. - 로딩 스피너 작은 링 변형
.ds-spinner--sm— 16px · 2px, 한 줄 안내 옆에 두는 링(결재선 패널의 「불러오는 중」이 첫 쓰임새). 확장 규칙대로 변수만 덮습니다.
2026-10-07 — 대상 선택기에 「호스트 후보 · 순서 번호 · 상한」 (feat/approval-line)
변경
- 대상 선택기 (entityPicker) 에 옵션 셋을 더했습니다 —
employees(호스트가 추린 후보를 넣으면 서버 디렉터리를 부르지 않음 · 사번 없이 「팀 · 직무」) ·ordered(칩에 1 · 2 · 3 번호,.ds-entity-chip__order) ·max(상한을 채우면 남은 행 비활성 + 안내). 첫 쓰임새는 결재선(MED-900)의 「결재자 고르기」. 드라이브 공유 · 시트 공유는 그대로입니다.
2026-10-07 — 하단 내비 리퀴드 글라스 · 선택 유리 (design/bottomnav-improve)
변경
- 앱 헤더
collapseOnScroll— 스크롤하면 헤더 줄 접기 — 탭 줄이 있는 화면에서 본문을 내리면 헤더 줄(날짜 · 알림 · 아바타)이 스크롤한 만큼 위로 접혀 사라지고 다 접히면 탭 줄만 상단에 남습니다(.ds-app-header--collapsible·--ds-app-header-collapse·.is-collapsed). 처음엔 24px 를 넘으면 240ms 로 접었는데 내용과 따로 움직여 튕겨 나오는 것처럼 보여(실기기 보고) 스크롤 연동으로 바꿨습니다. 그래도 튕긴다는 보고로 측정해 보니 원인이 셋이었습니다 — ① 헤더가 흐름 안이라 줄어드는 만큼 스크롤러가 끌려 올라가 본문이 두 배 속도로 움직임(헤더를 absolute 로 띄움) ② 접히는 동안 펼친 높이를 다시 재 반올림 오차로 매 프레임 흔들림(다 펼쳤을 때만 잼) ③ 손을 뗀 뒤 스냅이 화면을 혼자 움직임(제거). 접히는 속도는 스크롤의 0.6배입니다. 판정과 줄 높이(--ds-app-header-row-h)는 호스트 JS 가 넣습니다. 직원 앱은 결재 · 메신저 1depth 에서 켭니다 — 메신저는 대화 · 연락처 목록에data-app-scroll-root를 달고, 섹션을 줄 높이만큼 헤더 뒤로 올려 목록도 유리 탭 줄 뒤로 지나갑니다. 근무 · 더보기는 탭 줄이 없어 그대로입니다. 안쪽 목록 스크롤도.is-scrolled(가장자리 선)를 켜고, 메신저 셸 면은 흰색이 됐습니다. - 앱 헤더 뒤로 가기 버튼에
data-edge-swipe-back— iOS 엣지 스와이프 — 직원 앱 iOS 네이티브에서 왼쪽 가장자리를 밀면 화면 맨 위에 보이는 뒤로(<) 버튼을 누른 것과 같습니다. 화면이 손가락을 따라오고 35% 이상 · 빠른 튕김이면 뒤로 가며, 2depth 퇴장 슬라이드가 그 위치에서 이어집니다(x-depth-page가data-edge-swipe-from을 읽음). 풀레이어 팝업은 헤더가 < 일 때만(급여명세서 본인 확인), X 팝업은 불가. 안드로이드 · Safari 웹은 켜지 않고 햅틱은 없습니다. 메신저 자체 스와이프는 앱에서 꺼서 두 번 물러나지 않게 했습니다. - 하단 내비게이션 지금 탭을 한 번 더 누르면 맨 위로 — 직원 앱
selectBottomTab이 같은 탭이면 지금 보이는 화면(셸 스크롤러 · 메신저 목록)을 부드럽게 맨 위로 올립니다. 헤더 줄도 같이 펴집니다. - 모바일 대화 화면 「바로 갈 수 있는 화면」 팝오버 버튼이 line · muted — 팝오버 흰 면 위에서 연한 주황 면(solid · lightor)이 무거워 테두리형으로 바꿨습니다. 첫 화면 업무 바로가기는 그대로입니다. 직원 앱 AI 어시스턴트에는 기능 안내(「기능 바로가기」 · 답변 속 「화면에서 위치 보기」)를 연결하지 않습니다 — 같은 화면을 업무 바로가기와 「바로 갈 수 있는 화면」 이 바로 열어 주어 위치만 짚는 안내가 중복이었습니다. 관리자 · 인사 앱은 그대로입니다.
- 직원 앱 AI 어시스턴트 화면이 오른쪽에서 밀려 들어옴 — 다른 2depth 화면과 같은
x-depth-page(우 → 좌 260ms, 닫으면 오른쪽으로 빠짐)를 붙였습니다. 예전엔 이 지시문만 빠져 있어 하단 「AI 어시스턴트」 를 누르면 화면이 툭 바뀌었습니다. - 앱 헤더 스크롤 겹침이 리퀴드 글라스 — DS 소유로 — 본문이 헤더 뒤로 올라가면(
.is-scrolled, 앱 JS 가 붙임) 헤더가 하단 내비 캡슐과 같은 재질(면 색 66% +blur(20px) saturate(170%)+ 아래 가장자리 유리 선, 200ms 전환)이 됩니다. 예전엔 직원 앱main.css가 「면 90% + blur 8px」 로 갖고 있던 규칙을 DS.ds-app-header.is-scrolled로 옮겼고, 앱은 면 색--ds-app-header-surface(셸 회색 · 흰 면 화면 · solid 는 흰색)만 넘깁니다. 1depth(탭 줄) · 2depth · AI 어시스턴트 페이지 · 메신저 대화방이 같은 헤더라 한 번에 적용됩니다. 풀레이어 팝업 제목 줄(.modal-full__header)은 본문이 따로 스크롤해 뒤로 지나가는 내용이 없으므로 대상이 아닙니다.prefers-reduced-transparency면 94%. - 직원 앱 상태 표시줄 색이 화면 면 색을 따라감 — iOS Safari 로 열 때
theme-color가 브랜드 주황 고정이라(Safari 가 거부해 회색) 상단 상태 표시줄과 앱 배경이 갈려 보였고, 흰 면 화면에서 더 심했습니다. iOS 26 Safari 는theme-color를 더 이상 쓰지 않고body의 배경색으로 상태 표시줄을 칠하므로, 앱이 화면 맨 위의 불투명한 면 색(셸 회색 · 흰 면 · 풀레이어 팝업 흰색)을 읽어body배경(--app-status-bar-surface) ·theme-color(안드로이드 크롬 등) · 안드로이드 StatusBar 에 넣습니다(utils/status-bar-surface.ts). 스크롤돼 헤더가 유리가 되면 면 색을 흰색 쪽으로 34% 섞어 유리의 밝기에 맞추고, 딤은 건너뜁니다. iOS 네이티브는 상태 표시줄이 WebView 위에 겹쳐 원래 맞았습니다. 앱 헤더 「앱 소유로 남는 것」에 적었습니다. - 하단 내비게이션 분리형 캡슐이 리퀴드 글라스 — 흰 80% +
blur(16px)이던 캡슐이 흰 66% +blur(20px) saturate(170%)+ 유리 테두리(안쪽 흰 선 1px · 윗선 1px)가 됐습니다. Apple HIG 「Materials」의 regular 변형입니다(글자가 많고 밝은 바탕이라 사진·영상 전용 clear 가 아님). 흐림은 캡슐 한 겹뿐이고,prefers-reduced-transparency면 94% 흰색이 됩니다. - 선택 표시가 회색 바탕에서 선택 유리(
.ds-bottom-nav__glow)로 — 선택된 탭 뒤에 유리 한 장(흰 78% + 윗선 하이라이트 + 바깥 그림자)이 떠 있고, 손가락이 닿으면 그 탭이 0.96 으로 눌리며 유리는 제자리에서 1.08 로 부풀고(.is-lift), 누른 채 좌우로 끌면 손가락 아래 탭을 따라가며, 떼면 스프링(--ds-bottom-nav-move450ms ·--ds-bottom-nav-springlinear() 스프링, 넘침 약 6%, 미지원 브라우저는 cubic-bezier 폴백)으로 누른 탭까지 미끄러져 내려앉고 아이콘이 한 번 튕깁니다(.is-pop380ms). 위치는BottomNav.ts가 offsetLeft 로 재서 넣습니다(zoom을 건 호스트에서 화면 좌표는 어긋남).prefers-reduced-motion이면 즉시 옮겨 가고 눌림·튕김이 없습니다. 실행 버튼(원)은 눌림 0.96 만 있습니다. 예전__item-body회색 바탕(neutral-75)은 없어졌습니다. 한 줄형(실행 버튼 없음)은 그대로입니다. - 분리형 바닥 여백이 변수
--ds-bottom-nav-bottom-gap— 기본은 예전과 같은8px + safe-area이고 앱이 기기별로 덮어씁니다. 직원 앱은 iOS 만 홈 인디케이터 영역 안으로 12 들어간max(8px, safe-area − 12px)(iOS 26 탭바 위치)로, 캡슐과 채팅 입력줄(메신저 대화방 · AI 어시스턴트) 아래가 휑하던 것(8 + 34 = 42, 내비는zoom때문에 50)을 22 로 줄였습니다. 내비에zoom을 거는 호스트는 배율로 나눈 값을 넘겨야 합니다(env()도 배율을 탑니다). 스크롤 끝 · 배너 · 토스트 · 메신저 여백은64px × 배율 + 바닥 여백으로 바뀌었습니다. - 문서 · 데모 — 규칙(강제)에 선택 유리 · pointer 경로 · 모션 변수 · 흐림 한 겹 · 바닥 여백 다섯 항목을 더했고, 구조도와 「앱 소유로 남는 것」 표를 고쳤습니다. 데모(
DemoBottomNav)도 선택 유리와 눌림·스프링을 같은 클래스로 재현합니다.
2026-10-07 — 플로팅 버튼 스크롤 끝 여백 · 아이콘 (design/improve-scheduled-changes-ui)
변경
- 컨펌 다이얼로그 표 · 안내 · 아래 한 줄 옵션 —
askConfirm/showAlert/askChoice/showPrompt가table(제목 · 열 · 줄 · 열 강조 before/after · 「외 N개」) ·notice(아이콘 없는 notice 한 줄) ·footnote(맨 아래 작은 글자)를 받습니다. 표의emptyText(예: 「(비움)」)와 같은 칸은 취소선·굵게 없이 흐리게 그립니다. 순서는 본문 → 대상 → 표 → 안내 → 아래 한 줄. 표는 admin 의 표 칸 강제를 피해 격자로 그립니다. 예약된 변경의 실행 · 승인 · 미리보기 창이 처음 씁니다(페이지 안에 따로 두었던 확인 창은 지움). - 바 노티스
.ds-bar-notice신설 — 헤더 바로 아래 전체 폭 띠 알림입니다. notice 와 같은 색군이지만 선 없음 · 모서리 없음 · 상하 가운데이고, 축은 서로 독립입니다: 색 4종 · 글자 크기 3단계(12 · 13--md· 14--lg) · 아이콘 on/off · 버튼 최대 3개(__actions) · 닫기 X on/off(__close, 늘 윗줄 끝) · 배치 좌우/상하(--vertical, 버튼 묶음이 본문 아래 줄). Playground(<DemoBarNoticePlayground>)를 붙였습니다. admin 대시보드 「직원 앱 도입」 진행률 배너를 notice(ds-notice+rounded-none border-x-0)에서 옮겼습니다. - Notice 세로 정렬은 위 하나로 확정 — 버튼이 붙은 배너 때문에 한때 가운데로 바꿨다가, 여러 줄 notice 에서 아이콘이 첫 줄과 떨어져 되돌렸습니다(
align-items: flex-start· 아이콘margin-top: 1px, 이전과 같음). 가운데 정렬이 필요한 헤더 아래 띠는 바 노티스로 분리했습니다.
신규
- 채팅·AI 플로팅 버튼 스크롤 끝 여백
.ds-fab-safe/--ds-fab-clearance(108px) — 페이지 맨 아래 스크롤 상자 안쪽에 붙여, 평소엔 FAB 가 내용 위에 겹쳐 떠도 스크롤을 끝까지 내리면 마지막 줄·쪽 이동이 FAB 위로 올라와 온전히 보이게 합니다. admin 의 직원 관리 · 팀 관리 · 병동 · 병동 직원 · 연차 3표 · 근로시간 마감 2표 · 외근 · 정정 요청 · 문서 결재 · 문서 양식 · 전자 서명 · 설정 · 글로벌 파라미터 · 직원 앱 도입 · 예약된 변경에 적용했습니다(표 상자의pb-5를 대체). - 아이콘
ic-user-transfer—ic-user-arrow-right와 같은 그림(사람 → 화살표)을 표준 틀(0 0 24 24· 선 2)로 그린 것. 원본은 바깥 여백이 든 틀(-4 -4 32 32)이라 다른 24 아이콘 옆에서 75% 크기로 작아 보입니다. 기존 쓰임(팀 관리 · 직원 관리 · 병동 직원)은 그대로 둡니다.
2026-10-06 — 메신저 입력줄 여러 줄 · 연락처 프로필 (design/employeeapp-improvements)
신규
- 모바일 대화 화면 페이지 신설 (컴포넌트 — 커뮤니케이션) — 직원 앱 메신저 전체화면과 AI 어시스턴트 페이지 모드를 한 페이지로 분리했습니다. 두 화면 비교 표(들어가는 길 · 켜는 옵션 · 헤더 · 바탕 · 하단 내비 · 입력줄 · 모바일 전용 화면), 캡슐형 입력줄 상태 표, AI 첫 화면 구성(인사 · 업무 바로가기 · 예시 질문 · 바로 갈 수 있는 화면), 메신저 연락처 프로필, 페이지 모드 옵션 표, 라이브 데모(
<DemoMobileConversation>— 메신저 채팅방 · AI 첫 화면)를 담았습니다. 대화 UI 페이지의 캡슐형 입력줄 규칙 · 클래스 · 마크업은 이 페이지로 옮기고 링크만 남겼고, 메신저(화면 표에contactProfile추가) · AI 어시스턴트(이 페이지는 PC 도크 · 플로팅이라고 명시, 「admin 한 곳」 서술 정정) · 폼 컨트롤의 링크를 새 페이지로 돌렸습니다. 사이드바 「컴포넌트 — 커뮤니케이션」 을 내비게이션처럼 공통(대화 UI · 메신저) · 웹(채팅 위젯 · AI 어시스턴트) · 모바일(앱)(모바일 대화 화면) 세 묶음으로 나눴습니다.
변경
- 모바일 대화 화면 캡슐형 입력줄 — 보내기 버튼은 누를 수 있을 때만 보임 — 아무것도 안 쳤을 때(비활성) 흐린 버튼으로 남지 않고 자리째 빠져 입력칸이 넓어집니다(
.ds-composer--capsule .ds-composer__btn--send:disabled { display: none }). 글 없이 첨부만 있으면 버튼이 활성이라 보입니다. 직원 앱 메신저 · AI 어시스턴트에 적용되고, PC 채팅 위젯 · 관리자 AI 패널은 그대로입니다. - 폼 컨트롤 모바일 텍스트 필드 절 신설 — 직원 앱 입력칸을 다섯 경우로 정리했습니다: 폼 입력칸 ① 한 줄(
ds-input--48) ② 선택(ds-select--48) ③ 여러 줄(사유 · 메모 textarea)과, 따로 묶은 대화 입력줄 ④ 채팅(메신저 — 캡슐 + 첨부) ⑤ AI 어시스턴트(캡슐, 첨부 없음). 라이브 모음<DemoMobileTextFields>를 붙였고, 대화 입력줄 규칙의 정본은 대화 UI 페이지에 그대로 두고 여기서는 두 경우의 차이만 표로 적었습니다. 규칙(강제)에 「대화 입력줄은 폼 입력칸이 아니다(48 금지 · 캡슐형 사용)」 한 줄을 더했습니다. - 대화 UI 메신저 입력줄이 여러 줄(textarea) — 한 줄
<input>이던 칸이 줄이 넘치면 위로 자라고 다섯 줄에서 멈춰 안에서 스크롤합니다(직원 앱 화면 설정 「크게」는 네 줄). 새 규칙.ds-composer textarea.ds-composer__field.ds-input--40. Enter 는 PC 에서 전송(Shift+Enter 줄바꿈), 휴대폰 키보드에서는 줄바꿈이고 전송은 버튼입니다. 같은 템플릿을 쓰는 PC 채팅 위젯에도 함께 적용됩니다. 직원 앱 AI 어시스턴트(페이지 모드) 입력줄도 같은 규격(한 줄<input>→ textareads-input--40)이고, AI 패널/도크 포함 Enter 판정이 메신저와 같아졌습니다(shouldSendOnEnter). - 메신저 연락처 프로필 — 연락처를 누르면 바로 1:1 대신 사진 · 소속 · 역할 · 직무 · 직군 · 직위 · 이메일과 「1:1 채팅」 · 「전화하기」(병원이 전화번호를 공개할 때만, 관리자 「병원 설정 → 메신저 연락처 공개」)가 있는 화면이 먼저 열립니다. 아이콘
ic-phone추가.
2026-10-06 — 하단 내비 실행 버튼 · AI 어시스턴트 첫 화면 (design/employee-app-ai-button)
신규
- 대화 UI 캡슐형 입력줄
.ds-composer--capsule— 모바일(직원 앱 메신저 · AI 어시스턴트) 입력줄. 첨부 · 입력칸 · 보내기를 선 없는 둥근 캡슐 하나로 감싸고 모서리는--ds-composer-radius로 조절합니다. 포커스가 빠지면 한 줄 말줄임(.ds-composer__preview)으로 접히고, 포커스면 다섯 줄(「크게」 네 줄)까지 자랍니다. PC 채팅 위젯 · 관리자 AI 패널은 예전 입력줄 그대로입니다. 보내기 아이콘은 흰색이고(전역 비활성 버튼 회색 강제를 아이콘 칸에서 피함), 보낼 것이 없을 때는 버튼이 숨습니다(아래 「변경」 참고). AI 「바로 갈 수 있는 화면」 은 입력줄 위에 떠서 뒤 채팅과 겹치는 그림자(shadow-popover) 팝오버이고, 구분선 없이 줄마다 DS 버튼(solid · lightor · ml · 모서리 12,.ds-chat-menu-action)으로 아이콘 + 메뉴 이름이며, 아직 제공하지 않는 메뉴는 흐린 글자 + 「준비 중」 라벨로 보이고 눌러도 열리지 않습니다(AiMenuEntry.preparing). 캡슐 안 버튼은 40px 로 입력칸 한 줄과 같아 위·아래·좌우 여백이 4 로 같습니다. 첫 화면 업무 바로가기는 DS 버튼(solid · lightor · md · 모서리 12) +.ds-chat-start-action(글자만큼 폭)입니다. - 하단 내비게이션 분리형 + 실행 버튼
getAction/onAction— 실행 버튼을 주면 탭이 흰 캡슐(.ds-bottom-nav__tabs)로 뜨고, 그 오른쪽에 아이콘만 있는 BI 패밀리 그라디언트 원(.ds-bottom-nav__action, 56px)이 따로 섭니다(.ds-bottom-nav--split). 분리형의 선택된 탭은 주황 대신 글자·아이콘 neutral-700 + 바탕 neutral-75 입니다. 분리형 탭 아이콘은 20px, 라벨은 12px(b6)입니다. 하단 줄은 내용 위에 떠 있고, 탭 캡슐은 반투명 흰색 + 뒤 흐림이라 스크롤 내용이 캡슐 뒤로 흐리게 지나갑니다. 하단 줄 영역에는 화면 바탕색 그라데이션(--ds-bottom-nav-surface)이 깔려 맨 아래 내용이 녹아 사라집니다. 탭은 화면을 바꾸고 이 버튼은 무언가를 열어서 활성 상태가 없습니다. 직원 앱 「AI 어시스턴트」가 처음 씁니다. 넘기지 않으면 하단 내비는 예전과 같습니다. - 하단 내비게이션 문서 — 분리형 반영 — Playground 에 「실행 버튼 (분리형)」 축을 더하고(기본 켬) 모아보기 첫 칸을 분리형으로, 구조도를 한 줄형 · 분리형 두 벌로 나눴습니다. 사용법에
getAction호출 예시, 「앱 소유로 남는 것」 에 실행 버튼 정의 · 그라데이션 끝 색 · 스크롤 끝 여백 · 크기 고정을 더했습니다. 규칙(강제) 정정: 직원 앱 분리형 내비는 화면 설정과 무관하게 「기본」 크기로 고정됩니다(앱--app-nav-zoom반대 배율 — 72px 에 기대는 여백도 같은 배율을 곱함). 분리형 여부는:has()가 아니라 호스트가 켜는 body 클래스로 읽습니다. - AI 어시스턴트 페이지 모드 첫 화면 옵션 —
getStartActions(업무 바로가기) ·examplePrompts(예시 질문) ·getMenuCatalog(입력하는 동안 AI 없이 메뉴 맞추기 → 입력줄 위 「바로 갈 수 있는 화면」) ·onStartAction·composerPlaceholder. 페이지 모드는 여기에 더해startBrandIcon·startHeading(맨 위 「BI 심볼 + AI」 와 질문), 업무 바로가기는 한 줄에 하나씩 왼쪽 정렬된 DS 버튼(solid · lightor · md · 모서리 12), 예시 질문은 입력칸을 눌렀고 첫 질문 전일 때만 입력줄 위에 뜨고, 입력줄은 메신저와 같은 캡슐형(textareads-input--40)입니다. 위젯 안쪽 제목줄은 그리지 않습니다(제목·이전 대화는 앱 헤더가 진다). 옵션을 주지 않는 관리자·인사 앱 어시스턴트는 그대로입니다.
2026-10-02 — 앱 헤더 아이콘 크기 통일 · 알림 아이콘 교체 (design/employeeapp-improvements)
변경
- 알림 아이콘
ic-bell모양 교체 — 각진 종 → 둥근 몸통 · 넓은 밑판 · 반원 추(선 굵기 2, 끝·이음 둥글게). 짝인ic-bell-fill도 같은 외형(몸통 채움 + 같은 굵기 외곽선, 추는 반원 채움)으로 다시 그렸습니다. 레지스트리 한 곳(아이콘)만 바꿨으므로 admin · 총무 · 직원 앱 등 이 이름을 부르는 모든 화면에 함께 반영돼요. - 앱 헤더 우측 아이콘 버튼을
lg→md— 알림벨(md, 글리프 20)과 나란히 놓인 액션 아이콘(그룹 대화 + 등)만lg(24)라 20% 크고 선도 굵어 보였습니다. 우측 액션과 탭 줄 오른쪽 액션(getTabActions)을md로 맞췄어요. 문서에 남아 있던 「벨 24 강제」 설명(7월에 삭제된 규칙)도 고쳤습니다.
2026-10-02 — 입력칸 전용 모서리 축 ds-field-r-* (design/employeeapp-improvements)
신규
- 폼 컨트롤
ds-field-r-4/8/12/16— 입력칸(input · textarea)과 드롭다운(select)의 모서리만 바꾸는 축입니다. 버튼은 건드리지 않아요. 기존ds-r-*는 버튼과 텍스트필드를 같이 바꾸지만 select 는 따라오지 않아, 한 폼 안에서 입력칸과 드롭다운 모서리가 어긋났습니다.
변경
- 직원 앱 신청서 · 보고서 · 내 정보 등의 입력칸에 손으로 붙어 있던
border·rounded-xl·px-*·focus:*유틸을 걷었습니다. DS 규칙이 이겨 원래 적용되지 않던 값이라 화면은 그대로(4px)입니다.
2026-10-02 — 서브탭 업데이트 점 (design/employeeapp-improvements)
신규
- 서브탭
updateDot슬롯 — 탭 오른쪽 위 모서리에 「새로 생긴 것이 있다」 점(.ds-sub-tab__dot· 6px)을 붙입니다. 색은 TabNav 점과 같은 주황이에요. 직원 앱 결재 「내 신청·결재 현황」의 「반려」 서브탭이 처음 씁니다(아직 확인하지 않은 반려가 있을 때).
2026-10-01 — 게이트 화면 패턴 문서 · 태그 기본값 규칙 · 데모 동기화 (design/improve-gate-error-pages)
신규
- 게이트 화면 패턴 문서 — 로그인 · 비밀번호 · 가입 · 초대 · 허브 · 접근 불가 · 404 · 직원 앱 업데이트 차단·배너의 규격(제목 h3 · 부제 8/B4 · 입력칸 48 · 카피라이트 12 · 접근 불가 = 404 규격 · 직원 앱 40:60)을 한곳에 모음.
변경
- 타이포그래피 규칙에 「태그 기본값이 클래스를 이긴다」 추가 —
h1·p에text-*·mt-*를 붙이면 조용히 무시된다. 제목은div role="heading", 본문은div. - 모서리 —
ds-r-*가 텍스트필드에도 적용됨을 기초 문서·이력에 반영. 브랜드 락업 표에 Sign 락업과 워크스페이스 허브 사용처 반영. - docs 데모 동기화 — 로그인 · 비밀번호 찾기·변경 · 가입 데모를 실제 화면과 같게(제목 h3 · 부제 B4 ·
ds-input--48·.ds-form-error). Notice 플레이그라운드에 「버튼 배치(없음 · 좌우 · 상하)」 선택 추가. 데모 shim 에text-h3·mt-2추가.
2026-10-01 — 직원 앱 가입 락업 Works 로 · 게이트 부제 8 · B4 (design/improve-gate-error-pages)
변경
- 직원 앱 가입 화면 락업이 hereby Works 하나가 됐습니다 — 이전에는 연동되는 상위 서비스(
linkedBrandFamily: "medical")의 Medical 락업 아래hereby Works글자를 두어, 같은 앱 로그인(Works 심볼)과 다른 브랜드로 보였습니다. 직원 앱 설정에서linkedBrandFamily를 뺐고, 공용RegisterForm의 상위 서비스 축은 다른 앱을 위해 남겼습니다 → 회원가입 폼 - 게이트 화면 제목 아래 부제는 8px 아래 · B4(14px) 입니다(로그인 · 비밀번호 찾기 · 비밀번호 변경 · 가입 · 이메일 인증 · 시스템 어드민). 대부분
p태그 기본값 때문에 간격 0 · 16px 였습니다. - 직원 앱의 세로 정렬 화면(로그인 · 비밀번호 찾기·변경 · 조직 선택 · 업데이트 차단)은 위아래 빈 공간을 40:60 으로 둡니다(
.app-vbias). 가운데 정렬은 위 아이콘·로고 때문에 아래로 처져 보였습니다. 가입은 폼이 길어 제외합니다.
2026-10-01 — notice 버튼 배치(좌우·상하) · 모서리 축이 텍스트필드까지 (design/improve-gate-error-pages)
신규
.ds-notice__body·.ds-notice__actions·.ds-notice--vertical— 버튼이 붙는 notice의 배치를 좌우(기본)와 상하 둘로 정했습니다. 직원 앱 「버전 확인 실패」·「새 버전 준비됨」 배너가 상하를 씁니다(본문 위 · 버튼 아래 전체 폭) → Notice
변경
- 모서리 축
ds-r-*가 텍스트필드에도 적용됩니다 —--ds-btn-radius와 함께--ds-textfield-radius를 세팅합니다. 모바일 로그인(직원 앱·급여)과 도메인 설정 팝업은 버튼이 16 이라 입력칸도 16 이 됐습니다 → 버튼 → 모서리 - 직원 앱 「앱 업데이트가 필요해요」 화면: 제목 h3 · 설명 b4 · 아이콘·제목·설명 사이 12, 내용 묶음은 화면 세로 가운데.
2026-10-01 — 게이트 화면 제목 h3 · 카피라이트 간격 12 (design/improve-gate-error-pages)
변경
- 게이트 화면의 제목을 전부 h3(24px · 600)으로 맞췄습니다 — 로그인·비밀번호 찾기·비밀번호 변경(공용 폼 3종), admin 가입·이메일 인증·초대 수락·워크스페이스 허브·접근 불가, 시스템 어드민 로그인·접근 신청·인증 완료, 공용 404 페이지. 전에는
h1태그 기본값 32px가 적힌 클래스(text-2xl·text-h3)를 덮어 대부분 32px로 보였습니다 → 로그인 폼 - 카드 아래 카피라이트(
© 2026 hereby)와 카드 사이를 12px로 통일했습니다(앱 34곳).p태그 기본값이 여백·크기를 덮어mt-4가 먹지 않던 것을div+text-b6+mt-3으로 바꿨습니다. - 워크스페이스 허브 상단의
hereby글자를 BI 자산(이 앱의 패밀리 락업, 가입 화면과 같은 것)으로 바꿨습니다 → 브랜드 - 게이트 화면 입력칸을
ds-input--48하나로 통일했습니다(49곳) — 기준은 직원 앱 「도메인 설정」 팝업 입력칸(48 · 모서리 4 · 좌우 16 · 14px). 손으로 붙인rounded-lg·h-10·border-*·focus:*유틸을 걷었습니다. 모서리가 10px 로 버튼(4px)과 어긋나고, 높이가 화면마다 32/40/48 로 섞여 있었습니다. 오류 테두리는ds-input--error→ 폼 컨트롤
함정
h1·h2·p태그에 크기·여백 클래스를 붙이지 않습니다.tokens.css의 태그 기본값이 레이어 밖이라 클래스를 이깁니다. 제목은div role="heading" aria-level, 본문은div로 둡니다.
2026-10-01 — 비밀번호 변경 폼: 안내·검사를 병원 설정으로 (fix/password-guide-follows-org-policy)
변경
- 새 비밀번호 칸의 안내(placeholder)와 검사가 병원 설정의 일반 비밀번호 규칙을 따릅니다 — 「8자 이상, 대소문자+숫자+특수문자」를 박아 두던 것을
describeUserPasswordPolicy·userPasswordPolicyError(@hereby/core/constants)로 바꿨습니다. 병원이 최소 길이를 4로 낮추면 칸에는 「4자 이상」이 뜨고, 4자 비밀번호도 통과합니다 → 비밀번호 변경 폼 - 규칙은 로그인 응답과
auth.me의currentUser.passwordPolicy로 옵니다. 서버(auth.changePassword)도 같은 함수를 거쳐 문구·특수문자 기준이 화면과 같습니다(영문·숫자가 아닌 문자는 모두 특수문자). - 문서 데모(
DemoPasswordForm)의 안내도 설정을 안 바꾼 병원의 실제 문구 「8자 이상, 대문자·소문자·숫자·특수문자 포함」으로 맞췄습니다. - 회원가입 폼(
RegisterForm· admin 가입)도 같은 함수의 기본 규칙으로 안내·검사합니다 — 예전에는@$!%*?&일곱 글자만 특수문자로 인정해 다른 화면과 기준이 달랐고, 서버 거절 문구는 영문이었습니다. 데모(DemoSignupForm) 안내도 맞췄습니다 → 회원가입 폼 - 규칙 변경 안내 한 줄 — 회원가입 폼과 첫 로그인 비밀번호 변경(규칙을 바꿀 수 있는 사람에게만) 비밀번호 칸 아래에
.ds-form-help「비밀번호 규칙은 이후 설정에서 변경할 수 있어요.」를 둡니다. 처음 보는 기본 규칙(8자 · 네 종류)이 고정이라고 오해하지 않게 합니다 → 비밀번호 변경 폼
함정
- 안내 문구에 숫자를 직접 쓰지 않습니다. 숫자를 박으면 병원이 설정을 바꿔도 안내만 옛 값으로 남고, 화면 검사까지 숫자를 박으면 설정이 아예 안 먹습니다(실제로 첫 로그인 강제 변경이 4자 설정을 무시하고 8자로 막고 있었습니다).
- 회원가입 폼은 아직 병원이 없어서 기본 규칙(8자 · 네 종류)을 그대로 안내합니다 — 같은 함수에 설정 없이 넘긴 것과 같습니다.
2026-09-29 — 아이콘 추가: 세로 점 세 개 (design/improve-sheet-uxui)
신규
ic-dots-vertical— 세로로 놓인 점 세 개(⋮). 시트 서식 도구 모음의 「더보기」 단추에 씁니다 — 한 줄에 들어가지 않는 묶음을 오른쪽 끝부터 이 단추의 판으로 옮깁니다(구글 시트와 같은 자리·모양) → 아이콘
함정
ic-dots-horizontal(…) 과 뜻을 나누지 않습니다 — 방향만 다릅니다. 가로 점은 줄 안의 「더 있음」(목록 항목의 기타 동작), 세로 점은 막대 끝의 「넘친 도구 더보기」로 씁니다. 한 자리에 둘을 섞지 않습니다.
2026-09-23 — 아이콘 추가: 확장·축소 화살표 (design/improve-sheet-uxui)
신규
ic-expand— 네 모서리로 뻗는 확장 화살표. 시트 임베드의 「시트 전체화면으로 보기」 버튼에 씁니다 → 아이콘ic-collapse— 그 짝. 네 모서리에서 가운데로 모입니다. 전체화면 종료 버튼에 씁니다.
변경
- 전체화면 진입·종료 버튼(시트·스케줄러)이 모두 화살표 계열로 통일됐습니다. 한 쌍을 꺾쇠·화살표로 갈라 두지 않습니다 — 같은 동작의 켜고 끄기인데 그림의 계열이 다르면 서로 다른 기능처럼 읽힙니다.
함정
ic-maximize와 뜻이 겹치지 않습니다 — 그림이 다릅니다. 꺾쇠(ic-maximize)는 「여기까지가 화면」이라는 범위 표시고, 화살표(ic-expand)는 「넓어진다」는 동작입니다. 전체화면 진입처럼 누르면 무엇이 일어나는지 말해야 하는 자리에는 화살표를 씁니다. 한 의미에 한 쌍 규칙을 어기는 중복이 아닙니다.
2026-09-23 — hereby Sign 락업 등록 (design/improve-sheet-uxui)
신규
logo-lockup-hereby-sign(702×130) — 패밀리 영문 락업 3종 중 Sign 만 레지스트리에 없었습니다. 가입 화면은 이름을 조립해서 부르므로(getIcon(\logo-lockup-hereby-${family}`)) Sign 패밀리 앱에서는 **락업이 통째로 빈 채** 떴을 자리였습니다 —getIcon()` 은 없는 이름에 빈 문자열을 돌려줍니다 → 브랜드- 좌표·그라디언트는 새로 그린 것이 아니라 BI 데모(
DemoBrandLogo.vue)의 정본 상수에서 왔습니다. 같은 레시피로 medical·works 락업을 다시 만들면 기존 등록본과 한 글자도 다르지 않습니다(대조 확인). 락업은 「컨테이너(그라디언트) + 컨테이너·심볼을 합친 evenodd 흰 면 +hereby+ 서비스명」 네 겹입니다.
함정
pnpm check:icons는 이름을 이어 붙이는 호출을 일부러 건너뜁니다 —getIcon("logo-lockup-hereby-" + family)의 조각은 이름이 아니기 때문입니다. 그래서 패밀리 자산이 빠져도 게이트는 통과합니다. 대신icons.test.ts가 패밀리 3종의 심볼·락업·130 높이 비율을 확인합니다 — 새 패밀리를 추가하면 그 목록에 함께 넣습니다.
2026-09-23 — LNB 문서 예시의 죽은 아이콘 이름 교정 (design/improve-sheet-uxui)
변경
- LNB 사이드바 문서의
lnbConfig예시가 레지스트리에 없는 이름 5개를 쓰고 있었습니다 —ic-org·ic-role·ic-payroll·ic-allow·ic-leave. 실제 admin LNB 가 쓰는 이름으로 바꿨습니다(ic-organization·ic-id-card·ic-money·ic-cash·ic-calendar-check) → LNB 사이드바
함정
pnpm check:icons는.md를 보지 않습니다. 게이트가 훑는 것은.ts/.tsx/.html/.vue뿐이라, 문서 안 예시는 죽은 이름이어도 통과합니다. 그대로 복사해 가면getIcon()이 빈 문자열을 돌려주어 아이콘만 조용히 사라집니다(에러도 로그도 없음). 문서에 아이콘 이름을 적을 때는 아이콘 갤러리에서 확인하고 적습니다.- 변경 이력·과거 설계서에 남은 옛 이름(
ic-info→ic-info-circle통합 기록 등)은 역사라 그대로 둡니다 — 예시가 아니라 기록입니다.
2026-09-22 — 아이콘 추가: 셀 병합 · 서식 복사 (design/improve-sheet-uxui)
신규
ic-cell-merge— 셀 병합. 구글 시트 툴바의 셀 병합과 같은 모양(네 귀퉁이 꺾쇠 + 가운데로 모이는 화살표 두 개)을 선 아이콘(24 · stroke 2)으로 그렸습니다. 시트 서식 툴바의 병합 버튼에 씁니다 → 아이콘ic-paint-roller— 서식 복사(페인트 롤러). 시트 서식 툴바의 서식 복사 버튼에 씁니다. 같은 브랜치의 앞선 작업에서 레지스트리에 들어갔는데 이 페이지에 적지 않아 함께 남깁니다.
함정
- 아이콘 갤러리는 레지스트리(
packages/components/src/icons.ts)를 그대로 읽어 목록을 만듭니다 — 레지스트리에 넣으면 갤러리에 바로 나오고, 여기 이력만 따로 남기면 됩니다.
2026-09-22 — 임베드 시트의 「시트 어시스턴트」 FAB 복구 (fix/sheet-assistant-embed-fab)
변경
- 임베드(iframe) FAB 숨김에 예외가 생겼습니다 —
.ds-fab-embed-owner. 부모가 자기 AI 위젯을 치우고 자식에게 화면을 맡기는 경우(admin 급여 관리 › 시트 → hr-system 「시트 어시스턴트」), 자식 위젯 래퍼에 이 클래스를 달면 AI FAB·패널만.ds-embedded숨김에서 빠집니다. 채팅 FAB 은 예외 없음 → FAB 배치 계약 - 임베드 안에서 어시스턴트가 도크로 열리면 부모 FAB 도 비킵니다. 공용 위젯이
hereby:tm:ai-dock({ open, width })을 부모에 보내고, admin 이body의--ds-embed-ai-dock-w로 받아--ds-fab-dodge에 더합니다(레일 320px 와 합산)
함정
- 부모가 감추는 결정과 자식의
.ds-fab-embed-owner는 한 쌍입니다. 2026-09-04 도크 작업이.ds-embedded .ds-fab--ai를 숨기고, 2026-09-22 CS 수정이 admin 위젯을 시트 임베드에서suspended로 감추면서 서로 상대가 그린다고 믿어 임베드 시트에 AI 진입점이 하나도 남지 않았습니다(QA 리포트). 한쪽을 손대면 반드시 다른 쪽을 같이 봅니다 - iframe 안 CSS 는 부모 FAB 에 닿지 않습니다 — 도크 폭(
--ds-ai-dock-w)·body.ds-ai-dock-open은 iframe 문서 안의 값입니다. 부모가 알아야 할 것은 전부hereby:tm:*postMessage 로 보냅니다(레일 →rail, 도크 →ai-dock)
2026-09-22 — 라벨 말줄임 변형 · DS CSS 에서 :has() 제거 (fix/admin-employee-shift-badge-perf)
신규
.ds-label--trunc— 폭이 정해진 표 셀의 긴 라벨을 말줄임. 글자는.ds-label__text로 감싸고 전체 텍스트는title(툴팁)이 진다 → 라벨. admin 직원 관리 근무형태 칸에 적용(이름이 옆 칸까지 넘치던 CS-OKBEST-260922-0004).
변경
- DS CSS 와 앱 main.css 에서
:has()를 모두 걷어냈습니다. Blink 는:has()규칙이 하나라도 있으면 문서 어디서든 DOM 이 바뀔 때마다 문서 전체 스타일을 다시 계산합니다 — admin 직원 목록(368행)에서 툴팁 라벨 교체 1회 130ms, x-show 토글 1회 70~130ms 로 실측됐고(근무형태 출처를 hover 하며 스크롤하면 버벅이던 CS-OKBEST-260922-0003), 규칙을 전부 걷어내면 0ms 입니다. 판정은 JS 가 하고 CSS 는 결과 클래스만 받습니다:.has-ico(필터 바 · 탭 줄 우측 버튼,setupFilterBar()/TabNav) ·.has-underline(공유 탭 템플릿) ·.has-icon(옵션 카드 제목 마크업) ·body.ds-has-ai-fab(AI 어시스턴트) ·body.ds-backdrop-open(신고 FAB, backdrop-watch) ·.has-table(표 래퍼,setupTableHost()). - 툴팁 라벨 교체가 텍스트 노드의
data만 바꿉니다(textContent교체 대신). 자식을 갈아 끼우는 변경이 위의 재계산을 부르던 경로라,:has()가 남은 문서(외부 CSS)에서도 툴팁은 싸게 움직입니다.
함정
- 옵션 카드 제목에 아이콘을 넣을 땐
has-icon을 같이 답니다 — 빠지면 아이콘과 제목이 세로로 쌓입니다. - 커스텀 탭 nav 가
.ds-tab-underlinespan 을 직접 렌더한다면 탭 요소에has-underline을 답니다 — 없으면 이중 밑줄.
2026-09-28 — 권한 미리보기 배너가 화면을 내린다 (fix/impersonation-banner-offset)
변경
- 배너가 보이는 동안
body.ds-impersonating이 화면을 배너 높이(--ds-impersonation-banner-h28px)만큼 내립니다. 배너는 fixed 띠라 예전엔 그냥 얹혀 admin 헤더의 알림·닫기, 시트 툴바처럼 화면 맨 위 버튼을 눌러도 배너가 먹었습니다. 컴포넌트(ImpersonationBanner.ts)가 클래스를 달고 떼며,--ds-impersonation-offset은 평소 0px · 미리보기 중 배너 높이입니다.
함정
100vh/100dvh로 높이를 잡는 셸은 body 패딩만으로 그만큼 넘칩니다 — admin.app-shell, hr-system<main>, 직원 앱.app-container(배율·키보드 보정 포함)는calc(100vh - var(--ds-impersonation-offset, 0px))로 뺍니다. 새 앱 셸도 같은 식으로 잡으세요.- 뷰포트에 붙는 sticky 헤더(
sticky top-0)는.ds-impersonation-offset-top을 답니다(team-manager 헤더 줄). 스크롤 컨테이너 안의 sticky(표 머리글·admin 페이지 헤더)는 배너와 무관하니 달지 않습니다.
2026-09-28 — 권한 미리보기 배너 층 (feat/permission-preview-impersonation)
신규
--ds-z-impersonation-banner: 76·.ds-impersonation-banner— 시스템 관리자가 직원 권한으로 보는 중임을 알리는 상단 띠. 모든 팝업(권한 요청 75 포함) 위에 둔다. 대상 직원에게 권한이 없어 권한 요청 팝업이 화면을 덮는 순간이 관리자가 「종료」로 빠져나가야 하는 순간이기 때문이다(hr-system 실측). 한 줄 띠라 팝업 본문을 가리지 않는다.
2026-09-21 — 메뉴 패널 검색 줄 · 직원 소속 피커 활성 항목만 (fix/employee-affiliation-picker-active-search)
신규
.ds-menu__search— 항목이 많은.ds-menu피커 맨 위의 검색 줄(스크롤해도 붙어 있음) → 메뉴 패널
변경
- 직원 소속 칩의 팀 · 역할 피커와 「소속 추가」 메뉴가 활성 팀 · 역할만 보여 줍니다. 비활성 팀은 하위 팀까지 함께 숨고, 지금 그 소속에 붙어 있는 값만 비활성이라도 남아 선택 표시가 유지됩니다. 검색 중엔 팀 트리의 접기 · 계층을 무시하고 이름이 맞는 팀을 평평하게 보여 줍니다(관리자 직원 관리 · 직원 수정 패널 공통).
2026-09-18 — 체크박스 「일부 선택」 상태 · 메신저 연락처 팀별 묶음 (design/chat-contact-grouping)
신규
- 체크박스에 「일부 선택」(indeterminate) 모양이 생겼습니다. 채움은 「선택됨」과 같고 글리프가 가로 막대입니다. 팀 · 전체 선택처럼 여러 항목을 한꺼번에 고르는 체크박스에서 「몇 개만 골랐다」를 보여 줍니다 → 일부 선택
- 메신저 연락처가 팀별로 묶입니다. 그룹 대화 선택과 초대하기에서 팀 머리 체크박스로 그 팀을 한꺼번에 고르고, 목록 위 「전체 선택」으로 보이는 사람을 모두 고릅니다.
변경
- 연차 촉진 표 머리의 전체 선택 체크박스는 이미
indeterminate를 넣고 있었지만 모양이 없어 빈 칸으로 보였습니다. 이제 일부만 골랐을 때 막대로 보입니다.
함정
indeterminate는 HTML 속성이 아닙니다. 마크업에 적거나 Alpine:indeterminate로 묶어도 들어가지 않으니x-effect로$el.indeterminate를 넣어야 합니다.
2026-09-17 — 선택 + 비활성 체크박스 · 라디오가 빈 칸으로 보이던 문제 (fix/ward-auto-assign-schedule-group)
변경
- 켜진 채 잠긴 체크박스 · 라디오가 켜진 모양으로 보입니다. 검정 채움 + 흰 체크(흰 점)를 유지하고 45% 로만 흐립니다 → 체크박스 · 라디오
- 비활성 배경(
--ds-color-bg-alt)은:disabled:not(:checked)에만 칠합니다. 체크박스 · 라디오 둘 다 같은 규칙입니다. - 데모에 「선택됨 + disabled」를 추가했습니다.
함정
background한 줄은background-image까지 지웁니다. 체크 글리프가 배경 그림이라,:disabled::before { background: … }가:checked::before보다 뒤에 있고 명시도가 같아 이기면서 체크가 통째로 사라졌습니다. 문서 양식 「신청 시 입력 항목」의 「용도 · 항상」(사용 · 필수가 켜진 채 잠김)이 꺼진 것처럼 보여 발견했습니다 — DOM 의checked는 true 였습니다.
2026-09-17 — 채팅 새 메시지 브라우저 탭 알림 (feat/chat-unread-tab-alert)
변경
- 새 채팅 메시지를 확인하지 않았으면 탭 제목이 「신규 메시지가 도착했습니다.」로 바뀌고 파비콘이 움직입니다 — 파비콘은 채운 말풍선 아이콘(
ic-message-fill)에 오른쪽 위 작은 빨간 점이 붙고, 말풍선이 primary ↔ dark 색으로 번갈아 바뀝니다(원 없음). 새 메시지가 온 방을 모두 확인하면 원래 제목·파비콘으로 돌아옵니다. 채팅 위젯이 있는 7개 앱(admin · hr-system · team-manager · general-affairs · inventory · management-dashboard · module-manager)에 적용됩니다 → 채팅 위젯 · 브라우저 탭 알림 - 확인 안 한 새 메시지가 있는 동안 채팅 FAB 이 2초마다 통통 튑니다(
.ds-fab--bounce) — 그 메시지를 확인하거나 패널을 한 번 열어 보면 멈추고, 새 메시지가 또 오면 다시 튑니다. 마우스를 올리면 잠시 멈추고,prefers-reduced-motion이면 튀지 않습니다 - 알림 파비콘은 PNG 로 그려 사파리 탭에도 뜹니다 — 사파리는 SVG 파비콘을 탭에 그리지 않습니다
- 채팅 패널을 한 번도 열지 않아도 새 메시지를 실시간으로 받습니다 — 종전에는 패널을 열기 전까지 60초 주기 조회로만 배지가 따라왔습니다
함정
- 메시지 한 건에 미확인 수가 2 씩 올랐습니다 — 위젯 앱에서 실시간 수신을 직접 처리하고 같은 이벤트를 다시 받아 한 번 더 처리했습니다(재현: 0 → 2). 토큰 갱신으로 재접속할 때마다 리스너도 하나씩 늘었습니다. 구독을 한 벌로 묶었습니다
- 방을 열어 둔 채 패널을 닫거나 다른 탭으로 가면 새 메시지가 곧바로 「읽음」이 됐습니다 — 로컬·서버 미확인이 모두 0 으로 남아(재현) 탭 알림이 뜰 수 없었습니다. 이제 방이 실제로 보일 때만 읽음 처리하고, 탭으로 돌아오거나 패널을 다시 열 때 읽음으로 넘깁니다
2026-09-17 — 최근 머지된 기능으로 유저가이드의 틀린 절차를 고쳤습니다 (docs/guide-recent-prs)
유저가이드 본문과 영상은 9/10 코드 기준으로 정비됐습니다. 그 뒤 develop 에 머지된 PR 79개를 가이드와 대조해 22개가 갱신이 필요했고, 그중 지금 가이드대로 하면 화면과 달라지는 5개를 먼저 고쳤습니다.
⚠️ 사용자 가이드 — 외부 원고를 직접 고쳤습니다 (콸 리뷰 필요)
guide-admin.html · guide-nurse-scheduler.html · guide-employee-app.html 는 외부 PM 팀(콸/카나) 납품 원고입니다. 다음 재납품 때 되돌아가므로 원고에 반영이 필요합니다. 전부 코드와 로컬 화면으로 대조했습니다.
| PR | 고치기 전 | 실제 |
|---|---|---|
| #663 | 전자서명: 「직원 검색」→「템플릿 검색」→「전송」 | [서명 요청 보내기] 2단계 창(직원 → 계약서 템플릿) → Hereby Sign 작성 화면이 새 창으로 열림. 툴바에 목록 검색·[계약서 템플릿]·[계약서 추가하기] |
| #749 | 직원 등록: 소속은 선택, 근무 그룹 「그룹 미지정」 가능 | 소속·근무 그룹·직무 필수, 소속 팀마다 근무 줄, 팀 「대표 근무」 자동 선택, 소속이 둘 이상이면 주 소속의 근무가 출퇴근·연차 기준 |
| #656 | 문서 양식 변수 34종 · 직원 앱 서류 요청은 유형+파일/메모 | 증명서 양식에 「신청 시 입력 항목」(용도·제출처·주소·수량·비고), 변수 37종, 결재 화면에 신청 정보·발급될 증명서, 승인 즉시 발급. 직원 앱은 증명서 양식을 고르면 「신청 정보」 칸 |
| #700 | 연차 현황 「관리」 열에 「상세」·「조정」 글자 버튼 | 아이콘 버튼 + 툴팁, 촉진 버튼 이름이 진행 상태에 따라 바뀜 |
| #733 | 간호 스케줄러를 병동 단위로 설명 | 병동 안에 스케줄러가 여러 개 — 명부·근무표·교대 매핑·교육 정책은 스케줄러별, 환자수·간호등급·최소 인원은 병동 합산, 「겸임 중복 N」 경고 |
스케줄러 가이드의 자동등록 설명(「간호 직무로 거르지 않으니 직접 확인」)은 원래부터 틀린 문장이라 함께 고쳤습니다.
중괄호가 사라지던 문장(9/17 추가). 문서 양식 절에 옮겨 적은 화면 안내 「본문의 {{용도}} {{제출처}} … 자리에 들어가요」가 사이트에서 「본문의 자리에」로 나왔습니다. VitePress 는 이중 중괄호를 Vue 표현식으로 읽어 빈 값으로 그리고, vitepress build 도 통과합니다. 원고에서 중괄호를 문자 참조 {{용도}} 로 적어 사이트와 납품 HTML 모두 중괄호가 보이게 했습니다. 원고와 docs 페이지에 이중 중괄호를 쓸 때는 인라인 코드 안이라도 같은 방식으로 적어야 합니다 — 인라인 코드 안이라도 이름처럼 읽히면 빈 칸으로 사라지고(DS 문서 my-info-form 과 이 변경 이력의 서명 자리 표기 2곳이 그렇게 비어 보여 함께 고쳤습니다), 표현식으로 읽을 수 없는 글자가 들어가면 빌드가 실패합니다.
스크린샷
ad-01-hr · ad-12 · ad-15-form · ns-01 · ns-04 를 다시 찍고, 교대 매핑 절에 인력 설정 그림(ns-03)이 잘못 들어가 있어 ns-03-shifts 를 새로 넣었습니다. 전자서명 발송 창은 찍지 못했습니다 — 로컬 더미 조직에 Hereby Sign 연동이 없어 연동 안내만 보입니다(기존 ad-18-esign 은 그 안내 화면이라 그대로 맞음).
영상은 그대로입니다
전자서명(admin-esign-gate)·스케줄러 절 영상은 옛 화면입니다. 영상은 CDN 업로드 경로가 있어야 바꿀 수 있어 이번에는 글과 스크린샷만 고쳤습니다.
남은 갱신 (이번 범위 밖)
2순위(새 기능 미반영): 전체 근무기록(#729) · 산정 기준 보기·퇴직 시 입사일 기준 잔여(#689) · 급여 지급 대상(#722) · 시트 접근 권한(#728) · 연차 신청 리스트 반영(#736) · 시트 링크 복사(#676) · 직원 대량 업로드(#666·#671). 3순위: 목록 기본 필터 활성(#673·#699·#665) · 촉진 서식 없음 안내(#681) 등.
2026-09-17 — 탭 바가 좁아질 때: 셰브론과 버튼 아이콘화 (design/ui-improve-table-filter)
변경
- 탭이 넘치면 좌우
<>로 넘깁니다 — 공용 탭 바(tab-nav.html·TabNav.ts)가 넘치는 방향에만 셰브론과 가장자리 페이드를 띄우고, 잘려 있던 탭을 누르면 보이게 당깁니다. 스크롤바는 숨깁니다 → 탭 바 · 좁아질 때 - 탭 바 오른쪽 버튼은
.ds-tab-nav-row로 나란히 둡니다 — 근태 현황·스케줄러는 버튼을 탭 바 위에 absolute 로 겹쳐 올려, 400px 에서 「근무 설정」이 「외근」·「근로시간 마감」 글자를 덮었습니다. 이제 좁아지면 ① 버튼이 아이콘만 남고(라벨은 툴팁) ② 그래도 넘치면 탭이 스크롤됩니다
함정
- 탭 스크롤 박스는 활성 밑줄을 세로로 자릅니다 — 그래서
.tabnav-unclip(overflow visible)이 생겼는데, 그러면 스크롤도 셰브론도 꺼집니다. 스크롤 박스 아래로 4px 여유 + 같은 값의 음수 마진을 줘서 밑줄(2px)이 온전히 보이게 했습니다. 설정·문서 결재 탭 바는 변경 전후 높이·밑줄 위치가 같음을 확인했습니다
2026-09-17 — 필터 바 아이콘 버튼의 이름 유지 (design/ui-improve-table-filter)
변경
- 좁은 화면에서 아이콘만 남은 버튼이 원래 이름으로 읽힙니다 — 라벨을
display: none으로 숨기던 것을 눈에서만 숨기는 방식(visually-hidden)으로 바꿨습니다. 겉모습(32×32 아이콘 버튼)은 같습니다 → 필터 바 · 트랩
함정
display: none은 접근 이름까지 지웁니다 — 라벨이 사라지면 브라우저가title을 이름으로 씁니다. 직원 관리 「신규 직원 추가」가 1280px 에서 「신규 멤버를 추가합니다.」로 읽혀 e2e(admin-add-employee)가 버튼을 못 찾았습니다(재현 후 수정, 같은 스펙 3건 통과)
2026-09-16 — 좁은 화면의 표 가로 스크롤 · 페이지 트리 서랍 (design/ui-improve-table-filter)
변경
- 공지·드라이브 표가 좁은 화면에서 칸을 누르지 않고 가로 스크롤로 넘어갑니다 — 최소 폭이 없어 공지는 768px 부터 「카테고리」 머리글이 꺾이고 「무기한」이 한 글자씩 세로로 쌓였고, 드라이브는 900px 아래에서 「이름」 칸이 39px 까지 눌렸습니다. 표에
min-width(공지 780px · 드라이브 640px, 내용 폭 실측) +whitespace-nowrap을 줬습니다. 넓은 화면의 열 폭은 그대로입니다 → 데이터 테이블 · 가로 스크롤바 - 팀 관리 조직 트리 · 드라이브 폴더 트리가 768px 미만에서 서랍이 됩니다 — 트리가 좁은 화면에서도 폭(180~480px)을 계속 차지해 400px 에서 본문이 160~180px 만 남았습니다(병동 현황 카드 글자가 세로로 쌓임 · 드라이브 검색이 한 글자 폭). LNB 드로어와 같은 전환선(md)·같은 방식(fixed + translateX, 딤
--ds-dim-40, z 49/50)으로, 본문 위 「팀 목록」·「폴더 목록」 버튼으로 열고 딤 탭·항목 선택·Esc 로 닫습니다. 768px 이상은 지금처럼 옆에 둡니다
함정
- 드라이브는 iframe 이라 전환선이 iframe 폭 기준입니다 — admin 이 레일(68px)인 폭에서는 화면 836px 미만부터 드라이브 트리가 서랍이 되고, 같은 화면 폭의 팀 관리(admin 본체)는 768px 까지 옆에 둡니다. 각자 자기에게 남은 폭으로 판단하는 것이라 의도된 차이입니다
- 서랍 CSS 는 admin
main.css(.org-tree-panel) 와 drivemain.css(.drive-rail-panel) 두 벌입니다 — 앱이 달라 한쪽을 고치면 다른 쪽도 같이 고쳐야 합니다(두 블록이 서로를 가리키는 주석이 있습니다) - 서랍의 Esc 는 캡처 단계에서 모달에 양보합니다 — 서랍 안 「팀 추가」·「새 폴더」로 모달을 띄우고 Esc 를 누르면 모달과 서랍이 함께 닫혔습니다(둘 다 window 리스너). 버블 단계에서 「모달이 떠 있나」를 보면 모달 쪽 핸들러가 먼저 닫아 버려 늘 「없음」으로 읽히므로, 서랍 핸들러를
@keydown.escape.window.capture로 두고.ds-modal-backdrop이 보이면 아무것도 하지 않습니다. 공용registerEscLayer는 z 가 같은(50) 레거시 모달보다 서랍을 먼저 닫아 버려 이 경우에 쓰지 않습니다
2026-09-16 — 목록 화면 상단 필터 줄을 한 벌로 (design/ui-improve-table-filter)
변경
- 필터 바 패턴이 생겼습니다 — 목록 위 한 줄을 왼쪽=거르는 것 / 오른쪽=검색+하는 것 두 그룹으로 고정하고, 좁아지면 줄바꿈 대신 오른쪽은 아이콘만 · 검색은 돋보기로 접힘 · 왼쪽은 가로 스크롤, 그래도 모자라면 위아래 두 줄로 내립니다 → 필터 바
- 줄어드는 순서는 좌측 먼저, 버튼 라벨이 마지막입니다(4단: full → dense → compact → stacked). 라벨은 아이콘보다 정보가 많아 최대한 버팁니다 — 드롭다운 fit·가로 스크롤·검색 접기가 먼저 일어나고, 그래도 안 들어갈 때 버튼이 아이콘이 됩니다
- 필터가 많아 full 이 의미 없는 화면은
.ds-filter-bar--dense로 opt-in 합니다(직원 관리 — 필터 7개). full 을 건너뛰고 dense 에서 시작해 검색은 처음부터 돋보기 · 버튼은 라벨 유지가 섞인 모습이 되고, 제목은 아예 두지 않습니다(LNB·페이지 헤더가 이미 같은 말을 합니다) - 전환은 px 미디어쿼리가 아니라 폭 측정입니다. 기준이 화면 폭이 아니라 그 페이지의 필터·버튼 개수라, 같은 1280px 에서 역할 관리는 한 줄이고 팀 관리는 이미 넘칩니다.
setupFilterBar()를 앱 시작 시 한 번 부르면 ResizeObserver·MutationObserver 로 따라갑니다(행 선택으로 왼쪽 그룹이 일괄 액션 바로 바뀌는 것까지) - 돋보기 토글·「취소」 버튼·좌우 셰브론은 JS 가 주입하고, 아이콘만 남은 버튼의 툴팁도 라벨에서 자동으로 옮겨집니다. 페이지 마크업은 클래스 다섯 개뿐입니다
- 컴팩트에서 드롭다운은 고른 값 폭에 맞춰 좁아집니다(최대 4글자+…) — 「활성」 70px · 「전체 팀(병동)」 96px. 셀렉트 좌우 여백도
.ds-select--28값으로 함께 좁힙니다(새 수치 없음, 높이는 32px 유지) - 검색어 지우기 X 도 DS 가 가집니다 — 지금까지 팀 관리·직원 관리 두 곳에만 제각각 있던 것을 주입으로 흡수해, 이관한 화면은 전부 같은 자리에 같은 모양으로 생깁니다
- 적용: admin 역할 관리 · 병동 관리 · 팀 관리(조직/팀 2벌) · 직원 관리 · 스케줄러 상단 줄, hr-system 시트 기간 줄. 스케줄러는 환자수 입력 줄이 같은 flex-wrap 컨테이너에 있어 좁아지면 버튼이 줄바꿈으로 밀렸던 것을, 필터 바와 형제로 나눴습니다. 나머지(문서 결재·전자 서명·파라미터)는 마이그레이션 대상이고 전수 교체하지 않습니다
- 근태 현황 5탭(근무 · 연차 · 연장근무 · 외근 · 근로시간 마감)도 적용했습니다. 근무·연장근무는 team-manager 화면을 iframe 으로 띄운 것이라 team-manager 에서도
setupFilterBar()를 부릅니다. 연차 현황의 아이콘 없던 버튼 3개(일괄 통지·발송 내역·업로드)에 아이콘을 줘 좁은 폭에서 아이콘만 남게 했고(높이도 검색과 같은 32px 로), 근로시간 마감은 「검색」 버튼을 눌러야 찾던 것을 다른 탭처럼 입력 즉시 검색으로 바꾸고 다운로드를 필터 줄 오른쪽으로 옮겼습니다 - 공지 · 드라이브도 적용했습니다(각각 general-affairs · drive 앱의 iframe 이라 두 앱에서도
setupFilterBar()를 부릅니다). 공지는 400px 에서 셀렉트 두 개가 글자 없이 눌려 위아래로 쌓이던 것, 드라이브는 600px 이하에서 검색창이 36px(한 글자)까지 눌리고 「파일 업로드」 글자가 버튼 밖으로 잘리던 것이 사라졌습니다. 공지의 두 셀렉트는 둘 다 「전체」라 무엇을 거르는지 알 수 없어 **「전체 카테고리」·「전체 상태」**로 바꿨고, 드라이브는 거르는 필터가 없어 오른쪽 그룹만 둡니다(검색이 그룹 맨 앞으로 오면서 「권한 관리」 버튼과 자리가 바뀌었습니다). 두 화면이 직접 그리던 검색어 지우기 X 는 DS 주입으로 대체했습니다 - 직원 관리는 폭과 상관없이 늘 2줄이었습니다(
order·basis-full수제 고정 — 필터 6개가 1600px 에서도 한 줄에 안 들어가 들쭉날쭉 줄바꿈되던 것을 막으려던 것). 이제 폭을 재어 정하므로 1440px 에서 필터 7개가 한 줄에 다 들어갑니다
함정
- 검색어가 남아 있으면 검색창은 접히지 않습니다 — 접힌 돋보기 뒤에 검색어가 살아 있으면 "목록이 왜 이것뿐이지"가 됩니다. JS 가 강제합니다
overflow-x: auto는overflow-y: visible과 같이 못 씁니다 — 가로만 열어도 세로가 함께 잘려서 스트립 안 드롭다운 메뉴가 경계에서 사라집니다. 그래서.ms-dropdown__menu만position: fixed로 띄우고 좌표를positionFloatingMenu로 잡습니다. 스트립에 새 떠 있는 메뉴를 넣으면POPUP_PAIRS에 한 줄 추가해야 합니다- 컴팩트에서 드롭다운 폭은 고른 값에 맞춥니다(fit · 최대 4글자+…) — 네이티브
<select>는 교체 요소라 CSS 에 맡기면 지금 고른 값이 아니라 가장 긴 옵션 폭이 됩니다(fit-content도 같음). 그래서setupFilterBar()가 캔버스로 글자를 재서 인라인 width 를 줍니다. 고정 폭 상수를 대신 박지 마세요. 잘린 값은 hover 하면 전체가 툴팁으로 뜹니다 .is-measuring은 좌측 규칙을 특이도로 이겨야 합니다 —.ds-filter-bar.is-left-compact .ds-filter-bar__filters가flex: 1 1 0이라 측정 규칙을> *(0,2,0) 로만 쓰면 그 규칙(0,3,0)에 져서 재는 동안에도 좌측이 줄어듭니다. 넘치는데 폭에 안 나타나 무슨 폭에서든 dense 로 판정됐습니다(재현·수정). 스크롤 박스도 재는 동안overflow: visible로 풀어야 합니다- 자연 폭을
scrollWidth로 재면 오른쪽 패딩이 빠집니다 — 시트 툴바(px-4)에서 6px 넘치는데 "들어간다"로 판정돼 필터가 눌렸습니다. 패딩 뺀 안쪽 폭과 보이는 자식 폭의 합으로 바꿨습니다 x-show는 style 속성만 바꿔서 childList·ResizeObserver 어느 쪽에도 안 잡힙니다 — 행 선택·탭 전환이 바로 폭이 바뀌는 순간인데 재판정이 안 됐습니다(근처 글자 변경에 우연히 기대고 있었음). 바마다 속성 관찰자를 붙이고, 자기 쓰기에 다시 깨지 않게 쓰는 동안 관찰을 끊습니다- 아이콘 없는 버튼은 컴팩트에서 라벨이 남습니다(
:has(.ds-ico)) — 빈 네모를 막는 안전장치이지 허용이 아닙니다. 새 버튼에는 아이콘을 주세요 - admin
.employee-filter-toolbar는 그 안의<button>을 32px·1px 테두리로 강제합니다 — 주입 버튼(셰브론·「취소」·지우기 X)은.ds-btn이 아니라 기존 제외 명단에 안 걸려 네모로 뭉개집니다.:not()체인에.ds-filter-*를 넣어 풀었습니다. 새 화면에 그 툴바 클래스를 쓰지 마세요 - 스트립 안 날짜 피커가 스크롤 대신 눌렸습니다 — flex 기본값(줄어듦 허용)에서 폭 100% 입력칸을 품은 피커는 최소 폭이 0 에 가까워, 400px 에서 144 → 84px 로 눌려 날짜가 잘렸습니다(근태 현황, 재현).
.ds-filter-bar__scroller > *에flex-shrink: 0을 줘서 넘치면 스크롤되게 했습니다 .ms-dropdown은 앱마다 복사본이라 컴팩트 보정도 앱마다 필요합니다 — team-manager 에도 admin 과 같은 한 쌍(min-width: 0· 메뉴position: fixed)을 넣었습니다. 빠뜨리면 그 앱에서만 메뉴가 스트립에 잘립니다- 필터 바는 자기 줄의 폭만 봅니다 — 드라이브처럼 옆의 트리가 좁은 폭에서도 폭을 고정으로 차지하면, 400px 화면에서 이 줄에 132px 만 남아 검색을 펼칠 때 「취소」가 밖으로 밀립니다. 필터 바로는 못 풀고 트리 쪽 반응형이 필요합니다 → 아래 「페이지 트리 서랍」에서 해결
2026-09-16 — 병동·팀 연결을 사용자 가이드와 정책서에 반영했습니다 (docs/ward-team-guide-policy)
PR #711·#715 로 팀↔병동 연결과 다직군 근태 규칙이 들어갔지만, 문서에는 정책서의 병동 축만 반영돼 있었습니다. 유저 가이드는 한 줄도 반영되지 않았고, 그 사이 지금은 따라 할 수 없는 절차가 배포본에 남아 있었습니다.
⚠️ 사용자 가이드 — 외부 원고를 직접 고쳤습니다 (콸 리뷰 필요)
docs/ko/guides/fragments/guide-admin.html · guide-nurse-scheduler.html 는 외부 PM 팀(콸/카나) 납품 원고이고 gen-docs-guides.mjs 가 본문을 바이트 그대로 옮깁니다. 없어진 메뉴로 안내하는 절이 직원분들이 읽는 설명서에 그대로 있어 사용자 지시로 직접 고쳤습니다. 다음 재납품 때 되돌아가므로 콸 쪽 리뷰를 받아 원고에 반영해야 합니다.
사실이 틀렸던 곳입니다 — 전부 코드와 로컬 화면 양쪽으로 대조했습니다.
| 고치기 전 | 실제 |
|---|---|
| 간호 스케줄러 「병동 만들고 병동 종류 정하기」의 시작 위치가 「스케줄러 → 병동 설정 → 병동 관리」 | #711 이 그 탭을 없앴습니다. 병동은 관리자 인사 관리 > 병동 관리 한 곳에서만 만들고 고칩니다. 창에는 인력 설정·교대 매핑·교육 정책·주기 설정 네 탭만 남았습니다 |
| 관리자 병동 절의 「팝업 안에서도 병동 추가/수정/활성 전환을 할 수 있습니다」 | 같은 이유로 불가능합니다. 목록에 코드·연결 팀·병상 수·순서 열이 생겼고, 수정은 팝업이 아니라 표 안에서 그 줄이 입력칸으로 바뀝니다 |
| 병동 추가 창의 저장 버튼을 「저장」으로 안내 | 추가는 「생성」, 수정만 「저장」입니다(wards.html 의 wardFormMode) |
| 직원 명부 다운로드가 「직원 관리에서는 상태 필터만 적용」 | 지금은 화면에 보이는 명단과 같습니다 — 상태·팀·역할·직무·병동 필터와 검색어·입사일이 그대로 전달됩니다 |
| 조직 루트 배지 예시 「하나로병원 242」 | #711 이 인원 기준을 전체 = 재직 + 휴직(비활성 제외)으로 바꿔 같은 조직이 218 로 나옵니다 |
라벨도 화면과 맞췄습니다. 팀 관리·병동 현황 표·직원 수정 패널은 「수간호사」가 아니라 「책임자」 입니다(수간호사가 아닌 책임자도 있어 의도적으로 나눈 이름이며, 스케줄러 명부만 「수간호사」를 씁니다).
새로 넣은 절 (기존 절 안에서)
관리자 가이드에 팀 트리 인원 배지·병동 줄·미연결 병동, 팀과 병동 연결하기, 병동 화면, 병동 화면에서 직원 넣기(「팀에도 추가」·휴직 포함·권한), 추가 팝업 직무·팀 필터, 직원 수정의 병동 배정·직무, 설정 기본 출퇴근 기준시간, 연차 현황 근무 미배정 경고를 넣었습니다.
절을 새로 만들지 않았습니다
절 id({#s2-1})는 생성기가 위치로 매깁니다. 절을 하나 끼우면 뒤 절의 id 가 한 칸씩 밀리는데, 기능 문서가 admin.md#s4-1 처럼 그 id 를 참조합니다 — 20개 파일 154줄, 고유 앵커 90개입니다. 그래서 새 내용은 기존 절 안의 소제목 블록으로 넣었고, 재생성 후 제목 diff 가 0인 것으로 확인했습니다.
스크린샷
낡은 5장(ad-04 · ad-04-add-team · ad-06 · ad-06-add-ward · ns-02)을 다시 찍고 5장(ad-04-ward · ad-04-ward-add · ad-04-ward-setting · ad-02-ward · ad-20-attendance-time)을 더했습니다. 더미 조직(하나로병원)에서 촬영했고, 병동 화면을 보이려고 「재활의학과 병동」을 「간호부」 팀에 잠시 연결했다가 되돌렸습니다.
정책서 · 기능 문서
정책서에는 #715 전량(팀 헤더 「병동 설정」, 병동 모드 추가 팝업, 직무·팀 필터, 팀 이동 시 병동 배정 이동·줄 합치기)과 #711 중 문서에 없던 축(출퇴근 기준 시각 5단계, 연차 「근무 미배정」 경고 기준, 근무 그룹 변경 시 형태 비움, 직군 13종, 간호등급 간호사 수, 퇴사 시 소속 유지, 대량 업로드 이름 해석, 역할 배정 규칙)을 넣었습니다. 기능 문서 4편(organization-access · scheduling · hr-records · attendance-leave)도 같은 기준으로 맞췄습니다.
2026-09-15 — 표 가로 스크롤바를 아래쪽 하나로 (design/add-ward-management)
변경
- 가로로 넘치는 표의 스크롤바가 표 아래쪽에만 붙습니다. 위쪽 바를 없앴습니다 — 스크롤 박스가 화면 높이에 맞는 표(근태 현황 > 연차 등)에서 헤더 위에 한 줄 더 그려져 같은 바가 두 번 보였습니다 → 가로 스크롤바
- 화면마다 달던
data-ds-xscroll="bottom"속성(admin 7곳)을 지웠습니다. 기본이 아래쪽 하나라 필요 없고, 새 표에 빠뜨리면 위아래 두 줄이 되던 문제가 없어집니다. 해제용data-ds-xscroll="off"와 겹치지 않게 하는data-ds-xscroll-inflow는 그대로입니다
함정
- 표가 화면보다 길면 아래쪽이 화면 밖입니다 — 위쪽 바가 있던 이유였습니다. 아래 바를
position: sticky; bottom: 0으로 두어 표가 보이는 동안 화면 아래 끝에 붙게 했습니다. 단 가장 가까운 스크롤 조상이overflow: hidden처럼 스크롤되지 않는 상자면 sticky 가 걸리지 않아 바가 제자리에 있습니다
2026-09-10 — 모바일 전용 앱의 공용 모달을 풀레이어로 (design/app-ui-improvements)
변경
- 일반 모달에 풀레이어 표시 변형
.ds-modal--full이 생겼습니다. 카드 대신 화면 전체를 덮고, 여백은 앱 페이지와 같은 20 그리드(헤더20/20/16· 본문0 20 20· 푸터12/20/16 + safe-area)입니다. 네 번째 종류가 아닙니다 — 백드롭·닫기·스크롤 잠금·__header/__title/__body/__footer는 일반 모달 그대로고 바깥 여백과 카드 크기만 다릅니다 → 풀레이어 - 켜는 건 호스트입니다(
csReport({ fullLayer: true })) — 뷰포트 폭이 아닙니다. 직원 앱은 태블릿 폭에서도 모바일 레이아웃이라, 폭으로 갈면 그 폭에서만 카드로 돌아갑니다 - 첫 적용: 직원 앱의 불편·오류 신고. 그 앱 팝업 10종이 전부 풀레이어인데 이것만 가운데 카드로 떠서, 같은 동작이 한 앱 안에서 두 모습으로 읽혔습니다. 카드 여백(44/40/36)이 390px 폭에서 본문을 절반 가까이 깎던 것도 함께 해소됩니다
- 닫기 X 는 제목 줄 안으로 내려와 화면 우측 8px 에 섭니다 — 2depth 헤더 뒤로(
<)의 거울상. 실측(iPhone 13·배율 기본): X 박스 32, 우측 8, 제목 줄 top 12 로 헤더와 동일 - 안쪽 사이즈도 모바일 값으로 함께 바뀝니다 — 입력
ds-input--48, 푸터 CTAds-btn--lg반반(flex: 1), 라벨text-b4. 좁은 폭에서 버튼 셋은 라벨이 줄바꿈되므로 「취소」는 빼고 제목 줄의 X 에 맡깁니다
함정
zoom을 쓰는 앱은 높이 보정 선택자에 새 클래스를 같이 넣어야 합니다. 직원 앱은 글자 크기 배율을body { zoom }으로 걸어100dvh가 배율만큼 넘칩니다 — 빠뜨리면 기본 배율(1.2)에서만 푸터가 화면 밖으로 밀리고, 배율 1.0 인 개발자 브라우저에서는 멀쩡해 보입니다- 분기용 클래스 문자열을
.ts로 끌어오지 마세요. 앱 Tailwind 는@source ".../components/html"만 훑어서,.ts안에만 있는 유틸리티(mx-4·w-5)는 그 앱에서 아예 생성되지 않습니다. 공용 컴포넌트는fullLayer같은 불리언만 넘기고 클래스는 템플릿에 리터럴로 둡니다 - 내역 행의 접수번호는
whitespace-nowrap+ 줄 단위flex-wrap입니다 — 그냥 두면 좁은 폭에서CS-LOC-260904-/0001로 토막 나 전화로 부를 수 없습니다
2026-09-10 — 사용자 가이드에 AI 어시스턴트 절을 넣었습니다 (design/docs-DS-review-improvements)
관리자 가이드에서 AI 어시스턴트는 「0-4. 화면 어디에나 있는 것(인원 요약 · AI 어시스턴트)」 안의 한 문단이 전부였습니다. 도크로 열린다는 것 말고는 무엇을 물어볼 수 있고 무엇을 못 하는지가 없었고, 그 한 문단 안에 화면과 다른 서술이 셋 있었습니다. 절을 「0-4. 인원 요약」과 「0-5. AI 어시스턴트」로 쪼개고 0-5 를 새로 썼습니다.
⚠️ 사용자 가이드 — 외부 원고를 직접 고쳤습니다 (콸 리뷰 필요)
docs/ko/guides/fragments/guide-admin.html 는 외부 PM 팀(콸/카나) 납품 원고이고 gen-docs-guides.mjs 가 본문을 바이트 그대로 옮깁니다. 원칙대로면 요청만 남길 자리인데, 없는 기능을 약속하는 문장이 직원분들이 읽는 설명서에 그대로 있어 사용자 지시로 직접 고쳤습니다. 다음 재납품 때 되돌아가므로 콸 쪽 리뷰를 받아 원고에 반영해야 합니다. 원본과 생성물(guides/admin.md)을 둘 다 고치고 gen-docs-guides.mjs 를 다시 돌려 일치를 확인했습니다.
사실이 틀렸던 곳 3군데입니다 — 전부 코드와 라이브 배포본(admin) 양쪽으로 대조했습니다.
| 고치기 전 | 실제 |
|---|---|
| 「조직 설정에서 AI 를 켠 경우에만 보입니다」 | 병원 admin 의 설정 화면에는 토글이 없습니다. 조직별 settings.ai.enabled 는 시스템 관리 도구(운영팀) 가 켜고, 쓰는 사람에게는 역할 권한 ai:execute 가 따로 필요합니다 — 권한 트리의 실제 라벨은 「AI 어시스턴트 실행 (본인)」(그룹 「AI 어시스턴트 0/2」) |
| 「닫을 때는 도크 오른쪽 위의 닫기(×)」 | × 는 undock() — 「플로팅 버튼으로 되돌리기」 입니다. 대화가 그대로 남고 FAB 을 다시 누르면 이어집니다 |
| 「AI 가 자동으로 바꾸지 않고 제안·미리보기까지만 합니다」 | 제안도 미리보기도 없습니다. tool 다섯 개(searchEmployees · getEmployeeDetail · getLeaveBalance · getAttendanceSummary · getPayrollSummary)가 전부 read-only 이고, 시스템 프롬프트가 변경 요청을 「해당 화면에서 처리하세요」로 돌립니다 — 없는 기능을 약속하는 문장이었습니다 |
새로 쓴 0-5 에는 여는 법과 도크 폭 조절(360~800px · 키보드 ←/→·Home), 1280px 미만의 플로팅 폴백, 물어볼 수 있는 네 가지(직원 · 연차 · 근태 · 급여)와 조회되지 않는 것(시트 셀 값 · 근무표 편성 · 문서/공지 본문 · 재고), 「생각하는 중」·「데이터 조회 중」·「생각 과정 보기」, 새 대화·이전 대화 목록, 그리고 안 보이거나 막힐 때 4증상 표(버튼 없음 · 월 사용량 상한 · 권한 없음 · 오답 신고)를 넣었습니다.
「제안·미리보기」는 표기가 아니라 사실이 틀린 항목이었습니다
읽는 사람이 AI 에게 변경을 맡길 수 있다고 기대하게 만드는 문장입니다. 실제로는 조회만 되므로, 기대한 대로 되지 않으면 「기능이 고장 났다」로 읽힙니다. 그래서 0-5 에는 읽기 전용이라는 것을 콜아웃 한 칸으로 따로 세웠습니다.
2026-09-09 — 직원 추가·수정 패널의 이름을 문서 전체에서 맞췄습니다 (design/docs-DS-review-improvements)
왜
사용자 질문에서 출발했습니다 — 「모달 문서가 따로 있는데 왜 폼 메뉴에도 있나」. 파 보니 이름이 세 겹으로 어긋나 있었습니다. 사이드바는 「컴포넌트 — 폼」, 심볼은 AddEmployeePanel, 그런데 페이지 첫 줄은 「패널 모달입니다」로 컴포넌트의 정체를 모달이라고 규정하고 본문은 계속 「위저드」라고 불렀습니다.
모달은 이 컴포넌트의 정체가 아니라 뜨는 방식입니다. 모달을 쓰는 컴포넌트가 넷(권한 없음 · 불편·오류 신고 · 직원 추가 · 직원 수정)인데 그중 어느 것도 「모달」 메뉴에 있지 않은 이유가 그것입니다.
첫 줄 — 정체는 「폼」, 그릇은 링크로
직원 추가 패널 · 직원 수정 패널 두 쪽의 첫 줄을 「폼입니다」로 바로잡고, 담기는 그릇은 패널 모달 링크가 지도록 넘겼습니다. 이제 첫 줄과 사이드바 위치가 같은 말을 합니다.
「위저드」 → 「패널」 — 백로그였던 본문 표기
컴포넌트는 73fc32b0 에서 이미 개명됐고, 아래 모달 문서 통합 항목에서 제목 한 곳만 고치고 본문은 백로그로 남겨 뒀던 것을 이번에 닫았습니다.
- 6쪽 30여 곳 — 모달 · 직원 추가 패널 · 직원 수정 패널 · 내 정보 폼 · 권한 없음 모달 · 폼 컨트롤
- 조사가 함께 바뀝니다. 「위저드」는 받침이 없고 「패널」은 있어서 와→과 · 가→이 · 는→은 · 를→을 이 따라옵니다. 링크 괄호 뒤에 떨어져 있어 치환에 안 걸린
](…)와3곳도 「과」로 고쳤습니다
일괄 치환하지 마세요 — 2곳은 「위저드」가 맞습니다
모달 → 자유 이동과 직원 추가 패널의 「「다음 → 다음」으로 넘기는 위저드가 아닙니다」에서 위저드는 컴포넌트 이름이 아니라 단계형 폼이라는 일반명사입니다. 여기서 바꾸면 「패널이 아니다」가 되어 뜻이 정반대가 됩니다. 워크스페이스 생성·시트 생성이 「진짜 위저드」라 이름을 유지하는 것과 같은 기준입니다.
⚠️ 사용자 가이드 — 외부 원고를 직접 고쳤습니다 (콸 리뷰 필요)
docs/ko/guides/fragments/guide-admin.html · hereby-onboarding-playbook-v1.3.html 는 외부 PM 팀(콸/카나) 납품 원고이고 gen-docs-guides.mjs 가 본문을 바이트 그대로 옮깁니다. 이번에는 표기만이 아니라 설명 내용이 화면과 달랐고(단계형이 아닌 화면을 「4단계 위저드」로 설명), 직원분들이 읽는 설명서라 사용자 지시로 직접 고쳤습니다. 다음 원고 재납품 때 되돌아가므로 콸 쪽 리뷰를 받아 원고에 반영해야 합니다.
원본과 생성물을 둘 다 고쳤고(gen-docs-guides.mjs 재실행으로 일치 확인), 고친 곳은 5군데입니다.
| 위치 | 고치기 전 | 고친 뒤 |
|---|---|---|
| §1 제목 | 신규 직원 등록하기 (위저드 4단계 상세) | 신규 직원 등록하기 (네 카테고리 상세) |
| §1 도입 | 「…동시에 만들어지는 4단계 위저드입니다」 | 단계 서술을 빼고, 자유 이동(「다음」 없음) · 빨간 점 · 「점이 남으면 등록이 안 눌린다」를 설명. ①~④ 는 읽는 순서일 뿐임을 명시 |
| §2 정보 수정 | 「§1과 같은 4단계 화면에서 값을 고칩니다」 | 「§1과 같은 카테고리 화면」 + 수정은 다섯(「계정·로그인 보안」 추가) · 빨간 점 없음 |
| §3 팀 관리 | 등록 위저드(§1) | 등록 패널(§1) |
| 온보딩 플레이북 P3 | 신규 직원 추가 위저드 | 신규 직원 추가 패널 |
표기가 아니라 사실이 틀렸던 항목입니다
「4단계 위저드」는 이름만 낡은 게 아니라 동작 설명이 틀린 것이었습니다. 지금 화면에는 「다음」 버튼이 없고(add-employee-panel.html 에 해당 마크업 0건), 순서 강제 대신 빨간 점이 미완성을 알립니다. 그래서 「어디가 막혔는지 모르겠다」는 문의가 나오면 원고대로 읽은 사용자는 단계를 되짚으려 하게 됩니다 — 점을 보라는 안내를 새로 넣은 이유입니다.
곁다리로 잡은 것
- 추가 패널의 ESC 트랩이 공유 규칙을 다시 쓰고 있었습니다. 모달 → ESC 층으로 이관이 끝난 뒤에도 한 곳만 본문이 남아, 수정 패널처럼 링크 한 줄로 줄였습니다
- 그 트랩이 안고 있던 사실 오류 — 「패널 위 레이어가 넷」이라고 적혀 있지만
escapeClose()는 다섯을 처리합니다(알림 · 미리보기 · 근무 참고 · 주소검색 · 저장확인). 패턴 페이지의 다이어그램은 원래 다섯이라 정확합니다 - 주민등록번호 입력칸의
font-mono4곳을 걷어냈습니다(타이포그래피 — 사번·코드 등 데이터 식별자에 mono 금지). 주민번호는 코드가 아니라 데이터 식별자라 Inter 로 렌더돼야 합니다
2026-09-09 — Foundations 8쪽을 컴포넌트 페이지와 같은 규격으로 (design/docs-DS-review-improvements)
왜
컴포넌트 22쪽 중 21쪽이 쓰는 표준 골격(설명 1줄 → 배지 1줄 → Playground → 규칙(강제) → 탭)을 Foundations 는 한 쪽도 쓰지 않고 있었습니다.
상단 규격과 탭
- 상단을 8쪽 모두 맞췄습니다 — 설명 한 줄 + 배지 한 줄. 데모가 있는 브레이크포인트만
## Interactive playground까지 온전히 적용했습니다(76줄이라 탭은 씌우지 않았습니다 — 씌우면 빈 탭이 생깁니다) - ⚠️ 컴포넌트 규격을 그대로 씌우지는 않았습니다. 색·타이포그래피·간격·모서리·그림자·투명도 6쪽은 인터랙티브 데모가 하나도 없는 토큰 참조 표입니다. 표 위에
## Interactive playground를 붙이면 거짓말이 되고 「적용 방법 · API·규격」 탭도 걸 자리가 없어서, 상단만 맞추고 본문 뼈대는 그대로 뒀습니다 - 탭은 7쪽 — 브랜드 · BI 5탭, 나머지 6쪽 3탭(사용 가이드 · 변형·상태 · 변경·전환)
- Playground 가 없는 페이지는 「변형·상태」 탭을 먼저 엽니다(
DocTabs의variantsFirst). 토큰 페이지는 만질 것이 없어, 그대로 두면 무엇이 있는지 보기 전에 설명부터 읽게 됩니다 — 스와치·스케일 표를 앞으로 당겼습니다. ⚠️ Playground 가 있는 페이지에는 켜지 마세요 — 탭 순서가 페이지마다 달라집니다
색 규칙이 문서로 돌아왔습니다
색만 강제 규칙이 문서가 아니라 .claude/rules/frontend/design-tokens.md 에 있었습니다. 라우터 규칙이 못 박은 원칙(규칙은 문서 페이지 한 곳)과 정반대였고, 그래서 색상에는 규칙(강제) 블록이 아예 없었습니다 — 내용이 있는 8쪽 중 유일했습니다.
- 사용 우선순위 5단계 · 금지 패턴 5종 ·
var()가 안 통하는 자리 5종(canvas · SVG presentation attribute · 이메일 HTML ·meta theme-color· BI 자산) · 새 색을 추가하는 절차를 문서로 옮기고, 규칙 파일은 다른 6쪽처럼 가리키기만 하도록 줄였습니다 - 421줄을 3탭으로 나누고, 「정리 대기 중인 색상」 113줄은 규격이 아니라 작업 재고라 「변경·전환」으로 보냈습니다
- 앵커가 1개 → 8개로 늘었습니다. 하나뿐이라 채팅 문서가 걸어 둔
색상 문서(#brand-gradient)링크가 죽어 있었습니다(같은 날 브랜드 문서로 고쳤습니다)
아이콘 문서 두 쪽을 하나로
foundations/아이콘 과 resources/아이콘 라이브러리 가 따로 있었고 둘 다 「사용 규칙」을 갖고 있었습니다. 결정적으로 foundations 쪽의 「레지스트리(2026-06 기준 31종)」 표는 실제 171종의 18%만 담은 낡은 스냅샷이었고, 그 표를 정정하는 주석조차 「2026-07 기준 80종+」로 낡아 있었습니다.
- 표를 지우고 빌드 시점에 레지스트리를 그대로 렌더하는 갤러리(
<DemoIconGallery />)로 대체했습니다 — 171개 렌더 확인. 손으로 적은 목록은 적는 순간부터 낡습니다 resources/icons.md는 삭제하고 사이드바 항목도 뺐습니다
곁다리로 잡은 것
- 투명도 스와치가 375px 에서 33px 넘쳤습니다 — 7열이
repeat(7,1fr)인데 스와치가width:48px고정이라7×48 + 6×8 = 384px가 본문 폭 343px 을 넘었습니다. 열 수는 그대로 두고minmax(0,1fr)+ 열 폭을 따라가는 정사각형(max-width:48px; aspect-ratio:1)으로 바꿔 넘침 0(1280px 은 종전대로 48×48) - 죽은 한글 앵커 3곳 — VitePress 가 제목 id 를 NFKD 로 분해해 DOM 은 NFD 인데 문서에 적은 앵커는 NFC 라, 눌러도 아무 데도 가지 않습니다 — 제목에 ASCII id 를 명시해야 합니다
- 「사용 우선순위」와 「사용 우선순위 (코드 작성 시)」로 갈려 있던 절 이름을 후자로 통일(6쪽)
남은 것 — 이 페이지들 것이 아닙니다
768px 에서 보이는 189px 가로 넘침은 디자인 시스템 문서 전 페이지에서 같은 값입니다. VitePress 상단 내비(.VPNavBarMenu, 메뉴 7개)가 그 폭에서 넘치는 사이트 크롬 문제라 여기서는 손대지 않았습니다.
2026-09-09 — Toast 문서 신규 — 제품에 이미 쓰이는 두 계열을 정리 (design/docs-DS-review-improvements)
왜
사이드바의 Toast 는 5줄짜리 「준비 중」 스텁이었는데, 제품에는 이미 세 갈래로 들어가 있었습니다. 규칙이 없으니 앱마다 따로 자라고 있었고, 그 상태가 문서에 아무 데도 적혀 있지 않았습니다.
실제로 쓰이고 있던 것
| 어디 | 모양 | |
|---|---|---|
.ds-toast | admin · drive | 흰 카드 + 톤 아이콘 + 닫기 ✕, 화면 위쪽 |
| 자체 구현 | employee-app (stores/toast-store.ts) | 검은 알약, 톤 표현 없음, 화면 아래쪽 |
paste-toast.html | hr-system 시트 | 이름만 toast 인 붙여넣기 요약 줄 |
쓴 것
Toast 페이지를 표준 골격(설명 → 배지 → Playground → 규칙(강제) → 5탭)으로 새로 썼습니다. 코드에서 읽어 정리한 것들입니다 — 언제 쓰나(토스트 ↔ 다이얼로그 ↔ notice 경계) · 부르는 법 · 두 구현 비교 · 톤 3종 · 규격 · 앱에 붙이는 법 · 스토어 API 양쪽 · 토스트가 아닌 것.
라이브 Playground 도 냈습니다 — 톤을 고르고 「띄우기」를 누르면 무대 안에 실제로 쌓이고, 3초 뒤 사라지거나 ✕ 로 내려집니다. 스타일은 ds-toast-demo.css(admin main.css verbatim)입니다.
정리하며 드러난 것 — 검토 필요 사항
- 정본이 없습니다.
.ds-toast*가design-system.css에 없고 admin · drivemain.css두 곳에만 있습니다(문서 데모까지 세 벌). 두 사본의 차이는animation을 어디에 뒀는지뿐이라 지금이 승격하기 가장 쉬운 시점입니다 - 스토어도 글자까지 같은 복사본이 admin · drive
main.ts에 각각 있습니다 - z 가 토큰을 안 씁니다 —
--ds-z-toast: 80이 있는데 admin · drive 는z-index: 999999하드코딩. 직원 앱만 토큰을 씁니다 - 직원 앱은 톤을 버립니다 — 스토어는
variant를 받는데 마크업이 안 써서 성공과 실패가 같은 검은 알약입니다 info만 노랑입니다 — notice 의--info는 파랑 계열인데 토스트만hr-yellow-500- 쌓임 순서가 계열별로 반대입니다 — admin·drive 는 오래된 것이 위, 직원 앱은 최신이 위
2026-09-09 — 사이드바 이름 규칙을 세우고, 「라이브 미리보기」를 Playground 로 통일 (design/docs-DS-review-improvements)
왜
왼쪽 메뉴가 영문과 한글을 섞어 쓰고 있었습니다. 그룹 제목은 영문(Foundations · Patterns)인데 그 안의 항목은 한글이고, 패턴 목록은 Data table (Table 1) 과 근무 스케줄표 (Table 2) 가 나란히 서 있었어요. 기준이 없으니 새 문서를 넣을 때마다 그때그때 정하게 됩니다.
정한 기준 — 메뉴는 한글, 코드 심볼은 페이지 제목에 병기
처음에는 「컴포넌트는 코드 심볼이니 영문 유지」로 잡았는데, 그러면 한국어 문서의 왼쪽 메뉴 절반이 계속 영문으로 남습니다. 메뉴는 읽는 곳이지 grep 하는 곳이 아니다로 정리했습니다.
- 왼쪽 메뉴는 전부 한글입니다 —
페이지 헤더·토스트·채팅 위젯·권한 없음 모달… - 코드 심볼은 페이지 제목이 지킵니다 —
페이지 헤더 (PageHeader)처럼 한글 선두 + 괄호 병기. 검색은 제목에서 되고, 메뉴는 읽힙니다 - 약어·제품명은 그대로 둡니다 —
LNB 사이드바·AI 어시스턴트·Figma 토큰·임베드 iframe·Table 1/2. 번역 대상이 아니라 그 자체가 이름입니다 - 그룹 제목도 한글입니다(
파운데이션·컴포넌트 — 피드백·패턴·리소스…)
페이지 제목도 같이 맞췄습니다
사이드바와 제목이 다르면 눌러 들어갔을 때 다른 문서처럼 읽혀서, 개념 문서 다섯 쪽을 한글 선두 + 영문 병기로 바꿨습니다 — 모달 · 페이지네이션 · 차트 가 이미 쓰던 꼴입니다.
| 전 | 후 |
|---|---|
Data table (Table 1 · 표준 카드 테이블) | 데이터 표 (Table 1 · 표준 카드 테이블) |
Metric card (지표 카드 · 상태/비교) | 지표 카드 (Metric card · 상태/비교) |
Form controls (Input · Select · Picker) | 폼 컨트롤 (Input · Select · Picker) |
App chrome | 앱 크롬 (App chrome) |
Embed iframe | 임베드 iframe (Embed iframe) |
컴포넌트 문서 28쪽도 같은 꼴로 바꿨습니다 — # PageHeader → # 페이지 헤더 (PageHeader). 이미 병기가 있던 쪽은 순서만 뒤집었습니다(AiAssistant (AI 어시스턴트) → AI 어시스턴트 (AiAssistant)). 사이드바에서 MessengerShared 로 잘못 불리던 것도 실제 제목인 메신저 (Messenger) 로 맞췄습니다.
「라이브 미리보기」 → Playground
같은 것을 두 이름으로 부르고 있었습니다. 31쪽은 Interactive playground, 패턴 5쪽은 라이브 미리보기 였어요. 뒤엣것을 앞으로 맞췄습니다 — 데이터 표 · 근무 스케줄표 · 지표 카드 · 페이지네이션 · 차트.
- 옛 앵커(
#live-preview)는 살려 뒀습니다 — 절 위에 호환용 표식을 남겨서, 그 주소로 들어오는 링크가 그대로 동작합니다(전환된 페이지들이 이미 쓰던 방식) - 문서화 커버리지의 열 이름과 「적용 대기」 문구도 Playground 로 바꿨습니다
- ⚠️ 변경 이력의 문장은 그대로 뒀습니다 — 그때 그렇게 부른 것이 사실이라, 이력을 소급해 고치지 않습니다
2026-09-09 — 대화 UI 를 DS 부품으로: 패널 · 말풍선 · 입력줄 · 접속 표시 (design/docs-DS-review-improvements)
왜
채팅 위젯 · 직원앱 메신저 · AI 어시스턴트는 한 화면에 나란히 뜨는데, 정작 말풍선 정의가 셋이었습니다.
| 있던 곳 | 상태 |
|---|---|
messenger-content.html 의 <style> | 하드코딩 hex 6개. 레이어 밖이라 실제로 화면을 그리던 것 |
apps/employee-app/main.css 사본 | 문서 순서에서 위에 밀려 한 번도 그려지지 않음(값까지 갈림) |
ai-assistant.html 유틸 조합 | 유일하게 DS 토큰을 쓰던 쪽 |
그래서 두 대화창의 내 말풍선 주황이 서로 달랐습니다 — #ea580c(Tailwind 기본 orange-600, DS 팔레트에 없는 색)와 --color-primary(#f66014).
바꾼 것
design-system.css에.ds-bubble·.ds-composer·.ds-presence를 신설하고 정의 3곳을 여기로 모았습니다. 파셜의<style>과 employee-app 사본에는 「여기 다시 쓰지 말 것」 주석만 남겼습니다- 말풍선은
--sent·--received·--error셋 + 직교 축--plain(줄바꿈 보존). 폭은 말풍선이 아니라 목록이 정합니다(--ds-bubble-max, 기본 75% · 어시스턴트 도크 85%) - 입력줄은 껍데기(
.ds-composer-bar, 윗선·면)와 줄(.ds-composer, 여백·간격)로 나눴습니다 — 첨부 미리보기가 같은 바 안에 들어가야 해서입니다 - 접속 표시 점은
status-dot status-*(전역 이름) →.ds-presence로 옮기고 Tailwind 기본 4색을 DS 토큰으로 바꿨습니다 - 패널 껍데기도 두 벌이었습니다 —
.ds-chat-panel로 합쳤습니다. 다섯 군데가 갈려 있었어요: 높이600/560·rounded-2xl/rounded-16(같은 값, 다른 철자) · 그림자shadow-2xl(Tailwind 기본)/shadow-popover(DS 토큰) · 테두리neutral-200/neutral-100· 화면 상한 가드 유무. 가드는 둘 다 갖도록 했습니다(없으면 낮은 화면에서 패널 머리가 잘립니다) - 대화 UI 페이지 신설. Playground 는 진입점(FAB)을 눌러 패널을 여는 형태입니다 — 뒤에 표를 깔아 그림자가 보이게 했고(흰 바탕에 얹으면 껍데기 규격의 절반이 안 읽힙니다), 껍데기·말풍선·입력줄 모두 실제 DS 클래스로 그립니다. 패널 안의 대화/연락처 탭·공지 목록은 일부러 그리지 않았습니다 — Messenger 파셜(1,164줄)의 것이라 베껴 두면 그쪽이 바뀔 때 이 그림만 옛날에 남습니다
고쳐진 버그 — 전송·첨부 버튼이 원이 아니었습니다
메신저 입력줄의 전송·첨부 버튼은 rounded-full 을 달고 있었는데, blanket 규칙(button[class*="bg-"] 등)이 모든 <button> 의 radius 를 4px !important 로 강제해서 모난 사각으로 렌더되고 있었습니다. .ds-composer__btn 이 그 규칙이 읽는 --ds-btn-radius 를 세워 !important 없이 이깁니다 → radius 트랩
눈에 보이는 변화
| 전 | 후 | |
|---|---|---|
| 내 말풍선(메신저) | #ea580c | --color-primary #f66014 — 조금 밝고 선명해집니다 |
| 받은 말풍선 | #f3f4f6 · 글자 #1f2937 | --color-neutral-75 · --color-label-normal (거의 동일) |
| 채팅 패널 그림자 | shadow-2xl (Tailwind 기본, 진함) | --shadow-popover — 가벼워집니다 |
| 채팅 패널 테두리 | neutral-200 | --color-line-normal(neutral-100) |
| 어시스턴트 패널 높이 | 560px | 600px (<1280 에서만 보이는 떠 있는 창) |
| 어시스턴트 말풍선 | rounded-12, 꼬리 없음 | 메신저와 같은 16px + 꼬리 |
| 어시스턴트 전송 | 「전송」 텍스트 버튼 | 메신저와 같은 원형 아이콘 버튼 |
| 전송·첨부 버튼 | 사각(의도치 않음) | 원형 |
되돌릴 레버는 design-system.css 의 :root 에 있는 --ds-bubble-* 다섯 축과 --ds-chat-panel-w/h 입니다.
「그 주황이 원래 고른 색이었나」 — 아니었습니다
바꾸기 전에 근거를 확인했습니다. #ea580c 는 2026-04 일괄 「design-system refresh」 커밋에서 들어왔고, 뒤이은 토큰화 커밋이 그것을 --ds-ext-…(팔레트에 자리가 없는 색에 붙이는 접두사)로 바꿨습니다. 지금도 레거시 hr-* 스케일에만 있고 DS 색으로 등록된 적이 없습니다. 말풍선 색을 정한 설계 문서도 없습니다. 패널 그림자의 shadow-2xl 도 채팅 위젯을 처음 만든 커밋 이후 한 번도 재검토된 적이 없습니다.
곁다리로 드러난 것 — 채팅 패널은 낮은 화면에서 머리가 잘리고 있었습니다
껍데기를 합치며 화면 상한 가드(max-height: calc(100vh - 120px))를 양쪽 모두에 준 결과입니다. 채팅 패널은 600px 고정에 bottom: 104px 이라, 세로 704px 미만이면 패널 머리가 잘렸습니다 — 1280×720 노트북에서 브라우저 크롬을 빼면 실제 뷰포트가 그 아래입니다. 어시스턴트에만 있던 가드가 이제 둘 다에 걸립니다.
문서 데모도 함께 옮겼습니다
메신저 문서의 데모(DemoMessengerShell)가 옛 클래스(chat-bubble-* · status-*)와 하드코딩 6색 사본을 그대로 들고 있었습니다. 「파셜의 하드코딩을 그대로 보여 준다」는 이유로 둔 것인데, 정본이 생긴 순간 그 사본은 정본이 바뀌어도 안 따라오는 옛 그림이 됩니다. 정본 클래스로 바꾸고 사본 색은 지웠습니다.
세 페이지가 같은 화면을 보여 줍니다 — 그림은 한 벌입니다
「ChatWidget 페이지에 정작 말풍선·입력줄이 안 보인다」, 「AiAssistant 는 도해만 있고 실제 UI 가 없다」는 지적을 받아 진입점에서 패널이 열리는 실제 화면을 세 페이지에 모두 놓았습니다. 다만 미리보기를 페이지마다 복붙하면 그게 곧 드리프트라, 표면을 그리는 조각은 하나(DemoChatSurface)로 두고 페이지마다 축만 달리 붙였습니다.
| 페이지 | 고르는 축 |
|---|---|
| 대화 UI | 말풍선 종류 · 폭 · 줄바꿈 보존 · 전송 활성 |
| ChatWidget | AI FAB 동반 여부(가로 슬롯이 갈립니다) · 미확인 배지 |
| AiAssistant | 도크 폭 · 말풍선 폭 — UI 적용 뷰와 폭 계약 도해 둘 |
- ChatWidget 페이지의 「준비 중」 딱지를 뗐습니다 — 표준 머리(설명줄·배지줄·Playground)로 바꾸고, 이 페이지가 무엇을 맡고 무엇을 옆 문서에 넘기는지 명시했습니다
- 도크 미리보기는 진짜
.ds-ai-dock규칙으로 그립니다 — 데모가 되덮는 것은position하나뿐이라(진짜는fixed), 폭·모서리 0·왼쪽 테두리·그림자 없음이 전부 정본에서 옵니다
2026-09-09 — 문서가 아예 없던 컴포넌트 둘에 페이지를 냈습니다: AiAssistant · CsReport (design/docs-DS-review-improvements)
왜
문서 정비 상태를 훑다가, 공용 컴포넌트인데 자기 페이지가 한 쪽도 없는 것이 둘 남아 있었습니다. 규칙이 없던 게 아니라 채팅 FAB 문서 안에 얹혀 있었어요 — 남의 집에 세 든 셈이라 사이드바에서 찾을 수 없고, 「AI 도크 규칙이 왜 채팅 문서에 있지」가 됩니다.
| 컴포넌트 | 전 | 후 |
|---|---|---|
AiAssistant | chat-widget 의 #ai-dock 절 | AiAssistant |
CsReport | chat-widget 규칙의 5줄 + 캡처 tip | CsReport |
바꾼 것
- 두 페이지를 신설하고 표준 포맷(설명줄 · 배지줄 · Playground ·
규칙 (강제)· 5탭)에 맞췄습니다 - 원래 있던 규칙은 옮겼습니다 — 복사하지 않았습니다. chat-widget 에는 「옆에 서는 두 UI」 한 절만 남아 두 페이지를 가리킵니다. 규칙을 두 곳에 두면 드리프트가 시작되니까요
- chat-widget 에 남긴 것은 FAB 세트가 실제로 공유하는 것뿐입니다 — 가로 슬롯 계약, 비킴 변수, ESC 디스패처, 말풍선 글자 크기
- Playground 둘을 새로 만들었습니다. 대화창이나 신고 폼을 다시 그리는 대신, 두 컴포넌트에서 실제로 어려운 축만 세웠습니다
DemoAiDockPlayground— 화면 폭과 고른 폭을 바꾸면 상한 · 그리는 폭 · 본문 남는 폭 · 채팅 FAB 비킴이 함께 움직입니다. 「고른 폭」과 「그리는 폭」이 왜 따로여야 하는지가 눈에 보여요DemoCsReportPlayground— 배경 팝업 상태를 바꾸면 z 사다리에서 신고 버튼(65)·신고 모달(68)이 어디에 서는지, 그리고 그 화면을 캡처하면 무엇이 담기고 빠지는지가 함께 바뀝니다
문서 커버리지
커버리지 표의 예외 목록(COVERED_IN)에서 두 항목을 지웠습니다. 이제 전용 페이지로 잡히므로 「부분」이 아니라 문서화 완료 + 라이브 미리보기 있음으로 올라옵니다.
겸사겸사 고친 것
- chat-widget 의
색상 문서(#brand-gradient)링크가 죽어 있었습니다 —foundations/color.md에는 그런 앵커가 없어요. 그라디언트 규칙이 실제로 사는 브랜드 문서로 돌렸습니다 - 2026-09-04 이력의
chat-widget#ai-dock링크도 새 페이지로 옮겼습니다
2026-09-09 — 모달 문서를 한 페이지로 통합, 3종을 탭 + 라이브 Playground 로 (design/docs-DS-review-improvements)
왜
어제 두 페이지를 서로 연결해 놓고 보니, 패널 폼은 모달의 한 종류(패널 모달)인데 사이드바에 모달·패널 폼이 나란히 서 있어 여전히 별개 개념처럼 읽혔습니다. 링크로 잇는 것으로는 부족했고, 한 페이지 안에서 종류를 고르는 축으로 만들어야 맞았습니다.
바꾼 것
- 패널 폼을 모달 문서로 흡수하고
patterns/panel-form.md를 지웠습니다. 사이드바 Patterns 에서도 항목이 빠집니다 - 페이지를 탭 5개로 재배치했습니다 — 공통 · 컨펌 다이얼로그 · 일반 모달 · 패널 모달 · 적용·이력. 상단(3종 표 · Playground 안내 · 규칙(강제))은 탭 밖에 그대로 둡니다
## 규칙§1~§8은 쪼개지 않고 「공통」에 통째로 두었습니다. 문서 곳곳이 「§4 그대로」·「§1~§3과 동일」처럼 번호로 서로를 부르고 있어서, 나누면 그 참조가 전부 어긋납니다- 각 종류 탭 맨 위에 Playground를 놓았습니다. 카드만 놓지 않고 뷰어 안에 딤(40%)이 깔린 위로 실제로 뜬 모습이 뜨고, 속성 패널은 뷰어 아래에 옵니다(
DocPlayground에stacked옵션 신설)
정정 — 문서의 표와 그림이 8px 달랐습니다
「라이브 예시」의 일반 모달 데모가 실제 DS 클래스가 아니라 사본(.modal-demo-*)으로 그려져 있었고, 그 사본의 수치가 같은 페이지 내부 타이포·간격 표와 어긋나 있었습니다.
| 표가 정한 값 | 데모가 그리던 값 | |
|---|---|---|
| 타이틀 ↔ 본문 | 24px | 16px |
| 본문 ↔ 푸터 | 32px | 24px |
이제 컨펌 다이얼로그 데모와 같은 방식으로 실제 .ds-modal__header/__body/__footer 를 씁니다(DemoPlainModal.vue 신설). design-system.css 가 값을 바꾸면 데모도 같이 따라갑니다.
링크 · 앵커
panel-form을 가리키던 링크 18개(직원 추가·직원 수정·내 정보 문서 + 이 변경 이력)를modal#앵커로 옮겼습니다. 변경 이력의 문장은 그대로 두고 링크 대상만 바꿨습니다- 앵커 37개는 전부 살아 있습니다(모달 26 + 패널 폼 11). 숨은 탭 안의 앵커도 URL 로 바로 들어가면 그 탭이 열립니다. 절 하나가 새로 생겨
#panel-form이 늘었습니다 - 제목 한 곳만 정리했습니다 —
두 위저드→두 패널(컴포넌트는73fc32b0에서 이미AddEmployeePanel/EditEmployeePanel로 개명됨). 본문의 「위저드」 표기는 그대로 두었고 백로그입니다
상단을 다른 컴포넌트 페이지와 같은 규격으로
「설명란이 다른 페이지보다 많이 차지한다」는 지적에서 재봤더니 실제로 그랬습니다.
| 제목 아래 → 첫 Playground/탭 바 | |
|---|---|
| Spinner · TabNav · Notice | 209px |
| PermissionDeniedModal | 237px |
| 모달 (정리 전) | 1236px |
| 모달 (정리 후) | 251px |
디자인 시스템 49개 페이지 중 23개가 # 이름 → 설명 1줄 → 배지 1줄 → Playground 골격을 씁니다. 모달은 그 셋이 다 빠진 채 v1 경고 박스와 3종 표가 먼저 오고 있었습니다. 부피의 정체는 그 둘이고, ::: details 규칙 (강제)는 접혀 있어 화면을 차지하지 않습니다.
문구는 옮기기만 했습니다 — 핵심 3원칙 한 줄과 모달은 3종입니다는 「공통」 탭 맨 위로, ::: warning 1차 표준(v1)은 적용 현황을 담고 있어 「적용·이력」 탭 맨 위로 갔습니다. 상단에는 설명 한 줄과 배지 줄이 새로 오고, 라이브 예시가 각 탭 맨 위에 있다는 안내 한 줄이 남습니다.
패턴 페이지 9개 중 이 포맷을 쓰는 것은 모달이 처음입니다.
정정 — 배지 줄이 엉뚱한 자리에 있었습니다
**패턴 · Web** · 진행 중(WIP) 은 panel-form 페이지의 H1 배지였는데, 흡수되면서 「패널 모달」 탭 안 ## 패널 폼 절 아래에 그대로 남아 마치 그 절만의 배지처럼 읽혔습니다. 페이지 배지는 맨 위 한 곳뿐이므로 상단으로 올렸습니다.
prompt 다이얼로그의 본문↔입력칸 간격을 폼 규격(6px)에 맞췄습니다
컨펌 다이얼로그에서 한 줄 입력(prompt) 을 고르면 본문과 입력칸 사이 간격이 0px 이었고, 되살려 보니 12px 이었습니다. 입력칸에 mt-3 을 직접 주었기 때문인데, design-system.css 의 필드 기본 규칙(input:not(.cell-input):not(.ds-input-plain)…)이 margin: 0 을 선언하고 :not() 이 겹겹이라 특이도가 유틸 클래스보다 훨씬 높습니다.
실제 제품 마크업(ds-dialog.html)은 래퍼 <div class="mt-3"> 이 그 간격을 지고, 주석으로 「input 에 mt-3 을 주면 안 먹는다」고 못 박아 두었습니다. 데모만 그 경고를 어기고 있었던 것이라 제품과 같은 구조로 맞췄습니다 — !important 로 되살리지 않습니다.
그런데 12는 폼 컨트롤의 라벨 ↔ 입력칸 6px 과 어긋납니다. showPrompt 의 본문은 message: "시트 이름" 처럼 그 입력칸이 무엇인지 말하는 줄이라 폼과 같은 거리가 맞다고 보고 6px 으로 통일했습니다 — 제품 컴포넌트(ds-dialog.html)와 문서 데모를 함께 바꿨습니다.
본문 글자 등급은 본문(14/400) 그대로 두었습니다. 실제 호출부 3곳 중 2곳이 라벨이 아니라 안내 문장이라(「반려 사유를 입력해 주세요…」 · 두 줄짜리 삭제 경고), 라벨 등급(13/500)으로 바꾸면 그 두 곳이 어색해집니다.
이 간격은 문서 어디에도 없었습니다. 그래서 데모가 0px 으로 어긋나 있어도 대조할 기준이 없었습니다 — 내부 타이포·간격 표에 한 줄을 넣고, 한 줄 입력(prompt) 절을 새로 썼습니다.
실측: 본문↔입력칸 0 → 6px. 같은 화면의 일반 모달도 확인해 필드 타이틀↔인풋 6px · 그룹 사이 16px 로 규격대로였습니다.
정정 — 다이얼로그 본문이 14px 이 아니라 16px 로 그려지고 있었습니다
위 간격을 실제 앱에서 재다가 같이 발견했습니다. 다이얼로그 본문은 규격상 디스크립션 등급(14/400) 인데 앱에서 16px 로 렌더됐습니다.
| 같은 클래스, 다른 태그 | 렌더 |
|---|---|
<p class="text-b4"> | 16px |
<div class="text-b4"> | 14px |
tokens.css 의 레이어 없는 p { font-size: var(--typo-b3-size) }(16px)가 원인입니다. Tailwind 유틸(.text-b4)은 @layer 안에 있어 명시도와 무관하게 레이어 밖 규칙에 집니다. Notice 가 「본문을 <p> 에 넣지 말 것」이라고 적어 둔 것과 같은 함정인데, 다이얼로그가 그걸 밟고 있었습니다.
ds-dialog.html 의 본문과 대상 목록 두 곳을 <p> → <div> 로 바꿨습니다(클래스·동작 그대로, p 규칙이 margin: 0 이라 여백도 안 움직입니다). 실측 16 → 14px, 간격은 6px 그대로.
남은 것 — 같은 함정이 공유 컴포넌트에 54곳 더 있습니다
packages/components/html 을 훑어 <p> 에 text-b4·text-b5·text-b6 을 준 곳을 셌습니다. 전부 16px 로 눌려 있습니다.
| 파일 | 눌림 | 무해(text-b3=16, 우연히 일치) |
|---|---|---|
edit-employee-panel.html | 22 | 0 |
my-info-form.html | 19 | 0 |
messenger-content.html | 10 | 8 |
add-employee-panel.html | 2 | 0 |
permission-denied-modal.html | 1 | 0 |
| 합계 | 54 | 8 |
이번엔 다이얼로그만 고쳤습니다 — 54곳은 화면이 눈에 띄게 바뀌는 범위라 별도 판단이 필요합니다.
남은 것
DemoPanelModal의 닫기 ✕ 가 24px 로 그려집니다. 실제 앱은.ds-modal__close(24×24) 안에.ds-ico w-4 h-4(16px)를 넣습니다 —.ds-modal__close가 안쪽 svg 크기를 정하지 않기 때문입니다. 새로 만든 일반 모달 데모는 앱과 맞췄고, 패널 데모는 이번 범위 밖이라 그대로 뒀습니다
2026-09-08 — 모달 ↔ 패널 폼 연결, 두 패널의 중복 실태 기록 (design/docs-DS-review-improvements)
변경
- 모달 문서의 「패널 모달」 절에서 패널 폼으로 가는 길을 냈습니다. 그전에는 한쪽 링크뿐이었습니다 — 패널 폼은 모달을 가리키는데 모달에는 패널 폼 링크가 0건이라, 모달에서 패널 규격을 읽은 사람이 패널 폼 문서가 있다는 걸 알 방법이 없었습니다. 사이드바에 두 항목이 나란히 보이니 별개 개념처럼 읽히기도 했고요
- 경계를 한 줄로 못 박았습니다 — 모달이 정하는 것은 껍데기(백드롭 · 닫기 · 스크롤 잠금 · 카드 크기), 그 안에서 폼을 굴리는 규칙(필수 누락 표시 · 닫기 가드 · 패널 위 ESC 순서 · 주소 검색 · 주민번호)은 패널 폼입니다
- 모달 문서에 남아 있던 「위저드」 표기 2곳을 정리했습니다
정정
「모달 문서에 있는 위저드 전용 내용(중첩 ESC 가드)을 패널 폼으로 옮기자」고 했던 앞선 제안은 틀렸습니다. 그 가드(typeManagerChildOpen)는 유형·기준 관리 모달의 것이지 직원 패널 것이 아닙니다 — 옮길 것이 없어 그대로 뒀습니다.
기록 — 두 패널이 왜 나뉘어 있나
「추가와 수정이 왜 별도인가」라는 질문에서 세어 봤고, 결과를 검토 필요 사항에 남겼습니다.
- 처음부터 두 파일이었습니다. 하나가 자라 갈라진 게 아니라 2026-05-04 같은 커밋(
51930358)에서 한꺼번에 만들어졌습니다(TS 433 + 567줄, HTML 502 + 593줄) - 지금 함수는 추가 전용 30 · 이름이 같은 것 29 · 수정 전용 38 이고, 이름이 같은 29개 중 14개는 본문까지 글자 하나 안 다릅니다(순수 복사본)
- 나머지 15개는 「이름은 같은데 조금씩 다른」 것들이라 더 위험합니다 — 한쪽만 고쳐도 아무도 모릅니다. 실제로 카테고리 id 가
cert↔certification로 갈라졌고, 주소 흐름 주석에는 「추가에서 수정으로 이식」이라고 적혀 있습니다 - 분리 자체는 되돌릴 필요가 없습니다 — 저장 방식이 진짜로 다릅니다(생성 payload ↔ diff · 계정/비밀번호 별도 경로 · 사번 확정 절차). 갈라야 할 것은 「무엇을 저장하나」, 공유해야 할 것은 **「어떻게 생겼나」**인데 지금은 둘 다 복사돼 있습니다
2026-09-08 — 「Wizard」 이름을 실제 동작에 맞춰 Panel 로 (design/docs-DS-review-improvements)
제품 변경입니다. 파일·컴포넌트·Alpine 등록 이름이 바뀌지만 화면 동작·저장 값·testid 는 그대로입니다.
왜
사용자 질문에서 출발했습니다 — 「모달인데 왜 이름이 Wizard 인가」. 이력을 보니 원래는 진짜 위저드였습니다.
- 2026-05-04 최초 버전은
4-step wizard였습니다 —addEmployeeStep,addEmployeeNextStep(),addStep1Valid()로 순서대로만 갈 수 있었습니다 - 2026-07-02(
d666407b, 「직원 추가·수정 팝업을 패널형 모달로 통일」) 단계가 사라지고 좌측 카테고리 자유 이동이 됐습니다. 순서 강제 대신 빨간 점으로 미완성을 표시하는 방식으로 바뀌었고요 - 동작만 바꾸고 이름은 그대로 뒀습니다. 그래서 코드 첫 줄이 「Add Employee Wizard — … no step gating」으로 스스로 모순돼 있었습니다
게다가 이름이 정확히 뒤집혀 있었습니다 — 진짜 단계형인 RegisterForm은 이름에 위저드가 없고, 위저드라 불리던 둘은 단계가 없었습니다.
바꾼 것
| 전 | 후 |
|---|---|
AddEmployeeWizard.ts · EditEmployeeWizard.ts | AddEmployeePanel.ts · EditEmployeePanel.ts |
addEmployeeWizard(…) · editEmployeeWizard(…) | addEmployeePanel(…) · editEmployeePanel(…) |
add-employee-wizard.html · edit-employee-wizard.html | add-employee-panel.html · edit-employee-panel.html |
attemptCloseWizard() 등 | attemptClosePanel() 등 |
문서 양식 마법사 (patterns/form-wizard) | 패널 폼 (patterns/panel-form) |
사이드바 Components — Forms & Wizards | Components — Forms |
Panel 은 새 용어가 아닙니다 — .ds-modal--panel · panel-nav · testid edit-employee-panel 로 이미 쓰고 있던 말입니다.
범위 — 세어 보니 작았습니다
처음에는 「9개 앱과 e2e 를 동시에 건드린다」고 봤는데 아니었습니다.
- 코드 14파일 · 이 이름을 부르는 앱은 admin · hr-system 둘뿐
- testid 는 전혀 안 걸립니다 — 이미
add-employee-nav-*·edit-employee-panel로 「wizard」 없이 지어져 있었습니다. 진짜 계약은 거기인데 거긴 깨끗했습니다 - 빌드 설정은 주석 한 줄, e2e 는 스펙 안 지역 함수 이름 하나
- DB · API · URL 영향 없음
검증
- 컴포넌트 테스트 94개 통과(48 + 46) ·
pnpm build23/23 - 커버리지 자동 판정이 새 이름으로 짝을 찾는 것 확인(문서화 22 · 미작성 0) — 컴포넌트명↔문서 슬러그를 kebab 으로 맞추는 구조라 문서 파일명도 함께 바꿔야 했습니다
- 문서 3쪽 검증 통과 · 관련 8쪽 죽은 링크 0건
남긴 것
RegisterForm은 이름 그대로 뒀습니다. 진짜 2단계라RegisterWizard가 맞지만, 로그인·가입 화면은 9개 앱이 걸려 범위가 다릅니다- 워크스페이스 생성(
workspaces.html)과 시트 생성은 진짜 위저드라 이름을 유지했습니다
2026-09-08 — 인증 폼 네 개를 로그인 기준으로 통일 (design/docs-DS-review-improvements)
제품 변경입니다. 9개 앱이 같은 파셜을 인라인하므로 전 앱 로그인·가입·비밀번호 화면에 동시에 반영됩니다.
수정
사용자 리포트에서 출발했습니다 — 「로그인의 ID 칸은 라벨에 붙어 있는데 비밀번호 칸은 떨어져 있다」. 실측한 변경 전 상태입니다.
| 라벨↓필드 간격 | 라벨 글자 | 필드 높이 | |
|---|---|---|---|
| 로그인 — ID | 0px | 14px | 40px |
| 로그인 — 비밀번호 | 6px | 14px | 40px |
| 가입 | 4px | 12px | 32px |
| 비밀번호 변경 | 4px | 14px | 32px |
| 비밀번호 찾기 | 0px | 14px | 40px(손수 짠 유틸 + 인라인 style) |
- 네 축을 로그인 기준으로 맞췄습니다 — 라벨 15개는
mb-1.5(6px) +text-sm(14px), 입력 15개는ds-input--40. 찾기 폼의 인라인style="height: 40px"와 손수 짠 유틸, 무의미해진space-y-1.5래퍼 5개를 걷어냈습니다 - 이 6px 는 폼 컨트롤 문서의 필드 규격이 이미 정해 둔 값입니다 — 새로 정한 것이 아니라 지켜지지 않던 것을 맞춘 것입니다
⚠️ 원인 정정 — 처음 적은 진단이 틀렸습니다
처음에는 「design-system.css 가 unlayered 라 맨몸 input 규칙의 margin: 0 이 space-y-* 를 이겨서 로그인 ID 칸 간격이 0 이 됐다」고 적었습니다. 실제 앱 CSS 로 재 보니 사실이 아니었습니다.
Tailwind v4 의 space-y-* 는 뒤 형제의 위 여백이 아니라 앞 형제의 아래 여백입니다.
:where(.space-y-1\.5 > :not(:last-child)) { margin-block-end: 6px }즉 여백이 라벨에 붙습니다. 라벨은 input 규칙의 대상이 아니라 눌리지 않고, 실제 앱에서는 6px 가 정상 동작하고 있었습니다. 0px 로 보였던 것은 문서 데모의 shim 이 Tailwind v3 방식(> * + *, 뒤 형제의 위 여백)으로 적혀 있었기 때문입니다 — 그 형태로는 여백이 입력칸에 얹혀 눌립니다. 그 shim 규칙은 같은 날 e5f4cd31(LoginForm 문서)에서 제가 넣은 것이라, 하루짜리 문서 결함이었습니다.
남아 있던 진짜 차이는 가입·변경 두 폼이었습니다 — 간격 4px, 라벨 12px(가입), 필드 높이 32px. 로그인·찾기는 원래 맞았습니다. 위 표의 통일은 그래서 여전히 유효합니다.
부수적으로 「같은 원인으로 45곳이 더 있다」고 적었던 것도 취소합니다. 그 45곳은 전부 space-y-* 라 라벨에 여백이 붙어 정상입니다. 실제로 눌리는 것은 <input> 에 직접 margin 유틸을 준 경우뿐이고(mt-0.5·mb-2, 파일 4곳), 그건 별개 건입니다.
shim 전수 대조 — 문서가 앱과 같은지 기계로 확인했습니다
같은 실수가 더 있는지 보려고, shim 의 클래스 157개를 실제 admin 빌드 CSS 와 계산값으로 대조했습니다(클래스가 바꾸는 속성만 비교). 결과는 128 일치 · 실질 어긋남 0 입니다. 대조에서 잡아 고친 것 둘입니다.
shadow-sm이 DS 그림자(--ds-shadow-sm)로 적혀 있었습니다. 이 파일의 일은 「DS 답게 쓰기」가 아니라 **「Tailwind 출력 흉내 내기」**라서, 토큰으로 바꿔 두면 문서만 앱과 달라집니다. Tailwind 가 내는 값으로 되돌렸습니다text-b4·b5·b6·h5에letter-spacing이 빠져 있었습니다. Tailwind 는--text-N--letter-spacing도 함께 냅니다
남은 2건은 표기 차이입니다 — 그림자는 값이 같고 앱 쪽에 Tailwind 자리표시자(rgba(0,0,0,0) 0 0 0 0)가 더 붙어 있을 뿐이고, text-indigo-700 은 같은 색의 oklch ↔ rgb 표기입니다.
검증
- 9개 앱 모두 공유 파셜을
@source로 스캔하는 것을 확인(=mb-1.5가 전 앱에서 생성됨) - admin 을 실제로 빌드해
.mb-1\.5{margin-bottom:calc(var(--spacing)*1.5)}생성 확인 - 그 컴파일된 CSS 로 파셜을 렌더해 6px 실측(문서 shim 이 아닌 진짜 Tailwind 결과)
- 문서 데모도 같은 마크업으로 맞춰 네 폼이 간격 6 · 라벨 14 · 높이 40 으로 동일 측정
pnpm build23/23 성공. 린트 실패 1건은employee-app/src/styles/main.css의 기존 문제(변경분을 치워도 동일)
남은 것 — 같은 원인이 45곳 더 있습니다
관리자 초대·워크스페이스·이메일 인증, 급여 시트 모달 등 앱 화면 45곳에서 같은 이유로 라벨과 입력칸이 붙어 있습니다. 추가로 <input> 에 직접 준 margin 유틸 33곳도 조용히 무시되는 중입니다. 범위가 9개 앱 전체라 이번 변경에서는 건드리지 않았습니다 — 근본 수정(맨몸 input 규칙에서 margin: 0 제거)은 78곳이 한 번에 되살아나므로 전수 시각 QA 를 붙여 별도로 다뤄야 합니다.
2026-09-08 — Messenger 문서화 · 컴포넌트 준비중 0 (design/docs-DS-review-improvements)
커버리지의 🔴 준비중이 0 이 됐습니다. 이 세션 시작 시점에는 10개였습니다.
변경
- Messenger 페이지를 채웠습니다. 한 컴포넌트가 두 모드로 사는 것이 이 문서의 축입니다 — 직원 앱의 전체화면 하나, 나머지 일곱 앱의 떠 있는 채팅 위젯. 모아보기에서 같은 옵션이 모드에 따라 정상/고장인 것을 나란히 놓았습니다
- 파셜(1,164줄)·컴포넌트(1,996줄)는 재현하지 않고 서브내비 줄과 채팅 상세 헤더만 옮겼습니다 — 모드에 따라 실제로 달라지는 것이 그것이라서요
강제 규칙으로 적은 함정
hostHeader를 위젯에서 켜면 대화방에서 못 빠져나옵니다. 「호스트가 상단 앱바를 그린다」는 약속이라 켜면 채팅 상세가 자기 헤더 줄(뒤로가기)을 안 그립니다. 전체화면에는 그 앱바가 실제로 있어 정상이지만, 위젯에는 상단 헤더가 아예 없습니다. 기본값이false인 이유입니다- 컴포넌트를 spread 로 감싸면 getter 가 죽습니다. ChatWidget이
{ ...component }가 아니라 mutate 로 얹는 이유입니다 — 스프레드하면filteredConversations같은 getter 가 그 자리에서 한 번 평가돼 고정값이 되고, 대화가 와도 목록이 안 바뀝니다. 에러는 안 납니다 - 「대화 / 연락처」 전환은 SubTab 이 아니라 TabNav 입니다. 이름(
messengerSubTabs)도 타입(SubTabItem[])도 SubTab 이라고 말하지만 마크업은tabNav({ size: 'ml', divider: false })를 include 합니다. 두 타입이 구조적으로 호환돼 검사를 통과할 뿐입니다
발견
- 이 컴포넌트의 CSS 가 공유 파셜 안
<style>블록에 있습니다 —design-system.css도 앱main.css도 아닙니다(「모든 앱에서 동작하도록 심었다」는 주석). DS 로드 체인 밖이라 토큰 정리에서 빠졌고, 말풍선·상태 점의 하드코딩 hex 6종이 그대로 남아 있습니다. 같은 블록에서 배경 하나만var(--ds-bw-white)로 토큰화돼 있어 절반쯤 옮기다 만 상태입니다 - 미확인 배지가 60초 폴링에 기대고 있습니다. 실시간 구독이
loadData()안에서 걸리는데 그건 패널을 한 번 열어야 도므로, 한 번도 안 연 사용자에게는 최대 1분 지연이 있습니다
2026-09-08 — MyInfoForm 문서화 (design/docs-DS-review-improvements)
커버리지의 🔴 준비중이 2 → 1 로 줄었습니다. 남은 것은 Messenger 하나입니다.
변경
- MyInfoForm 페이지를 채웠습니다. 이 컴포넌트도 옵션이 하나도 없어서(9개 앱이
x-data="myInfoForm"로 똑같이 씁니다) 축이 하나뿐입니다 — 조직 설정selfEditableFields. 그래서 코드 탭에는 호출이 아니라 그 설정이 어떻게 읽히는지가 나옵니다 - 모달 전체(476줄)는 재현하지 않고 섹션 목록과 편집 연필이 어디에 붙는지만 옮겼습니다. 화면이 실제로 갈리는 것이 그것뿐이라서요
짚어 둔 것
- 기본값이 「전부 허용」이 아닙니다. 조직이 설정을 안 하면
canEdit()안에 박힌 기본값 주소 · 비상연락처 · 프로필 사진 셋만 열립니다. 연락처·계좌정보는 명시적으로 켜야 보입니다 - 전부 잠긴 상태가 정상입니다. 그때는 연필이 하나도 없고 「수정이 필요한 경우 관리자에게 문의해 주세요.」 한 줄이 유일한 설명이라, 지우지 말라고 강제 규칙에 적었습니다
- 사번·팀·입사일·이메일은 설정으로도 못 엽니다 —
canEdit대상 자체가 아닙니다. 「연필을 붙여 달라」는 요청은 설정이 아니라 정책 문제입니다 - 서명/도장은 캔버스로 360×160 안에 줄여 PNG data URI 로 저장합니다(투명 배경 보존, 서버 제한 약 300KB). 결재 문서 서식의
{{서명}}자리에 그대로 들어갑니다 - 알림은 DS 다이얼로그(
showAlert/showError)를 씁니다 — 위저드의 자체notice와 다르고, 이쪽이 맞는 방향입니다. 문서에도 그렇게 적었습니다
발견
- 주소 검색 로더 세 번째 복사본이 여기 있습니다(위저드 둘 + MyInfoForm). 패턴 문서에 적어 둔 것과 같은 건이고, 이 문서에서도 다시 짚었습니다
- 전화번호 포맷도 각자입니다 — 가입 폼과 규칙이 같은데 코드는 따로 있어, 한쪽만 고치면 어긋납니다
2026-09-08 — 폼 위저드 패턴 문서 신설, 위저드 문서 중복 정리 (design/docs-DS-review-improvements)
변경
- 폼 위저드 패턴 문서를 신설했습니다. 5줄 스텁이던 페이지입니다. 직원 추가·직원 수정 문서에 나뉘어 있던 공유 규칙을 여기로 모았습니다 — 패널 셸 · 좌측 카테고리 메뉴 · 필수 누락 표시 · 닫기 가드 · ESC 층 · 주소 검색 · 주민등록번호 · 알림 팝업
- 두 위저드 문서는 참조로 바꿨습니다. 옮긴 절은 제목과 앵커를 그대로 두고 본문만 한 줄 안내 + 링크로 교체했습니다 — 기존 주소가 하나도 안 깨집니다. 각 문서에는 그 위저드만의 것(카테고리 구성 · 저장 방식 · 빨간 점 유무 · 사번 변경 흐름)만 남았습니다
- 두 위저드가 함께 안고 있는 문제도 각 문서에서 빼고 패턴 문서의 「검토 필요 사항」 한 곳에 모았습니다
검증
- 옮긴 문단 6개가 패턴 문서에 문구 그대로 있는지 기계적으로 대조 — 유실 0
- 두 문서의 앵커(
#close-guard#esc#address#validation#free-nav#rrn#no-dots) 전부 살아 있음 - 새로 생긴 페이지 간 링크 11개가 5개 대상 앵커로 전부 정상 연결되는 것까지 실제로 눌러 확인
발견
- 주소 검색 로더가 세 벌 복사돼 있습니다.
AddEmployeeWizard·EditEmployeeWizard·MyInfoForm셋 다 자기 안에 같은_loadDaumPostcode()·daumPostcodePromise· CDN 주소를 갖고 있습니다.packages/components/src/utils/에 공용 자리가 이미 있는데(rrn.ts·fetch-all-pages.ts등) 주소 검색만 빠져 있습니다 — 패턴 문서에 **「네 번째를 복사하지 말 것」**을 강제 규칙으로 적었습니다
2026-09-08 — EditEmployeeWizard 문서화 (design/docs-DS-review-improvements)
커버리지의 🔴 준비중이 3 → 2 로 줄었습니다. 남은 것은 MyInfoForm · Messenger 입니다.
변경
- EditEmployeeWizard 페이지를 채웠습니다. 추가 위저드와 같은 패널 셸이라, 문서의 무게를 **「무엇이 다른가」**에 뒀습니다 — 모아보기에서 두 좌측 메뉴를 나란히 놓습니다
- 사번 변경 흐름과 저장 경로 둘을 다이어그램으로 넣었습니다. 사번은 로그인 ID 이기도 해서 입력 → 확정 해제 → 실시간 중복 검사(본인 제외) → [수정] 확정 → 저장의 단계를 지나야 하고, 비밀번호는 부모 저장 버튼이 아닌 별도 경로로 저장됩니다
발견 — 두 위저드가 이미 갈려 있습니다
같은 패널 셸에 같은 도메인인데 계약이 셋 다릅니다.
| 추가 | 수정 | |
|---|---|---|
| 카테고리 | 4개 (cert) | 5개 (certification + account) |
| 필수 누락 빨간 점 | 있음 | 없음 |
| 저장 | 폼 전체를 생성 payload 로 | 바뀐 것만(주소 diff · 계약 upsert) |
카테고리 id 가 cert ↔ certification 로 다른 것이 대표적입니다 — 한쪽 코드를 복사해 오면 조용히 안 맞습니다. 주소 흐름은 코드 주석에 **「추가에서 수정으로 이식」**이라고 적혀 있는데, 그 말은 다음에도 손으로 옮겨야 한다는 뜻입니다.
form-wizard 패턴 문서가 비어 있는 것이 이 문제의 자리입니다 — 두 위저드가 공유하는 것(패널 셸 · 좌측 카테고리 · ESC 층 · 닫기 가드)을 거기 한 번만 적고 두 문서가 참조하는 편이 낫습니다. 지금은 양쪽에 조금씩 들어가 있습니다.
2026-09-08 — AddEmployeeWizard 문서화 (design/docs-DS-review-improvements)
커버리지의 🔴 준비중이 4 → 3 으로 줄었습니다.
변경
- AddEmployeeWizard 페이지를 채웠습니다. 폼 전체는 재현하지 않았습니다 — 입력 마크업만 999줄이고, 문서가 정해야 할 것은 입력 칸이 아니라 좌측 카테고리 메뉴의 계약(자유 이동 + 필수 누락 빨간 점)이라서 그쪽만 실제 마크업으로 옮겼습니다. 축은 「어느 카테고리가 미완성인가」입니다
- 닫기 가드와 ESC 층을 다이어그램으로 넣었습니다. X·취소·ESC 가 전부
attemptCloseWizard()를 지나 손대지 않은 폼은 바로, 입력했으면 저장확인으로 갈리고, ESC 는 패널 위 레이어 넷을 위에서부터 하나씩만 닫습니다(막 닫은 뒤 500ms 유예). 맨 앞에서 권한 팝업에 양보하는 것도 같은 순서에 있습니다 - 저장 payload 규칙을 적었습니다 — 안 채운 선택 항목은
""가 아니라 키를 뺍니다. 주민번호는 13자리가 유효할 때만, 근태 방식은 조직 기본값과 다를 때만 넣습니다. 이 동작은 컴포넌트 테스트가 고정하고 있어, 문서 규칙 대부분의 출처가 테스트 파일입니다
짚어 둔 것
- 저장이 막힌 이유가 화면 밖에 있을 수 있습니다. 검사는 네 카테고리 전부를 보는데 빨간 점은 좌측 메뉴에만 있어서, 긴 폼을 스크롤하다 저장을 누르면 왜 안 되는지 바로 안 보입니다. 그래서 문서에 **「점을 없애면 안 된다」**를 강제 규칙으로 적었고, 저장 버튼 옆 안내는 「검토 필요 사항」으로 남겼습니다
- 알림 팝업이 자체 구현입니다.
notice: { show, tone, message }로alert()를 대체한 것인데 지금은 DS 다이얼로그가 있습니다. 코드 주석도tone이 「현재 시각 스타일은 동일」이라고 적고 있어 옮길 수 있어 보입니다 - 주소 검색이 외부 CDN(
t1.daumcdn.net)을 lazy 로드합니다. 망 분리·CDN 장애 때 무엇을 보여 줄지 정해져 있지 않습니다
2026-09-08 — PermissionDeniedModal 문서화 (design/docs-DS-review-improvements)
커버리지의 🔴 준비중이 5 → 4 로 줄었습니다.
변경
- PermissionDeniedModal 페이지를 채웠습니다. 옵션이
descriptions하나뿐이라, 문서의 무게를 **「어떻게 띄우나」**에 뒀습니다 — 이 컴포넌트는 인스턴스를 붙잡는 게 아니라 window 이벤트(permission-denied)로 열리고, 대부분은 SDK 가 403 을 받아 자동으로 띄웁니다. 그 사슬(403 →hereby:permission-error→ 앱이preventDefault()안 하면 →permission-denied→ 팝업)을 다이어그램으로 넣었습니다 - ESC 를 나눠 쓰는 규칙을 정리했습니다. 이 팝업과 위저드 패널이 둘 다
@keydown.escape.window를 쓰고 리스너 순서는 DOM 순서라 화면에 늦게 뜬 것과 무관하므로, 패널의escapeClose()는 맨 처음에permissionModalOwnsEsc()로 양보해야 합니다(막 닫힌 직후 500ms 도 양보 대상) - z 층 표를 넣었습니다 — 이 팝업은
--ds-z-modal-system(75)이라 일반 모달(50) · 신고(68) · 컨펌 다이얼로그(70)보다도 위입니다. 전역 팝업은 항상 마지막에 뜨므로 그게 맞습니다
발견
- ESC 양보 헬퍼를 앱에서 쓸 수 없습니다.
esc-guard.ts의permissionModalOwnsEsc()·registerEscLayer()가 패키지 index 로 내보내지지 않아, 지금 양보할 수 있는 것은packages/components안의 위저드 둘뿐입니다. 앱 안에 ESC 로 닫히는 패널을 새로 만들면 같은 사고가 다시 납니다 — 문서의 「검토 필요 사항」에 적었고 코드는 건드리지 않았습니다 - 오류 notice 에만 아이콘이 없습니다. 같은 팝업에서 전송 완료는
ic-check-circle이 있는데 오류는 글자만 있습니다. notice 규격상 아이콘은 독립 축이라 위반은 아니지만, 한 팝업 안에서 갈리는 것은 일관성이 떨어집니다 - 이 팝업은 DS 3종 모달 밖입니다. 카드 여백(
pt-11 px-10 pb-9) · 그림자(filter인라인 style) · 최대 폭이 마크업에 흩어져 있고 버튼은 레거시.ds-mini-modal__btn입니다. 값은 위저드 모달과 맞춰 둬서 화면은 어긋나지 않지만 규격이 마크업에 있는 상태라, 문서 곳곳에 「이걸 보고 새 모달을 만들지 말 것」을 적었습니다 - 직원 앱에는 권한 요청을 보낼 방법이 없습니다.
hereby:permission-error를preventDefault()로 먹고 토스트로만 알리는데, 그 한 줄이 이 팝업의 유일한 진입 경로를 닫습니다. 모바일에서 전체 모달이 과하다는 판단 자체는 타당하지만 결과는 확인이 필요합니다
2026-09-08 — Segment 문서 신설 (design/docs-DS-review-improvements)
그동안 SubTab 문서의 비교 tip 에 「.ds-segment 와 다른 형태」로만 언급돼 있고 자기 규격이 없던 컴포넌트입니다(커버리지 🟡 부분 3개 중 하나). 사이드바 Components — Navigation 에 항목을 더했습니다.
변경
- Segment 페이지를 새로 썼습니다. 축은 그룹(size · fill)과 탭 단위 슬롯(앞/뒤 아이콘 · disabled)이고, 여기에 「놓이는 자리의 폭」을 축으로 더했습니다 — 이 컴포넌트에서 실제로 터지는 것이 옵션이 아니라 폭이기 때문입니다
- 셋을 고르는 기준 표(Segment · SubTab · TabNav)를 넣었습니다. 세그먼트만 선택 없음이 불가능하다는 것이 갈림길입니다
실측으로 확인한 것 (문서에 수치를 남겼습니다)
- ⚠️ 아이콘 슬롯이 동작하지 않습니다 — 0×0.
leadingIcon/trailingIcon에 이름을 넘겨도 아무것도 안 보입니다. 래퍼<span class="inline-flex items-center">와 그 안의<svg>가 둘 다 0×0 으로 접힙니다(getComputedStyle도0px / 0px). 파셜에도 CSS 에도 크기 선언이 없고 등록본 SVG 는viewBox만 있어 기댈 값이 하나도 없습니다. 에러도 경고도 없어 켠 사람은 아이콘 이름을 의심하게 됩니다. 프로덕션에서 이 슬롯을 쓰는 곳이 한 곳도 없어 드러나지 않았을 뿐입니다 — 고치는 방향은 「검토 필요 사항」에 적었습니다 - 폭이 모자랄 때 무너지는 방식이
fill에 따라 다릅니다. 처음엔 「넘친 탭이 사라진다」로 적었다가, 재 보고 고쳤습니다.fill이면 항목이 균등하게 줄다가 라벨이 옆 탭 위로 삐져나와 겹치고(160px 에 4탭 → 항목 39px vs 라벨 48px),fill이 없으면 트랙이 부모를 넘어갑니다(240px 자리에 트랙 342px). 위험한 쪽은fill을 켠 자리이고, 직원앱 서류 업로드 · 셀 상세 패널 · 랜딩 데모가 전부fill입니다 - 같은 4탭이 560px 에서는 멀쩡합니다(항목 138px). 넓은 화면에서만 보면 못 잡는 고장이라, 모아보기에 240px · 560px 을 나란히 뒀습니다. 랜딩에서 이 상태로 4탭 중 3탭이 모바일에서 도달 불가가 됐던 기록이 앱 CSS 주석에 남아 있습니다
함정
- 데모 검사 스크립트가 세그먼트 자신의
role="tab"을 눌렀습니다. 문서 탭을[role="tab"]으로 잡고 있었는데 이 컴포넌트가 같은 role 을 쓰는 첫 사례라 충돌했습니다 —.doc-tabs__tab으로 좁혔습니다. 페이지 문제가 아니라 검사 문제였습니다
2026-09-08 — LNB 하단 브랜드 마크가 문서에 반영됐습니다 (design/docs-DS-review-improvements)
PR #591(2026-08-26 머지)은 brand.md 와 이 이력만 갱신하고 컴포넌트 문서 두 곳을 남겨 뒀습니다. 그 어긋남을 맞췄습니다.
수정
- LNB 셸 예시가 「하단 영역은 없다」로 적혀 있었고 코드에 브랜드 마크가 빠져 있었습니다. 그 예시를 그대로 복사하면 마크가 통째로 누락됩니다 — 가장 확실한 오류라 먼저 고쳤습니다. 「구조」 목록에도
brandmark를 넣고,bottom(프로필·토글이 있던 자리)과 다른 것임을 명시했습니다 - 하단 브랜드 마크 절을 새로 썼습니다. 자산이 펼침/접힘에 따라 락업 ↔ 심볼로 바뀌는 이유(레일 안쪽 폭 44px), 높이 18px 가 락업 최소 높이 16px 바로 위라는 것, 그리고 마크업도 숨김 판정도 partial 이 아니라 앱이 한다는 것을 적었습니다. 특히 **「숨긴 채로 재면
scrollHeight가clientHeight로 잘려 마크가 영영 안 돌아온다」**는 함정은 그동안 CSS 주석에만 있었습니다 DemoLnbSidebar가 하단 마크를 그립니다. 실측 확인 — 펼침 락업 120×18(865:130비율 그대로) · 접힘 심볼 18×18 · 불투명도 0.3 ·pointer-events: none·aria-hidden. 다만 데모는 높이가 고정이라 실제 앱이면 숨길 상황에서도 계속 보여 줍니다 — 그 점을 모아보기 설명에 적었습니다- WorkspaceSwitcher 문서의
.ws-brand서술이 낡아 있었습니다. 「그라데이션 로고 + "Hereby Workspace" 텍스트」로 적혀 있었는데Hereby대문자는 브랜드 표기 위반이고(항상 소문자), 실제 텍스트는$store.hereby.brand+ 조직명 두 줄입니다. 심볼 자리를 병원 로고가 가져갈 수 있다는 것도 별도 절로 넣었습니다 - 트랩 ②(
.ws-brand의x-data를 지우지 말 것)의 근거를 갱신했습니다.iconFor('logo-hereby-medical')→ 지금은iconFor('logo-hereby-' + brandFamily)이고, 무엇보다 로고를 등록한 조직에서는<img>라iconFor를 아예 안 탑니다 — x-data 를 지워도 그 조직에서는 멀쩡해 보이고 로고 없는 조직에서만 깨집니다. 확인 방법을 함께 적었습니다
⚠️ 사용자 가이드 — 외부 원고를 직접 고쳤습니다 (콸 리뷰 필요)
docs/ko/guides/fragments/guide-admin.html 는 외부 PM 팀(콸/카나) 납품 원고이고 gen-docs-guides.mjs 가 본문을 바이트 그대로 옮기는 구조입니다. 원칙대로면 요청만 남길 자리인데, 화면과 어긋난 설명이 직원분들에게 그대로 보이는 상태라 사용자 지시로 이번에 직접 고쳤습니다. 다음 원고 재납품 때 되돌아갈 수 있으므로 콸 쪽 리뷰를 받아 원고에 반영해야 합니다.
고친 곳 4군데입니다(3곳으로 알았다가, 앱 도움말 인용문이 낡은 것을 발견해 하나 늘었습니다).
| 위치 | 고치기 전 | 고친 뒤 |
|---|---|---|
| §0-2 화면 둘러보기 | 병원 로고가 함께 나란히(코브랜딩) 표시됩니다 | 그 자리를 병원 로고가 대신합니다 + hereby 는 좌측 메뉴 맨 아래로 |
| §19 로고 업로드 (앱 도움말 인용) | 「좌측 상단에 hereby 로고와 함께 병원 로고가…」 | 「좌측 상단 로고 자리에 병원 로고가…」 — 앱 화면의 현재 문구 |
| §19 등록 결과 | hereby 심볼과 나란히(코브랜딩) | 심볼 자리에 표시(hereby 심볼을 대신) |
| §19 설정 결과 요약 | 병원 로고는 코브랜딩으로 반영되고 | 병원 로고는 좌측 상단 로고 자리에 반영되고 |
「메뉴를 접으면 로고가 작아진다」 같은 서술은 넣지 않았습니다 — 접힘 레일에서 사라지는 것은 옆의 글자(.ws-trigger-text)이고 로고는 24px 그대로입니다.
갱신 요청 (이 레포에서 고칠 수 없는 것)
- 사양서
docs/spec/HBAD/HBAD100.md§05 가 아직 코브랜딩으로 적혀 있습니다. 정본이 Confluence 라 PR #591 이 손대지 않고 남긴 요청입니다 — 위 가이드 리뷰와 함께 전달해 주세요 - 앱 코드에 낡은 주석이 남아 있습니다 —
apps/admin/src/views/tabs/settings.html의 병원 로고 미리보기 주석이 「LNB 「hereby × 병원로고」 코브랜딩에 쓰이는 이미지」로 되어 있습니다. 화면 문구가 아니라 개발자 메모라 이번 문서 작업에서는 건드리지 않았습니다
2026-09-08 — 인증 화면 5종 문서화 (design/docs-DS-review-improvements)
커버리지의 🔴 준비중이 10 → 5 로 줄었습니다. 남은 것은 AddEmployeeWizard · EditEmployeeWizard · MyInfoForm · Messenger · PermissionDeniedModal 입니다.
변경
- LoginForm 문서가 「준비 중」 스텁에서 실제 문서가 됐습니다. 축을 두 갈래로 나눴습니다 — 앱이 넘기는 옵션(제목 · 부제 · BI 심볼 · 회원가입 링크 · 통합 로그인)은 호출 코드를 바꾸고, 서버가 정하는 것(로그인 방식 탭 · 비밀번호 찾기 링크)과 화면 상태(오류 · 로딩 · 인증번호 발송됨)는 코드를 바꾸지 않습니다. 이 구분이 이 컴포넌트에서 가장 자주 틀리는 부분이라 Playground 속성 패널에서도 줄을 갈라 놓았습니다. 모아보기에는 9개 앱이 실제로 쓰는 7가지 상태가 들어갑니다
- RegisterForm 문서도 채웠습니다. 이 컴포넌트는 넘길 옵션이 거의 없어서(
title·onSuccess둘뿐) 축이 대부분 상태입니다 — 단계(1↔2) · 브랜드 구성 3종 · 검증 오류 · 제출 실패 · 처리 중. 그래서 코드에 바뀌는 것은 폼 호출이 아니라 앱이 SDK 플러그인에 넘긴 브랜드 값이고, 그것이 상단 락업을 정합니다. 오류가 두 종류(필드 검증은 입력 아래 붉은 한 줄, 제출 실패는 notice 한 덩어리)라는 것을 모아보기에서 나란히 볼 수 있습니다 - ChangePasswordForm · ForgotPasswordForm 문서도 채웠습니다. 둘은 뼈대가 사실상 같아(원형 아이콘 배지 → 제목 → 부제 → 성공 notice 또는 폼) 데모 컴포넌트를 하나로 두고
kind로 갈랐습니다. 배지 아이콘이 자물쇠 ↔ 열쇠로 갈리는 것이 두 화면을 구분하는 유일한 시각 신호라 그것도 적어 뒀습니다. 변경 화면은 현재 비밀번호 칸이 없는 것이 규격이고(그 값은 스토어가 로그인 때 잡아 둔 것), 찾기 화면은 옵션이 하나도 없어 코드가 늘 같습니다 - AuthGate 문서를 채우면서, 이 컴포넌트가 어디서도 안 쓰인다는 것을 확인했습니다. 등록·내보내기·주석은 살아 있는데 레포 전체
.html에서x-data="authGate"가 0건입니다(빌드 산출물 포함). 아홉 앱은 전부 라우터 기반 뷰 전환을 쓰고, 그쪽만 강제 비밀번호 변경과 비밀번호 찾기를 다룹니다 — AuthGate 의 세 갈래에는 그 둘이 들어갈 자리가 없습니다. 이 사실을 페이지 맨 위 경고와 「검토 필요 사항」에 적었고, 그리는 것이 없는 컴포넌트라 Playground 대신 분기도를 넣었습니다 - 커버리지의 「라이브 미리보기 적용 대기」에 예외를 뒀습니다. 일부러 안 만든 것(지금은 AuthGate 하나)이 「대기」 줄에 서지 않도록
NO_PREVIEW를 두고, 사유를 반드시 적게 했습니다 — 사유 없이 늘리지 않기 위해서입니다. 그 목록은 표 위에 사유와 함께 따로 보입니다 - 인증 폼 유틸을
ds-tailwind-shim.css에 더했습니다. 이 네 화면은 DS 컴포넌트 클래스가 아니라 공용 partial 에 박힌 Tailwind 유틸로 짜여 있어서, 데모가 앱 마크업을 글자 그대로 쓰려면 그 유틸이 docs 에도 있어야 합니다(약 60개 — 여백 · 크기 · 보더 · 색 · 브랜드 조판 · 버튼 안 스피너 회전).rounded-md(6px)만 DS 에 대응 토큰이 없어 Tailwind 값을 그대로 씁니다
발견
RegisterForm.ts머리 주석의 기관 코드 설명이 코드와 다릅니다. 주석은 「organizationCode (3-20 chars, alphanumeric + hyphens)」인데 실제 정규식은/^[a-zA-Z][a-zA-Z0-9_-]{2,49}$/— 3~50자이고 밑줄도 허용합니다. 로케일 문구는 정규식 쪽과 맞으므로 주석만 낡은 것으로 보이지만, 어느 쪽이 의도인지 확인이 필요해 문서의 「검토 필요 사항」에만 적었습니다- module-manager 로그인의 「회원가입」 링크가 빈 화면으로 갑니다.
loginForm()에showSignupLink를 안 넘겨 기본값true가 걸리는데, 이 앱에는/signup뷰도 라우트도 없습니다. 누르면 어떤x-if에도 안 걸려 흰 화면이 되고, 새로고침하면isKnownPath검사에 걸려 404 안내로 튕깁니다. 기본값에 맡긴 앱은 9곳 중 여기 하나뿐입니다(admin 은 명시true+ 뷰 있음, 나머지 7곳은 명시false). 문서에만 기록했고 코드는 고치지 않았습니다 — 고치는 방법은 두 가지(그 앱에showSignupLink: false한 줄, 또는 기본값을false로 뒤집기)이고 후자는 동작 변경이라 별도 결정이 필요합니다
2026-09-08 — 문서가 코드와 어긋나던 두 곳 (design/docs-DS-review-improvements)
수정
- TabNav 의
fill이 API 표에 들어왔습니다.TabNav.ts(fill?: boolean, 기본false) ·tabNavFillClassgetter ·nav.ds-tab-nav--fillCSS 에 이미 구현돼 있는데 표에만 없던 옵션입니다.TabNavOptions에fill행을, 노출 멤버 표에tabNavFillClass행을 더했습니다 - Notice 사용법의 아이콘 예시를 실제 앱이 쓰는 형태로 바꿨습니다. 예시가 인라인
<svg class="ds-notice__icon">이라 그대로 앱에 옮기면pnpm check:icons가 커밋을 막던 코드였습니다(문서.md는 검사 대상이 아니라 조용히 남아 있었습니다). 앱 실제 사용처 12곳과 같은<span class="ds-ico ds-notice__icon" x-html="$icon('ic-exclamation-circle')">로 맞추고,ds-ico를 빼면 안 되는 이유(없으면display:inline이라 16×16 이 안 걸리고 주입된<svg>가 컨테이너를 채움)를 한 줄 덧붙였습니다
2026-09-07 — 컴포넌트 문서에 Playground + 탭 도입 (design/docs-DS-review-improvements)
변경
- Form controls 문서도 같은 형식으로 옮겼습니다. 여러 컨트롤이 한 페이지에 있어 축의 첫 자리를 종류(입력 · 드롭다운 · textarea · 숫자 · 체크박스 · 라디오 · 스위치)로 두고 사이즈 · 상태 · 필드 슬롯을 조합합니다. 피커는 팝오버로 뜨는 별개 UI라 축에 넣지 않고 모아보기에서 봅니다. ⚠️ 옮기는 과정에서
ds-menu__item--danger설명과 「메뉴 항목에 hover 유틸 금지」 경고가 미리보기 절에만 있어 사라질 뻔한 것을 확인해#menu-panel절로 원문 그대로 옮겼습니다(클래스 표에도 없던 내용) - LnbSidebar 문서도 같은 형식으로 옮겼습니다. 축은 펼침↔접힘(208px ↔ 68px)과 두 종류(LNB · 패널 모달 내비)이고, 코드에는 루트에
--expanded/--collapsed중 하나가 반드시 붙어야 한다는 것과 접기 버튼의 모바일 가드가 함께 나옵니다. 예전 데모 주소#panel-nav-demo는modal.md가 페이지 간 링크로 참조하므로 앵커로 유지했습니다 - AppHeader 문서도 같은 형식으로 옮겼습니다. 축은
appHeader(options)그대로(깊이 · solid · divider · 탭 줄 · 액션 · 벨 · 아바타)이고, 깊이는 별도 플래그가 아니라onBack을 넘기느냐로 정해진다는 점이 코드에 그대로 드러납니다. 본문에 흩어져 있던 데모 8개는 「모아보기」 탭으로 모았습니다 - 「모아보기」에서는 속성 패널이 뷰 아래로 내려갑니다. 조합을 넓게 펼쳐야 하는 탭이라 뷰가 전체 폭(686px)을 쓰고, 패널은 아래에서 가로 3열로 흐릅니다. 미리보기·코드 탭은 좌우 배치 그대로입니다
- BottomNav 문서도 같은 형식으로 옮겼습니다. 축은
BottomNavItem이 실제로 갖는 슬롯(활성 fill 글리프 · 배지 ·disabled·hidden)이고, 바꾸면 config 코드가 함께 바뀝니다. 모아보기에서hidden(목록에서 빠짐)과disabled(남되 안 눌림)의 차이, 배지 150 → 「99+」 잘림, fill↔outline 비교를 나란히 볼 수 있습니다 - WorkspaceSwitcher 문서도 같은 형식으로 옮겼습니다. 옵션이
current하나뿐인 컴포넌트라 축은 그 하나에 문서가 설명하던 두 표시 상태(정적 브랜드.ws-brand· LNB 접힘)를 더했습니다 — 둘 다 CSS 에는 있는데 데모가 못 그리던 상태입니다. 「신규 도입 금지」는 상단 표기와 모아보기 설명에 모두 남겼습니다 - PageHeader 문서도 같은 형식으로 옮겼습니다. 3 region(TitleBar · ActionGroup · Toolbar) 안의 슬롯을 켜고 끄면 호출 코드가 패턴 1↔2 로 바뀝니다(ActionGroup 이 있으면 셸을 직접 써야 하므로). 손으로 짠 정적 목업 4개를 실제 컴포넌트 렌더로 교체했습니다 —
DemoPageHeader에 region/슬롯 props 를 더해(기본값은 기존 「풀 상태」 그대로) 모아보기에서 네 상태를 그립니다 - TabNav 문서도 같은 형식으로 옮겼습니다. 축(size · divider · fill)과 탭 단위 슬롯을 Playground 에서 켜고 끄면 호출 코드가 함께 바뀝니다. 흩어져 있던 데모 8개는 「모아보기」 탭으로 모았습니다. ⚠️
fill(줄을 균등 분할,.ds-tab-nav--fill)은TabNav.ts·파셜·CSS 에 이미 구현돼 있는데 문서 API 표에는 빠져 있었습니다 — Playground 에는 넣었고, 표에는 2026-09-08 에 행을 더했습니다 - SubTab 문서도 같은 형식으로 옮겼습니다. 축은 문서가 정의한 넷(size · radius · color · fill)이고, 코드는 클래스가 아니라
subTab({…})호출 + partial include 형태로 나옵니다(마크업을 손으로 짓지 말라는 강제 규칙과 같은 방향). 축별로 따로 펼쳐 두던 데모 10개는 「모아보기」 탭으로 모았습니다 - Tooltip 문서도 같은 형식으로 옮겼습니다. 축은 문서가 정의한 셋(종류 · placement · 색 톤)이고, 미리보기는 흉내가 아니라 실제 경로입니다 —
data-ds-tip+title마크업만 두면 docs 가 앱과 똑같이 호출해 둔 싱글톤setupTooltip()이 hover 를 처리합니다. 기존 네 줄짜리 데모(DemoTooltip)는 「모아보기」 탭으로 옮겼습니다.rightplacement 는 셀렉터 전용(접힌 LNB 메뉴)이라 Playground 로는 켤 수 없어 모아보기에서만 보입니다 - Spinner 문서도 같은 형식으로 옮겼습니다. 축은 「종류(영역 링 · 인라인 아이콘) × 받침 · 지름 · 두께」이고, 지름이나 두께를 바꾸면 코드가 확장 규칙대로 변수만 덮는 변형 클래스 형태로 나옵니다 — 인라인 style 을 권하지 않기 위해서입니다. 예전 「라이브 미리보기」의 세 칸에 인라인 아이콘 칸을 더해 「두 종류」가 한 화면에서 비교됩니다
- Notice 문서도 같은 형식으로 옮겼습니다. 축은 문서가 정의한 그대로 「변형 4종 × 아이콘 on/off」이고, 예전 「라이브 미리보기」의 8상태 그리드는 「모아보기」 탭으로 들어갑니다. 미리보기 아이콘은 인라인
<svg>에서 레지스트리 아이콘으로 바꿨습니다 —.ds-notice__icon이 평범한 클래스 선택자라<span class="ds-ico ds-notice__icon">에 규격이 그대로 걸립니다 - Buttons·Labels 문서가 「Interactive playground + 탭」 형식이 됐습니다. 조합을 하나 골라 실제 DS CSS 로 렌더된 결과와 같은 조합의 코드를 함께 보는 방식입니다. 공용 컴포넌트는
DocPlayground.vue(미리보기/코드 · 초기화 · 코드 복사)와DocTabs.vue(슬롯이 있는 탭만 노출) 두 개이고, 포맷 규격은docs/internal/component-docs-template.md에 있습니다 - Labels 의 전체 그리드 탐색기(
DemoLabelExplorer)를 Playground(DemoLabelPlayground)로 바꿨습니다. 축(변형 Tint·Solid·Line · 모양 · 크기 3종 · 색 12종 · 굵기 4종 · disabled · 좌우 아이콘)과 클래스 조합 규칙은 그대로이고, 표시 형태만 전 조합 그리드에서 단일 조합 미리보기로 바뀝니다 - 본문(색 표 · 강조 채움 · 크기 · 굵기 · 아이콘 · 의미색 매핑 · 접근성)은 문구를 바꾸지 않고 「사용 가이드」·「변형·상태」 탭으로 위치만 옮겼습니다. 기존 앵커는 전부 유지되고, 예전 주소
#live-preview는 Playground 위치로 이어집니다 - 내용이 없는 탭은 만들지 않습니다 — Labels 에는 「적용 방법」·「API·규격」·「변경·전환」 탭이 뜨지 않습니다
함정
- docs 에는 Tailwind 가 없습니다.
flex-1·font-medium같은 유틸은ds-tailwind-shim.css의.demo-tw스코프 안에서만 동작하므로, 데모 마크업이 그 유틸에 기대면 래퍼에demo-tw를 붙여야 합니다(안 붙이면 굵기·flex 가 조용히 빠집니다) - 문서 탭과 Playground 는 VitePress 문서 탐색용 UI 입니다. 제품의 Alpine
TabNav·SubTab과 무관하고 DS 컴포넌트도 아니므로, 제품 화면의 탭 규칙을 여기에 맞추지 마세요
2026-09-04 — 떠 있는 어시스턴트도 ESC 로 닫힘 (design/ai-assistant-dock)
변경
- 떠 있는 어시스턴트(좁은 화면)가 ESC 로 닫힙니다. 그때는 본문 위에 얹힌 팝업이라 ESC 가 자연스럽습니다. 도크는 그대로 둡니다 — 본문을 밀어내고 자리를 차지하는 상시 크롬이라, 모달을 띄운 채로도 쓰라고 만든 것을 키 하나로 접으면 전제가 깨집니다
- 실측: 떠 있는 AI(z65) + 모달(50) 상태에서 ESC 1회 → 어시스턴트, 2회 → 모달. 도크에서는 ESC 를 눌러도 유지됩니다
2026-09-04 — 캡처가 어시스턴트·시트 레일을 빼던 것 (design/ai-assistant-dock)
수정
- 어시스턴트를 열어 둔 채 신고하면 그 패널이 그림에서 빠졌습니다(사용자 리포트). 캡처 필터가
.ds-fab-layer를 통째로 걸러 채팅·어시스턴트 패널과 시트 워크북 레일까지 지웠습니다 — 어시스턴트가 문제일 때가 신고가 가장 필요한 순간인데 정작 증거가 사라진 것입니다. 이제 빼는 것은 신고 UI 자신과 확인 다이얼로그 둘뿐입니다 - 도크가 열려 있을 때 오른쪽을 잘라내던 크롭도 제거했습니다. 패널이 필터에서 빠지던 시절 빈 흰 칸을 없애려던 보정인데, 이제는 그 크롭이 어시스턴트를 잘라냅니다
2026-09-04 — 좁은 화면 자동 접힘 · 떠 있는 창은 하나만 (design/ai-assistant-dock)
변경
- 1280 밑으로 내려가는 순간 어시스턴트가 접힙니다. 떠 있는 창으로 바꿔 두면 그 폭에서 채팅과 80% 겹쳐 뒤쪽을 못 읽습니다 — 열어 둔 채 두는 것보다 접는 편이 낫습니다
- 떠 있는 상태에서는 채팅과 어시스턴트가 한 번에 하나만 열립니다(UI 겹침 방어). 여는 쪽이 신호를 쏘고 반대쪽이 접습니다 → FAB 배치 계약
함정
- 경계를 넘는 순간에만 접어야 합니다 — 좁은 화면에서 사용자가 직접 연 떠 있는 창까지 리사이즈마다 닫으면 못 씁니다
- 도크에서는 상호 배타를 걸지 않습니다 — 채팅이 도크 왼쪽으로 비켜서 겹치지 않으므로 둘 다 열려 있어도 됩니다(실측 겹침 0). 무조건 하나만 열리게 하면 도크의 이점이 사라집니다
2026-09-04 — 도크 폭이 창을 줄였다 넓히면 안 돌아오던 것 (design/ai-assistant-dock)
수정
- 창을 줄이면 도크 폭이 그대로 굳어 다시 넓혀도 안 돌아왔습니다. 800 으로 쓰던 상태에서 창을 900px 로 줄였다 1920 으로 되돌리면 360 으로 남았습니다(실측). 창이 좁아질 때 고른 폭 자체를 덮어쓰고 있었기 때문입니다 — 이제 표시만 물리고(
dockRenderWidth) 고른 값(dockWidth)은 그대로 둡니다. 확인: 800 → 680 → 384 → 680 → 800 - 드래그 기준도 「지금 그려진 폭」으로 바꿨습니다. 고른 폭이 상한에 물려 있는 상태에서 고른 값을 기준으로 잡으면 손잡이를 잡는 순간 폭이 튑니다
2026-09-04 — ESC 는 가장 위에 뜬 팝업부터 (design/ai-assistant-dock)
변경
- ESC 가 「화면에서 가장 위에 있는 것」 하나만 닫습니다. 예전에는 팝업마다 자기
@keydown.escape.window를 달아 먼저 등록된 리스너가 먼저 돌았는데, 그 순서는 Alpine 이x-data를 만나는 순서(DOM 순서)라 늦게 뜬 팝업과 무관했습니다 — 모달 위에 신고 팝업을 띄우고 ESC 를 누르면 밑에 깔린 모달이 닫혔습니다(사용자 리포트).esc-guard.ts에 공용 디스패처를 두고 신고 모달·채팅 패널을 등록했습니다. 실측: 모달+신고 상태에서 ESC 1회 → 신고만, 2회 → 모달 - 새 팝업은
registerEscLayer(getEl, close)로 등록하고 마크업의 ESC 리스너는 뺍니다 → FAB 배치 계약
함정
- 디스패처는 window 캡처 단계에 걸어야 합니다. 버블 단계면 다른 팝업의 리스너와 다시 순서 싸움이 됩니다
- 「가장 위」는 시간이 아니라 z-index 로 고릅니다 — 나중에 뜰수록 높은 층에 서므로 결과가 같고, 등록을 빠뜨린 팝업이 있어도 무너지지 않습니다. 레거시 모달이 더 위면 비켜서서 그 모달의 자기 리스너가 처리합니다
2026-09-04 — 신고 모달을 팝업 위로 · 어시스턴트 글자 정합 (design/ai-assistant-dock)
수정
- 신고 모달이 다른 팝업 아래로 들어가던 것을 고쳤습니다(사용자 리포트). 신고는 화면이 이상할 때 부르는 것이라 그 화면이 이미 모달이거나 모달 위 모달(60)인 경우가 흔한데, 기본 백드롭(50)이라 그 아래에 깔려 「눌렀는데 아무 일도 안 난다」로 보였습니다.
.ds-modal-backdrop--report(--ds-z-modal-report68)를 신설했습니다 — 컨펌(70)보다는 아래라 신고 모달 안에서 띄우는 확인 팝업이 자기를 덮습니다 - 어시스턴트 답변의 문단만 16px 로 뜨던 것을 고쳤습니다 — 공유 DS 의 unlayered
p규칙이 말풍선의text-b5(13px)를 이겨서, 사용자 말풍선(13px)과 나란히 놓였을 때 어시스턴트만 커 보였습니다..ai-md p에font-size: inherit을 넣었습니다
변경
- 응답 피드백(👍/👎)을 감췄습니다.
ai.feedback로 저장은 되는데 읽는 곳이 한 군데도 없어 사용자가 누른 값이 아무 데도 쓰이지 않습니다. 쓰는 곳이 생기면 마크업을 되살리면 됩니다
2026-09-04 — 딤 위 신고 버튼 · 어시스턴트에서 신고 진입점 제거 (design/ai-assistant-dock)
수정
- 버그 리포트 캡처에 팝업이 담기지 않던 것을 고쳤습니다 — 아래 함정 참고
추가
- 팝업이 떠 있을 때만 뜨는 신고 버튼
.ds-report-fab(흰 원 + 어두운 글리프) — 층은 어시스턴트와 같은 65(--ds-z-report-fab)라 겹쳐 뜬 모달(60) 위에서도 눌립니다 — 팝업이 뜨면 헤더의 「불편·기능 신고」가 딤에 가려 못 누르는데, 정작 팝업이 문제일 때가 신고가 가장 필요한 순간입니다. 딤 위(--ds-z-report-fab55)에 뜨고, 결정을 묻는 팝업(컨펌 70·권한 75)보다는 아래입니다 → FAB 배치 계약
변경
- 어시스턴트 상단바의 「버그 리포트 하기」를 뺐습니다. 신고 진입점은 헤더의 상시 진입(확성기)과 오류 다이얼로그의 「리포트 보내기」, 그리고 위 플로팅 버튼이 맡습니다 — 대화창에 같은 입구를 하나 더 두면 어디로 들어가야 하는지가 흐려집니다
함정
offsetParent로 「모달이 떠 있나」를 재면 안 됩니다. 백드롭은position: fixed라 항상 null 이라, 그 판정을 쓴 채팅 ESC 가드가 통째로 죽어 있었습니다(2026-09-04 실측) — 모달 위에서 ESC 를 누르면 모달 대신 채팅이 닫혔습니다. computeddisplay로 봅니다- 신고 버튼을 55 에 두면 겹쳐 뜬 모달(60)에 깔립니다 — admin 「근무 설정」 패널 위 「휴가/연차 유형」 같은 흔한 조합입니다(사용자 리포트). 어시스턴트와 같은 65 로 올렸습니다
- 캡처가 팝업을 통째로 빼고 있었습니다(2026-09-04 사용자 리포트). 필터가 클래스만 보고
.ds-modal-backdrop을 전부 걸러, 사용자가 신고하려는 그 팝업이 그림에서 사라졌습니다 — 팝업이 문제일 때가 신고가 가장 필요한 순간인데 정작 증거가 빠진 것입니다. 이제 확인 다이얼로그(--top)만 빼고 일반 팝업은 담습니다. 리포트 모달 자신은data-cs-report-host로 이미 걸러집니다 <button>으로 두면 원이 안 됩니다. 전역 blanket 규칙이 모든<button>의 radius 를 4px 로 강제해 모난 사각으로 렌더됩니다(실측) — 채팅·AI FAB 과 같이<div role="button">을 씁니다- 헤더 안 버튼만 위로 올릴 수는 없습니다. 헤더 래퍼의
z-index(그리고position: sticky)가 쌓임 맥락을 만들어 그 안의z-index는 바깥과 겨루지 못합니다 — 자식에position: fixed를 줘도 같습니다. 줄 전체를 올리면 팝업 중에 상단바만 밝게 남아 어색해서, 화면 최상위에 따로 그리는 플로팅 버튼으로 갔습니다 - FAB 줄과 같은 높이에 두면 안 됩니다. AI FAB 과 좌표가 정확히 겹치는데(실측 둘 다
x=1532) AI FAB 은 딤 위(65)라 이 버튼(55)을 덮어 클릭이 그쪽으로 갑니다 — 눈에는 안 보이는 고장입니다. 한 칸 위(bottom: 104px)에 세웁니다 - 보임/숨김은 CSS
:has()가 정합니다. MutationObserver 는 admin(2만 노드)에서 x-show 토글마다 돌아 버튼 하나 값어치를 넘습니다
2026-09-04 — 대화 말풍선 b5로 축소 · 채팅 ESC 닫기 (design/ai-assistant-dock)
변경
- 채팅·어시스턴트 말풍선 본문을
text-b3(16px) →text-b5(13px) 로 내렸습니다(실측 확인). 두 대화창이 한 화면에 나란히 뜨므로 같은 값이어야 합니다. 여백도 함께 좁혔습니다 — 어시스턴트px-3 py-2→px-2.5 py-1.5, 채팅px-3.5 py-2→px-3 py-1.5, 메시지 간격gap-2→gap-1.5 - 어시스턴트 마크다운(
.ai-md)의 크기 위계를 다시 잡았습니다 — 제목 b2(18)→b4(14), code b5(13)→b6(12), 문단·목록·표 여백도 한 단계씩. 본문만 내리면 제목이 본문보다 커 보이고 code 가 본문과 같아져 위계가 뭉갭니다 - ESC 로 채팅 패널이 접힙니다. 어시스턴트는 그대로 안 닫힙니다 — 상시 크롬이라 ESC 의 대상이 아닙니다 → FAB 배치 계약
함정
- 말풍선 크기는 한쪽만 바꾸면 안 됩니다. 채팅과 어시스턴트가 나란히 떠서 글자가 다르면 바로 눈에 띕니다. 그리고 어시스턴트는 마크다운 스케일이 본문에 물려 있어 두 파일을 같이 봐야 합니다
- ESC 처리를
stopImmediatePropagation()에 기대지 마세요. 모달도 같은 window 리스너를 쓰는데 등록 순서는 Alpine 이x-data를 만나는 순서라 예측할 수 없습니다 — 화면마다 결과가 달라집니다. 지금 무엇이 떠 있는지로 판정해야 하고, 숨은 백드롭이 DOM 에 여러 개 있으므로 존재가 아니라 표시 여부를 봅니다
2026-09-04 — 우하단 FAB 정리 + 어시스턴트 사이드 패널(도크) (design/ai-assistant-dock)
변경
- AI FAB 과 채팅 FAB 의 자리를 맞바꿨습니다 — AI 가 바깥(가장자리 24px), 채팅이 안쪽(80px) 입니다(사용자 결정). 색도 갈립니다: AI = BI 패밀리 그라디언트(
.ds-fab--brand), 채팅 = 단색 다크(bg-neutral-900). 예전에는 채팅이bg-orange-400, AI 가bg-neutral-900이었습니다 - 가로 자리를 마크업에서 걷어냈습니다.
right-[calc(80px+…)]같은 임의값 대신.ds-fab--ai/.ds-fab--chat만 붙이고design-system.css가 슬롯을 고릅니다 — 채팅은 AI FAB 이 실제로 DOM 에 있을 때만 안쪽으로 물러납니다(body:has(.ds-fab--ai)). AI 는 admin 한 곳에만, 그것도 조직 AI 가 켜져 있을 때만 그려지므로 못 박으면 나머지 화면에서 가장자리가 빕니다 → FAB 배치 계약
추가
- 어시스턴트가 화면 오른쪽에 붙는 도크로 열립니다 — 덮지 않고 본문을 밀어냅니다(
body.ds-ai-dock-open의padding-right). 폭은 좌측 핸들 드래그로360 ~ min(800, 화면폭 − 720), 키보드(←/→·Home)로도 조절됩니다. 태블릿 이하(<1280)에서는 예전의 떠 있는 패널로 자동 폴백합니다 → 도크 규칙 - 어시스턴트만 모달 위에 섭니다(
--ds-z-fab-ai65). 상시 크롬이라 모달을 띄운 채 물을 수 있어야 하는데 44 에서는 딤 아래로 내려가 통째로 못 썼습니다. 위 칸은 컨펌 다이얼로그(70)·권한 팝업(75)이 가져갑니다 - AI FAB 의 새 답변 표시
.ds-fab__dot— 개수를 세지 않으므로 숫자 배지가 아니라 점 하나입니다. 흰 링은 장식이 아니라 필수입니다(그라디언트 면에서 빨간 점이 묻힙니다) - iframe 안에서는 두 FAB 을 그리지 않습니다(
.ds-embedded) — admin 이 품는 앱들도 자기 화면에서 FAB 을 그려 한 화면에 두 벌 떴습니다
함정
- 채팅·어시스턴트 패널의 앞뒤를 z-index 로 바꾸려 하지 마세요. 어시스턴트는 모달(50) 위, 채팅은 모달 아래여야 해서 두 요구가 동시에 성립하지 않습니다 — 빈 z 칸을 어떻게 배치해도 풀리지 않습니다. 겹치지 않게 만드는 것이 해법이고, 도크가 그 일을 합니다(겹침 0 실측)
--ds-z-fab토큰을 올려서 해결하지 마세요. 채팅 FAB·패널과 시트 워크북의 수식 범위 바가 함께 씁니다 — 올리면 2026-08 에 고친 「FAB 이 모달의 확정 버튼을 덮는다」가 돌아옵니다. 예외는 요소 단위(더블 클래스)로만 줍니다- 도크로 전환해도 AI FAB 은 DOM 에 남습니다(
x-show).body:has(.ds-fab--ai)가 계속 매치해 그냥 두면 채팅이 안쪽에 선 채 바깥 자리만 빕니다 —body.ds-ai-dock-open규칙이 특이도로 되돌립니다 - 드래그 중 iframe 의 포인터 이벤트를 죽여야 합니다. admin 은 iframe 을 여럿 품는데, 커서가 그 위로 가면 부모가 이벤트를 못 받아 드래그가 그 자리에 굳습니다
2026-08-26 — 안내 아이콘 한 쌍으로 통합 + 이름 규칙 명문화 (design/icon-check-update-docs)
수정
- 획을
stroke가 아니라 「채운 면」으로 그린 아이콘 15개가 굵기 정규화를 피해 갔습니다. 실측하니organization1.20px ·workspace·team·signature1.25px ·money·setting1.30px 로 표준(1.67px @20px)의 0.72~0.78배 였어요 — 화면에서 혼자 얇아 보이던 이유입니다.stroke-width가 아예 없으니 8/25 굵기 개정이 닿지 않았습니다 money·organization·workspace를 stroke 기반 표준으로 다시 그렸습니다(0.99~1.05x 로 수렴)setting은gear와 중복이었고,gear쪽이 이미 표준 굵기였습니다 —setting이름을 유지한 채 도형을gear것으로 바꾸고ic-gear는 삭제했습니다(호출 4곳 이동).ic-setting-fill도 같은 실루엣의 solid 로 교체ic-chevron-down만 혼자 채운 면이라 나머지 세 방향보다 두꺼웠습니다 — stroke 기반으로 바꿔 네 방향이 같아졌습니다ic-dots-grid는 이름과 다른 그림이었습니다 — 실제로는 키보드(M11 14h2가 스페이스바)였어요. 이름대로 3×3 점 격자로 다시 그렸습니다ic-party의 폭죽 파티클이 깨져 보였습니다 — 점 좌표를 정리했습니다ic-refresh-fill을 삭제했습니다(호출 1곳 →ic-refresh)team·signature도 같은 원인으로 얇아 다시 그렸습니다 —signature는 테두리 안 흘림이 획 2에서 뭉개져 필기선 + 밑줄 형태로 바꿨습니다- 점(dot) 크기를 통일했습니다 —
ic-dots-grid는 이름과 달리 키보드였고, 3×3 격자로 다시 그리면서 점을ic-dots-horizontal과 같은 구성(반지름 .75 원 + stroke 2 = 지름 3.5)으로 맞췄습니다.ic-grip도 지름 2.8 → 3.5 - line 을 다시 그리면
-fill짝도 같이 그려야 합니다 —organization과workspace는 line 만 바꿔서 한동안 짝이 서로 다른 그림이었어요. 둘 다 새 구성에 맞춰 solid 를 다시 만들었습니다 ic-terminal(1.83x)은 예외입니다 — 짝 없는 solid 글리프라 두꺼운 게 맞습니다.ic-file-xlsx(0.72x)는 안에 «XLSX» 글자가 든 배지형이라 성격이 달라 그대로 뒀습니다- fill 변형 7종을 추가했습니다 —
ic-bell-fill·ic-camera-fill·ic-cap-fill·ic-employee-fill·ic-folder-fill·ic-star-fill·ic-tag-fill. line↔fill 쌍이 18 → 25쌍이 됐어요 - 자동 생성은 열린 선 디테일을 지워버립니다 —
ic-bell-fill의 추와ic-cap-fill의 술이 사라졌었습니다. 둘 다 열린 선(M10 21h4,M21 7v6)이라 채우면 넓이가 0이 돼요. line 의 획 굵기까지 반영한 범위로 채운 알약을 직접 그려 넣었습니다(예: 추 =M10 20h4a1 1 0 0 1 0 2h-4a1 1 0 0 1 0-2z→ line 의M10 21h4+ stroke 2 와 같은 x 9~15 · y 20~22) ic-question-circle-fill을 새로 추가했습니다 — line 만 있고 fill 이 없던 쌍입니다. line 과 채움 비율이 같도록 viewBox 를 계산해서("0.4 0.4 19.2 19.2") 넣어 1.00x 로 맞췄습니다ic-navigation을 지우고ic-map-pin으로 통합했습니다. 종이비행기 모양이었는데, 하필 쓰이는 곳도 스케줄러 「제출」 버튼 한 곳뿐이라rotate-90으로 돌려 "보내기" 아이콘처럼 쓰고 있었어요 — 이름과 그림과 용도가 셋 다 어긋나 있었습니다. 「제출」 버튼은 원래 그 뜻인ic-send로 바꾸고(회전도 불필요해졌습니다), 지도 위치는 이미 있던ic-map-pin이 맡습니다. 「한 의미에 한 쌍만」 규칙대로 같은 뜻의 두 번째 이름을 만들지 않았어요ic-map-pin-fill을 새로 추가했습니다 — line 만 있던 쌍입니다. line 의 획 바깥선과 같은 실루엣으로 그리고 안쪽 원은fill-rule="evenodd"로 파냈습니다(1.03x — 허용 범위 8% 이내)- 알림 아이콘을 심각도 3종으로 정리했습니다 — 오류는 원+
!(ic-exclamation-circle) · 경고는 삼각형+!(ic-warning) · 안내는 원+i(ic-info-circle). 색만으로 구분하면 빨간 상자 안에 안내 기호가 들어가 톤이 어긋나요 → 알림 아이콘 - 중복이던
ic-info를ic-info-circle로 합쳤습니다(호출 64곳 이동). 두 원(exclamation·info)은 같은 원(r=9)에 막대와 점만 상하 반전한 형제로 다시 그려 한 가족으로 읽힙니다 - 오류 공지 29곳이 안내 기호(ⓘ)를 쓰고 있던 걸 바로잡았습니다 — 로그인·회원가입 실패, 초대 오류, 연차 정책 불일치 등. 같은 자리에서 원래도 어긋나 있던 2곳(develop 시점부터
ic-info)도 함께 교정했습니다 ic-info-circle-fill의i를 다시 그렸습니다. line 쪽i와 글자 모양이 아예 달랐어요(글자가 눌리고 아래에 이상한 발이 붙어 비대칭). viewBox 도 20 vs 24 로 달라 나란히 놓으면 fill 이 더 커 보였습니다. 이제 line 과 같은 24 좌표계에서 같은 위치·굵기로 그린 뒤fill-rule="evenodd"로 안쪽을 파냅니다ic-lightbulb이 찌그러져 있었습니다. 유리부 호의 현 길이가 11.54 인데 반지름이 6(지름 12)이라 거의 한계치였고,large-arc=1과 겹쳐 원 둘레의 59% 를 그리는 기형 호가 됐습니다 — 좌상단이 움푹 들어가고 좌우가 어긋나 보였어요. 반지름 5.6 의 정상 호로 다시 그렸습니다
추가
이름 규칙을 문서에 명문화했습니다 —
ic-{의미}-{형태}-{채움}순서이고 채움 자리는fill일 때만 씁니다(line 은 접미사 없음). 한 의미에 한 쌍만 두고, 쌍은 같은 글자·같은 좌표계로 그립니다line↔fill 의 크기가 어긋난 3쌍을 맞췄습니다 —
ic-warning(fill 이 17% 작음) ·ic-lock(17% 큼) ·ic-check-circle(13% 큼).d좌표는 건드리지 않고 viewBox 만 조정해 고쳤습니다(예:ic-check-circle-fill"0 0 16 16"→"-1.5 -1.5 18 18"). 15쌍 전체를 실측해 1.00x 로 수렴한 것을 확인했습니다
앞선 기록 정정
- "viewBox 가 어긋난 쌍 5개" 는 잘못된 진단이었습니다. 실측해 보니 viewBox 숫자와 실제 보이는 크기는 별개였어요 —
ic-menu(24↔16)·ic-refresh(24↔20)는 viewBox 가 달라도 채움 비율이 같아 멀쩡했고, 반대로 viewBox 가 같은ic-lock(24↔24)이 17% 어긋나 있었습니다. 기준을 "글리프가 박스를 채우는 비율" 로 바꿔 문서에 명시했습니다 - "fill 안쪽 마크가 얇다" 도 과잉 진단이었습니다. 15쌍을 크게 놓고 보니 문제가 아니었어요 — 파낸 마크는 검은 바탕 위 흰 영역이라 같은 폭이어도 더 두껍게 보여서(irradiation), 얇게 그린 것이 오히려 올바른 광학 보정입니다. line 굵기에 맞춰 키우지 마세요
ic-message(0.91x)·ic-user(0.92x)는 정상 범위로 두었습니다 — solid 는 원래 조금 작게 그립니다
2026-08-25 — 락업 최소 높이 24 → 16px, LNB 브랜드 자리 재배치 (design/lnb-hospital-logo)
변경
- 락업 최소 높이를 24px → 16px 로 내렸습니다 → 브랜드 · 크기와 보호 영역. 「그보다 작으면 워드마크를 떼고 심볼만」이라는 판단 자체는 그대로이고, 그 경계선만 옮겼습니다. 심볼 단독에 하한이 없다는 것도 종전과 같습니다
- 데모의 높이 슬라이더 하한도 16 → 10 으로 내렸습니다. 규칙 하한과 슬라이더 하한이 둘 다 16 이면 「최소 크기 미만」 경고를 한 번도 볼 수 없게 되기 때문입니다 — 규칙은 보여줄 수 있어야 규칙입니다
추가
- LNB 하단 브랜드 마크(
.ds-lnb__brandmark) — 영문 outline 락업(다크 배경용 흰색 단색) · 높이 18px · 불투명도 30% · 가운데 정렬 · 비클릭. 접힘 레일(안쪽 폭 44px)에서는 락업 대신 같은 outline 심볼로 바뀌고, 메뉴가 세로로 다 들어가지 않는 화면에서는 숨겨 메뉴에 자리를 돌려줍니다(세로가 짧은 노트북에서 안 보이는 것이 정상입니다). CSS 는 공용이지만 지금 렌더하는 앱은 admin 하나입니다 - outline 자산 2종을 레지스트리에 등록했습니다 —
logo-lockup-hereby-medical-outline-on-dark·logo-hereby-medical-outline-on-dark. outline 은 색이 배경에서 갈리므로 이름에 배경이 붙습니다
수정
- LNB 헤더의 「hereby 심볼 × 병원 로고」 코브랜딩을 걷어냈습니다. 208px LNB 에서 브랜드 텍스트가 쓸 수 있는 폭이 29px 까지 밀려 「hereby Me…」로 잘렸어요(
.ws-brand안쪽 136 − 심볼 24 − gap 8 − 코브랜딩 블록 75). 이제 로고를 등록한 조직은 심볼 자리를 로고가 대체하고(같은 24px 정사각),hereby는 위의 하단 브랜드 마크가 맡습니다 - 「LNB 헤더에 락업을 못 쓰는 이유」가 규칙 위반에서 디자인 판단으로 바뀌었습니다. 132px 폭에 넣으면 높이가 19.8px 인데, 하한이 24 이던 때는 위반이었고 16 인 지금은 규칙상 가능합니다. 그래도 화면은 심볼 + 텍스트를 유지합니다 — 승격하려면 시안을 먼저 받으세요
2026-08-25 — 획 굵기 규격 16px 기준 재정의 + 아이콘 갤러리 신설 (design/icon-check-update-docs)
추가
- 아이콘 라이브러리 페이지를 채웠습니다 — 그동안 "준비 중" 스텁이라, 등록된 아이콘 162개를 훑어볼 방법이 레포에 없었습니다(
packages/static/icons/*.svg폴더를 Finder로 여는 게 유일한 우회로였어요). 이름 검색 · 12~24px 미리보기 크기 토글 · 클릭하면 이름 복사 - 목록을 손으로 적지 않습니다 —
packages/components/src/icons.ts를 빌드 시점에 그대로 불러와(getIcon/iconNames) 렌더하므로, 아이콘을 새로 등록하면 이 페이지도 다음 배포에서 자동으로 같이 늘어납니다 - 이 페이지 자체가 회귀 확인 도구입니다 — 크기 토글로 전 아이콘을 12~24px 구간에서 눈으로 훑을 수 있습니다. 아래 두 결함 다 이 갤러리를 보다가 찾았어요
수정
- 획 굵기 규격을 "16px 표시에서 1.33px" 로 다시 정하고 획 기반 아이콘 123개를 전부 맞췄습니다. 굵기가 5가지로 갈려 있었어요 — 1.00px(88개) · 1.12px(3) · 1.20px(7) · 1.33px(24) · 1.50px(1). 원인은 하나입니다: Heroicons v1 outline 을 그대로 붙여넣은 것(그쪽 기본이
stroke-width="2", 우리 규격은 1.5였음).ic-refresh는 path 까지 원본과 바이트 단위로 같았습니다 - 왜 "적은 숫자" 가 아니라 "16px 환산" 이 기준인가 — 아이콘은 대부분
w-4(16px)로 쓰는데 굵기는 viewBox 좌표계 값이라, 적은 숫자와 보이는 굵기가 다릅니다. 실제 굵기는stroke-width ÷ viewBox가 정해요. 옛 규격(24÷1.5)은 24px 표시를 전제한 값이라 실사용 16px 에서는 1.0px 헤어라인으로 렌더되고 있었습니다. 새 규격 24 viewBox · stroke 2(= 16px 에서 1.33px)는 Heroicons·Lucide 와 같은 값이고, 이미 24개가 여기 있었습니다. viewBox 가 24 가 아니면viewBox ÷ 12로 환산합니다(16 → 1.3333, 32 → 2.6667) → 스타일 규칙 ic-close는 24 좌표계로 되돌리고 글리프만 키웠습니다. 이 아이콘만 16 좌표계 특례였는데, 그러면 굵기 규격에서 혼자 벗어납니다. 24 박스 안에서 X 가 박스의 50% 밖에 안 차지해 작아 보이던 게 진짜 원인이었어요 — 62.5%(15 유닛)로 키워 16px 에서 X 폭 8px → 10px, 굵기는 새 표준 1.33px 입니다. X 를 쓰는 481곳이 여기 해당합니다- 적용은
stroke-width숫자만 바꿨습니다(ic-close제외) — path 좌표를 건드리지 않아 도형이 깨질 위험이 없습니다.ic-spinner는 굵은 링이 목적이라 유일한 예외로 남겼습니다(2.67px) ic-badge-check도형이 찌그러져 있었습니다. path 끝의 호(arc) 4개가 통째로 빠져 도형이 닫히지 않았고, 시작점까지 대각선으로 뚝 끊겨 이어졌습니다 — 씰(seal) 한쪽이 잘려나간 모양이었어요. 2026-08-10 레지스트리 최초 등록 때부터 그랬습니다. 출처(Heroicons) 원본과 대조해 복원했고, 끝점 좌표 합이 (0,0)으로 닫히는지 계산으로 확인했습니다- docs 데모 5개가 아이콘을 손으로 베껴 쓰던 것을 레지스트리 직접 참조로 바꿨습니다 —
DemoLnbSidebar·DemoWorkspaceSwitcher·DemoButtons·DemoEmployeeTable·DemoDataTable. 사본이라 등록본이 바뀌어도 문서만 옛 그림으로 남아 실제로 벌어져 있었습니다:org는 2×2 격자(실제는 조직도 글리프) · 총무의ic-clipboard는 빈 사각형+줄 3개(실제는 클립+체크리스트) · 「수정」은 획 2(실제 1.5) · 「삭제」는ic-trash와 아예 다른 모양
재발 방지
- 데모는 이제 이름만 적습니다 —
getIcon('ic-…')로 읽으므로 등록본이 바뀌면 문서가 자동으로 따라옵니다. 새 데모에서도 SVG 를 손으로 그리지 마세요(DemoLnbSidebar에는 "icons copied from icons.ts" 라는 사실과 다른 주석까지 붙어 있어 드리프트를 더 늦게 발견했습니다) - 예외는 둘뿐입니다 — ① 브랜드/BI 자산: 그라디언트
id가 문서 전역이라 한 페이지에 둘이 들어가면 충돌하므로 데모 전용 id 를 쓴 사본을 유지합니다 ②:d런타임 바인딩(표 정렬 화살표): 레지스트리 대상이 아닙니다
남은 것
- fill 이 없는 아이콘이 아직 100여 개 있습니다. 이 중 화살표·chevron·정렬선처럼 면이 없는 것 22개는 대상이 아니고(채워도 그릴 게 없습니다), 나머지가 후보입니다
- 일괄 자동 생성은 안 됩니다 — 시도해 보고 접었습니다. 획을 면으로 바꾸는 걸
fill-rule="evenodd"로 자동화해 17개를 돌렸더니 5개만 쓸 만했어요.ic-clipboard-check·ic-calendar-check는 조각만 남고,ic-approval은 검은 사각형,ic-search는 손잡이가 사라진 원이 됐습니다 — 내부 디테일이 별도<path>인 아이콘은 하나로 합치는 순간 형태가 무너집니다 - 그래서 나머지는 한 개씩 손으로 그려야 합니다. 서두르면 결함이 그대로 들어갑니다 — 이번에 발견된
ic-badge-check(도형이 안 닫힘)와ic-info-circle-fill(눌린i)이 정확히 그렇게 들어온 것들이었어요 - 자동 생성분에는 크기 보정이 필수입니다. 획의 중심선을 쓰기 때문에 일관되게 0.89~0.91x 로 작게 나옵니다(좌우로 획 절반씩 손실). 이번 7종도 viewBox 를 계산해 1.00x 로 맞췄습니다
packages/static/icons/*.svg파생본 99개를pnpm icons:build로 함께 갱신했습니다 — 등록본을 고칠 때 이 명령을 빼먹으면pnpm icons:check가 잡습니다- 채움(fill) 전용 38개는 손대지 않았습니다 — 획이 없어 굵기 축 밖입니다. 다만 이들도 Heroicons v1 solid 계열로 보여, 나중에 아웃라인과 나란히 놓았을 때 무게감이 맞는지는 따로 볼 여지가 있습니다
2026-08-13 — 로딩 스피너 문서 정본화 + 확장 축 개방 (design/update-loading-components)
추가
- Spinner 페이지를 신설했습니다 — 스피너는 이미 4곳에서 돌고 있었지만 규칙이 코드 주석에만 있어, "언제 링이고 언제 아이콘인가"를 판단할 근거가 문서에 없었습니다
- 종류는 두 개뿐이고, 자리가 정합니다 — 영역이 아직 아무것도 못 그리면 div 링
.ds-spinner, 컨트롤 하나만 바쁘면 SVG 아이콘ic-spinner+animate-spin. 판단이 애매하면 "이 스피너를 지우면 그 자리에 뭐가 보이나" 를 물어보세요 — 아무것도 안 보이면 링입니다 - 영역 로딩이 아이콘이 아니라 div 링인 이유(되돌리지 마세요): SVG
transform애니메이션은 메인 스레드가 막히면 합성 레이어로 못 올라가 프레임이 튑니다. 영역 로딩은 정의상 메인 스레드가 바쁜 순간이라 정확히 그때 끊깁니다 — 시트 로딩에서 "뚝뚝 끊김"으로 실제 리포트된 현상이에요. div 테두리 회전 +will-change는 GPU 합성이 안정적입니다 - 확장 축 5개를 변수로 열었습니다 —
--ds-spinner-size(2rem) ·--ds-spinner-thickness(3px) ·--ds-spinner-track(neutral-200) ·--ds-spinner-indicator(orange-500) ·--ds-spinner-badge-size(4rem). 기본값이 종전과 같아 화면 변화는 없습니다. 새 종류는.ds-spinner--<이름>으로 변수만 덮습니다 —width/border/animation을 다시 선언하면 GPU 합성과 reduced-motion 대응을 새 종류가 못 물려받아요 → 확장 절차 - 스피너가 아닌 로딩 표시도 같은 페이지에 지도로 정리했습니다 — 진행률을 아는 경우(N/M)는 스피너가 아니라 카운트 배너(시트 「추가 행 로딩 중… 500 / 1000」), 패널 안 짧은 목록은 텍스트 한 줄. 스켈레톤과 진행률 바는 DS에 없습니다 → 스피너가 아닌 것
수정
- 인라인
style로 복제돼 있던 링 1곳을 공용 클래스로 되돌렸습니다 — 시트 [설정 완료] 처리 중 화면(setup-complete.html). 겉보기는 같았지만 사본이라 ①--ds-spinner-*변수를 안 따라오고 ②prefers-reduced-motion에서 혼자만 1s 로 빠르게 돌고 있었습니다(다른 스피너는 2.4s). 모달 · 화이트 딤 문서의 예제 코드도 같은 복제본이라 함께 고쳤습니다 — 문서가 잘못된 패턴을 퍼뜨리고 있던 셈입니다 - 흰 딤 위에서는 받침(
.ds-spinner-badge)을 씌우지 않습니다 — 흰 바탕에 흰 원이 겹쳐 테두리만 보입니다. 받침은 링이 콘텐츠 위에 겹쳐 뜰 때만
재발 방지
pnpm check:spinners를 신설했습니다 (pre-commit 차단). 회전(animate-spin)과 원형 테두리를 한 줄에서 조합한 손으로 그린 링을 추가된 줄만 보고 막습니다. 이번에 정리한 인라인 style 형뿐 아니라 Tailwind 유틸 조합 형(border-2 border-orange-500 border-t-transparent rounded-full animate-spin)도 같이 잡습니다 — 두 철자가 실제로 존재했습니다. 아이콘 스피너(ds-ico/$icon(가 같은 줄)는 정상 사용법이라 대상이 아니고, 로딩이 아닌 회전 원은ds-spinner-exempt: <사유>로 통과시킵니다. 판정기는 7개 케이스(차단 2 · 통과 5)로 확인했습니다- 다섯 축을
@property { inherits: false }로 등록했습니다. CSS 변수는 기본이 상속이라, 패널 하나에--ds-spinner-size를 걸면 그 안에 든 부팅·임베드 스피너까지 따라 줄어듭니다. 이제 조상에 건 값은 내려가지 않고 변형 클래스나 요소 자신의 선언만 먹습니다 — 의도한 확장 방식 그대로입니다.@property를 모르는 브라우저는 블록을 무시할 뿐 렌더는 동일합니다
남은 것
ic-spinner를 영역 로딩에 쓰는 자리 11곳 — admin 스케줄러 4 · team-manager 3 · inventory · general-affairs · module-manager 대시보드 ·system-admin/loading.html(부팅 화면인데 아이콘을 씀)- 손으로 그린 링 3곳 —
employee-app/modals/work-settings.html·work-type-change.html·team-manager/dashboard.html. 두께 2px 라 공용 링(3px)과 미세하게 다르고 reduced-motion 에서 혼자 빠르게 돕니다 - 둘 다 마이그레이션 대상이지 위반이 아닙니다 — 일괄 스윕하지 말고 그 파일을 고칠 때 함께 바꾸세요. 전 앱이
design-system.css를 로드하므로 치환은<span class="ds-spinner"></span>한 줄입니다 - 복제본 없음 확인 — 앱
main.css어디에도.ds-spinner재정의가 없어 정본만 고치면 전 앱에 반영됩니다(모달·페이지네이션 같은 copy trap 이 없는 드문 경우)
2026-08-10 — 처리 중(로딩) 전용 화이트 딤 백드롭 (design/sheet-setup-usage-mode)
추가
- 백드롭에
--white변형을 넣었습니다 —.ds-modal-backdrop.ds-modal-backdrop--white, 딤 색만var(--ds-glass-70)로 바뀌고 나머지(fixed inset-0 · 가운데 정렬 · z · 스크롤 잠금)는 기본과 같습니다 → 화이트 딤 - 어두운 딤과 역할이 다릅니다. 어두운 딤은 "화면을 덮었으니 저기에 집중하라"는 신호지만, 흰 딤은 "같은 화면이 잠깐 멈춤" 으로 읽힙니다. 화면 전환 없이 몇 초 잠그고 스피너 + 한 줄 안내만 얹는 자리에 씁니다. 사용자 확인을 받는 다이얼로그에는 쓰지 않습니다 — 흰 딤 위에 선택 버튼을 얹으면 멈춤 신호가 선택 화면으로 바뀝니다
- 선택자를 더블 클래스로 둔 이유: 앱
main.css들이.ds-modal-backdrop단일 클래스 복사본을 갖고 있어, 특이도가 낮으면 앱에서 조용히 덮입니다. 더블 클래스(0,2,0)는!important없이 항상 이깁니다 - 첫 사용처는 급여 시트 [설정 완료] 처리 중입니다(UP-008 설정/사용 모드) — 확정 카드를 숨기고 같은 백드롭 안에서 흰 딤 + 스피너로 교체합니다
2026-08-07 — 컨펌 다이얼로그가 열릴 때 확인 버튼에 포커스 (design/sheet-uiux-fx)
변경
- 다이얼로그(알림·확인·선택형)가 열리면 확인 버튼이 포커스를 가집니다 — Enter 가 곧 확인이 되고(네이티브
confirm()관례), Tab 으로 취소/대안 버튼에 옮겨 Enter·Space 로 누를 수 있습니다. prompt 는 지금처럼 입력칸이 포커스를 가집니다 → 키보드 - 배경: 포커스가 다이얼로그를 연 쪽 입력창(급여 시트 수식바)에 남아, 수식을 Enter 로 확정한 뒤 범위 선택 다이얼로그에서 Enter 를 또 쳐도 아무 일도 일어나지 않았습니다("Enter 를 쳐도 수식 작성이 안 끝난다" 리포트). 이제 Enter 두 번이면 수식 확정 → 범위 확정까지 끝납니다
2026-08-06 — 채팅·AI FAB 비킴 변수 --ds-fab-dodge (design/sheet-uiux-fx)
추가
- 오른쪽 드로어가 열릴 때 FAB 를 왼쪽으로 비켜 세우는 계약을 넣었습니다 — 채팅/AI FAB 와 패널의
right가calc(<기본값> + var(--ds-fab-dodge, 0px))로 바뀌었습니다. 변수 기본값이 0px 라 세우지 않는 앱은 아무 변화가 없습니다 → FAB 배치 계약 - 첫 사용처는 급여 시트 워크북입니다: 오른쪽 레일 드로어(셀 상세·메모 / 열 설정 / 급여 반영 / 행 정보, 320px)가 열리면
body.sheet-rail-open이 320px 를 세우고, admin 임베드에서는hereby:tm:railpostMessage 로 부모 문서의 FAB 도 함께 밀립니다 - 배경: FAB 는
position:fixed라 드로어가 그리드를 밀어내도 그대로 드로어 위에 얹혀 하단 버튼(드로어 푸터)을 가렸습니다. 드로어 푸터 버튼들이 좌측 정렬로 도망가 있던 이유가 이것이었고, 비킴 도입으로 취소=왼쪽·저장=오른쪽 정렬이 가능해졌습니다
2026-08-05 — 컨펌 다이얼로그에 선택형(askChoice) 추가 (design/sheet-uiux-fx)
추가
- 선택지가 둘인 확인
askChoice를 넣었습니다 —"confirm"(오른쪽) ·"alt"(가운데) ·"cancel"(Esc). 물음이 「할까/말까」가 아니라 「어느 쪽이냐」 일 때 씁니다. 첫 사용처는 급여 시트에서 셀에 넣은 수식의 적용 범위(「이 셀만」 / 「전체 열에 적용」)입니다 → 선택형 - 네 번째 모달 종류가 아닙니다 — 카드·제목·여백·타이포는 컨펌 다이얼로그와 완전히 같고 푸터 버튼만 갈립니다. 모달 3종 분류는 그대로입니다
- 취소 버튼을 두지 않았습니다. 선택지 둘만 세우고 되돌아 나가는 길은 Esc 가 집니다. 셋째 버튼을 두면 무엇이 기본인지 흐려지고, 두 선택지 중 하나를 「취소」 자리에 앉히면 사용자가 무엇을 고른 건지 흐려집니다
- 호스트가 없으면
"cancel"입니다.askConfirm은 같은 상황에서 통과(true)시키지만 — 띄울 수 없는 확인창이 동작을 조용히 취소하면 안 되므로 — 선택형에는 통과시킬 기본값이 없습니다. 임의로 고르면 사용자가 고르지 않은 쪽이 실행됩니다
2026-08-04 — 급여 시트에도 가로 스크롤바 + 썸을 반투명으로 (design/sheet-uiux-fx)
변경
- 가로 스크롤바 제외 목록에서 급여 시트를 뺐습니다 — 이제
.sched-grid(근무표)만 제외입니다. 시트야말로 열이 수십 개라 가로로 넘치는 대표 화면이고, 이 기능을 만든 이유("윈도우에는 표를 가로로 스크롤할 입력 수단이 사실상 없다")가 가장 아프게 걸리는 곳이었습니다 → 가로 스크롤바 - 시트에는 아래쪽 바만 붙입니다. 시트의 스크롤 박스는
flex-1로 화면 높이에 맞춰져 있어 아래 바가 항상 보이고, 위 바는 sticky 열 헤더를 10px 가려 스프레드시트에서는 손해가 큽니다. 마크업 4곳에data-ds-xscroll="bottom"을 뿌리는 대신table-xscroll.ts의BOTTOM_ONLY_SELECTOR한 곳에서 정합니다 - 시트에서는 바가 표를 덮지 않고 자기 자리(10px)를 차지합니다 — 새 변형
.ds-xscroll--inflow(래퍼에data-ds-xscroll-inflow,.sheet-scroll은 기본 적용). 다른 표는 아래에 여백이 있어 겹쳐도 되지만, 시트는 스크롤 박스가 화면 끝까지 차서 맨 아래가 데이터 행(또는 sticky 합계 행) 이라 겹치면 그 줄이 잘려 보였습니다. 흐름 안에 두면flex-1인 박스가 그만큼 줄고 시트가 바 위쪽에 온전히 들어옵니다 - 표와 바 사이에 분리선(
border-top: 1px solid var(--color-line-normal))을 넣었습니다 — 시트 툴바·오른쪽 레일과 같은 선입니다. 겹치는 바에는 넣지 않습니다(표 위에 얹혀 있어 행 사이를 가로지르는 줄로 읽힘).border-box라 테두리가 트랙 안쪽을 먹으므로 바 높이만 10 → 11px로 키워 트랙은 그대로 10px입니다 - 썸을 평상시 반투명(
--ds-opacity-50)으로 낮췄습니다 — 이 바는 표 위에 상시 겹쳐 그려지므로, 진하면 데이터를 읽는 내내 눈에 걸립니다. hover·드래그 중에는neutral-400+ 불투명으로 또렷해져 조작 피드백은 그대로입니다 - 호스트 단위 제외 상수(
EXCLUDED_HOST_SELECTOR)는 없앴습니다 — 끄는 방법은data-ds-xscroll="off"하나로 통일합니다
2026-07-31 — 파비콘 캐시 무효화 + 문서 사이트 파비콘은 마스터 심볼 (design/BI-update)
수정
- 파비콘을
fill본으로 바꿨는데 탭에는 예전 아이콘이 그대로 남았습니다. 브라우저가 파비콘을 URL 기준으로 따로 캐시하기 때문이고, 강력 새로고침으로도 잘 지워지지 않습니다. 10개 앱의href에?v=2를 붙여 다시 받게 했습니다 — 앞으로 파비콘 파일을 바꾸면 이 값을 같이 올려야 합니다(값이 갈리면 앱마다 다른 시점의 아이콘이 남습니다) - 서빙되는 파일 자체는 정상이었습니다 — 16px로 렌더해 십자가 흰색으로 채워지는 것을 확인했습니다. 파일이 아니라 캐시가 원인이었다는 뜻입니다
추가
- 문서 사이트(docs)에 파비콘을 붙였습니다 — 마스터 심볼(스우시)입니다. 종전에는 파비콘이 아예 없어 브라우저 기본 아이콘이 떴습니다. 이 사이트의 주체는 특정 패밀리가 아니라 hereby 제품군 전체라 십자·사람·펜을 쓰지 않습니다
- 자산은 예외적으로
docs/public/favicon.svg에 둡니다 — 문서 사이트는@hereby/static을 소비하지 않아/static미들웨어가 없고 VitePress의public/이 유일한 경로입니다.href에는 base를 붙였습니다(버전 문서는/1.2.3/하위 경로라 루트 절대경로면 404)
2026-07-31 — BI 심볼 내부를 fill/outline 두 케이스로 등록 + 전 사용처 fill 전환 (design/BI-update)
추가
- 심볼을 그리는 방식을 둘로 등록하고 기본형을
fill로 정했습니다 —fill(그라디언트 면 + 안쪽 흰색) ·outline(그라디언트 없이 워드마크 색을 그대로 따르는 단색, 안쪽은 채우지 않음).outline은 선(stroke)이 아닙니다 — 면은 그대로이고 색이 단색으로 바뀌는 것입니다 → 심볼을 그리는 두 방식 - 심볼만이든 락업이든 기본은
fill입니다. 다크 배경 락업에서 워드는light로 뒤집히는데 심볼의 십자만 검게 남던 것이 이 규칙을 못 박은 계기입니다 — 워드마크에는 톤 규칙이 있어도 심볼 안쪽에는 규칙이 없었습니다 → 기본형 outline은 브랜드 컬러를 쓰지 않습니다 — 오렌지 단색도 그라디언트도 아니고, 워드마크와 같은 색(밝은 배경#1B1B1B· 어두운 배경 흰색) 하나입니다. 내보내기에는linearGradient가 아예 들어가지 않습니다outline은 컬러 없는 워드마크와만 조합합니다 — 서비스명 톤dark·light만 되고primary(오렌지)와는 금지입니다. 심볼이 워드마크 색을 따라가므로 워드에 컬러가 있으면 심볼까지 그 컬러가 되어 정의 자체가 깨집니다 → 조합 규칙outline을 자리별로 규정하지 않았습니다 — 「어느 화면은 outline」 같은 규칙은 두지 않습니다. 기본은 언제나fill이고outline은 데모에서 받아 쓰는 케이스입니다- 데모에 「심볼 내부」 선택기를 넣었습니다(기본값
fill, 심볼을 끄면 사라지고 마스터엔 없습니다).outline을 고르면primary버튼이 잠기고,primary상태에서outline을 고르면 그 배경의 중립 톤으로 물러납니다 — 배경 × 톤 금지 조합과 같은 처리입니다 - 내보내기 파일명 맨 뒤에 축이 붙습니다 —
hereby-bi-medical-en-dark-on-white-fill.svg·hereby-bi-medical-symbol-fill.svg. 기본형도 생략하지 않습니다: 생략하면 예전에 받아 둔outline파일과 같은 이름이 되어 조용히 덮어써집니다.outline은 심볼만이어도 배경이 붙습니다(…-symbol-outline-on-white.svg) — 색이 배경에서 갈리기 때문입니다
변경
- 심볼이 박힌 자리를 전부
fill본으로 교체했습니다(12곳) —icons.ts의 심볼 3(logo-hereby-medical·-sign·-works)과 락업 2종 안의 심볼, 파비콘 2(9개 앱이 참조), 랜딩 인라인 3(nav.html·footer.html·데모의 Sign), docs 데모 2(DemoLnbSidebar·DemoWorkspaceSwitcher). PNG 앱 아이콘은 유지합니다 fill본은 새로 그리지 않고 등록된 정본에서 파생합니다 —컨테이너+컨테이너 ⊕ outline 원본(fill-rule="evenodd"대칭차 = 정확히 안쪽 도형) 두 줄입니다. 디자인 재요청이 없고, 원본이 바뀌면fill본이 따라옵니다.clipPath·mask는 쓰지 않습니다(자산은 어디서 열어도 같아야 합니다) → 파생식- 컨테이너를 얻는 방법이 심볼마다 다릅니다 — Medical은 첫 서브패스가 이미 라운드 사각형, Sign은 펜이 외곽선에 통째로 파여 서브패스가 1개라 상자가 같은 Medical 컨테이너를 재사용, Works는 몸통도 외곽선에 파여 있어 그 구간만 Medical 컨테이너 하단으로 되돌립니다
- Works의 상단 노치는
fill본에서도 비어 있습니다 — 노치는 안쪽 도형이 아니라 컨테이너 실루엣의 일부라, 흰색이 되는 것은 사람(머리+몸통)뿐입니다. 위 파생식이 이것까지 자동으로 지킵니다 - 마스터엔 이 축이 없습니다 — 스우시 하나라 컨테이너도 안쪽 도형도 없습니다(뚫린 데가 없으니 채울 것도 없습니다). 마스터 데모에는 선택기가 나타나지 않습니다
2026-07-29 — 라벨에 굵기 축 추가 + 채팅 위젯 미확인 배지 (design/review-and-apply-improvements)
추가
- 라벨 굵기를 크기와 분리했습니다 —
.ds-fw-regular/medium/semibold/bold하나를 얹으면 크기는 그대로 두고 굵기만 바뀝니다(기본 medium). 버튼이 쓰던 모디파이어를 그대로 공유하고, 각 크기 변형이 읽는--ds-label-weight변수만 세팅하므로 새!important는 0입니다 → 라벨 → 굵기 - 라이브 미리보기에 굵기 토글을 넣어 4단계를 실제 CSS로 비교할 수 있게 했습니다
변경
- 채팅 위젯(FAB)의 반투명을 걷어냈습니다. 닫힌 상태가
bg-orange-500/50+text-white/80이라 시트 위에 띄우면 뒤 숫자가 그대로 비쳐 버튼인지 얼룩인지 구분이 안 됐습니다 — 기본은 불투명orange-400+ 흰 아이콘, hover 에서 primary(orange-500) 로 한 단계 진해집니다. 상시 노출되는 버튼이라 기본은 primary 보다 한 톤 낮추고 강조는 hover 가 집니다 - 미확인 배지를 DS 라벨로 교체했습니다 — 손으로 조합한
min-w-4 h-4 rounded-full bg-red-500 text-[9px]대신.ds-label--xs --round --solid --red+.ds-fw-bold. 세는 대상은 확인 안 한 대화(채널 포함) + 공지 합계이고, 99 초과는+99로 줄입니다(예전99+)
수정
- admin 의
.admin-app .ds-label { font-weight: 500 }이 굵기 축을 조용히 삼켰습니다. 특이도(0,2,0)가 크기 변형(0,1,0)보다 높아 admin 안에서만.ds-fw-bold가 무시됐습니다 —var(--ds-label-weight, 500)으로 바꿔 admin 기본값(medium)은 유지하면서 축이 살아 있게 했습니다. 앱 override 가 변수를 안 읽으면 그 앱에서만 DS 축이 죽는다는 사례입니다
2026-07-29 — 정보성 영역은 notice 사용 강제 (design/review-and-apply-improvements)
금지 (재유입 차단)
- 안내·주의·경고·오류를 알리는 박스는 반드시 notice + 변형으로 만듭니다. 새 기능이든 기존 화면 수정이든 같습니다 —
bg-red-50 border border-red-200 text-red-600같은 유틸 조합 틴트 박스를 새로 만들지 않습니다. 제각각인 크기·간격·색을 한 규격으로 모으는 것이 이 컴포넌트의 존재 이유입니다 - 이모지로 아이콘을 대신하지 않습니다 —
⚠️·❗대신<svg class="ds-notice__icon">. 이모지는 OS·폰트마다 크기·색이 달라 변형 색과 어긋나고 16×16 규격도 못 맞춥니다 - notice가 아닌 것을 함께 적었습니다 — 상태 배지(
.ds-label) · 흐름을 막는 확인창(모달) · 표 행 하이라이트 · 박스 없는 한 줄 검증 문구 - 레거시는 마이그레이션 대상이지 위반이 아닙니다. 일괄 스윕하지 않고 고치고 있는 파일 안에서만 바꿉니다(모달·버튼과 같은 정책).
bg-*-50조합 310곳이 잡히지만 상당수는 알림 박스가 아니라 배지·행 하이라이트입니다
변경
- 로그인·계정 화면의 알림 박스 10곳을 notice로 전환했습니다 — 공용
signin-form(오류 3 · 인증코드 안내 1) ·forgot-password-form(성공·안내·오류) ·change-password-form(성공·오류) ·signup-form(오류). 공용 컴포넌트라 8개 앱 로그인 화면에 한 번에 반영됩니다. 인증코드 발송 안내는 orange 조합이었는데 notice 변형에 orange가 없어--info(yellow)로 갑니다 - admin 의 계정 화면 오류 6곳 + 스케줄러 경고 목록을 notice 로 전환했습니다 — 워크스페이스 선택(3) · 회원가입 · 이메일 인증 · 초대 수락은
--danger, 스케줄 경고 모달의 항목은--warning+ 아이콘(⚠️이모지를 규격 아이콘으로 교체). 같은 화면의 team-manager 복사본은 아직 남아 있습니다 - team-manager 의 안내 박스 6곳을 notice 로 전환했습니다 — 병동 설정의 조직 정책 안내·교육 정책 안내 2종(예전엔 orange/amber 로 색이 서로 달랐습니다) · 스케줄 경고 목록(
⚠️이모지 → 규격 아이콘) · 치료 인센티브의 항목 미등록 경고. admin 에는 이미 적용돼 있고 team-manager 복사본만 옛 상태로 남아 있던 드리프트였습니다 - 직원앱의 "승인 대기 중인 신청이 있어요"를
--warning, 모듈 매니저의 "API 연결 실패"를--danger로 바꿨습니다. 모듈 매니저 쪽은 박스 안에 있던 재시도 버튼을 notice 밖(아래)으로 뺐습니다 — notice 는 액션 슬롯이 없으니 버튼은 밖에 둡니다 - hr-system 은 급여 시트 셀 상세 패널의 "발송 완료" 한 곳만
--success로 바꿨습니다. 나머지 후보는 열어보니 성격이 달랐습니다 — 호봉/급여 미리보기는 값 카드, 엑셀 가져오기 결과는 버튼이 달린 결과 카드(코드 주석에 "not a plain ds-notice"로 이미 명시), 치료 유형 문구는 읽기 전용 필드의 보조 텍스트, "보호된 행이 없습니다"는 빈 상태입니다. 버튼을 품은 결과 카드는 DS 에 정의가 없습니다 — notice 는 아이콘+문구 전용이라 액션 슬롯이 없어서, 결과 카드 패턴 정의는 백로그로 둡니다 .ds-modal__desc는 정본에 없습니다 — admin·hr-systemmain.css두 곳에만 있어서, team-manager 에서 쓰면 스타일이 통째로 빠져 전역p { 16px }로 렌더됩니다(조용한 깨짐). 두 복사본은margin값도 어긋나 있습니다. 근무 불일치 보정 모달의 설명문은 그래서 이 클래스 대신text-b4 text-label-assistive로 넣었고, 함정은.claude/rules/frontend/design-system-architecture.md의 복제 표에 기록했습니다- 모두가 안내 박스인 건 아닙니다 — 자격 유형 폼의 "자격유형 · 기본 · 삭제 불가" 카드와 희망근무 상세의 날짜 목록은 색 틴트를 쓰지만 목록 항목이라 notice 로 바꾸지 않았습니다. 색이 들어간 박스라고 전부 notice 가 아니라, 흐름을 설명·경고하는 박스만 notice 입니다
- module-manager(4010)가
design-system.css를 아예 로드하지 않고 있었습니다 —main.css가@import "tailwindcss"뿐이라, 이 앱만 공용 로그인 폼의.ds-btn이 무스타일로 렌더되고 있었습니다(기존 결함). notice 전환 시 투명 박스가 될 자리라 정본@import한 줄을 추가해 다른 8개 앱과 같은 로드 체인으로 맞췄습니다 - 연차 정책의 "5인 미만 사업장" 경고를
--danger+ 아이콘으로 전환했습니다(admin 유형·기준 관리). 손으로 조합한 red 박스(bg-red-50+text-b5 font-semibold text-red-600+ ⚠️ 이모지)를 DS 규격(패딩 10/12 · radius-4 · 12px · 아이콘 red-500)으로 맞췄고, 본문은<span class="flex-1">로 감쌌습니다 — admin의 unlayeredp { font-size: 16px }가 notice 의 12px를 이기기 때문에 notice 안에서는<p>를 쓰지 않습니다
2026-07-29 — 신규 모달은 무조건 DS 3종 (design/modal-apply-feedback-DS)
금지 (재유입 차단)
- 신규 기능에서 모달을 만들 때 DS 3종을 벗어나면 커밋이 막힙니다 —
pnpm check:modals(pre-commit blocking). 잡는 것: 백드롭 직접 조합(fixed inset-0+ 배경) ·bg-black/*·bg-[var(--ds-dim…)]· 새.ds-mini-modal· 모달 카드에 직접 준 패딩 ·.ds-modal__title에 얹은 색 - 추가된 줄만 봅니다. 레거시가 72곳(백드롭 25 · 딤 24 · mini-modal 17 · 패딩 6) 있어 전체를 막으면 아무 커밋도 못 합니다 — 목적은 과거 청산이 아니라 새 위반 차단입니다. 현황은
pnpm check:modals:audit - 정당한 예외는 사유를 적어 통과시킵니다 —
ds-modal-exempt: <사유>(같은 줄 또는 윗줄). 컨텍스트 메뉴·피커·라이트박스·드로어 딤처럼 문서가 인정하는 예외용이고, 사유 없는 예외는 두지 않습니다 - 문서에 새 모달을 만들 때 절을 만들어 3종 복붙 시작점과 막히는 목록을 함께 뒀습니다
변경
- 컨펌 팝업을 특징별로 나누지 않습니다. 파괴적(삭제) 확인도 카드·제목·여백·타이포가 완전히 같고, 차이는 푸터 버튼이 집니다 —
tone: "danger"는 이제 확인 버튼 색만 바꿉니다(제목 red 제거). 같은 컴포넌트가 두 종류처럼 보이던 것을 없앴습니다
수정
- 문서 데모의 다이얼로그 상단 여백이 실제와 달랐습니다 — VitePress 의
.vp-doc h3(margin-top:32px, 특이도 0,1,1)가.ds-modal__title(0,1,0)의margin:0을 이겨서 카드 위 여백이 28 이 아니라 60 으로 보였습니다. 실제 앱은 28 이었으니 문서 쪽만 어긋난 드리프트입니다.ds-tailwind-shim.css에서 모달 카드 안 헤딩의 본문 크롬을 무력화해 고쳤고(특이도 0,2,1), 새 모달 데모에도 자동 적용됩니다
2026-07-29 — 모달 3종 확정 + 컨펌 다이얼로그 여백 28 · 타이틀 「확인」 (design/modal-apply-feedback-DS)
변경
- 모달의 종류를 셋으로 확정하고 이름을 붙였습니다 — 컨펌 다이얼로그(confirmation dialog,
.ds-dialog) · 일반 모달(modal,.ds-modal) · 패널 모달(panel modal,.ds-modal--panel). 셋은 백드롭·닫기·스크롤잠금·카드 내부 구조가 전부 같고 바깥 여백과 크기만 다릅니다. 네 번째 종류는 만들지 않습니다 → 모달은 3종입니다 - 컨펌 다이얼로그 여백을 상하좌우 28로 일괄 조정했습니다(일반 모달 상44/좌우40/하36). 문장 한두 줄 + 버튼뿐인 카드에 40을 주면 내용 대비 여백이 과해 카드가 비어 보였습니다. 안쪽 간격(타이틀↔본문 24 · 본문↔푸터 32)과 타이포는 일반 모달과 그대로 동일합니다 — 달라진 건 바깥 여백 하나뿐입니다
- 여백 차이는 마크업이 아니라 CSS가 집니다 —
.ds-dialog .ds-modal__*가 값을 갖습니다. 선택자 특이도(0,2,0)가 앱main.css에 복제된.ds-modal__header(0,1,0)보다 높아 소스 순서와 무관하게 이깁니다(복사본은 admin·hr-system·management-dashboard 세 곳) - 컨펌 다이얼로그 타이틀을 on/off 축으로 만들고 기본값을 「확인」으로 통일했습니다. 예전엔 종류마다 기본 제목이 달랐습니다(alert 「안내」/「오류」, confirm 「확인」, prompt 「입력」) — 같은 컴포넌트인데 화면마다 제목이 갈려 서로 다른 것처럼 보였습니다. 이제 종류 불문 「확인」, 끄려면
title: ""/title: false(헤더가 통째로 빠지고.ds-dialog--no-title이 본문 위 여백을 대신 집니다), 바꾸려면 문자열 - 실패 신호는 제목이 아니라 톤이 집니다 —
showError의 제목도 「확인」이고,tone: "danger"가 제목을 red로, 확인 버튼을lightor로 바꿉니다 - 타이틀을 비워 부르던 급여 시트 4곳(
rows.ts)의title: ""를 지워 기본 타이틀 「확인」이 적용되게 했습니다
메모
.ds-mini-modal(저장확인·위저드 확인)은 이 3종 밖의 레거시입니다. 역할은 컨펌 다이얼로그와 같은데 규격이 다릅니다(패딩 24 · gap 32 · 타이틀 14) —.ds-dialog로 흡수하는 것이 목표이고 새 코드에서는 쓰지 않습니다. 일괄 스윕은 하지 않았습니다
2026-07-29 — 네이티브 얼럿 폐지 + 확인/알림 다이얼로그를 폼 모달 규격으로 (design/modal-apply-feedback-DS)
추가
- 공용 다이얼로그를 하나 만들었습니다 —
packages/components/src/dialog.ts+html/ds-dialog.html.askConfirm/showAlert/showError/showPrompt네 함수로confirm()/alert()/prompt()를 전부 대신합니다. 문서: 모달 → 확인·알림·입력 다이얼로그 - 등록은 앱이 아니라 플러그인이 합니다 —
createAuthComponentsPlugin()이Alpine.store("dialog", …)를 대신 걸어, 앱이 빠뜨리면 조용히 no-op(alert)·무조건 통과(confirm)로 떨어지는 사고를 구조적으로 막습니다
변경
- 다이얼로그 타이포·간격을 폼 모달과 동일하게 맞췄습니다. 예전
.ds-mini-modal(패딩 24 · gap 32 · 타이틀 14/600 · 본문 13)은 같은 화면의 폼 모달(44/40/36 · 타이틀 20/600 · 본문 14)과 눈에 띄게 달랐습니다. 이제 다이얼로그가.ds-modal__header/__title/__body/__footer를 그대로 씁니다 — 수치를 복제하지 않으므로 폼 모달이 바뀌면 다이얼로그도 따라갑니다. 타이틀↔본문 24px 는 헤더의padding-bottom이 만듭니다 - 네이티브
alert()/confirm()/prompt()를 전부 걷어냈습니다 — 231곳(TS) + 13곳(HTML). 실패 경로는showError(제목 「오류」 + red), 나머지는showAlert(제목 「안내」)로 나눴고,confirm()은await askConfirm()으로 바꾸며 호출부를 async 로 승격했습니다. 파괴적 확인(삭제·해체·초기화·revoke)은tone: "danger"→ 확인 버튼lightor - 중복 구현 3개를 공용 하나로 접었습니다 — hr-system 시트의
dialog슬라이스 +dialog-bridge+input-prompt, employee-app 의confirm스토어, Messenger 의 자체 폴백. 슬라이스는 얇은 위임만 남기고(this.askConfirm(...)170여 개 호출부 무변경) 상태·템플릿·브리지는 삭제했습니다
금지 (재유입 차단)
- 네이티브 시스템 다이얼로그는 이제 금지입니다 — 예외 없음. 걷어내는 것만으로는 다시 들어옵니다. 문서 + 기계적 차단 두 겹으로 막았습니다
- Biome
lint/suspicious/noAlert를error로 켰습니다 —.ts의alert(·window.alert(·globalThis.prompt(를pnpm lint:check에서 잡습니다 pnpm check:dialogs(pre-commit blocking) 를 새로 뒀습니다 — Biome 이 못 잡는 캐스트형(window as any).confirm(· 인덱스형window["alert"](·.html전부를 담당합니다. 색 검사와 달리|| true가 없어 걸리면 커밋이 막힙니다- 두 겹인 이유는 캐스트형이 실제로 9곳 새어 나갔기 때문입니다. 소스 grep 은 통과했고 빌드 산출물을 스캔해서야 발견했습니다(team-manager·admin 스케줄러). Biome 은 그 형태를 전역 참조로 보지 않습니다
- 예외는 다이얼로그 자체 구현(
dialog.ts·ds-dialog.html)뿐이며 스크립트ALLOW목록에 명시돼 있습니다
- Biome
메모
showAlert는 일부러 await 할 수 없습니다 — 대부분catch에서 부르는데 거기서 await 하면 뒤따르는finally정리가 사용자 클릭까지 멈춰 섭니다- e2e의
page.on("dialog", …)는 이제 아무것도 잡지 못합니다. 조용한 no-op 이 되어 「얼럿이 안 떴다」 검증을 항상 통과시키는 가짜 초록을 만들었습니다 — 시트 스펙 5개를 새 헬퍼helpers/ds-dialog.ts로 옮겼습니다. 다이얼로그를 띄우는 동작은 사용자의 답을 기다리므로await하지 말고 먼저 시작해 둔 뒤 확인을 누르고 기다립니다 ds-dialog.html루트의x-data는 지우면 안 됩니다. 이 파일은 앱index.html최상위(어떤x-data스코프에도 없는 자리)에 include 되는데, Alpine 은x-data루트에서만 트리를 초기화합니다. 없으면x-cloak이 남아 스토어는 열렸는데 화면엔 아무것도 안 뜨는 조용한 실패가 되고, 빌드·린트·타입체크는 전부 green 입니다 — 브라우저에서 실제로 띄워 봐야 잡힙니다ds-dialog.html주석에 include 지시문을 예시로 적으면 안 됩니다 — 빌드의html-include가 주석까지 훑어 자기 자신을 끼워 넣습니다(첫 빌드가 이걸로 깨졌습니다).ds-mini-modal은 그대로 남습니다 — 저장확인(close-confirm)·위저드 확인 등 네이티브 대체가 아닌 작은 팝업이 계속 씁니다. 이번 정렬 범위는 「네이티브 다이얼로그 대체」 하나입니다
2026-07-29 — 상태 툴팁은 「상태 + 행동」 2줄로 (design/modal-apply-feedback-DS)
변경
- hr-system 급여 시트의 반영 상태 칩 툴팁을 멀티라인 2줄로 바꿨습니다. 기존 문구는 「시트 값이 급여대장에 반영된 값과 다릅니다. 다시 반영하면 급여대장이 시트와 같아집니다」로, 다시 반영하는 방법이 문장 어디에도 없었습니다 — 상태만 알려 주고 행동은 사용자가 화면에서 찾아야 했습니다. 이제 1줄은 지금 상태, 2줄은 「오른쪽 「급여대장에 반영」 버튼을 누르면 …」처럼 누를 자리와 그 결과를 적습니다
- 못 누르는 상태에서는 먼저 풀어야 할 것을 앞세웁니다 — 작업 완료·보호·대상 미지정이면 버튼이 비활성이라 「버튼을 누르세요」가 막다른 안내가 됩니다. 판정은 반영 버튼과 같은
commitBlockedReason하나를 공유해 칩과 버튼의 안내가 어긋나지 않게 했습니다 - 급여대장 화면에도 안내를 넣었습니다 — 여기는 집계 열뿐이라 상태 칩도, 「급여대장에 반영」 버튼도 아예 없고 「소스 전체 반영」만 있습니다. 숫자가 여기 보이니 고칠 곳도 여기라고 읽혀 「반영 버튼이 안 보인다」로 되돌아오던 자리라, 그 버튼 툴팁 1줄째에 값이 소스 시트에서 온다는 사실을 먼저 적고 2줄째에 미반영 소스 개수와 「변경된 시트만 반영」을 적습니다
- 사이드바 상태 점을 색 있는 2단계로 바꿨습니다. 예전에는 미반영일 때만 점이 떠서, 점이 없는 상태가 「작업 완료」인지 「반영까지 끝난 작업 중」인지 구분되지 않았습니다. 이제 작업 완료가 아닌 시트는 전부 점을 달고 색이 반영 여부를 말합니다 —
primary=반영 필요 ·neutral-300=반영 완료. 라벨도 색의 짝을 읽어 줍니다(「작업 중 / 반영 필요」·「작업 중 / 반영 완료」) - 라벨은 상태 이름까지만, 방법은 적지 않습니다. 어떻게 반영하는지는 시트를 열면 툴바 칩과 반영 버튼이 이미 안내하므로 목록에서 같은 말을 두 번 하지 않습니다. 「편집 중」이라는 옛 라벨은 「작업 중」으로 정정했습니다: 시트 상태는 「완료 / 잠김 / 작업 중」 3종인데 「편집 중」은 그중 어느 것도 아니었고, 급여대장에서는 아무도 편집하지 않았는데 소스가 밀려 켜지므로 사실과도 달랐습니다
- 반영 개념이 없는 시트는 둘째 줄을 뺍니다 — 반영 열도 없고 소스도 받지 않는 시트에 회색 점을 달고 「반영 완료」라고 쓰면 하지도 않은 반영을 했다고 말하게 됩니다. 목록 API가
commitState(needed/done/none)로 이 세 갈래를 내려 줍니다 - 3줄째는 마지막으로 값을 고친 시각입니다(「3시간 전 수정」). 여기서 쓰는 값은
lastChangeAt(행·셀의updatedAt최댓값)이지 시트의updatedAt이 아닙니다 — 셀 편집 경로는sheet_views레코드를 건드리지 않아서, 시트updatedAt을 쓰면 방금 고친 시트가 「3일 전 수정」으로 보입니다(사이드바 목록에 이미 떠 있는 「N분 전」 텍스트가 그 값이라 같은 줄에서 두 시각이 어긋날 수 있습니다). 목록 API가 판정용으로 이미 뽑던 값이라 쿼리는 늘지 않았습니다
메모
- 줄바꿈 말고는 아무것도 더 하지 않았습니다 —
title에\n이 생긴 것만으로tooltip.ts가 상세 도움말 버블로 자동 전환합니다(data-ds-tip은 원래 있던 placement 지정 그대로, 새 클래스 0). 아래 2026-07-27 「멀티라인 툴팁 범위 확장」이 실제 문구 개선으로 이어진 첫 사례입니다 - 문구는 마크업이 아니라 TS getter(
commitStatusTooltip)에 둡니다. 상태 4갈래 × 2줄을:title삼항식에 넣으면 읽을 수 없고, 버튼 툴팁(commitButtonTooltip)과 같은 자리에 있어야 둘이 같이 관리됩니다
2026-07-27 — 툴팁 밝은 톤(light) 추가 (design/recheck-applied-feedback)
추가
- 툴팁에 밝은 톤을 만들었습니다 — 지금까지 툴팁은 검은 알약 하나뿐이라, 흰 카드·패널 위에서는 필요 이상으로 무겁게 튀었습니다. 밝은 배경 +
--color-label-alternative글자 +--color-line-normal1px 라인의 반대 톤을 하나 두었습니다 - 켜는 법은 속성 하나입니다 — 대상에
data-ds-tip-tone="light". 조상에 걸어도 됩니다(closest로 판정) — 밝은 톤은 보통 트리거 하나가 아니라 패널·화면 단위 결정이라, 패널 루트에 한 번만 걸면 그 안의 툴팁이 전부 따라옵니다. 안쪽 마크업은 한 줄도 고치지 않습니다 - 색 톤은 「세 번째 종류」가 아니라 세 번째 축입니다. 종류는 여전히 한 줄·멀티라인 2가지, placement도 4개 그대로이고, 톤은 그 둘과 직교합니다(멀티라인 밝은 compact-center 같은 조합이 그냥 됩니다). 톤 값은
light하나뿐이며 늘리지 않습니다 — 기본이 어두움이라dark가 필요 없고, 버블 스타일이 갈라지기 시작하면 되돌리기 어렵습니다
변경
- 색을 변수 2개(
--ds-tip-bg·--ds-tip-fg)로 모읍니다. 버블 배경과 4개 placement의 화살표가 같은 변수를 읽으므로, 톤 모디파이어는 변수만 덮으면 되고 placement별로 색을 다시 적지 않습니다. 예전처럼 화살표마다 색이 하드코딩돼 있으면 톤을 하나 추가할 때 3곳을 조용히 빠뜨립니다. 어두운 톤의 값은 그대로라 기존 화면의 시각 변화는 0입니다
메모
- 밝은 톤에만 테두리가 있습니다 — 흰 버블은 흰 배경 위에서 경계를 잃기 때문입니다. 화살표에도 같은 라인을 그리는데, 45° 회전한 사각형이라 바깥을 향하는 두 변이 placement마다 다릅니다(아래 방향
bottom+right· 위 방향top+left· 왼쪽 방향left+bottom). 화살표 안쪽 절반이 버블 테두리 위에 겹쳐 그려지므로 화살표를 1px 바깥으로 밀어 두 선을 잇습니다 - 그림자는 밝은 톤만
--ds-shadow-md로 바꿨습니다 — 어두운 톤의 25% 검정 그림자는 밝은 버블 아래에서 탁하게 번집니다. 어두운 톤의 그림자 2종은 매칭 토큰이 없어 하드코딩 유지라는 기존 결정 그대로입니다 - 적용 화면은 아직 없습니다. 컴포넌트만 준비된 상태이고, 「밝은 패널 위에서 검은 알약이 과하다」고 판단된 화면부터 붙입니다
2026-07-27 — 멀티라인 툴팁 범위 확장 + 가로 위치 보정 (design/recheck-applied-feedback)
변경
- 툴팁의 종류를 2가지로 정리했습니다 — 「한 줄」과 「멀티라인 상세 도움말」. 어디에 뜨는지(placement)는 별개의 축이고, 어떤 종류인지는 라벨에 줄바꿈이 있느냐 하나로 갈립니다
- 멀티라인을 버튼과 여러 구간에서 쓸 수 있게 범위를 넓혔습니다. 그동안은
.icon-btn·select같은 정해진 셀렉터에 걸리거나data-ds-tip을 붙인 대상만 DS 툴팁이 떴고, 그 밖의 요소는 여러 줄title을 줘도 브라우저 기본 툴팁이 떴습니다. 이제 줄바꿈이 곧 opt-in입니다 — 평범한<button>, 표 셀, 배지, 구간 제목 어디든 여러 줄title만 주면 상세 도움말 버블이 뜹니다(기본 위치는 대상 위 가운데).data-ds-tip은 위치를 바꾸고 싶을 때만 씁니다 - 한 줄 툴팁의 규칙은 그대로입니다. 아무 요소에나 한 줄
title을 단다고 DS 툴팁이 되지는 않습니다 — 범위가 넓어진 것은 멀티라인뿐입니다 - hr-system 급여 시트의 수식 힌트
ƒ는 마크업을 한 줄도 고치지 않았는데 자동으로 DS 멀티라인 툴팁이 됐습니다(원래 개행 title을 갖고 있었지만 opt-in이 없어 브라우저 기본 툴팁으로 떴습니다). 확장의 효과가 바로 보이는 사례입니다
추가
- 가로 방향 위치 보정. 지금까지 flip은 위아래 전용이라, 화면 가장자리 대상에 320px 버블이 뜨면 잘렸습니다. 범위를 넓히면 가장자리 버튼이 흔해지므로 같이 넣었습니다 — 버블은 뷰포트 안으로 되돌리고(양옆 8px) 화살표만 대상 위에 남깁니다. 계산은 순수 함수(
clampTooltipX·clampTooltipLeft)로 분리해 단위 테스트 12개로 고정했습니다
수정
- 오른쪽 끝에서 버블이 스스로 좁아지며 세로로 길어지던 버그를 재현·수정했습니다.
position: fixed+width: auto는 shrink-to-fit 폭을 자기left기준 잔여 공간으로 계산합니다 — 화면 오른쪽 끝에 앵커되면 남은 공간이 좁으니 버블이 그만큼 찌그러졌습니다(297px → 157px로 재현)..ds-tooltip에width: max-content를 주어 폭을 위치와 분리했습니다. 가로 보정을 넣으며 실측하다 발견했고, 확장 이전에는 가장자리 사용 자체가 드물어 드러나지 않던 문제입니다 [data-placement="top"][data-flip="down"]블록이 똑같이 두 번 선언돼 있어(뒤엣것만 적용되는 죽은 코드) 앞의 사본을 지웠습니다. 화살표 동작을 고치려다 죽은 쪽을 고치기 십상인 자리입니다
2026-07-27 — 툴팁 문서 정정: placement 4개 + 멀티라인 사용처 전수 (design/recheck-applied-feedback)
추가
- 라이브 미리보기에서 멀티라인 툴팁을 직접 확인할 수 있습니다 — 기존 미리보기에는 top·right·compact 3개뿐이라, 방금 문서에 적은 멀티라인을 눈으로 볼 방법이 없었습니다. 새 줄에 ⓘ(top·멀티라인) ·
?배지(compact-center·멀티라인) · 한 줄 비교 3종을 놓았습니다 - 이 줄은 데모가 아니라 실물입니다. docs 사이트는 앱과 똑같이
setupTooltip()을 한 번 호출해 두고 있어서,data-ds-tip+ 여러 줄title마크업만 두면 프로덕션 코드가 그대로 처리합니다 — 미리보기에서 보이는.ds-tooltip--multiline전환이 실제 화면의 그것과 같은 경로입니다. docs 데모가 실제 컴포넌트와 어긋나는(재구현 드리프트) 문제를 이 지점에서는 구조적으로 없앴습니다 - 미리보기의 Vue 미러 쪽도 실제 코드에 맞췄습니다 —
.ds-tooltip--multiline자동 토글, top placement의 아래로-flip(문서에는 있는데 데모에만 빠져 있었습니다)
수정
- placement가 3개라고 적혀 있었지만 실제로는 4개입니다 —
compact-center(data-ds-tip="compact-center")는tooltip.ts와design-system.css양쪽에 이미 구현돼 있는데 문서에만 빠져 있었습니다. compact와 같은 작은 버블이지만 트리거 가운데에 정렬되고 아래 화살표가 붙습니다 —?도움말 배지처럼 좁은 트리거에서 좌측 정렬 버블이 어긋나 보이는 문제 때문에 만든 변형입니다. 자동 대상 목록에.ds-btn--icon도 빠져 있어 함께 채웠습니다
메모
- 멀티라인 툴팁(
.ds-tooltip--multiline)이 실제로 뜨는 곳을 코드에서 전수 확인해 표로 남겼습니다 — admin 근무 유형 모달의 ⓘ 2개(연차 차감 판정 · 공휴일 근무 유형), hr-system 시트 「열 설정」 모달의?배지 1개, 이렇게 3곳뿐입니다 - ⚠️ 아래 두 항목은 같은 날 범위 확장(맨 위 항목)으로 폐기됐습니다 — 지금은 개행 하나로 충분하고,
ƒ힌트도 DS 툴팁으로 승격됐습니다. 기록으로만 남깁니다 - 발동 조건은 「개행 title」 하나가 아니라 두 가지입니다 — ① 툴팁 대상일 것(자동 셀렉터 또는
data-ds-tip) ② 평가된title에 실제 개행이 있을 것. hr-system 시트의 수식 열ƒ힌트는 개행 title을 갖고 있지만data-ds-tip이 없어(그 파일에는data-ds-tip이 하나도 없습니다) 브라우저 기본 툴팁으로 뜹니다. 미전환 1건으로 문서에 적어 뒀습니다 - Alpine
:title="..."이 소스에서 여러 줄에 걸쳐 있는 것은 개행이 아닙니다. 이 기준으로 다시 세면 후보 4건은 전부 한 줄 툴팁입니다(스케줄러 희망근무 셀 · 연차 규칙 · 직원 삭제 · 시트 상단 버튼들) - 가로 방향 충돌 처리는 없습니다 — flip은 세로 전용이라, 화면 가장자리에 붙은 트리거에 320px 멀티라인 버블이 뜨면 잘립니다. 지금 사용처 2곳이 모두 가운데 뜨는 모달 안이라 표면화되지 않았을 뿐입니다(미리보기 stage를 가운데 정렬한 것도 같은 이유). 필요해지면 그때 좌우 clamp를 넣기로 하고 한계로 적어 뒀습니다
2026-07-21 — AppHeader 배경·구분선을 화면별로 켤 수 있게 (+ 메신저 화면 light 통일) (design/employee-app)
수정
- AppHeader의
solid·divider가boolean외에() => boolean도 받습니다. employee-app처럼 헤더 인스턴스 하나가 여러 섹션을 도는 셸에서는 boolean이 무용지물이었습니다 —x-data표현식은 마운트 시 한 번만 평가되므로 첫 화면의 값이 그대로 굳어, 섹션을 바꿔도 배경이 따라오지 않습니다. 함수로 넘기면appHeaderRootClassgetter가 매번 다시 읽어 화면별로 갈립니다. 기존 boolean 호출부는 그대로 동작합니다(옵션 타입만 넓힘) - 판단 기준을 문서에 적었습니다 — 본문 맨 위가 흰 면(서브탭 바·카드)으로 시작하면
solid로 이어 붙이고, 회색 셸이 그대로 이어지면 기본형(투명)을 둡니다
수정
- 헤더 탭의 활성 밑줄이 웹 탭보다 얇게 보이던 문제.
.ds-tab-underline의 기본 오프셋(md-12px/ ml-15px)은nav.ds-tab-nav의 하단 1px 구분선 위에 겹치라고 1px 더 내려간 값입니다. 헤더 탭 줄에는 그 선이 없고 대신overflow-y: clip이 걸려 있어서, 2px 밑줄의 아래쪽이 그대로 잘려 나갔습니다 — 브라우저에서 실측하니 밑줄이 아이템 바닥을 0.8px 넘어가 그만큼 깎여 2px가 ~1.2px로 렌더됐습니다..ds-app-header__tabs안에서만 1px씩 올려(-11px/-14px) 밑줄 전체가 아이템 박스 안에 들어오게 했습니다. 수정 후 재측정: 헤더-0.2px(= 완전히 안쪽), 웹 탭과 동일한 굵기 - 모바일 탭에서 hover·pressed 배경 틴트 제거. 터치 기기에서
:hover는 탭한 뒤에도 다음 탭을 누를 때까지 남습니다(iOS·Android 공통) — 그래서 선택하지도 않은 탭에 회색 박스가 붙어 있는 것처럼 보였습니다..ds-app-header__tabs안에서만 배경을 투명으로 고정했습니다(웹 TabNav는 그대로 틴트 사용). 선택 피드백은 글자색 + 하단 밑줄이 담당합니다.@media (hover: hover)로 가르지 않았습니다 — 그러면 데스크톱 브라우저로 앱을 여는 개발·검수 화면과 실기기가 갈립니다. 문서: AppHeader — 배경 틴트 없음, TabNav 상태 목록에도 예외 표기 - 헤더 우측 아이콘 버튼을 알림벨과 같은 톤으로.
getActions버튼(.ds-btn--icon --muted --lg)과 알림벨은 박스 36px · 글리프 24px까지는 같은데, 색이neutral-400(벨은 500)이고 레지스트리 아이콘 선이 1.5(벨의 path는 2)라 나란히 두면 액션만 옅고 가늘게 보였습니다..ds-app-header__actions안에서만 벨에 맞춰 색·선 굵기·hover(배경 원 없이 색만 진해짐)를 통일했습니다. 특성도로 이깁니다 —.ds-btn--icon.ds-btn--muted와.ds-btn--icon:hover:not(...)가 파일 뒤쪽에 있어 클래스 2개짜리로 쓰면 순서에서 집니다(새!important0). 실측 확인: 액션·벨 모두36×36박스 /24×24글리프 /rgb(94,94,94)/ path stroke2px - 확인 방법. 같은 마크업을
nav.ds-tab-nav와.ds-app-header__tabs두 곳에 넣고 앱 빌드 CSS(Tailwind 유틸 포함)를 물린 뒤getBoundingClientRect로 쟀습니다. ⚠️design-system.css만 걸고 재면relative·inline-flex유틸이 없어 밑줄의 기준 박스가.ds-tab-item으로 바뀌어 측정값이 통째로 달라집니다(처음에 이걸로 한 번 틀렸습니다)
추가
showBack옵션 —onBack이 있어도 false면 그 화면만 1depth로 렌더합니다. 앱 셸은 헤더 인스턴스가 하나인데 목록(1depth)과 상세(2depth)를 오가므로, "onBack이 있으면 2depth" 규칙만으로는 깊이를 바꿀 수 없었습니다(onBack유무는 마운트 시점에 굳습니다). 제목 강조(--depth2)도onBack유무가 아니라 실제 백버튼 렌더 여부를 따르도록 고쳤습니다 — 안 그러면 목록 화면에서 날짜만 화면 제목처럼 커집니다showBell·showAvatar도() => boolean허용 — 상세에서 벨·아바타를 끄려면solid와 같은 이유로 함수가 필요합니다onBellClick옵션 — 넘기면 공유 벨의 드롭다운을 렌더하지 않고 그 핸들러만 부릅니다. 모바일에서 알림 팝오버는 어차피 화면을 거의 다 덮어서, 직원 앱은 알림을 2depth 화면으로 엽니다. 미읽음 배지는 두 모드가 같은notificationBell스코프 안에 있어 카운트 폴링이 그대로 유지됩니다. 문서: AppHeader — 알림 벨- ⚠️ 셸이 연 depth의 뒤로가기를
app-depth-back이벤트로 돌리면 엉뚱한 섹션이 자기 goBack()을 실행합니다(직원 앱은 메신저가 그 이벤트를 듣습니다). 셸이 연 화면은 셸이 직접 닫습니다. 같은 이유로 메신저의x-effect가setDepth(null)로 모든 depth를 밀던 것도kind가messenger*일 때만 닫도록 좁혔습니다 — 안 그러면 알림 화면이 열리자마자 닫힙니다
- ⚠️ 셸이 연 depth의 뒤로가기를
- 문서에 헤더 하나가 목록과 상세를 겸할 때 절 추가 — 상태는 라우터 스토어에, 동작(뒤로가기)은 window 이벤트로 넘기라는 원칙 포함
ic-message-plus아이콘 신설 — 말풍선 + 안쪽 플러스("대화를 새로 만든다"). 말풍선 path는ic-message와 동일하고 중심에 6단위 십자만 얹었습니다AppHeader.test.ts신설(12케이스) — 함수형 옵션이 매번 다시 읽히는지, 깊이 판정과 제목 강조가 함께 움직이는지, 탭이 있으면 하단 8px이 붙지 않는지를 잠급니다
메모
- 직원 앱 메신저 탭(대화/연락처)을 본문 → 헤더로 이관(ml 48px). 본문에
nav.ds-tab-nav를 두던 구조라 모바일 상단 내비게이션은 헤더와 탭이 한 컴포넌트라는 규칙을 어기고 있었습니다(결재 탭은 이미 이관 완료). 함께 있던 「+ 그룹 대화」 버튼은 헤더 우측 아이콘 액션(ic-message-plus)으로 옮겼습니다. 그룹 선택 모드의 컨텍스트 바(취소 / n명 / 그룹 만들기)는 탭이 아니라 선택 상태 전용 툴바라 본문에 남고, 그동안 헤더 탭과 그룹 액션은 감춥니다 — 예전에도 탭 줄 자리를 이 바가 통째로 차지했습니다 - 그룹 대화 만들기(상대 고르기)도 2depth 화면으로. 「+」를 누르면 뷰는 연락처 그대로지만 헤더가 백버튼+「그룹 대화」로 바뀌고 하단 내비가 숨습니다. 본문 툴바의 「취소」 버튼은 제거 — 백버튼이 곧 취소이고(
goBack()이groupSelectMode를 가장 먼저 풉니다) 둘 다 두면 같은 동작이 한 화면에 두 번 나옵니다. 헤더가 없는 chat-widget에서는 그 버튼이 유일한 취소라 그대로 둡니다 messengerGroupSelect스토어 거울 제거. 그룹 선택이 depth로 승격되면서 탭·액션을 감추던 두 군데 가드가isDepth하나로 덮여 읽는 곳이 없어졌습니다 — 남겨두면 "왜 있지" 하는 죽은 상태가 됩니다- 헤더가 탭을 품으면 헤더 하단 8px은 붙지 않습니다(요청받아 확인).
(solid || divider) && !hasTabs조건이라 메신저(배경 solid + 탭)는--pad-bottom없이 탭 줄이 바로 본문에 이어집니다. 테스트 4케이스로 잠갔습니다 - 직원 앱: 메시지방·공지 상세를 2depth 페이지로 전환. 자체 헤더 줄 대신 공유 AppHeader가 백버튼·제목·액션(검색·멤버)을 그리고, 하단 내비는 숨습니다. 상세 상태는
router스토어의depth가 소유하고(헤더는 앱 셸 스코프, 상세는 섹션 스코프라 로컬로 공유 불가 —approvalTab과 같은 이유), 백버튼·헤더 액션은 window 이벤트(app-depth-back등)로 섹션에 전달합니다 - 공지 상세: 「확인 했어요」를 하단 고정 + 끝까지 읽어야 활성화. 버튼이 본문 스크롤 안에 있어 긴 공지는 끝까지 내려야 보였습니다 → 스크롤러 바깥 형제로 빼서 화면 하단에 고정하고(
position: fixed가 아니라 채팅 입력줄과 같은shrink-0패턴), 본문을 끝까지 본 뒤에만 활성화되도록 했습니다. 함정 둘: ① 내용이 짧아 스크롤이 없는 공지는scroll이벤트가 영원히 안 와서 버튼이 영영 비활성이 됩니다 → 열릴 때 한 번 직접 잽니다. ② 그 측정을 화면에 붙기 전에 하면clientHeight·scrollHeight가 둘 다 0이라 "끝까지 봤다"가 참이 됩니다 →clientHeight === 0이면 재지 않습니다. 두 함정 모두Messenger.test.ts(8케이스)로 잠갔습니다 - 공지 상세 메타를 DS 라벨로 교체(
--md24px/13px) · 날짜text-b4. 중요도·분류 칩이 유틸 조합(px-2 py-0.5 rounded+bg-…/text-…+text-[10px])으로 손수 그려져 있었습니다 →.ds-label --md --square+ 색 변형 클래스로 바꿨습니다(라벨은 색 변형으로만 칠하는 것이 강제 규칙).noticePriorityColor()도 Tailwind 유틸 대신ds-label--red/--primary/--gray/--light-gray를 반환합니다. 분류 칩은 중요도 칩과 바로 옆에 붙어 있어 같은 회색이면 구분이 안 되므로--line(테두리)로 갈랐습니다 - 공지 제목
text-h3(24px) · 본문text-b3(16px). 제목은<h2 class="text-base">였는데 16px이 아니라 h2 기본값으로 렌더되고 있었습니다 — 공유 DS의 unlayeredh1~h6규칙이 Tailwind 유틸을 이기고, 앱 가드는 DS 토큰 클래스만 덮기 때문입니다(공지 목록의<p class="text-xs">와 같은 함정) - ⚠️ 메신저 마크업은 데스크톱 chat-widget(7개 앱)과 공유입니다. 위젯에는 상단 헤더가 아예 없어서 자체 헤더 줄을 지우면 대화방에서 빠져나올 방법이 사라집니다 →
hostHeader옵션(기본 false)으로 employee-app에서만 숨깁니다. 또한 safe-area 하단 패딩을 갖고 있던 게 하단 내비라, 내비가 숨는 화면에서는 채팅 입력줄이.safe-bottom을 직접 가져야 홈 인디케이터에 깔리지 않습니다 - 죽은 헤더 교체 감지기 제거 —
.safe-top요소를 찾아 앱 헤더를 숨기려던MutationObserver(섹션 콘텐츠 전체를subtree+attributes로 관찰)가 남아 있었는데, 결과값sectionHeaderReplacementVisible을 읽는 템플릿이 하나도 없었습니다. 이번 2depth 구조가 그 의도를 제대로 대체하므로 함께 걷어냈습니다 - 직원 앱 메신저 화면을 전부 light(흰 면) 한 장으로 통일했습니다. 이전에는 투명 헤더(셸 회색) → 서브탭 바(neutral-25) → 대화 목록(neutral-50)으로 세 단계의 회색이 겹쳐 헤더 아래에 회색 띠가 남았습니다. 헤더는 메신저에서만
solid를 켜고,.messenger-subnav-bar는 neutral-25 → 흰색, 대화 검색·목록의bg-neutral-50과 메시지 검색 바의bg-gray-50은 걷어내 messenger-content.html 루트가bg-white한 곳에서 면을 소유합니다 - 공지 구간의 카드를 걷고 메시지 구간과 같은 눈금에 올렸습니다. 공지만 흰 카드(
mx-4+px-4+ 행px-2)로 묶여 있어 제목 열이 메시지 이름 열보다 안쪽으로 밀려 있었습니다 → 구간px-4 py-2· 행px-3 py-2.5 gap-3· 아이콘 40px로 맞췄습니다. 이 과정에서<p class="text-xs">가 12px이 아니라 16px로 렌더되던 것도 드러났습니다 — 공유 DS의 unlayeredp { font-size }가 Tailwind 유틸을 이기고, employee-appmain.css의:is(p,h1..h6).text-*가드는 DS 토큰 클래스만 덮기 때문입니다(text-xs·text-[10px]은 무방비).<span>/<div>+text-b4/text-b6로 바꿔 메시지 행과 같은 스케일이 됐습니다 - 행에서 테두리와 좌우 여백을 걷어 폭을 넓게 씁니다. 필수 대화방의
border border-orange-100을 없애고(배경 틴트만으로 구분) 행의px-3도 뺐습니다 — 라인이 사라지면 행을 안쪽으로 물릴 이유가 없습니다. 이제 좌우 여백은 구간의px-4(16px) 하나만 남아, 아바타·시각·읽지 않음 배지가 각각 12px씩 넓게 자리합니다. 공지·채널 행도 같은 규칙입니다 - 공지 목록의 중복 마크업 한 벌 제거.
slice(0, 3)과slice(3)이 완전히 같은 행 마크업 두 벌이라 한쪽만 고치면 「더보기」 이후 행만 조용히 갈라졌습니다 →slice(0, showAllNotices ? length : 3)한 벌로 합쳤습니다(35줄 감소). 미확인 공지 아이콘의 하드코딩fill="#ea580c"(구버전 오렌지)도fill-orange-500으로 교체 - 회색 배경을 걷으면
hover:bg-white가 같이 죽습니다. 채널·대화 행과 메시지 검색 결과가 회색 위에서 흰색으로 밝아지는 hover였는데, 바닥이 흰색이 되면서 아무 변화가 없어집니다 →hover:bg-neutral-50 active:bg-neutral-100으로 뒤집었습니다. 연락처 행은 원래부터 틴트 오버레이(.msg-row-select)라 영향이 없습니다
2026-07-20 — 모바일 앱 셸 크롬 2종 신설 (AppHeader · BottomNav) (design/employee-app)
추가
- AppHeader · BottomNav 신설. 그동안 모바일 상단 바와 하단 탭바는 DS에 정의가 아예 없었고(SoT에
@media0건 ·safe-area-inset0건), employee-appmain.css가.bottom-nav/.bottom-nav-item/.unread-badge/.safe-top으로 자체 보유하고 있었습니다. 정의를 공유 DS로 올려.ds-app-header*(7규칙) ·.ds-bottom-nav*(5규칙)로 세웠습니다. 현재 소비 앱은 employee-app 하나이지만, 모바일 프리미티브가 DS 밖에 있던 구조 자체를 해소하는 것이 목적입니다 - 설정 기반(config-driven) 구조. 탭 추가·삭제·순서 변경·배지·권한 숨김이 호출부 배열 수정만으로 끝납니다(
apps/employee-app/src/nav-config.ts). 템플릿과 컴포넌트는 손대지 않아요. 항목 옵션:icon/iconSvg(이중 주입) ·activeIcon/activeIconSvg·badge()·hidden()·disabled - 활성 상태 fill 아이콘. 선택된 탭은 색뿐 아니라 글리프가 outline → solid로 바뀝니다. 활성 변형은 선택 사항이라 지정하지 않은 항목은 기본 아이콘으로 폴백해요
- 배지 일반화. 기존
.unread-badge는 메신저 전용이었지만,badge()는 어느 탭에나 붙고0·null·""반환 시 자동으로 숨습니다(badgeMax초과분은"99+") - 셸 폭 토큰
--ds-app-shell-max-width(기본 430px) — 하드코딩 430px를 대체
수정
- AppHeader 기본형 높이 57 → 48px.
padding: 12px 16px 8px+ 흰 배경 +border-bottom: 1px이던 것을padding: … 16px 0으로 바꾸고, 배경·구분선을 기본형에서 걷어내 옵션으로 돌렸습니다. 헤더가 셸 배경과 이어지고, 아래 콘텐츠와의 간격은 콘텐츠가 소유합니다(헤더에 하단 패딩을 되돌리면 화면마다 간격이 이중으로 붙습니다) - 배경(
solid)·하단선(divider)은 서로 독립 축. 넷 중 아무 조합이나 가능하고 기본형은 둘 다 off입니다 —.ds-app-header--solid(흰 배경) /.ds-app-header--divider(하단 1px). 앱 CSS에서.ds-app-header에 배경을 덧칠하면 변형이 갈라지므로 옵션으로만 켜도록 문서에 못박았습니다 - 하단 여백 8px은 조건부로 되살아납니다. 헤더가 배경이나 선을 가져 하나의 "면"이 되면 콘텐츠와의 여백을 헤더가 직접 가져야 하므로
--pad-bottom(8px)이 붙습니다. 단 탭 줄이 있으면 붙지 않습니다 — 탭이 그 아래를 채우므로 더하면 사이가 벌어집니다. 조건은(solid || divider) && !hasTabs이고, 판정은 컴포넌트가 하고 CSS는 결과 클래스만 받습니다(:has()의존 회피). 결과 높이: 기본형 48 · 배경만 56 · 선 포함 57px — 초기 구현의 57px이 정확히divider+ 하단 8px 조합이었던 셈입니다 - AppHeader에 1depth / 2depth 도입.
onBack을 넘기면 2depth — 좌측에 백버튼(.ds-app-header__back, chevron-left 24px)이 붙고.ds-app-header--depth2가 루트에 걸려__leading이 보조 텍스트(b4·neutral-400)에서 화면 제목(b3·semibold·neutral-900)으로 바뀝니다. 별도depth옵션 대신 **"뒤로 갈 곳이 있으면 2depth"**로 판정해 호출부가 한 옵션만 넘기면 되게 했습니다. 백버튼+제목 묶음은.ds-app-header__lead가 담당 - 깊이별 시각 예시를 문서에 고정 렌더로 넣었습니다 —
DemoAppHeader에depth·tabs·bell·avatarprop을 추가해, 체크박스를 켜지 않고도 1depth / 2depth / 2depth+탭 줄을 나란히 비교할 수 있습니다(ASCII 다이어그램을 실제 렌더로 교체). 3depth 이상도 2depth와 동일 형태 — 깊이를 세지 않고 "뒤로 갈 곳이 있는가"로만 판정합니다 - 메신저 아이콘 점 3개 정렬. 말풍선 원의 중심은
x=11.25인데 점 3개는 Heroicons 원본 좌표(평균12.375)를 물려받아 1.125 오른쪽으로 치우쳐 있었습니다(말풍선만 다른 path로 교체되고 점이 따라오지 않은 흔적). 시작점M8.625→M7.5로 세 점 중심을7.125 · 11.25 · 15.375로 맞췄습니다 - 알림벨 글리프 확대를 클래스 훅으로 이관. 앱 CSS의
[x-data="notificationBell"] > .relative > button > svg는 공유 템플릿의 4단 중첩 구조에 의존해 마크업이 바뀌면 조용히 깨졌습니다 →.ds-app-header__bell로 대체 - messenger-content.html의
text-[9px]→text-c2(10px). 9px는 타이포그래피 스케일에 없는 값이고 employee-app 실렌더 최소값이었습니다.<span>이라 unlayeredp규칙에 눌리지 않고 실제로 9px로 렌더되던 자리예요
문서
- 내비게이션 섹션에 두 페이지 추가.
.ds-tabbar(상단 탭)와.ds-bottom-nav(하단 탭바)의 혼동,PageHeader(데스크톱)와AppHeader(모바일)의 혼동을 각 페이지의규칙 (강제)에 트랩으로 명시 - 내비게이션 사이드바를
Web/Mobile (App)2계층으로 재편. 카테고리에(App)을 명시한 이유는 반응형 모바일 웹과 구분하기 위해서입니다 — 좁아진 데스크톱 화면은 Web 컴포넌트 + 브레이크포인트 규칙이 담당하고, 이 그룹은 Capacitor 네이티브 앱 셸만 다룹니다 - 모바일 상단 내비게이션은 헤더와 탭이 한 컴포넌트. 작업 중간에
TabNav (Mobile)문서를 따로 만들었다가, 모바일에서는 헤더와 탭이 같은 것이라는 정리에 따라 그 문서를 없애고 AppHeader가 탭 줄까지 품도록 통합했습니다.getTabs를 넘기면 헤더 줄 아래.ds-app-header__tabs가 렌더되고, 생략하면 헤더만 남습니다. 웹처럼 본문에nav.ds-tab-nav를 두지 않습니다 - 탭 아이템 스타일은 웹 TabNav와
.ds-tab-item을 공유합니다(현재--ml48px 고정, 모바일 전용 사이즈 베리에이션은 미정). 활성 클래스도tab-active로 동일 — BottomNav의is-active와 다르니 주의 - 활성 밑줄이 세로 스크롤을 만드는 문제를 DS 안에서 막았습니다.
.ds-app-header__tabs가overflow-y: clip을 자체 보유하므로 앱 로컬 보정이 필요 없습니다. 웹은 반대로.tabnav-unclip으로 클립을 푸는 opt-in 보정을 쓰므로, 두 규칙을 서로 복사하면 그대로 버그입니다(양쪽 문서에 경고 유지)
메모
- 라이브 미리보기 신설 —
DemoAppHeader·DemoBottomNav. docs theme이 design-system.css 전체를 import하므로 데모가 실제.ds-*클래스로 렌더됩니다(시각은 프로덕션과 동일하고, 재구현되는 건 상태 로직뿐). BottomNav 데모는 활성 fill 아이콘을 토글해 outline과 직접 비교할 수 있고, AppHeader 데모는 슬롯(액션·벨·아바타)을 켜고 끄며 우측 고정 순서를 확인할 수 있습니다. 대신 각 페이지에 **「데모의 한계」**를 명시했습니다 — safe-area 패딩·네이티브 키보드 숨김·벨 드롭다운·오버플로 클립 조건은 브라우저에서 재현되지 않습니다 - employee-app
main.css76줄 감소 - 남은 모바일 프리미티브 부채(DS 정의 없음): 바텀시트 · 액션시트 · 토스트 · 스피너/스켈레톤 · 빈 상태 · 카드 · 아바타 · safe-area 유틸
2026-07-24 — 로그인 BI 규칙을 opt-in 으로 완화 (design/employee-app)
변경
- 「로그인은 텍스트 고정」을 「기본은 텍스트, 심볼은 앱이 켜서 쓴다」로 바꿨습니다. 2026-07-20에 하지 않기로 못박았던 항목인데, 직원 앱이 제품 판단으로 로그인 상단에 Works 심볼을 놓기로 하면서 규칙이 실제 화면을 막고 있었습니다. 금지 대신 확장 가능한 형태로 열었습니다 —
loginForm({ showBrandLogo: true })로 그 앱만 켜고 기본값은false라, 안 켠 앱 7개는 종전과 100% 동일한 텍스트 제목입니다. - 열되 경계는 남겼습니다. ① 로그인에 놓을 수 있는 건 심볼뿐이고 가입의 락업을 옮기는 것은 여전히 금지입니다(워드마크가 들어가면 바로 아래 부제의 서비스명이 두 번 적힙니다). ② 심볼은
$store.hereby.brandFamily를 따라가고 자산 키를 문자열로 박지 않습니다. ③ 켠 화면은 심볼 → 제목 → 부제 3단이고, 「로그인 제목 = 앱 이름」 규칙은 그대로입니다 — 바뀐 건 심볼 노출 여부뿐입니다. - 「앱 이름 자체가 패밀리 브랜드인 앱」을 규칙에 명시했습니다. 직원 앱의 제품명은
hereby Works(국문hereby 웍스)라 앱 이름과 브랜드가 같은 말입니다. 그동안 규칙이 admin(「관리자」 ≠hereby Medical)처럼 둘이 다른 경우만 상정하고 있어서, 직원 앱 로그인 제목이 규칙 위반처럼 읽혔습니다. 예외가 아니라 일치하는 경우임을 적어 오독을 막았습니다. 아울러nav.employee_app은 「직원 앱」이라는 일반 서술어라 제품명이 아니라는 점도 함께 적었습니다. - 같은 내용을
CLAUDE.md의 Brand/BI 한 줄 가드레일에도 반영했습니다(정본은brand.md).
수정
- 심볼을 켠 로그인 제목이 「브랜드 조판」대로 렌더되지 않던 문제. 제목 전체에
font-brand한 장만 걸려 있어서, 영문hereby는 Geist SemiBold 600으로 맞았지만 국문 서비스명웍스는 스택 폴백의 시스템 한글 서체 · weight 600 으로 떨어졌습니다(정본은 Pretendard Bold 700). 한 요소에는 서체·weight 를 하나씩밖에 못 주므로loginForm에titlePartsgetter 를 두어 한글 덩어리만 잘라 내고, 조각별로font-brand font-semibold/font-pretendard font-bold를 물렸습니다. 실측 확인:hereby=Geist600,웍스=Pretendard Variable700. 한 워드마크 안에서 두 폰트가 섞이는 것이 정상이라는 조판 규칙(브랜드)을 그대로 따른 것입니다- ⚠️
x-for템플릿 안팎에 공백·개행을 넣으면 텍스트 노드가 함께 복제돼 낱말 사이가 벌어집니다 — 한 줄로 붙여 씁니다 - ⚠️ 제목 크기는 반드시 DS 토큰 클래스(
text-h2등)로 줍니다.tokens.css의 unlayeredh1{font-size:32px}가@layer utilities의 Tailwind 유틸을 이겨서text-xl같은 클래스는 조용히 무시됩니다
- ⚠️
2026-07-24 — 모바일 화면 배율 라벨·디폴트 재정의 (design/employee-app)
변경
- 글자 크기 배율 3단계 라벨을 한 칸씩 내리고 디폴트를 가운데로 — 이전
기본(×1.0) / 크게(×1.2) / 매우 크게(×1.4), 디폴트 ×1.0 에서 →작게(×1.0) / 기본(×1.2) / 크게(×1.4), 디폴트기본(×1.2) 로 바꿨습니다. 웹은 정의 타이포(×1.0) 기준으로 개발하고, 모바일은 최초 진입부터 한 단계 키운 배율(×1.2)을 기본으로 주어 손안의 화면에서 읽기 편하게 시작합니다. CSSzoom값과data-font-scale키(base/lg/xl)는 그대로라 기존 저장값·CSS 마이그레이션이 없습니다(저장소의base=작게,lg=기본,xl=크게 로 라벨만 이동).
문서
- 타이포그래피 문서에 모바일 화면 배율 섹션 신설 — 작게/기본/크게를 실제
zoom으로 나란히 렌더한 세 배율 비교 미리보기와 구현 위치를 명시했습니다.
2026-07-24 — 표 가로 스크롤바 전역 적용 (design/apply-feedback-uiux-2)
추가
- 가로로 넘치는 모든 표(리스트)에 위·아래 가로 스크롤바를 자동으로 붙입니다 —
setupTableXScroll()(@hereby/components)을 각 앱main.ts에서 1회 호출하면 DOM을 훑어 붙이고, Alpine이 나중에 그리는 표·모달 안 표까지 MutationObserver로 따라갑니다. 적용: admin · team-manager · hr-system · general-affairs · management-dashboard · inventory. 화면 마크업은 한 줄도 고치지 않았습니다 - 출발점은 윈도우입니다. 윈도우에는 표를 가로로 스크롤할 입력 수단이 사실상 없습니다 — 휠은 세로 전용이고
Shift+휠은 대부분 모릅니다. 네이티브 가로 스크롤바는 스크롤 컨테이너 바닥에만 생기는데 표가 길면 그 바닥이 화면 밖이라, 「옆에 열이 더 있다」는 사실조차 보이지 않습니다. 그래서 위에도 하나 더 두고 둘 다 상시 노출입니다 - 레이아웃 높이는 0입니다 — 바(10px)는 같은 크기의 음수 마진을 받아 표 위에 겹쳐 그려집니다. 표가 아래로 밀리지 않습니다. 겹치는 자리가 sticky thead(z 30)·sticky 헤더 컬럼(z 31)이라
--ds-z-table-xscroll(36) 토큰을 새로 뒀습니다 - PC·태블릿(≥768px =
md)만. 모바일은 터치 스크롤이 기본이라 바를 띄울 이유가 없습니다. CSS 미디어쿼리와 JS 양쪽에서 막습니다
메모
- 네이티브 스크롤바(
::-webkit-scrollbar)를 쓰지 않기로 했습니다. 처음엔 그렇게 만들었다가 되돌렸습니다 — macOS는 오버레이라 스크롤하는 동안에만 보이고(상시 노출 요구 위반), Chrome은 같은 요소에scrollbar-width/scrollbar-color가 있으면::-webkit-scrollbar규칙을 통째로 무시하며, OS의 「스크롤 막대 표시」 설정에도 흔들립니다. 실제로 헤드리스 Chromium에서는 격리 테스트로도 커스텀 스크롤바가 전혀 렌더되지 않았습니다. 트랙(.ds-xscroll) + 썸(.ds-xscroll__thumb)을 직접 그리고 포인터 드래그를 직접 처리하는 쪽이 어느 OS에서도 동일합니다 - 가로 flex/grid 부모 아래 래퍼에는 붙지 않습니다. 바는 래퍼의 앞뒤 형제로 들어가는데, 부모가 가로 flex면 형제가 새 「열」이 되어 배치가 무너지기 때문입니다. 안전하게 건너뜁니다
- 세로 flex 부모에서는
flex: 0 0 auto가 필수였습니다. flex 아이템은 기본이flex-shrink: 1이라, 컨테이너가 꽉 차면 바가 10px → 7px로 눌려 음수 마진과 어긋났습니다(실측으로 발견) - 제외 대상: 근무 스케줄표(
.sched-grid, Table 2)와 급여 시트(.sheet-grid/.sheet-scroll) — 자체 가상 스크롤 정책이 따로 있습니다. 화면별 해제는data-ds-xscroll="off"
2026-07-20 — BI 적용 범위 결정 기록 (design/apply-BI-UIcomponents)
메모
남은 항목을 훑고 하지 않기로 한 것을 정본에 못박았습니다. 셋 다 「빠진 것」처럼 보여서, 기록해 두지 않으면 다음 사람이 되돌립니다.
- 로그인 화면은 텍스트 유지 — 가입만 BI 락업이라 비대칭이지만 의도된 것입니다. 로그인은 「어느 앱에 들어가는가」가 먼저라 앱 이름이 큰 제목을 차지하고, 가입은 「어느 서비스에 계정을 만드는가」가 먼저라 상단이 락업입니다
- hr-system 헤더는 대상이 아닙니다 — 헤더가 없는 것이 의도된 설계입니다(시트 화면을 세로로 최대한 쓰려고 상단바를 걷어냄). 「브랜드가 빠졌다」고 헤더를 새로 만들지 마세요
og:image는 썸네일 제작 전이라 보류 — 파비콘과 달리 심볼을 그대로 못 씁니다.1200×630가로 캔버스에 락업을 배치해야 해서 배경·크기·앱 이름 표기가 전부 디자인 결정입니다. 시안이 나온 뒤 착수합니다
2026-07-20 — 파비콘 전 앱 적용 + 헤더·LNB 브랜드 정본화 (design/apply-BI-UIcomponents)
추가
- 파비콘을 9개 앱 전부에 적용 — 그동안 11개 앱 중 1개에만 있어 브라우저 탭에 기본 아이콘이 떴습니다. 자산은
packages/static/brand/favicon-hereby-<패밀리>.svg하나뿐이고(앱마다 복사하지 않습니다) 심볼만 씁니다 — 파비콘 크기에서는 워드마크가 읽히지 않기 때문입니다. 직원 앱은 Works, 나머지는 Medical - 경로는 상대경로여야 합니다.
href="static/brand/…"로 걸어야 CDN(STATIC_URL)이 있으면 플러그인이 리라이트하고, 없으면 앱 base(/앱이름/) 기준으로 해소됩니다. 절대경로/static/…는 후자에서 404 납니다 — 실제 빌드로 두 경우를 모두 확인한 뒤 규칙으로 적었습니다
수정
- team-manager 헤더의 구버전 마스터 락업 교체 —
viewBox="0 0 125 32"마스터 스우시를 인라인하고 있어, admin(Medical 심볼)에서 「내부 결재」를 단독 접속하면 로고가 바뀌어 보였습니다. 게다가 그 SVG 는 그라디언트에var()를 써서, 자산이 CSS 변수 없는 곳으로 나가면 심볼이 검붉게 뭉개지고 워드마크가 사라집니다(재현 확인). 정본(icons.ts)의 Medical 락업을 꺼내 쓰도록 바꿨습니다 — 52줄 인라인 SVG 가 6줄로 줄었습니다 - LNB 브랜드의 하드코딩 제거 —
workspace-switcher.html(공용)과 admin 자체 인라인이 심볼 키와 서비스명을 문자열로 박고 있었습니다. 「공용 템플릿에서 브랜드를 하드코딩하지 않는다」를 이 PR 이 직접 명문화해 놓고 정작 이 파일이 어기고 있던 상태입니다. 둘 다$store.hereby.brandFamily·brand를 읽도록 바꿨습니다 - 직원 앱 PWA 아이콘 10종 재생성 — 기존 아이콘은 hereby BI 가 아예 아닌 다른 디자인(사원증 모양) 에 구버전 오렌지였습니다. Works 심볼로 다시 뽑고, 마스크 아이콘(
maskable)은 어떤 모양으로 잘려도 살아남도록 안전영역 62% 안에 넣었습니다.theme_color도 구버전#ea580c→ 토큰값#f66014
2026-07-20 — 가입 화면을 BI 락업으로 + 앱에서 쓰는 락업 자산 등록 (design/apply-BI-UIcomponents)
추가
icons.ts에 락업 2종 등록 —logo-lockup-hereby-medical(865×130) ·logo-lockup-hereby-works(790×130). 그동안 앱에는 심볼만 있어 락업을 쓸 수 없었습니다. 워드마크는 저장소 폰트로 path화했고(정본 4종 재현으로 검증된 생성기),viewBox로 비율만 고정해 크기는 쓰는 쪽 CSS가 정합니다- 스토어에 BI 자산 선택 축 2개 추가 —
brandFamily(이 앱의 패밀리 키) ·linkedBrandFamily(연동되는 상위 서비스). 기존brand가 사람이 읽는 표기라면 이쪽은 자산 선택용 식별자입니다
수정
- 가입 화면 상단을 글자에서 BI 락업으로 교체 —
[상위 서비스 락업]+이 앱 표기+새 계정을 만드세요. 직원 앱은hereby Medical락업 아래hereby Works가 오고, 자기 자신이 상위인 앱(hr-system)은 아래 줄을 생략합니다 — 안 그러면 같은 브랜드가 위아래로 두 번 적힙니다 - 직원 앱 가입 화면의
hereby Medical오표기 해소.RegisterForm의 브랜드 문자열 폴백(title: opts.title ?? "hereby Medical")이 인자 없이 쓰인 가입 화면에 그대로 걸려, Works 앱에 Medical이 큰 제목으로 뜨고 있었습니다. 폴백을 없애고 그 자리에 「브랜드를 글자로 박으면 다른 패밀리가 새어 나간다」를 주석으로 남겼습니다 - 강제 규칙의 「공용 템플릿 하드코딩 금지」를 글자에서 자산까지 확장했습니다
2026-07-20 — 락업 데모의 톤 폴백 버그 수정 (design/apply-BI-UIcomponents)
수정
- 배경을 다크로 바꾸면 서비스명 톤이
light가 아니라primary로 튀던 버그.dark는 어두운 배경에서 금지 조합이라 다른 톤으로 옮겨야 하는데, 데모가 무조건primary로 되돌리고 있었습니다. 패밀리 기본값이dark인 이유는 「심볼이 이미 그라디언트로 색을 지녀서 서비스명까지 오렌지면 심볼이 묻힌다」 이고 이 이유는 배경과 무관한데,primary로 튕기면 정확히 그 피하려던 상태가 됩니다. 체계 전환(setBrand)에도 같은 문제가 있어 함께 고쳤습니다 - 데모는 자산을 내려받는 곳이라 영향이 큽니다 — 다크 배경용 락업을 받으려던 사람이 의도치 않게 오렌지 버전을 받고, 파일명(
…-primary-on-dark.svg)만으로는 눈치채기 어려웠습니다
추가
- 브랜드 · BI에 「중립 톤」 개념 명시 —
dark와light는 워드마크hereby가 배경 따라 뒤집히는 것과 같은 한 짝이고,primary만 그 짝 밖에서 의도를 갖고 직접 고르는 톤입니다. 따라서 배경별 기본은 밝은 배경dark/ 어두운 배경light입니다
2026-07-20 — 브랜드 규칙을 에이전트 가드레일까지 반영 + 이메일 정정 (design/apply-BI-UIcomponents)
추가
- 「마스터 + 일반명사」 허용을 명문화 — 금지되는 건 서비스명(등록된 패밀리 브랜드)을 붙이는 것이지 뒤에 오는 모든 말이 아닙니다.
hereby System Admin·hereby Design System처럼 일반명사로 대상을 가리키는 표현은 정본이고, 구분자(·) 없이 띄어쓰기로 잇습니다. 이 문장이 없으면 다음 사람이hereby System Admin을 위반으로 보고 되돌립니다 design-tokens.md에 BI 그라디언트 hex 예외 추가 — 토큰 규칙만 읽은 에이전트가 BI 그라디언트를var()로 "고쳐서" 심볼을 검게 만드는 능동적 사고를 막습니다(데모 2종에서 실제로 났던 일). 이메일 예외도 색에만 적용되고 브랜드 표기는 규칙을 따른다는 점을 함께 못박았습니다
수정
CLAUDE.md 가드레일에 「표기」 규칙 편입. 그동안 가드레일은 락업(자산) 만 담고 있었고, 정작 이번 사고의 원인인 텍스트 표기 규칙(소문자 강제 · 저작권=마스터 · 앱 이름≠브랜드 · 자리별 기준 · 공용 템플릿 하드코딩 금지)이 통째로 빠져 있었습니다. 자산/표기 두 줄로 분리해 채웠습니다
CLAUDE.md 자신의 위반 정정 — 첫 문장이
Hereby is a multi-tenant…였습니다. 이 파일은 매 세션 자동 로드되므로 「Hereby가 정상 표기」라는 반례를 매번 주입하고 있었습니다라우터(
design-system-docs.md) 정리 — brand 행이 규칙을 4절이나 복제해 자기 원칙(「중복 = 드리프트」)을 어기고 있었고, 예언대로 이미 낡아 있었습니다(소문자·저작권 규칙 없음). 한 줄 힌트로 줄였습니다.paths:글롭에tools/**·docs/ko/design-system/**·docs/.vitepress/theme/components/**를 추가 — DS 문서·데모를 고치는 세션에 라우터가 로드되지 않던 공백을 메웠습니다이메일 7건 정정 (
email.service.ts) — 「app-wide」라던 직전 정정이 이 파일만 통째로 건너뛰어, 가입·초대·비밀번호 메일이 전부 구버전 표기로 나가고 있었습니다. 제목 3종[Hereby]→[hereby], 본문 1곳, 푸터© Hereby Platform×3 →© 2026 hereby(앱 31곳과 동일 형태). 계정 메일은 앱이 공유하므로 특정 서비스를 가리킬 수 없어 마스터가 맞습니다system-admin 로그인 부제
hereby · System Admin→hereby System Admin(구분자 제거)package.jsondescription19개 정정 — 앱 9개 →hereby Medical, 직원 앱 →hereby Works, 전 서비스 대상 도구(importer·system-admin)와 인프라 패키지 →hereby(마스터). 폐기 조합Hereby Platform도 함께 제거했습니다. 화면에 뜨지 않는 메타데이터지만, 남겨두면Hereby검색이 계속 걸려 매번 「저건 괜찮은 것」을 다시 판단해야 합니다SMS 발신 접두사 2곳 (
sms.service.ts) — 임시 비밀번호·로그인 인증번호 문자의[${organizationName || "Hereby"}]폴백. 조직명이 없을 때[Hereby]가 그대로 문자로 발송되고 있었습니다 →[hereby]. 이메일 제목과 같은 부류인데 파일이 달라 P1에서 빠져 있었습니다AI 어시스턴트 시스템 프롬프트 (
ai/prompts/system.ts) —당신은 Hereby의 HR 어시스턴트입니다. Hereby는…. 정적 문자열이 아니라 모델이 답변에서 그대로 따라 쓰는 표기라, 프롬프트가 틀리면 어시스턴트가 사용자에게 계속Hereby라고 말합니다 →hereby
메모
- 남은
Hereby는 대부분 코드 식별자(HerebyClient·HerebyTemplate·listHerebyTemplates·X-Hereby-Timestamp· 마이그레이션 클래스명)와 코드 주석이라 표기 규칙 대상이 아닙니다 - 판단이 남은 3건 — ① 시드 데이터
Hereby Demo Corporation(데모 조직 이름, 참조처는 시드 파일 2곳뿐이라 변경은 안전하지만 브랜드 표기인지 데이터인지 성격 판단 필요), ② CLI 도움말·배너(hereby CLI·=== Hereby Excel Importer ===, 개발자 대상), ③ system-admin 연동 탭 placeholderHereby production(입력 예시)
2026-07-20 — 직원 앱을 hereby Works로 통일 (design/apply-BI-UIcomponents)
추가
- 공용 템플릿용 브랜드 주입 경로 신설 —
createAlpinePlugin({ brand })→$store.hereby.brand(기본값hereby Medical).packages/components/html/의 템플릿은 8개 앱이 같은 파일을 인라인하므로 브랜드를 박아 두면 한 앱을 고치는 순간 나머지 7개가 깨집니다. 「공용 템플릿에서 브랜드를 하드코딩하지 않는다」를 브랜드 · BI의 강제 규칙(표기절)에도 추가했습니다
수정
- 직원 앱 8곳을
hereby Works로 정정 — 로그인 부제 · 공용 로딩 화면 · 「더보기」 버전 표기 ·<title>· iOS 홈화면 라벨 ·manifest(name/short_name) · CapacitorappName· 푸시 알림 제목 폴백(+push-sw.test.ts기대값) - 직원 앱은 한 앱이 자기 이름을 세 가지로 말하고 있었습니다 — 홈화면은
Hereby Works, 로딩·로그인은hereby Medical, 더보기는 다시Hereby Works. 직전 커밋이 8개 앱 로그인 부제를 일괄로hereby Medical로 맞췄는데, 직원 앱은 Works 패밀리라 그 정정이 이 앱에서만 오답이었던 것이 원인입니다 - 로딩 화면은 공용 파일이라 문자열 치환이 불가능해 위 주입 경로로 바꿨습니다. 나머지 7개 앱은 코드 변경 없이 기본값
hereby Medical을 그대로 받습니다(빌드 산출물로 확인)
메모
manifest·appName은 앱을 다시 설치해야 반영됩니다 — 홈화면 아이콘 라벨·앱서랍·런처 이름은 설치 시점에 굳습니다. 나머지(로딩·로그인·더보기·탭 제목)는 배포 즉시 반영됩니다- 검증: 직원 앱 로그인 화면에 「직원 앱」 +
hereby Works+© 2026 hereby, admin 로딩 화면에hereby Medical— 실제 렌더로 확인.push-sw테스트 4/4, 전체 빌드 21/21 green
2026-07-20 — hereby Works를 세 번째 패밀리로 등록 (design/apply-BI-UIcomponents)
추가
브랜드 · BI에 패밀리
hereby Works등록. 직전 항목이 「미결 —Works가 별개 제품명인지 판단 필요」로 남겼던 것의 결론입니다: Works는 패밀리이고, Medical과 연동되는 직원 앱입니다. 이로써 패밀리는 Medical · Sign · Works 셋이 됐고, 「등록된 것은 둘뿐」이라 못박아 둔 서술 3곳(강제 규칙 2곳 + 경고 박스)을 전부 갱신했습니다Works 심볼 확정. 그라디언트가 패밀리 정본(
#FE4D43→#FF7732→#FFAF00)과 stop·offset까지 일치하고, 그라디언트 벡터도 Medical과 동일합니다(박스 오프셋(1, 6)을 더하면 소수점까지 같은 값). 즉 패밀리 규격을 그대로 따른 자산입니다Figma export의
id를 그대로 쓰지 말라는 규칙 추가. export는paint0_linear_…·clip0_…같은 일련번호id를 다는데,id는 문서 전역이라 다른 BI 자산과 충돌합니다(실제로 났던 버그). 등록할 때lnb-hereby-<서비스>-grad로 바꾸고, 클립 사각형이 viewBox와 같은 크기면 아무것도 자르지 않으므로clipPath째 지웁니다국문 서비스명 「웍스」 확정 —
메디컬·사인에 이어 세 번째 국문 정본입니다. 조판 규격표·translate="no"규칙·서비스명 톤 등 국문 서비스명을 열거하던 자리 6곳에 반영했습니다Works 락업(영문·국문) export 수령 + 검증. 조판이 정본 그리드 위에 있음을 교차검증했습니다 — export의
hereby→ 서비스명 간격146.55 − 40.9497 = 105.6003이, 정본 규격(486 − 134 = 352@font-size 100)을font-size 30으로 환산한105.6과 소수점까지 일치합니다락업 폭 산출 규칙을 문서화(비율은 계산으로 구합니다) —
viewBox 폭 = 486 + 서비스명의 커닝 적용 advance(@ font-size 100), 올림. 저장소에 폰트가 있으므로 비율은 계산으로 구하는 값이고 Figma 프레임에서 읽어오는 값이 아닙니다. 이 규칙은 기존 정본 4종(865·746·702·659)을 전부 정확히 재현해 검증했습니다Works 비율 확정 —
hereby Works790 × 130,hereby 웍스659 × 130. 국문이hereby 사인과 같은659인 것은 한글 글리프 advance가 동일해 2글자 국문 서비스명은 항상 같은 폭이기 때문입니다path 정본도 직접 생성 가능함을 확인·문서화. 같은 절차로 정본 path 5종(
hereby·Medical·메디컬·Sign·사인)을 오차0.00으로 재현해 생성기를 검증했습니다. 생성 시 지킬 값(베이스라인100.5· 서비스명x=486· 커닝 적용 · Pretendard는wght=700인스턴싱)도 함께 적었습니다Works 심볼을
icons.ts에 등록 —logo-hereby-works. Medical·Sign과 같은 규약(viewBox="1 6 28 28")을 쓰고, Figma export의 일련번호id는lnb-hereby-works-grad로 갈랐습니다. 함께 딸려온clipPath는 클립 사각형이 심볼 박스와 같아 상단을0.001단위만 자르는 no-op(24px 렌더 기준0.0009px)이라 제거했습니다데모(
DemoBrandLogo.vue)에 Works 락업 2종 추가 — 서비스 선택기에Works가 붙고, 영문·국문 전환·톤·배경·심볼/워드마크 토글·SVG 내보내기가 모두 동작합니다(파일명hereby-bi-works-en-dark-on-white.svg형태로 자동 파생). 심볼은 데모 좌표계(x2~95/ y18.5~111.5)로 정렬했습니다
메모
- 디자인 재요청 없이 완료했습니다. 국문 서비스명 · 비율 · path를 모두 저장소의 폰트로 산출했습니다
- 생성 path가 디자인 export와 동등함을 픽셀로 확인 — 라이브 텍스트 ↔ path 차이가 Works
1.06%(영문)·1.17%(국문)로 기존 정본 Medical1.04%· Sign1.00%와 같은 수준입니다(전부 글자 경계 안티에일리어싱). 대조군 없이 절대값만 보면 오판하므로 기존 정본을 같은 방법으로 함께 재는 것이 핵심이었습니다 - 남은 것은 자산이 아니라 적용입니다 — 직원 앱이
hereby Medical(로그인 부제·공용 로딩)과 옛 대문자Hereby Works(<title>·manifest·appName·버전 표기)를 섞어 쓰는 상태. 공용loading.html은 8개 앱 공유라 앱별 파라미터화가 필요합니다 - Figma 프레임 폭을 비율로 쓰지 말 것을 danger로 명시 — 받은 export는 영문·국문이 똑같이
258 × 40인 고정 프레임이라 우측 여백이 각각26.4/59.6남습니다. 그대로 옮기면 국문 락업에 60 가까운 빈 공간이 붙습니다 - 커닝을 반드시 적용해야 합니다 — 끄면
Medical이384.00(정본379),hereby가338.30(정본328.20)으로 어긋납니다. 브라우저에서file://로 woff2를 로드해 재려다 폰트가 폴백되면 값이 통째로 틀리므로, 측정은 폰트 파일에서 직접 해야 합니다(이 작업에서 실제로 한 번 잘못 재고 정정했습니다) - 받은 export를 그대로 쓰면 3가지가 깨진다는 점을 문서에 명시 — ①
font-family="Pretendard"(등록명은Pretendard Variable, 정본이 경고해 둔 함정을 그대로 밟음), ②font-weight="bold"(정본 표기는700), ③ 영문·국문 두 파일이 같은id(paint0_linear_131_108·clip0_131_108)를 써서 한 페이지에 둘 다 넣으면 그라디언트가 충돌 - 직원 앱이 아직 Medical로 표기돼 있습니다. 직전 항목에서 8개 앱 로그인 부제를 일괄로
hereby Medical로 맞췄는데, 직원 앱은 Works이므로 그 정정이 이 앱 한 곳에서는 오답이었습니다. 로딩 화면은 8개 앱이 공유하는loading.html에 하드코딩돼 있어 문자열만 바꾸면 나머지 7개가 깨집니다 — 앱별 파라미터화가 필요합니다 - 「아직 정리되지 않은 것」의 사실오류 3건 정정 — ①
packages/static/brand/자산은 「8개 중 7개 미사용」이 아니라 8개 전부 미사용(랜딩은.svg를 참조하지 않고 path를 인라인), ②logo-hereby-sign은 「아무 화면도 안 씀」이 아니라 랜딩 데모가 심볼 path를 인라인해 이미 렌더 중(미사용인 것은icons.ts엔트리), ③ team-manager 헤더에 남은125×32구버전 마스터 락업을 별도 항목으로 분리(화면 주체가 Medical인데 마스터를 쓰는 패밀리 규칙 위반)
2026-07-20 — 브랜드 텍스트 표기 규칙 신설 + 전역 정정 (design/apply-BI-UIcomponents)
추가
- 브랜드 · BI의 「규칙 (강제)」에
표기 (락업이 아닌 일반 텍스트)절 신설. 그동안 강제 규칙은 락업(자산) 만 다뤘고, 로그인 제목·푸터처럼 브랜드명을 글자로 적는 자리에는 규칙이 없었습니다. 그 공백에서Hereby Admin·Hereby Inventory·Hereby Platform같은 마스터+서비스명 조합이 8개 앱에 퍼졌습니다 — 정작 이 조합은 락업 규칙이 이미 금지한 형태입니다 - 자리별 표기 기준을 표로 명시 — 제품 화면(로그인·로딩) =
hereby Medical/ 법인·플랫폼(©·계약서·공문) =hereby/ 전 서비스 대상 내부 도구 =hereby. 락업과 같은 기준(그 화면의 주체가 누구인가)을 텍스트에도 적용합니다 - 「© 문구는 대문자 예외」 통념 폐기. 문서에 근거가 없던 구전 규칙이었고, 저작권자는 개별 서비스가 아니라 플랫폼이므로
© 2026 hereby가 정본입니다
수정
- 로그인·가입 화면 8개 앱 전부 정정 — 제목은 i18n한 앱 이름(
nav.admin→ 「관리자」), 부제는hereby Medical.Hereby Admin·Hereby General Affairs·Hereby Inventory·Hereby Internal Approval이 전부 사라졌습니다.LoginForm.ts·RegisterForm.ts의 폴백"Hereby"도hereby Medical로 교체 - © 푸터 30곳 →
© 2026 hereby(8개 앱의 signin/signup/forgot-password/change-password + 랜딩). 서비스명이던Platform도 뗐습니다 - 공용 로딩 화면·재고 대시보드 →
hereby Medical/ system-admin(전 조직 프로비저닝 내부 도구) →hereby · System Admin/Hereby Sign→hereby Sign(등록된 패밀리, 대소문자만 정정) - i18n 키 3종 추가(ko·en) —
nav.admin·nav.employee_app·nav.module_manager. admin 로그인 제목을 하드코딩 대신 i18n으로 넣으려니 키가 없었습니다
메모
- 남은 미결: 직원 앱 하단의
Hereby Works v1.0.0—hereby Works는 등록된 패밀리가 아니라(Medical·Sign 둘뿐) 별개 제품명인지 판단이 필요해 손대지 않았습니다
2026-07-20 — LNB 브랜드를 패밀리(hereby Medical)로 전환 (design/apply-BI-UIcomponents)
수정
- LNB 헤더 심볼을 마스터 스우시 → 패밀리 Medical 심볼로 교체 —
iconFor('logo-hereby')→iconFor('logo-hereby-medical'). 「그 화면의 주체가 누구인가」 규칙에 따라, admin·총무·경영 대시보드 워크스페이스의 주체는 hereby 제품군 전체가 아니라 Medical 서비스 자신입니다. 적용처는 workspace-switcher.html(공용 파셜 — 총무·경영이 include)과 admin의 인라인.ws-brand두 곳 - 브랜드 라벨
Hereby→hereby Medical. 소문자 표기가 정본입니다(hereby는 영문 고유명사). 이에 맞춰.ws-trigger-label의text-transform: uppercase를 삭제했습니다 — 남겨두면HEREBY MEDICAL로 렌더돼 표기 규칙을 깹니다. 대문자 조판용이던letter-spacing: 0.04em도 함께 제거하고, 두 단어로 길어진 만큼nowrap+ellipsis가드를 넣었습니다 - docs 데모 2종의 인라인 심볼 동기화 — DemoLnbSidebar.vue · DemoWorkspaceSwitcher.vue. 이 과정에서 두 데모가 그라디언트
stop-color에var(--color-orange-400/yellow-400)을 쓰던 토큰 규칙 위반도 hex로 정정했습니다(BI 그라디언트는 hex 하드코딩이 정본 — CSS 변수가 없는 곳에서 심볼이 검게 렌더되므로). 그라디언트id는 문서 전역이라 데모별로 분리(demo-lnb-…/demo-ws-…)
메모
- 이 자리는 BI 락업이 아닙니다 — 「패밀리 심볼 + 텍스트 서비스명」입니다. 락업은 비율 고정(
865×130)이라 최소 높이 24px에서 폭이 160px인데, 208px LNB에서 브랜드 가용 폭은 132px입니다(.ds-lnb좌우 패딩 24 + 접기 토글 24 + gap 8 +.ws-brand좌우 패딩 20 차감). 우겨넣으면 높이가 19.8px로 떨어져 최소 높이 규칙 위반이고, 높이를 지키면 토글을 밀어냅니다. 그래서 심볼만 패밀리 정본을 쓰고 서비스명은 일반 텍스트로 뒀습니다. LNB 폭이 넓어지면 락업 승격을 재검토하세요 - 이로써
logo-hereby-medical이 첫 실사용처를 얻었습니다.logo-hereby-sign은 여전히 사용처 0이고, 마스터 심볼은 화면 사용처 0(락업 데모·내보내기 전용)이 되었습니다 - 남은 인접 부채: loading.html의
Hereby대문자 표기,WorkspaceSwitcher.tstriggerLabel의"Hereby"폴백 — 둘 다 LNB 밖이라 이번 범위에서 제외
2026-07-14 — orange 유틸리티 강제 심 제거 (「이름 ≠ 렌더 값」 트랩 해소) (design/landing-update)
수정
- design-system.css의 orange 유틸 강제 심 32규칙(전부
!important) 삭제 — blue→orange 리맵 시대의 잔재로,.text-orange-500이orange-600(#d3440e)으로 렌더되는 등 클래스 이름과 실제 값이 달랐다(랜딩 히어로 타이틀이 챕터 라벨·버튼과 다른 주황으로 보인 원인). 함께 삭제된 "Strong pass" 화석 4규칙 중.text-orange-600/700 → --ds-color-focus는 파란색을 가리키던 부비트랩(뒤 블록에 가려 미발현). 이제 Tailwind 유틸리티가@theme토큰을 직접 참조 → 이름 = 값 - 사용처 전수를 실제 렌더 값 기준으로 기계적 리네임(시각 변화 0) — 약 90파일:
text-orange-500/700→600·text-orange-800→700·text-orange-900→800·bg-orange-600→500·bg-orange-700/800/900 → 한 단계씩 하향·border-orange-600→500·hover:bg/text-orange-700→600·focus:ring-orange-400→300. 리네임 제외(심 미적용이라 원래 진짜 값): 슬래시 투명도(bg-orange-600/50) ·hover:text-orange-900·focus:border-orange-500등 기타 변형 접두사 - 랜딩의
text-orange-50012곳은 리네임 대신text-primary채택 — 디스플레이 타이틀 강조를 진짜 브랜드 주황(#f66014)으로 복원(의도된 시각 변경, 별도 승인)
문서
- Buttons · button-system-spec — 레거시 버튼 예시 표기(
bg-orange-600 px-3 …)를 새 이름(bg-orange-500 …)으로 동기화
메모
- 공유 DS의
!important부채 32건 감소. 남은 인접 부채:.text-red-600/700 → --ds-color-danger·.text-green-600/700 → --ds-color-success·.rounded/.rounded-lg강제(별도 작업)
2026-07-14 — 패밀리 BI(hereby Medical · hereby Sign) 등록
추가
패밀리 BI 체계 신설. 그동안 BI는 마스터 하나뿐이었고
hereby Medical은 "마스터 심볼 + 오렌지 도메인 워드"인 도메인 락업으로만 정의돼 있었습니다. 이번에 패밀리 사이트는 전용 심볼을 가진다는 것이 확정되어(Medical=십자, Sign=서명 획), 브랜드 · BI에 마스터/패밀리 두 체계를 세웠습니다. 락업은 3종 → 7종(마스터 3 + 패밀리 4)선택 규칙 — "그 화면의 주체가 누구인가". 같은
hereby Medical을 두 가지로 그릴 수 있게 되었으므로 선택 규칙이 필요합니다: 패밀리 사이트 자신이 주체인 자리(헤더·파비콘·앱 아이콘·로그인) → 패밀리 락업, hereby가 제품군 전체를 거느리는 자리(통합 랜딩·계약서·공문) → 마스터 락업. 도메인 락업은 폐기하지 않고 둘 다 정본으로 유지합니다패밀리 심볼 2종을
icons.ts에 등록 —logo-hereby-medical·logo-hereby-sign. 마스터 심볼과 같은 박스(x 2..95 / y 18.5..111.5)에 정렬해, 체계를 바꿔도 워드마크가 제자리에 있습니다. 아직 사용처는 0이며, 패밀리 사이트가 생길 때 붙입니다패밀리 워드 path 정본 확보 —
Sign(Geist SemiBold 600)·사인·메디컬(Pretendard Bold 700) 아웃라인을 폰트 파일에서 직접 생성. 이로써 7종 전부 path 폴백·path 내보내기가 가능합니다패밀리는 서비스명이 필수입니다. 패밀리 심볼 +
hereby만 쓰는 락업은 없습니다 — 어느 서비스인지 사라져 "마스터의 심볼이 바뀐 것"처럼 읽히기 때문입니다. 서비스명을 뗀 기본 락업(hereby)은 마스터에만 있습니다(심볼만 쓰는 파비콘·앱 아이콘은 예외 — 워드마크 자체가 없으므로)데모를 체계별로 분리(DemoBrandLogo.vue) — 두 체계는 규칙이 다르므로(특히 서비스명 필수 여부) 한 컨트롤에 섞지 않고
systemprop으로 마스터 영역 / 패밀리 영역을 나눠 심었습니다. 마스터 데모는서비스명 = 없음을 고를 수 있고, 패밀리 데모에는 「없음」이 아예 없습니다. 패밀리 데모에서Medical↔Sign을 바꾸면 심볼과 그라디언트가 함께 바뀌고, 내보내는 SVG의 그라디언트도 따라갑니다심볼만 내보내기 신설 (파비콘·앱 아이콘). 문서는 「24px 미만·파비콘·앱 아이콘 = 심볼만」을 규정해 놓고 정작 그 구성을 만들 수단이 없었습니다 — 심볼 체크박스는 심볼을 끄는 용도라 워드마크만 남았고, 그래서 락업을 받아 디자인 툴에서 잘라 써야 했습니다(자르는 순간 심볼의 크기·여백이 정본에서 벗어납니다). 데모에 「워드마크」 토글을 추가해, 끄면 정사각 심볼(
viewBox 2 18.5 93 93)이 그대로 내려받아집니다(hereby-bi-<체계>-symbol.svg). 심볼과 워드마크를 동시에 끌 수는 없고(체크박스가 잠김), 심볼만일 때는 최소 24px 경고를 띄우지 않습니다(그 하한을 벗어나는 방법이 바로 심볼 단독이므로)내보내는 SVG의 그라디언트
id를 체계별로 분리했습니다(bi-grad-master/-medical/-sign). 종전에는 모든 구성이bi-grad하나를 공유해서, 받은 사람이 마스터 락업과 패밀리 락업을 한 페이지에 인라인으로 붙이면 뒤엣것이 앞엣것의 그라디언트로 칠해졌습니다BI 심볼의 그라디언트 stop을
icons.ts에서도 hex로 통일했습니다. 마스터 심볼이var(--color-orange-400)를 쓰고 있었는데, 이는 이 페이지가 규정한 그라디언트 hex 예외 규칙과 어긋납니다(CSS 변수가 없는 곳에서 심볼이 검게 렌더). 값은 토큰과 동일해 시각 변화는 없습니다국문 서비스명에도
translate="no". 「메디컬」이 브라우저 자동번역으로 바뀌면 Pretendard Bold 700 자리에 폴백 서체가 들어와 락업이 깨집니다 — 언어별 정본은 우리가 고르는 것이지 브라우저가 바꾸는 것이 아닙니다내보내는 파일명이 구성을 담습니다(파일명 규칙). 종전에는 배경이 파일명에 없어 내용이 다른 파일이 같은 이름으로 덮어써졌습니다 — 워드마크 색이 배경에서 갈리는데(다크면 흰색, 아니면 검정)
hereby-bi-master.svg하나로 나왔습니다. 이제hereby-bi-medical-en-dark-on-white.svg처럼 체계·언어·심볼/워드마크 유무·톤·배경이 모두 들어갑니다. 배경에on-을 붙인 것은 톤(dark)과 배경(white)이 뒤섞여 읽히는 것을 막기 위해서입니다.라이브 텍스트/path모드는 일부러 넣지 않았습니다 — 내보내기는 언제나 path라 모드를 바꿔도 파일이 한 바이트도 안 바뀌고(md5 동일 확인), 이름에livetext를 넣으면 path를 담은 파일이 스스로를 라이브 텍스트라 말하게 됩니다강제 규칙 정본을 최종 점검했습니다. 본문에만 있고 「규칙 (강제)」 접이 섹션에 빠져 있던 3건을 편입 — ① 국문 서비스명에도
translate="no", ② 파비콘·앱 아이콘은 「워드마크」를 꺼서 심볼만 받고, 락업을 잘라 쓰지 않는다, ③ SVG 그라디언트id는 문서 전역이라 한 페이지에 BI 자산 둘 이상을 인라인하면id가 겹쳐선 안 된다(실제로 났던 버그). 라우터(design-system-docs.md)와 CLAUDE.md의 한 줄 가드레일에도 "패밀리는 심볼·그라디언트가 다르다" 를 명시했습니다 — 이번 작업에서 가장 놓치기 쉬웠던 지점입니다
변경 (⚠️ 기존 규칙과 달라진 것)
- ⚠️ 도메인 락업을 폐기했습니다. 마스터는
hereby하나뿐입니다. 종전에는 마스터 심볼에 서비스명을 덧붙인 도메인 락업(hereby Medical오렌지 워드 /hereby 메디컬)이 함께 정본이었으나, 서비스명과 영문/국문 축은 전부 패밀리의 것으로 정리했습니다.hereby는 영문 고유명사라 국문 마스터도 없습니다. 락업은 7종 → 5종(마스터 1 + 패밀리 4). 마스터 데모에서 서비스명·언어 선택기가 사라졌고, 죽은 path 상수(MEDICAL_D·MEDICAL_KO_D, x=473 앵커)도 제거했습니다 - 이에 따라 서비스명 색 3톤(primary·dark·light)은 패밀리 전용이 되었고, 기본값은
dark하나입니다(종전에는 "마스터=primary / 패밀리=dark"로 체계마다 달랐습니다) - 그라디언트가 두 벌이 되었습니다. 마스터
#F8884F→#FF4141→#F6BC3D(값이 토큰과 동일, CSS 각도 290°), 패밀리#FE4D43→#FF7732→#FFAF00(대응 토큰 없는 전용 색, 314°). 섞어 쓰면 다른 마크가 됩니다. 종래 "BI 그라디언트 = 토큰과 값이 같다"는 서술은 이제 마스터에만 해당합니다 - 서비스명 색의 기본값이 체계마다 다릅니다 — 마스터 도메인 워드 =
primary(오렌지), 패밀리 워드 =dark. 패밀리는 심볼이 이미 그라디언트로 색을 지니므로 워드까지 오렌지면 색이 겹칩니다. 세 톤(primary·dark·light)이 모두 정본인 것은 그대로이고, 배경×톤 금지 조합도 그대로입니다 - 문서의 「도메인 워드」 표현을 **「서비스명」**으로 통일했습니다(마스터·패밀리 양쪽을 가리키므로)
검증
- 아웃라인 생성 파이프라인을 먼저 검증했습니다. 이미 정본이 있는
Medical·hereby를 폰트 파일에서 다시 뽑아 기존 값과 대조 → 좌표가 완전 일치(481 · 29.5 · 498.5 · 518.1 …). 그 다음에야 같은 방법으로Sign·사인을 생성했습니다 - 생성한 path ↔ 라이브 텍스트 픽셀 비교 → 심볼 0.00%(정확히 일치), 워드는 글자 경계의 안티에일리어싱만. 정본과 바이트 수준으로 같은
hereby가 동일한 오차 패턴을 보이는 것을 기준선으로 삼아 판별했습니다 - Sign 심볼의
clipPath가 형태를 자르는지 확인 — 래스터 비교로는 902px 차이가 나 "자른다"고 오판할 뻔했으나(clip 레이어가 만든 안티에일리어싱), 경로의 실제 bounds가(1.0, 6.0002, 29.0, 34.0002)로 clip 사각형과 정확히 일치함을 기하학적으로 확인 → Figma 상용구로 판정하고 단일 path로 구웠습니다 - 패밀리 락업이 마스터보다 넓은 이유(
865vs852)를 규명 — 심볼/폰트 비율은 동일(0.930 vs 0.933)하고hereby와 서비스명 사이 간격만 2.2배(0.108em → 0.238em) 넓습니다. 디자인 의도로 보고 보존했습니다 - ⚠️ SVG 그라디언트
id는 문서 전역입니다. 데모를 마스터/패밀리 둘로 나누자 두 인스턴스가 같은id를 정의했고, 브라우저는 문서상 먼저 나온 정의를 써서 패밀리 심볼이 마스터 그라디언트로 칠해졌습니다. 형태(검정/흰색)만 비교하던 검증은 이걸 못 잡았고 — 색까지 비교해서야 드러났습니다.id를 체계별로 분리해 해결했고, 정규화한 패밀리 그라디언트가 전달받은 원본 SVG와 픽셀 색 평균 차이 0.04/255(11만 px)로 일치함을 확인했습니다
2026-07-13 — 브랜드(BI) Foundations 신설 + Geist 브랜드 폰트 도입
규칙 정본 편입
- BI 페이지를 「docs = 규칙 정본」 체계에 편입. 상단에
규칙 (강제) · 코딩 에이전트용접이 섹션을 신설해 조판(Geist 600 / Pretendard 700) · 폰트 실패 시 path 폴백 · 번역 금지 · 색과 배경×톤 금지 조합 · 그라디언트 hex 예외 · 형태 제약을 한곳에 모았습니다. 본문의 「하지 말 것」 절은 중복(=드리프트) 이라 제거하고 접이 섹션을 가리키게 했습니다 - 라우터(design-system-docs.md)에는 한 줄만 추가했습니다(규칙 내용 복제 없음). CLAUDE.md의 Foundations 열거에도 brand/BI를 편입
추가
- 브랜드 · BI 페이지 신설. 그동안 BI는 문서에 정의 자체가 없었고, 코드에서도 심볼이
icons.ts·랜딩 자산·team-manager 인라인 SVG 세 곳에 중복돼 있었습니다. Figma 정본(Hearby-med Design system)을 근거로 심볼·워드마크·락업 3종(기본471×130/ 영문 도메인hereby Medical852×130/ 국문 도메인hereby 메디컬733×130)을 정의하고, 두 가지 정본(path / 라이브 텍스트) 과 사용처 기준을 세웠습니다 - 조판 규격 확정 —
hereby·Medical은 Geist SemiBold 600,메디컬은 Pretendard Bold 700, 자간 0. 색은 워드마크--color-neutral-900(#1B1B1B) · 도메인 워드--color-orange-500(#F66014) — 세 색 모두 기존 토큰과 정확히 일치해 새 색을 만들지 않았습니다 - 폰트 로드 실패 시 path로 대체하는 것이 규격. 라이브 텍스트는 "폰트가 도착했을 때만 올라가는 향상"이고 기본값은 항상 path입니다.
document.fonts.load()+check()가 통과했을 때만.brand-font-ready를 붙여 텍스트로 교체하고, 실패하면 path가 그대로 남습니다 — 브랜드 폰트를 못 받은 사용자에게 다른 서체의 워드마크를 보여주는 일은 없어야 하기 때문입니다. 구현 코드는 문서에 포함 - 구성 변형 2종 정의 — 심볼 on/off(워드마크 단독 사용 / 24px 미만이면 반대로 심볼 단독), 도메인 워드 색 3종(
primary--color-orange-500·dark--color-neutral-900·light흰색)을 모두 정본으로 명시. 워드마크hereby는 배경에 따라 dark/light만 오가고, 세 톤을 오가는 것은 도메인 워드입니다 - 배경 × 도메인 톤 조합 제약 — 배경에 묻히는 조합은 금지입니다: 밝은 배경(화이트·뉴트럴)에
light❌, 어두운 배경에dark❌.primary는 모든 배경에서 안전합니다. 데모에서도 금지 조합은 버튼이 잠기고, 배경을 바꿔 현재 톤이 금지 조합이 되면primary로 자동 보정됩니다 - SVG 내보내기 — 항상 path. 데모 하단에서 지금 보고 있는 구성(락업 · 심볼 유무 · 톤)을 다운로드/코드 복사할 수 있습니다. 화면에서 라이브 텍스트를 보고 있어도 내보내지는 파일은 언제나 path입니다 — 배포된 자산이
<text>를 품고 있으면 받는 쪽 폰트 환경에 따라 워드마크가 다른 서체로 그려질 수 있기 때문입니다. 색도 hex로 실체화되어var()가 남지 않습니다(CSS 변수가 없는 곳에서 검게 렌더되는 것을 막음). 즉 라이브 텍스트는 우리 코드 안에서만, 밖으로 나가는 자산은 path로 통일 - 국문 도메인 락업의 path 정본 확보 —
메디컬을 Pretendard Bold 700 아웃라인으로 생성(Figma와 동일 좌표x=473, y=100.5, 100px). 레포의PretendardVariable.woff2@700 렌더와 픽셀 비교해 강한 차이 0.151%(전부 안티에일리어싱)로 일치 확인. advance width 259.3 → 끝 x가 732.3으로 Figma 캔버스733과 맞아떨어져 동일 글자꼴임이 교차 검증됨. 이로써 세 락업 모두 path 폴백·path 내보내기가 가능해졌습니다 - BI 색 정책 — 평면 색은 토큰, 그라디언트는 예외. 워드마크·도메인 워드는 값이 일치하는 기존 토큰(
--color-neutral-900/--color-orange-500)에 맞춥니다. 반면 심볼의 3-stop 그라디언트는 hex 하드코딩을 유지합니다 — BI 자산은 CSS 변수가 없는 컨텍스트(이메일 HTML·단독 SVG 파일·외부 배포본)에서도 열려야 하는데,var()로 두면 그런 곳에서 심볼이 검게 렌더되기 때문입니다. 값 자체는 토큰과 동일하므로, 어긋나서가 아니라 이식성 때문에 두는 예외입니다 - 워드마크 번역·현지화 금지 규칙.
hereby는 영문 고유명사이므로 브라우저 자동번역·접속 지역에 따라 바뀌면 안 됩니다 → 라이브 텍스트로 쓸 때translate="no"+lang="en"필수, 제품 UI 기본값은 번역이 원천 불가능한 path - 브랜드 폰트 Geist SemiBold 도입(Geist-SemiBold.woff2 · SIL OFL, 46KB).
--font-brand토큰 신설(tokens.css:root+design-system.css@theme→ Tailwindfont-brand유틸 자동 생성).@font-face는font-display: block— 기본값swap이면 폴백 서체가 먼저 보였다 바뀌는데, 워드마크에서 그건 느린 렌더가 아니라 브랜드 사고이기 때문입니다. 폰트는 실제로 워드마크를 그리는 화면에서만 내려받습니다(@font-face는 지연 로드) - 라이브 데모(DemoBrandLogo.vue) — 락업 3종 × path ↔ 라이브 텍스트 토글, 폰트 로드 실패 재현, 크기 슬라이더(최소 24px 경고), 보호 영역, 배경 3종
검증
- path 버전과 라이브 텍스트(Geist SemiBold) 버전을 픽셀 비교 → 형태 차이 0.18%, 전부 글자 경계의 안티에일리어싱. 두 정본은 같아 보인다는 것을 측정으로 확인
- Figma 그라디언트 3-stop이 기존 토큰과 일치함을 확인 —
#F8884F=--color-orange-400,#FF4141=--color-hr-red-400,#F6BC3D=--color-yellow-400. 벡터를 CSS 각도로 환산하면 290° 로, 기존--gradient-logo토큰과 같습니다(그동안 사용처 0인 채 방치돼 있던 토큰이 사실 BI 그라디언트였음) - Figma의 SVG export를 그대로 쓰면 국문이 깨진다는 점을 확인 — export에는
font-family="Pretendard"로 적히지만 저장소에 등록된 패밀리는Pretendard Variable이라 폴백됩니다. 문서에 교정 방법을 명시
남은 일 (이번 변경에 포함되지 않음)
packages/static/brand/자산 8개 중 7개 미사용, 유일 사용처인 랜딩hereby-wordmark.svg는 구버전 락업(신규 BI와 비율 상이) → 자산 정본화 필요icons.ts의logo-hereby는 stop이 토큰·hex 혼용 상태 → hex로 통일 필요(그라디언트 예외 정책에 맞춤)- admin 등 대부분 앱에 파비콘·og:image 부재
- 다크 배경용 반전 정본 부재 (현재 제공 자산은 라이트 모드 한 벌)
2026-07-13 — 버튼 모서리(radius) 축 신설 (ds-r-* · --ds-btn-radius) (design/btn-radius)
신규
--ds-btn-radius축 +.ds-r-4/-8/-12/-16/-999모디파이어(design-system.css) — 버튼 모서리를 변형·색·크기와 독립된 축으로 분리. 기본은 종전대로 4px, 클래스를 얹었을 때만 8/12/16/999(알약)로 바뀐다. 굵기 축(--ds-btn-weight·.ds-fw-*)과 동일한 구조: 버튼의border-radius선언이 변수를 읽게 만들어 새!important없이 override가 성립한다(기존 4px 강제 3규칙 —button:not([class*="bg-"])…·button[class*="border"]·button[class*="bg-"]— 의 값을var(--ds-btn-radius, 4px)로 전환). 변수를 읽지 않는 버튼 외 요소는 무영향. 원형 아이콘 버튼(--icon/--circle)은 999px 고정이라 축에서 제외--radius-12: 12px토큰 — 8↔16 중간 단계. 2배수 progression의 예외로 정식 채택(이전의 "신설 취소" 결정을 뒤집음).rounded-12유틸도 함께 생성된다. 덕분에 SubTab이 12px 요청을 토큰 부재로 8px로 내려 채택했던 제약도 해소됨(시각 변경 여부는 별도 결정)- radius 단일 출처화 —
design-system.css가@import하는tokens.css가2·4·6·8·10·12·16이라는 별도 스케일을 갖고 있어@theme스케일과 어긋나 있었다. 사용처 0건이던--radius-6/10/12를 제거해 radius 정의를@theme한 곳으로 모았다(6px·10px는 의미 토큰--ds-radius-sm/--ds-radius-lg로 계속 참조)
문서
- Buttons — 「모서리(radius)」 섹션 신설(클래스 표·컨테이너 상속·아이콘 버튼 제외), 클래스 API 표에 모서리 축 행 추가. 버튼 탐색기(DemoButtonExplorer.vue)에 모서리 컨트롤(기본 4 · 8 · 12 · 16 · 999) 추가 — 색 × 크기 전 조합에 실시간 적용
- 모서리 — primitive 표에
--radius-12행 추가 + 「radius의 단일 출처는 이 스케일 하나」 명시. 트랩 ①의 「커스텀 radius는<div role="button">으로 우회」 안내를 정식 축(ds-r-*) 안내로 교체(규칙 블록 + 본문), 강제 제외 명단을 실제 셀렉터와 일치하도록 보정(.ds-menu__item·.icon-btn·.ds-btn--icon·.ds-btn--circle·.org-tree__action-btn누락분 추가), 로드맵·변경 이력 갱신. 버튼 기본 모서리(4px) 유지 여부와 SubTab 12px 복원 여부를 검토 항목으로 등록 - Sub-tab — 「12px 토큰 부재로 8px 채택」 메모에 토큰 신설로 선행 조건이 해소됐음을 반영(현재 8px 유지)
결정
- 버튼 기본 모서리 =
4px유지 확정 — 탐색기에서 8/12/16/999를 비교한 뒤 내린 결정. 기본값은 그대로 두고, 다른 모서리가 필요한 버튼에만ds-r-*축을 얹는다. 기본값 변경 제안은 다시 열지 않는다 - SubTab radius =
8px현황 유지 확정 —--radius-12신설로 "토큰 부재" 제약은 사라졌으나, 12px 상향은 시각 변경이라 현행 유지. 항목을 닫는다(재개하려면 디자인 재검토 선행)
2026-07-07 — 표·스케줄러·툴팁·필터 DS 정렬 문서화 + 메모 마커 코너 이동 (design/adjust-table)
수정
- 근무 스케줄표 셀 메모 마커(
.memo-corner)를 우상단 → 좌상단으로 이동(admin main.css). 희망근무 보기(prefShow)·출근현황 보기(showAttendance)는 독립 토글이라 함께 켤 수 있는데, 그러면 메모(우상단 삼각형)와 출결 배지(.att-badge, 우상단 원형)가 같은 코너에서 겹쳤음 → 메모를 좌상단으로 옮겨 세 표식이 각기 다른 코너(좌상=메모 / 우상=출결 / 우하=희망근무.pref-corner)를 차지. 삼각형 방향(빗변 우상→좌하)·주석도 갱신. admin 빌드 green - 툴팁
topplacement도 상단 잘림 시 아래로 flip 추가(tooltip.ts · design-system.css.ds-tooltip[data-placement="top"][data-flip="down"]). 짧은 임베드 iframe(admin 안 team-manager/hr-system) 상단의 아이콘 버튼에서 툴팁이 프레임 위로 잘리던 문제 해결. 싱글톤 재사용 요소라show()가 매번data-flip을 선제거 → 직전 flip 잔재(뒤집힌 화살표·오프셋) 누수도 함께 수정
문서
- Tooltip —
top도 flip 반영(placement 표·동작 원리 flip 초기화·collision flip 항목·로드맵·변경이력) - Data table — 「숫자·식별자 표기」(정렬 열
tabular-nums· 식별자font-mono금지, 근거는 타이포그래피) + 「빈 상태(<tbody>안colspan행)」 스펙 신설. 자격유형 표(admin 설정)·공지 표(총무)·문서관리(team-manager)를 공유 스켈레톤으로 마이그레이션함을 사용처에 반영 - 근무 스케줄표 — 「관리자 네이티브 스케줄러 확장」 섹션 신설: 셀 코너 표식 3종(좌상=메모/우상=출결/우하=희망근무 코너 분리) · 희망근무 팔레트(
.pref-corner--*·.pref-tint-*·.pref-shift--*를 근무표 D/E/N 공유 토큰yellow-500·hr-emerald-600·blue-500으로 정렬) · 환자수 행(고정폭 라벨 슬롯 열 정렬 + 접기/펼치기) · sticky 범례 밴드. admin이.sched-grid복제본을 갖는다는 점 단일 출처에 명시. 라이브 데모(DemoScheduleTable.vue + ds-sched-demo.css)에 셀 좌상단 메모 세모(출결 배지와 코너 분리 시연)와 「근무 변경」 피커(기존 인라인 순환을 실제 admin 동작과 일치하는 셀 위치 팝오버로 교체 — 더블클릭·드래그로 2칸+ 선택 완료 두 경로 모두 지원, 다중 선택이면 선택 전체 적용) 반영 - Form controls — 「날짜 범위 필터(프리셋 버튼)」 패턴 신설:
dsDatePicker2개(시작·종료,x-effect교차 clamp) + 프리셋 줄(이번주/지난주/이번달/지난달/최근 3개월 | 전체) +--icon --muted초기화. 공유 헬퍼resolveDatePresetRange/datePresetBtnClass재사용 - Buttons — 사용 규칙에 「리스트 행 상세·보기 =
line · normal · sm」 추가 + 즉석 색 pill 금지·--line은 톤 필수 tip - 모달 — 「상세(읽기전용) 모달」 섹션 신설(공지 상세: 넓은 셸·이전/다음
--icon·닫기--white-bk·메타ds-label·x-text전용). §1에 임베드 앱 백드롭 오프셋(ga-embedded/tm-embeddedpadding-bottom: 10vh), §4에 모달 안 탭 바tabnav-flush-left규칙 추가
메모
- 이 브랜치의 실제 토큰화(10/11/12px →
text-c2/c1/b6,tabular-nums,font-mono제거)는 이미 타이포그래피·Data table에 규정된 규칙을 적용한 것이라 신규 토큰·컴포넌트는 없음 — 문서는 사용처·예시·근거 링크만 보강. 가짜 데이터(전자서명·공지)·푸시 설정 이관 등은 DS 문서 대상 아님(코드 리뷰 이슈로 별도 처리)
2026-07-04 — 전역(시스템) 팝업 z-index 티어 신설 (--ds-z-modal-system · .ds-modal-backdrop--system) (design/adjust-modal-employee-management)
신규
--ds-z-modal-system: 75+.ds-modal-backdrop--system— 권한 요청(permission-denied-modal)처럼 SDK/전역 이벤트로 어떤 화면·모달 스택 위에서든 뜨는 전역 팝업 전용 티어(design-system.css). alert(70)와 toast(80) 사이. 쌓임 원칙: 팝업은 최신 표시 순서대로 위에 쌓인다 — 전역 팝업은 항상 마지막에 뜨므로 최상단 모달 티어를 가진다. 기본 티어(z-50)로 두면 첨부파일 미리보기 뷰어(--top, z-70) 위에서 발생한 403 권한 팝업이 뷰어 아래에 깔려 보이지 않던 문제(직원 수정 팝업 자격증/면허 탭에서 발견) 해결. permission-denied-modal에 첫 적용
문서
- 모달 §단일 출처·규칙 — z 토큰 표에
alert·system행 추가, 쌓임 원칙 명시,--top낡은 z-60 표기를 실제 값(z-70)으로 교정
2026-07-03 — 상태 배지(.ds-status-badge) 색을 등록 라벨 팔레트로 통일 (design/adjust-modal-employee-management)
신규
.ds-status-badge--success— 누락돼 있던 성공(활성) 톤 모디파이어 추가(design-system.css).--success정의가 없어활성·재직·복직배지가 base 스타일(투명 배경)로 떨어져 회색 평문처럼 보이던 문제 해결(직원 수정 팝업 자격증/면허 탭에서 노출)
변경
- 상태 배지 4종(
--success·--warning·--danger·--neutral) 색을 등록 라벨(.ds-label) secondary 팔레트로 통일(design-system.css). 기존 진한--color-*-200(bg)/-300(border)/-800(text) 톤은 등록 라벨(연한 bg + 밝은 글자, solid는 테두리 없음)과 드리프트가 있었음 → 라벨 solid와 동일 색으로:success=--ds-secondary-green-bg/--ds-secondary-green,warning=--ds-secondary-yellow-bg/--color-yellow-500,danger=--ds-secondary-red-bg/--ds-color-danger,neutral=.ds-label--gray값 미러링. base의1px solid transparent테두리를 유지(모디파이어가 border-color 미지정)해 라벨 solid처럼 테두리 없이 렌더. 앱 전역 상태 배지 11곳(활성·휴직·퇴직·비활성 등)에 일괄 반영
문서
- Label §의미색 매핑 규칙 — 상태 배지(
.ds-status-badge)가 등록 라벨의 secondary 팔레트와 동일 색을 공유함을 명시
2026-07-03 — 패널 모달 최소 높이 720px 변형 (.ds-modal--panel-tall) (design/adjust-modal-employee-management)
신규
.ds-modal--panel-tall— 패널 모달(.ds-modal--panel)에 얹는 최소 높이 변형(design-system.css). 기본min-height: 300px를 **720px**로만 재정의 — 입력 필드가 많아 세로 공간이 넉넉해야 하는 폼형 패널에 사용. 낮은 뷰포트에서height(뷰포트−여백)가 720px 밑으로 줄어도 최소 720px 확보(그 아래로는 본문 스크롤). 높이 축만 재정의하므로-narrow(폭)·-loose(상하 여백)와 그대로 조합. 직원 추가·직원 수정 팝업에 첫 적용(둘 다-loose·-narrow와 병용) — 유형·기준 통합 관리는 기존 min-height 300 유지
문서
- 모달 → 패널 모달 §사이즈 —
-narrow설명 아래에-tall변형 설명 추가
2026-07-02 — 패널 모달 좌우 여백 2배 변형 (.ds-modal--panel-narrow) (design/adjust-modal-employee-management)
신규
.ds-modal--panel-narrow— 패널 모달(.ds-modal--panel)에 얹는 좌우 여백 2배(100 → 200px) 변형(design-system.css).width: min(calc(100vw - 400px), 1280px)만 재정의하고 상하·최소 규격(min-width 768 · min-height 300)은 기본 패널과 동일 — 폭이 넓을 필요가 없는 폼형 패널에 사용. 뷰포트 1680px 이상에서는 최대 폭 1280 캡이 먼저 걸려 기본 패널과 동일.-loose(상하축)와 축이 달라 함께 얹을 수 있음. 직원 추가(loose와 병용)·직원 수정 팝업에 첫 적용 — 유형·기준 통합 관리는 기존 좌우 100px 유지
문서
- 모달 → 패널 모달 §사이즈 —
-loose설명 아래에-narrow변형 설명 추가
2026-07-02 — 패널 모달 상하 여백 3배 변형 (.ds-modal--panel-loose) (design/adjust-modal-employee-management)
신규
.ds-modal--panel-loose— 패널 모달(.ds-modal--panel)에 얹는 상하 여백 3배(60 → 180px) 변형(design-system.css).height: calc(100vh - 360px)만 재정의하고 폭·최소 규격(min-width 768 · min-height 300)은 기본 패널과 동일 — 뷰포트 대비 콘텐츠가 가벼운 폼형 패널에 사용. 직원 추가 팝업에 첫 적용
문서
- 모달 → 패널 모달 §사이즈 — 사이즈 표 아래에
-loose변형 설명 한 줄 추가
2026-07-02 — LNB 배지를 DS .ds-label로 렌더 + 다크 서피스 tone 적용 (design/lnb-disabled-menu)
변경
- LNB 배지가 전용
.ds-lnb__badge일회성 스타일 대신 DS.ds-label로 렌더(LnbSidebar.ts).LnbItem.badge가string \| number(알림 카운트 필, primary·round) 또는LnbBadge객체(tone·line·shape·size로 DS 라벨 변형 지정)를 받는다..ds-lnb__badge는 접힘 레일 숨김 훅으로만 남김 - 다크 레일용 tone 적용 — LNB 레일이 어두워(neutral-900) 준비중 라벨에 밝은 배경용
light-gray(어두운 글자)를 쓰면 안 보였음 → 다크 서피스 tonelight-gray-dark(solid·square·xs)로 교체.LnbBadgeTone에gray-dark·light-gray-dark추가. admin 총무 준비 메뉴(대시보드·총무·관리)에 "준비중" 배지 + disabled 적용
문서
- LnbSidebar — 배지 설명을 DS 라벨 기반으로 갱신,
LnbBadge타입·다크 레일 tone 주의 추가, 라이브 미리보기(<DemoLnbSidebar>)의 준비중 배지를light-gray-dark로 렌더
2026-07-02 — 다크 배경용 라벨 색 변형 신설 (--gray-dark · --light-gray-dark) (design/ds-label-dark-tone)
신규
- 다크 bg 위에서 쓰는 라벨 색 변형
--gray-dark·--light-gray-dark추가(design-system.css). 기존--gray/--light-gray는 밝은 배경용(어두운 텍스트)이라 어두운 배경 위에 얹을 중립 라벨이 없었음. 두 변형은 그 반대로 밝은 텍스트 + 흰색 반투명 채움(glass) —--gray-dark는 글자--ds-label-white+ 배경--ds-glass-18(라인 테두리--ds-glass-30),--light-gray-dark는 글자--ds-glass-70(라이트 그레이) + 배경--ds-glass-08(라인 테두리--ds-glass-18). solid·--line모두 지원
문서
- Label §색 변형 표에
--gray-dark·--light-gray-dark행 추가(색 10종 → 12종). 라이브 미리보기(<DemoLabelExplorer>)에 두 컬럼 추가 — light 라벨이라 진짜 어두운 바탕(--color-neutral-800)에 얹어 표시하고, 설명란에 "다크 bg 위에서 쓰는 라벨" 주석 추가
2026-07-01 — 패널 모달(.ds-modal--panel) 문서 등록 + LNB 인-모달 변형 (design/adjust-modal-attendence)
문서
- 모달 → 패널 모달 섹션 신규 — 근태 「유형·기준 통합 관리」에 첫 적용된 좌측 메뉴 + 우측 현황 2단 큰 팝업 변형. 페이지 목차(우측 아웃라인)에 "패널 모달" 항목으로 노출. 인터랙티브 라이브 예시(
<DemoPanelModal>— 좌측 메뉴로 5개 섹션 전환·닫기/다시 열기), 사이즈 규격(width min(100vw-200px,1280) · min-width 768 · height 100vh-120), 구조(좌측 220px 메뉴·우측 헤더/툴바/현황 표), 중첩 자식 ESC 가드(typeManagerChildOpen·stopImmediatePropagation·500ms 유예) 정리. "어디서 쓰이나"에type-manager.html추가 - LnbSidebar → 패널 모달 내비게이션 섹션 신규 — 패널 모달 좌측 메뉴를 LNB 패턴의 인-모달 경량 변형으로 등록. 앱 LNB(
.ds-lnb·다크 레일) vs 패널 메뉴(밝은 배경·플랫·현황 전환) 비교표 + 모달 문서로 바로가기 링크. 아이콘 일치 규칙(출처 페이지 정체성 아이콘 재사용) 공유 명시. "사용처"에도 패널 메뉴 항목 추가 <DemoPanelModal>데모 컴포넌트 신규(theme/components) — 실제.ds-modal--panel/.ds-modal__close/.type-manager__nav-icon/.ds-label/.demo-admin표 CSS로 렌더, 백드롭을 stage 안에 가두는 데모 보정만 스코프 스타일로 추가(하드코딩 hex·새!important0)
2026-06-30 — 근태 현황 날짜 필터 커스텀 달력(dsDatePicker) 일괄 전환 + --32 사이즈 (design/adjust-modal-attendence)
신규
.ds-datepicker--32사이즈 모디파이어 — 트리거 32px. 필터 줄의ds-select--32/ds-input--32와 높이를 정렬하기 위한 중간 크기(기존: 기본 40px ·--sm28px). design-system.css.ds-datepicker--32
변경
- 근태 현황 페이지의 모든 날짜 필터를 네이티브
<input type="date">→ 커스텀 달력(dsDatePicker)으로 일괄 전환 — 근무(출퇴근 현황)·연차(연차/휴가 결재)·연장근무·외근(결재) 탭의 기간from~to입력 10개. 모두ds-datepicker--32로 필터 줄과 높이 정렬,onChange로 기존@change와 동일하게 즉시 재조회 - 연장근무 탭 '기간 드롭다운(초안→적용)'을 인라인 from~to 커스텀 피커(즉시 적용)로 통일 — 커스텀 달력 팝오버는
body로 teleport되어ms-dropdown(바깥 클릭 닫힘) 안에 중첩하면 달력 클릭 시 드롭다운이 닫히는 충돌이 있어, 다른 탭과 동일한 인라인 방식으로 정리. 자주 쓰는 기간(이번주/지난주/…) 프리셋 버튼은 유지
문서
- Form controls — 컴팩트 트리거 항목에
ds-datepicker--32(32px, 필터 줄 정렬) 추가(--sm28px와 병기)
2026-06-30 — SubTab(낱개 하위 탭) 신규 (design/adjust-modal-attendence)
신규
- SubTab 컴포넌트 신규 — 상위 TabNav(밑줄형) 아래에서 쓰는 낱개 하위 탭. 낱개 탭이 간격을 두고 나열되고 선택(active) 탭만 강조, 비선택은 공통 neutral 라인 테두리.
.ds-segment(회색 통 안에서 흰 pill 이동)와 구분되는 별도 형태. CSS.ds-sub-tab/.ds-sub-tab__item(design-system.css) + AlpinesubTab(SubTab.ts · sub-tab.html) - 축(axis) 4종 — size
md(36px·b5 13px) /ml(44px·b4 14px) · radius4/8/16(--radius-*, 기본 8) · colordark/primary· fillsolid/line. color×fill로 선택 강조 4종(dark·solid 기본 = 검정 채움+흰 글자). 모두subTab({ size, radius, color, fill })옵션 →subTabGroupClass모디파이어로 반영 - 토큰만 사용 — color/radius/typography/geometry 모두 DS 토큰. 하드코딩 hex·arbitrary
[...]·새!important0
문서
- SubTab 페이지 신규 — 인터랙티브 라이브 미리보기(
<DemoSubTab controls>— size·radius·color·fill 4축 클릭 토글), 축 4종 표·미리보기, API/토큰. Components — Navigation 사이드바에SubTab추가 - 상위 TabNav와의 계층 데모(
<DemoSubTabHierarchy>) — 상위(밑줄) → 하위를 한 컨테이너에 쌓고, 동일 배경색 공유 + 상·하위 탭 사이 간격 24px로 위계를 시각화 - 검토 필요: radius 중간값은 요청
12였으나 시스템에 12px radius 토큰이 없어 인접한--radius-8(8px) 사용 — 12px 필요 시--radius-12토큰 신규 추가 선행
2026-06-30 — 탭 크기 2단계 변형(md/ml) + 하단 구분선 on/off (design/adjust-modal-attendence)
신규
- TabNav에 크기축(size) 추가 — 기존 단일 사이즈를
md(기본, 현행: 40px · padding 10/12 · b5 13px) /ml(48px · padding 12/16 · b4 14px) 2단계로 변형. CSS.ds-tab-item--ml모디파이어 신설(design-system.css,.ds-tab-*). size축은 padding·높이·라벨 폰트만 바꾸고 색·언더라인 두께(2px)·hover는 공통 - 활성 하단바 오프셋 크기별 재계산 — 라벨이 세로 중앙이라 오프셋 = (탭높이 − 라벨높이)/2. md
-11px(기존) / ml-14px - 컴포넌트 옵션
size—tabNav({ size: 'md' | 'ml' })(기본md) +tabNavSizeClassgetter가 각.ds-tab-item에 모디파이어를 반영(TabNav.ts · tab-nav.html). 기존 호출부는 옵션 생략 시 그대로md— 비파괴
변경
- 탭 바 하단 구분선(회색 1px)을 DS 소유로 이전 + on/off — 기존엔 partial markup의 Tailwind
border-b border-neutral-200였던 것을nav.ds-tab-nav { border-bottom: 1px solid var(--color-neutral-200) }로 DS가 소유. 끄는 모디파이어.ds-tab-nav--flush(border-bottom: 0) 신설. 컴포넌트 옵션tabNav({ divider: boolean })(기본true) +tabNavDividerClassgetter. 기본값은 기존과 동일 1px — 비파괴 - 활성 탭 언더라인을 하단 구분선과 overlap 정렬 — 활성 2px 검정바(
.ds-tab-underline)가 회색 1px 구분선 바로 위에 붙어 "2줄"로 보이던 것을, 구분선을 덮도록 오프셋을 보더 1px만큼 더 내림(md-11px→-12px/ ml-14px→-15px). 활성 탭은 검정 한 줄, 비활성 탭은 회색 한 줄
문서
- TabNav "크기 (size)" 섹션 신설 — md/ml 표 + 라이브 미리보기(
<DemoTabNav size="ml">). API에size옵션·tabNavSizeClass추가, 사용된 토큰(Typography b4·Geometry per-size) 갱신 - TabNav — 하단 구분선 "하단 구분선 (divider)" 섹션 신설 — on/off 라이브 미리보기(
<DemoTabNav :divider="false">) + 활성 바(2px)와 구분선(1px)이 별개임을 명시. API에divider옵션·tabNavDividerClass추가 <DemoTabNav>인터랙티브 컨트롤 —controlsprop 추가로 미리보기 상단에서 체크박스로 ml 크기·divider를 토글(시각 미리보기 §0). 데모 탭 둘레 20px 여백으로 하단 구분선 가시성 개선
2026-06-26 — 모달 텍스트 색 위계 + 인풋 타이틀·간격 표준 (design/adjust-modal-addmember)
변경
- 모달 안 텍스트 색을
label-*시맨틱 토큰 3단 위계로 통일 — 모달 타이틀·그룹 타이틀 =label-normal(neutral-900), 모달 디스크립션·인풋 타이틀 =label-assistive(neutral-500), 기타 보조 설명 =label-muted(neutral-400). rawneutral-*대신 시맨틱 토큰 사용(테마 대응) - 인풋(필드) 타이틀 색
text-neutral-600→text-label-assistive전앱 통일 — 221곳(admin·team-manager·general-affairs·management-dashboard·inventory + 공유 컴포넌트/레퍼런스 위저드). neutral-600(204)·neutral-700(10)로 혼재하던 것을 한 토큰으로. (모바일 employee-app·급여 hr-system·시스템툴 제외) - 그룹(섹션) 타이틀 14px(b4) → 16px(b3) — 인풋 타이틀(13px)과 위계 분리
- 좌우로 놓인 인풋 사이 간격 = 12px(
gap-3) 명문화 — 직원추가 모달이 이미 쓰던 값,gap-2(8px)였던 ward-settings 등 정렬
문서
- 모달 패턴 §4 — 타이포·간격 표에 모달 디스크립션·그룹 타이틀·좌우 인풋 간격 행 추가 + "텍스트 색 위계" 표 신설(normal/assistive/muted). 예제 라벨을
text-label-assistive·보조설명text-label-muted로 갱신
2026-06-26 — 숫자 입력 변형 (ds-input--number) 신설
신규
<input type="number">용 공유 변형ds-input--number추가(design-system.css). 네이티브 증감 화살표(스피너)를 평소엔 숨기고 hover/focus 시에만 노출 — 평소엔 가운데 정렬 숫자가 화살표에 밀리지 않고 깔끔하게, 조작 시엔step단위 증감(▲▼)이 가능(키보드↑/↓는 항상 동작). 숫자 자리수 정렬용font-variant-numeric: tabular-nums포함- 조합형 변형 — 숫자 고유 처리(스피너 + tabular-nums)만 담당. 크기
ds-input--XX· 너비w-full· 가운데 정렬text-center유틸과 조합(정렬은 선택) - 흩어진 핵을 대체할 단일 기준 — 기존엔 admin
.spinner-on-hover,.patient-count-input·.sched-grid input[type=number](항상 숨김), team-manager 인라인style="-moz-appearance:textfield"로 제각각이었음. 그중 검증된 hover/focus 노출 동작(admin.spinner-on-hover)을 공유 DS로 승격
적용
- scheduler 근무지 설정(ward-settings) 의 간호사·조무사·간병인 비율 입력칸(admin · team-manager) — 기존
ds-input--40 w-full text-center(스피너 처리 없음 → 화살표가 가운데 숫자를 밀던 상태)에ds-input--number추가
문서
- Form controls "숫자 입력 (ds-input--number)" 섹션 신설 + 라이브 미리보기(
<DemoFormControls>)에 숫자 토글 추가
2026-06-26 — 시간 입력 피커 = teleport 드롭다운으로 전환 (dsTimePicker)
변경
- 시간 입력 피커를 dim 중앙 다이얼로그 → 인풋 아래 드롭다운으로 전환(날짜 피커와 동작 통일). 기존
te*인라인 로직(.ds-modal-backdrop--top+.ds-mini-modal중앙 다이얼로그)을 공유 컴포넌트dsTimePicker(Alpine 팩토리 DsTimePicker.ts + 마크업 partial ds-time-picker.html +.ds-timepicker*CSS)로 추출. 사용처는 호스트 div + include 한 줄,x-modelable="value" x-model="..."로HH:MM(24h) 바인딩 - 동작:
x-teleport="body"+position:fixed로 트리거 아래 드롭다운 — 모달overflow·filter탈출해 안 잘림, dim 없음, z = 모달 위 1레이어. Esc·바깥클릭·취소 = 피커만 닫힘(모달 유지). 12h 표시 / 24h 저장 ·17→오후5 정규화 · 확인은 유효+변경 시만 활성 (te* 동작 보존) - 적용: admin shift-form(근무 설정 시작/종료시간) · general-affairs notice-form(공지 만료일시 = 네이티브 날짜 + 커스텀 시간 드롭다운). 닫기 이벤트
ds-picker-close로 날짜·시간 피커 통일(동시 1개만 열림) - Form controls "구성 (커스텀 —
dsTimePicker)"로 갱신 +## 피커인트로 "시간 = 커스텀 다이얼로그" → "커스텀 드롭다운"
메모
- docs 라이브 데모(
<DemoTimeInput>/<DemoDateTime>)는 아직 중앙 다이얼로그 형태(미리보기 전용) — 후속으로 드롭다운 형태에 맞춰 갱신 예정
2026-06-26 — 커스텀 날짜 달력 컴포넌트(dsDatePicker) 신설 + 앱 적용 (design/adjust-modal-addmember)
신규
- Form controls "날짜 선택기 구성 (커스텀 —
dsDatePicker)" 신설 — 네이티브type=date를 대체하는 공유 커스텀 달력을 실제 컴포넌트로 등록. Alpine 컴포넌트 DsDatePicker.ts(@hereby/components,createAuthComponentsPlugin등록 → 전 앱 사용 가능) + 공유 마크업 partial ds-date-picker.html +.ds-datepicker*CSS(design-system.css). 사용처는 호스트 div + include 한 줄(로직·외형·마크업 모두 공유, 중복 없음) - 팝오버 =
x-teleport="body"+position:fixed드롭다운 — 트리거 바로 아래에 뜨되 모달의overflow-y-auto·filter를 탈출해 절대 안 잘림(모달 밖으로 넘어가도 OK). dim 없음, z = 모달 위 1레이어(--ds-z-modal-top). 닫기 = Esc · 바깥 클릭 · 날짜 선택 → 피커만 닫힘(모달 유지). 좌우 clamp·위로 flip·동시 1개만 열림 보정 포함 - 옵션·확장:
dsDatePicker({ min, max, placeholder, onChange })(범위 밖 날짜 비활성) · 비활성은 호스트에x-effect="disabled = (조건)"· 선택 시 파생 로직은onChange콜백(유저 pick/clear/today에만 발화 — 네이티브@change동등, 프로그램적 로드엔 안 뜸). 핵심 로직은 단위 테스트로 커버(DsDatePicker.test.ts·DsTimePicker.test.ts)
적용 (12필드 — 데스크톱 폼 전수)
- general-affairs 이수기록(이수일·만료일)·실행기록(예정일) · admin 자격증(발급일·최근신고일·차기신고기간 —
max·비활성·신고일→차기기한 자동계산 보존)·스케줄러 희망일(item.date) · hr-system 연장근무·치료세션(근무일) · inventory 품목(유효기간) · team-manager 치료 인센티브(날짜)·희망일(item.date) - 컴팩트 변형
ds-datepicker--sm(트리거 28px) 신설 — 스케줄러/팀 희망일 목록의 좁은 인라인 행(x-for, text-xs 형제와 같은 높이)에 적용 - 보류: 데스크톱 범위필터(From/To, 카테고리 B) · 모바일 employee-app(Capacitor 네이티브 휠 의도 —
x-clamp-year)
정정
- 기존 "단일 날짜는 그대로 네이티브
type=date(커스텀 달력 안 만듦)" 서술을 정정 — 커스텀 달력 그리드는 단독·결합 모두 사용(단독 = teleport 드롭다운 / 결합 = 한 팝업 인라인).## 피커인트로의 "날짜 = 네이티브"도 "날짜 = 커스텀 달력(dsDatePicker)"으로 수정
2026-06-25 — 시간 입력 피커 — Form controls 섹션 + Modal 내부 피커 등록 (design/adjust-modal-addmember)
신규
- Form controls 문서를 Input · Select · Picker 3패밀리로 정리 — 제목에 Picker 추가,
## 피커 (Picker)상위 섹션 신설하고 달력(날짜·월)·시간 입력을 그 아래로 그룹화(#calendar/#time-input앵커 유지). 피커 = 모달·페이지 공용 패밀리(모달 전용 아님) - Form controls "시간 입력 (Time input)" 섹션 + 라이브 데모(
<DemoTimeInput>) 신설 — 안내형 12시간 입력 다이얼로그를 DS 패턴으로 등록. 오전/오후 드롭다운(ds-select--40) + 시/분 키보드 입력(ds-input--40) + 위·아래 스텝 아이콘 버튼(간격 6px) + 취소/확인(ds-btn--solid white-bk/dark--md),.ds-mini-modalon.ds-modal-backdrop--top(z60). 표시 = 12시간제 · 저장 = 24시간제HH:MM - 값 규칙 명문화: 시 칸은 24시간제 입력 허용(
17→ 오후 5시 자동 정규화), 자정 = 오전 12 · 정오 = 오후 12. 확인 버튼은시 0–23·분 0–59 순수 숫자AND원래 값에서 변경일 때만 활성(숫자 아님/무변경이면 비활성) - 날짜 = 커스텀 달력 우선 (정책 전환) + 단독 커스텀 날짜 피커 데모(
<DemoCustomDate>) 신설 — 결합 피커와 동일한 커스텀 달력(연도 드롭다운 · 월 이동 ‹ › · 삭제 · 오늘 · 오늘=채움/다른 날=테두리 · 바깥클릭 닫기)을 단독 날짜 선택에도 추가. 앞으로 날짜는 커스텀으로 통일·우선하고 네이티브type=date는 대안으로 유지(점진 전환). 기존 "날짜=시스템 기본, 커스텀 안 만듦" 정책을 뒤집음 - 날짜 + 시간 결합 정책 + 라이브 데모(
<DemoDateTime>) 신설({#datetime}) — 네이티브datetime-local(OS마다 외형/동작 상이, 공지 만료일시가 이 케이스)을 한 팝업에 [커스텀 달력 그리드(좌) + 커스텀 시간 폼(우)] 결합 뷰로 대체. ⚠️ 달력 커스텀은 결합 케이스 한정(단일 날짜는 그대로 네이티브type=date— 네이티브 달력은 우리 시간 폼과 한 팝업에 못 합치기 때문). 마이그레이션 대상: 공지 작성 만료일시 등datetime-local은 이 결합 뷰로 교체 권장 - Modal "§7 모달 안의 피커" — 짧은 참조만 추가. 피커(날짜·월·시간)는 공용 폼 컨트롤이라 home은 Form controls(모달 전용 아님). 모달 문서엔 모달 안에서 쓸 때만 더해지는 규칙(다이얼로그형 =
.ds-modal-backdrop--top모달 위 · 팝오버형 = 바디overflow-y-auto비잘림 · Esc/바깥클릭은 피커만 닫고 모달 유지)만 명시
메모
- 달력(날짜 = 네이티브
type=date· 월 = 커스텀 월 선택기)은 기존 "달력(날짜·월 선택)" 섹션 유지 — 이번엔 시간 입력만 추가(사용자 결정: 달력은 기존 기본 사용 + 커스텀 뷰 조합) - 원본 구현: shift-form.html 근무 설정 시작/종료시간 (
teOpenFor/te24/teNormHour/teStep*/teCanConfirm)
2026-06-25 — 모달·얼럿 푸터 버튼 강조 규칙 (위치 → 맥락·중요도, weight 3티어) (design/adjust-modal-addmember)
신규
- Modal "§6 푸터 버튼 — 강조는 위치가 아니라 맥락·중요도로" 섹션 신설. 그동안 문서가 정의하지 않던(라이브 데모로만 암묵 표준이던) 푸터 확정 버튼 강조를 2축으로 명문화: ① 위계(가장 무거운 버튼 = 권장 액션 — "우측이라서"가 아니라 "권장 액션이라서") × ② weight 3티어(중요도로 무게 결정). 통합 버튼 체계의
ds-btn조합 그대로 — 새 클래스 없음 - weight 3티어: 기본/권장 컨펌 =
solid · dark(대부분) · 크리티컬 컨펌(삭제·비가역) =solid · lightor(연주황 틴트, 드물게) · 취소·닫기 등 물러나는 동작 =solid · white-bk(흰 모달 위 텍스트만). 위계dark>lightor>white-bk. "가장 우측이니 orange/dark 채움" 관성 폐기 - 위험 반전: 데이터 손실 확인(변경 폐기·삭제 직전)은 안전한 선택을 권장 버튼(
dark)으로 올리고 파괴 동작은 약화(white-bk)/lightor, 자동 포커스·기본 Enter는 취소에. 라이브 푸터 강조 갤러리(일반/크리티컬/위험반전 3종, 실제ds-btn렌더) 추가
변경
- Modal 라이브 데모를 새 규칙에 동기화 — 저장(권장) = dark, 취소 = white-bk, 저장확인 팝업은 계속편집(안전) = dark · 닫기 = white-bk로 위험 반전 적용, "모달 다시 열기" 유틸도 dark(데모에서 orange 제거). "목표 & 로드맵"에 푸터 버튼 강조 정렬 행 추가
- Buttons "사용 규칙(맥락→조합)" 표 정정 — 모달·얼럿 푸터 행을 권장 =
solid · dark· 크리티컬 =solid · lightor· 취소·닫기 =solid · white-bk3티어로 교체(기존solid · primary/line · dark), 모달 푸터 강조 규칙으로 연결하는 안내 추가. 의미색green/red는 모달 밖 인라인/툴바/워크플로 컨텍스트로 한정 명시
수정
ds-btnlight 변형 hover/pressed 오버레이 색 매칭 (design-system.css) —lightred/lightgreen/lightblue/lightpurple/lightyellow/lightaquablue가 hover overlay 그룹에서 빠져 default--color-label-muted(회색)를 써, 거의 흰-50채움 위에서 hover 시 회색으로 바래던 문제 수정. 각자 의미색(-600/yellow-700)으로--ds-btn-ov-hf/--ds-btn-ov-pr매칭 —lightor가--color-primary(orange)로 매칭하던 것과 동일 패턴. 문서 결재(doc-preview) 반려(lightred) hover가 빨강으로 진해짐. Buttons "상태" 설명 동기화
메모
- 모달 내 워크플로 승인/반려는 예외로 확정 — 문서 결재(
doc-preview) 승인=green·반려=red(연한 시작lightred)는 의미가 강해 의미색 유지하되 DS 통합 버튼(ds-btn--solid)으로 구현(기존bg-green-600/bg-red-*유틸 교체), 같은 푸터 닫기·취소는white-bk. §6 "현황"에 예외 명문화 - 앱 마이그레이션은 버튼 체계 마이그레이션과 함께 점진 진행. 급여(hr-system)는 표준 적용 제외
2026-06-24 — Notice danger 변형 + 문서 신설 (design/adjust-modal-addmember)
신규
- Notice 컴포넌트 문서 신설 —
.ds-notice베이스 + 변형(--info/--warning/--success/--danger)의 라이브 미리보기·규격·토큰·적용 현황. 등록은 돼 있었으나 전용 문서가 0이던 인라인 알림 callout(피드백 그룹에 추가) .ds-notice--danger변형 신설(오류·반려: red-50/200/700, 아이콘 red-500) — 기존 info/warning/success와 동일 규격
변경
- 문서 결재 미리보기(team-manager
doc-preview) 반려 사유 + PermissionDeniedModal 요청 실패 에러의 임시bg-red-50 border-red-200 text-red-*조합을.ds-notice--danger표준 변형으로 정규화 — 반려 사유엔 경고 아이콘(.ds-notice__icon) 추가, notice 아래 footer 구분선 제거(빨간 박스가 시각 구분 제공) - 문서관리 목록(team-manager
document-management)의 구분·상태 배지를 앱 로컬.badge/임시bg-purple-100·bg-orange-100에서 DSds-label(--blue/--primary/--yellow/--green/--red/--gray)로 통일 — 같은 데이터를 띄우는 미리보기 팝업과 배지 컴포넌트·색 매핑 일치(취소=gray 분리 포함) - Modal 라이브 예시 닫기(
.modal-demo-x)에 hover 상태 추가 — doc 전용 클래스라 hover 규칙이 빠져 마우스를 올려도 변화가 없던 문제. 실제 앱 모달(admin/ga/md)의 표준 닫기 버튼.ds-modal__close와 동일하게 재현: 24×24 + 16px SVG ✕, 투명 배경 → hover 시 neutral-100이 ✕ 뒤에 차오름(공유button{border-radius:4px!important}강제 규칙으로 라운드 사각형 렌더, 앱과 동일)·focus-visible윤곽선. 입력·드롭다운은 전역input/.ds-select규칙으로 이미 hover·focus 반영됨
2026-06-23 — 모달 데모 타이틀·마진 표준 동기화 (design/adjust-modal-addmember)
변경
- Modal 라이브 예시 모달 타이틀(
.modal-demo-title)을 16px/700 → 20px/600으로 수정 — 실제ds-modal__title과 어긋나 있던 데모 값을 표준에 동기화(line-height 1.4·letter-spacing -0.2px 포함) - Modal 라이브 예시 카드 패딩 24px → 44·40·36(상/좌우/하), X 닫기 위치 14px → 20px —
ds-modal(header·body·footer) 표준 마진과 일치 - Modal "내부 타이포·간격" 표에 카드 마진(44/40/36)·모달 타이틀(20/600) 행 추가 — 데모 CSS에만 있던 값을 명시 문서화
- 모달 텍스트 가드(
.ds-modal-backdrop p.text-*)에text-h5·text-h4추가 —<p class="text-h5">모달 타이틀(20px)이 design-system.css를 Tailwind에@import하지 않는 앱(team-manager·employee-app 등, 런타임 로드만)에서도 동일 적용. 그 앱들은text-h5유틸이 생성되지 않아 헤딩/타이틀 크기가 누락되던 문제 수정
2026-06-19 — 입력 컴포넌트 문서 보강 (design/apply-ds-input-components)
신규
- Form controls "메뉴 패널(
ds-menu)" 섹션 신설 — 공유 DS의 커스텀 드롭다운 패널(__item/__item--selected/__item--row/__divider/__label/__hint) 라이브 인라인 미리보기 + 클래스/토큰 표. 등록은 돼 있었으나 문서가 0이던 컴포넌트(실제 직원 수정 모달 팀/역할 선택에 사용) - Form controls "달력(날짜·월 선택)" 섹션 신설 + 라이브 데모(
<DemoDatePicker>) — DS 정책 명시: 날짜=시스템 기본type="date"(네이티브 지원 충분, 커스텀 달력 미제작), 월=커스텀 월 선택기(type="month"지원 약함 →.ds-menu팝오버 + 연도.ds-select+ 월 그리드). 팝오버는 트리거 버튼 바로 아래 6px 간격·우측 정렬. 시각 확인도 네이티브 인풋을 직접 보게 구성
변경
- Form controls "사용처" → **"적용 범위 & 도입 현황"**으로 재구성: 전역 기본(자동·전 서비스) vs 명시적 사이즈 전환(도입 진행)으로 2층 분리, 모달 마이그레이션(직원 위저드·근태 모달 →
--40) 진행상황을 표로 반영. 곧 낡는 "사용처 카탈로그" 대신 진행상황 기록으로 전환 - Form controls
ms-dropdown정정 — 공유design-system.css가 아닌 admin·team-managersrc/styles/main.css의 앱 로컬 패턴임을 명시(공유 표준은ds-menu) - Form controls 라이브 미리보기(
<DemoFormControls>)에 textarea·드롭다운 채움 변형(--fill-gray/--fill-white) 추가 — 등록된 변수를 더 시각화(같은 상태가 input·select·textarea에 동시 반영) - Form controls 검토 필요 사항 정리 —
--ds-textfield-*/--ds-dropdown-*primitive 연결 항목을 runtime-safe literal 트레이드오프로 명시(보류:--ds-*는 의도적 literal 세트라@themetree-shaking으로 일부 앱서 primitive가:root서 제거됨 — 실측--color-label-white@module-manager·inventory). chevron(값 on-palette#8f8f8f=neutral-400·data-uri 한계)·24px(일관 literal px)·!important-free(정상) 항목은 검토 완료로 제거 - 라이브 미리보기 = 페이지 상단(데모 우선) 통일 — 데모가 있는 7개 페이지(Form controls · Data table · Tooltip · TabNav · WorkspaceSwitcher · PageHeader · LnbSidebar)에서 미리보기 블록을 H1·인트로 바로 아래로 이동(컴포넌트를 먼저 보고 → 세부 읽기). 본문/캡션은 그대로 유지
- Form controls 상단 라이브 미리보기를 3종 컴포넌트 갤러리(텍스트필드·드롭다운·textarea / 메뉴 패널 / 달력)로 재구성 — 각 항목에 "설명 더보기 →" 앵커로 상세 섹션(
{#size-scale}·{#menu-panel}·{#calendar}) 연결, 상세 섹션의 중복 미리보기는 제거(미리보기는 상단 한 곳에 모음)
메모
- 입력 컴포넌트(크기 스케일·토큰) 자체는 이전 작업(PR #247 등, 커밋
ab7675c8/d99c3fce)에서 이미 DS 등록·develop 머지 완료 — 이 작업은 문서 반영 전용(새 CSS 없음)
2026-06-18 — 토대 문서 누락분 보강 (foundations)
변경
- 색상 Label 표에 누락돼 있던
--color-label-black-normal(=--color-neutral-900별칭) ·--color-label-black-strong(#000000) 2개 토큰 추가 —design-system.css정의와 표 동기화 - 모서리 placeholder → 실문서: primitive
--radius-2~512/full(@theme→ Tailwindrounded-*) + 컴포넌트--ds-radius-sm/md/lg/label-sm/label-md토큰표·미리보기, 전역 버튼 radius 4px!important강제 트랩 명시 - 그림자 placeholder → 실문서:
--ds-shadow-xs~xlrecipe + 칩(--ds-shadow-chip-*)·drop-shadow(--ds-drop-shadow-*) 토큰표·미리보기, box-shadow recipe의 Figma 비전파 사유 명시 - 타이포그래피 "숫자 표기(Numeric figures)" 섹션 신설 — 데이터 숫자는 Inter 기본, 자릿수 정렬이 필요한 표/열에만
tabular-nums적용(단독 인라인 숫자엔 미적용), 사번·코드 등 식별자에font-mono금지(코드/키캡 전용). admin 근태관리 모달 사번font-mono→tabular-nums정리에서 도출 - 타이포그래피 토큰 중복 정리 + 문서 정정: ①
--ds-font-family를var(--font-app)별칭으로 변경(literal 단일화·동기화) ②--typo-*↔--text-*는 Tailwind tree-shaking 때문에 병합 불가임을 빌드 산출물로 검증(미사용--text-h1이:root에서 제거됨) → "단일화 대상" 표현을 "메커니즘 분리 유지"로 정정 ③ "font-weight 토큰 미정의"는 사실과 달라 정정(이미 정의·사용 중)
메모
- 세 페이지 모두 기재값을
design-system.css실제 토큰과 1:1 대조 후 작성 (수기 표 ↔ CSS 일치 검증) - 타이포 정정은 admin dist CSS(빌드 산출물) 직접 확인으로 검증 —
--text-b5/--text-c2존재,--text-h1부재
2026-06-12 — LNB 개편 + 헤더 프로필 (design/update-lnb-structure-and-merge-pages)
신규
- PageHeader: Toolbar 우측 끝 프로필 아바타(
showProfileopt-in, radius 8, 벨과 간격 24) + 프로필 팝오버(썸네일 64 원형 → 메일 → 이름 → 내 정보·로그아웃,onLogout호스트 콜백). LNB 하단 프로필 대체 - LnbSidebar 접힘 레일: 플라이아웃(
.ds-lnb__flyout— 흰 바탕·라인·아이콘/타이틀 행, fixed) · 커스텀 툴팁(.ds-lnb__tip— 네이티브 title 대체, 클릭 즉시 숨김, 열린 메뉴만 억제) ·is-child-active(활성 하위를 가진 부모 강조) .ws-brand: 비클릭 정적 브랜드 변형 — workspace(admin)는 WorkspaceSwitcher 드롭다운 대신 사용- 아이콘 13종:
ic-id-badgeic-file-textic-tableic-clockic-slidersic-calendar-clockic-calendar-checkic-clock-plusic-chart-baric-tagic-map-pinic-gaugeic-list-check— LNB 아이콘 중복 제거용 (LNB·헤더·embed 레지스트리 아이콘 일치 규칙 도입)
변경
- workspace(admin) LNB: 접기 토글 하단 → 브랜드 우측(헤더), 하단 profile 영역 제거, 레일 스크롤바 비표시(스크롤 유지). 접힘 토글이 우측 sticky 헤더에 가려 잘리던 문제 z 조정으로 해소
- NotificationBell 팝업 색 토큰화: Tailwind 기본 gray →
neutral-*,shadow-xl→shadow-popover,rounded-xl→rounded-16— 전역 버튼 강제 보정 의존 제거. 두 팝업(알림·프로필)이 동일한 라인(neutral-100)·radius 16 체계로 통일 - 전역 버튼 radius 강제(4px
!important) 제외 명단에.ds-page-header__avatar추가 — 규칙 자체 정리는 별도 브랜치 예정
메모
- radius 12 토큰 신설은 검토 후 취소 — 기존
--radius-8/16스케일 사용 (토큰 변경 없음) - docs 토큰 브리지 신설 (
.vitepress/theme/ds-token-bridge.css):@theme블록 토큰이 앱 빌드(Tailwind)에서만 :root로 처리되어 docs 라이브 데모에서 비어 있던 문제 수정. design-system.css의 모든@theme토큰(색 팔레트·의미별칭·폰트·타이포·radius·그림자·spacing)을scripts/gen-docs-bridge.mjs로 자동 생성(docs predev/prebuild 시 실행)해 수기 사본 없이 단일 출처에서 동기화 — 전 데모가 프로덕션과 동일하게 렌더링 - 라이브 데모 최신화: PageHeader(프로필 아바타·팝오버 추가,
.vp-doc h1타이틀 간섭 보정) · LnbSidebar(workspace 패턴 — 브랜드+헤더 토글·하단 profile 제거·접힘 플라이아웃/툴팁/child-active·새 아이콘) · WorkspaceSwitcher 문서에 "워크스페이스 미사용" 상태 라벨 명시
2026-06 — 모달 표준 v1 (design/modal-dim-display-standard)
신규
- 토큰:
--ds-dim-40(모달 딤 40%), z-index 스케일--ds-z-*(base 0 / raised 10 / nav 20 / dropdown 40 / modal 50 / modal-top 60 / toast 80 / tooltip 90) - 컴포넌트:
.ds-modal-backdrop— 딤 40% + 가운데 정렬 + z 토큰 + 스크롤 잠금 내장 (overscroll-behavior: none). 변형--top(z-60) - 패턴 문서: 모달 v1 — 표시 · 닫기 · 스크롤 잠금 · 내부 타이포 · 예외 목록 · 라이브 예시
표준 적용 (전 모달)
- dim을 화면별로 제어하지 않는다 — 공통 dim opacity 40%(공용
.ds-modal-backdrop) 적용, 항상 표시, 바깥 클릭으로 닫히지 않음. team-manager · admin(native/탭 인라인/scheduler) · general-affairs(4005) · management-dashboard(4006) · 공유 위자드/설정 모달 적용 - 저장확인 + pristine 가드: 폼 모달의 X/취소/Esc는 변경이 있을 때만 확인 팝업 경유, 변경 없으면 바로 닫힘
- 모달 내부 타이포: 필드 타이틀 13px(
text-b5) + 간격 6px(mb-1.5), 콘텐츠 그룹 간격 16px(space-y-4) - 상태(활성/비활성) 선택을 드롭다운으로 통일 (pill 토글 · 스위치 5곳 변환)