diff --git a/agent-roadmap/phase/messaging-runtime/PHASE.md b/agent-roadmap/phase/messaging-runtime/PHASE.md index 34f6db19..7270cd32 100644 --- a/agent-roadmap/phase/messaging-runtime/PHASE.md +++ b/agent-roadmap/phase/messaging-runtime/PHASE.md @@ -40,6 +40,9 @@ Mattermost server/webapp/push-proxy는 upstream-followable runtime으로 두고, - [완료] Flutter Web 알림 - 경로: `agent-roadmap/archive/phase/messaging-runtime/milestones/flutter-web-notification.md` - 요약: `packages/messaging_flutter`를 Flutter Web/Chrome foreground browser notification까지 확장하고, Full Web Push는 별도 후속 계약으로 분리한다. +- [계획] Flutter Web 알림 Smoke 보완 + - 경로: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md` + - 요약: Flutter Web foreground browser notification smoke가 원격 web runner와 forwarded localhost URL에서 실제로 재현되도록 host scaffold, Chrome 테스트, 수동 evidence 기준을 보완한다. - [계획] iOS 알림 테스트 - 경로: `agent-roadmap/phase/messaging-runtime/milestones/ios-notification-test.md` - 요약: 선행 정리 후 iOS/APNs 권한, token, open routing, ACK/dismiss 계약을 실제 설정과 smoke 기준으로 검증한다. diff --git a/agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md b/agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md new file mode 100644 index 00000000..39fce7d6 --- /dev/null +++ b/agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md @@ -0,0 +1,78 @@ +# Milestone: Flutter Web 알림 Smoke 보완 + +## 위치 + +- Roadmap: `agent-roadmap/ROADMAP.md` +- Phase: `agent-roadmap/phase/messaging-runtime/PHASE.md` + +## 목표 + +Flutter Web foreground browser notification이 실제 브라우저 환경에서 반복 검증될 수 있게 한다. +기존 API와 fake interop 단위 테스트 근거만으로 완료 처리된 gap을 보완하고, 원격 runner에서 열린 Flutter Web server를 사용자가 forwarded localhost URL로 접근해 permission, display, click/open routing을 확인할 수 있는 smoke 기준을 만든다. + +## 상태 + +[계획] + +## 승격 조건 + +- 없음 + +## 구현 잠금 + +- 상태: 해제 +- 결정 필요: 없음 + +## 범위 + +- `apps/flutter-test`를 Flutter Web build/run 대상 host scaffold로 구성한다. +- `packages/messaging_flutter`의 VM 단위 테스트와 Chrome/web 테스트를 분리해 각 platform expectation이 충돌하지 않게 정리한다. +- 원격 runner의 Flutter Web server와 사용자가 여는 forwarded localhost URL을 전제로 browser notification permission, display, click/open routing smoke 절차를 만든다. +- `bin/test`, `bin/lint`, `bin/build` 또는 별도 opt-in 명령에서 web smoke/build 검증이 누락되지 않도록 workspace helper와 테스트 기준을 보강한다. + +## 기능 + +### Epic: [web-host] Web 테스트 Host + +Flutter Web 알림 smoke가 실제 브라우저에서 열릴 수 있도록 test host와 실행 경계를 만든다. + +- [ ] [web-scaffold] `apps/flutter-test`에 Flutter Web scaffold를 추가하고 web build가 통과하도록 구성한다. 검증: 원격 runner에서 `apps/flutter-test` web build가 성공해야 한다. +- [ ] [web-runtime] 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다. 검증: 사용자가 forwarded URL에서 permission 요청, notification display, click/open routing 상태를 확인할 수 있어야 한다. + +### Epic: [web-tests] Web 검증 분리 + +VM 단위 테스트와 Chrome/web 테스트가 서로 다른 platform expectation을 올바르게 검증하도록 나눈다. + +- [ ] [chrome-tests] `packages/messaging_flutter`의 Chrome/web 테스트가 web runtime에서는 browser notification support를 기대하고, VM 테스트는 non-web unsupported를 기대하도록 분리한다. 검증: 원격 runner에서 package Chrome 테스트가 통과해야 한다. +- [ ] [helper-route] workspace helper 또는 테스트 규칙에 web build/smoke opt-in 경로를 추가해 `bin/test`만으로 web smoke가 완료된 것처럼 보이지 않게 한다. 검증: web 검증을 생략한 경우 skip 또는 미실행 사유가 명확히 보고되어야 한다. + +### Epic: [evidence] 완료 Evidence + +완료 판정이 fake interop 단위 테스트에만 기대지 않도록 browser evidence 기준을 남긴다. + +- [ ] [manual-evidence] browser notification permission/display/click 수동 smoke evidence 기준을 민감값 없이 정리한다. 검증: 완료 리뷰에 원격 실행 명령, 사용자 확인 결과, 생략된 Full Web Push 범위가 함께 남아야 한다. + +## 완료 리뷰 + +- 상태: 없음 +- 요청일: 없음 +- 완료 근거: 없음 +- 리뷰 필요: + - [ ] 사용자가 완료 결과를 확인했다 + - [ ] archive 이동을 승인했다 +- 리뷰 코멘트: 없음 + +## 범위 제외 + +- 브라우저가 닫힌 상태에서도 수신되는 Full Web Push 구현 +- service worker, VAPID, `web_rn-v2` server device-token 등록, core/push-proxy web target 구현 +- Mattermost webapp UI/Redux 알림 구현 복제 +- 제품 앱 UI 또는 앱별 메시징 화면 구현 + +## 작업 컨텍스트 + +- 관련 경로: `packages/messaging_flutter/`, `apps/flutter-test/`, `bin/`, `agent-test/local/` +- 표준선(선택): 실제 host, port, credential, 포워딩 명령 원문은 tracked roadmap/docs에 쓰지 않고 ignored local test environment 문서 또는 사용자 제공 환경 기준에서 확인한다. +- 선행 작업: Flutter Web 알림 +- 후속 작업: Full Web Push platform 계약 +- 확인 필요: 원격 runner에서 Chrome/web device와 사용자가 접근 가능한 forwarded localhost URL을 함께 열어 실제 browser permission/display/click evidence를 남긴다. diff --git a/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/code_review_local_G06_0.log b/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/code_review_local_G06_0.log new file mode 100644 index 00000000..e3b9f015 --- /dev/null +++ b/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/code_review_local_G06_0.log @@ -0,0 +1,188 @@ + + +# Code Review Reference - WEB-SCAFFOLD + +> **[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, user-owned 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`. +> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only. + +## 개요 + +date=2026-06-08 +task=m-flutter-web-notification-smoke/01_web_scaffold, plan=0, tag=WEB-SCAFFOLD + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md` +- Task ids: + - `web-scaffold`: `apps/flutter-test`에 Flutter Web scaffold를 추가하고 web build가 통과하도록 구성한다. +- Completion mode: check-on-pass + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [WEB-SCAFFOLD-1] Web scaffold 추가 | [x] | +| [WEB-SCAFFOLD-2] Firebase web init fallback | [x] | +| [WEB-SCAFFOLD-3] README web host 기준 반영 | [x] | + +## 구현 체크리스트 + +- [x] `apps/flutter-test`에 Flutter Web scaffold를 추가한다. +- [x] web 실행 시 Firebase config 부재가 test host UI 자체를 막지 않도록 `main()` 초기화를 안전하게 조정한다. +- [x] `apps/flutter-test/README.md`의 Structure/Verification에 web host와 remote web build 기준을 반영하되 host/port 원문은 쓰지 않는다. +- [x] 원격 runner 기준으로 `apps/flutter-test` web build가 통과하는지 검증한다. +- [x] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. + +- [x] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [x] 판정과 `차원별 평가`, Required/Suggested/Nit 분류가 서로 일치한다. +- [x] active `CODE_REVIEW-*-G??.md`를 `code_review_{review_lane}_GNN_N.log`로 아카이브한다. +- [x] active `PLAN-*-G??.md`를 `plan_{build_lane}_GNN_M.log`로 아카이브한다. +- [x] `.gitignore`의 Agent-Ops 관리 block이 `agent-task/**/*.md`와 `agent-task/**/*.log`를 unignore하고 `agent-roadmap/current.md`를 ignore하는지 확인한다. +- [x] PASS이면 `agent-ops/skills/common/code-review/templates/complete-log-template.md` 기준으로 `complete.log`를 작성하고 active `.md` 파일을 남기지 않는다. +- [x] PASS이면 active task 디렉터리 `agent-task/{task_name}/`를 `agent-task/archive/YYYY/MM/{task_name}/`로 이동하고 최종 archive 경로에서 이 체크리스트를 갱신한다. +- [x] PASS이고 task group이 `m-`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, roadmap 수정이나 `update-roadmap` 직접 호출을 하지 않는다. +- [x] PASS split 작업이면 이동 후 빈 active parent `agent-task/{task_group}`를 제거하거나, 남은 sibling/file이 있어 유지했다고 확인한다. +- [ ] WARN/FAIL이고 user-review gate가 트리거되지 않았으면 다음 active `PLAN-{build_lane}-GNN.md`와 `CODE_REVIEW-{review_lane}-GNN.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`에 Flutter-generated web scaffold(`web/index.html`, `web/manifest.json`, favicon, icons)와 `.metadata` web platform metadata를 추가했다. +- `main()`의 Firebase 초기화를 `_initializeFirebaseForHarness()` best-effort helper로 분리해 Firebase web config가 없어도 harness UI가 렌더링되게 했다. +- `apps/flutter-test/README.md`에 `web/` host scaffold와 `flutter build web` 검증 기준을 추가하고, 실제 host/port/credential/forwarding 값은 tracked README에 쓰지 않는 기준으로 정리했다. + +### 계획 대비 변경 사항 + +- `agent-test/local/web-smoke.env`가 없어 최종 원격 명령은 local shell 변수로만 runner 값을 주입해 실행했다. tracked 파일에는 실제 원격 값을 기록하지 않았다. +- 원격 checkout이 dirty 상태라 직접 덮지 않고 현재 checkout을 `/tmp/nexo-web-scaffold.solJRQ` 임시 디렉터리에 복사해 검증했다. + +### 검증 결과 + +```text +$ cd apps/flutter-test && flutter pub get +Resolving dependencies... +Downloading packages... +Got dependencies! +11 packages have newer versions incompatible with dependency constraints. +``` + +```text +$ cd apps/flutter-test && flutter analyze --no-fatal-infos +Analyzing flutter-test... +No issues found! (ran in 4.1s) +``` + +```text +$ cd apps/flutter-test && flutter test +00:00 +0: loading /config/workspace/nexo/apps/flutter-test/test/widget_test.dart +00:00 +9: All tests passed! +``` + +```text +$ cd apps/flutter-test && flutter build web +Compiling lib/main.dart for the Web... +Wasm dry run succeeded. Consider building and testing your application with the `--wasm` flag. +Compiling lib/main.dart for the Web... 28.7s +✓ Built build/web +``` + +```text +$ cd apps/flutter-test && rg --sort path -n "web|browser|remote" README.md +57: web/ # Web test host scaffold for browser smoke checks +75:Android/iOS/device smoke tests and browser previews should receive runtime URLs +120:flutter build web +125:event-channel, and opened-routing coverage. Use `flutter build web` to verify +126:that the web host scaffold remains buildable before browser notification smoke +127:checks run on the remote runner. +``` + +원격 checkout 상태 확인 결과 기존 변경이 있어 임시 복사본에서 검증했다. + +```text +$ ssh "$NEXO_REMOTE_SSH" "zsh -lc 'cd ${NEXO_REMOTE_REPO} && git status --short'" + M README.md + M apps/flutter-test/pubspec.lock + M apps/mattermost/android/app/build.gradle + M bin/test + M docs/runtime-image-validation.md + M services/core/compose/README.md +?? agent-task/m-cicd-operations/ +``` + +```text +$ tar -czf - --exclude='.git' --exclude='*/build' --exclude='*/.dart_tool' --exclude='*/node_modules' --exclude='./agent-task/archive' --exclude='./agent-roadmap/archive' . | ssh "$NEXO_REMOTE_SSH" "tar -xzf - -C '$NEXO_REMOTE_TMP'" +# NEXO_REMOTE_TMP=/tmp/nexo-web-scaffold.solJRQ +# exit code 0 +``` + +```text +$ ssh "$NEXO_REMOTE_SSH" "zsh -lc 'cd ${NEXO_REMOTE_TMP}/apps/flutter-test && flutter pub get && flutter analyze --no-fatal-infos && flutter test && flutter build web'" +Resolving dependencies... +Changed 2 dependencies! +11 packages have newer versions incompatible with dependency constraints. +The following plugins do not support Swift Package Manager for ios: + - nexo_messaging +The following plugins do not support Swift Package Manager for macos: + - nexo_messaging +Analyzing flutter-test... +No issues found! (ran in 1.6s) +00:00 +0: loading /private/tmp/nexo-web-scaffold.solJRQ/apps/flutter-test/test/widget_test.dart +00:00 +9: All tests passed! +Compiling lib/main.dart for the Web... +Wasm dry run succeeded. Consider building and testing your application with the `--wasm` flag. +Compiling lib/main.dart for the Web... 22.1s +✓ Built build/web +``` + +### 남은 위험 + +- Browser notification permission/display/click 수동 smoke evidence는 계획대로 후속 `02+01_web_runtime` 범위다. +- 원격 Flutter는 iOS/macOS Swift Package Manager 미지원 경고를 출력했지만 현재 검증 명령은 exit code 0으로 통과했다. + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 코드리뷰 결과 + +### 2026-06-08 리뷰 + +- 종합 판정: PASS +- 차원별 평가: + - Correctness: Pass + - Completeness: Pass + - Test coverage: Pass + - API contract: Pass + - Code quality: Pass + - Plan deviation: Pass + - Verification trust: Pass +- 발견된 문제: 없음 +- 다음 단계: PASS이므로 `complete.log`를 작성하고 active task directory를 archive로 이동한다. diff --git a/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/complete.log b/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/complete.log new file mode 100644 index 00000000..b8aaa515 --- /dev/null +++ b/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/complete.log @@ -0,0 +1,44 @@ +# Complete - m-flutter-web-notification-smoke/01_web_scaffold + +## 완료 일시 + +2026-06-08 + +## 요약 + +Flutter Web scaffold 보완 작업을 1회 리뷰했고 최종 판정은 PASS다. + +## 루프 이력 + +| Plan | Review | Verdict | 메모 | +|------|--------|---------|------| +| `plan_local_G06_0.log` | `code_review_local_G06_0.log` | PASS | Web scaffold, Firebase init fallback, README web build 기준이 계획대로 반영됐고 검증이 통과했다. | + +## 구현/정리 내용 + +- `apps/flutter-test/web/` Flutter Web scaffold와 `.metadata` web platform metadata를 추가했다. +- `apps/flutter-test/lib/main.dart`에서 Firebase 초기화를 harness best-effort helper로 분리해 config 부재 시에도 UI가 렌더링되게 했다. +- `apps/flutter-test/README.md`에 web host scaffold와 `flutter build web` 검증 기준을 반영했다. + +## 최종 검증 + +- `flutter pub get` - PASS; `Got dependencies!`, 11개 newer-version 안내만 출력. +- `flutter analyze --no-fatal-infos` - PASS; `No issues found!`. +- `flutter test` - PASS; `00:00 +9: All tests passed!`. +- `flutter build web` - PASS; `Built build/web`. +- 원격 임시 복사본 검증 - PASS; `flutter pub get && flutter analyze --no-fatal-infos && flutter test && flutter build web`가 구현 로그 기준 exit code 0으로 완료됐다. + +## Roadmap Completion + +- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md` +- Completed task ids: + - `web-scaffold`: PASS; evidence=`plan_local_G06_0.log`, `code_review_local_G06_0.log`; verification=`flutter pub get`, `flutter analyze --no-fatal-infos`, `flutter test`, `flutter build web`, remote temporary-copy verification +- Not completed task ids: 없음 + +## 잔여 Nit + +- 없음 + +## 후속 작업 + +- 없음 diff --git a/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/plan_local_G06_0.log b/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/plan_local_G06_0.log new file mode 100644 index 00000000..9a9c1b42 --- /dev/null +++ b/agent-task/archive/2026/06/m-flutter-web-notification-smoke/01_web_scaffold/plan_local_G06_0.log @@ -0,0 +1,227 @@ + + +# Implementation Plan - WEB-SCAFFOLD + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 필수다. 구현 후 검증을 실행하고 실제 출력과 변경 내용을 채운 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 사용자 결정, 사용자 소유 외부 환경, scope 충돌 때문에 막히면 review stub의 `사용자 리뷰 요청` 섹션에 근거를 쓰고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 최종 archive, `complete.log`, roadmap 반영은 code-review/runtime 책임이다. + +## 배경 + +`Flutter Web 알림`은 완료 처리됐지만 `apps/flutter-test`가 web project로 구성되어 있지 않아 원격 runner에서 `flutter build web`이 실패한다. 첫 Epic의 선행 작업은 test host가 실제 Flutter Web build/run 대상이 되게 만드는 것이다. 이 작업은 `web-runtime` 수동 smoke의 선행 조건이다. + +## 사용자 리뷰 요청 흐름 + +구현 중 blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 질문은 금지하며, code-review가 blocker 타당성을 검증하고 필요할 때만 `USER_REVIEW.md`를 만든다. + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md` +- Task ids: + - `web-scaffold`: `apps/flutter-test`에 Flutter Web scaffold를 추가하고 web build가 통과하도록 구성한다. +- 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-smoke.md` +- `agent-ops/rules/project/domain/client-app/rules.md` +- `agent-ops/rules/project/domain/workspace-ops/rules.md` +- `agent-test/local/rules.md` +- `agent-test/local/client-app-smoke.md` +- `agent-test/local/runtime-env.md` +- `apps/flutter-test/pubspec.yaml` +- `apps/flutter-test/lib/main.dart` +- `apps/flutter-test/test/widget_test.dart` +- `apps/flutter-test/README.md` + +### 테스트 환경 규칙 + +사용자 지시상 local 수용 검증은 사용하지 않는다. 규칙 파일명은 `agent-test/local/rules.md`지만, 이번 검증은 이 규칙의 `runtime-env` profile에 있는 standard remote runner를 사용한다. `client-app-smoke`의 기본 명령은 `flutter pub get`, `flutter analyze --no-fatal-infos`, `flutter test`이며, web build는 repository manifest fallback으로 `flutter build web`을 추가한다. 실제 host, port, credential 값은 tracked plan/review에 쓰지 않고 ignored environment profile에서 변수로 주입한다. + +### 테스트 커버리지 공백 + +- Web scaffold 부재: 기존 widget tests는 `MyApp` UI만 검증하고 web platform scaffold나 `flutter build web`을 검증하지 않는다. +- Firebase web config 부재: `apps/flutter-test/lib/main.dart:7-10`은 `Firebase.initializeApp()` 실패 시 앱 UI를 띄우지 못할 수 있다. 기존 tests는 `main()`을 실행하지 않으므로 이 gap을 잡지 못한다. +- Browser notification permission/display/click 수동 smoke는 후속 `02+01_web_runtime` 계획에서 다룬다. + +### 심볼 참조 + +Renamed/removed symbols: none. 새 helper를 추가할 경우 call site는 `main()` 하나다. + +### 분할 판단 + +Split policy 적용 결과, 첫 Epic은 두 subtask로 분리한다. 공유 task group은 `agent-task/m-flutter-web-notification-smoke/`다. + +- `01_web_scaffold`: web scaffold와 web build 가능 상태를 만든다. 독립 선행 작업. +- `02+01_web_runtime`: 사용자가 접근하는 forwarded browser smoke 절차와 evidence를 다룬다. `01_web_scaffold` 완료 후 실행한다. + +분리 이유: generated platform scaffold와 interactive browser evidence는 위험과 검증 방식이 다르다. user-owned browser/port-forward evidence는 별도 plan에서 다루는 것이 review 가능하다. + +### 범위 결정 근거 + +이 계획은 `apps/flutter-test` web host scaffold와 web build 가능성만 다룬다. `packages/messaging_flutter` Chrome test 분리, workspace helper opt-in, Full Web Push, service worker, VAPID, core/push-proxy web target은 제외한다. 원격 preview run과 사용자 수동 smoke evidence는 dependent subtask가 담당한다. + +### 빌드 등급 + +Build lane/grade: `local-G06`. Generated web scaffold와 Firebase web init fallback이 포함되지만 범위는 `apps/flutter-test`로 제한되고 원격 web build로 검증 가능하다. + +## 구현 체크리스트 + +- [ ] `apps/flutter-test`에 Flutter Web scaffold를 추가한다. +- [ ] web 실행 시 Firebase config 부재가 test host UI 자체를 막지 않도록 `main()` 초기화를 안전하게 조정한다. +- [ ] `apps/flutter-test/README.md`의 Structure/Verification에 web host와 remote web build 기준을 반영하되 host/port 원문은 쓰지 않는다. +- [ ] 원격 runner 기준으로 `apps/flutter-test` web build가 통과하는지 검증한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +### [WEB-SCAFFOLD-1] Web scaffold 추가 + +#### 문제 + +`apps/flutter-test` 하위에 `web/` 디렉터리가 없다. 현재 `flutter build web`은 `This project is not configured for the web.`로 실패한다. + +#### 해결 방법 + +`apps/flutter-test`에서 Flutter web scaffold만 생성한다. + +```sh +cd apps/flutter-test +flutter create . --platforms web --project-name nexo_client +``` + +생성 결과에서 Android/iOS/macOS/Linux/Windows 파일이 변경되면 web scaffold와 직접 관련 없는 generated churn이므로 되돌리지 말고 먼저 diff를 확인하고, 불필요한 대량 변경은 구현 범위에서 제외한다. 유지 대상은 `apps/flutter-test/web/**`와 web build에 필요한 최소 metadata다. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/flutter-test/web/index.html` +- [ ] `apps/flutter-test/web/manifest.json` +- [ ] `apps/flutter-test/web/favicon.png` +- [ ] `apps/flutter-test/web/icons/**` +- [ ] `apps/flutter-test/.metadata`가 생성/갱신되면 web scaffold에 필요한지 diff로 확인한다. + +#### 테스트 작성 + +새 Dart test는 작성하지 않는다. 이 항목은 generated platform scaffold 추가이며 pass/fail은 web build로 판정한다. + +#### 중간 검증 + +```sh +cd apps/flutter-test && flutter build web +``` + +기대 결과: web project 구성 오류 없이 build가 성공한다. + +### [WEB-SCAFFOLD-2] Firebase web init fallback + +#### 문제 + +`apps/flutter-test/lib/main.dart:7-10`은 앱 UI를 띄우기 전에 `Firebase.initializeApp()`을 await한다. + +```dart +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + await Firebase.initializeApp(); + runApp(const MyApp()); +} +``` + +Web smoke는 민감값 없는 foreground notification UI를 확인하는 것이 목적이다. Firebase web config가 없는 상태에서 초기화 실패가 앱 렌더링을 막으면 permission/display smoke controls에 접근할 수 없다. + +#### 해결 방법 + +Firebase 초기화를 harness best-effort helper로 분리하고 실패해도 UI는 렌더링한다. 기존 `_initializePlugin()`의 try/catch처럼 test host가 상태 UI를 계속 보여주게 한다. + +```dart +Future main() async { + WidgetsFlutterBinding.ensureInitialized(); + await _initializeFirebaseForHarness(); + runApp(const MyApp()); +} + +Future _initializeFirebaseForHarness() async { + try { + await Firebase.initializeApp(); + } catch (error, stackTrace) { + debugPrint('[NexoClient] Firebase initialization skipped: $error'); + debugPrintStack(stackTrace: stackTrace); + } +} +``` + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/flutter-test/lib/main.dart` + +#### 테스트 작성 + +별도 mock Firebase test는 작성하지 않는다. `test/widget_test.dart`는 `MyApp(initializePlugin: false)`를 직접 pump해 UI contract를 검증한다. 실제 web startup은 build와 후속 runtime smoke로 검증한다. + +#### 중간 검증 + +```sh +cd apps/flutter-test && flutter test +cd apps/flutter-test && flutter build web +``` + +기대 결과: widget tests PASS, web build PASS. + +### [WEB-SCAFFOLD-3] README web host 기준 반영 + +#### 문제 + +`apps/flutter-test/README.md:47-57`의 구조 목록에 `web/`이 없고, `apps/flutter-test/README.md:73-76`은 browser preview가 "added later"라고 되어 있다. + +```text +apps/flutter-test/ + lib/ # Small test harness UI + test/ # Widget tests for the harness + integration_test/ # Device/emulator plugin integration tests + android/ # Android test host used to load the plugin + ios/ # iOS host scaffold + macos/ # macOS host scaffold +``` + +#### 해결 방법 + +README에 web scaffold와 remote-runner smoke 기준을 추가한다. 실제 host, port, credential, forwarding command 값은 tracked README에 쓰지 않는다. ignored environment profile 또는 사용자 제공 환경에서 확인한다고 적는다. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/flutter-test/README.md` + +#### 테스트 작성 + +문서 변경은 테스트를 추가하지 않는다. + +#### 중간 검증 + +```sh +rg --sort path -n "web|browser|remote" apps/flutter-test/README.md +``` + +기대 결과: web host 기준이 README에 있고 민감한 환경값 원문이 없다. + +## 수정 파일 요약 + +| 파일 | 항목 | +| --- | --- | +| `apps/flutter-test/web/**` | WEB-SCAFFOLD-1 | +| `apps/flutter-test/.metadata` | WEB-SCAFFOLD-1 | +| `apps/flutter-test/lib/main.dart` | WEB-SCAFFOLD-2 | +| `apps/flutter-test/README.md` | WEB-SCAFFOLD-3 | + +## 최종 검증 + +아래 명령은 ignored environment profile에서 `NEXO_REMOTE_SSH`와 `NEXO_REMOTE_REPO`를 주입한 뒤 실행한다. 실제 값은 tracked 파일에 기록하지 않는다. + +```sh +set -a; source agent-test/local/web-smoke.env; set +a +ssh "$NEXO_REMOTE_SSH" "zsh -lc 'cd ${NEXO_REMOTE_REPO}/apps/flutter-test && flutter pub get && flutter analyze --no-fatal-infos && flutter test && flutter build web'" +``` + +기대 결과: 모든 명령 exit code 0. 원격 checkout이 dirty여서 현재 작업 diff를 반영할 수 없으면 구현 에이전트는 현재 checkout을 원격 임시 디렉터리에 복사해 같은 명령을 실행하고, 복사 경로와 명령 출력을 review stub에 기록한다. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/agent-task/m-flutter-web-notification-smoke/02+01_web_runtime/CODE_REVIEW-cloud-G07.md b/agent-task/m-flutter-web-notification-smoke/02+01_web_runtime/CODE_REVIEW-cloud-G07.md new file mode 100644 index 00000000..9a5f937b --- /dev/null +++ b/agent-task/m-flutter-web-notification-smoke/02+01_web_runtime/CODE_REVIEW-cloud-G07.md @@ -0,0 +1,90 @@ + + +# Code Review Reference - WEB-RUNTIME + +> **[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, user-owned 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`. +> Do not ask the user directly, present choices in chat, or call `request_user_input` during implementation. +> Finalization (`코드리뷰 결과`, log rename, `complete.log`, archive moves, `코드리뷰 전용 체크리스트`) is review-agent-only. + +## 개요 + +date=2026-06-08 +task=m-flutter-web-notification-smoke/02+01_web_runtime, plan=0, tag=WEB-RUNTIME + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md` +- Task ids: + - `web-runtime`: 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다. +- Completion mode: check-on-pass + +## 이 파일을 읽는 리뷰 에이전트에게 + +> **[REVIEW AGENT ONLY]** 아래 종결 절차는 코드리뷰 에이전트 전용이다. 구현 에이전트는 이 섹션을 실행하지 않는다. + +각 항목의 구현을 실제 소스 파일과 대조하고, `검증 결과` 섹션의 출력이 코드와 일치하는지 확인하세요. PASS이고 task group이 `m-`이면 완료 이벤트 메타데이터를 보고한다. roadmap 상태 체크와 `update-roadmap` 호출은 런타임 책임이다. + +--- + +## 구현 항목별 완료 여부 + +| 항목 | 완료 여부 | +|------|---------| +| [WEB-RUNTIME-1] Predecessor gate | [ ] | +| [WEB-RUNTIME-2] Ignored remote preview environment contract | [ ] | +| [WEB-RUNTIME-3] README smoke procedure 연결 | [ ] | +| [WEB-RUNTIME-4] Remote server reachability and user evidence handoff | [ ] | + +## 구현 체크리스트 + +- [ ] `01_web_scaffold` predecessor complete log를 확인한다. +- [ ] remote preview 실행에 필요한 ignored environment variable contract를 `agent-test/local/runtime-env.md` 또는 별도 ignored profile에 정리한다. +- [ ] `apps/flutter-test/README.md`에 web runtime smoke 절차를 환경값 없이 연결한다. +- [ ] 원격 preview server reachability를 검증하고 사용자 browser smoke evidence 수집 조건을 기록한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +## 코드리뷰 전용 체크리스트 + +> **[REVIEW AGENT ONLY]** 이 체크리스트는 코드리뷰 에이전트만 사용한다. + +- [ ] `코드리뷰 결과`에 `PASS`, `WARN`, `FAIL` 중 하나의 판정을 append한다. +- [ ] 판정과 Required/Suggested/Nit 분류가 서로 일치한다. +- [ ] PASS이면 `complete.log`를 작성하고 active task directory archive 준비를 한다. + +## 구현 에이전트 기록 + +### 변경 요약 + +_구현 에이전트가 실제 변경 요약을 작성한다._ + +### 계획 대비 변경 사항 + +_계획과 달라진 점이 없으면 `없음`이라고 쓴다._ + +### 검증 결과 + +_실행한 명령과 실제 stdout/stderr를 붙인다. 출력이 길면 저장 경로와 저장 명령을 기록한다._ + +### 남은 위험 + +_남은 위험이 없으면 `없음`이라고 쓴다._ + +## 사용자 리뷰 요청 + +_기본값은 `없음`이다. 구현 중 사용자 결정, 사용자 소유 외부 환경/secret/서비스 준비, 또는 계획 범위 변경 없이는 안전하게 진행할 수 없으면 아래 항목을 실제 내용으로 교체하고, 구현을 중단한 뒤 active 파일을 그대로 둔 채 리뷰를 요청한다. 구현 에이전트는 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 후속 에이전트가 명령 재실행이나 산출물 수집으로 해소할 수 있는 검증 증거 공백만으로는 사용자 리뷰 요청을 작성하지 않는다._ + +- 상태: 없음 +- 사유 유형: 없음 +- 결정 필요: 없음 +- 차단 근거: 없음 +- 실행한 검증/명령: 없음 +- 자동 후속 불가 이유: 없음 +- 재개 조건: 없음 + +## 코드리뷰 결과 + +_리뷰 에이전트가 판정을 append한다._ diff --git a/agent-task/m-flutter-web-notification-smoke/02+01_web_runtime/PLAN-cloud-G07.md b/agent-task/m-flutter-web-notification-smoke/02+01_web_runtime/PLAN-cloud-G07.md new file mode 100644 index 00000000..6f592d7b --- /dev/null +++ b/agent-task/m-flutter-web-notification-smoke/02+01_web_runtime/PLAN-cloud-G07.md @@ -0,0 +1,231 @@ + + +# Implementation Plan - WEB-RUNTIME + +## 이 파일을 읽는 구현 에이전트에게 + +`CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채우는 것이 필수다. 구현 후 검증을 실행하고 실제 출력과 변경 내용을 채운 뒤 active 파일을 그대로 두고 리뷰 준비를 보고한다. 사용자 결정, 사용자 소유 외부 환경, scope 충돌 때문에 막히면 review stub의 `사용자 리뷰 요청` 섹션에 근거를 쓰고 멈춘다. 구현 중 사용자에게 직접 질문하거나 선택지를 제시하거나 `request_user_input`을 호출하지 않는다. 최종 archive, `complete.log`, roadmap 반영은 code-review/runtime 책임이다. + +## 배경 + +`web-runtime`은 Flutter Web server를 원격 preview surface에 띄우고, 사용자가 forwarded localhost URL에서 browser notification permission/display/click 상태를 확인할 수 있게 만드는 작업이다. 이 작업은 `01_web_scaffold`가 web build 가능한 host를 만든 뒤에만 의미가 있다. 실제 host/port/credential 값은 tracked 파일에 쓰지 않는다. + +## 사용자 리뷰 요청 흐름 + +구현 중 blocker는 active review stub의 `사용자 리뷰 요청` 섹션에 기록한다. 직접 사용자 질문은 금지하며, code-review가 blocker 타당성을 검증하고 필요할 때만 `USER_REVIEW.md`를 만든다. 사용자가 forwarded browser를 열어야 하는 수동 evidence가 마지막 blocker로 남으면 실행한 명령, server 상태, 재개 조건을 기록한다. + +## Roadmap Targets + +- Milestone: `agent-roadmap/phase/messaging-runtime/milestones/flutter-web-notification-smoke.md` +- Task ids: + - `web-runtime`: 원격 Flutter Web server와 forwarded localhost URL 기반 수동 smoke 절차를 정리한다. +- 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-smoke.md` +- `agent-ops/rules/project/domain/client-app/rules.md` +- `agent-ops/rules/project/domain/workspace-ops/rules.md` +- `agent-test/local/rules.md` +- `agent-test/local/client-app-smoke.md` +- `agent-test/local/runtime-env.md` +- `apps/flutter-test/pubspec.yaml` +- `apps/flutter-test/lib/main.dart` +- `apps/flutter-test/test/widget_test.dart` +- `apps/flutter-test/README.md` + +### 테스트 환경 규칙 + +사용자 지시상 local 수용 검증은 사용하지 않는다. `agent-test/local/runtime-env.md`의 standard remote runner를 사용하되, 실제 host/port/credential 값은 ignored environment profile에서 변수로 주입한다. `client-app-smoke`의 widget/unit 검증은 참고하되, browser notification permission/display/click evidence는 원격 preview와 사용자 browser 확인이 필요하다. + +### 테스트 커버리지 공백 + +- Existing widget tests cover smoke control presence, unsupported VM display, and opened routing via injected events. +- Existing tests do not prove that a remote Flutter Web server is reachable through the preview/forwarded URL. +- Existing tests do not prove browser permission prompt, visible browser notification display, or click/open routing in a real browser. This plan records the manual evidence path and blocker handoff. + +### 심볼 참조 + +Renamed/removed symbols: none. + +### 분할 판단 + +이 plan은 `agent-task/m-flutter-web-notification-smoke/02+01_web_runtime`이며 predecessor index `01`에 의존한다. 구현 전 같은 task group에서 `01_web_scaffold/complete.log`가 active 또는 archive에 있는지 확인해야 한다. 없으면 구현하지 말고 dependency missing으로 보고한다. + +### 범위 결정 근거 + +이 계획은 첫 Epic의 `web-runtime` Task만 다룬다. Web scaffold 구현은 `01_web_scaffold`가 완료해야 한다. `packages/messaging_flutter` Chrome test 분리, workspace helper opt-in, Full Web Push, service worker, VAPID, core/push-proxy web target은 제외한다. + +### 빌드 등급 + +Build lane/grade: `cloud-G07`. Remote preview process control, forwarded browser evidence, and user-owned permission UI are central success conditions. + +## 의존 관계 및 구현 순서 + +1. `agent-task/m-flutter-web-notification-smoke/01_web_scaffold/complete.log` 또는 archive의 같은 predecessor complete log를 확인한다. +2. 완료 로그가 없으면 구현을 시작하지 않는다. +3. 완료 로그가 있으면 remote preview runbook/evidence 절차를 보강하고 server reachability를 검증한다. + +## 구현 체크리스트 + +- [ ] `01_web_scaffold` predecessor complete log를 확인한다. +- [ ] remote preview 실행에 필요한 ignored environment variable contract를 `agent-test/local/runtime-env.md` 또는 별도 ignored profile에 정리한다. +- [ ] `apps/flutter-test/README.md`에 web runtime smoke 절차를 환경값 없이 연결한다. +- [ ] 원격 preview server reachability를 검증하고 사용자 browser smoke evidence 수집 조건을 기록한다. +- [ ] CODE_REVIEW-*-G??.md의 구현 에이전트 소유 섹션을 실제 구현 내용과 검증 출력으로 채운다. 이 항목이 완료되기 전에는 구현이 완료된 것이 아니다. + +### [WEB-RUNTIME-1] Predecessor gate + +#### 문제 + +`web-runtime`은 web build 가능한 host가 있어야 실행 가능하다. 현재 subtask name `02+01_web_runtime`은 predecessor `01` 완료를 runtime dependency로 선언한다. + +#### 해결 방법 + +구현 시작 전에 active/archive 후보만 확인한다. + +```sh +find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/01_*/*' -name complete.log -print +find agent-task/archive -path '*/m-flutter-web-notification-smoke/01_*/complete.log' -print +``` + +#### 수정 파일 및 체크리스트 + +- [ ] 이 항목은 파일 수정 없음. + +#### 테스트 작성 + +테스트 없음. Dependency gate는 file protocol 확인이다. + +#### 중간 검증 + +기대 결과: predecessor complete log가 정확히 하나 확인된다. + +### [WEB-RUNTIME-2] Ignored remote preview environment contract + +#### 문제 + +원격 web smoke에는 remote shell, repo path, preview container, container repo path, web server port 같은 환경값이 필요하다. tracked docs/roadmap/task/review log에 원문 값을 쓰면 안 된다. + +#### 해결 방법 + +ignored local test environment 문서 또는 ignored env profile에 변수 contract만 정리한다. tracked plan/review에는 변수명만 남긴다. + +필요 변수 후보: + +```sh +NEXO_REMOTE_SSH +NEXO_REMOTE_REPO +NEXO_PREVIEW_CONTAINER +NEXO_CONTAINER_REPO +NEXO_WEB_HOSTNAME +NEXO_CONTAINER_WEB_PORT +NEXO_BROWSER_PREVIEW_URL +``` + +#### 수정 파일 및 체크리스트 + +- [ ] `agent-test/local/runtime-env.md` 또는 ignored local profile + +#### 테스트 작성 + +테스트 없음. 환경 contract 문서화 작업이다. + +#### 중간 검증 + +```sh +set -a; source agent-test/local/web-smoke.env; set +a +test -n "$NEXO_REMOTE_SSH" +test -n "$NEXO_PREVIEW_CONTAINER" +test -n "$NEXO_WEB_HOSTNAME" +test -n "$NEXO_CONTAINER_WEB_PORT" +``` + +기대 결과: 필요한 변수들이 비어 있지 않다. 실제 값은 review output에 출력하지 않는다. + +### [WEB-RUNTIME-3] README smoke procedure 연결 + +#### 문제 + +`apps/flutter-test/README.md:73-76`은 browser preview가 나중에 추가된다고 되어 있고, 실제 remote preview smoke 절차로 이어지지 않는다. 해당 문단은 기존 frontend slot을 언급하지만, 이 plan/review에는 실제 port 값을 반복 기록하지 않는다. + +#### 해결 방법 + +README는 공개/사람용 문서이므로 값 원문을 쓰지 않고, ignored environment profile을 통해 remote preview server를 띄운 뒤 forwarded localhost URL에서 확인한다는 절차만 적는다. Browser smoke checklist는 permission request, display status, click/open routing status를 포함해야 한다. + +#### 수정 파일 및 체크리스트 + +- [ ] `apps/flutter-test/README.md` + +#### 테스트 작성 + +문서 변경은 테스트를 추가하지 않는다. + +#### 중간 검증 + +```sh +rg --sort path -n "Web|browser|permission|display|click|forwarded|environment" apps/flutter-test/README.md +``` + +기대 결과: web runtime smoke 절차가 환경값 없이 연결된다. + +### [WEB-RUNTIME-4] Remote server reachability and user evidence handoff + +#### 문제 + +Browser notification permission/display/click은 agent-only terminal 검증으로 완료할 수 없다. 사용자가 forwarded browser URL을 열어 확인해야 한다. + +#### 해결 방법 + +원격 preview server를 실행하고 reachability를 확인한다. 사용자가 browser를 열어야 하는 단계가 남으면 `사용자 리뷰 요청`에 server 상태, URL 확인 방법의 변수명, 재개 조건을 기록한다. + +```sh +set -a; source agent-test/local/web-smoke.env; set +a +ssh "$NEXO_REMOTE_SSH" "zsh -lc 'docker exec ${NEXO_PREVIEW_CONTAINER} sh -lc \"cd ${NEXO_CONTAINER_REPO}/apps/flutter-test && flutter run -d web-server --web-hostname ${NEXO_WEB_HOSTNAME} --web-port ${NEXO_CONTAINER_WEB_PORT}\"'" +``` + +별도 shell에서 reachability: + +```sh +set -a; source agent-test/local/web-smoke.env; set +a +ssh "$NEXO_REMOTE_SSH" "zsh -lc 'curl -fsSI ${NEXO_BROWSER_PREVIEW_URL}'" +``` + +#### 수정 파일 및 체크리스트 + +- [ ] `CODE_REVIEW-cloud-G07.md` 검증 결과 또는 사용자 리뷰 요청 + +#### 테스트 작성 + +자동 테스트 없음. 사용자 browser permission UI가 필요한 manual smoke다. + +#### 중간 검증 + +기대 결과: server가 응답한다. 사용자가 forwarded browser에서 permission request, notification display, click/open routing 상태를 확인하면 review stub에 결과를 기록한다. 사용자가 열어야 해서 agent가 끝낼 수 없으면 `사용자 리뷰 요청`으로 남긴다. + +## 수정 파일 요약 + +| 파일 | 항목 | +| --- | --- | +| `agent-test/local/runtime-env.md` 또는 ignored local profile | WEB-RUNTIME-2 | +| `apps/flutter-test/README.md` | WEB-RUNTIME-3 | +| `agent-task/m-flutter-web-notification-smoke/02+01_web_runtime/CODE_REVIEW-cloud-G07.md` | WEB-RUNTIME-4 | + +## 최종 검증 + +아래 명령은 ignored environment profile에서 필요한 값을 주입한 뒤 실행한다. 실제 값은 tracked 파일에 기록하지 않는다. + +```sh +find agent-task/m-flutter-web-notification-smoke -maxdepth 2 -path '*/01_*/*' -name complete.log -print +set -a; source agent-test/local/web-smoke.env; set +a +ssh "$NEXO_REMOTE_SSH" "zsh -lc 'docker exec ${NEXO_PREVIEW_CONTAINER} sh -lc \"cd ${NEXO_CONTAINER_REPO}/apps/flutter-test && flutter build web\"'" +ssh "$NEXO_REMOTE_SSH" "zsh -lc 'curl -fsSI ${NEXO_BROWSER_PREVIEW_URL}'" +``` + +기대 결과: predecessor complete log 확인, remote/container web build PASS, preview URL HEAD 응답 PASS. Browser permission/display/click은 사용자 forwarded browser evidence가 필요하며, 완료하지 못하면 review stub의 `사용자 리뷰 요청`에 재개 조건을 기록한다. + +모든 코드 변경 완료 후 반드시 `CODE_REVIEW-*-G??.md`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다. diff --git a/apps/flutter-test/.metadata b/apps/flutter-test/.metadata new file mode 100644 index 00000000..59d7aa3e --- /dev/null +++ b/apps/flutter-test/.metadata @@ -0,0 +1,30 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa + base_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa + - platform: web + create_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa + base_revision: 2c9eb20739dfec95e2c74bd3dfa4601b0a8a36aa + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/apps/flutter-test/README.md b/apps/flutter-test/README.md index f7c7ef91..1dc047da 100644 --- a/apps/flutter-test/README.md +++ b/apps/flutter-test/README.md @@ -54,6 +54,7 @@ apps/flutter-test/ android/ # Android test host used to load the plugin ios/ # iOS host scaffold macos/ # macOS host scaffold + web/ # Web test host scaffold for browser smoke checks ``` ## Running The App @@ -70,10 +71,9 @@ Run on a connected device or emulator: flutter run ``` -This harness does not own a default host HTTP port. Android/iOS/device smoke -tests should receive runtime URLs from the invoking shell or ignored local -profiles. If a browser preview is added later, use the workspace frontend slot -`13040` unless a later migration plan changes the baseline. +This harness does not own default host, port, credential, or forwarding values. +Android/iOS/device smoke tests and browser previews should receive runtime URLs +from the invoking shell or ignored local profiles. For Android FCM smoke testing, make sure the Android app has the required Firebase configuration, including `android/app/google-services.json`. @@ -117,11 +117,14 @@ Run checks from this directory: flutter analyze flutter test flutter test integration_test +flutter build web ``` Use `flutter test` for the thin-host contract and `flutter test integration_test` for real Flutter host registration, method-channel, -event-channel, and opened-routing coverage. +event-channel, and opened-routing coverage. Use `flutter build web` to verify +that the web host scaffold remains buildable before browser notification smoke +checks run on the remote runner. Run Android native unit tests from `apps/flutter-test/android`: diff --git a/apps/flutter-test/lib/main.dart b/apps/flutter-test/lib/main.dart index 07a4a3a2..0b23cf08 100644 --- a/apps/flutter-test/lib/main.dart +++ b/apps/flutter-test/lib/main.dart @@ -6,10 +6,19 @@ import 'package:nexo_messaging/nexo_messaging.dart'; Future main() async { WidgetsFlutterBinding.ensureInitialized(); - await Firebase.initializeApp(); + await _initializeFirebaseForHarness(); runApp(const MyApp()); } +Future _initializeFirebaseForHarness() async { + try { + await Firebase.initializeApp(); + } catch (error, stackTrace) { + debugPrint('[NexoClient] Firebase initialization skipped: $error'); + debugPrintStack(stackTrace: stackTrace); + } +} + class MyApp extends StatefulWidget { const MyApp({super.key, this.initializePlugin = true}); @@ -173,8 +182,7 @@ class _MyAppState extends State { key: const Key('web-display-status'), ), ElevatedButton( - onPressed: () => - unawaited(_refreshWebNotificationStatus(plugin)), + onPressed: () => unawaited(_refreshWebNotificationStatus(plugin)), child: const Text('Refresh web permission'), ), ElevatedButton( diff --git a/apps/flutter-test/web/favicon.png b/apps/flutter-test/web/favicon.png new file mode 100644 index 00000000..8aaa46ac Binary files /dev/null and b/apps/flutter-test/web/favicon.png differ diff --git a/apps/flutter-test/web/icons/Icon-192.png b/apps/flutter-test/web/icons/Icon-192.png new file mode 100644 index 00000000..b749bfef Binary files /dev/null and b/apps/flutter-test/web/icons/Icon-192.png differ diff --git a/apps/flutter-test/web/icons/Icon-512.png b/apps/flutter-test/web/icons/Icon-512.png new file mode 100644 index 00000000..88cfd48d Binary files /dev/null and b/apps/flutter-test/web/icons/Icon-512.png differ diff --git a/apps/flutter-test/web/icons/Icon-maskable-192.png b/apps/flutter-test/web/icons/Icon-maskable-192.png new file mode 100644 index 00000000..eb9b4d76 Binary files /dev/null and b/apps/flutter-test/web/icons/Icon-maskable-192.png differ diff --git a/apps/flutter-test/web/icons/Icon-maskable-512.png b/apps/flutter-test/web/icons/Icon-maskable-512.png new file mode 100644 index 00000000..d69c5669 Binary files /dev/null and b/apps/flutter-test/web/icons/Icon-maskable-512.png differ diff --git a/apps/flutter-test/web/index.html b/apps/flutter-test/web/index.html new file mode 100644 index 00000000..2516cc2e --- /dev/null +++ b/apps/flutter-test/web/index.html @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + nexo_client + + + + + + + diff --git a/apps/flutter-test/web/manifest.json b/apps/flutter-test/web/manifest.json new file mode 100644 index 00000000..66eb24c9 --- /dev/null +++ b/apps/flutter-test/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "nexo_client", + "short_name": "nexo_client", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +}