diff --git a/README.md b/README.md index 21da5f2..74f01c2 100644 --- a/README.md +++ b/README.md @@ -73,8 +73,9 @@ - Phase 1 **A~C** + Track A/B/C + **Q8**(로그인·설정·로그아웃) 코드 완료 - 라이브: [`https://msn.iykyka.com`](https://msn.iykyka.com) · 데모 코드 **`DEMO-YKAVU`** -- **진행 중 (설계 완료·구현 Wi 승인 대기):** 웹 고도화 [`docs/web-upgrade.md`](./docs/web-upgrade.md) (W0 경계 done · W1~W7 todo) -- **후순위 (Master):** Android N4 — `google-services.json` · 실기기 FCM · UI 탭 · APK · `SHARE_URL` +- **웹 고도화 (W0~W7):** 구현·배포 완료 — [`docs/web-upgrade.md`](./docs/web-upgrade.md). + **남은 것:** W4 **accept** (하드 리프레시·알림 허용·로그인 후 `/admin/push-test` → `sent >= 1`) +- **후순위 (Master):** Android N4 — `google-services.json` PC 배치 · 실기기 FCM · UI 탭 · APK · `SHARE_URL` - **결정 대기:** Q9 — L2 의미 (카피 정렬 ± 수신 자동응대) — 웹 트랙에도 **비범위** - **맨 마지막:** N5 / D — 사람 PoC. §3 기본값 추측 금지 diff --git a/docs/deploy-checklist.md b/docs/deploy-checklist.md index 4321080..688af0d 100644 --- a/docs/deploy-checklist.md +++ b/docs/deploy-checklist.md @@ -37,8 +37,8 @@ Phase 1 **A~C** 이후 실행 트랙. 작업 단위를 하나씩 처리한다. - 앱 코드는 클로즈드 베타 직전 수준 - **`https://msn.iykyka.com` 라이브 + N3 완료 + Gemini 실초안 OK + Track A/B 완료** -- **웹 고도화:** [`web-upgrade.md`](./web-upgrade.md) — W0~W3·W5~W7 **done** · **W4 web APP_ID live** (accept: 브라우저 하드 리프레시·알림 허용·push-test) -- 후순위: **N4 Android FCM/UI** — Master 시크릿·실기기 +- **웹 고도화:** [`web-upgrade.md`](./web-upgrade.md) — W0~W7 구현·배포 **done** · **W4 accept만** (하드 리프레시·알림·push-test) +- 후순위: **N4 Android FCM/UI** — `google-services.json` PC 배치·실기기 (서버 SA는 배치됨) - UI: **iMessage-inspired light default** + soft charcoal dark 프로덕션 반영 - **Track C 콘텐츠 갭 A~F**: 프로덕션 반영 완료 (`95422bb`대) - **Q8 계정·설정 IA (2026-08-03 확정·구현):** 로그인 탭 · 설정 허브 · 로그아웃 @@ -217,7 +217,7 @@ N2-A 전체 확정. 다음 구현 트랙은 **N1 스모크 → N2-B (Dockerfile/ | **N4-W1** | 웹 로컬 지속성 (prefs/idb) | **done** (2026-08-04) | `app_database_web.dart` SharedPreferences · Drift WASM 비채택 · 라이브 하드 리프레시 스모크는 배포 후 | | **N4-W2** | 데모 메신저 UX | **done** (2026-08-04) | ≥900px 분할·WS 상태·ID 복사·웹 안내 배너 | | **N4-W3** | 인앱·Notification API | **done** (2026-08-04) | 웹 Timer+Notification · 포커스 past-due · 설정 권한 | -| **N4-W4** | Web Push (FCM + VAPID) | **web-live** (2026-08-04) | `:web:` APP_ID·SW populated · **accept:** 하드 리프레시 후 실 토큰·push-test | +| **N4-W4** | Web Push (FCM + VAPID) | **web-live** (2026-08-04) | 시크릿·`:web:`·SW 배포 done · **accept만:** 하드 리프레시·알림·실 토큰·push-test | | **N4-W5** | PWA | **done** (2026-08-04) | manifest 테마 · nginx no-cache · OfflineBanner | | **N4-W6** | 테스터 가이드 | **done** (2026-08-04) | `tester-guide.md` 웹 절 | | **N4-W7** | 품질 | **done** (2026-08-04) | `scripts/e2e_web_smoke.sh` + 부록 QA (Playwright는 후속) | @@ -228,7 +228,7 @@ N2-A 전체 확정. 다음 구현 트랙은 **N1 스모크 → N2-B (Dockerfile/ |----|------|--------|-----------| | **N4-1** | Firebase + `google-services.json` | doing | Master: 앱 등록됨 · JSON을 Android 빌드 PC에 배치 | | **N4-2** | 실 FCM registration token | done* | `PushTokenService` — Firebase 있으면 실 토큰, 없으면 `install:` (*전송은 N4-1 후) | -| **N4-3** | 서버 FCM 자격증명 (HTTP v1) | doing | Master: `secrets/firebase-service-account.json` (레거시 서버 키 대신). 웹 W4와 공유 | +| **N4-3** | 서버 FCM 자격증명 (HTTP v1) | **done** (2026-08) | 프로덕션 `secrets/firebase-service-account.json` 마운트됨. 웹 W4와 공유 | | **N4-4** | 푸시 수신 (Android) | blocked | N4-1+N4-3 후 `/admin/push-test` + 기기 수신 | ### Android UI 탭 (`mobile/README.md`) @@ -290,8 +290,8 @@ N1~N4(배포·품질에 필요한 최소분) 이후에만 착수. `roadmap.md` P 확인 필요, 그때까지는 인앱 배지·배너가 실질적 대체 경로. Track C A~F 프로덕션 재배포는 **완료** (`95422bb` / docs `f363e8e`, 2026-08-03). -**바로 다음:** 웹 **W4 accept** — `msn.iykyka.com` 하드 리프레시·알림 허용·로그인 후 `/admin/push-test` · 또는 Android N4-1/3. -웹 W0~W7 코드·`:web:` 시크릿 배포 **done** (브라우저 실토큰 확인만 남음). +**바로 다음:** 웹 **W4 accept** — `msn.iykyka.com` 하드 리프레시·알림 허용·로그인 후 `/admin/push-test` · 또는 Android N4-1/4. +웹 W0~W7 코드·`:web:` 시크릿 배포·서버 SA **done** (브라우저 실토큰·push-test만 남음). 완료 시 본 표의 Status를 `done`으로 바꾸고, [`roadmap.md`](./roadmap.md) §4/§5의 대응 `[~]`/`[ ]`도 같이 갱신한다. diff --git a/docs/fcm-setup.md b/docs/fcm-setup.md index 22471c6..ef72bfd 100644 --- a/docs/fcm-setup.md +++ b/docs/fcm-setup.md @@ -3,14 +3,15 @@ 서버·클라이언트의 푸시 **코드 경로는 준비됨**. 새 Firebase 프로젝트는 **레거시 서버 키가 비활성**인 경우가 많아, **HTTP v1 + 서비스 계정 JSON**을 쓴다. -## 이미 된 것 (코드) +## 이미 된 것 (코드 · 프로덕션) | 계층 | 동작 | |------|------| | Flutter | `PushTokenService` — Firebase 가능하면 실 FCM 토큰, 아니면 `install:` 플레이스홀더 | | Android | `google-services.json`이 있을 때만 Google Services 플러그인 적용 | -| Web (N4-W4) | `FirebaseWebConfig` + `FIREBASE_*`/`VAPID` dart-define · SW template · 미설정 시 `install:` | -| core-backend | `notifyUser` + `POST /admin/push-test` — **FCM HTTP v1**(서비스 계정) 우선, 레거시 `FCM_SERVER_KEY`는 폴백 | +| Web (N4-W4) | `FirebaseWebConfig` + 프로덕션 `.env` `FIREBASE_*`/`VAPID` 주입 · SW populated (`:web:` APP_ID) | +| core-backend | `notifyUser` + `POST /admin/push-test` — **FCM HTTP v1**(서비스 계정) 우선 | +| 서버 SA (N4-3) | 프로덕션 `secrets/firebase-service-account.json` 마운트 **done** | ## Master가 할 일 @@ -18,44 +19,35 @@ 1. [Firebase Console](https://console.firebase.google.com/) → Android 앱 추가 package: **`com.ykavu.ykavu_mobile`** -2. `google-services.json`을 로컬에만 배치 (git 금지): +2. `google-services.json`을 **Android 빌드 PC**에만 배치 (git 금지): ```bash cp ~/Downloads/google-services.json mobile/android/app/google-services.json ``` -### N4-3 — 서비스 계정 JSON (HTTP v1) +### N4-3 — 서비스 계정 JSON (HTTP v1) — **프로덕션 done** -레거시 **서버 키**가 Cloud Messaging 탭에서 `사용 중지됨`이면 정상이다. 아래를 쓴다. +레거시 **서버 키**가 Cloud Messaging 탭에서 `사용 중지됨`이면 정상이다. -1. Google Cloud → 사용자 인증 정보 → 서비스 계정 만들기 - (API: Firebase Cloud Messaging API, 데이터: **애플리케이션 데이터**) -2. 역할: **Firebase Cloud Messaging Admin** (없으면 Firebase 관리자 / 임시 소유자) -3. 키 유형 **JSON** 다운로드 -4. 서버(또는 이 워크스페이스)에 배치: +프로덕션 호스트에 이미 배치됨: + +```bash +# ~/project/ykavu/secrets/firebase-service-account.json +# compose: ./secrets → /secrets, FCM_SERVICE_ACCOUNT_FILE=/secrets/firebase-service-account.json +``` + +새 환경에 다시 놓을 때: ```bash -# 파일명 고정 mkdir -p secrets mv ~/Downloads/iykyka-*.json secrets/firebase-service-account.json chmod 600 secrets/firebase-service-account.json -``` - -5. 프로덕션 호스트에도 동일 파일: - -```bash -# 예: scp 후 -cd ~/project/ykavu -# secrets/firebase-service-account.json 존재 확인 docker compose up -d --build core-backend ``` -`docker-compose.yml`이 `./secrets` → 컨테이너 `/secrets`로 마운트하고 -`FCM_SERVICE_ACCOUNT_FILE=/secrets/firebase-service-account.json`을 읽는다. - **git / 채팅에 JSON 내용을 붙여넣지 않는다.** -### N4-2 / N4-4 — 실기기 스모크 +### N4-2 / N4-4 — Android 실기기 스모크 ```bash cd mobile @@ -72,24 +64,27 @@ curl -sS -X POST https://msn.iykyka.com/admin/push-test \ 기대: `sent >= 1`. `only_placeholder_tokens` → Android에 `google-services.json` 넣고 재설치. -`fcm_not_configured` → 서버에 서비스 계정 파일 경로 확인. +`fcm_not_configured` → 서비스 계정 경로 확인. ## Web (N4-W4) 설계·수락: [`web-upgrade.md`](./web-upgrade.md) §N4-W4 · 실행 표: [`deploy-checklist.md`](./deploy-checklist.md) §N4-W. -Android N4(실기기)와 **병행 가능**. 서버 서비스 계정(HTTP v1)은 공유하고, -클라이언트는 `google-services.json`(Android) vs Firebase Web config + VAPID(Web)로 분리. +**프로덕션:** Firebase Web config + VAPID + `:web:` APP_ID가 서버 `.env`에 있고 `web` 이미지에 빌드 주입됨. +SW(`firebase-messaging-sw.js`) populated. 서버 SA는 Android와 공유. -**코드 shipped.** define이 비어 있으면 웹은 계속 `install:`만 등록 → `/admin/push-test`의 `only_placeholder_tokens`는 정상. +### 남은 accept (브라우저) -### Master 준비물 (live accept) +1. `https://msn.iykyka.com` **하드 리프레시** (또는 사이트 데이터 삭제) +2. 알림 **허용** → 로그인 +3. device_tokens에 실 토큰(`platform=web`, `install:` 아님) +4. `/admin/push-test` → `sent >= 1` (탭 백그라운드에서도 알림) -1. Firebase Console → **Web** 앱 추가 (authorized domain: `msn.iykyka.com`) — SA 프로젝트와 동일 - - `FIREBASE_APP_ID`는 **`1:…:web:…` 형태**여야 함. Android(`:android:`) / `google-services.json`의 mobilesdk_app_id를 넣으면 웹 토큰 발급이 실패할 수 있음. -2. Cloud Messaging → Web Push certificates / **VAPID public key** -3. 배포 호스트 **`~/project/ykavu/.env`**(클라우드 에이전트 `/workspace/.env`가 아님)에 기입 - (`.env.example` 키 이름 — **값 git 금지**): +로컬/스테이징에서 define이 비어 있으면 웹은 `install:`만 등록 → `only_placeholder_tokens`가 정상. + +### 새 환경에 Web 시크릿을 넣을 때 + +배포 호스트 **`~/project/ykavu/.env`**(클라우드 에이전트 `/workspace/.env`와 별개): ```bash FIREBASE_API_KEY= @@ -97,18 +92,14 @@ FIREBASE_AUTH_DOMAIN= # 비우면 {projectId}.firebaseapp.com FIREBASE_PROJECT_ID= FIREBASE_STORAGE_BUCKET= # 비우면 {projectId}.appspot.com FIREBASE_MESSAGING_SENDER_ID= -FIREBASE_APP_ID= # must be :web: app id +FIREBASE_APP_ID= # must be 1:…:web:… (not :android:) FIREBASE_VAPID_KEY= ``` -4. 웹 재빌드 후 하드 리프레시: - ```bash docker compose up -d --build web ``` -5. 로그인 → 알림 허용 → device_tokens에 실 토큰(`platform=web`) → `/admin/push-test` → `sent >= 1` - ### 로컬 Flutter web ```bash @@ -126,5 +117,5 @@ flutter run -d chrome \ - `mobile/lib/config/firebase_web_config.dart` - `mobile/lib/services/push_token_service.dart` (`_tryFirebaseWebToken`) -- `mobile/web/firebase-messaging-sw.js` (+ `.template`, Dockerfile 치환) +- `mobile/web/firebase-messaging-sw.js` (+ `.template`, `scripts/docker_build_web.sh`) - `mobile/Dockerfile` / `docker-compose.yml` build-args diff --git a/docs/roadmap.md b/docs/roadmap.md index cee082a..a529985 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -417,12 +417,12 @@ Claude/Cursor 통합 DONE 목록과 항목 ID(N1-1 … N5-5, **N4-W0…W7**)는 - [x] **W1** 웹 로컬 지속성 (prefs/idb · Drift WASM 비채택) — 2026-08-04 - [x] **W2** 데모 UX (분할·WS 상태·ID 복사) — 2026-08-04 - [x] **W3** 인앱 + Notification API — 2026-08-04 -- [x] **W4** Web Push 코드 경로 (FCM + VAPID dart-define) — **live accept:** Master `.env` 시크릿 후 +- [x] **W4** Web Push (FCM + VAPID · `:web:` APP_ID 프로덕션 주입) — **accept 대기:** 브라우저 하드 리프레시·알림·push-test - [x] **W5** PWA (manifest 테마 · 셸 캐시) — 2026-08-04 (W4와 독립 선행) - [x] **W6** 테스터 가이드 — 2026-08-04 - [x] **W7** edge 스모크 (`e2e_web_smoke.sh`) — 2026-08-04; Playwright UI는 후속 -구현은 Wi 단위. W4만 Master 시크릿 블로커. Android N4와 서버 SA 공유. +W0~W7 코드·배포 완료. W4만 브라우저 실토큰·`/admin/push-test` 확인 남음. Android N4와 서버 SA 공유. ## Phase 2 — L3 확장 + 베타 확대 diff --git a/docs/tester-guide.md b/docs/tester-guide.md index db3da1c..3cd3977 100644 --- a/docs/tester-guide.md +++ b/docs/tester-guide.md @@ -15,10 +15,11 @@ API 메타: `GET https://msn.iykyka.com/demo` — `pairing_steps` / `notes` 포 1. **넓은 화면(≥900px)** — 왼쪽 대화 목록 · 오른쪽 채팅이 나란히 보입니다. 2. **내 ID 복사** — 목록 상단 칩 또는 설정 → 계정 행을 탭합니다. -3. **브라우저 알림** — 설정 → 「브라우저 알림」에서 허용하면 답장 마감 리마인드를 받을 수 있습니다(거부해도 인앱 배지는 동작). -4. **홈 화면 추가(PWA)** — Chrome 주소창 옆 설치 아이콘 또는 메뉴 → 「앱 설치」. -5. **로그아웃** — 설정 → 로그아웃 → 입장 화면 「이미 가입」으로 복귀. -6. **캐시가 옛 버전일 때** — 강력 새로고침, 또는 DevTools → Application → Service Workers → Unregister 후 새로고침. +3. **브라우저 알림** — 설정 → 「브라우저 알림」에서 허용하면 답장 마감 리마인드·(허용 시) Web Push를 받을 수 있습니다(거부해도 인앱 배지는 동작). +4. **로그인 세션 만료 시각** — 설정 → 로그인 세션의 「만료」는 **기기 로컬 시간**(`yyyy-MM-dd HH:mm`)으로 표시됩니다. +5. **홈 화면 추가(PWA)** — Chrome 주소창 옆 설치 아이콘 또는 메뉴 → 「앱 설치」. +6. **로그아웃** — 설정 → 로그아웃 → 입장 화면 「이미 가입」으로 복귀. +7. **캐시가 옛 버전일 때** — 강력 새로고침, 또는 DevTools → Application → Service Workers → Unregister 후 새로고침. 상세 설계: [`web-upgrade.md`](./web-upgrade.md). @@ -42,9 +43,9 @@ API 메타: `GET https://msn.iykyka.com/demo` — `pairing_steps` / `notes` 포 - **초안(AI)**: Gemini 키가 서버에 설정되어 있어 **실제 초안**이 생성됩니다. - **L0(비서)**: 와카뷰 발송이 서버에서 막혀 있습니다. 초안 → 입력창 → 직접 전송. -- 푸시: Android·Web Push는 Master Firebase 설정 후 (`docs/fcm-setup.md`, `web-upgrade` W4). - 웹은 서버 `.env`에 `FIREBASE_*`/`VAPID`가 있고 `web` 이미지를 그 값으로 빌드한 뒤에야 실 토큰이 등록됩니다. 그전엔 `install:` 플레이스홀더. - Web Push 배포 직후엔 **하드 리프레시**(또는 사이트 데이터 삭제)로 `firebase-messaging-sw.js`를 갱신하세요. +- 푸시: 웹은 프로덕션에 Firebase Web(`:web:`)·VAPID가 이미 주입되어 있습니다. + **하드 리프레시**(또는 사이트 데이터 삭제) → 알림 **허용** → 로그인하면 실 FCM 토큰이 등록됩니다. + Android 실기기 푸시는 `google-services.json` 배치 후 (`docs/fcm-setup.md`). - 문제/스크린샷은 Master에게 전달해 주세요. - 민감 정보·실명 대화는 베타 특성상 최소화해 주세요. diff --git a/docs/web-upgrade.md b/docs/web-upgrade.md index 96848cf..5337235 100644 --- a/docs/web-upgrade.md +++ b/docs/web-upgrade.md @@ -255,38 +255,38 @@ flowchart LR | | | |--|--| -| **Status** | **web APP_ID live** (2026-08-04) — SW `:web:` · **accept 대기:** 하드 리프레시→알림 허용→로그인 후 실 토큰·`/admin/push-test` | +| **Status** | **web-live** (2026-08-04) — `:web:` APP_ID·VAPID·SW 프로덕션 주입 완료 · **accept 대기:** 하드 리프레시→알림→로그인→실 토큰·`/admin/push-test` | | **목표** | 웹 탭이 백그라운드여도 에스컬레이션 등 서버 `notifyUser`가 **실 FCM 웹 토큰**으로 전달 | | **비범위** | 레거시 `FCM_SERVER_KEY` 신규 의존, 커스텀 푸시 프로토콜 | -### As-is → shipped +### Shipped (프로덕션) -- `FirebaseWebConfig` + `--dart-define=FIREBASE_*` / `FIREBASE_VAPID_KEY` -- `PushTokenService` 웹 분기: config 없으면 `install:` soft-fallback, 있으면 `initializeApp` + `getToken(vapidKey:)` -- `mobile/web/firebase-messaging-sw.js` (+ Dockerfile이 template로 치환) · `index.html` SW 등록 -- compose `web` build-args · `.env.example` 키 이름만 · nginx no-cache for SW +- `FirebaseWebConfig` + compose/`Dockerfile` build-args · SW template 치환 +- `PushTokenService` 웹 분기 · `msn.iykyka.com`에 `:web:` APP_ID·VAPID 주입·재배포됨 +- 서버 SA(`secrets/firebase-service-account.json`) 공유 · 시크릿 git 미커밋 -### Master 액션 (live accept 블로커) +### Master 액션 (accept만) -1. Firebase Console에 Web 앱 추가 (`msn.iykyka.com`) — 프로젝트 `iykyka` SA와 동일 프로젝트 -2. Cloud Messaging Web Push 인증서/VAPID 키 발급 -3. 서버 `~/project/ykavu/.env`에 `FIREBASE_API_KEY` … `FIREBASE_VAPID_KEY` 기입 (git 금지) -4. `docker compose up -d --build web` 후 하드 리프레시 → 로그인 → `/admin/push-test` +1. Chrome에서 `https://msn.iykyka.com` **하드 리프레시** (또는 사이트 데이터 삭제) +2. 알림 **허용** → DEMO/계정 로그인 +3. device_tokens에 `platform=web` 실 토큰 확인 후 `POST /admin/push-test` → `sent >= 1` ### 작업 분해 - [x] 빌드 주입: `--dart-define=FIREBASE_…` + SW template 치환 (gitignore/시크릿 미커밋) - [x] `PushTokenService` 웹 분기 + permission - [x] Docker web 빌드에 define 전달 (`mobile/Dockerfile` / compose) -- [ ] `/admin/push-test`로 user 지정 → Chrome 백그라운드 수신 (**Master 시크릿 후**) +- [x] 프로덕션 `.env`에 `FIREBASE_*` / VAPID · `:web:` APP_ID · `web` 재빌드 +- [ ] `/admin/push-test`로 user 지정 → Chrome 백그라운드 수신 (**브라우저 accept**) - [x] `docs/fcm-setup.md` Web 절 동기화 - [x] `DataFlowScreen` 푸시 문구 갱신 ### 수락 기준 -- [ ] device_tokens에 `install:`이 아닌 토큰 + `platform=web` (**시크릿 후**) -- [ ] `POST /admin/push-test` → `sent >= 1`, 브라우저 알림 표시 (**시크릿 후**) +- [ ] device_tokens에 `install:`이 아닌 토큰 + `platform=web` (**브라우저 로그인 후**) +- [ ] `POST /admin/push-test` → `sent >= 1`, 브라우저 알림 표시 - [x] 시크릿이 git history에 없음 (define/env만) +- [x] 프로덕션 SW populated (`firebase.initializeApp`, appId `:web:`) ### 위험 @@ -466,13 +466,13 @@ Wi를 끝낼 때마다: --- -## 부록 B — Master 시크릿 체크리스트 (W4) +## 부록 B — Master 시크릿·accept 체크리스트 (W4) -- [ ] Firebase Web app 등록 (도메인 `msn.iykyka.com`) -- [ ] VAPID key -- [ ] 서버 `~/project/ykavu/.env`에 `FIREBASE_*` / `FIREBASE_VAPID_KEY` (git 미포함) → `docker compose up -d --build web` -- [ ] 서버 `secrets/firebase-service-account.json` 유지 (Android와 공유) -- [ ] push-test로 `sent >= 1` 확인 +- [x] Firebase Web app 등록 (도메인 `msn.iykyka.com`, APP_ID `:web:`) +- [x] VAPID key +- [x] 서버 `~/project/ykavu/.env`에 `FIREBASE_*` / `FIREBASE_VAPID_KEY` (git 미포함) → `web` 재빌드 +- [x] 서버 `secrets/firebase-service-account.json` 유지 (Android와 공유) +- [ ] 하드 리프레시·알림 허용·로그인 후 push-test로 `sent >= 1` 확인 --- diff --git a/mobile/README.md b/mobile/README.md index cd47c46..41a133d 100644 --- a/mobile/README.md +++ b/mobile/README.md @@ -69,8 +69,8 @@ sudo apt-get install -y libsqlite3-dev libsqlcipher1 - 로컬 DB: `lib/db/app_database_web.dart` — **W1 done**: SharedPreferences 지속성(비암호화 프리뷰) - 스누즈 OS 알림: 웹 no-op → **W3** Notification API / 인앱 -- 푸시: 웹은 `FIREBASE_*` + `FIREBASE_VAPID_KEY` dart-define 시 실 FCM 토큰 · 없으면 `install:` ([`docs/fcm-setup.md`](../docs/fcm-setup.md) Web 절) -- PWA: `web/manifest.json` 골격 있음 → **W5** 테마·설치·셸 캐시 +- 푸시: 프로덕션은 `FIREBASE_*` + VAPID 주입됨 · 로컬은 dart-define 없으면 `install:` ([`docs/fcm-setup.md`](../docs/fcm-setup.md) Web 절) +- PWA: **W5 done** — manifest 테마·설치·셸 캐시 - **Q9**(수신 자동응대)는 웹 트랙 비범위 ```bash @@ -86,8 +86,8 @@ cd mobile && flutter run -d chrome --dart-define=CORE_API_BASE=http://localhost: ## 아직 없는 것 -- 웹 W1~W7 구현 ([`docs/web-upgrade.md`](../docs/web-upgrade.md) — 설계만 완료, Wi 승인 후) -- Master Firebase Android 시크릿 후 실기기 푸시 스모크 (N4-1/3/4) +- 웹 W4 **accept** — 브라우저 실 FCM 토큰·`/admin/push-test` (코드·`:web:` 배포는 완료, [`web-upgrade.md`](../docs/web-upgrade.md)) +- Android: `google-services.json` PC 배치 후 실기기 푸시 스모크 (N4-1/4; 서버 SA는 N4-3 done) - 멀티디바이스 실시간 설정 동기화 고도화 - 온보딩 말투 UX 디테일 (PoC #1 결과는 맨 마지막에 반영) - iOS 빌드 (v1 범위 밖)