Veri ambarına dışa aktarım
Pushizo; teslimat, olay, dönüşüm, kullanıcı ve abonelik verilerini düzenli olarak kendi veri ambarınıza aktarır: BigQuery, Snowflake veya S3 (Parquet). İlk çalıştırma geçmiş verinin tamamını, sonrakiler yalnızca yeni ve…
Pushizo; teslimat, olay, dönüşüm, kullanıcı ve abonelik verilerini düzenli olarak kendi veri ambarınıza aktarır:
BigQuery, Snowflake veya S3 (Parquet). İlk çalıştırma geçmiş verinin tamamını, sonrakiler yalnızca yeni ve
değişen satırları aktarır (docs/adr/0030-event-streams-ve-veri-ambari.md).
Yönetim: dashboard Geliştirici → Veri ambarı (organizasyon sahibi/yöneticisi) veya public API
/v1/apps/{appId}/warehouse-exports (admin kapsamlı API anahtarı).
Tablolar
| Tablo | Tür | İmleç | Not |
|---|---|---|---|
deliveries | artımlı | updated_at | Durum her değiştiğinde yeni satır; güncel durum için id başına en büyük updated_at |
delivery_events | artımlı | occurred_at | gönderildi, teslim edildi, açıldı, tıklandı … |
events | artımlı | received_at | Özel olaylar; occurred_at istemci zamanıdır |
conversions | artımlı | attributed_at | Dönüşüm ve atıf |
users | anlık görüntü | — | Günde bir (planlı çalıştırmada) |
subscriptions | anlık görüntü | — | Cihaz token'ı ve hassas konum aktarılmaz |
Her satırda ek kolonlar: _run_id (çalıştırma kimliği) ve _exported_at (dışa aktarım zamanı, UTC). Anlık görüntü
tablolarında en güncel görüntü max(_exported_at) ile seçilir. Kolon listesi ve şema sürümleri
GET /v1/apps/{appId}/warehouse-exports/tables ile okunur.
-- BigQuery: teslimatların güncel durumu
SELECT * EXCEPT(rn) FROM (
SELECT *, ROW_NUMBER() OVER (PARTITION BY id ORDER BY updated_at DESC) AS rn
FROM `proje.pushizo.deliveries`
) WHERE rn = 1;
```text
Şema değişince kolonlar yalnızca **eklenir** (sona, boş değer kabul eden); hedef tablo bir sonraki çalıştırmada
güncellenir.
## Zamanlama ve güvenilirlik
- **Saatlik:** her saat başından 5 dk sonra; **günlük:** 00:15 UTC. "Şimdi çalıştır" ile elle tetiklenebilir
(`POST …/warehouse-exports/{id}/run`); bekleyen veya süren bir çalıştırma varsa ya da dışa aktarım duraklatılmışsa
`409` döner.
- Okuma, çalıştırma başlangıcından 5 dk öncesine kadar yapılır (geç tamamlanan işlemler kaçmaz; kalan kısım bir
sonraki çalıştırmada gelir).
- Geçici hatalar (ağ, zaman aşımı, 429, 5xx) 1, 2, 4 dk aralıklarla yeniden denenir. Yarıda kalan çalıştırma son
yazılan parçadan devam eder ve **çift satır üretmez** (parça bazında idempotent yazım).
- 3 ardışık başarısız çalıştırmada organizasyon sahip/yöneticilerine e-posta gönderilir ve denetim kaydı
(`warehouse_export.failing`) oluşur. Son başarılı imleç korunduğundan sorun giderildiğinde veri kaybı olmaz.
- Çok büyük ilk aktarımlar parçalara bölünür: çalıştırma 20 dk sonra ilerlemeyi kaydedip kısmi biter, devamı
dakikalar içinde otomatik başlar.
## BigQuery
1. Google Cloud'da bir servis hesabı oluşturun; projede **BigQuery Data Editor** ve **BigQuery Job User** rollerini verin.
2. Servis hesabı için JSON anahtar oluşturun ve içeriğini sihirbazdaki alana yapıştırın.
3. Proje kimliği, dataset (yoksa oluşturulur) ve konumu (`EU`, `US`, `europe-west3` …) girin.
Yükleme NDJSON **load job** ile yapılır (akış ücreti yok). Tablolar `_exported_at` üzerinde günlük bölümlüdür; JSON
alanlar `JSON` türündedir.
```bash
curl -X POST "$API/v1/apps/$APP_ID/warehouse-exports" -H "Authorization: Bearer $HS_KEY" -H 'content-type: application/json' -d '{
"name": "BigQuery günlük",
"destination": "bigquery",
"config": { "project_id": "my-project", "dataset": "pushizo", "location": "EU" },
"credentials": { "service_account_json": "<servis hesabı JSON içeriği, metin olarak>" },
"tables": ["deliveries", "events", "conversions"],
"schedule": "daily"
}'
```text
## Snowflake
**Önkoşul:** Pushizo veritabanı, şema ve warehouse **oluşturmaz** (yalnızca tabloları oluşturur ve kolon ekler).
Hedef veritabanı, şema ve warehouse sihirbazdan önce Snowflake'te var olmalıdır:
```sql
CREATE DATABASE IF NOT EXISTS ANALYTICS;
CREATE SCHEMA IF NOT EXISTS ANALYTICS.PUSHIZO;
CREATE WAREHOUSE IF NOT EXISTS LOAD_WH WITH WAREHOUSE_SIZE = 'XSMALL' AUTO_SUSPEND = 60 AUTO_RESUME = TRUE;
```text
Bunlar yoksa bağlantı testi ve çalıştırmalar `permission_denied` (nesne yok veya yetki yok) hatasıyla kalıcı olarak
başarısız olur.
1. Anahtar çifti oluşturun (şifresiz PKCS#8):
```bash
openssl genrsa 2048 | openssl pkcs8 -topk8 -inform PEM -out rsa_key.p8 -nocrypt
openssl rsa -in rsa_key.p8 -pubout -out rsa_key.pub
```text
2. Genel anahtarı kullanıcıya atayın ve yetki verin:
```sql
ALTER USER HS_LOADER SET RSA_PUBLIC_KEY='MIIBIjANBgkqh…';
GRANT USAGE ON WAREHOUSE LOAD_WH TO ROLE HS_LOADER_ROLE;
GRANT USAGE ON DATABASE ANALYTICS TO ROLE HS_LOADER_ROLE;
GRANT USAGE, CREATE TABLE ON SCHEMA ANALYTICS.PUSHIZO TO ROLE HS_LOADER_ROLE;
```text
3. Sihirbazda hesap tanımlayıcısı (`myorg-myaccount` veya `xy12345.eu-central-1`), kullanıcı, veritabanı, şema,
warehouse, isteğe bağlı rol ve `rsa_key.p8` içeriğini girin.
Tablolar `CREATE TABLE IF NOT EXISTS` ile oluşturulur; JSON alanlar `VARIANT`, zamanlar `TIMESTAMP_TZ`'dir.
## S3 (Parquet)
- Bucket, bölge, anahtar öneki ve erişim anahtarı (yalnızca `s3:PutObject` ve bağlantı testi için `s3:DeleteObject`
yeterli) girin. Cloudflare R2, MinIO gibi uyumlu depolamalar için özel uç verilebilir (iç ağ adresleri kabul edilmez).
- Dosya düzeni (Hive bölümleme, `dt` = dışa aktarım günü UTC):
```text
<önek>/table=events/dt=2026-10-15/part-<çalıştırma>-0000.parquet
```text
- Dosyalar GZIP sıkıştırmalı Parquet'tir; Athena, Spark, DuckDB, BigQuery external table ve pandas/pyarrow doğrudan okur:
```sql
-- DuckDB
SELECT count(*) FROM read_parquet('s3://hs-lake/pushizo/table=events/dt=*/*.parquet', hive_partitioning = true);
```text
## Güvenlik
- Kimlik bilgileri zarf şifrelemeyle saklanır, API yanıtlarında ve denetim kayıtlarında yer almaz; yalnızca gizli
olmayan özet gösterilir (servis hesabı e-postası, Snowflake anahtar parmak izi, maskeli erişim anahtarı).
- Kimlik bilgisini değiştirmek için düzenlemede `credentials` alanını yeniden gönderin.
- Yerel geliştirmede `PROVIDER_MODE=mock` iken BigQuery/Snowflake istekleri ağa çıkmaz (mock taşıyıcı); S3 her modda
gerçek istemcidir (yerelde RustFS).Event Streams: webhook gövde şablonu ve olay filtresi
Event Streams, giden webhook'ların (docs/webhooks.md) gövdesini alıcının beklediği biçime dönüştürmenizi ve yalnızca ilgilendiğiniz olayları almanızı sağlar (ADR-0030). Dashboard'da Geliştirici → Webhooks → endpoint…
Dışa ve içe aktarma (CSV)
CSV export işleri (users, subscriptions, events, deliveries), imzalı indirme bağlantısı, Pushizo ve OneSignal CSV içe aktarma, hata raporu ve saklama süreleri.