---
title: "🔧 260526-월요일_셀기능 시각검증 후속 fix (이슈 1~10 + 7옵션B, 11번 RLS 별도 트랙)"
notion_id: "36c229620868812bb770fa6aaa79cda0"
notion_url: "https://app.notion.com/p/36c229620868812bb770fa6aaa79cda0"
category: "workreport"
parent: "Claude Code 작업보고"
updated: "2026-05-26"
priority: "Medium"
purpose: "셀기능 시각검증 리포트 11건 중 9건 일괄 fix + 컬럼 커스텀 옵션B 구현. 11번 OAuth RLS는 v0.9 작업2 별도 트랙 이관"
---

> ⚡ **작업 메타**
> - 일자: 2026-05-26 (월) 저녁 ~ 알 수 없음
> - 범위: 셀기능 시각검증 리포트 11건 중 9건 일괄 처리 + 컬럼 커스텀 옵션B 구현
> - 커밋: `a453a0c` (origin/main 반영)
> - 빌드: 성공 (417 modules, gzip 328KB)
> - 이전 작업: `c6b6090 feat(cellmode): 셀기능 추가 Phase 1~4`

## 1. 사용자 시각검증 리포트 (데스크탑+모바일)

11건 이슈 보고 + Q1 온소롤 진행 + Q2 추천안 승인 (11번 RLS 별도 트랙 + 체크리스트·핸드오프 리마인드 의무) + 7번 옵션B 선택.

## 2. 이슈 11건 처리 분류

| # | 이슈 | 분류 | 처리 |
|---|---|---|---|
| 1 | 러닝 마일리지 셀 마감 어색 | P0 마감 | ✅ isLast borderRight 일괄 |
| 2 | 메모 컴럼 ellipsis | P1 UI | ✅ 보기모드 nowrap+ellipsis |
| 3 | 메모 셀 클릭 펼침 편집 | P2 UX | ✅ 8번 자세히모달로 통합 충족 |
| 4 | 수정버튼 위치 → 페이지네이션 옆 | P1 UI | ✅ 한 줄 통합 액션바 |
| 5 | 단위 표시 + 자동계산 색 | P1 UI | ✅ 셀에 유니트 / 연 라임 #d4e8a0 |
| 6a | 가운데정렬 + 여백 축소 | P1 UI | ✅ justifyContent: center + padding 축소 |
| 6b | 날짜+시간 정렬 (더블런) | P1 정렬 | ✅ History sort 보조키 run_time |
| 7 | 컬럼 선택 + 순서 커스텀 | P2 기능 | ✅ 옵션B — 토글 + 화살표 순서 + localStorage |
| 8 | 자세히 모달 클릭 복원 | P0 회귀 | ✅ onDetailOpen props + 행 onClick |
| 9 | 일괄 삭제 | P0 회귀 | ✅ "선택 삭제" 버튼 + ConfirmDialog |
| 10 | 단건 삭제 | P0 회귀 | ✅ 9번과 동일 (1행 선택 삭제) |
| **11** | **OAuth 계정 런타입 조작 차단 (RLS)** | **P3 별도 트랙** | **⚠️ v0.9 작업 2(멀티유저 보안)으로 이관. 체크리스트·핸드오프·v0.9충족기준 3중 리마인드 등재** |

## 3. 대표 변경 코드

### 3-1. 자세히 모달 복원 (이슈 8)

```typescript
// CellModeBody.tsx / CellModeRunning.tsx
const onRowClick = !editMode && onDetailOpen && r.id
  ? () => { const orig = records.find(x => x.id === r.id); if (orig) onDetailOpen(orig) }
  : undefined
```

History.tsx: `<CellModeBody ... onDetailOpen={setDetailBody} />`, `<CellModeRunning ... onDetailOpen={setDetailRun} />`

### 3-2. 삭제 기능 (이슈 9·10)

```typescript
const requestDelete = () => {
  const sel = rows.filter(r => selectedKeys.has(r._key))
  const dbIds = sel.filter(r => r.id).map(r => r.id!)
  const tempKeys = sel.filter(r => !r.id).map(r => r._key)
  setDeleteConfirm({ ids: dbIds, tempKeys })
}
const doDelete = async () => {
  if (ids.length > 0) await supabase.from('body_records').delete().in('id', ids)
  if (tempKeys.length > 0) setRows(prev => prev.filter(r => !tempKeys.includes(r._key)))
}
```

### 3-3. 날짜+시간 정렬 (이슈 6b)

```typescript
const runTimeKey = (r: RunningLog) => {
  if (r.run_time_hour == null) return -1
  const h12 = r.run_time_hour % 12
  const h24 = (r.run_time_period === 'PM' ? 12 : 0) + h12
  return h24 * 60 + (r.run_time_minute ?? 0)
}
// sort 안
const d = b.recorded_at.localeCompare(a.recorded_at)
return d !== 0 ? d : runTimeKey(b) - runTimeKey(a)  // date_desc — 같은 날 PM이 AM보다 아래
```

### 3-4. 컬럼 커스텀 (이슈 7 옵션B)

신규: `useColumnConfig` hook (localStorage 영속) + `ColumnConfigDropdown` UI (체크박스 + ↑↓)

```typescript
const { columns, visibleColumns, state, toggleVisible, moveColumn, reset } =
  useColumnConfig('body', BODY_COLUMNS)
```

storageKey: `cellmode_columns_body_v1` / `cellmode_columns_running_v1`. 새 컬럼 추가·구 컬럼 제거 대응 보정 로직 포함.

### 3-5. routine_id 저장 활성화

