Notifly SDK 연동 스킬
사용자가 Notifly SDK를 설치/설정/연동하려고 할 때 이 스킬을 사용하세요.
대상은:
- 푸시 알림
- 인앱 팝업 메시지 / 웹 팝업
- 유저 식별/유저 프로퍼티
- 이벤트 트래킹(플랫폼 SDK가 지원하는 범위)
- 웹 푸시 (Service Worker 기반)
- 웹 연동 (JavaScript SDK / Google Tag Manager)
연동 전략 (MCP 우선)
이 스킬은 항상 MCP 우선으로 동작하여, 최신의 검증된 문서/SDK 소스를 기준으로
의사결정합니다.
1단계: MCP 사용 가능 여부 확인
- Notifly MCP 도구가 있는지 확인:
notifly-mcp-server:search_docs
notifly-mcp-server:search_sdk
2단계: 기본 경로 (MCP 사용 가능)
notifly-mcp-server:search_docs로 대상 플랫폼의 공식 설치/초기화 단계를
확인
notifly-mcp-server:search_sdk로 정확한 API 시그니처/공식 샘플 코드를
확인
- MCP 결과가 존재하면 이를 단일 기준으로 취급 (추측 금지)
3단계: 대체 경로 (MCP 사용 불가)
- 이 레포의 정적 자료를 사용:
references/: 체크리스트/설명/문제 해결
examples/: 공식 문서/샘플에 맞춘 코드 패턴
- MCP가 필요하면 먼저 설치/구성:
- 참고:
references/mcp-integration.md
- 또는 실행:
bash skills/integration/scripts/install-mcp.sh --help
에이전트 작업 가이드라인
Cursor, Claude Code, Codex, Amp 등 AI IDE에서 이 스킬을 사용할 때:
- 사전 탐색부터 시작
- 플랫폼(들)과 진입점을 식별 (
AppDelegate.swift, Application, main.dart,
index.js 등)
- 수정할 파일을 미리 선언
- 필요하면 질문
- RN/Flutter 같이 iOS/Android가 동시에 있는 경우, 어떤 플랫폼부터 할지 확인
- “푸시만” vs “푸시 + 인앱 팝업” 범위를 확인
- 공식 소스 우선
- 플랫폼별 공식 문서를 기준으로 진행
- API는
search_sdk로 확인해서 추측하지 않기
- 마지막에 검증 요약
- 변경 파일/설정 위치/검증 방법(콘솔 확인 포함)을 요약
연동 워크플로우
0단계: MCP 설정 (선택이지만 권장)
MCP 도구가 없다면 먼저 notifly-mcp-server를 구성하세요:
- 공식 가이드:
https://docs.notifly.tech/ko/devtools/notifly-mcp-server.md
- 이 레포:
references/mcp-integration.md
- 자동 설치/구성:
bash skills/integration/scripts/install-mcp.sh --help
1단계: 사전 준비(필수 확인)
진행 전 반드시 확인:
- Mobile:
- Firebase 연동 완료 (Notifly는 FCM 사용)
- iOS APNs 인증을 Firebase에 등록 (iOS / Flutter iOS / RN iOS)
- Android 인앱 팝업은 Android 11 (API 30)+ 필요
- Web (웹 푸시 사용 시):
- VAPID 키 생성: 콘솔 설정 → SDK 설정 → 웹사이트 설정
- HTTPS 필수: Web Push/Service Worker/PushSubscription은 secure context에서만
동작합니다. 로컬 웹푸시 검증도
https://localhost로 서버를 띄워 테스트하세요.
- Service Worker 파일 제공: 번들러 사용 시 SW 파일이 누락되지 않도록
public/static assets 복사 설정
공식 가이드:
- Android:
https://docs.notifly.tech/ko/developer-guide/android-sdk.md
- iOS:
https://docs.notifly.tech/ko/developer-guide/ios-sdk.md
- Flutter:
https://docs.notifly.tech/ko/developer-guide/flutter-sdk.md
- React Native:
https://docs.notifly.tech/ko/developer-guide/react-native-sdk.md
- JavaScript(Web):
https://docs.notifly.tech/ko/developer-guide/javascript-sdk
2단계: 자격 증명(SDK)
Notifly SDK 설정의 실제 입력은 플랫폼 무관하게 projectId와 username을 기준으로
확인합니다. 일부 SDK API는 호환성을 위해 password 인자/필드를 계속 요구하지만, 현재
정책상 password 값은 사용하지 않습니다.
NOTIFLY_PROJECT_ID
NOTIFLY_USERNAME
password 인자/필드가 필요하면 빈 문자열("") 또는 username과 같은 더미값
Notifly 콘솔에서 확인: https://console.notifly.tech/ → Project Settings → SDK
credentials.
권장 사항:
- iOS/Android/Flutter/RN/Web 모두 password를 별도 secret/env로 요구하지 마세요.
특히 Web에서
NEXT_PUBLIC_NOTIFLY_PASSWORD 또는 NEXT_PUBLIC_NOTIFLY_PROJECT_PASSWORD
같은 공개 password env를 새로 만들지 않습니다.
- SDK 타입/시그니처가
password 필드를 요구하면 필드는 유지하되, "", username,
또는 프로젝트가 정한 더미값을 넘깁니다.
projectId/username 값을 소스에 하드코딩/커밋하지 마세요.
- 플랫폼에 맞는 런타임/빌드타임 주입 방식을 사용하세요. Web은 번들 공개성을 고려해
프로젝트가 정한 public config/server-injected config/빌드타임 config 정책을 따릅니다.
.env.example의 존재/내용은 프로젝트마다 다를 수 있으므로 연동 품질의 필수 판정
기준으로 삼지 않습니다.
projectId가 외부 설정값이면 프로젝트 규칙(예: 32자 hex)에 맞게 검증하고,
missing/invalid를 구분해 보고하세요. 기존 validation/test가 있으면 보존합니다.
3단계: 플랫폼 식별(프로젝트 타입)
프로젝트가 어느 플랫폼인지 식별:
- iOS:
.xcodeproj / .xcworkspace, Podfile, Swift/Obj-C 소스
- Android:
build.gradle(.kts), AndroidManifest.xml, Kotlin/Java 소스
- Flutter:
pubspec.yaml, lib/main.dart, ios/ + android/
- React Native: RN 의존성이 있는
package.json, ios/ + android/
- Web (JavaScript):
package.json에 notifly-js-sdk 의존성, 또는 HTML의 CDN <script>
public/notifly-service-worker.js (또는 동등한 루트 경로 SW 파일)
구조가 애매하면 멈추고 사용자에게 질문하세요.
우선순위 규칙(중요):
- React Native 또는 Flutter가 확인되면, 네이티브
ios/, android/가
존재해도 RN/Flutter를 1차 플랫폼으로 취급합니다.
4단계: SDK 설치 (플랫폼별)
아래 “플랫폼 플레이북”을 기준으로 진행합니다. 가능한 한 공식 문서의 표현을
그대로 따르고, API는 MCP로 확인하세요.
플랫폼 플레이북
iOS (Swift / Objective-C)
설치(공식):
- CocoaPods:
pod 'notifly_sdk'
- Swift Package Manager:
https://github.com/team-michael/notifly-ios-sdk
프로젝트 설정(공식):
- Push Notifications 활성화
- Background Modes 활성화 (Remote notifications, Background fetch)
- 최소 iOS 타겟 13.0+
초기화(공식 패턴):
AppDelegate에서 FirebaseApp.configure() 및 Notifly 초기화 수행
- 알림 권한 요청 후 원격 알림 등록
UNUserNotificationCenter 델리게이트 설정
- APNs 토큰/푸시 콜백을 Notifly로 전달
공식 가이드: https://docs.notifly.tech/ko/developer-guide/ios-sdk.md
예시: examples/ios-integration.swift
Android (Kotlin / Java)
설치(공식):
- JitPack 저장소 추가
- 의존성 추가:
implementation 'com.github.team-michael:notifly-android-sdk:<latest>'
초기화(공식):
Application.onCreate()에서 초기화:
Notifly.initialize(applicationContext, NOTIFLY_PROJECT_ID, BuildConfig.NOTIFLY_USERNAME, "")
- SDK 시그니처가
password 값을 요구하면 빈 값/username 더미값을 넘기며,
별도 NOTIFLY_PASSWORD secret을 요구하지 않습니다.
유저 식별(초기화 후, 공식):
Notifly.setUserId(context, userId) (로그아웃 시:
Notifly.setUserId(context, null))
Notifly.setUserProperties(context, params)
이벤트 트래킹(초기화 후, 공식):
Notifly.trackEvent(context, eventName, eventParams, segmentationEventParamKeys)
예시: examples/android-integration.kt
Flutter
설치(공식):
flutter pub add notifly_flutter
- iOS:
cd ios && pod install
초기화(공식):
Firebase.initializeApp() 보장
await NotiflyPlugin.initialize(projectId: ..., username: ..., password: "")
(password 인자가 필요하면 빈 값/username 더미값 사용)
- (선택) 콘솔에서 “자동 권한 요청”이 비활성화된 경우:
await NotiflyPlugin.requestPermission()
- (선택) 인앱 팝업 이벤트 구독(공식 예시):
NotiflyPlugin.inAppEvents.listen(...)
예시: examples/flutter-integration.dart
React Native
설치(공식):
- npm 패키지:
notifly-sdk
- iOS:
cd ios && pod install
설정(공식):
- RN은 iOS/Android 네이티브 연동이 필요(공식 RN 문서 참조)
- 네이티브 연동 후, JS에서
notifly-sdk API 사용
JS API 사용(네이티브 연동 후):
notifly.setUserId(userId) (로그아웃: notifly.setUserId(null) 또는
notifly.setUserId())
notifly.setUserProperties({...})
notifly.setEmail(email)
notifly.setPhoneNumber(phoneNumber)
notifly.setTimezone(timezone)
예시: examples/react-native-integration.tsx
Web (JavaScript SDK)
먼저 범위를 분리합니다. 웹 팝업과 웹 푸시는 같은 SDK를 쓰지만 실패 지점이
다릅니다. 자세한 계약은 references/web-javascript.md를 함께 확인하세요.
- 웹 팝업 only: Service Worker/Notification 권한이 아니라
initialize → user state sync → trackEvent → campaign condition match → renderer
경로가 핵심입니다.
- 웹 푸시 only: HTTPS, Notifly 콘솔의 VAPID/웹사이트 SDK 설정,
Service Worker path/scope, 브라우저 권한, PushSubscription 생성이 핵심입니다.
- 웹 팝업 + 웹 푸시: 초기화는 하나지만, 검증은 user/event 축과
Service Worker/permission 축을 따로 수행합니다.
필수 선행(웹 푸시 사용 시, 공식):
- 콘솔에서 VAPID 키 생성: 설정 → SDK 설정 → 웹사이트 설정
- HTTPS secure context에서 서비스. Web Push는 plain HTTP에서 검증하지 않습니다.
로컬 테스트도
https://localhost로 서버를 띄워 Service Worker/권한/구독 흐름을
확인하세요.
- Service Worker 파일 제공: 기본 권장 경로는
/notifly-service-worker.js입니다.
단, 공식 문서상 파일명/경로는 변경 가능하며 Notifly 콘솔의
serviceWorkerPath 설정과 실제 제공 경로가 반드시 일치해야 합니다.
- 기존 PWA/Firebase/OneSignal/Braze/Workbox Service Worker가 있는지 먼저 확인하고,
root scope 충돌 가능성이 있으면 무작정 새 SW를 추가하지 않습니다.
1) Service Worker 등록(웹 푸시 사용 시):
- public/static 경로에 Service Worker 파일을 생성하거나 기존 SW에 통합
- 내용(공식 패턴):
self.importScripts("https://cdn.jsdelivr.net/npm/notifly-js-sdk@2/dist/NotiflyServiceWorker.js");
- 번들러 사용 시 SW 파일이 번들에 흡수/삭제되지 않도록 assets copy 설정
- 실제 URL이 HTML fallback이 아니라 JavaScript 파일로 200 응답하는지 확인
예시: examples/notifly-service-worker.js
2) SDK 설치(선택):
- npm/yarn/pnpm:
notifly-js-sdk 설치
- 또는 CDN으로 로드 후
window.notifly 접근
3) SDK 초기화(현재 SDK 2.5.0+ 공식 패턴):
- 코드에는
projectId, username, 그리고 SDK 시그니처 호환용 password 필드를
둡니다. 단, password 값은 사용하지 않으므로 별도 secret/env를 요구하지 말고
"", username, 또는 프로젝트가 정한 더미값을 넘깁니다. 특히 Web에서
NEXT_PUBLIC_NOTIFLY_PASSWORD/NEXT_PUBLIC_NOTIFLY_PROJECT_PASSWORD를 새로 요구하지
않습니다.
projectId가 env/config/콘솔 입력처럼 외부에서 들어오면 형식 검증(프로젝트 규칙,
예: 32자 hex)과 missing/invalid 오류 분리를 유지합니다. 기존 config parser와 테스트가
있으면 삭제하지 말고 확장합니다.
- SDK 2.5.0+에서는 세션/웹푸시 세부 옵션(VAPID/SW 경로/권한 팝업/지연시간 등)이
콘솔 웹사이트 SDK 설정값으로 대체됩니다.
- SDK 2.5.0+ 신규 연동에서
pushSubscriptionOptions나 top-level
serviceWorkerPath를 임의로 추가하지 않습니다. Legacy SDK 2.4 이하를 명시적으로
지원할 때만 pushSubscriptionOptions를 사용합니다.
- 웹 팝업 HTML 내부에서 사용자 정의 이벤트 로깅이 필요한 경우에만 SDK 2.17.2+에서
allowUserSuppliedLogEvent: true를 추가합니다. 기존 프로젝트에 이 옵션/env/config
plumbing이나 테스트가 있으면 제거하지 말고 보존합니다.
예시: examples/web-integration.js
4) 권한 요청(웹 푸시 사용 시):
- 먼저 HTTPS 로컬 서버 또는 배포 HTTPS 도메인에서 페이지를 엽니다. plain HTTP에서
권한/Service Worker/PushSubscription 흐름을 검증하지 않습니다.
- Next.js 로컬 테스트는
npm run dev -- --experimental-https 또는
npx next dev --experimental-https로 실행하고 https://localhost:3000에서 확인합니다.
필요하면 --experimental-https-key, --experimental-https-cert로 mkcert 인증서를 지정합니다.
- Next.js가 아니면 대상 프로젝트의
package.json/lockfile/scripts로 현재 웹 프레임워크를
먼저 식별한 뒤, 해당 프레임워크의 공식 local HTTPS dev-server 방법을 찾아 실행합니다.
- 콘솔에서 자동 권한 팝업을 켜면 방문 시 안내 → 브라우저 권한 요청 순서로 동작
- 특정 타이밍에만 요청하려면 SDK 2.7.0+에서 콘솔 자동 노출을 끄고
notifly.requestPermission(...) 호출
requestPermission(...) 호출은 “권한 프롬프트를 시도했다”는 뜻일 뿐입니다. Notification.permission,
Service Worker 등록, PushSubscription 생성, Notifly device property logging을 별도로 확인합니다.
- SDK 초기화/ready 상태와 웹푸시 구독 verified/subscribed 상태를 분리해서 UI/문서/리포트에 표시합니다.
- 브라우저 권한이 이미
denied이면 SDK가 다시 요청할 수 없으므로 브라우저/site
설정에서 사용자가 직접 변경해야 합니다.
5) 유저/이벤트(웹 팝업/타깃팅 핵심):
- 로그인 직후 권장 순서:
setUserId → setUserProperties → trackEvent
notifly.setUserId(userId | null) (null/무인자는 로그아웃 처리이며 문서상 유저
데이터 삭제성 동작이 있으므로 의도 확인)
notifly.setUserProperties({...})
notifly.trackEvent(name, params, segmentationEventParamKeys)
(segmentationEventParamKeys는 최대 1개 키)
6) Google Tag Manager(GTM) 옵션(선택):
- 코드 수정 없이 초기화/유저/이벤트를 구성 가능(공식 GTM 가이드 참고)
- SDK script load timing과 dataLayer 이벤트 순서를 보장해야 합니다.
- 단, 웹 푸시를 쓰는 경우 SW 파일 제공은 여전히 필요합니다.
- CSP가 있으면
script-src, connect-src, worker-src에서 Notifly/CDN 호출을
허용해야 합니다.
5단계: SDK 초기화 위치 확정(레포 기준 증빙)
이 단계는 “어디에 코드를 넣는지”와 “레포에서 증명 가능한지”를 점검합니다.
기존 앱에 provider/config/client/test 구조가 있으면 새 단일 파일로 덮어쓰기보다 그 구조를
보존한 채 필요한 SDK 호출과 검증만 추가하는 편이 좋습니다. 다만 이 항목들은 기존 앱의
명시적 계약을 깨지 않는 한 hard blocker가 아니라 quality/parity 신호로 보고합니다.
웹 데모/재적용 검토에서 다음은 기본적으로 non-blocking parity signal입니다. 사용자가
명시적으로 hard requirement로 지정했거나 기존 앱의 계약을 실제로 깨는 경우에만 blocker로
올립니다:
- 기존 provider/config/client/test 구조 보존
- root-level SDK init과 route coverage
- permission CTA analytics event 보존
- demo fixture의 exact SDK version pinning 보존
- validator가 marker pass를 넘어 behavioral contract 차이를 잡는 능력
iOS 초기화 체크리스트
- 엔트리포인트:
AppDelegate.swift (또는 SwiftUI에서
@UIApplicationDelegateAdaptor(AppDelegate.self) 사용)
- 필수 포함:
FirebaseApp.configure()
Notifly.initialize(projectId:username:password) (password는 빈 값/더미값)
UNUserNotificationCenter.current().delegate = self
- 아래 콜백 전달:
application(_:didRegisterForRemoteNotificationsWithDeviceToken:)
application(_:didFailToRegisterForRemoteNotificationsWithError:)
userNotificationCenter(_:didReceive:withCompletionHandler:)
userNotificationCenter(_:willPresent:withCompletionHandler:)
Android 초기화 체크리스트
- 엔트리포인트: 커스텀
Application 클래스 (Kotlin/Java)
AndroidManifest.xml의 android:name으로 등록
- 필수 포함:
Application.onCreate()에서 Notifly.initialize(...)
Flutter 초기화 체크리스트
- 엔트리포인트:
lib/main.dart (+ iOS 브릿지 파일은 공식 문서대로)
- 필수 포함:
await NotiflyPlugin.initialize(...)
- iOS 참고: 공식 Flutter 문서는
ios/Runner/AppDelegate.mm 작업을 기대함
(flutter-sdk.md 참조)
React Native 초기화 체크리스트
- 네이티브: 공식 RN 문서대로 iOS
AppDelegate.mm, Android Application
연동 수행
- JS: 공식 RN SDK 샘플 패턴대로 API 사용(예시 파일 참조)
6단계: 검증(필수)
- 모바일 스크립트 실행(앱 프로젝트 루트에서):
bash skills/integration/scripts/validate-sdk.sh
참고: 위 스크립트는 모바일 플랫폼(iOS/Android/Flutter/RN) 검증용입니다.
- Web(JavaScript) 정적 검증:
bash skills/integration/scripts/validate-web-sdk.sh /path/to/web-app
이 스크립트는 notifly-js-sdk 설치/CDN, notifly.initialize(...), 자격 증명 마커,
Service Worker 후보, NotiflyServiceWorker.js import, legacy 옵션, user/event API
마커를 확인합니다. 추가로 projectId 검증/allowUserSuppliedLogEvent/수동 권한 요청의
런타임 의미를 경고로 표시합니다. 정적 검증은 충분조건이 아니므로 아래 런타임 검증까지 수행하세요.
- 빌드/실행 후 콘솔에서 확인:
- 초기화 로그/동작 확인
- 푸시 토큰 등록(네이티브) 확인
- Notifly 콘솔에서 이벤트/기기 등록 확인
- Web 런타임 검증(웹 푸시/웹 팝업):
- 웹 푸시는 HTTPS secure context에서만 검증합니다. 로컬도
https://localhost로 실행합니다.
- Next.js:
npm run dev -- --experimental-https 또는 npx next dev --experimental-https
- Next.js가 아니면
package.json으로 프레임워크를 식별하고, 해당 프레임워크의 공식
local HTTPS 실행법을 찾아 서버를 띄운 뒤 테스트합니다.
- 콘솔에 설정한 Service Worker path가 실제로 200 JS 응답인지 확인
(
/notifly-service-worker.js가 기본 예시이며, HTML fallback이면 실패)
- DevTools → Application → Service Workers에서 등록/scope 확인
- Network에서
/sdk-configurations?project_id=...&type=website 200 확인
- 브라우저에서 알림 권한 요청/허용 흐름이 의도대로 동작하는지 확인
(
requestPermission(...) 호출 자체는 prompt 시도일 뿐 성공/구독 증명이 아님)
- 권한 허용 후 PushSubscription 생성 및 device property logging 확인
- SDK 초기화/ready 상태와 웹푸시 verified/subscribed 상태를 분리해 확인
setUserId → setUserProperties → trackEvent 호출 후 콘솔에서 반영 확인
- 웹 팝업 캠페인 조건에 맞는 이벤트 호출 시 modal 노출 확인
7단계: 플랫폼별 레포 검증 체크리스트
iOS
- 의존성 존재 (Pods 또는 SPM)
- Capability 설정 완료 (Push + Background Modes)
AppDelegate에서 APNs 콜백을 Notifly로 전달
Android
- JitPack repo 설정
- SDK 의존성 존재
Application 클래스 존재 및 매니페스트 등록
Application.onCreate()에서 Notifly.initialize(...)
Flutter
pubspec.yaml에 notifly_flutter 포함
ios/Podfile.lock이 pod install 이후 업데이트됨
NotiflyPlugin.initialize(...) 호출
React Native
package.json에 notifly-sdk 포함
ios/Podfile.lock이 pod install 이후 업데이트됨
- 공식 문서대로 네이티브 연동 완료
- JS 호출이 공식 샘플 패턴과 일치
Web (JavaScript)
notifly-js-sdk 설치(npm) 또는 CDN 로드 확인
- 앱 코드에서 현재 SDK 2.5.0+ 패턴인
notifly.initialize({ projectId, username, password }) 호출 확인
- SDK 호환용
password 필드는 필요하면 유지하되, password 값은 사용하지 않으므로
별도 공개 env/secret을 요구하지 않습니다. "", username, 또는 프로젝트 더미값을
넘기고, 프로젝트의 주입/노출 정책을 확인합니다.
- 외부 config에서 받은
projectId 검증과 missing/invalid 오류 분리를 보존합니다.
기존 config parser/provider/tests가 있으면 삭제하지 말고 확장합니다.
- 신규 SDK 2.5.0+ 연동에서
pushSubscriptionOptions 또는 top-level
serviceWorkerPath를 추가하지 않았는지 확인(legacy SDK 2.4 이하 예외)
- (웹 팝업)
setUserId → setUserProperties → trackEvent 호출 순서와 이벤트/속성 설계가
캠페인 조건과 일치
- (웹 팝업) 웹 팝업 HTML 내부 custom event logging이 필요할 때만
allowUserSuppliedLogEvent: true 사용. 기존 plumbing/test가 있으면 보존
- (웹 푸시) 콘솔의 Service Worker path와 실제 제공 경로가 일치
- (웹 푸시) SW 파일이
NotiflyServiceWorker.js를 importScripts 하는지 확인
- (웹 푸시) 기존 PWA/Firebase/OneSignal/Braze/Workbox Service Worker와 scope/handler
충돌이 없는지 확인
- (웹 푸시) 권한 요청 및 구독 흐름이 동작하는지 확인
(
requestPermission(...) 호출, Notification.permission, PushSubscription, device logging을 분리)
- (웹 푸시) SDK ready와 push subscribed/verified 상태를 같은 의미로 보고하지 않음
8단계: 문서화
연동 후 README/내부 문서에 다음을 기록:
- 필요한 자격 증명과 주입 방법(시크릿은 노출하지 않기)
- iOS/Android 빌드/런 방법
- Notifly 콘솔에서 검증하는 방법
문서 사용 노트 (MCP vs 정적 자료)
- MCP 사용 가능:
search_docs / search_sdk 결과를 단일 진실원으로 취급
- MCP 사용 불가: 공식 문서 링크 + 이 스킬 폴더의
examples/, references/ 사용
점진적 공개(Progressive Disclosure)
- 레벨 1:
SKILL.md / SKILL.ko.md
- 레벨 2:
references/
- 레벨 3:
examples/
- 레벨 4:
scripts/
참고 자료(References)
references/sdk-reference.md
references/error-handling.md
references/framework-patterns.md
references/web-javascript.md
references/mcp-integration.md
예시(Examples)
examples/ios-integration.swift
examples/android-integration.kt
examples/flutter-integration.dart
examples/react-native-integration.tsx
examples/notifly-service-worker.js
examples/web-integration.js
스크립트(Scripts)
scripts/install-mcp.sh (클라이언트에 MCP 서버 구성)
scripts/validate-sdk.sh (모바일 SDK 연동 마커 검증)
scripts/validate-web-sdk.sh (JavaScript/Web SDK 연동 마커 검증)
1---2name: notifly-integration3description: 노티플라이(Notifly) SDK를 Mobile(iOS/Android/Flutter/React Native) 및 Web(JavaScript/Tag Manager) 프로젝트에 연동합니다. 공식 Notifly 문서와 SDK 샘플을 단일 기준으로 삼아 설치/초기화/MCP 설정/검증/트러블슈팅을 단계별로 안내합니다.4---56# Notifly SDK 연동 스킬78사용자가 **Notifly SDK**를 설치/설정/연동하려고 할 때 이 스킬을 사용하세요.9대상은:1011- 푸시 알림12- 인앱 팝업 메시지 / 웹 팝업13- 유저 식별/유저 프로퍼티14- 이벤트 트래킹(플랫폼 SDK가 지원하는 범위)15- 웹 푸시 (Service Worker 기반)16- 웹 연동 (JavaScript SDK / Google Tag Manager)1718## 연동 전략 (MCP 우선)1920이 스킬은 항상 **MCP 우선**으로 동작하여, 최신의 검증된 문서/SDK 소스를 기준으로21의사결정합니다.2223### 1단계: MCP 사용 가능 여부 확인2425- Notifly MCP 도구가 있는지 확인:26 - `notifly-mcp-server:search_docs`27 - `notifly-mcp-server:search_sdk`2829### 2단계: 기본 경로 (MCP 사용 가능)3031- `notifly-mcp-server:search_docs`로 대상 플랫폼의 **공식 설치/초기화 단계**를32 확인33- `notifly-mcp-server:search_sdk`로 **정확한 API 시그니처/공식 샘플 코드**를34 확인35- MCP 결과가 존재하면 이를 **단일 기준**으로 취급 (추측 금지)3637### 3단계: 대체 경로 (MCP 사용 불가)3839- 이 레포의 정적 자료를 사용:40 - `references/`: 체크리스트/설명/문제 해결41 - `examples/`: 공식 문서/샘플에 맞춘 코드 패턴42- MCP가 필요하면 먼저 설치/구성:43 - 참고: `references/mcp-integration.md`44 - 또는 실행: `bash skills/integration/scripts/install-mcp.sh --help`4546## 에이전트 작업 가이드라인4748Cursor, Claude Code, Codex, Amp 등 AI IDE에서 이 스킬을 사용할 때:4950- **사전 탐색부터 시작**51 - 플랫폼(들)과 진입점을 식별 (`AppDelegate.swift`, `Application`, `main.dart`,52 `index.js` 등)53 - 수정할 파일을 미리 선언54- **필요하면 질문**55 - RN/Flutter 같이 iOS/Android가 동시에 있는 경우, 어떤 플랫폼부터 할지 확인56 - “푸시만” vs “푸시 + 인앱 팝업” 범위를 확인57- **공식 소스 우선**58 - 플랫폼별 공식 문서를 기준으로 진행59 - API는 `search_sdk`로 확인해서 추측하지 않기60- **마지막에 검증 요약**61 - 변경 파일/설정 위치/검증 방법(콘솔 확인 포함)을 요약6263## 연동 워크플로우6465### 0단계: MCP 설정 (선택이지만 권장)6667MCP 도구가 없다면 먼저 `notifly-mcp-server`를 구성하세요:6869- 공식 가이드: `https://docs.notifly.tech/ko/devtools/notifly-mcp-server.md`70- 이 레포: `references/mcp-integration.md`71- 자동 설치/구성: `bash skills/integration/scripts/install-mcp.sh --help`7273### 1단계: 사전 준비(필수 확인)7475진행 전 반드시 확인:7677- **Mobile**:78 - **Firebase 연동 완료** (Notifly는 FCM 사용)79 - **iOS APNs 인증을 Firebase에 등록** (iOS / Flutter iOS / RN iOS)80 - **Android 인앱 팝업은 Android 11 (API 30)+ 필요**81- **Web (웹 푸시 사용 시)**:82 - **VAPID 키 생성**: 콘솔 **설정 → SDK 설정 → 웹사이트 설정**83 - **HTTPS 필수**: Web Push/Service Worker/PushSubscription은 secure context에서만84 동작합니다. 로컬 웹푸시 검증도 `https://localhost`로 서버를 띄워 테스트하세요.85 - **Service Worker 파일 제공**: 번들러 사용 시 SW 파일이 누락되지 않도록86 public/static assets 복사 설정8788공식 가이드:8990- Android: `https://docs.notifly.tech/ko/developer-guide/android-sdk.md`91- iOS: `https://docs.notifly.tech/ko/developer-guide/ios-sdk.md`92- Flutter: `https://docs.notifly.tech/ko/developer-guide/flutter-sdk.md`93- React Native:94 `https://docs.notifly.tech/ko/developer-guide/react-native-sdk.md`95- JavaScript(Web): `https://docs.notifly.tech/ko/developer-guide/javascript-sdk`9697### 2단계: 자격 증명(SDK)9899Notifly SDK 설정의 실제 입력은 플랫폼 무관하게 `projectId`와 `username`을 기준으로100확인합니다. 일부 SDK API는 호환성을 위해 `password` 인자/필드를 계속 요구하지만, 현재101정책상 password 값은 사용하지 않습니다.102103- `NOTIFLY_PROJECT_ID`104- `NOTIFLY_USERNAME`105- `password` 인자/필드가 필요하면 빈 문자열(`""`) 또는 `username`과 같은 더미값106107Notifly 콘솔에서 확인: `https://console.notifly.tech/` → Project Settings → SDK108credentials.109110**권장 사항**:111112- iOS/Android/Flutter/RN/Web 모두 password를 별도 secret/env로 요구하지 마세요.113 특히 Web에서 `NEXT_PUBLIC_NOTIFLY_PASSWORD` 또는 `NEXT_PUBLIC_NOTIFLY_PROJECT_PASSWORD`114 같은 공개 password env를 새로 만들지 않습니다.115- SDK 타입/시그니처가 `password` 필드를 요구하면 필드는 유지하되, `""`, `username`,116 또는 프로젝트가 정한 더미값을 넘깁니다.117- `projectId`/`username` 값을 소스에 하드코딩/커밋하지 마세요.118- 플랫폼에 맞는 런타임/빌드타임 주입 방식을 사용하세요. Web은 번들 공개성을 고려해119 프로젝트가 정한 public config/server-injected config/빌드타임 config 정책을 따릅니다.120- `.env.example`의 존재/내용은 프로젝트마다 다를 수 있으므로 연동 품질의 필수 판정121 기준으로 삼지 않습니다.122- `projectId`가 외부 설정값이면 프로젝트 규칙(예: 32자 hex)에 맞게 검증하고,123 missing/invalid를 구분해 보고하세요. 기존 validation/test가 있으면 보존합니다.124125### 3단계: 플랫폼 식별(프로젝트 타입)126127프로젝트가 어느 플랫폼인지 식별:128129- **iOS**: `.xcodeproj` / `.xcworkspace`, `Podfile`, Swift/Obj-C 소스130- **Android**: `build.gradle(.kts)`, `AndroidManifest.xml`, Kotlin/Java 소스131- **Flutter**: `pubspec.yaml`, `lib/main.dart`, `ios/` + `android/`132- **React Native**: RN 의존성이 있는 `package.json`, `ios/` + `android/`133- **Web (JavaScript)**:134 - `package.json`에 `notifly-js-sdk` 의존성, 또는 HTML의 CDN `<script>`135 - `public/notifly-service-worker.js` (또는 동등한 루트 경로 SW 파일)136137구조가 애매하면 멈추고 사용자에게 질문하세요.138139**우선순위 규칙(중요)**:140141- **React Native** 또는 **Flutter**가 확인되면, 네이티브 `ios/`, `android/`가142 존재해도 **RN/Flutter를 1차 플랫폼**으로 취급합니다.143144### 4단계: SDK 설치 (플랫폼별)145146아래 “플랫폼 플레이북”을 기준으로 진행합니다. 가능한 한 공식 문서의 표현을147그대로 따르고, API는 MCP로 확인하세요.148149## 플랫폼 플레이북150151### iOS (Swift / Objective-C)152153**설치(공식)**:154155- CocoaPods: `pod 'notifly_sdk'`156- Swift Package Manager: `https://github.com/team-michael/notifly-ios-sdk`157158**프로젝트 설정(공식)**:159160- **Push Notifications** 활성화161- **Background Modes** 활성화 (Remote notifications, Background fetch)162- 최소 iOS 타겟 **13.0+**163164**초기화(공식 패턴)**:165166- `AppDelegate`에서 `FirebaseApp.configure()` 및 Notifly 초기화 수행167- 알림 권한 요청 후 원격 알림 등록168- `UNUserNotificationCenter` 델리게이트 설정169- APNs 토큰/푸시 콜백을 Notifly로 전달170171공식 가이드: `https://docs.notifly.tech/ko/developer-guide/ios-sdk.md`172173예시: `examples/ios-integration.swift`174175### Android (Kotlin / Java)176177**설치(공식)**:178179- JitPack 저장소 추가180- 의존성 추가:181 `implementation 'com.github.team-michael:notifly-android-sdk:<latest>'`182183**초기화(공식)**:184185- `Application.onCreate()`에서 초기화:186 - `Notifly.initialize(applicationContext, NOTIFLY_PROJECT_ID, BuildConfig.NOTIFLY_USERNAME, "")`187 - SDK 시그니처가 `password` 값을 요구하면 빈 값/`username` 더미값을 넘기며,188 별도 `NOTIFLY_PASSWORD` secret을 요구하지 않습니다.189190**유저 식별(초기화 후, 공식)**:191192- `Notifly.setUserId(context, userId)` (로그아웃 시:193 `Notifly.setUserId(context, null)`)194- `Notifly.setUserProperties(context, params)`195196**이벤트 트래킹(초기화 후, 공식)**:197198- `Notifly.trackEvent(context, eventName, eventParams, segmentationEventParamKeys)`199200예시: `examples/android-integration.kt`201202### Flutter203204**설치(공식)**:205206- `flutter pub add notifly_flutter`207- iOS: `cd ios && pod install`208209**초기화(공식)**:210211- `Firebase.initializeApp()` 보장212- `await NotiflyPlugin.initialize(projectId: ..., username: ..., password: "")`213 (`password` 인자가 필요하면 빈 값/`username` 더미값 사용)214- (선택) 콘솔에서 “자동 권한 요청”이 비활성화된 경우:215 `await NotiflyPlugin.requestPermission()`216- (선택) 인앱 팝업 이벤트 구독(공식 예시):217 `NotiflyPlugin.inAppEvents.listen(...)`218219예시: `examples/flutter-integration.dart`220221### React Native222223**설치(공식)**:224225- npm 패키지: `notifly-sdk`226- iOS: `cd ios && pod install`227228**설정(공식)**:229230- RN은 iOS/Android 네이티브 연동이 필요(공식 RN 문서 참조)231- 네이티브 연동 후, JS에서 `notifly-sdk` API 사용232233**JS API 사용(네이티브 연동 후)**:234235- `notifly.setUserId(userId)` (로그아웃: `notifly.setUserId(null)` 또는236 `notifly.setUserId()`)237- `notifly.setUserProperties({...})`238- `notifly.setEmail(email)`239- `notifly.setPhoneNumber(phoneNumber)`240- `notifly.setTimezone(timezone)`241242예시: `examples/react-native-integration.tsx`243244### Web (JavaScript SDK)245246**먼저 범위를 분리합니다.** 웹 팝업과 웹 푸시는 같은 SDK를 쓰지만 실패 지점이247다릅니다. 자세한 계약은 `references/web-javascript.md`를 함께 확인하세요.248249- **웹 팝업 only**: Service Worker/Notification 권한이 아니라250 `initialize → user state sync → trackEvent → campaign condition match → renderer`251 경로가 핵심입니다.252- **웹 푸시 only**: HTTPS, Notifly 콘솔의 VAPID/웹사이트 SDK 설정,253 Service Worker path/scope, 브라우저 권한, PushSubscription 생성이 핵심입니다.254- **웹 팝업 + 웹 푸시**: 초기화는 하나지만, 검증은 user/event 축과255 Service Worker/permission 축을 따로 수행합니다.256257**필수 선행(웹 푸시 사용 시, 공식)**:258259- 콘솔에서 VAPID 키 생성: 설정 → SDK 설정 → 웹사이트 설정260- HTTPS secure context에서 서비스. Web Push는 plain HTTP에서 검증하지 않습니다.261 로컬 테스트도 `https://localhost`로 서버를 띄워 Service Worker/권한/구독 흐름을262 확인하세요.263- Service Worker 파일 제공: 기본 권장 경로는 `/notifly-service-worker.js`입니다.264 단, 공식 문서상 파일명/경로는 변경 가능하며 Notifly 콘솔의265 `serviceWorkerPath` 설정과 실제 제공 경로가 반드시 일치해야 합니다.266- 기존 PWA/Firebase/OneSignal/Braze/Workbox Service Worker가 있는지 먼저 확인하고,267 root scope 충돌 가능성이 있으면 무작정 새 SW를 추가하지 않습니다.268269**1) Service Worker 등록(웹 푸시 사용 시)**:270271- public/static 경로에 Service Worker 파일을 생성하거나 기존 SW에 통합272- 내용(공식 패턴):273 - `self.importScripts("https://cdn.jsdelivr.net/npm/notifly-js-sdk@2/dist/NotiflyServiceWorker.js");`274- 번들러 사용 시 SW 파일이 번들에 흡수/삭제되지 않도록 assets copy 설정275- 실제 URL이 HTML fallback이 아니라 JavaScript 파일로 200 응답하는지 확인276277예시: `examples/notifly-service-worker.js`278279**2) SDK 설치(선택)**:280281- npm/yarn/pnpm: `notifly-js-sdk` 설치282- 또는 CDN으로 로드 후 `window.notifly` 접근283284**3) SDK 초기화(현재 SDK 2.5.0+ 공식 패턴)**:285286- 코드에는 `projectId`, `username`, 그리고 SDK 시그니처 호환용 `password` 필드를287 둡니다. 단, password 값은 사용하지 않으므로 별도 secret/env를 요구하지 말고288 `""`, `username`, 또는 프로젝트가 정한 더미값을 넘깁니다. 특히 Web에서289 `NEXT_PUBLIC_NOTIFLY_PASSWORD`/`NEXT_PUBLIC_NOTIFLY_PROJECT_PASSWORD`를 새로 요구하지290 않습니다.291- `projectId`가 env/config/콘솔 입력처럼 외부에서 들어오면 형식 검증(프로젝트 규칙,292 예: 32자 hex)과 missing/invalid 오류 분리를 유지합니다. 기존 config parser와 테스트가293 있으면 삭제하지 말고 확장합니다.294- SDK 2.5.0+에서는 세션/웹푸시 세부 옵션(VAPID/SW 경로/권한 팝업/지연시간 등)이295 콘솔 웹사이트 SDK 설정값으로 대체됩니다.296- SDK 2.5.0+ 신규 연동에서 `pushSubscriptionOptions`나 top-level297 `serviceWorkerPath`를 임의로 추가하지 않습니다. Legacy SDK 2.4 이하를 명시적으로298 지원할 때만 `pushSubscriptionOptions`를 사용합니다.299- 웹 팝업 HTML 내부에서 사용자 정의 이벤트 로깅이 필요한 경우에만 SDK 2.17.2+에서300 `allowUserSuppliedLogEvent: true`를 추가합니다. 기존 프로젝트에 이 옵션/env/config301 plumbing이나 테스트가 있으면 제거하지 말고 보존합니다.302303예시: `examples/web-integration.js`304305**4) 권한 요청(웹 푸시 사용 시)**:306307- 먼저 HTTPS 로컬 서버 또는 배포 HTTPS 도메인에서 페이지를 엽니다. plain HTTP에서308 권한/Service Worker/PushSubscription 흐름을 검증하지 않습니다.309- Next.js 로컬 테스트는 `npm run dev -- --experimental-https` 또는310 `npx next dev --experimental-https`로 실행하고 `https://localhost:3000`에서 확인합니다.311 필요하면 `--experimental-https-key`, `--experimental-https-cert`로 mkcert 인증서를 지정합니다.312- Next.js가 아니면 대상 프로젝트의 `package.json`/lockfile/scripts로 현재 웹 프레임워크를313 먼저 식별한 뒤, 해당 프레임워크의 공식 local HTTPS dev-server 방법을 찾아 실행합니다.314- 콘솔에서 자동 권한 팝업을 켜면 방문 시 안내 → 브라우저 권한 요청 순서로 동작315- 특정 타이밍에만 요청하려면 SDK 2.7.0+에서 콘솔 자동 노출을 끄고316 `notifly.requestPermission(...)` 호출317- `requestPermission(...)` 호출은 “권한 프롬프트를 시도했다”는 뜻일 뿐입니다. `Notification.permission`,318 Service Worker 등록, PushSubscription 생성, Notifly device property logging을 별도로 확인합니다.319- SDK 초기화/ready 상태와 웹푸시 구독 verified/subscribed 상태를 분리해서 UI/문서/리포트에 표시합니다.320- 브라우저 권한이 이미 `denied`이면 SDK가 다시 요청할 수 없으므로 브라우저/site321 설정에서 사용자가 직접 변경해야 합니다.322323**5) 유저/이벤트(웹 팝업/타깃팅 핵심)**:324325- 로그인 직후 권장 순서: `setUserId → setUserProperties → trackEvent`326- `notifly.setUserId(userId | null)` (`null`/무인자는 로그아웃 처리이며 문서상 유저327 데이터 삭제성 동작이 있으므로 의도 확인)328- `notifly.setUserProperties({...})`329- `notifly.trackEvent(name, params, segmentationEventParamKeys)`330 (`segmentationEventParamKeys`는 최대 1개 키)331332**6) Google Tag Manager(GTM) 옵션(선택)**:333334- 코드 수정 없이 초기화/유저/이벤트를 구성 가능(공식 GTM 가이드 참고)335- SDK script load timing과 dataLayer 이벤트 순서를 보장해야 합니다.336- 단, 웹 푸시를 쓰는 경우 SW 파일 제공은 여전히 필요합니다.337- CSP가 있으면 `script-src`, `connect-src`, `worker-src`에서 Notifly/CDN 호출을338 허용해야 합니다.339340### 5단계: SDK 초기화 위치 확정(레포 기준 증빙)341342이 단계는 “어디에 코드를 넣는지”와 “레포에서 증명 가능한지”를 점검합니다.343기존 앱에 provider/config/client/test 구조가 있으면 새 단일 파일로 덮어쓰기보다 그 구조를344보존한 채 필요한 SDK 호출과 검증만 추가하는 편이 좋습니다. 다만 이 항목들은 기존 앱의345명시적 계약을 깨지 않는 한 hard blocker가 아니라 quality/parity 신호로 보고합니다.346347웹 데모/재적용 검토에서 다음은 기본적으로 **non-blocking parity signal**입니다. 사용자가348명시적으로 hard requirement로 지정했거나 기존 앱의 계약을 실제로 깨는 경우에만 blocker로349올립니다:350351- 기존 provider/config/client/test 구조 보존352- root-level SDK init과 route coverage353- permission CTA analytics event 보존354- demo fixture의 exact SDK version pinning 보존355- validator가 marker pass를 넘어 behavioral contract 차이를 잡는 능력356357#### iOS 초기화 체크리스트358359- **엔트리포인트**: `AppDelegate.swift` (또는 SwiftUI에서360 `@UIApplicationDelegateAdaptor(AppDelegate.self)` 사용)361- **필수 포함**:362 - `FirebaseApp.configure()`363 - `Notifly.initialize(projectId:username:password)` (`password`는 빈 값/더미값)364 - `UNUserNotificationCenter.current().delegate = self`365 - 아래 콜백 전달:366 - `application(_:didRegisterForRemoteNotificationsWithDeviceToken:)`367 - `application(_:didFailToRegisterForRemoteNotificationsWithError:)`368 - `userNotificationCenter(_:didReceive:withCompletionHandler:)`369 - `userNotificationCenter(_:willPresent:withCompletionHandler:)`370371#### Android 초기화 체크리스트372373- **엔트리포인트**: 커스텀 `Application` 클래스 (Kotlin/Java)374- `AndroidManifest.xml`의 `android:name`으로 등록375- **필수 포함**: `Application.onCreate()`에서 `Notifly.initialize(...)`376377#### Flutter 초기화 체크리스트378379- **엔트리포인트**: `lib/main.dart` (+ iOS 브릿지 파일은 공식 문서대로)380- **필수 포함**: `await NotiflyPlugin.initialize(...)`381- **iOS 참고**: 공식 Flutter 문서는 `ios/Runner/AppDelegate.mm` 작업을 기대함382 (`flutter-sdk.md` 참조)383384#### React Native 초기화 체크리스트385386- **네이티브**: 공식 RN 문서대로 iOS `AppDelegate.mm`, Android `Application`387 연동 수행388- **JS**: 공식 RN SDK 샘플 패턴대로 API 사용(예시 파일 참조)389390### 6단계: 검증(필수)3913921. 모바일 스크립트 실행(앱 프로젝트 루트에서):393394- `bash skills/integration/scripts/validate-sdk.sh`395396> 참고: 위 스크립트는 **모바일 플랫폼(iOS/Android/Flutter/RN)** 검증용입니다.3973982. Web(JavaScript) 정적 검증:399400- `bash skills/integration/scripts/validate-web-sdk.sh /path/to/web-app`401402이 스크립트는 `notifly-js-sdk` 설치/CDN, `notifly.initialize(...)`, 자격 증명 마커,403Service Worker 후보, `NotiflyServiceWorker.js` import, legacy 옵션, user/event API404마커를 확인합니다. 추가로 projectId 검증/`allowUserSuppliedLogEvent`/수동 권한 요청의405런타임 의미를 경고로 표시합니다. 정적 검증은 충분조건이 아니므로 아래 런타임 검증까지 수행하세요.4064073. 빌드/실행 후 콘솔에서 확인:408409- 초기화 로그/동작 확인410- 푸시 토큰 등록(네이티브) 확인411- Notifly 콘솔에서 이벤트/기기 등록 확인4124134. Web 런타임 검증(웹 푸시/웹 팝업):414415- 웹 푸시는 HTTPS secure context에서만 검증합니다. 로컬도 `https://localhost`로 실행합니다.416 - Next.js: `npm run dev -- --experimental-https` 또는 `npx next dev --experimental-https`417 - Next.js가 아니면 `package.json`으로 프레임워크를 식별하고, 해당 프레임워크의 공식418 local HTTPS 실행법을 찾아 서버를 띄운 뒤 테스트합니다.419- 콘솔에 설정한 Service Worker path가 실제로 200 JS 응답인지 확인420 (`/notifly-service-worker.js`가 기본 예시이며, HTML fallback이면 실패)421- DevTools → Application → Service Workers에서 등록/scope 확인422- Network에서 `/sdk-configurations?project_id=...&type=website` 200 확인423- 브라우저에서 알림 권한 요청/허용 흐름이 의도대로 동작하는지 확인424 (`requestPermission(...)` 호출 자체는 prompt 시도일 뿐 성공/구독 증명이 아님)425- 권한 허용 후 PushSubscription 생성 및 device property logging 확인426- SDK 초기화/ready 상태와 웹푸시 verified/subscribed 상태를 분리해 확인427- `setUserId → setUserProperties → trackEvent` 호출 후 콘솔에서 반영 확인428- 웹 팝업 캠페인 조건에 맞는 이벤트 호출 시 modal 노출 확인429430### 7단계: 플랫폼별 레포 검증 체크리스트431432#### iOS433434- 의존성 존재 (Pods 또는 SPM)435- Capability 설정 완료 (Push + Background Modes)436- `AppDelegate`에서 APNs 콜백을 Notifly로 전달437438#### Android439440- JitPack repo 설정441- SDK 의존성 존재442- `Application` 클래스 존재 및 매니페스트 등록443- `Application.onCreate()`에서 `Notifly.initialize(...)`444445#### Flutter446447- `pubspec.yaml`에 `notifly_flutter` 포함448- `ios/Podfile.lock`이 `pod install` 이후 업데이트됨449- `NotiflyPlugin.initialize(...)` 호출450451#### React Native452453- `package.json`에 `notifly-sdk` 포함454- `ios/Podfile.lock`이 `pod install` 이후 업데이트됨455- 공식 문서대로 네이티브 연동 완료456- JS 호출이 공식 샘플 패턴과 일치457458#### Web (JavaScript)459460- `notifly-js-sdk` 설치(npm) 또는 CDN 로드 확인461- 앱 코드에서 현재 SDK 2.5.0+ 패턴인462 `notifly.initialize({ projectId, username, password })` 호출 확인463- SDK 호환용 `password` 필드는 필요하면 유지하되, password 값은 사용하지 않으므로464 별도 공개 env/secret을 요구하지 않습니다. `""`, `username`, 또는 프로젝트 더미값을465 넘기고, 프로젝트의 주입/노출 정책을 확인합니다.466- 외부 config에서 받은 `projectId` 검증과 missing/invalid 오류 분리를 보존합니다.467 기존 config parser/provider/tests가 있으면 삭제하지 말고 확장합니다.468- 신규 SDK 2.5.0+ 연동에서 `pushSubscriptionOptions` 또는 top-level469 `serviceWorkerPath`를 추가하지 않았는지 확인(legacy SDK 2.4 이하 예외)470- (웹 팝업) `setUserId → setUserProperties → trackEvent` 호출 순서와 이벤트/속성 설계가471 캠페인 조건과 일치472- (웹 팝업) 웹 팝업 HTML 내부 custom event logging이 필요할 때만473 `allowUserSuppliedLogEvent: true` 사용. 기존 plumbing/test가 있으면 보존474- (웹 푸시) 콘솔의 Service Worker path와 실제 제공 경로가 일치475- (웹 푸시) SW 파일이 `NotiflyServiceWorker.js`를 importScripts 하는지 확인476- (웹 푸시) 기존 PWA/Firebase/OneSignal/Braze/Workbox Service Worker와 scope/handler477 충돌이 없는지 확인478- (웹 푸시) 권한 요청 및 구독 흐름이 동작하는지 확인479 (`requestPermission(...)` 호출, `Notification.permission`, PushSubscription, device logging을 분리)480- (웹 푸시) SDK ready와 push subscribed/verified 상태를 같은 의미로 보고하지 않음481482### 8단계: 문서화483484연동 후 README/내부 문서에 다음을 기록:485486- 필요한 자격 증명과 주입 방법(시크릿은 노출하지 않기)487- iOS/Android 빌드/런 방법488- Notifly 콘솔에서 검증하는 방법489490## 문서 사용 노트 (MCP vs 정적 자료)491492- MCP 사용 가능: `search_docs` / `search_sdk` 결과를 단일 진실원으로 취급493- MCP 사용 불가: 공식 문서 링크 + 이 스킬 폴더의 `examples/`, `references/` 사용494495## 점진적 공개(Progressive Disclosure)496497- **레벨 1**: `SKILL.md` / `SKILL.ko.md`498- **레벨 2**: `references/`499- **레벨 3**: `examples/`500- **레벨 4**: `scripts/`501502## 참고 자료(References)503504- `references/sdk-reference.md`505- `references/error-handling.md`506- `references/framework-patterns.md`507- `references/web-javascript.md`508- `references/mcp-integration.md`509510## 예시(Examples)511512- `examples/ios-integration.swift`513- `examples/android-integration.kt`514- `examples/flutter-integration.dart`515- `examples/react-native-integration.tsx`516- `examples/notifly-service-worker.js`517- `examples/web-integration.js`518519## 스크립트(Scripts)520521- `scripts/install-mcp.sh` (클라이언트에 MCP 서버 구성)522- `scripts/validate-sdk.sh` (모바일 SDK 연동 마커 검증)523- `scripts/validate-web-sdk.sh` (JavaScript/Web SDK 연동 마커 검증)