<!-- task=mattermost_push_plugin_extraction/01_plugin_api plan=1 tag=REVIEW_API -->

# Mattermost Push Plugin API Review Follow-up Plan

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

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

## 배경

이전 리뷰에서 `01_plugin_api` 구현은 scaffold와 public Dart API를 만들었지만, 계획이 요구한 `token_refresh` 이벤트 테스트를 누락했다. `onDeviceTokenReady`는 host 앱이 push token을 서버에 등록하는 연결점이므로, native event parsing 테스트에 포함되어야 한다. 이번 후속 작업은 새 API 범위를 넓히지 않고 누락된 regression test만 닫는다.

## 분석 결과

### 읽은 파일

- `agent-task/mattermost_push_plugin_extraction/01_plugin_api/plan_cloud_G07_0.log`
- `agent-task/mattermost_push_plugin_extraction/01_plugin_api/code_review_cloud_G07_0.log`
- `../mattermost-push-plugin/lib/mattermost_push_plugin.dart`
- `../mattermost-push-plugin/lib/src/mattermost_push_plugin.dart`
- `../mattermost-push-plugin/lib/src/notification_opened_event.dart`
- `../mattermost-push-plugin/lib/src/push_notification_type.dart`
- `../mattermost-push-plugin/test/mattermost_push_plugin_test.dart`
- `../mattermost-push-plugin/pubspec.yaml`
- `../mattermost-push-plugin/analysis_options.yaml`

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

- `NotificationOpenedEvent.fromMap`: 기존 plugin test가 정상/기본값 경로를 검증한다.
- `message` + `userInteraction: true`: 기존 plugin test가 opened handler routing을 검증한다.
- `token_refresh` native event: 계획의 필수 테스트였지만 `../mattermost-push-plugin/test/mattermost_push_plugin_test.dart`에 없다.
- `saveDeviceToken` MethodChannel payload: token prefix 계약(`android_rn-v2:<token>`)이 callback과 함께 검증되지 않았다.

### 심볼 참조

- renamed/removed symbol: 없음.
- 관련 심볼:
  - `MattermostPushPlugin.handleNativeEvent`: `../mattermost-push-plugin/lib/src/mattermost_push_plugin.dart`
  - `PushNotificationType.tokenRefresh`: `../mattermost-push-plugin/lib/src/push_notification_type.dart`
  - `MattermostPushPlugin.actionChannelName`: `../mattermost-push-plugin/lib/src/mattermost_push_plugin.dart`

### 분할 판단

- split decision policy를 평가했다.
- 기존 multi-plan subtask `mattermost_push_plugin_extraction/01_plugin_api`의 review follow-up이며, 누락된 단위 테스트 1건만 처리한다.
- 새 subtask로 분리하면 기존 review loop 상태가 끊기므로 같은 subtask 디렉터리의 plan 1로 유지한다.

### 범위 결정 근거

- `../mattermost-push-plugin/test/mattermost_push_plugin_test.dart`에 regression test를 추가한다.
- production code는 테스트 가능성을 막는 문제가 실제로 확인될 때만 최소 수정한다. 우선 `TestDefaultBinaryMessengerBinding`의 MethodChannel mock으로 검증한다.
- Android/iOS/macOS native generated scaffold, host app call-site migration, README 상세 통합 문서는 이 follow-up 범위가 아니다.

### 빌드 등급

- Build lane: `cloud-G07`; review lane: `cloud-G07`. Public push API의 test coverage 실패를 닫는 follow-up이며 기존 route가 충분하다.

## 구현 체크리스트

- [ ] [REVIEW_API-1] `token_refresh` 이벤트가 device token 저장 payload와 `onDeviceTokenReady` 콜백을 검증하도록 plugin unit test를 보강한다.
- [ ] 중간 검증과 최종 검증 명령을 모두 실행하고 실제 출력을 `CODE_REVIEW-cloud-G07.md`에 붙여 넣는다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

### [REVIEW_API-1] Add token_refresh Regression Test

#### 문제

`plan_cloud_G07_0.log`는 `token_refresh` event가 `onDeviceTokenReady`를 호출하는 테스트를 요구했다. 현재 `../mattermost-push-plugin/test/mattermost_push_plugin_test.dart:34`의 `MattermostPushPlugin.handleNativeEvent` 그룹은 opened/message/clear 흐름만 검증하고, `../mattermost-push-plugin/lib/src/mattermost_push_plugin.dart:106`의 `PushNotificationType.tokenRefresh` branch를 검증하지 않는다.

#### 해결 방법

`test/mattermost_push_plugin_test.dart`에서 MethodChannel mock을 등록한 뒤 `handleNativeEvent`를 직접 호출한다.

Before:

```dart
group('MattermostPushPlugin.handleNativeEvent', () {
  late MattermostPushPlugin plugin;

  setUp(() {
    plugin = MattermostPushPlugin.instance;
    plugin.onNavigateToChannel = null;
    plugin.onNavigateToThread = null;
    plugin.onDeviceTokenReady = null;
  });
```

After:

```dart
import 'package:flutter/services.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  group('MattermostPushPlugin.handleNativeEvent', () {
    late MattermostPushPlugin plugin;
    final actionChannel = MethodChannel(
      MattermostPushPlugin.actionChannelName,
    );

    tearDown(() {
      TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
          .setMockMethodCallHandler(actionChannel, null);
    });
```

Add a test that:

- registers a mock handler for `saveDeviceToken`;
- captures `call.arguments['token']`;
- sets `plugin.onDeviceTokenReady`;
- calls `plugin.handleNativeEvent({'type': PushNotificationType.tokenRefresh, 'token': 'raw-token'})`;
- awaits the callback;
- asserts both the channel payload and callback token equal `android_rn-v2:raw-token`.

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

- [ ] `../mattermost-push-plugin/test/mattermost_push_plugin_test.dart`에 `package:flutter/services.dart` import 추가
- [ ] `TestWidgetsFlutterBinding.ensureInitialized()` 호출 추가
- [ ] `MattermostPushPlugin.actionChannelName` 기반 `MethodChannel` mock 등록/해제 추가
- [ ] `token_refresh` event가 `saveDeviceToken` payload와 `onDeviceTokenReady` callback을 모두 검증하는 test 추가

#### 테스트 작성

작성: `../mattermost-push-plugin/test/mattermost_push_plugin_test.dart`

- test name: `token_refresh event saves formatted device token and invokes callback`
- assertion goal: native event token이 `android_rn-v2:` prefix로 저장되고 동일 값이 callback에 전달되는지 검증한다.

#### 중간 검증

```bash
cd /config/workspace/mattermost-push-plugin && flutter test test/mattermost_push_plugin_test.dart
```

Expected: all plugin unit tests pass, including the new `token_refresh` regression test.

## 수정 파일 요약

| 파일 | 항목 |
|------|------|
| `../mattermost-push-plugin/test/mattermost_push_plugin_test.dart` | REVIEW_API-1 |
| `../mattermost-push-plugin/lib/src/mattermost_push_plugin.dart` | REVIEW_API-1, only if needed for testability |

## 최종 검증

```bash
cd /config/workspace/mattermost-push-plugin && dart format --output=none --set-exit-if-changed lib test
cd /config/workspace/mattermost-push-plugin && flutter analyze --no-fatal-infos
cd /config/workspace/mattermost-push-plugin && flutter test
```

Expected: all commands succeed. Cached test output is acceptable for this Dart-only regression test.

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