<!-- task=mattermost_push_plugin_extraction/03+01,02_host_consumer plan=1 tag=REVIEW_REFACTOR -->

# Host Consumer Review Follow-up Plan

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

이 계획은 `code_review_cloud_G07_0.log`의 FAIL Required 항목만 닫는다. 구현을 끝내기 전 `CODE_REVIEW-cloud-G07.md`의 구현 에이전트 소유 섹션을 반드시 채운다. 검증 명령을 실제로 실행하고 stdout/stderr를 붙여 넣은 뒤 active 파일을 그대로 둔 채 review ready를 보고한다. 최종 판정, log rename, `complete.log`, archive 이동은 code-review-skill 전용이다.

## 배경

host app은 `mattermost_push_plugin` consumer로 전환되었지만, 리뷰에서 notification tap/open event 전달과 dependency ownership, Android build 검증 신뢰가 닫히지 않았다고 판정했다. 이 follow-up은 새 기능 범위를 넓히지 않고 FAIL Required 3건만 수정한다.

## 빌드 등급

- Build lane: `cloud-G07`
- Review lane: `cloud-G07`
- 사유: Android Activity intent lifecycle, Flutter plugin EventChannel delivery, host dependency lockfile, Android debug build verification을 함께 다룬다.

## 구현 체크리스트

- [ ] [REVIEW_REFACTOR-1] plugin notification tap/open intent handling을 `singleTop` new intent와 EventChannel pending delivery까지 보강한다.
- [ ] [REVIEW_REFACTOR-2] host app의 unused `flutter_local_notifications` direct dependency와 generated registrant 잔여물을 제거한다.
- [ ] [REVIEW_REFACTOR-3] Android debug build 검증 신뢰를 회복하고 실제 stdout/stderr를 기록한다.
- [ ] 중간 검증과 최종 검증 명령을 모두 실행하고 실제 출력을 `CODE_REVIEW-cloud-G07.md`에 붙여 넣는다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## [REVIEW_REFACTOR-1] Notification tap/open intent delivery

### 문제

`apps/mobile/android/app/src/main/java/com/tokilabs/mattermost/MainActivity.kt`는 이제 host-only `FlutterActivity`다. 하지만 `../mattermost-push-plugin/android/src/main/kotlin/com/tokilabs/mattermost_push_plugin/MattermostPushPlugin.kt`는 `onAttachedToActivity`에서 현재 `activity.intent`만 즉시 전송한다. `singleTop` activity 재사용 시 들어오는 `onNewIntent`를 plugin이 듣지 않고, EventChannel sink가 아직 없을 때 payload를 보존하지 않아 notification tap/open event가 drop될 수 있다.

### 해결 방법

plugin 쪽으로 launch intent 책임을 완전히 이동한다.

- `MattermostPushPlugin.kt`에서 intent extras를 payload map으로 바꾸는 helper를 만든다.
- `ActivityPluginBinding.addOnNewIntentListener`를 등록하고 `onDetachedFromActivity*`에서 제거한다.
- initial intent와 new intent 모두 같은 helper를 사용한다.
- `PushNotificationEvents`는 `eventSink`가 null일 때 tap/open payload를 pending queue에 저장하고, `onListen`에서 flush한다.
- 같은 payload를 중복 flush하지 않도록 clear/cancel 경계를 명확히 둔다.

### 수정 파일 및 체크리스트

- [ ] `../mattermost-push-plugin/android/src/main/kotlin/com/tokilabs/mattermost_push_plugin/MattermostPushPlugin.kt`
- [ ] `../mattermost-push-plugin/android/src/main/kotlin/com/tokilabs/mattermost_push_plugin/PushNotificationEvents.kt`
- [ ] 필요 시 `../mattermost-push-plugin/android/src/test/kotlin/com/tokilabs/mattermost_push_plugin/**`에 pending delivery 단위 검증 추가

### 테스트 결정

가능하면 pending delivery queue는 Kotlin unit test로 확인한다. Android SDK가 없는 환경이면 test 실행 실패 stdout/stderr를 기록하되, source grep과 app build 검증으로 listener 등록 및 manifest merge 경계를 확인한다.

### 중간 검증

```bash
cd /config/workspace/nomadcode && rg --sort path "NewIntentListener|addOnNewIntentListener|removeOnNewIntentListener|pending|flush" ../mattermost-push-plugin/android/src/main/kotlin/com/tokilabs/mattermost_push_plugin
cd /config/workspace/mattermost-push-plugin && flutter test
```

Expected: new intent listener registration/removal and pending/flush logic are visible. Plugin Dart tests pass.

## [REVIEW_REFACTOR-2] Remove host local notification direct dependency

### 문제

`apps/mobile/pubspec.yaml` still declares `flutter_local_notifications` as a direct dependency even though host foreground notification implementation was deleted and plugin owns notification display. This also leaves generated registrant entries in the host runner.

### 해결 방법

Remove the direct dependency and regenerate dependency artifacts.