사용자 마이그레이션 적용 완료 확인 → `RunningLog.routine_id?: string | null` 신설 + `payload` 안 활성화.

## 4. 이슈 11번 세부 — 별도 트랙 (필수 리마인드)

> ⚠️ **현재 현상**
> - 마스터 계정(localStorage 기반): run_type_configs 읽기/쓰기/수정/삭제 정상
> - OAuth 계정(`ccy4848@gmail.com`): run_type_configs 조작 자체 차단
> - 원인: Supabase RLS 정책이 `auth.uid()=user_id` 기준으로 구성되었는데 명세·적용 상태 불분명

**권고 레공 (v0.9 작업 2 수행 시):**

1. Supabase Dashboard → Authentication > Policies 접속
2. 대상 테이블 점검: `run_type_configs`, `shoe_configs`, `exercise_configs`, `app_settings`
3. RLS 활성 여부 + 현재 정책 확인
4. 결정: 이 테이블들이 (a) 관리자 관리 글로벌 테이블인지, (b) 사용자별 개도로 소유되어야 하는지
5. 세부 시나리오:
	- (a) 관리자 귀속: 마스터만 편집 가능, OAuth 일반 사용자는 SELECT만 허용. 이 경우에도 OAuth에서 읽기 자체는 되어야 함. 현재 읽기도 안되는 건 RLS가 익명/OAuth 모두 거부하고 있을 가능성
	- (b) 사용자별 귀속: 각 row에 `user_id` 컴럼 추가 + RLS `auth.uid()=user_id` 정책. 마이그레이션 + 기존 글로벌 데이터 소유자 결정 필요
6. (a) 권장 — 신발/런타입/운동종목은 서비스 가이드 성격. 단 사용자별 커스텀 필요 시 추후 분리
7. 적용 후 OAuth 계정으로 재테스트 → 하단 Nav·설정에서 런타입 드롭다운 정상 노출 확인

**리마인드 등재 위치:**

- ✅ 이 작업보고 §4 (본 문서)
- ✅ 핸드오f58 26-05-26_1 §2-4 추가
- ✅ v0.9 충족기준 작업 2 안에 세부항목 추가
- ✅ 작업 체크리스트에 "이슈 11 — RLS 검증·수정" 등재

## 5. 명세 이슈별 적용 상세

### 이슈 1 (러닝 마일리지 셀 마감)

- `getCellStyle(col, isLast)` 헬퍼 신설. isLast=true면 borderRight: 'none'
- Fragment + (i === lastIdx) 조건으로 일관적 적용
- 컬럼 숨김/교체 시에도 잘 동작 (이슈 7과 조합)

### 이슈 5b (자동계산 색)

- 이전: `color: var(--text3)` (#7a7a7a 수준) — 다크모드에서 너무 연해 안 보임
- 변경: `#d4e8a0` 연 라임 — 화이트와 구분되면서 가독성 확보
- 체성분(체지방률·BMR)·러닝(페이스·속도) 4가지 자동계산 필드에 공통 적용

### 이슈 7 (컬럼 커스텀 옵션B)

- 상태 저장: localStorage `cellmode_columns_body_v1` / `cellmode_columns_running_v1`
- 새 컬럼 추가 · 구 컬럼 제거 시 자동 보정 — defaults 기준으로 정합·차집합 검증
- 임면 렬·메모리 이슈 최소화 (popover 원자립 닫힌 등)
- 이후 세컨드 페이즈(근력 Phase 5)에서도 재사용 가능

## 6. 변경 파일

| 파일 | 종류 | 요약 |
|---|---|---|
| `src/lib/supabase.ts` | 수정 | RunningLog.routine_id?: string \| null 추가 |
| `src/pages/History.tsx` | 수정 | onDetailOpen 전달 + 러닝 날짜+시간 보조 정렬 |
| `src/components/cellmode/CellModeBody.tsx` | 수정(재작성) | 이슈 1·2·3+8·4·5·6a·7·9·10 일괄 반영 |
| `src/components/cellmode/CellModeRunning.tsx` | 수정(재작성) | 동일 + routine_id 활성화 |
| `src/components/cellmode/useColumnConfig.ts` | 신규 | hook + localStorage 영속 |
| `src/components/cellmode/ColumnConfigDropdown.tsx` | 신규 | popover UI |

6 files / +682 / -411 lines

## 7. 검증

- `npx tsc --noEmit`: 오류 0
- `npm run build`: 성공 (417 modules, gzip 328KB — 이전 326KB에서 +2KB)
- 실제 시각 검증: 사용자 사후 체크 (Cloudflare 자동 배포 후)

## 8. 후속 권고

1. 사용자: [dallog.pages.dev](http://dallog.pages.dev) 재검증 (모바일/데스크탑)
2. v0.9 작업 2 (멀티유저 보안) 진행 시 이슈 11 포함 — [핸드오프 §2-4](#/doc/handoff-13) 참조
3. 근력 Phase 5 (세컨드 페이즈) 진입 시 컬럼 커스텀 hook/dropdown 재사용
4. 메모 편집 — 현재 자세히 모달을 통해 수정. 대량 메모 편집이 필요해지면 메모 전용 다이얼로그 검토

---

> ✅ **결론**
> 시각검증 11건 중 9건 일괄 처리 + 컬럼 커스텀 옵션B 신규 구현. `c6b6090..a453a0c` 푸쉬 완료. 이슈 11 RLS는 v0.9 작업 2의 구체 세부항으로 따로 때어 4중(작업보고·핸드오프·v0.9충족기준·체크리스트) 리마인드 등재.
