# Milestone: Mattermost Messaging Android Smoke

## 위치

- Roadmap: `agent-roadmap/ROADMAP.md`
- Phase: `agent-roadmap/phase/external-integration/PHASE.md`

## 목표

`mattermost_push_plugin`이 서버와 같은 `../nexo` repo의 `packages/messaging_flutter` package로 합쳐지고, 알림 전용에서 메시징 지원까지 포함하는 방향으로 전환된 현재 상태를 Android 기준으로 검증한다. 사용자 테스트까지 진행하지 않고, 원격 Android SDK 환경에서 build가 통과하고 Mattermost 메시지/FCM 알림이 실제 Android runtime에 도착하는지 확인하는 데서 완료 범위를 닫는다.

## 상태

[완료]

## 구현 잠금

- 상태: 해제
- 결정 필요: 없음

## 범위

- `apps/client` host와 `../nexo/packages/messaging_flutter` package 경계가 현재 messaging 방향성과 충돌하지 않는지 확인
- 원격 Android SDK runner에서 `apps/client`의 Android debug build 검증
- Android device 또는 emulator에서 앱 boot, Firebase 초기화, Mattermost auth/token handoff, 알림 callback이 깨지지 않는지 smoke 확인
- Mattermost 메시지 또는 push trigger를 통해 Android 시스템 알림이 도착하는지 확인
- 검증 중 드러나는 build/configuration regression은 smoke를 통과시키는 최소 수정 범위에서 처리

## 기능

### Epic: [android-smoke] Remote Android notification verification

Mattermost messaging package 전환 이후 Android build와 알림 수신 경로가 실제 환경에서 깨지지 않았는지 확인한다.

- [x] [scope-check] `apps/client`, `apps/client/push-notification-todo.md`, `../nexo/packages/messaging_flutter` 경계를 확인해 현재 repo 업데이트가 메시징 지원 방향성과 맞는지 정리한다.
- [x] [remote-build] `docs/test-environments.md#android-sdk-remote-runner` 기준 원격 Android SDK 환경에서 `apps/client`의 `flutter pub get`과 `flutter build apk --debug`를 통과시킨다. 검증: `toki@toki-labs.com`의 `/Users/toki/jenkins/workspace/nomadcode/apps/client`에서 `flutter pub get`과 `flutter build apk --debug`가 통과했다.
- [x] [runtime-smoke] Android device 또는 emulator에서 앱을 실행해 앱 boot, Firebase 초기화, Mattermost auth/token handoff가 crash 없이 진행되는지 확인한다. 검증: `emulator-5554`에서 앱 boot, Firebase 초기화, notification permission authorized, Mattermost login, auth token/signing key 저장, FCM device token 등록을 secret redaction 상태로 확인했다.
- [x] [notification-arrival] Mattermost 메시지 또는 push trigger로 Android 시스템 알림이 도착하는지 확인한다. 검증: Mattermost post trigger `201`, `NexoFirebaseMessagingService.onMessageReceived`, ACK 전송, Android `NotificationRecord(pkg=com.tokilabs.mattermost)`, Flutter event 전송을 확인했다.
- [x] [evidence-note] build와 알림 smoke 결과, 사용자 테스트 미포함 한계, 후속 보완이 필요한 경우를 완료 리뷰 근거로 남긴다. 검증: 아래 `완료 리뷰`와 `작업 컨텍스트`에 secret 없이 evidence를 기록했다.

## 완료 리뷰

- 상태: 승인됨
- 요청일: 2026-05-27
- 완료 근거:
  - 원격 Android SDK runner에서 `flutter pub get`과 `flutter build apk --debug`가 통과했다.
  - Android 14 emulator `emulator-5554`에서 앱 boot, Firebase 초기화, Mattermost login, auth token/signing key 저장, FCM device token 등록이 통과했다.
  - Mattermost post trigger 후 FCM 수신, ACK 전송, Android system notification record, Flutter notification event 전송을 확인했다.
- 리뷰 필요:
  - [x] 사용자가 완료 결과를 확인했다
  - [x] archive 이동을 승인했다
- 리뷰 코멘트: 사용자 테스트/UAT는 범위 제외이며, 원격 smoke 중 token, password, signing key, FCM/device token은 문서에 기록하지 않았다. 사용자가 Mattermost 내 tester 메시지 도착과 `nomadcode` 웹 채널 메시지 도착도 확인했다.

## 범위 제외

- 사용자 테스트, UAT, 제품 사용성 검증
- iOS/macOS native push full implementation 또는 runtime smoke
- Mattermost 메시징 제품 UX 구현
- Mattermost server-side plugin 대규모 기능 확장
- External Integration Milestone의 Plane/Jira/Agent Integrator/IOP adapter 구현

