<!-- task=review_followup_alignment/03_nexo_notification_boundary plan=0 tag=REVIEW_NEXO -->
# PLAN-local-G05: Nexo 알림 경계 정리
date=2026-07-06

## 목적
IOP Client가 Mattermost 통합의 소유자처럼 동작하지 않도록 정리한다. IOP는 상위 폴더의 `../nexo`가 제공하는 notification 기능만 사용하고, Mattermost-compatible 인증/등록/서버 통합 책임은 Nexo 쪽 경계로 둔다.

## 분석 결과
- 읽은 파일: `agent-ops/rules/project/rules.md`, `agent-ops/rules/private/rules.md`, `agent-ops/rules/common/rules-roadmap.md`, `agent-ops/skills/common/router.md`, `agent-ops/skills/common/plan/SKILL.md`, `agent-test/local/rules.md`, `agent-test/local/client-smoke.md`, `agent-ops/rules/project/domain/client/rules.md`, `apps/client/lib/client_bootstrap.dart`, `apps/client/lib/client_home_page.dart`, `apps/client/lib/main.dart`, `apps/client/lib/src/integrations/mattermost/mattermost_auth_service.dart`, `apps/client/lib/src/integrations/mattermost/mattermost_push_client.dart`, `apps/client/lib/src/integrations/mattermost/mattermost_push_host_integration.dart`, `apps/client/lib/src/integrations/mattermost/mattermost_push_plugin_client.dart`, `apps/client/test/client_bootstrap_test.dart`, `apps/client/test/integrations/mattermost_push_host_integration_test.dart`, `apps/client/pubspec.yaml`, `apps/client/Dockerfile`, `apps/client/README.md`, `../nexo/AGENTS.md`, `../nexo/packages/messaging_flutter/lib/nexo_messaging.dart`, `../nexo/packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart`, `../nexo/packages/messaging_flutter/lib/src/nexo_messaging_options.dart`.
- SDD 기준: Client integration 경계 정리 follow-up이다. 현재 로드맵 active Milestone은 `[스케치]` 및 구현 잠금 상태이므로 로드맵 완료 항목을 선언하지 않는다.
- 테스트 환경 규칙: local 기준으로 작성하되 Flutter 실행 가능 여부는 환경에 의존한다. 실행 불가 시 구현 에이전트는 원인과 대체 분석을 `CODE_REVIEW-local-G05.md`에 기록한다.
- 테스트 커버리지 공백: 현재 테스트는 Mattermost host integration 자체를 검증하고 있어, IOP가 notification consumer 역할만 한다는 경계 검증이 부족하다.
- 심볼 참조: `bootstrapClientApp`, `MattermostPushHostIntegration`, `MattermostAuthService`, `MattermostPushPluginClient`, `NexoMessagingPlugin`.
- 분할 판단: 이 plan은 Flutter Client와 sibling Nexo API 경계만 다룬다. Edge 로그, docs, mock resource 작업과 독립적이다.
- 범위 결정 근거: 사용자 결정이 이미 확정됐다. IOP는 Mattermost role을 직접 가져가지 않고 알림 기능만 사용한다.
- 빌드 등급: `local-G05`. Client integration naming/API/test 경계를 건드리며, Flutter test 실행이 필요하다.

## 이 파일을 읽는 구현 에이전트에게
구현 후 `CODE_REVIEW-local-G05.md`의 구현 에이전트 소유 섹션을 실제 변경 내용과 검증 출력으로 채운다. 구현 중 직접 사용자에게 질문하거나 선택지를 제시하지 않는다. 선택된 Milestone의 `구현 잠금 > 결정 필요` 항목이 실제 구현을 차단할 때만 review stub의 `사용자 리뷰 요청` 섹션에 근거를 기록하고 멈춘다. `../nexo`는 읽기/참조 경계로 보고, 이 plan에서는 sibling repo를 수정하지 않는다.

## 작업 항목

### REVIEW_NEXO-1. IOP Client의 Mattermost 소유 책임 제거
- 문제:
  - `apps/client/lib/client_bootstrap.dart:8` 계열 bootstrap option이 Mattermost 초기화를 기본값처럼 다룬다.
  - `apps/client/lib/src/integrations/mattermost/mattermost_auth_service.dart:8` 계열 코드가 IOP 안에서 Mattermost 자동 로그인, credential asset 로드, device token 등록을 수행한다.
  - `apps/client/lib/src/integrations/mattermost/mattermost_push_host_integration.dart:6` 계열 comment/API가 IOP Client가 Mattermost host boundary를 소유하는 듯한 구조를 만든다.
  - `apps/client/pubspec.yaml:41` 계열 Nexo messaging dependency와 `assets/` 설정이 섞이면서 notification consumer와 Mattermost integration owner 책임이 분리되지 않는다.
