From 7d291aa90ce3ad7dfa46111bb69e80525a24e56b Mon Sep 17 00:00:00 2001 From: toki Date: Thu, 28 May 2026 20:08:15 +0900 Subject: [PATCH] feat: client-validation task and update READMEs - Add m-client-validation task directory - Update apps/flutter-test/README.md - Update packages/messaging_flutter/README.md - Update packages/messaging_flutter/docs/android-test-environment.md --- .../01_docs_boundary/CODE_REVIEW-local-G04.md | 171 ++++++++++++++ .../01_docs_boundary/PLAN-local-G04.md | 188 ++++++++++++++++ .../CODE_REVIEW-cloud-G05.md | 133 +++++++++++ .../PLAN-cloud-G05.md | 166 ++++++++++++++ .../CODE_REVIEW-cloud-G07.md | 148 +++++++++++++ .../PLAN-cloud-G07.md | 209 ++++++++++++++++++ apps/flutter-test/README.md | 14 +- packages/messaging_flutter/README.md | 30 ++- .../docs/android-test-environment.md | 17 ++ 9 files changed, 1071 insertions(+), 5 deletions(-) create mode 100644 agent-task/m-client-validation/01_docs_boundary/CODE_REVIEW-local-G04.md create mode 100644 agent-task/m-client-validation/01_docs_boundary/PLAN-local-G04.md create mode 100644 agent-task/m-client-validation/02+01_flutter_contract_tests/CODE_REVIEW-cloud-G05.md create mode 100644 agent-task/m-client-validation/02+01_flutter_contract_tests/PLAN-cloud-G05.md create mode 100644 agent-task/m-client-validation/03+01,02_android_native_validation/CODE_REVIEW-cloud-G07.md create mode 100644 agent-task/m-client-validation/03+01,02_android_native_validation/PLAN-cloud-G07.md diff --git a/agent-task/m-client-validation/01_docs_boundary/CODE_REVIEW-local-G04.md b/agent-task/m-client-validation/01_docs_boundary/CODE_REVIEW-local-G04.md new file mode 100644 index 00000000..75360dc7 --- /dev/null +++ b/agent-task/m-client-validation/01_docs_boundary/CODE_REVIEW-local-G04.md @@ -0,0 +1,171 @@ + + +# Code Review Reference - DOCS + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a user-only decision, external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume. +> Follow the ownership table at the bottom of this file for which sections you own. + +## 개요 + +date=2026-05-28 +task=m-client-validation/01_docs_boundary, plan=0, tag=DOCS + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. +리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다. + +1. 판정을 append한다. +2. `CODE_REVIEW-local-G04.md` -> `code_review_local_G04_0.log`, `PLAN-local-G04.md` -> `plan_local_G04_0.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-client-validation/01_docs_boundary/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. +4. PASS이고 task group이 `m-client-validation`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. +5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [DOCS-1] flutter-test README 경계 보강 | [x] | +| [DOCS-2] plugin README SDK 경계와 smoke runbook 보강 | [x] | +| [DOCS-3] Android test environment guide 보강 | [x] | + +## 구현 체크리스트 + +- [x] [DOCS-1] `apps/flutter-test/README.md`에 thin host 책임, plugin-owned SDK boundary, remote Android guide 연결을 명확히 한다. +- [x] [DOCS-2] `packages/messaging_flutter/README.md`에 nexo-owned embedded SDK 경계와 manual FCM/ACK smoke runbook의 사전조건/증거를 보강한다. +- [x] [DOCS-3] `packages/messaging_flutter/docs/android-test-environment.md`가 local Android SDK 없음, remote emulator, Gradle unit test 실패 조건을 분명히 설명하게 한다. +- [x] `rg --sort path -n "nexo product app|manual Firebase FCM|nexo-owned|android-test-environment|testDebugUnitTest|flutter test integration_test" apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md`로 문서 기준선 문구를 확인한다. +- [x] `git diff --check -- apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md`를 통과시킨다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. +> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] active `CODE_REVIEW-*-G??.md`를 `code_review_local_G04_0.log`로 아카이브한다. +- [ ] active `PLAN-*-G??.md`를 `plan_local_G04_0.log`로 아카이브한다. +- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [ ] PASS이면 active task 디렉터리 `agent-task/m-client-validation/01_docs_boundary/`를 `agent-task/archive/YYYY/MM/m-client-validation/01_docs_boundary/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [ ] PASS이고 task group이 `m-client-validation`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-client-validation/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-local-G04.md`와 `CODE_REVIEW-local-G04.md`를 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다. +- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. + +## 계획 대비 변경 사항 + +없음. + +## 주요 설계 결정 + +- `apps/flutter-test` README에는 앱이 plugin API consumer/verification host임을 추가하고, native push/ACK/storage/rendering은 `packages/messaging_flutter` 소유로 남겼다. +- `packages/messaging_flutter` README에는 nexo-owned embedded SDK 경계를 별도 섹션으로 두고, Mattermost mobile app source를 팔로잉하지 않는다는 기준을 명시했다. +- manual FCM/ACK smoke는 자동 테스트가 아니라 외부 Firebase/server 인프라가 필요한 checklist로 유지하고, prerequisites/evidence만 보강했다. + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 외부 환경 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. code-review가 이 내용을 검증해 `USER_REVIEW.md`를 작성한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- 문서가 `apps/flutter-test`를 제품 앱으로 확장하지 않는지 확인한다. +- SDK boundary가 Mattermost mobile app code following과 혼동되지 않는지 확인한다. +- manual FCM/ACK smoke가 자동 검증과 명확히 분리되었는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +### DOCS-1 중간 검증 + +```sh +$ rg --sort path -n "plugin API consumer|source of truth|android-test-environment" apps/flutter-test/README.md +21:The app is a plugin API consumer and verification host. Native push handling, +81:[`../../packages/messaging_flutter/docs/android-test-environment.md`](../../packages/messaging_flutter/docs/android-test-environment.md). +``` + +### DOCS-2 중간 검증 + +```sh +$ rg --sort path -n "nexo-owned|Mattermost mobile|Prerequisites|Evidence" packages/messaging_flutter/README.md +13:This package is the nexo-owned embedded messaging SDK. Its Android +16:the Mattermost mobile app source tree; that app remains under `apps/mattermost/` +252:Prerequisites: +261:Evidence to capture: +``` + +### DOCS-3 중간 검증 + +```sh +$ rg --sort path -n "SDK location not found|ANDROID_HOME|sdk.dir|remote" packages/messaging_flutter/docs/android-test-environment.md +14:Use these environment variables for every remote Android test session: +18:export ANDROID_HOME="$HOME/Library/Android/sdk" +19:export ANDROID_SDK_ROOT="$ANDROID_HOME" +24:Before using the remote host, check whether the local machine already has the +34:`./gradlew testDebugUnitTest` requires either `ANDROID_HOME`/`ANDROID_SDK_ROOT` +35:or a valid `sdk.dir` entry in `apps/flutter-test/android/local.properties`. If +36:the command fails with `SDK location not found`, treat it as a local environment +37:blocker and use the remote flow below instead of changing repository files. +42:remote directory. This is useful when local changes are not committed yet. +69:export ANDROID_HOME="$HOME/Library/Android/sdk" +70:export ANDROID_SDK_ROOT="$ANDROID_HOME" +``` + +### 최종 검증 + +```sh +$ rg --sort path -n "plugin API consumer|source of truth|nexo-owned|Mattermost mobile|Prerequisites|Evidence|SDK location not found|ANDROID_HOME|sdk.dir" apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md +apps/flutter-test/README.md:21:The app is a plugin API consumer and verification host. Native push handling, +apps/flutter-test/README.md:74:Android Gradle tests require a configured Android SDK through `ANDROID_HOME`, +packages/messaging_flutter/README.md:13:This package is the nexo-owned embedded messaging SDK. Its Android +packages/messaging_flutter/README.md:16:the Mattermost mobile app source tree; that app remains under `apps/mattermost/` +packages/messaging_flutter/README.md:194:Android Gradle tests require a configured Android SDK through `ANDROID_HOME` or +packages/messaging_flutter/README.md:232:Use the repository tests as the source of truth for plugin behavior: +packages/messaging_flutter/README.md:252:Prerequisites: +packages/messaging_flutter/README.md:261:Evidence to capture: +packages/messaging_flutter/docs/android-test-environment.md:18:export ANDROID_HOME="$HOME/Library/Android/sdk" +packages/messaging_flutter/docs/android-test-environment.md:19:export ANDROID_SDK_ROOT="$ANDROID_HOME" +packages/messaging_flutter/docs/android-test-environment.md:34:`./gradlew testDebugUnitTest` requires either `ANDROID_HOME`/`ANDROID_SDK_ROOT` +packages/messaging_flutter/docs/android-test-environment.md:35:or a valid `sdk.dir` entry in `apps/flutter-test/android/local.properties`. If +packages/messaging_flutter/docs/android-test-environment.md:36:the command fails with `SDK location not found`, treat it as a local environment +$ git diff --check -- apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md +(no output) +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** +> If anything is blank, go back and fill it in before saving this file. +> Leave review-agent-only sections unchanged. + +Sections and their ownership: + +| Section | Owner | Note | +|---------|-------|------| +| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these | +| 구현 항목별 완료 여부 | Fixed at stub creation | Implementing agent checks `[ ]` -> `[x]` only | +| 구현 체크리스트 | Fixed at stub creation from plan | Implementing agent checks `[ ]` -> `[x]` only | +| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section | +| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content | +| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required | +| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan | +| 검증 결과 | Fixed headings and commands | Implementing agent fills command output only | diff --git a/agent-task/m-client-validation/01_docs_boundary/PLAN-local-G04.md b/agent-task/m-client-validation/01_docs_boundary/PLAN-local-G04.md new file mode 100644 index 00000000..1f34e6c8 --- /dev/null +++ b/agent-task/m-client-validation/01_docs_boundary/PLAN-local-G04.md @@ -0,0 +1,188 @@ + + +# Plan - DOCS + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 명령 출력, 계획 대비 변경 사항을 채운 뒤 active 파일을 그대로 둔 채 리뷰 준비 상태로 보고한다. 최종 판정, 로그 rename, `complete.log`, archive 이동은 code-review 스킬 전용이다. 사용자만 결정할 수 있는 사항, 외부 환경 준비, 범위 충돌로 막히면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 결정 필요 사항과 근거를 채우고 멈춘다. + +## 배경 + +현재 Milestone은 `apps/flutter-test`를 제품 앱이 아닌 얇은 플러그인 검증 호스트로 고정해야 한다. README들은 이미 방향을 담고 있지만, SDK ownership boundary와 수동 FCM/ACK smoke runbook이 한눈에 이어지지 않는다. 먼저 문서 기준선을 정리해야 후속 테스트 작업이 범위를 넓히지 않는다. + +## 사용자 리뷰 요청 흐름 + +구현 중 blocker는 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 섹션 형식은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`와 같으며, code-review가 검증 후 실제 `USER_REVIEW.md` 작성 여부를 결정한다. + +## 분석 결과 + +### 읽은 파일 + +- `agent-roadmap/current.md` +- `agent-roadmap/phase/product-foundation/PHASE.md` +- `agent-roadmap/phase/product-foundation/milestones/client-validation.md` +- `agent-ops/rules/project/domain/client-app/rules.md` +- `agent-ops/rules/project/domain/messaging-flutter/rules.md` +- `agent-ops/rules/project/domain/workspace-ops/rules.md` +- `apps/flutter-test/README.md` +- `packages/messaging_flutter/README.md` +- `packages/messaging_flutter/docs/android-test-environment.md` +- `apps/flutter-test/lib/main.dart` +- `apps/flutter-test/test/widget_test.dart` +- `apps/flutter-test/integration_test/plugin_integration_test.dart` +- `packages/messaging_flutter/lib/nexo_messaging.dart` +- `packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart` +- `packages/messaging_flutter/lib/src/notification_opened_event.dart` +- `packages/messaging_flutter/lib/src/push_notification_type.dart` +- `packages/messaging_flutter/test/nexo_messaging_test.dart` +- `apps/flutter-test/pubspec.yaml` +- `packages/messaging_flutter/pubspec.yaml` + +### 테스트 커버리지 공백 + +- 문서 기준선 변경: 자동 테스트는 직접 커버하지 않는다. `rg --sort path` 검색과 `git diff --check`로 링크/용어 회귀를 확인한다. +- SDK ownership boundary 설명: 기존 Dart/widget/integration 테스트가 동작 자체를 커버하지만 README 문구 자체는 테스트하지 않는다. +- FCM/ACK manual smoke runbook: 외부 Firebase/server 인프라가 필요해 자동화하지 않는다. + +### 심볼 참조 + +- 변경/삭제할 심볼 없음. +- 확인한 관련 참조: `rg --sort path -n "android-test-environment|google-services|ACK|Manual Smoke|testDebugUnitTest|flutter test integration_test" apps/flutter-test packages/messaging_flutter`. + +### 분할 판단 + +- split decision policy를 plan 파일 선택 전에 평가했다. +- 공유 task group: `agent-task/m-client-validation`. +- 이 subtask: `01_docs_boundary`, 선행 없음. +- 후속: `02+01_flutter_contract_tests`는 문서 기준선 후 테스트 계약을 보강한다. `03+01,02_android_native_validation`은 문서와 Flutter 계약 테스트 후 Android/원격 검증을 정리한다. + +### 범위 결정 근거 + +- `apps/mattermost/**`, `services/**`는 이 Milestone의 client validation 범위가 아니므로 제외한다. +- `apps/flutter-test`를 제품 UI로 확장하지 않는다. README 문구와 문서 링크만 정리한다. +- `docs/` root에는 환경별 host/token/runbook을 두지 않는 private rule 때문에 새 root docs를 만들지 않는다. + +### 빌드 등급 + +- build=`local-G04`, review=`local-G04`. 문서 중심이고 자동 검증은 검색/공백 검사지만, 두 도메인 README를 연결하므로 G04로 둔다. + +## 구현 체크리스트 + +- [ ] [DOCS-1] `apps/flutter-test/README.md`에 thin host 책임, plugin-owned SDK boundary, remote Android guide 연결을 명확히 한다. +- [ ] [DOCS-2] `packages/messaging_flutter/README.md`에 nexo-owned embedded SDK 경계와 manual FCM/ACK smoke runbook의 사전조건/증거를 보강한다. +- [ ] [DOCS-3] `packages/messaging_flutter/docs/android-test-environment.md`가 local Android SDK 없음, remote emulator, Gradle unit test 실패 조건을 분명히 설명하게 한다. +- [ ] `rg --sort path -n "nexo product app|manual Firebase FCM|nexo-owned|android-test-environment|testDebugUnitTest|flutter test integration_test" apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md`로 문서 기준선 문구를 확인한다. +- [ ] `git diff --check -- apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md`를 통과시킨다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +### [DOCS-1] flutter-test README 경계 보강 + +#### 문제 + +[apps/flutter-test/README.md](/config/workspace/nexo/apps/flutter-test/README.md:7)는 test harness 경계를 설명하지만 SDK ownership boundary와 manual smoke owner가 분리되어 보이지 않는다. + +Before: + +```markdown +7 This app is the workspace test harness for `packages/messaging_flutter`. Keep it +8 small and focused on proving the messaging/notification package contract: +``` + +#### 해결 방법 + +`Purpose` 뒤에 이 앱은 plugin API 소비자이며 native push/ACK/storage source of truth는 `packages/messaging_flutter`라는 문장을 추가한다. `Verification`에는 local에서 device가 없으면 integration test가 실패할 수 있고 remote guide를 쓰라는 연결을 더 직접적으로 둔다. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/flutter-test/README.md` + +#### 테스트 작성 + +문서 변경이라 테스트 파일은 추가하지 않는다. + +#### 중간 검증 + +```sh +rg --sort path -n "plugin API consumer|source of truth|android-test-environment" apps/flutter-test/README.md +``` + +### [DOCS-2] plugin README SDK 경계와 smoke runbook 보강 + +#### 문제 + +[packages/messaging_flutter/README.md](/config/workspace/nexo/packages/messaging_flutter/README.md:6)는 plugin이 push domain을 소유한다고 설명하지만, Mattermost mobile code를 팔로잉하지 않는 nexo-owned embedded SDK 경계는 명시적이지 않다. [packages/messaging_flutter/README.md](/config/workspace/nexo/packages/messaging_flutter/README.md:238)의 manual checklist도 사전조건과 증거 형식이 부족하다. + +Before: + +```markdown +6 The plugin owns the push-notification domain that should not be duplicated in +7 each consuming app: native FCM handling, notification display, notification tap +8 events, inline replies, dismiss handling, ACK delivery, device-token storage, +9 auth-token storage, and server signing-key storage. +``` + +#### 해결 방법 + +`Platform Status` 전후에 SDK ownership boundary를 추가한다. `Manual Smoke Checklist`를 유지하되 `Prerequisites`와 `Evidence to capture`를 더해 Firebase config, server URL/auth/signing key, logcat/notification/ACK evidence를 기록하게 한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `packages/messaging_flutter/README.md` + +#### 테스트 작성 + +문서 변경이라 테스트 파일은 추가하지 않는다. + +#### 중간 검증 + +```sh +rg --sort path -n "nexo-owned|Mattermost mobile|Prerequisites|Evidence" packages/messaging_flutter/README.md +``` + +### [DOCS-3] Android test environment guide 보강 + +#### 문제 + +[packages/messaging_flutter/docs/android-test-environment.md](/config/workspace/nexo/packages/messaging_flutter/docs/android-test-environment.md:73)는 remote check 명령을 제공하지만, local failure mode와 Gradle SDK precondition이 README와 같은 언어로 연결되지 않는다. 현재 local `./gradlew testDebugUnitTest`는 `SDK location not found`로 실패했다. + +Before: + +```markdown +73 ## Run The Checks +75 Run the deterministic Flutter checks: +``` + +#### 해결 방법 + +`Run The Checks` 앞에 local preflight와 expected fallback을 추가한다. `flutter doctor -v`, `ANDROID_HOME`, `local.properties sdk.dir` 확인을 넣고, local Android SDK가 없으면 remote run이 source of truth임을 적는다. + +#### 수정 파일 및 체크리스트 + +- [ ] `packages/messaging_flutter/docs/android-test-environment.md` + +#### 테스트 작성 + +문서 변경이라 테스트 파일은 추가하지 않는다. + +#### 중간 검증 + +```sh +rg --sort path -n "SDK location not found|ANDROID_HOME|sdk.dir|remote" packages/messaging_flutter/docs/android-test-environment.md +``` + +## 수정 파일 요약 + +| 파일 | 항목 | +| --- | --- | +| `apps/flutter-test/README.md` | DOCS-1 | +| `packages/messaging_flutter/README.md` | DOCS-2 | +| `packages/messaging_flutter/docs/android-test-environment.md` | DOCS-3 | + +## 최종 검증 + +```sh +rg --sort path -n "plugin API consumer|source of truth|nexo-owned|Mattermost mobile|Prerequisites|Evidence|SDK location not found|ANDROID_HOME|sdk.dir" apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md +git diff --check -- apps/flutter-test/README.md packages/messaging_flutter/README.md packages/messaging_flutter/docs/android-test-environment.md +``` + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-client-validation/02+01_flutter_contract_tests/CODE_REVIEW-cloud-G05.md b/agent-task/m-client-validation/02+01_flutter_contract_tests/CODE_REVIEW-cloud-G05.md new file mode 100644 index 00000000..9aa2184c --- /dev/null +++ b/agent-task/m-client-validation/02+01_flutter_contract_tests/CODE_REVIEW-cloud-G05.md @@ -0,0 +1,133 @@ + + +# Code Review Reference - TEST + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a user-only decision, external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume. +> Follow the ownership table at the bottom of this file for which sections you own. + +## 개요 + +date=2026-05-28 +task=m-client-validation/02+01_flutter_contract_tests, plan=0, tag=TEST + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. +리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다. + +1. 판정을 append한다. +2. `CODE_REVIEW-cloud-G05.md` -> `code_review_cloud_G05_0.log`, `PLAN-cloud-G05.md` -> `plan_cloud_G05_0.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-client-validation/02+01_flutter_contract_tests/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. +4. PASS이고 task group이 `m-client-validation`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. +5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [TEST-1] integration test exact contract 보강 | [ ] | +| [TEST-2] local Dart/widget 계약 보강 | [ ] | + +## 구현 체크리스트 + +- [ ] [TEST-1] `apps/flutter-test/integration_test/plugin_integration_test.dart`가 notification/action channel constants와 exact opened-routing UI state를 검증하게 보강한다. +- [ ] [TEST-2] `apps/flutter-test/test/widget_test.dart` 또는 `packages/messaging_flutter/test/nexo_messaging_test.dart`에 integration에서 device 때문에 못 보는 계약을 local test로 보강한다. +- [ ] `flutter test`를 `packages/messaging_flutter`에서 실행해 package Dart contract가 통과함을 기록한다. +- [ ] `flutter test`를 `apps/flutter-test`에서 실행해 thin host widget test가 통과함을 기록한다. +- [ ] `flutter test integration_test`를 `apps/flutter-test`에서 실행한다. device 없음이면 실제 실패 출력을 기록하고, remote/device 검증은 후속 `03+01,02_android_native_validation`에 남긴다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. +> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G05_0.log`로 아카이브한다. +- [ ] active `PLAN-*-G??.md`를 `plan_cloud_G05_0.log`로 아카이브한다. +- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [ ] PASS이면 active task 디렉터리 `agent-task/m-client-validation/02+01_flutter_contract_tests/`를 `agent-task/archive/YYYY/MM/m-client-validation/02+01_flutter_contract_tests/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [ ] PASS이고 task group이 `m-client-validation`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-client-validation/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G05.md`와 `CODE_REVIEW-cloud-G05.md`를 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다. +- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 외부 환경 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. code-review가 이 내용을 검증해 `USER_REVIEW.md`를 작성한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- `01_docs_boundary` complete dependency가 충족된 뒤 구현되었는지 확인한다. +- integration test가 exact opened state를 검증하되 product UI를 늘리지 않았는지 확인한다. +- local test 보강이 integration gap을 정직하게 줄이는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +### TEST-1 중간 검증 + +```sh +$ flutter test integration_test +``` + +### TEST-2 중간 검증 + +```sh +$ cd packages/messaging_flutter && flutter test +$ cd apps/flutter-test && flutter test +``` + +### 최종 검증 + +```sh +$ cd packages/messaging_flutter && flutter test +$ cd apps/flutter-test && flutter test +$ cd apps/flutter-test && flutter test integration_test +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** +> If anything is blank, go back and fill it in before saving this file. +> Leave review-agent-only sections unchanged. + +Sections and their ownership: + +| Section | Owner | Note | +|---------|-------|------| +| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these | +| 구현 항목별 완료 여부 | Fixed at stub creation | Implementing agent checks `[ ]` -> `[x]` only | +| 구현 체크리스트 | Fixed at stub creation from plan | Implementing agent checks `[ ]` -> `[x]` only | +| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section | +| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content | +| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required | +| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan | +| 검증 결과 | Fixed headings and commands | Implementing agent fills command output only | diff --git a/agent-task/m-client-validation/02+01_flutter_contract_tests/PLAN-cloud-G05.md b/agent-task/m-client-validation/02+01_flutter_contract_tests/PLAN-cloud-G05.md new file mode 100644 index 00000000..bda1f5b5 --- /dev/null +++ b/agent-task/m-client-validation/02+01_flutter_contract_tests/PLAN-cloud-G05.md @@ -0,0 +1,166 @@ + + +# Plan - TEST + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 명령 출력, 계획 대비 변경 사항을 채운 뒤 active 파일을 그대로 둔 채 리뷰 준비 상태로 보고한다. 최종 판정, 로그 rename, `complete.log`, archive 이동은 code-review 스킬 전용이다. 사용자만 결정할 수 있는 사항, 외부 환경 준비, 범위 충돌로 막히면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 결정 필요 사항과 근거를 채우고 멈춘다. + +## 배경 + +`apps/flutter-test`의 Dart widget test와 integration test는 plugin registration, method channel, event channel, opened-routing 경로를 보호해야 한다. 현재 unit/widget 테스트는 통과하지만 integration test는 local Android device/emulator가 없어 실행되지 않는다. 이 subtask는 device-dependent integration test를 더 결정적으로 만들고 local에서 가능한 테스트 계약을 보강한다. + +## 사용자 리뷰 요청 흐름 + +구현 중 blocker는 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 섹션 형식은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`와 같으며, code-review가 검증 후 실제 `USER_REVIEW.md` 작성 여부를 결정한다. + +## 분석 결과 + +### 읽은 파일 + +- `apps/flutter-test/lib/main.dart` +- `apps/flutter-test/test/widget_test.dart` +- `apps/flutter-test/integration_test/plugin_integration_test.dart` +- `apps/flutter-test/pubspec.yaml` +- `packages/messaging_flutter/lib/nexo_messaging.dart` +- `packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart` +- `packages/messaging_flutter/lib/src/notification_opened_event.dart` +- `packages/messaging_flutter/lib/src/push_notification_type.dart` +- `packages/messaging_flutter/test/nexo_messaging_test.dart` +- `packages/messaging_flutter/pubspec.yaml` +- `packages/messaging_flutter/README.md` +- `apps/flutter-test/README.md` + +### 테스트 커버리지 공백 + +- plugin registration constant: integration test checks `notificationChannelName` only; `actionChannelName` is only checked in package unit test. +- event-channel opened-routing: integration test checks text contains IDs but not exact `Last opened` state. +- method-channel debug event: package unit test checks Dart method invocation; integration test checks native route via `debugSendNativeEventForTesting`. +- local environment gap: `flutter test integration_test` currently fails with no supported Android device. This is environment-dependent and must be recorded, not hidden. + +### 심볼 참조 + +- 변경/삭제할 심볼 없음. +- 관련 참조는 `rg --sort path -n "debugSendNativeEvent|listenNativeChannelForTesting|notificationChannelName|actionChannelName|handleNativeEvent" apps/flutter-test packages/messaging_flutter`로 확인했다. + +### 분할 판단 + +- split decision policy를 plan 파일 선택 전에 평가했다. +- shared task group: `agent-task/m-client-validation`. +- predecessor: `01_docs_boundary` must produce `complete.log` first because it fixes the test-host scope and verification wording. +- this subtask: `02+01_flutter_contract_tests`. +- dependent sibling: `03+01,02_android_native_validation` waits for this because it will rely on the finalized Flutter contract test shape. + +### 범위 결정 근거 + +- Native Kotlin/JVM test changes are excluded here and handled by `03+01,02_android_native_validation`. +- No public Dart API rename or package identifier change is allowed in this Milestone subtask. +- No product UI is added to `apps/flutter-test`. + +### 빌드 등급 + +- build=`cloud-G05`, review=`cloud-G05`. The code change is small, but integration verification is device-dependent and local tests do not fully cover the behavior. + +## 의존 관계 및 구현 순서 + +- Runtime dependency from directory name: wait for `agent-task/m-client-validation/01_docs_boundary/complete.log`. +- Do not start this subtask until the predecessor has PASS completion. + +## 구현 체크리스트 + +- [ ] [TEST-1] `apps/flutter-test/integration_test/plugin_integration_test.dart`가 notification/action channel constants와 exact opened-routing UI state를 검증하게 보강한다. +- [ ] [TEST-2] `apps/flutter-test/test/widget_test.dart` 또는 `packages/messaging_flutter/test/nexo_messaging_test.dart`에 integration에서 device 때문에 못 보는 계약을 local test로 보강한다. +- [ ] `flutter test`를 `packages/messaging_flutter`에서 실행해 package Dart contract가 통과함을 기록한다. +- [ ] `flutter test`를 `apps/flutter-test`에서 실행해 thin host widget test가 통과함을 기록한다. +- [ ] `flutter test integration_test`를 `apps/flutter-test`에서 실행한다. device 없음이면 실제 실패 출력을 기록하고, remote/device 검증은 후속 `03+01,02_android_native_validation`에 남긴다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +### [TEST-1] integration test exact contract 보강 + +#### 문제 + +[apps/flutter-test/integration_test/plugin_integration_test.dart](/config/workspace/nexo/apps/flutter-test/integration_test/plugin_integration_test.dart:10)는 singleton과 notification channel만 확인한다. [apps/flutter-test/integration_test/plugin_integration_test.dart](/config/workspace/nexo/apps/flutter-test/integration_test/plugin_integration_test.dart:32)는 `find.textContaining` 위주라 opened state regression을 덜 정확히 잡는다. + +Before: + +```dart +10 testWidgets('singleton instance is accessible', (WidgetTester tester) async { +11 expect(NexoMessagingPlugin.instance, isNotNull); +12 expect( +13 NexoMessagingPlugin.notificationChannelName, +14 'com.tokilabs.nexo.messaging/notifications', +15 ); +16 }); +``` + +#### 해결 방법 + +`actionChannelName` assertion을 추가한다. channel/thread integration tests에는 exact `Last opened: ...` assertion을 추가하되 existing navigation assertions는 유지한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/flutter-test/integration_test/plugin_integration_test.dart` + +#### 테스트 작성 + +기존 integration test를 보강한다. 새 파일은 만들지 않는다. + +#### 중간 검증 + +```sh +flutter test integration_test +``` + +예상: local Android device/emulator가 없으면 현재처럼 "No supported devices connected"로 실패할 수 있다. 그 경우 출력 전체를 review stub에 기록한다. + +### [TEST-2] local Dart/widget 계약 보강 + +#### 문제 + +[packages/messaging_flutter/test/nexo_messaging_test.dart](/config/workspace/nexo/packages/messaging_flutter/test/nexo_messaging_test.dart:192)는 channel constants를 커버하지만 `apps/flutter-test/test/widget_test.dart`는 debug/native event path 대신 direct `handleNativeEvent`만 본다. device 없는 환경에서 integration gap을 보완할 local assertion이 더 필요하다. + +Before: + +```dart +192 group('Channel constants', () { +193 test('notification and action channel names are preserved', () { +``` + +#### 해결 방법 + +가능하면 existing local tests에 small assertion을 추가한다. 예: widget test initial state가 product-like controls 없이 status text만 렌더링하는 thin host임을 확인하거나 package unit test에 `message` without `userInteraction` does not navigate assertion을 추가한다. 새 public API는 만들지 않는다. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/flutter-test/test/widget_test.dart` 또는 `packages/messaging_flutter/test/nexo_messaging_test.dart` + +#### 테스트 작성 + +기존 test file에 regression assertion을 추가한다. + +#### 중간 검증 + +```sh +cd packages/messaging_flutter && flutter test +cd apps/flutter-test && flutter test +``` + +## 수정 파일 요약 + +| 파일 | 항목 | +| --- | --- | +| `apps/flutter-test/integration_test/plugin_integration_test.dart` | TEST-1 | +| `apps/flutter-test/test/widget_test.dart` | TEST-2 | +| `packages/messaging_flutter/test/nexo_messaging_test.dart` | TEST-2 | + +## 최종 검증 + +```sh +cd packages/messaging_flutter && flutter test +cd apps/flutter-test && flutter test +cd apps/flutter-test && flutter test integration_test +``` + +`flutter test integration_test`가 local device 부재로 실패하면 그 실제 출력을 기록하고, remote/device 재검증은 `03+01,02_android_native_validation`에서 수행한다. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-client-validation/03+01,02_android_native_validation/CODE_REVIEW-cloud-G07.md b/agent-task/m-client-validation/03+01,02_android_native_validation/CODE_REVIEW-cloud-G07.md new file mode 100644 index 00000000..9d3fab69 --- /dev/null +++ b/agent-task/m-client-validation/03+01,02_android_native_validation/CODE_REVIEW-cloud-G07.md @@ -0,0 +1,148 @@ + + +# Code Review Reference - ANDROID + +> **[IMPLEMENTING AGENT — READ FIRST] Filling in this file is the mandatory final step of implementation.** +> The task is NOT complete until every implementation-owned section below is filled in. +> Complete the `구현 체크리스트`; the final checklist item is mandatory before saving. +> Fill implementation-owned sections, then stop with active files in place and report ready for review. +> If implementation is blocked by a user-only decision, external environment prerequisite, or scope conflict, fill `사용자 리뷰 요청` with evidence and stop with active files in place; code-review decides whether to write `USER_REVIEW.md`. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only, even after compaction/resume. +> Follow the ownership table at the bottom of this file for which sections you own. + +## 개요 + +date=2026-05-28 +task=m-client-validation/03+01,02_android_native_validation, plan=0, tag=ANDROID + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. +리뷰 완료는 아래 순서까지 끝난 상태를 의미합니다. + +1. 판정을 append한다. +2. `CODE_REVIEW-cloud-G07.md` -> `code_review_cloud_G07_0.log`, `PLAN-cloud-G07.md` -> `plan_cloud_G07_0.log`로 아카이브한다. +3. PASS이면 `complete.log` 작성 후 active task 디렉터리를 `agent-task/archive/YYYY/MM/m-client-validation/03+01,02_android_native_validation/`로 이동한다. WARN/FAIL이면 user-review gate를 확인한 뒤 다음 active plan/review 파일 또는 `USER_REVIEW.md`를 작성한다. +4. PASS이고 task group이 `m-client-validation`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. +5. 적용 가능한 `코드리뷰 전용 체크리스트` 항목을 최종 `.log` 위치에서 체크한 뒤 보고한다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [ANDROID-1] Native unit test 계약 보강 | [ ] | +| [ANDROID-2] Local Android preflight 기록 | [ ] | +| [ANDROID-3] Remote/device verification handoff | [ ] | + +## 구현 체크리스트 + +- [ ] [ANDROID-1] `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt`를 plugin method-call/intent payload 계약 중심으로 보강한다. +- [ ] [ANDROID-2] local Android preflight를 실행하고 `./gradlew testDebugUnitTest`의 실제 통과 또는 SDK blocker 출력을 기록한다. +- [ ] [ANDROID-3] remote Android guide를 사용 가능한 경우 integration/native checks를 실행하고, 불가능하면 review stub의 사용자 리뷰 요청에 필요한 외부 준비 사항을 정확히 남긴다. +- [ ] `flutter doctor -v`와 `command -v adb`/`command -v emulator`/`command -v sdkmanager` 결과를 기록한다. +- [ ] `./gradlew testDebugUnitTest`를 `apps/flutter-test/android`에서 실행하고 실제 stdout/stderr를 기록한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. +> 구현 에이전트는 이 섹션을 수정하거나 체크하지 않는다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] active `CODE_REVIEW-*-G??.md`를 `code_review_cloud_G07_0.log`로 아카이브한다. +- [ ] active `PLAN-*-G??.md`를 `plan_cloud_G07_0.log`로 아카이브한다. +- [ ] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [ ] PASS이면 active task 디렉터리 `agent-task/m-client-validation/03+01,02_android_native_validation/`를 `agent-task/archive/YYYY/MM/m-client-validation/03+01,02_android_native_validation/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [ ] PASS이고 task group이 `m-client-validation`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [ ] PASS split 작업이면 이동 후 빈 active parent `agent-task/m-client-validation/`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-cloud-G07.md`와 `CODE_REVIEW-cloud-G07.md`를 작성하고 `complete.log`를 작성하지 않는다. +- [ ] USER_REVIEW이면 `agent-ops/skills/common/code-review/templates/user-review-template.md` 기준으로 `USER_REVIEW.md`를 작성하고 active `PLAN-*.md`, `CODE_REVIEW-*.md`, `complete.log`를 남기지 않는다. +- [ ] USER_REVIEW가 사용자 결정으로 완료/PASS 해소되면 `USER_REVIEW.md`를 해소 상태로 갱신하고 `complete.log`를 작성한 뒤 task directory를 archive로 이동한다. + +## 계획 대비 변경 사항 + +_구현 에이전트가 계획과 다르게 구현한 부분을 이유와 함께 기록한다._ + +## 주요 설계 결정 + +_구현 에이전트가 주요 설계 결정 사항을 기록한다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 외부 환경 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. code-review가 이 내용을 검증해 `USER_REVIEW.md`를 작성한다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 재개 조건: 없음 + +## 리뷰어를 위한 체크포인트 + +- predecessor `01_docs_boundary`와 `02+01_flutter_contract_tests`가 complete인지 확인한다. +- native tests가 template `getPlatformVersion` 수준을 넘어 plugin contract를 검증하는지 확인한다. +- Android SDK/device blocker를 PASS처럼 처리하지 않았는지 확인한다. + +## 검증 결과 + +_구현 에이전트가 각 중간 검증 및 최종 검증 명령 실행 후 출력을 여기에 붙여 넣는다._ + +### ANDROID-1 중간 검증 + +```sh +$ cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +### ANDROID-2 중간 검증 + +```sh +$ command -v adb +$ command -v emulator +$ command -v sdkmanager +$ flutter doctor -v +$ cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +### ANDROID-3 중간 검증 + +```sh +$ cd apps/flutter-test && flutter test integration_test -d emulator-5554 +$ cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +### 최종 검증 + +```sh +$ command -v adb +$ command -v emulator +$ command -v sdkmanager +$ flutter doctor -v +$ cd apps/flutter-test/android && ./gradlew testDebugUnitTest +$ cd apps/flutter-test && flutter test integration_test -d emulator-5554 +$ git diff --check -- packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt packages/messaging_flutter/android/build.gradle.kts packages/messaging_flutter/docs/android-test-environment.md +``` + +--- + +> **[IMPLEMENTING AGENT — BEFORE SAVING] Have you filled in every implementation-owned section: completion table, implementation checklist, changes from plan, design decisions, and verification output?** +> If anything is blank, go back and fill it in before saving this file. +> Leave review-agent-only sections unchanged. + +Sections and their ownership: + +| Section | Owner | Note | +|---------|-------|------| +| Header comment, 개요, 리뷰 에이전트 지시 | Fixed at stub creation | Implementing agent must not modify or execute these | +| 구현 항목별 완료 여부 | Fixed at stub creation | Implementing agent checks `[ ]` -> `[x]` only | +| 구현 체크리스트 | Fixed at stub creation from plan | Implementing agent checks `[ ]` -> `[x]` only | +| 코드리뷰 전용 체크리스트 | Review agent only | Implementing agent must not modify or check this section | +| 계획 대비 변경 사항, 주요 설계 결정 | Implementing agent | Replace placeholder text with actual content | +| 사용자 리뷰 요청 | Implementing agent | Keep `상태: 없음` unless user input is required | +| 리뷰어를 위한 체크포인트 | Fixed at stub creation | Pre-filled from plan | +| 검증 결과 | Fixed headings and commands | Implementing agent fills command output only | diff --git a/agent-task/m-client-validation/03+01,02_android_native_validation/PLAN-cloud-G07.md b/agent-task/m-client-validation/03+01,02_android_native_validation/PLAN-cloud-G07.md new file mode 100644 index 00000000..43702b92 --- /dev/null +++ b/agent-task/m-client-validation/03+01,02_android_native_validation/PLAN-cloud-G07.md @@ -0,0 +1,209 @@ + + +# Plan - ANDROID + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션 작성은 필수다. 구현 후 검증을 실행하고 실제 변경 내용, 명령 출력, 계획 대비 변경 사항을 채운 뒤 active 파일을 그대로 둔 채 리뷰 준비 상태로 보고한다. 최종 판정, 로그 rename, `complete.log`, archive 이동은 code-review 스킬 전용이다. 사용자만 결정할 수 있는 사항, 외부 환경 준비, 범위 충돌로 막히면 review stub의 `사용자 리뷰 요청` 섹션에 정확한 결정 필요 사항과 근거를 채우고 멈춘다. + +## 배경 + +Milestone은 Android native unit test와 remote Android verification path를 기준선으로 요구한다. 현재 local 환경은 Android SDK가 없어 `./gradlew testDebugUnitTest`가 `SDK location not found`로 실패하고, integration test도 Android device/emulator가 없어 실패한다. 이 subtask는 native test 내용을 템플릿성 확인에서 실제 plugin contract로 키우고, local/remote verification을 정직하게 기록한다. + +## 사용자 리뷰 요청 흐름 + +구현 중 blocker는 active `CODE_REVIEW-*-G??.md`의 `사용자 리뷰 요청` 섹션에 기록한다. 섹션 형식은 `agent-ops/skills/common/_templates/implementation-user-review-request-section.md`와 같으며, code-review가 검증 후 실제 `USER_REVIEW.md` 작성 여부를 결정한다. + +## 분석 결과 + +### 읽은 파일 + +- `apps/flutter-test/android/local.properties` +- `apps/flutter-test/android/settings.gradle.kts` +- `apps/flutter-test/android/build.gradle.kts` +- `apps/flutter-test/android/app/build.gradle.kts` +- `apps/flutter-test/android/app/src/main/AndroidManifest.xml` +- `packages/messaging_flutter/android/build.gradle.kts` +- `packages/messaging_flutter/android/src/main/AndroidManifest.xml` +- `packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt` +- `packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/PushNotificationEvents.kt` +- `packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/LaunchIntentHelper.kt` +- `packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoFirebaseMessagingService.kt` +- `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt` +- `packages/messaging_flutter/docs/android-test-environment.md` +- `apps/flutter-test/README.md` +- `packages/messaging_flutter/README.md` + +### 테스트 커버리지 공백 + +- `NexoMessagingPlugin.onMethodCall`: current native test only checks `getPlatformVersion`; invalid argument paths and debug event method are not covered. +- `intentPayload`: no native unit test currently verifies extras -> opened/userInteraction payload mapping. +- Local Android verification: blocked because local `apps/flutter-test/android/local.properties` has `flutter.sdk=/sdk/flutter` but no `sdk.dir`, and `ANDROID_HOME` is unavailable. +- Remote Android verification: documented but not executed in this local session. + +### 심볼 참조 + +- 변경/삭제할 심볼 없음. +- Relevant references checked with `rg --sort path -n "debugSendNativeEvent|intentPayload|testDebugUnitTest|ANDROID_HOME|sdk.dir" apps/flutter-test packages/messaging_flutter`. + +### 분할 판단 + +- split decision policy를 plan 파일 선택 전에 평가했다. +- shared task group: `agent-task/m-client-validation`. +- predecessor dependencies from directory name: `01_docs_boundary` and `02+01_flutter_contract_tests`. +- this subtask: `03+01,02_android_native_validation`, waits for both because it relies on finalized doc language and Flutter contract tests. + +### 범위 결정 근거 + +- No remote credentials or host-specific tokens are added to tracked docs. +- No Android SDK is installed into the repository. +- No public package rename, manifest identifier rename, or generated Flutter platform file regeneration is allowed. +- FCM real delivery remains manual smoke; this subtask may document/run it only when external infrastructure is already prepared. + +### 빌드 등급 + +- build=`cloud-G07`, review=`cloud-G07`. Success depends on terminal/Gradle workflow, environment diagnosis, Android SDK/device availability, and possibly remote execution. + +## 의존 관계 및 구현 순서 + +- Wait for `agent-task/m-client-validation/01_docs_boundary/complete.log`. +- Wait for `agent-task/m-client-validation/02+01_flutter_contract_tests/complete.log`. +- Do not add dependencies beyond the `03+01,02_...` directory name. + +## 구현 체크리스트 + +- [ ] [ANDROID-1] `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt`를 plugin method-call/intent payload 계약 중심으로 보강한다. +- [ ] [ANDROID-2] local Android preflight를 실행하고 `./gradlew testDebugUnitTest`의 실제 통과 또는 SDK blocker 출력을 기록한다. +- [ ] [ANDROID-3] remote Android guide를 사용 가능한 경우 integration/native checks를 실행하고, 불가능하면 review stub의 사용자 리뷰 요청에 필요한 외부 준비 사항을 정확히 남긴다. +- [ ] `flutter doctor -v`와 `command -v adb`/`command -v emulator`/`command -v sdkmanager` 결과를 기록한다. +- [ ] `./gradlew testDebugUnitTest`를 `apps/flutter-test/android`에서 실행하고 실제 stdout/stderr를 기록한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +### [ANDROID-1] Native unit test 계약 보강 + +#### 문제 + +[packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt](/config/workspace/nexo/packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt:8)는 template comment와 `getPlatformVersion` 단일 테스트만 갖고 있다. [packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt](/config/workspace/nexo/packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt:139)의 `debugSendNativeEvent` invalid argument path와 [packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt](/config/workspace/nexo/packages/messaging_flutter/android/src/main/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPlugin.kt:122)의 `intentPayload` mapping은 native test로 고정되어 있지 않다. + +Before: + +```kotlin +16 internal class NexoMessagingPluginTest { +17 @Test +18 fun onMethodCall_getPlatformVersion_returnsExpectedValue() { +``` + +#### 해결 방법 + +기존 template comment를 제거하고, 최소한 다음 native tests를 추가한다. + +- `onMethodCall_debugSendNativeEvent_withInvalidPayload_returnsInvalidArg` +- `onMethodCall_saveDeviceToken_withoutToken_returnsInvalidArg` +- 가능하면 Android SDK/Robolectric 없이 가능한 범위에서 `intentPayload` mapping test. 필요하면 implementation blocker로 남기고 문서화한다. + +새 dependency는 추가하지 않는 것을 기본으로 한다. Robolectric이 꼭 필요하면 `packages/messaging_flutter/android/build.gradle.kts`의 `testImplementation` 추가 여부와 이유를 review stub에 기록한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt` +- [ ] 필요 시 `packages/messaging_flutter/android/build.gradle.kts` + +#### 테스트 작성 + +Native unit test를 직접 추가한다. + +#### 중간 검증 + +```sh +cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +### [ANDROID-2] Local Android preflight 기록 + +#### 문제 + +현재 local `./gradlew testDebugUnitTest`는 Android SDK path가 없어 실패했다. [apps/flutter-test/android/local.properties](/config/workspace/nexo/apps/flutter-test/android/local.properties:1)는 `flutter.sdk`만 갖고 있고 `sdk.dir`이 없다. + +Observed: + +```text +SDK location not found. Define a valid SDK location with an ANDROID_HOME environment variable or by setting the sdk.dir path in your project's local properties file +``` + +#### 해결 방법 + +구현자는 local 환경을 repo에 설치하지 않는다. `command -v adb`, `command -v emulator`, `command -v sdkmanager`, `flutter doctor -v`, `./gradlew testDebugUnitTest`를 실행하고 실제 출력을 review stub에 기록한다. `ANDROID_HOME`이 준비되어 있으면 Gradle test를 통과시킨다. + +#### 수정 파일 및 체크리스트 + +- [ ] 소스 파일 변경 없음. 검증 결과 기록만 수행한다. + +#### 테스트 작성 + +테스트 작성 없음. 환경 preflight다. + +#### 중간 검증 + +```sh +command -v adb +command -v emulator +command -v sdkmanager +flutter doctor -v +cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +### [ANDROID-3] Remote/device verification handoff + +#### 문제 + +[packages/messaging_flutter/docs/android-test-environment.md](/config/workspace/nexo/packages/messaging_flutter/docs/android-test-environment.md:73)는 remote check path를 제공하지만 실제 실행은 외부 SSH/device 조건이 필요하다. + +Before: + +```markdown +73 ## Run The Checks +77 cd "$HOME/tmp/nexo-codex-test/packages/messaging_flutter" +``` + +#### 해결 방법 + +remote host 접근이 가능하면 guide의 sync/emulator/check commands를 그대로 실행한다. 접근이 불가능하면 `사용자 리뷰 요청`에 필요한 준비 사항을 남긴다: Android SDK 또는 remote SSH availability, emulator/device, Firebase config 여부. + +#### 수정 파일 및 체크리스트 + +- [ ] 필요 시 `packages/messaging_flutter/docs/android-test-environment.md`의 command drift만 수정한다. + +#### 테스트 작성 + +새 테스트 없음. 외부 환경 검증이다. + +#### 중간 검증 + +```sh +cd apps/flutter-test && flutter test integration_test -d emulator-5554 +cd apps/flutter-test/android && ./gradlew testDebugUnitTest +``` + +## 수정 파일 요약 + +| 파일 | 항목 | +| --- | --- | +| `packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt` | ANDROID-1 | +| `packages/messaging_flutter/android/build.gradle.kts` | ANDROID-1, only if a test dependency is justified | +| `packages/messaging_flutter/docs/android-test-environment.md` | ANDROID-3, only if command drift is found | + +## 최종 검증 + +```sh +command -v adb +command -v emulator +command -v sdkmanager +flutter doctor -v +cd apps/flutter-test/android && ./gradlew testDebugUnitTest +cd apps/flutter-test && flutter test integration_test -d emulator-5554 +git diff --check -- packages/messaging_flutter/android/src/test/kotlin/com/tokilabs/nexo/messaging/NexoMessagingPluginTest.kt packages/messaging_flutter/android/build.gradle.kts packages/messaging_flutter/docs/android-test-environment.md +``` + +Local Android SDK/device 부재는 PASS가 아니라 environment blocker다. blocker가 남으면 `사용자 리뷰 요청`을 채우고 code-review가 stop 여부를 판단하게 한다. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/apps/flutter-test/README.md b/apps/flutter-test/README.md index e6730e8c..e7cbf060 100644 --- a/apps/flutter-test/README.md +++ b/apps/flutter-test/README.md @@ -18,6 +18,10 @@ This app is not a nexo product app and is not the original Mattermost app. The original Mattermost app belongs under `apps/mattermost/`; app-specific product UI and business logic belong in consuming apps outside this repository. +The app is a plugin API consumer and verification host. Native push handling, +ACK delivery, token/key storage, notification rendering, inline reply, and +dismiss handling remain owned by `packages/messaging_flutter`. + ## Structure ```text @@ -67,11 +71,13 @@ Run Android native unit tests from `apps/flutter-test/android`: ./gradlew testDebugUnitTest ``` -Android Gradle tests require a configured Android SDK through `ANDROID_HOME` or -`apps/flutter-test/android/local.properties`. +Android Gradle tests require a configured Android SDK through `ANDROID_HOME`, +`ANDROID_SDK_ROOT`, or `apps/flutter-test/android/local.properties`. -When the local machine does not have a usable Android SDK or emulator, use the -repository-level remote environment guide: +When the local machine does not have a usable Android SDK, device, or emulator, +the expected local result is an environment failure rather than a product +failure. Use the repository-level remote environment guide for Android +integration and native unit verification: [`../../packages/messaging_flutter/docs/android-test-environment.md`](../../packages/messaging_flutter/docs/android-test-environment.md). ## Maintenance Rules diff --git a/packages/messaging_flutter/README.md b/packages/messaging_flutter/README.md index aa2ab0e7..dbfc41c8 100644 --- a/packages/messaging_flutter/README.md +++ b/packages/messaging_flutter/README.md @@ -8,6 +8,14 @@ each consuming app: native FCM handling, notification display, notification tap events, inline replies, dismiss handling, ACK delivery, device-token storage, auth-token storage, and server signing-key storage. +## SDK Ownership Boundary + +This package is the nexo-owned embedded messaging SDK. Its Android +implementation follows the nexo server/push contract, Android and FCM platform +changes, and Flutter plugin registration behavior. It does not follow or mirror +the Mattermost mobile app source tree; that app remains under `apps/mattermost/` +as an upstream clone. + ## Platform Status | Platform | Status | Notes | @@ -237,7 +245,27 @@ Use the repository tests as the source of truth for plugin behavior: ## Manual Smoke Checklist -Use this checklist before promoting a plugin change to a consuming app: +Use this checklist before promoting a plugin change to a consuming app. These +checks require external Firebase and nexo server infrastructure, so they are not +expected to pass in a headless repository test run. + +Prerequisites: + +- Firebase is configured for the host app with `android/app/google-services.json`. +- The host app has called `NexoMessagingPlugin.instance.initialize()`. +- The test user has a server URL, auth token, and signing key saved through the + plugin API. +- The nexo server can send a push payload with `ack_id`, `server_url` or + resolvable `server_id`, `channel_id`, and a valid signature. + +Evidence to capture: + +- `logcat` lines from `NexoFirebaseMessagingService` for receipt, ACK, and + signature handling. +- A screenshot or device recording of the displayed notification. +- Server-side ACK/reply request logs showing response status. +- Host app UI evidence for `onNotificationOpened`, `onNavigateToChannel`, and + `onNavigateToThread` routing. - [ ] FCM payload wakes `NexoFirebaseMessagingService`. - [ ] Valid nexo push payload passes signing-key verification. diff --git a/packages/messaging_flutter/docs/android-test-environment.md b/packages/messaging_flutter/docs/android-test-environment.md index 6c726447..aa97fc3b 100644 --- a/packages/messaging_flutter/docs/android-test-environment.md +++ b/packages/messaging_flutter/docs/android-test-environment.md @@ -19,6 +19,23 @@ export ANDROID_HOME="$HOME/Library/Android/sdk" export ANDROID_SDK_ROOT="$ANDROID_HOME" ``` +## Local Android Preflight + +Before using the remote host, check whether the local machine already has the +Android toolchain needed for integration and Gradle unit tests: + +```sh +flutter doctor -v +command -v adb +command -v emulator +command -v sdkmanager +``` + +`./gradlew testDebugUnitTest` requires either `ANDROID_HOME`/`ANDROID_SDK_ROOT` +or a valid `sdk.dir` entry in `apps/flutter-test/android/local.properties`. If +the command fails with `SDK location not found`, treat it as a local environment +blocker and use the remote flow below instead of changing repository files. + ## Sync A Working Copy From the local repository root, copy the current working tree to an isolated