nexo/agent-task/m-flutter-web-notification/04+02,03_display/PLAN-local-G08.md
toki ea77708c4f feat(messaging): Web 알림 전경 계약을 추가한다
Flutter Web foreground 알림 흐름을 이어가기 위해 permission API와 payload mapper를 패키지 내부 계약으로 고정한다.
2026-06-07 15:08:40 +09:00

10 KiB

Plan - WEBDISPLAY

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

이 task는 Chrome foreground 알림 Epic의 display Task를 완료하기 위한 구현 계획이다. 03+02_event_map이 PASS되어 complete.log가 생긴 뒤 구현한다. 구현 후 반드시 active CODE_REVIEW-local-G08.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운 뒤, active 파일을 그대로 두고 리뷰 준비를 보고한다.

사용자에게 직접 질문하지 말고, 선택지를 채팅으로 제시하지 말고, request_user_input을 호출하지 않는다. 사용자만 결정할 수 있는 차단이 생기면 CODE_REVIEW-local-G08.md사용자 리뷰 요청 섹션에 정확한 근거를 남기고 멈춘다. 구현 에이전트는 USER_REVIEW.md, complete.log, *.log archive를 만들지 않는다.

배경

Permission API와 foreground mapper가 준비되면 Web foreground payload를 browser notification으로 표시하고 click/open routing을 기존 Dart stream/callback 계약으로 연결할 수 있다. 이 작업은 browser interop, public method, click event bridge가 함께 필요하므로 바로 구현하지 않고 독립 계획으로 남긴다.

사용자 리뷰 요청 흐름

구현 중 차단은 active review stub의 사용자 리뷰 요청 섹션에 기록한다. 직접 사용자 프롬프트는 금지되며, code-review가 요청 정당성을 검증하고 필요할 때만 USER_REVIEW.md를 작성한다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백은 사용자 리뷰 요청이 아니다.

Roadmap Targets

  • Milestone: agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification.md
  • Task ids:
    • display: foreground payload를 browser notification으로 표시하고 click 이벤트를 NotificationOpenedEvent와 host navigation callback으로 변환한다.
  • Completion mode: check-on-pass

분석 결과

읽은 파일

  • agent-roadmap/current.md
  • agent-roadmap/phase/messaging-runtime/PHASE.md
  • agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification.md
  • agent-test/local/rules.md
  • agent-test/local/messaging-flutter-smoke.md
  • agent-test/local/client-app-smoke.md
  • packages/messaging_flutter/pubspec.yaml
  • packages/messaging_flutter/lib/nexo_messaging.dart
  • packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart
  • packages/messaging_flutter/lib/src/nexo_messaging_web.dart
  • packages/messaging_flutter/lib/src/notification_opened_event.dart
  • packages/messaging_flutter/lib/src/push_notification_type.dart
  • packages/messaging_flutter/lib/src/web/browser_notification_interop.dart
  • packages/messaging_flutter/lib/src/web/browser_notification_interop_web.dart
  • packages/messaging_flutter/lib/src/web_notification_permission.dart
  • packages/messaging_flutter/test/nexo_messaging_test.dart
  • apps/flutter-test/lib/main.dart
  • apps/flutter-test/test/widget_test.dart
  • agent-task/archive/2026/06/m-flutter-web-notification/02+01_web_plugin_baseline/complete.log

