---
title: "📊 260527-수요일_엑셀형 외부 편집기 Phase 1 (PoC + 기획서 + 목업)"
notion_id: "36d229620868811f9f27f15cf699fa97"
notion_url: "https://app.notion.com/p/36d229620868811f9f27f15cf699fa97"
category: "workreport"
parent: "Claude Code 작업보고"
updated: "2026-05-27"
priority: "High"
purpose: "엑셀형 외부 편집기 별도 레이아웃(/history/excel) Phase 1 — 기획서·목업·체성분 단일 테이블 PoC 구현 (의존성 추가 0)"
read_when: ["엑셀·셀입력기능"]
---

## 📌 요약

- 셀 모드 점진 보강의 발산 문제 극복 차원으로, **엑셀형 외부 편집기**를 별도 레이아웃(라우트 `/history/excel`)에 신설.
- **Phase 1 범위 (사용자 확정 정의)**: 기획보고서 + UI/UX 목업 + 체성분 단일 테이블 PoC 구현.
- **의존성 추가 0건** — react-data-grid 도입은 사용자 PoC 검증 후 Phase 2 결정 항목으로 보존. 자체 그리드(`<table>`) 구현으로 빌드 위험 회피.
- 체성분 탭: 풀 기능 (fetch·셀 클릭 편집·키보드 네비·다중선택·행 추가·diff 저장·자동계산). 러닝·근력 탭: Phase 2/3 안내 placeholder.
- `npm run build` 통과 → 커밋 3건 작성 → `origin/main` 푸쉬 완료 (논스톱 위임).
- 사용자 지시에 따라 **사용 후 Phase 2 결정 이관** — 라이브러리·합쳐령 패턴·진입 시점·근력 우선순위·수식 지원 5개 항목.

---

## 결정 배경

### 사용자 제안

> "이렇게 하나하나 백엔드로 바꾸면 한도 끝도 없으니. (물론 해당 환경에 익숙한 고급사용자에 한정되는 타겟) 차라리 엑셀 기능을 최대한 구현한 에셀형 편집기를 별도 레이아웃에 띄우게 하는 버튼과 액션, 기능을 추가로 만드는게 나을것 같아. MS파워포인트에서 차트 데이터 변경할때 활용할수 있는 데이터편집(엑셀창 띄우기)처럼."

### 핵심 메시지 수렴

- 셀 모드의 점진적 백엔드 보강은 발산 (사용자 요구 1건마다 fix 1건 누적)
- 타겟 분리: 일반 사용자는 셀 모드, **고급 사용자는 에셀형 편집기**
- 별도 레이아웃 (인라인이 아닌 별도 페이지 진입)
- 참조 패턴: PowerPoint 차트 데이터 편집 → 에셀창 팝업

### 작업 수행 조건 (사용자 명시)

- **퇴근 후 중간 컴펀 불가** → 논스톱 진행 위임
- **새 라이브러리 추가로 인한 빌드 위험 회피** → 의존성 미추가 원칙 설정
- **기획서 §10 5개 결정 항목은 사용자 결정으로 보존** (Claude 임의 선택 금지)

---

## 완료 작업 3단계

### 단계 1 — 기획보고서 작성 (커밋 `f3215f0`)

- 산출: `docs/260527_excel_editor_external_layout_plan.md`
- 12개 섹션: 배경·한계·라이브러리 비교·통합 패턴·데이터 흐름·기능 매트릭스·작업 사이즈·진입 시점·미결정·결정 요청·제외 항목·참고
- 권장안:
	- 라이브러리: **react-data-grid** (MIT, ~150KB) — 다른 후보(luckysheet·glide·handsontable·AG-Grid·MUI) 비교표 명시
	- 통합 패턴: **별도 라우트** `/history/excel` (모바일·데스탑 모두 풀스크린)
	- PoC 우선: 체성분 단일 테이블 (4~6h)
	- 진입 시점: v0.9 출시 후 (데드라인 압박 회피)
	- 근력 통합 우선순위: Phase 3 후순위
	- 수식 지원: Phase 4+ 보류

### 단계 2 — UI/UX 목업 HTML 발행 (커밋 `0b0e29a`)

- 산출: `docs/260527_excel_editor_external_layout_mockup.html` (37KB)
- 작업 전 충돌 위험 측정 (KST 16:33):
	- 활성 worktree: 1개 (단독)
	- 병렬 로컬 브랜치: 없음
	- 최근 6시간 커밋 작성자: 단일 (ccy-hansbridge)
	- **다른 에이전트 작업 흔적 없음 → 충돌 위험 0**
- 9개 섹션: 진입 버튼, 풀스크린 에디터, 셀 상태 범례 6종, 단축키 12종, 저장 컨펌 모달, Phase 매트릭스, 데이터 흐름, 제외 항목, 검토 요청
- 스타일 톤: 기존 `260527_strength_phase5_option_b_mockup.html` 다크·라임 액센트 패턴 일치

