PushizoDocs
Göç

Firebase Cloud Messaging'den (FCM) Pushizo'ya göç

Bildirimleri doğrudan Firebase Cloud Messaging (FCM HTTP v1 API, Firebase Admin SDK ya da Firebase konsolu) ile gönderiyorsanız bu rehber Pushizo'ya geçişi anlatır. Pushizo Android'de FCM'i taşıma katmanı olarak…

Bildirimleri doğrudan Firebase Cloud Messaging (FCM HTTP v1 API, Firebase Admin SDK ya da Firebase konsolu) ile gönderiyorsanız bu rehber Pushizo'ya geçişi anlatır. Pushizo Android'de FCM'i taşıma katmanı olarak kullanmaya devam eder; iOS'ta doğrudan APNs'e, web'de standart Web Push'a (VAPID) gönderir. Dolayısıyla Firebase projeniz ve mevcut Android token'larınız geçerliliğini korur.

1. Neler değişir

KonuFCM ile doğrudan gönderimPushizo
Android taşımaFCMFCM (aynı Firebase projesi, servis hesabı JSON'u ile)
iOS taşımaFCM → APNs (Firebase iOS SDK gerekir)Doğrudan APNs (.p8 anahtarı); Firebase iOS SDK gerekmez
Web taşımaFCM web (Firebase VAPID anahtarı)Standart Web Push, Pushizo'nun ürettiği VAPID çifti
HedeflemeToken, topic, conditionKullanıcı (external_id), abonelik, segment (tag/özellik/olay filtreleri), alias
Kullanıcı modeliYok (token listenizi siz tutarsınız)Kullanıcı + çoklu abonelik; cihaz birleştirme (login)
Zamanlama, sessiz saatler, frekans sınırıKendi kodunuzdaPlatform özelliği (send_after, delivery_time_of_day, app ayarları)
AnalitikFirebase Analytics olayları (notification_receive, notification_open)Teslimat zaman çizelgesi (queued → sent → received → opened), dönüşüm atribüsyonu, webhook olayları
E-posta / SMS / in-app / bildirim kutusuYokDahil

2. Kanal kurulumu

Android (android_push)

  1. Firebase konsolu → Project settings → Service accounts → Generate new private key ile servis hesabı JSON'unu indirin (firebase-adminsdk-…json). Zaten Admin SDK ile gönderim yapıyorsanız aynı dosyadır.
  2. Dashboard → Kanallar → Android Push → JSON'u yükleyin → Doğrula (POST /v1/apps/{app_id}/channels/android_push/validate FCM'e test bağlantısı yapar). Dosya envelope encryption ile saklanır ve hiçbir yanıtta dönmez.
  3. API ile: PUT /v1/apps/{app_id}/channels/android_push { "provider": "fcm", "service_account": { …JSON nesnesi ya da dosya içeriği metni… } } (admin kapsamı; proje değişiyorsa confirm_project_change: true).

Servis hesabı aynı Firebase projesine ait olduğu sürece uygulamanızdaki mevcut FCM token'ları Pushizo'dan de teslim alır. SENDER_ID_MISMATCH hatası görürseniz servis hesabı başka projeye aittir.

iOS (ios_push)

Firebase iOS SDK'sı APNs token'ını FCM token'ına çevirir; Pushizo bu dolaylamayı kullanmaz. Apple Developer → Keys → APNs anahtarı (.p8), Key ID, Team ID ve Bundle ID'yi Kanallar → iOS Push ekranına girin; ortam olarak Xcode derlemesi için sandbox, TestFlight/App Store için production seçin. Uygulamada Firebase Messaging'i kaldırabilir, FirebaseApp.configure()'ı yalnızca Analytics/Crashlytics için tutabilirsiniz.

Web (web_push)

Kanallar → Web Push etkinleştirildiğinde Pushizo bir VAPID çifti üretir. Firebase'in VAPID anahtarıyla oluşturulmuş tarayıcı abonelikleri taşınamaz; ziyaretçiler Pushizo Web SDK'sı ile yeniden abone olur (izin verilmişse autoResubscribe ile sessizce).

3. Token'ların taşınması

Seçenek A — SDK ile yeniden kayıt (önerilen)

