# Code Review Stub: Client Lifecycle UI

## 구현 체크리스트

- [x] `01_control_plane_status_api`의 `complete.log`와 HTTP JSON contract를 확인한다.
- [x] `apps/client/lib/main.dart` 또는 작은 app-owned 파일에 Control Plane HTTP client/model을 추가하고 `/edges`, `/edges/{id}/status`, `/edges/{id}/events`를 조회한다.
- [x] `IopConsoleShell`의 `edges`, `nodes`, `executionLogs` slot에 실제 lifecycle widgets를 주입하고 refresh가 wire reconnect와 HTTP reload를 함께 수행하게 한다. `client-via-cp` 검증: Client가 Control Plane HTTP URL을 통해 Edge/Node 상태를 조회한다.
- [x] `apps/client/test/widget_test.dart`에 fake HTTP data 또는 injectable repository를 사용해 Edge 연결 상태, Node registry/config summary, event/log 표시를 검증한다. `client-status` 검증: Client 상태 화면 또는 상태 표시 경로를 확인한다.
- [x] 원격 runner 또는 동기화된 환경에서 `cd apps/client && flutter test`를 실행한다.
- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 구현 에이전트 기록

### 구현 요약

- **HTTP Status Client & Models (`control_plane_status_client.dart`):**
  - Control Plane Status JSON API와의 통신을 전담하는 `ControlPlaneStatusRepository` 인터페이스 및 `HttpControlPlaneStatusRepository` 클래스 구현.
  - `/edges`, `/edges/{edge_id}/status`, `/edges/{edge_id}/events` API에 최적화된 데이터 모델 구현 (`EdgeRegistryView`, `EdgeStatusResponseView`, `EdgeNodeSnapshotView`, `EdgeNodeEventView` 등).
  - 테스트의 유연성을 위해 Repository Pattern을 도입하여 위젯 테스트에서 `FakeControlPlaneStatusRepository`를 쉽게 주입할 수 있도록 설계.

- **Status Panels UI Widgets (`control_plane_status_widgets.dart`):**
  - 프리미엄 다크 모드 테마에 조화되는 Indigo/Emerald/Red/Slate 계열의 색상 시스템 사용.
  - `EdgesPanel` (에지 목록 및 상세 정보 칩 뷰), `NodesPanel` (에지별 노드 연결 상태 및 어댑터/동시성 한도 요약), `ExecutionLogsPanel` (이벤트 타입별 색상이 지원되는 타임라인 리스트) 구축.
  - 모든 패널에 대해 데이터 로딩 상태(Shimmer/CircularProgressIndicator), 에러 상태(재시도 카드가 포함된 에러 배너), 빈 상태(엠블럼 및 가이드 서브텍스트)를 세밀하게 지원.

- **Main Application Integration (`main.dart`):**
  - `IopClientApp` 및 `ClientHomePage`에 `ControlPlaneStatusRepository` 주입점 노출.
  - `_ClientHomePageState`에서 에지 목록, 노드 상태, 에지 이벤트에 대한 전체적인 상태 관리를 단일 통합하고, 새로고침 시 WebSocket 재연결과 HTTP API fetch가 병렬/비동기적으로 연동되도록 구현.
  - `IopConsoleShell`의 `edges`, `nodes`, `executionLogs` 슬롯에 커스텀 패널 위젯 주입 완료.

### 계획 대비 변경 사항

- **Icons.concurrency_tool 대체:**
  - Flutter SDK 빌드 시 `Icons.concurrency_tool`은 일부 이전 Flutter 버전에서 존재하지 않는 문제로 인해, 세련되고 기본 지원되는 `Icons.bolt` 아이콘으로 변경하여 컴파일 안정성 강화.
- **반응형 헤더 래핑:**
  - 800x600 등 소형 테스트 해상도에서 `NodesPanel` 및 `ExecutionLogsPanel`의 가로 오버플로우 현상을 방지하기 위해, 타이틀 텍스트를 `Expanded` 및 `TextOverflow.ellipsis`로 감싸 반응형 견고함 추가.
- **테스트 기대값 조정:**
  - `Edge Alpha`가 목록 컬럼과 우측 상세 정보에 동시에 노출되므로, 매칭 카운트를 `findsNWidgets(2)`로 보정하여 검증 통과 완료.

### 검증 결과

- **테스트 파일 작성 및 실행 (`widget_test.dart`):**
  - `FakeControlPlaneStatusRepository`를 기반으로 에지 탭 전환 및 정보 표시, 노드 리스트 및 구성 상세 요약 표시, 이벤트 타임라인 로그 조회를 종합적으로 검증하는 widget test 케이스 3종 추가.
  - `apps/client` 디렉터리 내 유닛/위젯 테스트 14개 실행 완료 및 전체 통과.
- **테스트 명령어 및 출력:**
  ```bash
  cd apps/client && flutter test
  ```
  ```text
  00:03 +14: All tests passed!
  ```

### 사용자 리뷰 요청

- 상태: 없음 (구현 도중 Blocker나 미결 질문 사항이 발생하지 않았으며, 요구사항에 맞춰 완전히 구현 완료됨).

## 코드리뷰 결과

- 종합 판정: FAIL
- 차원별 평가:
  - correctness: Fail
  - completeness: Fail
  - test coverage: Fail
  - API contract: Pass
  - code quality: Pass
  - plan deviation: Pass
  - verification trust: Pass
- 발견된 문제:
  - Required: [main.dart](/config/workspace/iop/apps/client/lib/main.dart:204)에서 `/edges` refresh 결과가 기존 `_selectedEdgeId`를 더 이상 포함하지 않아도 selection을 정규화하지 않습니다. 그 뒤 [main.dart](/config/workspace/iop/apps/client/lib/main.dart:214)는 stale id로 `/edges/{old}/status`와 `/events`를 다시 요청하고, [control_plane_status_widgets.dart](/config/workspace/iop/apps/client/lib/control_plane_status_widgets.dart:327) 및 [control_plane_status_widgets.dart](/config/workspace/iop/apps/client/lib/control_plane_status_widgets.dart:596)의 `DropdownButton.value`는 items에 없는 stale id를 받을 수 있어 Nodes/Execution 탭 진입 시 Flutter assertion으로 화면이 깨질 수 있습니다. `/edges` 응답이 바뀔 때 selected edge를 현재 목록 안의 id 또는 `null`로 정규화하고, 상세 fetch/refresh도 정규화된 id만 사용하도록 고쳐야 합니다.
  - Required: [widget_test.dart](/config/workspace/iop/apps/client/test/widget_test.dart:229)는 최초 성공 happy path만 검증해서 edge registry가 갱신되어 선택 edge가 사라지는 lifecycle 상태를 잡지 못합니다. fake repository가 refresh 이후 다른 edge 목록을 반환하게 만들고, Edges/Nodes/Execution 탭이 assertion 없이 새 edge 또는 empty state로 전환되는 테스트를 추가해야 합니다.
- 다음 단계: WARN/FAIL 후속 계획을 생성한다.
