시트 UX 개선 요구사항 — 사용자 피드백 정리 (2026-07, v3)
원본: 베스트 병원 / STG 사용자 피드백. 테마별 재구성 + 현재 동작(원인) → 방향 → 난이도. 구현 구조 참고: 시트 아키텍처 · 참조·수식 설계
v3 (2026-07-06): 19개 항목 전부 종결 — E-2 성능 최적화까지 완료, C-3은 셀 단위 수식(C-1)으로 충족되어 불필요 판정(2026-07-06 사용자 확인).
상태: ✔ 구현 완료 · ◐ 부분 완료 · 📐 설계 완료 · ✅ 방향 확정(미착수) · 💡 아이디어 · 🔍 조사 필요 · ⏳ 보류
한 줄 진단 (v3 시점)
"엑셀에서 되던 게 안 된다"는 마찰 대부분이 해소됨: 새 시트가 A~Z × 1000행 빈 그리드로 시작하고, 복사해서 부으면 알아서 되고(오버플로우·부분성공·텍스트 기본), 이름만 부으면 직원과 연결되고, = 타이핑으로 수식을 쓴다. 남은 큰 덩어리는 구조 undo · 테두리 · 픽커 단순화 · 병합 · 성능 계측.
A. 되돌리기 (Undo/Redo) — 완료
| # | 상태 | 구현 내역 |
|---|
| A-1 | ✔ | 구조 undo 커맨드 패턴: Transaction { kind, changes?, revert?, reapply? } — 구조 변경 tx는 revert/reapply 클로저 실행. 기록 kinds: style · row-move · col-move · col-config(열 설정 저장) · col-rename(H-4). Ctrl+Z/Ctrl+Shift+Z 라이브 검증 |
| A-2 | ✔ | 서식 되돌리기 — A-1의 style kind: 선택 영역 셀별 이전 스타일 patch 스냅샷 → JSON 그룹핑 → 일괄 revert |
B. 행 추가 · 직원 연동 — 전부 완료
| # | 상태 | 구현 내역 (2026-07-06) |
|---|
| B-1 | ✔ | 구글 시트 동일 초기 그리드: 새 시트 = A~Z 26열 × 빈 행 1000개 (seedEmptyRows, FALLBACK_LAYOUT A~Z 텍스트 컬럼). 하단 바 "하단에 [1000]개 행 추가" + 삽입 메뉴 "행/열 여러 개 추가…" (열은 Z 다음 AA, AB…로 이어짐) |
| B-2 | ✔ | Paste-overflow 자동 행 생성: onPasteCreateRows 전면 재작성 — 식별 셀 없으면 bare 행 생성, 모든 편집 가능 컬럼 값 저장(종전 amount만), batchCreate 1회 + batchSet 2000 청크 |
| B-3 | ✔ | B-2에 포함 + 토스트 요약 ("N개 행 생성, N개 셀 업데이트, N개 건너뜀 (사유)") |
| B-4 | ✔ | text→식별 전환 자동 매핑: 서버 sheetRow.linkEmployeesFromColumn (이름=lastName‖firstName, 사번, 동명이인 안내, 입사일 가드) — 일치 행 승격 + literal 정리, 미일치 셀 붉은 배경(#fee2e2) + 사유 alert. 부수 수정: 식별 전환 시 refField 기본값 성명(빈 모델 함정), 성명 셀 직접 타이핑 최초 연결(빈 행 편집 게이트 완화 + confirm 생략), 성명 셀 붙여넣기 연결(onCellPaste identity 분기 신설 — 종전 침묵 드롭) |
| B-5 | ✔ | 일괄 추가 부분 성공: batchCreate → {created, skipped[사유]} — 자격 미달만 스킵, "N명 추가, M명 제외" 요약 |
C. 수식 — C-3만 보류
| # | 상태 | 구현 내역 |
|---|
| C-1 | ✔ | = 인라인 셀 수식 (R3): 셀에 = 입력 → kind=formula 저장(표시형 참조 canonicalize + slug 자동 부여), 재편집 시 수식 시딩(cellMeta), resolver 셀 수식 평가 pass 신설(컬럼 수식 결과·크로스시트·상수 참조). 부수: amount 에디터 type=number→text (수식 입력 차단 해소) |
| C-2 | ✔ | 이름 기반 표시 (R1): [uuid:col] → [시트이름!컬럼라벨] 양방향 치환, 라운드트립 무손실(모호하면 canonical 유지), uuid→slug 자동 업그레이드. 행 참조 (R4): [colKey@rowId] 저장(행 이동에도 유지) ↔ [라벨@행번호] 표시, 수식 중 다른 셀 클릭 → 참조 삽입. =[colKey] 단일 참조는 원시값 미러링(텍스트는 텍스트로, 빈 값은 빈칸 — 엑셀 =A1) |
| C-3 | ✔ | 불필요 판정 (2026-07-06 사용자 확인) — C-1 셀 단위 수식(= 인라인)이 합계 행 요구를 이미 충족 |
D. 서식 · 표현 자유도
| # | 상태 | 구현 내역 / 방향 |
|---|
| D-1 | ✔ | F-1(R1)으로 해소 — 참조사항은 원래 시트에 두고 [시트이름!컬럼] 참조 |
| D-2 | ✔ | 기본 텍스트: 신규 컬럼(FALLBACK·열 추가) format=text, 빈 텍스트 셀 "-" 플레이스홀더 제거. 폴백 렌더: 숫자 컬럼의 비숫자 텍스트를 0으로 삼키지 않고 원시값 표시(+안내 툴팁), 콤마 문자열 정상 파싱 |
| D-3 | ✔ | 셀 병합 구현 (2026-07-06, 설계 확정 반영): 값 동기화 병합 — 병합 시 블록 전체가 앵커 값으로 통일(기록), 앵커 편집·붙여넣기 후 자동 재동기화, 통일 전 값은 Ctrl+Z로만 복구(히스토리 소실 후 해제는 값 유지). sheet_views.cellMerges jsonb(마이그레이션 1845000000000) + merge map 렌더(colspan/rowspan/skip, 무효 병합 조용히 비활성), 세로 병합은 정렬/검색/필터 off일 때만(켜지면 일시 해제 ⚠), 가상 스크롤 윈도우-앵커 확장, 키보드 내비 블록 스냅, 우클릭 ⬜ 셀 병합/⬛ 해제 + 검증(편집 가능 값 열만·식별/수식/집계 제외·겹침 거부), XLSX mergeCells 반영. 단위 테스트 13종. 2단 헤더는 columnGroup 밴드 기구현 — 잔여(우클릭 그룹 편집·XLSX 밴드)는 소형 후속 |
| D-4 | ✔ | 테두리: style.border 6종 (아래/아래 굵게/아래 이중/위/전체/없음) + 툴바 팝오버, 렌더러 변형 적용. XLSX 내보내기 반영 완료 — exportXlsx를 ExcelJS로 전환(커뮤니티 xlsx는 스타일 미지원), 셀 테두리·색·볼드 + 헤더 스타일·컬럼 폭까지 그리드와 동일하게 내보냄 |
| D-5 | ✔ | 프리셋 12색 + 최근 색 8(localStorage) + ✕기본(지우기) + 직접 선택(드래그 중 라이브 프리뷰 → 닫을 때 저장). ③ 색 불일치 원인 규명: 선택 하이라이트가 background:틴트!important로 셀 색을 교체 → background-image gradient 오버레이로 수정 (선택 중에도 진짜 색이 보임) |
E. 복사/붙여넣기 · 성능
| # | 상태 | 구현 내역 / 방향 |
|---|
| E-1 | ✔ | 붙여넣기 후 전체 loadSheets() → _refreshSheetMetaSilently() (건수만 제자리 패치, 깜빡임·자동선택 재실행 없음) |
| E-2 | ✔ | 계측 + 최적화 완료 (2026-07-06). 계측(1000행 실측): 서버 500행 페이지 243ms(문제 없음) · 병목은 전부 클라이언트 렌더 — ①전체 렌더 ~2ms/행: 가상화 임계 500이라 ≤500행 시트는 편집/붙여넣기/스타일마다 최대 ~1s 프리즈(500행 1,054ms 실측), 스트리밍 첫 배치(정확히 500행)도 동일 ②_applyCellStyles가 렌더마다 모든 td에 11개 스타일 클리어 쓰기(스타일 0개여도) ③드래그 mousemove(60~120Hz)마다 같은 셀인데도 선택 재계산+CSS 리페인트+engineTick(Alpine 재평가)+fill-handle 레이아웃 읽기. 수정: 가상화 임계 150(최악 전체 렌더 ~27ms, 그 이상은 윈도우 ~11ms) · 스타일 오버레이 styledCell 마커 기반(스타일 없는 td 쓰기 0) + 메모 마커 조기 반환 · 드래그 동일 셀 가드(셀 경계 넘을 때만 작업). 결과: 첫 로드 1,662→476ms · 가상화 렌더 46→11ms · 최악 전체 렌더 1,054→27ms · 드래그 100 이벤트 23ms. 회귀 검증: 스타일 적용/제거·메모 마커·전체 테스트 105 통과 |
F. 시트 간 연동
| # | 상태 | 구현 내역 / 남은 것 |
|---|
| F-1 | ✔ | 완료 (R1): 백엔드 [slug:colKey] 엔진 + 이름 표시 치환 + 픽커 표시 문법 삽입, 커밋 시 canonical + slug 자동 부여(ensureSlug). 표기 규칙 (2026-07-06): buildSheetDisplayNames — 이름 중복 시 폴더명 → 기간(YYYY.MM) → 서수 순 구분 배지 (픽커 UI 전용, 수식 문법에는 불침투 — 모호하면 canonical 유지 원칙 그대로). 픽커 3곳(수식 트리·xref 빌더·크로스시트 검색) 적용 + 장문 말줄임(truncate)+툴팁. 단위 테스트 7종 |
G. 메모 · 협업
| # | 상태 | 구현 내역 / 남은 것 |
|---|
| G-1 | ✔ | 1단계: 본인 메모 수정/삭제 (작성자 서버 강제, soft delete 감사 보존). 2단계 (2026-07-06): 스레드형 코멘트 — parentMemoId 단일 레벨 스레드(마이그레이션 1844000000000, 답글의 답글은 루트로 승격·앵커 상속), 메모 모달이 스레드 뷰(루트 버블+답글 목록+답글 입력), 해결은 스레드 단위(루트만 — 답글 개별 해결 거부, 미해결 수·상태 필터도 루트 기준), @이름 멘션 → 직원 매칭(lastName‖firstName, 동명이인 전원) 후 in-app/push 알림(NotificationType.MEMO 신설), 답글 시 스레드 참여자(루트 작성자+기존 답글자) 알림, 이력 패널 ↳답글 배지. @ 자동완성: 메모 textarea·답글 input에서 @ 타이핑 → 직원 드롭다운(이름/사번 필터, ↑↓·Enter/Tab·Esc·클릭), 선택 시 @이름 치환 — 서버 파서와 동일 표기 보장 |
H. 컬럼 종류 · 상수 관리
| # | 상태 | 구현 내역 / 방향 |
|---|
| H-1 | ✔ | 픽커 단순화: 기본 3카드 (✏️값·ƒ수식·👤식별) + "고급 종류" 접기(현재 값이 고급이면 자동 펼침), 식별 format select 비활성+자동 동기화 |
| H-2 | ✔ | 문법·해석 (R2): 수식 [$namespace.key] — 기간 유효 버전 해석 + 💲 상수 픽커 + 참조 확인 검증. 관리 편의 (2026-07-06): 픽커 ⚙ 관리 버튼 → hr-system 인앱 상수 관리 모달 — 조회·값 수정(변경 사유 → append-only 이력)·신규 등록(숫자 자동 감지·콤마 파싱), admin 패널 이동 불필요 (iframe 임베드 환경에서도 동작) |
| H-3 | ✔ | refField→format 고정 매핑 (identityFormatFor: 사번=텍스트·입사일=날짜·호봉=숫자, 미등록=텍스트) — UI 비활성+자동 동기화, 저장 시 강제 정규화 |
| H-4 | ✔ | 인라인 열 이름 변경 (원본 요구 "이름만 바꾸려 해도 설정에 들어가야 해서 불편" — 요구사항 대조에서 누락 발견분): 헤더 더블클릭(비수식 컬럼) 또는 우클릭 → ✏️ 이름 바꾸기(수식 컬럼 포함) → 헤더가 그 자리에서 입력창으로 — Enter 저장·Esc 취소, syncLayout으로 서버 저장, col-rename undo 기록(Ctrl+Z/Ctrl+Shift+Z). 수식 컬럼 더블클릭은 기존대로 수식 편집 유지 |
우선순위 (v3 — 남은 작업)
남은 작업 (소형 후속만)
- 2단 헤더 우클릭 그룹 편집 · XLSX 헤더 밴드 반영 · 월 이월 시 병합/조정입력 정책 (별도 일괄)
보류: C-3 행 기준 수식 (원문 명시)
완료 요약 (v2 → v3 사이 구현)
- 빠른 승리 6종: E-1 · B-5 · D-5(①②③) · G-1 1단계 · H-3 · B-1
- 붙여넣기 세트: B-2/B-3 오버플로우 · D-2 텍스트 기본+폴백
- 식별 연동 세트: B-4 전환 매핑 · 성명 타이핑/붙여넣기 연결 · H-3
- 수식 세트: C-1
= 셀 수식 · C-2 이름/행 참조 · =[x] 미러링 (R1~R4 아키텍처 전체) - 상수: H-2
[$…] 문법+픽커 (R2) - 검증: 항목별 라이브 E2E(실 브라우저) + 단위 테스트(hr-system 85 / api 89) + 전체 빌드 그린