# 2026-04-04 작업일지

## 오늘 작업

- Plan 목록 조회 버튼을 자동조회 중심 UX로 개편(남은 시간 표시/토글)
- 자동조회 버튼 레이아웃 깨짐/문구 중복/선택 드래그 문제 보정
- 앱 업데이트 진행 UI에 단계 표시와 프로그레스 흐름 추가
- 서비스워커 교체 흐름(`SKIP_WAITING`, 등록 확인, 타임아웃) 안정화
- 업데이트 실패 시 상태 복구와 오류 가시성 개선
- `vite-plugin-pwa` 업데이트 경로를 공식 흐름 우선으로 정리
- 자동화 Codex 실행 타임아웃 도입 및 롤백 과정 반영
- Plan 삭제 응답/정리 로직 개선
- work-server 메인 프로젝트 경로/풀 동작 정리

## 이슈 및 메모

- 업데이트 이슈는 단일 원인보다 서비스워커 교체 타이밍/등록 상태/환경 설정이 복합적으로 영향
- 자동조회는 텍스트/배지/오버레이가 겹치면 UX가 빠르게 악화됨
- Codex 타임아웃은 안전장치가 되지만 과도하면 정상 작업도 중단시킬 수 있음

## 결정 사항

- 업데이트 상태는 단순 성공/실패가 아닌 단계 기반으로 노출
- 서비스워커 등록/교체는 실패 복구 경로까지 포함해 설계
- 자동조회 UI는 버튼 본문 최소화 + 보조 배지 방식 유지
- 워커 경로 설정은 환경별 명확한 기준 경로로 통일

## 상세 작업 내역

- Plan 보드에서는 자동조회 중심 운영을 위해 상단 액션을 재설계하고 모바일/데스크톱 표시 균형을 맞춤
- 앱 업데이트 영역은 사용자 체감 기준(지금 무엇을 하는지)으로 문구와 상태 전이를 재구성
- 서비스워커 관련 반복 장애를 줄이기 위해 등록 확인, 교체 메시지 처리, 타임아웃/롤백 로직을 함께 점검
- 서버 측 경로 및 삭제 처리 개선으로 운영 중 발생하던 잔여 데이터/응답 일관성 문제를 줄임

## 스크린샷

- 저장소 기준 연결된 스크린샷 없음

## 소스

- `src/app/main/appUpdate.ts`, `src/app/main/MainHeader.tsx`: 앱 업데이트를 단계형 상태와 프로그레스 UI로 노출하고 서비스워커 등록 대기/재시도 흐름을 추가했습니다.
- `src/features/planBoard/PlanBoardPage.tsx`: 자동조회 버튼 UX와 Plan 목록 상단 액션 구성을 손봤습니다.
- `scripts/run-plan-codex-once.mjs`: Codex 자식 프로세스 종료/에러를 중복 처리하지 않도록 `settled` 가드를 추가했습니다.
- `etc/servers/work-server/src/services/plan-service.ts`: Plan 삭제 시 연관 소스작업/조치/이슈 이력까지 함께 정리하도록 트랜잭션 삭제로 바꿨습니다.
- `etc/servers/work-server/src/workers/plan-worker.ts`: 타임아웃과 실패 처리 흐름을 보강했습니다.

```diff
diff --git a/etc/servers/work-server/src/services/plan-service.ts b/etc/servers/work-server/src/services/plan-service.ts
-  await db(PLAN_TABLE).where({ id }).delete();
+  await db.transaction(async (trx) => {
+    await trx(PLAN_SOURCE_WORK_TABLE).where({ plan_item_id: id }).delete();
+    await trx(PLAN_ACTION_TABLE).where({ plan_item_id: id }).delete();
+    await trx(PLAN_ISSUE_TABLE).where({ plan_item_id: id }).delete();
+    await trx(PLAN_TABLE).where({ id }).delete();
+  });

diff --git a/src/app/main/MainHeader.tsx b/src/app/main/MainHeader.tsx
+import { applyAppUpdate, getAppUpdateSnapshot, subscribeAppUpdate, type AppUpdateStatus } from './appUpdate';
...
+            <Button
+              block
+              icon={appUpdateStatus === 'updating' ? <ReloadOutlined spin /> : <DownloadOutlined />}
+            >
```

## 변경 파일 (전체, 중복 제거, KST 기준)

- M src/app/main/appUpdate.ts
- M etc/servers/work-server/src/routes/plan.ts
- M etc/servers/work-server/src/services/plan-service.ts
- M src/features/planBoard/api.ts
- M etc/servers/work-server/src/config/env.ts
- M etc/servers/work-server/src/workers/plan-worker.ts
- M scripts/run-plan-codex-once.mjs
- M src/sw.ts
- M vite.config.ts
- M src/app/main/MainHeader.tsx
- M src/styles.css
- M etc/servers/work-server/.env.example
- M etc/servers/work-server/docker-compose.yml
- M src/features/planBoard/PlanBoardPage.tsx
- M docker-compose.yml
- A src/app/main/appUpdate.ts
- M src/main.tsx

## 실행 커맨드

```bash
npm run build
npm run plan:codex:once
```

## 변경 파일

- `docs/worklogs/2026-04-04.md`
- `src/app/main/appUpdate.ts`
- `src/app/main/MainHeader.tsx`
- `src/features/planBoard/PlanBoardPage.tsx`
- `src/sw.ts`
- `vite.config.ts`
- `etc/servers/work-server/src/config/env.ts`
- `etc/servers/work-server/src/workers/plan-worker.ts`
- `etc/servers/work-server/src/services/plan-service.ts`
- `scripts/run-plan-codex-once.mjs`