## 작업 컨텍스트

- 관련 경로: `apps/client/`, `apps/client/push-notification-todo.md`, `docs/test-environments.md`, `../nexo/packages/messaging_flutter`
- 연관 core 경계: `services/core/internal/adapters/mattermost/`, `services/core/internal/notification/`
- 선행 작업: Mattermost Push Plugin Extraction, Client Integration Standardization
- 후속 작업: External Integration의 Mattermost 메시지 발송 adapter 구현
- 표준선: Android SDK 의존 검증은 `docs/test-environments.md#android-sdk-remote-runner`를 따른다.
- 보안 주의: Mattermost token, Firebase credential, signing key, device token은 roadmap이나 문서에 기록하지 않는다.
- 2026-05-26 scope-check: `apps/client` host dependency/import 문서를 `../nexo/packages/messaging_flutter`의 현재 Dart package명 `nexo_messaging`과 `NexoMessagingPlugin` API에 맞췄고, ignored `assets/mattermost_credentials.json`을 smoke 때 bundle할 수 있도록 assets 디렉터리를 선언했다. 원격 Android build와 실제 알림 도착 smoke는 환경 의존 작업으로 plan에서 수행한다.
- 2026-05-26 runtime-smoke 준비: `~/docker/services/mattermost` 기준 Mattermost public URL은 `https://mattermost.toki-labs.com`, server-side push target은 `http://mattermost-push-proxy:8066`, push notification은 enabled 상태임을 확인했다. `nomadcode` 공개 채널 ID는 확인됐고, 값은 secret이 아니지만 재사용은 ignored `.env.mattermost.local`을 우선한다.
- 2026-05-26 runtime-smoke secret 상태: post trigger용 Mattermost PAT는 활성화되어 API `/api/v4/users/me`와 `nomadcode` 채널 post가 성공했다. 토큰 값은 roadmap에 기록하지 않고, 로컬 및 원격 runner의 ignored `.env.mattermost.local`에 저장했다.
- 2026-05-26 남은 차단점: post trigger env는 준비됐지만 앱 수신자 등록은 아직 남았다. 현재 앱은 `assets/mattermost_credentials.json`에서 `serverUrl/loginId/password`만 읽어 로그인 후 FCM device token을 등록하므로, 테스트 사용자 credential asset을 준비하거나 token 기반 smoke credential 지원을 구현해야 한다.
- 2026-05-26 다음 재개 기준: 원격 runner에서 `.env.mattermost.local`을 로드해 trigger env를 주입하고, 앱 수신자 credential을 준비한 뒤 Android emulator에서 boot/FCM registration/post trigger/system notification evidence를 secret 없이 다시 기록한다. FCM/device token은 로그에 붙이기 전에 redaction한다.
- 2026-05-27 사용자 결정 해소: 앱 수신자 인증은 ignored `apps/client/assets/mattermost_credentials.json` 방식으로 준비하고, notification smoke 발신자는 앱 수신자와 분리된 테스트용 PAT를 사용한다. `apps/client/macos/Flutter/GeneratedPluginRegistrant.swift`와 `apps/client/push-notification-todo.md` 변경은 `nexo_messaging` rename 정정으로 이번 smoke 범위에 포함한다.
- 2026-05-27 secret 준비 상태: 로컬과 원격 runner에 credential asset과 `.env.mattermost.local`을 `0600` 권한으로 준비했고, 값 노출 없이 Mattermost 발신자 API 접근과 수신자 login/token header를 확인했다.
- 2026-05-27 원격 환경 정리: `toki@toki-labs.com`의 `~/.nomadcode-env.sh`에 `FLUTTER_HOME=$HOME/SDK/flutter`, `ANDROID_HOME=$HOME/Library/Android/sdk`, `ANDROID_SDK_ROOT=$ANDROID_HOME`, 관련 `PATH`를 설정하고 bash/zsh login shell에서 로드되도록 했다.
- 2026-05-27 smoke evidence: 원격 nexo package copy가 오래된 `MattermostPushPlugin` metadata를 들고 있어 `NexoMessagingPlugin` method channel이 누락된 것을 확인했고, 최신 `../nexo/packages/messaging_flutter` package로 원격 테스트 copy를 동기화한 뒤 Android generated registrant가 `com.tokilabs.nexo.messaging.NexoMessagingPlugin`을 등록하도록 재생성했다. 이후 debug APK build와 runtime smoke, notification arrival smoke가 통과했다.
- 2026-05-27 사용자 확인: 사용자가 Mattermost 내 tester 메시지 도착을 확인했고, `nomadcode` 채널 웹 메시지 발송도 정상 도착으로 확인했다.
