<!-- task=flutter_first_client_consolidation/03+02_app_workspace_surface plan=0 tag=REFACTOR -->

# Flutter Workspace Surface Plan

## 이 파일을 읽는 구현 에이전트에게

`CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 반드시 채우세요. 이 subtask는 directory name 기준으로 `02_contract_boundary`의 `complete.log`가 선행 조건입니다. 구현 후 실제 검증 출력과 계획 대비 변경 사항을 기록하고, active 파일은 그대로 둔 채 리뷰 준비 상태로 보고하세요.

## 배경

Flutter 앱은 현재 `apps/mobile/lib/main.dart:113-118`에서 `nomadcode-app` 텍스트만 표시한다. React web의 project workspace mock은 `apps/web/src/api/projects.ts:17-88`에 있고, code-server는 `window.open`으로 열 뿐이다. Flutter-first 전환에서는 앱 자체가 project/workspace surface를 소유하고 code-server를 React wrapper 없이 직접 열어야 한다.

## 분석 결과

### 읽은 파일

- `agent-ops/roadmap/current.md`
- `agent-ops/roadmap/milestones/flutter-first-client-consolidation.md`
- `apps/mobile/lib/main.dart`
- `apps/mobile/lib/services/mattermost_auth_service.dart`
- `apps/mobile/lib/services/push_notification_background.dart`
- `apps/mobile/lib/services/push_notification_service.dart`
- `apps/mobile/test/widget_test.dart`
- `apps/mobile/pubspec.yaml`
- `apps/mobile/README.md`
- `apps/mobile/analysis_options.yaml`
- `apps/web/src/api/projects.ts`
- `packages/contracts/README.md`

### 테스트 커버리지 공백

- Flutter home rendering: existing widget test only checks `nomadcode-app`; it must be updated.
- code-server launch: plugin/platform launch cannot be fully covered by widget test. Add unit/widget coverage through an injectable launcher callback; real platform launch remains manual/smoke.
- notification flows: out of scope and should keep existing behavior.

### 심볼 참조

- `MyHomePage` is referenced in `apps/mobile/lib/main.dart:55`.
- test imports `MyApp` from `apps/mobile/test/widget_test.dart:10`.
- React project mock fields are in `apps/web/src/api/projects.ts:3-15`; these can seed Flutter model fields but should not create a dependency on `apps/web`.

### 분할 판단

split decision policy를 먼저 평가했다. 이 task group은 세 subtask로 나뉜다.
- `01_react_retire`: independent.
- `02_contract_boundary`: independent.
- `03+02_app_workspace_surface`: depends on `02_contract_boundary`; implementation must not start until `agent-task/flutter_first_client_consolidation/02_contract_boundary/complete.log` exists.

### 범위 결정 근거

이 작업은 Flutter 앱에 최소 workspace surface와 direct code-server launch를 추가한다. React scaffold 삭제, core API 구현, OpenAPI generator, push notification redesign, native WebView embedding은 제외한다. code-server 자체나 terminal/editor를 Flutter native로 재구현하지 않는다.

### 빌드 등급

build lane: `cloud-G07`, review lane: `cloud-G07`. Flutter UI, dependency manifest, platform launch behavior가 얽히고 widget test coverage가 제한적이다.

## 의존 관계 및 구현 순서

이 subtask directory `03+02_app_workspace_surface`는 predecessor index `02`를 가진다. 구현 전 `agent-task/flutter_first_client_consolidation/02_contract_boundary/complete.log`가 있어야 한다.

## 구현 체크리스트

- [ ] `02_contract_boundary` complete.log 존재를 확인한다.
- [ ] Flutter project/workspace model과 mock seed를 `apps/mobile` 안에 만든다.
- [ ] `MyHomePage` placeholder를 project/workspace dashboard로 교체한다.
- [ ] code-server를 React wrapper 없이 직접 열 수 있는 launcher service를 추가한다.
- [ ] widget test를 Flutter-first 화면 기준으로 갱신한다.
- [ ] 중간 검증과 최종 검증을 실행한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REFACTOR-1] Flutter workspace model 추가

문제: Flutter 앱에는 project/workspace 모델이 없다. React mock에는 `apps/web/src/api/projects.ts:3-15`에 필요한 필드가 있으나, Flutter 앱이 `apps/web`에 의존하면 전환 목적과 충돌한다.

해결 방법: `apps/mobile/lib/models/project_workspace.dart`를 추가하고 `ProjectWorkspace`, `ProjectStatus`, `mockProjectWorkspaces`를 Flutter 안에 둔다. seed는 React mock을 복사하지 말고 NomadCode, IOP, proto-socket 같은 최소 예시로 재작성한다.

수정 파일 및 체크리스트:
- [ ] `apps/mobile/lib/models/project_workspace.dart`

테스트 작성: widget test에서 project name이 렌더링되는지 검증한다.

중간 검증:

```bash
cd apps/mobile && flutter test test/widget_test.dart
```

예상 결과: updated widget test 통과.

### [REFACTOR-2] Direct workspace launcher 추가

문제: React web은 `apps/web/src/api/projects.ts:81-83`에서 `window.open(project.codeServerUrl)`로 code-server를 연다. Flutter 앱에는 직접 launch 표면이 없다.

해결 방법: `apps/mobile/pubspec.yaml`에 `url_launcher`를 `flutter pub add url_launcher`로 추가하고, `apps/mobile/lib/services/workspace_launcher.dart`를 만든다. service는 `launchUrl(Uri.parse(project.codeServerUrl), mode: LaunchMode.externalApplication)`를 기본으로 사용한다. 테스트 가능하도록 UI에는 `Future<bool> Function(ProjectWorkspace)` callback을 주입할 수 있게 한다.

Before:

```dart
113   Widget build(BuildContext context) {
114     return Scaffold(
115       body: const Center(
116         child: Text('nomadcode-app'),
117       ),
118     );
119   }
```

After:

```dart
class WorkspaceLauncher {
  Future<bool> openCodeServer(ProjectWorkspace project) {
    return launchUrl(Uri.parse(project.codeServerUrl), mode: LaunchMode.externalApplication);
  }
}
```

수정 파일 및 체크리스트:
- [ ] `apps/mobile/pubspec.yaml`
- [ ] `apps/mobile/pubspec.lock`
- [ ] `apps/mobile/lib/services/workspace_launcher.dart`

테스트 작성: plugin call itself는 skip; UI callback injection으로 button tap이 launcher callback을 호출하는지 widget test 작성.

중간 검증:

```bash
cd apps/mobile && flutter pub get
cd apps/mobile && flutter test test/widget_test.dart
```

예상 결과: dependency resolve와 widget test 통과.

### [REFACTOR-3] Flutter-first home surface 교체

문제: `apps/mobile/lib/main.dart:49-55`는 `MaterialApp` home으로 `MyHomePage(title: 'nomadcode-app')`만 사용하고, `apps/mobile/lib/main.dart:113-118`은 텍스트 placeholder만 렌더링한다.

해결 방법: `MyHomePage`를 `WorkspaceHomePage`로 교체하거나 내부를 분리해 project list, selected project detail, code-server button, task/status placeholder를 표시한다. existing push notification snackbar listener는 유지한다. route/deep link 구조는 후속 Project Workspace Management UX로 넘긴다.

수정 파일 및 체크리스트:
- [ ] `apps/mobile/lib/main.dart`
- [ ] `apps/mobile/lib/screens/workspace_home_page.dart`
- [ ] `apps/mobile/test/widget_test.dart`

테스트 작성: `WorkspaceHomePage`가 app title, 최소 project name, code-server button을 렌더링하고 tap 시 injected launcher callback이 호출되는지 검증한다.

중간 검증:

```bash
cd apps/mobile && flutter test
cd apps/mobile && flutter analyze --no-fatal-infos
```

예상 결과: tests pass, analyzer는 기존 baseline의 `avoid_print` info 외 새 error가 없다.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `apps/mobile/lib/models/project_workspace.dart` | REFACTOR-1 |
| `apps/mobile/pubspec.yaml`, `apps/mobile/pubspec.lock` | REFACTOR-2 |
| `apps/mobile/lib/services/workspace_launcher.dart` | REFACTOR-2 |
| `apps/mobile/lib/main.dart` | REFACTOR-3 |
| `apps/mobile/lib/screens/workspace_home_page.dart` | REFACTOR-3 |
| `apps/mobile/test/widget_test.dart` | REFACTOR-1, REFACTOR-2, REFACTOR-3 |

## 최종 검증

```bash
test -f agent-task/flutter_first_client_consolidation/02_contract_boundary/complete.log
cd apps/mobile && flutter pub get
cd apps/mobile && flutter test
cd apps/mobile && flutter analyze --no-fatal-infos
rg --sort path -n "apps/web|window.open|nomadcode-web" apps/mobile/lib apps/mobile/test || true
```

예상 결과: dependency complete.log exists, pub get/test/analyze succeed, Flutter app source does not reference React web or `window.open`.

모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.
