PushizoDocs
OperasyonRunbook'lar

Veri dışa / içe aktarma (export / import)

Faz 8 ile gelen export/import işleri maintenance kuyruğunda worker tarafından çalışır; dosyalar S3 uyumlu nesne depolamada (yerelde RustFS, S3_* ortam değişkenleri) tutulur. Dashboard: Kitle → Dışa / İçe Aktarım. API:…

Faz 8 ile gelen export/import işleri maintenance kuyruğunda worker tarafından çalışır; dosyalar S3 uyumlu nesne depolamada (yerelde RustFS, S3_* ortam değişkenleri) tutulur. Dashboard: Kitle → Dışa / İçe Aktarım. API: POST/GET /v1/apps/{app_id}/exports, POST/GET /v1/apps/{app_id}/imports (admin kapsamı).

Export

TürSütunlar
usersid, external_id, tags (JSON), properties (JSON), session_count, first_seen_at, last_active_at, created_at — filters.segment_id ile segment kitlesi
subscriptionsid, user_id, external_id, channel, status, token_masked (son 8), device (JSON), test_device, last_active_at, unsubscribed_at, created_at — filters.channel, filters.status
eventsid, user_id, subscription_id, name, properties (JSON), value, source, occurred_at — filters.name, from, to
deliveriesid, message_id, campaign_id, subscription_id, user_id, channel, status, error_code, suppression_reason, sent_at, delivered_at, opened_at, clicked_at, created_at — filters.message_id, campaign_id, status, from, to
  • Dosya UTF-8 BOM ile CSV'dir (Excel uyumu); =, +, -, @ ile başlayan hücreler tek tırnakla etkisizleştirilir.
  • Üst sınır 1.000.000 satır; keyset sayfalama ile 5.000'lik gruplar okunur. Ölçüm: 100.000 kullanıcı ≈ 2 sn (18 MB).
  • GET …/exports/{id} tamamlanmış iş için download_url döner (imzalı, EXPORT_URL_TTL_HOURS, varsayılan 24 saat). Tarayıcıya verilen adres S3_PUBLIC_ENDPOINT ile belirlenir. Bu adres yol öneki içeremez (SigV4 imzası yolu ve Host'u kapsar); compose üretimde ayrı alan adı kullanılır: STORAGE_HOST (nginx yalnızca GET/HEAD iletir, Host korunur) ve S3_PUBLIC_ENDPOINT=https://<STORAGE_HOST>.
  • Token'lar ham olarak dışa aktarılmaz (maskeli); e-posta/telefon gibi PII ileride eklenirse aynı maskeleme uygulanır.

Import

POST …/imports gövdesi multipart/form-data: type (csv_users | onesignal_players) ve file (CSV, en fazla 50 MB). İş tamamlanınca stats (processed, created_users, updated_users, created_subscriptions, skipped, errors) ve hatalı satırlar için error_report_url (sütunlar: line, error, row) döner.

Pushizo CSV (csv_users)

SütunAçıklama
external_idKullanıcı kimliği (abonelik yoksa zorunlu). Aynı external_id tekrar edince tag/property birleştirilir.
channelios_push, android_push, email, sms (token varsa zorunlu; web_push CSV ile aktarılamaz: p256dh/auth anahtarları yok)
tokenCihaz token'ı / e-posta / telefon; (app, channel, token) benzersiz, varsa güncellenir
statussubscribed (varsayılan), unsubscribed, invalid
language, timezoneproperties.language ve device.timezone (IANA)
tagsJSON nesnesi, ya da tag.<anahtar> sütunları
propertiesJSON nesnesi, ya da property.<anahtar> sütunları

Örnek:

external_id,channel,token,language,timezone,tag.plan,tag.city
u-1001,ios_push,0a1b2c…,tr,Europe/Istanbul,pro,Ankara
u-1002,,,en,,free,
```text

### OneSignal player CSV (`onesignal_players`)

OneSignal panelindeki "Export" dosyası olduğu gibi yüklenir. Eşleme:

| OneSignal | Pushizo |
|-----------|------------|
| `external_user_id` | `external_id` (boşsa ve token varsa anonim kullanıcı) |
| `identifier` | token |
| `device_type` 0 → `ios_push`; 1, 2, 13 → `android_push`; 5, 7, 8, 9, 10 → web (yalnızca kullanıcı); 11 → `email`; 14 → `sms` |
| `invalid_identifier` = t | abonelik `invalid` |
| `notification_types` < 0 | abonelik `unsubscribed` |
| `tags` (JSON) | tags |
| `language` | `properties.language`, `device.locale` |
| `timezone` (UTC'den saniye) | `device.timezone` = `Etc/GMT∓h` (tam saat değilse boş) |
| `device_model`, `device_os`, `game_version` | `device.model`, `device.os_version`, `device.app_version` |
| `session_count`, `created_at`, `last_active` | `session_count`, `first_seen_at`, `last_active_at` |

Örnek dosya: `tests/fixtures/onesignal-players-sample.csv`. Import idempotenttir: aynı dosya ikinci kez yüklendiğinde kullanıcı/abonelik yinelenmez (`updated_users` artar).

## Sorun giderme

- İş `failed` ise `error` alanına bakın; depolama erişilemiyorsa API başlangıcında "Nesne depolama erişilemedi" uyarısı loglanır (`npm run infra:status` → rustfs).
- Büyük import dosyalarını 500 bin satırın altında tutun (`IMPORT_MAX_ROWS`); daha büyük dosyaları bölerek yükleyin.

Bu sayfada