- 해결 방법:
  - IOP Client의 public naming을 Mattermost 중심에서 Nexo notification 중심으로 바꾼다. 예: `initializeMattermost` -> `initializeNotifications`, `MattermostPushHostIntegration` -> `NexoNotificationHostIntegration`.
  - IOP에서 Mattermost 자동 로그인, credential asset 로드, Mattermost REST device registration 책임을 제거한다.
  - IOP는 `nexo_messaging` plugin 초기화, notification stream 구독, notification-open navigation callback 연결만 수행한다.
  - 인증 토큰/signing key/server registration이 필요하면 IOP의 hard-coded asset이 아니라 Nexo/상위 앱 세션 경계에서 주입된 값만 사용한다.
  - 변경 전 예:
    ```dart
    const ClientBootstrapOptions({this.initializeMattermost = true});
    ```
  - 변경 후 예:
    ```dart
    const ClientBootstrapOptions({this.initializeNotifications = true});
    ```
- 수정 파일 및 체크리스트:
  - [ ] `apps/client/lib/client_bootstrap.dart`: Mattermost 명명과 default host wiring을 notification 중심으로 정리.
  - [ ] `apps/client/lib/client_home_page.dart`: prop/import/snack text를 Nexo notification 경계에 맞게 정리.
  - [ ] `apps/client/lib/main.dart`: 앱 prop과 wiring에서 Mattermost 소유 표현 제거.
  - [ ] `apps/client/lib/src/integrations/mattermost/*`: notification integration 경로로 rename/refactor하거나 제거. 특히 `MattermostAuthService`의 asset login/registration 책임은 제거.
  - [ ] `apps/client/test/client_bootstrap_test.dart`: bootstrap skip/initialize 테스트를 notification naming으로 갱신.
  - [ ] `apps/client/test/integrations/*`: Nexo notification host consumer 테스트로 갱신.
  - [ ] `apps/client/pubspec.yaml`: 불필요해진 `http` dependency와 Mattermost credential asset 의존성 제거 여부 확인.
  - [ ] `apps/client/README.md`: 필요 시 IOP가 Nexo notification consumer라는 짧은 설명만 추가.
- 테스트 작성:
  - [ ] bootstrap이 notification host를 주입받아 초기화하되 Mattermost login/credential asset을 요구하지 않음을 검증한다.
  - [ ] notification stream과 notification opened callback이 UI 상태/route로 연결되는지 fake client로 검증한다.
  - [ ] `assets/mattermost_credentials.json` 참조가 코드와 pubspec에서 제거되었음을 검색 검증한다.
- 중간 검증:
  - [ ] `cd apps/client && flutter test`
  - [ ] `rg --sort path -n 'mattermost_credentials|MattermostAuthService|autoLoginAndRegister' apps/client/lib apps/client/test apps/client/pubspec.yaml` 결과가 비어 있는지 확인한다.
  - [ ] `rg --sort path -n 'Mattermost|mattermost' apps/client/lib apps/client/test` 결과가 IOP Client의 직접 integration owner 표현을 남기지 않는지 확인한다.

## 구현 체크리스트
- [ ] REVIEW_NEXO-1의 Client notification 경계 refactor와 테스트 갱신을 수행한다.
- [ ] 중간 검증 명령을 실행하고 Flutter 실행 불가 시 환경 사유와 대체 확인 결과를 `CODE_REVIEW-local-G05.md`에 기록한다.
- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

## 최종 검증
```bash
cd apps/client && flutter test
rg --sort path -n 'mattermost_credentials|MattermostAuthService|autoLoginAndRegister' apps/client/lib apps/client/test apps/client/pubspec.yaml
rg --sort path -n 'Mattermost|mattermost' apps/client/lib apps/client/test
```
예상 결과: Flutter test가 PASS한다. 첫 번째 `rg`는 출력이 없다. 두 번째 `rg`는 IOP Client가 Mattermost integration owner로 보이는 lib/test 잔여 표현을 출력하지 않는다.

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