### 단계 3 — Phase 1 PoC 코드 구현 (커밋 `7d34c2e`)

- 사용자 지시: "이 지시에 한하여 커밋-푸쉬에 관련된 제약사항은 완화할테니까 커밋-푸쉬까지 논스톱으로 진행"
- 탐색 → 구현 → 빌드검증 → 도중 타입에러 해소 → 커밋 2건 분리 → 푸쉬 일련 수행

#### 수정 파일

| 구분 | 파일 | 변경 요지 |
|---|---|---|
| 신규 | `src/pages/HistoryExcel.tsx` | 약 600줄. 자체 그리드(`<table>`). 체성분 풀 구현 + 러닝/근력 placeholder. 키보드 핸들러, diff 저장, 자동계산, 모일 가드 |
| 수정 | `src/App.tsx` | 라우트 등록 1줄 (`<Route path="history/excel" element={<HistoryExcel />} />`) + import 1줄 |
| 수정 | `src/pages/History.tsx` | 셀모드 영역 상단에 `⌸ 에셀 편집기 열기` 버튼 추가. tab 쿼리 보존 프로파게이션 |

#### 기능 (체성분 탭)

- **데이터 흐름**: 진입 시 `body_records` 365건 + `app_settings` `fitness_projects` JSON 키 fetch → `records.map(toEditRow)`
- **셀 편집**: 클릭 선택 → Enter/F2/더블클릭 입력 진입 → Tab/Enter/Esc/Blur 종료
- **키보드 네비**: ↑↓←→ 셀 이동, Space 행 선택, Del 선택 삭제, Ctrl+S 저장
- **행 추가**: `+ 행 추가` 버튼 → 임시 key + `_isNew: true` 행 상단 삽입
- **행 삭제**: DB 행 → `deletedIds` Set에 축적. 임시 행 → rows에서 제거
- **diff 집계**: rows 순회 → added/updated/deleted 카운터 계산. 의존 useMemo
- **자동계산**: 체지방률 = fat_kg/weight_kg×100, BMR = 370 + 21.6×(weight - fat) (CellModeBody 식 계승)
- **저장**: `_isNew` + dirty rows 검증 → upsert `onConflict: 'recorded_at'` + `delete in (ids)` Promise.all → 재로딩 → 알림
- **더티 추적**: 변경 건수 배지(상단바) + beforeunload 경고
- **컴폼 모달**: 저장 / 이탈 2종 (공통 ConfirmDialog 재사용)
- **모바일 가드**: 768px 미만 진입 시 안내 배너 (닫기 가능)
- **세션 자동로딩**: tab 파라미터 변경 시 useEffect 재호출

#### 기능 (러닝·근력 탭)

- placeholder 카드 표시 ("Phase 2/3에서 준비 중")
- 체성분 편집기로 이동 / 셀 모드로 돌아가기 2 버튼

---

## 아키텍처

```javascript
React Client (dallog.pages.dev)
    ↓ navigate('/history/excel?tab=body')
[HistoryExcel 페이지]
    1. Supabase fetch (body_records 365건 + app_settings.fitness_projects)
    2. records → editRows[] (id·_isNew·_origin 보존)
    3. 사용자 상호작용 (셀 편집·행 추가/삭제·선택)
    4. diff 집계 (rows 순회 → added/updated/deleted)
    5. 저장 버튼 → ConfirmDialog → onConfirm
    6. upsert (onConflict: recorded_at) + delete (.in('id', deletedIds))
    7. 성공 → 재 fetch → rows 재설정 → NotifyDialog
```

기존 셀 모드과의 관계: **단방향** (진입 시 fetch / 저장 시 적용). 양방향 실시간 동기화는 의도적으로 제외 (데이터 무결성 위험).

---

## 빌드·커밋

- `npm run build` 통과 — 421 modules transformed, gzip 347KB. 관련 접근되는 청크 크기 경고는 기존부터 있었던 것 (변동 없음)
- 타입체크 — 초기 PromiseLike 호환 오류 2건 발생 → `(async () => {...})()` 패턴으로 즉시 수정 → 통과
- 커밋 3건 (한 의미 단위 = 한 커밋 원칙):
	- `f3215f0 docs(cellmode): 엑셀형 외부 편집기 기획보고서 (사용자 제안)`
	- `0b0e29a docs(history/excel): 엑셀형 외부 편집기 UI/UX 목업`
	- `7d34c2e feat(history/excel): Phase 0 PoC — 체성분 엑셀형 외부 편집기 (별도 라우트)`
- push: `origin/main` 완료. 이전 컨텍스트의 로컬 커밋 `88b6982` (SSE 스트리밍) 동반 푸쉬

---

## 의도적으로 안 한 결정