Pushizo SDK'ları ilk açılışta cihazı POST /sdk/v1/apps/{app_id}/subscriptions ile kaydeder; Android'de token FirebaseMessaging.getInstance().token üzerinden alınır, iOS'ta didRegisterForRemoteNotificationsWithDeviceToken ile SDK'ya verilir. Kullanıcı kimliğini bildiğiniz anda Pushizo.login(externalId) çağırın; böylece tüm cihazlar aynı kullanıcıda birleşir. Bu yol ek veri aktarımı gerektirmez; aktif kullanıcılar uygulamayı açtıkça Pushizo'ya geçer.

Seçenek B — CSV içe aktarma (csv_users)

Uygulama açılmadan da hedeflenebilsin istiyorsanız kendi veritabanınızdaki FCM token'larını Pushizo CSV biçiminde dışa aktarıp yükleyin (Firebase'in token'ları dışa aktaran bir API'si yoktur; token'lar sizin sunucunuzdadır).

SütunDeğer
external_idKullanıcı kimliğiniz (token yoksa zorunlu)
channelandroid_push (Android FCM token'ı), email, sms. ios_push yalnızca ham APNs token'ı (hex) için; FCM'den gelen iOS token'ları aktarılamaz. web_push CSV ile aktarılamaz.
tokenFCM kayıt token'ı
statussubscribed (varsayılan), unsubscribed, invalid
language, timezonetr, Europe/Istanbul (IANA)
tags ya da tag.<anahtar>JSON nesnesi ya da sütun başına tag (ör. tag.topic_news)
properties ya da property.<anahtar>Kullanıcı özellikleri
external_id,channel,token,language,timezone,tag.topic_news,tag.plan
u-1001,android_push,dGhpcyBpcyBhIHRva2Vu…,tr,Europe/Istanbul,1,pro
u-1002,android_push,YW5vdGhlciB0b2tlbg…,en,Europe/London,,free
u-1003,,,tr,,1,
```text

```bash
curl -X POST "https://api.example.com/v1/apps/app_…/imports" \
  -H "Authorization: Bearer hs_live_…" -F type=csv_users -F file=@fcm-tokens.csv
```text

İş tamamlanınca `stats` (`processed, created_users, updated_users, created_subscriptions, skipped, errors`) ve hatalı satırlar için `error_report_url` döner. İçe aktarma idempotenttir; `(app, channel, token)` benzersiz olduğundan aynı token ikinci kez yüklendiğinde güncellenir. Toplu içe aktarma webhook üretmez. Sınır: 50 MB, 500.000 satır (`IMPORT_MAX_ROWS`); daha büyük dosyaları bölün.

Token FCM tarafından geçersiz bulunursa (`UNREGISTERED`) ilk gönderimde abonelik otomatik `invalid` olur; eski token'ları önceden temizlemeniz gerekmez.

## 4. Topic ve condition → segment / tag

FCM topic'lerinin Pushizo'da karşılığı yoktur; aynı işlevi **tag + segment** ya da **kategori tercihleri** sağlar.

| FCM | Pushizo |
|-----|------------|
| `FirebaseMessaging.getInstance().subscribeToTopic("news")` | `Pushizo.User.addTag("topic_news", "1")` (SDK) ya da `PATCH /v1/apps/{app_id}/users/by/external_id/{id}` `{ "tags": { "topic_news": "1" } }` |
| `unsubscribeFromTopic("news")` | `Pushizo.User.removeTag("topic_news")` ya da `{ "tags": { "topic_news": null } }` |
| `"topic": "news"` ile gönderim | Segment tanımı: `{ "all": [{ "field": "tags.topic_news", "op": "eq", "value": "1" }] }` → `target.included_segments: ["seg_…"]`; ya da kaydetmeden `target.filters` ile aynı tanım |
| `"condition": "'news' in topics && 'tr' in topics"` | Segment AST `all`/`any`/`none` grupları: `{ "all": [{ "field": "tags.topic_news", "op": "eq", "value": "1" }, { "field": "tags.topic_tr", "op": "eq", "value": "1" }] }` |
| Kullanıcının kendi seçtiği konu abonelikleri | **Kategoriler** (Dashboard → Kitle → Kategoriler) + `User.setPreferences([{ category: "news", optedIn: true }])`; kategoriye kapalı kullanıcı o kategorideki mesajı almaz (`suppression_reason: category_opt_out`) |
| Herkese gönderim (`"topic": "all"`) | `target.all: true` |

Segment önizleme (`POST /v1/apps/{app_id}/segments/preview`) sayım ve örnek kullanıcıları döndürür; bir hedef için gönderim yapmadan alıcı sayısı almak için `POST /v1/notifications/estimate`.

## 5. Mesaj gövdesi eşlemesi

FCM HTTP v1 `message` nesnesi ile Pushizo `POST /v1/notifications` alanları:

| FCM v1 | Pushizo | Not |
|--------|------------|-----|
| `token` / `topic` / `condition` | `target.include_subscription_ids` / `target.include_external_ids` / `target.included_segments` / `target.filters` | Hedef nesnesi zorunludur. |
| `notification.title` / `notification.body` | `headings` / `contents` | Çok dilli nesne: `{ "tr": "…", "en": "…" }`; alıcının diline göre seçilir. |
| `notification.image` | `big_picture` | Android büyük resim, iOS ek (NSE), web `chrome_web_image`. |
| `data` | `data` | Yalnızca metin değerler. Android'de Pushizo her zaman **data-only** gönderir; görünür bildirimi SDK (`PushizoMessagingService`) kurar, `data` alanınız tıklama olayında `event.notification.data` ile gelir. |
| `android.priority: HIGH` / `apns.headers.apns-priority: 10` | `priority: 10` | Normal için `5`. |
| `android.ttl` / `apns-expiration` | `ttl` | Saniye. |
| `android.collapse_key` / `apns-collapse-id` | `collapse_id` | |
| `android.notification.channel_id` | `android_channel_id` | Kanal tanımları: Dashboard → Ayarlar → Android bildirim kategorileri. |
| `android.notification.icon` / `color` / `sound` / `visibility` | `small_icon` / `android_accent_color` / `android_sound` / `android_visibility` | Renk `AARRGGBB`; görünürlük `1`, `0`, `-1`. |
| `android.notification.tag` (gruplama) | `android_group` | Grup + özet bildirimi. |
| `android.notification.click_action` / `webpush.fcm_options.link` | `url` / `app_url` | `app_url` deep link. |
| `apns.payload.aps.sound` | `ios_sound` | |
| `apns.payload.aps.badge` | `ios_badge_type: "SetTo"` + `ios_badge_count` (ya da `"Increase"`) | |
| `apns.payload.aps.category` | `ios_category` | |
| `apns.payload.aps.thread-id` | `thread_id` | |
| `apns.payload.aps.interruption-level` | `ios_interruption_level` | `passive`, `active`, `time-sensitive`, `critical` |
| `apns.payload.aps.relevance-score` | `ios_relevance_score` | |
| `apns.payload.aps.target-content-id` | `target_content_identifier` | |
| `apns.payload.aps.mutable-content` | `mutable_content` | Görünür bildirimlerde Pushizo zaten `1` gönderir (NSE zengin medya + `received`). |
| `apns.payload.aps.content-available` (sessiz) | `content_available: true` | Android'de `hs_silent` data mesajı, iOS'ta `background` push. |
| `apns.fcm_options.image` | `big_picture` ya da `ios_attachments` | |
| `webpush.notification.icon` / `image` / `badge` | `chrome_web_icon` / `chrome_web_image` / `chrome_web_badge` | |
| `webpush.notification.actions` | `web_buttons` | En fazla 2 düğme. |
| `webpush.notification.requireInteraction` | `require_interaction` | |
| `webpush.headers.Topic` | `web_push_topic` | |
| `fcm_options.analytics_label` | `name`, `labels` | Panel ve raporlarda görünür. |
| `android.direct_boot_ok`, `android.restricted_package_name` | — | Desteklenmez. |

Örnek (Firebase Admin SDK → Pushizo Node SDK):

```ts
// Önce (firebase-admin)
await admin.messaging().send({
  token,
  notification: { title: 'Siparişiniz yola çıktı', body: 'Takip bağlantısı içeride', image: 'https://cdn.example.com/box.png' },
  data: { order_id: '1001', screen: 'orders' },
  android: { priority: 'high', notification: { channelId: 'orders' } },
  apns: { payload: { aps: { sound: 'default', 'thread-id': 'orders' } } },
});

// Sonra (@pushizo/node)
await hs.notifications.create({
  idempotency_key: 'order-1001-shipped',
  target: { include_external_ids: [userId] },           // token yerine kullanıcı
  headings: { tr: 'Siparişiniz yola çıktı', en: 'Your order has shipped' },
  contents: { tr: 'Takip bağlantısı içeride', en: 'Tracking link inside' },
  big_picture: 'https://cdn.example.com/box.png',
  data: { order_id: '1001', screen: 'orders' },
  priority: 10,
  android_channel_id: 'orders',
  ios_sound: 'default',
  thread_id: 'orders',
});
```text

Aynı istek Python/Go/Java/.NET/Ruby SDK'larında `notifications.create` ile yapılır; sunucu SDK'sı olmayan dillerde `curl`:

```bash
curl -X POST https://api.example.com/v1/notifications \
  -H "Authorization: Bearer hs_live_…" -H "Content-Type: application/json" -H "Idempotency-Key: order-1001-shipped" \
  -d '{"app_id":"app_…","target":{"include_external_ids":["u-1001"]},"headings":{"tr":"Siparişiniz yola çıktı"},"contents":{"tr":"Takip bağlantısı içeride"},"data":{"order_id":"1001"}}'
```text

### Data (sessiz) mesajlar

- FCM `data`-only mesajı: Pushizo'da `content_available: true` + `data`. Android SDK bildirim göstermez; iOS'ta `apns-push-type: background` ile gönderilir (`aps.content-available: 1`). iOS arka plan push'larında Apple'ın saat başına birkaç mesaj sınırı geçerlidir.
- Uygulamanızda `FirebaseMessagingService.onMessageReceived` içinde yaptığınız özel işleme Pushizo'da `Pushizo.Notifications.addForegroundLifecycleListener` (ön plan) ve `addClickListener` (tıklama, `event.notification.data`) ile taşınır. Kendi `FirebaseMessagingService` sınıfınız kalacaksa manifestte yalnızca biri FCM mesajlarını alır; Pushizo'nun `PushizoMessagingService`'i manifest merge ile eklenir, kendi servisinizi kaldırın ya da Pushizo dışı mesajları ayırt etmek için `data.hs_delivery_id` alanına bakın.

## 6. Analitik farkları

| Ölçüm | Firebase | Pushizo |
|-------|----------|------------|
| Gönderildi | FCM yanıtı (`messageId`) | `delivery.sent` (`provider_message_id`), mesaj sayacı `counts.sent` |
| Cihaza ulaştı | Yok (yalnızca GA `notification_receive`, Android) | `received` — Android SDK `onMessageReceived`, iOS NSE, web service worker tarafından raporlanır (`confirmed delivery`) |
| Açıldı | GA `notification_open` | `opened` (+ `button_id`), webhook `delivery.opened` |
| Başarısız / geçersiz token | FCM hata kodu, token'ı siz temizlersiniz | `delivery.failed` (`error_code`), abonelik otomatik `invalid`, `subscription.invalidated` webhook'u |
| Dönüşüm | GA dönüşüm olayı | Olay tanımı `is_conversion` + atribüsyon penceresi (`GET /v1/apps/{app_id}/analytics/conversions`) |
| Raporlar | Firebase konsolu | Dashboard → Analitik (teslimat, abonelik büyümesi, olay hacmi, funnel, retention, sağlayıcı sağlığı) ve `GET /v1/apps/{app_id}/analytics/*` (CSV için `format=csv`) |
| Ham olay dışa aktarımı | BigQuery export | `POST /v1/notifications/{id}/export_events`, `POST /v1/apps/{app_id}/exports` (`deliveries`, `events`) |

Firebase Analytics olaylarını (`notification_receive`, `notification_open`) kullanan panolarınız varsa, Pushizo webhook'larını (`delivery.*`) kendi veri ambarınıza yazarak aynı metrikleri üretebilirsiniz; olaylar `Pushizo-Event-Id` ile tekilleştirilir.

## 7. Geçiş sırası

1. Kanalları kurup doğrulayın; bir test cihazını **Test cihazı** yapıp **Mesajlar → Test push gönder** ile teslimatı görün.
2. Sunucu tarafında gönderimleri Pushizo'ya taşıyın (önce işlemsel bildirimler, sonra toplu kampanyalar). Topic bazlı gönderimleri segmentlere çevirin.
3. Android/iOS uygulamalarına Pushizo SDK'sını ekleyip (`docs/sdk/android.md`, `docs/sdk/ios.md`) yeni sürümü yayınlayın; `login(externalId)` çağrısını kimlik doğrulama akışına koyun.
4. Eski sürümlerdeki kullanıcılar için (SDK'sız) Seçenek B ile token'ları içe aktarın; yeni sürüm yayıldıkça bu kayıtlar SDK kayıtlarıyla `(app, channel, token)` üzerinden birleşir.
5. Firebase konsolundan/Admin SDK'dan gönderimi durdurun; servis hesabı anahtarını yalnızca Pushizo'da bırakın.

Bu sayfada