- Delete `flutter_local_notifications` from `apps/mobile/pubspec.yaml`.
- Run `flutter pub get` from `apps/mobile`.
- Keep transitive Firebase Messaging from `mattermost_push_plugin`; do not add host direct `firebase_messaging`.
- Confirm generated registrants no longer register `flutter_local_notifications` unless another host-owned feature explicitly requires it.

### 수정 파일 및 체크리스트

- [ ] `apps/mobile/pubspec.yaml`
- [ ] `apps/mobile/pubspec.lock`
- [ ] `apps/mobile/macos/Flutter/GeneratedPluginRegistrant.swift`
- [ ] Any other generated registrant touched by `flutter pub get`

### 테스트 결정

No new unit test is required; this is dependency ownership cleanup. Use `flutter pub get`, analyzer/test, and targeted `rg`.

### 중간 검증

```bash
cd /config/workspace/nomadcode/apps/mobile && flutter pub get
cd /config/workspace/nomadcode && rg --sort path "flutter_local_notifications|FlutterLocalNotifications" apps/mobile/pubspec.yaml apps/mobile/pubspec.lock apps/mobile/lib apps/mobile/test apps/mobile/android apps/mobile/ios apps/mobile/macos apps/mobile/linux apps/mobile/windows apps/mobile/web
```

Expected: `flutter pub get` succeeds. The `rg` command has no output and exits 1.

## [REVIEW_REFACTOR-3] Restore Android build verification trust

### 문제

`code_review_cloud_G07_0.log` records `flutter build apk --debug` failing with `[!] No Android SDK found`. The original plan required a successful Android debug build, so the extraction cannot PASS until this command is proven in a build-capable environment.

### 해결 방법

After REVIEW_REFACTOR-1 and REVIEW_REFACTOR-2, rerun the exact app verification commands. Do not replace the Android build command. If the current environment still lacks Android SDK, record exact stdout/stderr and clearly state that PASS remains blocked by build environment.

### 수정 파일 및 체크리스트

- [ ] `CODE_REVIEW-cloud-G07.md` verification output records the fresh command output
- [ ] Android debug build command succeeds in an SDK-enabled environment before reporting ready for PASS review

### 테스트 결정

No new test file is needed for this item. It exists to recover verification trust.

### 중간 검증

```bash
cd /config/workspace/nomadcode/apps/mobile && flutter build apk --debug
```

Expected: exit 0 in an Android SDK-enabled environment.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `../mattermost-push-plugin/android/src/main/kotlin/com/tokilabs/mattermost_push_plugin/MattermostPushPlugin.kt` | REVIEW_REFACTOR-1 |
| `../mattermost-push-plugin/android/src/main/kotlin/com/tokilabs/mattermost_push_plugin/PushNotificationEvents.kt` | REVIEW_REFACTOR-1 |
| `../mattermost-push-plugin/android/src/test/kotlin/com/tokilabs/mattermost_push_plugin/**` | REVIEW_REFACTOR-1 |
| `apps/mobile/pubspec.yaml` | REVIEW_REFACTOR-2 |
| `apps/mobile/pubspec.lock` | REVIEW_REFACTOR-2 |
| `apps/mobile/**/GeneratedPluginRegistrant.*` | REVIEW_REFACTOR-2 |
| `CODE_REVIEW-cloud-G07.md` | REVIEW_REFACTOR-3 |

## 리뷰어를 위한 체크포인트

- plugin, not host `MainActivity`, owns initial and `singleTop` notification tap/open intent delivery.
- Pending notification open payloads are not lost before Dart subscribes to EventChannel.
- `apps/mobile` has no direct `flutter_local_notifications` ownership left.
- Android debug build output is fresh and successful before PASS.

## 최종 검증

```bash
cd /config/workspace/nomadcode/apps/mobile && flutter pub get
cd /config/workspace/mattermost-push-plugin && flutter test
cd /config/workspace/nomadcode/apps/mobile && dart format --output=none --set-exit-if-changed lib test
cd /config/workspace/nomadcode/apps/mobile && flutter analyze --no-fatal-infos
cd /config/workspace/nomadcode/apps/mobile && flutter test
cd /config/workspace/nomadcode/apps/mobile && flutter build apk --debug
cd /config/workspace/nomadcode && rg --sort path "PushNotificationService|push_notification_service|MattermostFirebaseMessagingService|NotificationReplyBroadcastReceiver|NotificationDismissService|ReceiptDelivery|PushNotificationDataHelper" apps/mobile/lib apps/mobile/android/app/src/main/java apps/mobile/test
cd /config/workspace/nomadcode && rg --sort path "flutter_local_notifications|FlutterLocalNotifications" apps/mobile/pubspec.yaml apps/mobile/pubspec.lock apps/mobile/lib apps/mobile/test apps/mobile/android apps/mobile/ios apps/mobile/macos apps/mobile/linux apps/mobile/windows apps/mobile/web
```

Expected: first six commands succeed. The two final `rg` commands produce no output and exit 1. Record actual stdout/stderr and exit codes. Android build must be freshly run in an environment with Android SDK.

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