| 결정 항목 | 현재 상태 | 사유 |
|---|---|---|
| react-data-grid 도입 | 미추가 (자체 구현) | (a) 퇴근으로 npm install 권한 다이얼로그 대응 불가 (b) CSS 충돌 · peer deps 등 빌드 깨짐 위험 (c) 기획서 §10 라이브러리 선택은 사용자 결정 항목으로 보존 |
| 다중 셀 복붙 (Ctrl+C/V) | 미구현 | Phase 2 범위 |
| 컬럼 헤더 클릭 정렬 | 미구현 | Phase 2 범위 |
| 컬럼 너비 드래그 조정 | 미구현 | Phase 2 범위 |
| Undo/Redo | 미구현 | Phase 4 범위 (명령 스택 필요) |
| CSV/Excel import-export | 미구현 | Phase 4 범위 |
| 러닝 편집 | placeholder | Phase 2 진입 시 체성분 패턴 재사용 |
| 근력 편집 | placeholder | Phase 3 범위 (3-테이블 트랜잭션 복잡도 ↑) |
| 수식 지원 (SUM·AVG·VLOOKUP) | 미구현 | Phase 5+ — luckysheet 전환 시점에 재검토 |
| 셀모드 ↔ 엑셀편집기 양방향 동기화 | 의도적 제외 | 데이터 무결성 위험 — fetch/save 양단 적용으로 통일 |

---

## 회귀 / 호환성 체크

- 셀 모드(CellModeBody/Running/Strength) — **변경 없음**. 단수 history 페이지의 셀모드 영역에 진입 버튼 1개만 추가
- 다른 라우트(대시보드·로그·코치 등) — 영향 없음
- `app_settings.fitness_projects` JSON 키 fetch 패턴 — History.tsx:332 동일 패턴 차용
- `body_records` upsert with `onConflict: 'recorded_at'` — CellModeBody.tsx:259 동일 패턴 차용
- `body_records` delete `.in('id', ids)` — CellModeBody.tsx:210 동일 패턴 차용
- ConfirmDialog/NotifyDialog — 공통 Modal 재사용
- CSS 컬러 톤 — 기존 CSS 변수(`--bg`, `--bg2`, `--bg3`, `--accent`, `--text` 등)만 사용. 새 면역 CSS 삽입 없음

---

## 사용자 검증 요청 (퇴근 후)

논스톱 진행으로 인해 **실제 브라우저 렌더링·클릭 검증은 미실시**. 다음 항목 사용자 사후 체크 필요:

1. `/history/excel?tab=body` 진입 → 데이터 로드 정상 (loading → rows 렌더링)
2. 셀 이동 (화살표) → 포커스 아웃라인 표시
3. Enter/F2/더블클릭 → 입력 진입·포커스
4. 수정 → 셀 하이라임 배경 표시 + 더티 카운터 증가
5. `+ 행 추가` → 상단에 신규 행 (녹색 하이라임)
6. Space → 행 선택, Del → 선택 행 삭제 표시(취소선 적용)
7. Ctrl+S → 저장 컨펌 모달 → 확인 → DB 반영
8. 더티 상태에서 `✕ 취소` → 이탈 컨펌
9. 러닝/근력 탭 진입 → placeholder 카드 표시
10. 모바일 (768px 미만) → 가드 배너 표시
11. 셀몠드→에셀편집기 / 에셀편집기→셀모드 이동

---

## Phase 2 결정 항목 (사용자 결정)

기획서 §10 결정 요청 항목 5건 재명시:

1. **라이브러리**: react-data-grid (권장) / luckysheet (풀 에셀) / 자체 그리드 유지 / 기타
2. **통합 패턴**: 별도 라우트 (현재) / 모달 / 새 창 ([window.open](http://window.open))
3. **진입 시점**: v0.9 출시 후 (권장) / v0.9 내 / 차후 미정
4. **Phase 2 PoC 다음 우선순**: 체성분 풀 기능 보강 (복붙·정렬·undo) / 러닝 탭 / 근력 탭
5. **사용 빈도 예상**: 일주 1회 미만 / 일주 수회 / 매일

---

## 이후 / 미수행

- 사용자 브라우저 검증 (위 11건)
- Phase 2 결정 항목 응답
- Phase 2 작업 계획 수립
- 다른 세션과의 중복: 특히 없음 (충돌 측정 통과)

---

## 참조

- 기획보고서: `docs/260527_excel_editor_external_layout_plan.md`
- UI/UX 목업: `docs/260527_excel_editor_external_layout_mockup.html`
- 작업일지: [📅 2026-05-27 (수) 작업일지](#/doc/devlog-13) §02
- 핸드오프: [📋 26-05-26_1-달록_핸드오프](#/doc/handoff-13) §15 (본 컨텍스트 갱신)
- 커밋 3건: `f3215f0`, `0b0e29a`, `7d34c2e` → [github.com/ccy-hansbridge/dallog](http://github.com/ccy-hansbridge/dallog)
- 최종 push: `origin/main` (`88b6982..7d34c2e`)

---

*2026-05-27 (수) · Claude Opus 4.7 (1M context) · 검토 대상: ccy-hansbridge*