테스트 환경 규칙

  • test_env=local.
  • 적용 profile:
    • agent-test/local/messaging-flutter-smoke.md
    • agent-test/local/client-app-smoke.md는 app host가 변경될 경우에만 적용한다.
  • 기본 적용 명령:
    • cd packages/messaging_flutter && flutter pub get
    • cd packages/messaging_flutter && flutter test
    • cd packages/messaging_flutter && flutter analyze --no-fatal-infos
  • apps/flutter-test/**를 수정하면 추가로 cd apps/flutter-test && flutter pub get, cd apps/flutter-test && flutter test, cd apps/flutter-test && flutter analyze --no-fatal-infos를 실행한다.

테스트 커버리지 공백

  • 기존 tests는 native opened event routing을 검증하지만 browser Notification display/click을 검증하지 않는다.
  • 이 plan은 browser interop를 fake 가능한 boundary로 두고, display call과 click callback이 handleNativeEvent()로 이어지는지 Dart unit test로 검증해야 한다.
  • 실제 Chrome permission prompt와 OS notification tray 표시는 local unit test 대상이 아니다.

심볼 참조

  • renamed/removed symbol: none.
  • 새 display API는 NexoMessagingPlugin public API와 web-only interop boundary를 함께 확인해야 한다.
  • apps/flutter-test host UI는 smoke Epic의 test-host Task가 별도라 기본 범위에서 제외한다.

분할 판단

  • split decision policy를 평가했다.
  • shared task group: m-flutter-web-notification.
  • predecessor 02agent-task/archive/2026/06/m-flutter-web-notification/02+01_web_plugin_baseline/complete.log로 충족됐다.
  • predecessor 03agent-task/m-flutter-web-notification/03+02_event_map/complete.log 또는 archive의 matching complete.log가 생겨야 충족된다.
  • 이 task directory 04+02,03_display02 baseline과 03 mapper에 의존한다.
  • display는 browser interop, public API, stream/callback routing을 포함하므로 event-map과 분리한다.

범위 결정 근거

  • 포함: package public display method, browser Notification display/click interop, click -> existing opened routing bridge, focused tests.
  • 제외: Firebase onMessage subscription wiring, apps/flutter-test web UI scaffold, Full Web Push/service worker/VAPID, server/push-proxy changes.
  • 제외 이유: display Task는 foreground payload를 표시하고 click routing으로 변환하는 package contract까지이며, Firebase source wiring과 host smoke UI는 별도 Task다.

빌드 등급

  • local-G08: browser interop와 public routing이 함께 바뀌지만 deterministic fake interop tests로 검증 가능하고 scope는 package 내부로 제한된다.

구현 체크리스트

  • 구현 시작 전 predecessor 03+02_event_map complete.log가 active 또는 archive 경로에 있는지 확인한다.
  • browser Notification 표시를 담당하는 web-only interop method를 추가하되 공용 Dart/API가 package:web를 직접 import하지 않게 유지한다.
  • NexoMessagingPlugin에 foreground web notification display public method를 추가하고 permission이 granted가 아니거나 unsupported면 표시하지 않는 결과를 반환한다.
  • display click event가 normalized payload를 PushNotificationType.opened/userInteraction=true map으로 변환해 기존 handleNativeEvent() routing을 재사용하게 한다.
  • fake interop/client 기반 unit test로 unsupported/permission denied/granted display/click routing을 검증한다.
  • cd packages/messaging_flutter && flutter pub get, cd packages/messaging_flutter && flutter test, cd packages/messaging_flutter && flutter analyze --no-fatal-infos를 실행한다.
  • CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다.

[WEBDISPLAY-1] Browser Foreground Display And Click Routing

문제

현재 NexoMessagingPlugin은 native event stream과 web permission API를 제공하지만, Web foreground payload를 browser notification으로 표시하는 public method가 없다. click/open routing도 NotificationOpenedEvent와 host navigation callback으로 이어지지 않는다.

해결 방법

구현자는 03+02_event_map의 mapper를 사용해 payload를 normalized map으로 만든 뒤, web-only display interop와 public plugin method를 연결한다.

권장 public method 예시:

Future<NexoMessagingWebNotificationDisplayResult>
showWebForegroundNotification(Map<String, dynamic> payload)

요구 사항:

  • unsupported 또는 permission not granted 상태에서는 browser notification을 만들지 않고 testable result를 반환한다.
  • granted 상태에서는 title/body/tag/data 등 최소 fields를 browser Notification API에 전달한다.
  • click callback은 normalized map을 opened event로 변환하고 기존 handleNativeEvent()를 호출한다.
  • Android/iOS/macOS common code는 package:web를 직접 import하지 않는다.

수정 파일 및 체크리스트

  • packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart public method 추가
  • packages/messaging_flutter/lib/src/web/browser_notification_interop.dart display/click boundary 추가
  • packages/messaging_flutter/lib/src/web/browser_notification_interop_web.dart browser implementation 추가
  • 필요 시 result/status value object 추가 및 lib/nexo_messaging.dart export
  • packages/messaging_flutter/test/에 fake 기반 unit tests 추가
  • README의 Web foreground 상태를 display API에 맞게 갱신

테스트 작성

  • unsupported/non-granted 상태에서 display가 no-op result를 반환하는지 검증한다.
  • granted 상태에서 fake interop가 notification display call을 받는지 검증한다.
  • fake click callback이 기존 onNotificationOpened, onNotification, onNavigateToChannel/onNavigateToThread 경로로 이어지는지 검증한다.

중간 검증

cd packages/messaging_flutter && flutter test
cd packages/messaging_flutter && flutter analyze --no-fatal-infos

기대 결과: tests와 analyzer가 통과한다.

수정 파일 요약

파일 항목
packages/messaging_flutter/lib/src/nexo_messaging_plugin.dart WEBDISPLAY-1
packages/messaging_flutter/lib/src/web/browser_notification_interop.dart WEBDISPLAY-1
packages/messaging_flutter/lib/src/web/browser_notification_interop_web.dart WEBDISPLAY-1
packages/messaging_flutter/lib/src/web/** WEBDISPLAY-1
packages/messaging_flutter/test/** WEBDISPLAY-1
packages/messaging_flutter/README.md WEBDISPLAY-1

최종 검증

cd packages/messaging_flutter && flutter pub get
cd packages/messaging_flutter && flutter test
cd packages/messaging_flutter && flutter analyze --no-fatal-infos

기대 결과: 세 명령 모두 exit code 0.

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