test(client-app): Flutter Web smoke 보완을 준비한다

브라우저 smoke의 선행 조건으로 test host를 web build 가능 상태로 만들고, 후속 runtime evidence 계획과 완료 로그를 함께 남긴다.
This commit is contained in:
toki 2026-06-08 10:52:46 +09:00
parent 26e8d698d6
commit e2823b38e0
17 changed files with 991 additions and 8 deletions

View file

@ -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 기준으로 검증한다.

View file

@ -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를 남긴다.

View file

@ -0,0 +1,188 @@
<!-- task=m-flutter-web-notification-smoke/01_web_scaffold plan=0 tag=WEB-SCAFFOLD -->
# 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-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. 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-<milestone-slug>`이면 런타임이 읽을 완료 이벤트 메타데이터를 보고하고, 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로 이동한다.

View file

@ -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
- 없음
## 후속 작업
- 없음

View file

@ -0,0 +1,227 @@
<!-- task=m-flutter-web-notification-smoke/01_web_scaffold plan=0 tag=WEB-SCAFFOLD -->
# 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<void> 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<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await _initializeFirebaseForHarness();
runApp(const MyApp());
}
Future<void> _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`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -0,0 +1,90 @@
<!-- task=m-flutter-web-notification-smoke/02+01_web_runtime plan=0 tag=WEB-RUNTIME -->
# 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-<milestone-slug>`이면 완료 이벤트 메타데이터를 보고한다. 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한다._

View file

@ -0,0 +1,231 @@
<!-- task=m-flutter-web-notification-smoke/02+01_web_runtime plan=0 tag=WEB-RUNTIME -->
# 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`의 구현 에이전트 소유 섹션을 채운다. 이 파일 작성이 구현의 마지막 단계다.

View file

@ -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'

View file

@ -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`:

View file

@ -6,10 +6,19 @@ import 'package:nexo_messaging/nexo_messaging.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
await _initializeFirebaseForHarness();
runApp(const MyApp());
}
Future<void> _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<MyApp> {
key: const Key('web-display-status'),
),
ElevatedButton(
onPressed: () =>
unawaited(_refreshWebNotificationStatus(plugin)),
onPressed: () => unawaited(_refreshWebNotificationStatus(plugin)),
child: const Text('Refresh web permission'),
),
ElevatedButton(

Binary file not shown.

After

Width:  |  Height:  |  Size: 917 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html>
<head>
<!--
If you are serving your web app in a path other than the root, change the
href value below to reflect the base path you are serving from.
The path provided below has to start and end with a slash "/" in order for
it to work correctly.
For more details:
* https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
This is a placeholder for base href that will be replaced by the value of
the `--base-href` argument provided to `flutter build`.
-->
<base href="$FLUTTER_BASE_HREF">
<meta charset="UTF-8">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<meta name="description" content="A new Flutter project.">
<!-- iOS meta tags & icons -->
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="nexo_client">
<link rel="apple-touch-icon" href="icons/Icon-192.png">
<!-- Favicon -->
<link rel="icon" type="image/png" href="favicon.png"/>
<title>nexo_client</title>
<link rel="manifest" href="manifest.json">
</head>
<body>
<!--
You can customize the "flutter_bootstrap.js" script.
This is useful to provide a custom configuration to the Flutter loader
or to give the user feedback during the initialization process.
For more details:
* https://docs.flutter.dev/platform-integration/web/initialization
-->
<script src="flutter_bootstrap.js" async></script>
</body>
</html>

View file

@ -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"
}
]
}