Files
sp/sase-posthog-events-prd.md
Semih fc6a3f7a39 feat(phase6a-v1.2): dual-mode custom-event enrichment (v1.0 + v2.0 aliases)
- Prisma: posthog_person_cache (24h TTL), posthog_group_cache, session_custom_events
- SessionMeta: +posthogDistinctId, +groupKey, +customEventCount
- PostHog client: listSessionEvents, getPerson, getGroup
- posthog-cache.ts: cache-with-stale-refresh for person + group properties
- event-taxonomy.ts: dual-mode alias map (vin_decoded↔vin_decode_initiated,
  vin_decode_success↔vin_decode_succeeded, vin_decode_error↔vin_decode_failed,
  payment_success↔payment_succeeded). 56 tracked event names total.
- enrich.ts: per-session custom events fetch, persist to session_custom_events,
  attach user_properties + group_properties via cache.
- tagger.ts: 14 new custom-event tags
  (vin_decode_fail_pattern, provider_reliability_issue, payment_friction,
   payment_ui_silent_failure (P0), payment_failed_session, checkout_abandonment,
   downgrade_pending, compatibility_quality_gap, parts_export_abandoned,
   search_validation_friction, onboarding_stuck, upgrade_hesitation,
   power_user_path, at_risk_active_session, provider_mismatch,
   api_key_friction, webhook_setup_struggle); group-context priority bump.
- heuristic.ts: customEventPromoteReasons() — 10 custom-event promote signals.
- compress.ts: merge_rrweb_and_custom_events interleaving with ⤷ EVENT: prefix,
  ±1.5s grouping, standalone flush for events with no nearby rrweb. Adds
  company_context header line; key_events lists top-5 custom event counts.
- /insights page: +Events column. /insights/sessions/[id]: collapsible custom
  events table + group key display.

Graceful: when Sase.tr emits 0 custom events the pipeline falls back to
rrweb-only tagging from Phase 6a v1.1.

PRD: behavioral-insight-pipeline-prd-1.md (v1.2),
     sase-posthog-events-prd.md (Sase.tr-side, separate codebase).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-13 22:17:18 +00:00

50 KiB
Raw Blame History

Sase.tr — PostHog Event Taxonomy & Implementation PRD

Proje Kodu: SASE-PH-001 Pilot: Süper Panel Behavioral Insight Pipeline (BIP-001) Phase 6 Prerequisite Doküman Türü: Implementation PRD (Sase.tr codebase work) Durum: Draft v1.0 Sahip: Founder (Thinxtra SaaS Studio) Hedef Branch: feature/posthog-event-expansion


İçindekiler

  1. Vizyon ve Bağlam
  2. Hedefler ve Hedef Olmayanlar
  3. Mevcut Event Inventory ve Değerlendirme
  4. Identification Strategy (User + Group)
  5. Yeni Event Inventory
  6. Event Schema Standardı
  7. Mevcut Event İyileştirmeleri
  8. Data Privacy ve KVKK Uyumu
  9. Implementation Plan
  10. Testing Strategy
  11. Migration ve Backward Compatibility
  12. PostHog Dashboard Setup
  13. Documentation Standardı
  14. Riskler
  15. Karar Logu

1. Vizyon ve Bağlam

Bu PRD Neden Var

Süper Panel Behavioral Insight Pipeline (BIP) Phase 6 pilot'u Sase.tr üzerinde çalışacak. Pilot başlangıcında pipeline'ın aşağı yukarı 4 katmandan oluşacağı planlandı: ingestion → tagging → compression → LLM. Ancak gerçek değer üretmek için giriş katmanındaki sinyal kalitesi belirleyici.

Sase.tr'de mevcut PostHog event yapısı iskelet olarak hazır ama insight pipeline için 6 kritik alanda gap var:

  1. VIN decode performance context yok (timing, retry, provider detail)
  2. Parts/compatibility layer'da neredeyse hiç event yok
  3. Multi-provider fallback visibility yok
  4. Search behavior pre-submit görünmez
  5. Feature discovery pattern'leri yok
  6. User identification + group analytics belirsiz

Pipeline bu gap'ler kapatılmadan başlatılırsa:

  • Insight'lar generic ve actionable olmaz
  • LLM hallucination riski artar (eksik context'i tahminle doldurmaya çalışır)
  • Cost-per-validated-insight hedefi tutturulamaz
  • KVKK compliance riski (data-private audit yapılmadan)

Kapsam

Bu PRD sadece Sase.tr codebase work'tür. Süper Panel tarafı (ingestion, compression, LLM) ayrı PRD'de (BIP-001) ele alınır.

İçerik:

  • Identification flow audit ve update
  • 35+ yeni event eklemesi (3 fazda)
  • 8 mevcut event'in property zenginleştirmesi
  • data-private attribute audit
  • PostHog dashboard ve funnel kurulumu

Bağımlılık Zinciri

[Bu PRD - Sase.tr Event Work]
        ↓ (output: zengin event stream)
[BIP Phase 6a - Ingestion + Filter]
        ↓
[BIP Phase 6b - LLM Analysis MVP]
        ↓
[Insight pipeline value]

Bu PRD'nin Faz 0 (blocker) kısmı tamamlanmadan BIP Phase 6a başlatılmamalı. Faz 1 (high-ROI) ise BIP Phase 6a ile paralel yürüyebilir.


2. Hedefler ve Hedef Olmayanlar

Hedefler

# Hedef Ölçü
G1 BIP pilot'un yüksek-kalite insight üretmesi için gereken event'leri eklemek Event taxonomy %100 dokümante, 0 ad-hoc capture
G2 B2B account-level analiz için group analytics kurulumu posthog.group('company') tüm authenticated session'larda çalışır
G3 User cohort segmentation kapasitesi identify() çağrısı plan_tier, signup_date, company_id, total_queries içerir
G4 KVKK uyumlu sensitive data handling Tüm PII alanları data-private veya PostHog mask config'i ile korunur
G5 Mevcut event'lerin geriye dönük kırılmaması Production funnels/dashboards bozulmaz
G6 Faz 0 (blocker) 2 gün içinde tamamlanır Phase 6a başlangıç tarihini bloklamaz
G7 Tüm yeni event'ler tek bir taxonomy kaynağında dokümante docs/posthog-events.md tek doğruluk kaynağı

Hedef Olmayanlar

  • PostHog SDK migration: posthog-js / posthog-node mevcut versiyonlar kalır, upgrade ayrı
  • PostHog → diğer analytics geçişi: Bu PRD'de PostHog tercihi sabit
  • Tüm autocapture event'lerinin manual'a dönüştürülmesi: PostHog autocapture (pageview, autocapture, rageclick) korunur
  • Backend event coverage'ın frontend'e eşitlenmesi: Bazı event'ler doğal olarak sadece frontend (UI interaction) veya sadece backend (transaction confirmation)
  • Mobile app event coverage: Sase.tr mobile yok, varsa ayrı PRD
  • Real-time event processing: PostHog ingestion latency'si kabul edilir
  • A/B test infrastructure: Bu PRD'de feature flag setup yok (BIP Phase 6d'de ele alınır)
  • Custom property dictionary'nin uluslararasılaştırılması: Property anahtarları İngilizce kalır

3. Mevcut Event Inventory ve Değerlendirme

3.1 Mevcut Event Dökümü

Aşağıdaki event'ler şu an Sase.tr'de production'da gönderiliyor:

Auth & Kullanıcı Yaşam Döngüsü

Event Properties Kaynak Pipeline Değerlendirmesi
user_signed_up method: "email" | "google" _auth/register.tsx:41,78 İyi durumda
user_logged_in method: "email" | "google" _auth/login.tsx:42,65 İyi durumda
user_logged_out reason?: "account_deleted" dashboard.tsx:148, settings-content.tsx:136 İyi durumda
Event Properties Kaynak Pipeline Değerlendirmesi
vin_decoded vin search.tsx:142 ⚠️ Naming muğlak (initiated mi success mi?), context fakir
vin_decode_success vin, vehicle_id, source? search.tsx:166, index.tsx:529 ⚠️ Performance context yok, source belirsiz
vin_decode_error vin, error, source? search.tsx:174, index.tsx:534 ⚠️ Error code yok, retry context yok
vin_decode_candidates (çoklu eşleşme modal) search.tsx:157 ⚠️ Candidate sayısı/yapısı yok
vin_decode_candidate_selected (seçim) search.tsx:225 ⚠️ Hangi candidate seçildi (index, confidence) yok

Subscription / Pricing Funnel

Event Properties Kaynak Pipeline Değerlendirmesi
plan_selected plan subscription/index.tsx:326 ⚠️ Context fakir (price, period?)
yearly_toggle_clicked period: "monthly" | "yearly" :1039, 1050
checkout_started plan, period :344 ⚠️ Coming-from context yok
trial_started yok :936 ⚠️ Plan offered yok
subscription_cancelled yok :897 ⚠️ Cancellation reason yok
subscription_resumed yok :737 ⚠️ Time-away yok
cancel_flow_viewed yok :876
cancel_save_clicked yok :268 ⚠️ Hangi save offer kabul edildi?
downgrade_offer_shown yok :364 ⚠️ Which offer?
downgrade_offer_accepted yok :264 ⚠️ Which?
downgrade_offer_declined yok :827 ⚠️ Which?

Trial Urgency Banner (FN-306)

Event Properties Kaynak Pipeline Değerlendirmesi
trial_urgency_banner_viewed yok subscription/index.tsx:430, trial-urgency-banner.tsx:77 ⚠️ Days left to trial end yok
trial_urgency_banner_cta_clicked yok :492, :97 ⚠️ Same
trial_urgency_banner_dismissed yok :501, :87 ⚠️ Same

Payment

Event Properties Kaynak Pipeline Değerlendirmesi
payment_initiated method: "iyzico" | "eft", plan, period, amount payment-content.tsx:196,202 İyi
payment_success (dual: FE+BE) payment-content.tsx:73,135, payments.service.ts:122,214 ⚠️ Dual-capture clarify gerekli
payment_failed (dual: FE+BE) payment-content.tsx:76, payments.service.ts:130,237 ⚠️ Failure reason zayıf
receipt_uploaded payment_id payment-content.tsx:209

Schema / Parts

Event Properties Kaynak Pipeline Değerlendirmesi
oem_code_copied oem_code, part_id, ... parts-panel.tsx:52 ⚠️ Tek parts event'i, layer'ın geri kalanı görünmez

Social Proof

Event Properties Kaynak Pipeline Değerlendirmesi
social_proof_impression page, section? _auth.tsx:23, index.tsx:572,589,606, subscription/index.tsx:456,473
social_proof_engaged page, section? _auth.tsx:33, index.tsx:616, subscription/index.tsx:483,487

3.2 Genel Değerlendirme

Güçlü yönler:

  • Subscription/pricing funnel disiplinli (downgrade offer zinciri özellikle değerli)
  • VIN decode için ayrı success/error/candidates ayrımı doğru pattern
  • Auth events çift kanal değil (sadece frontend, duplicate yok)
  • Payment dual-capture infrastructure değerli (reliability için), kullanımı netleşince güçlenir

Genel gap'ler:

  • 11 event'in 0 properties olması (boş capture)
  • VIN decode family'sinde performance/context fakirliği
  • Parts layer'da single event (Sase.tr'nin core value layer'ı)
  • Provider multi-source görünmezliği
  • Identification + group analytics belirsizliği

3.3 Identification Audit (Önce Doğrulanmalı)

Bilinmeyenler — Faz 0 öncesi audit gerekli:

  • posthog.identify(userId, properties) çağrılıyor mu? Nerede?
  • Hangi user property'leri set ediliyor?
  • posthog.group('company', companyId) çağrılıyor mu? (Büyük ihtimalle hayır, çünkü event listesinde company_id görünmüyor)
  • Anonymous → authenticated geçişte posthog.alias() çağrılıyor mu?
  • posthog.reset() logout'ta çağrılıyor mu?

Bu beş soruyu Faz 0 başlangıcında 30 dakikalık codebase audit ile cevapla.


4. Identification Strategy (User + Group)

4.1 User Identification

Hedef: Her authenticated session başlangıcında posthog.identify() çağrılır ve aşağıdaki property setlenir/güncellenir.

User Properties Schema

type PostHogUserProperties = {
  // Identity (set once, $set_once kullan)
  signup_date: string;              // ISO 8601
  signup_method: 'email' | 'google';
  
  // Mutable state (set every login, $set kullan)
  email_domain: string;             // "domain.com" (full email değil — PII)
  plan_tier: 'free' | 'starter' | 'brand_specific' | 'full';
  plan_period: 'monthly' | 'yearly' | null;
  subscription_status: 'trial' | 'active' | 'cancelled' | 'past_due' | 'none';
  trial_ends_at: string | null;     // ISO 8601
  
  // B2B
  company_id: string | null;
  company_role: 'owner' | 'admin' | 'member' | null;
  
  // Behavior aggregates (periyodik update, daily cron)
  total_vin_queries: number;
  total_vin_queries_last_30d: number;
  preferred_provider: 'PL24' | 'PCAT' | 'RMEX' | 'TecDoc' | null;
  last_query_at: string | null;
  total_logins: number;
  days_since_signup: number;
  
  // Feature flags / preferences
  language: 'tr' | 'en';
  timezone: string;                 // "Europe/Istanbul"
  has_api_keys: boolean;
  has_webhooks: boolean;
  
  // Locked properties (asla değişmez)
  user_id_internal: string;         // Sase.tr internal ID (same as distinct_id genellikle)
}

Önemli kurallar:

  • Email asla ham olarak set edilmez (sadece email_domain)
  • $set_once ile setlenen property'ler signup_date, signup_method
  • $set ile her identify'da update edilenler diğerleri
  • total_vin_queries gibi aggregate'ler backend'den periyodik update (her event'te güncelleme PostHog hızını yavaşlatır)

Identify Çağrı Pattern'i

// frontend: src/lib/posthog/identify.ts
import posthog from 'posthog-js'
import { hashEmail } from '@/lib/crypto'

export function identifyUserToPostHog(user: User, company: Company | null) {
  posthog.identify(user.id, {
    // $set_once
    $set_once: {
      signup_date: user.createdAt,
      signup_method: user.signupMethod,
    },
    // $set (every call updates)
    $set: {
      email_domain: user.email.split('@')[1],
      plan_tier: user.subscription?.tier ?? 'free',
      plan_period: user.subscription?.period ?? null,
      subscription_status: user.subscription?.status ?? 'none',
      trial_ends_at: user.subscription?.trialEndsAt ?? null,
      company_id: company?.id ?? null,
      company_role: user.companyRole ?? null,
      total_vin_queries: user.stats.totalQueries,
      total_vin_queries_last_30d: user.stats.queries30d,
      preferred_provider: user.stats.preferredProvider,
      last_query_at: user.stats.lastQueryAt,
      total_logins: user.stats.totalLogins,
      days_since_signup: daysSince(user.createdAt),
      language: user.language,
      timezone: user.timezone,
      has_api_keys: user.apiKeyCount > 0,
      has_webhooks: user.webhookCount > 0,
      user_id_internal: user.id,
    },
  })
  
  // Group identification - B2B için kritik
  if (company) {
    posthog.group('company', company.id, {
      name: company.name,
      tier: company.tier,
      seat_count: company.seatCount,
      seats_used: company.seatsUsed,
      industry: company.industry ?? 'unknown',
      country: company.country ?? 'TR',
      signup_date: company.createdAt,
      mrr_usd: company.mrrUsd,
      total_queries_last_30d: company.stats.queries30d,
    })
  }
}

Identify Trigger Noktaları

Trigger Çağrı
Login başarılı identifyUserToPostHog(user, company)
User profile update identifyUserToPostHog(user, company)
Subscription change identifyUserToPostHog(user, company)
Company tier change identifyUserToPostHog(user, company)
Logout posthog.reset() ← önemli, anonymous distinct_id yenilenir
Anonymous → authenticated geçiş posthog.alias(user.id, posthog.get_distinct_id()) çağrısı ardından identify

4.2 Group Analytics (B2B Backbone)

posthog.group('company', companyId, properties) çağrısı PostHog'a "bu session bir company context'inde yapılıyor" der. Bu kurulum B2B insight kalitesini ikiye katlar.

Company Properties Schema

type PostHogCompanyGroupProperties = {
  name: string;
  tier: 'free' | 'starter' | 'brand_specific' | 'full';
  seat_count: number;
  seats_used: number;
  industry: string;
  country: 'TR' | 'DE' | 'others';
  signup_date: string;            // ISO 8601
  mrr_usd: number;                // monthly recurring revenue
  total_queries_last_30d: number;
  primary_use_case: 'parts_dealer' | 'auto_service' | 'fleet_manager' | 'unknown';
  
  // Computed nightly (admin DB job)
  active_user_count_last_7d: number;
  active_user_count_last_30d: number;
  churn_risk_score: number;       // 0-100, BIP pipeline'a değerli
}

Group Identification Trigger'ları

Her authenticated event sırasında posthog-js otomatik olarak son group'u event'e ekler. Yani bir kez posthog.group() çağrılırsa, sonraki tüm event'ler bu company context'inde gider.

Kritik nokta: Multi-tenant kullanıcılar (1 user, multiple companies) varsa company switch sırasında re-group çağrılmalı:

function switchCompany(newCompanyId: string) {
  // ... company switch logic
  posthog.group('company', newCompanyId, companyProperties)
  posthog.capture('company_switched', { 
    from_company_id: oldCompanyId,
    to_company_id: newCompanyId 
  })
}

4.3 Anonymous → Authenticated Continuity

PostHog posthog.alias() ile anonymous session'ı authenticated user'a bağlar. Bu signup funnel analizi için kritik:

async function onSignupSuccess(newUser: User) {
  const anonymousDistinctId = posthog.get_distinct_id()
  posthog.alias(newUser.id, anonymousDistinctId)
  posthog.identify(newUser.id, /* properties */)
  posthog.capture('user_signed_up', { method: 'email' })
}

Bu olmadan signup öncesi /pricing ziyareti ile signup sonrası ilk VIN sorgusu ayrı user gibi görünür, funnel kırılır.


5. Yeni Event Inventory

Event'ler üç fazda gruplandı: Blocker (Faz 0), High-ROI (Faz 1), Optimization (Faz 2).

5.1 Faz 0 — Pilot Blocker Events (ZORUNLU, 2 gün)

Bu event'ler olmadan BIP pipeline anlamlı insight üretmez.

Identification Audit + Update

Item Description
Audit Mevcut identify() çağrı noktaları belirlenir
Update Bölüm 4.1'deki property schema'ya göre identify güncellenir
Add posthog.group('company', ...) çağrısı eklenir
Add posthog.alias() signup flow'a eklenir
Add posthog.reset() logout'a eklenir (yoksa)

Parts/Compatibility Events (5 adet, en kritik)

Sase.tr'nin core value layer'ı, mevcut tek event (oem_code_copied) yetersiz.

// Kullanıcı parts panel'i ilk gördüğünde
posthog.capture('parts_panel_viewed', {
  vehicle_id: string,
  parts_count: number,
  load_time_ms: number,
  source_provider: 'PL24' | 'PCAT' | 'RMEX' | 'TecDoc' | 'multi',
})

// Filter uygulandığında
posthog.capture('parts_filter_applied', {
  filter_type: 'category' | 'brand' | 'oem_code' | 'price_range' | 'search',
  filter_value: string,        // sanitize edilmiş (uzun text varsa truncate)
  results_count_before: number,
  results_count_after: number,
})

// Compatibility check başlatıldığında
posthog.capture('compatibility_check_initiated', {
  part_id: string,
  target_vehicle_id: string,
  source_vehicle_id: string,
})

// Compatibility check tamamlandığında
posthog.capture('compatibility_check_completed', {
  part_id: string,
  target_vehicle_id: string,
  result: 'compatible' | 'incompatible' | 'unknown' | 'partial',
  confidence: number,          // 0-1
  duration_ms: number,
})

// Parts export başlatıldığında
posthog.capture('parts_export_initiated', {
  format: 'csv' | 'xlsx' | 'pdf',
  row_count: number,
  columns_selected: number,
  vehicle_id: string,
  has_filters_applied: boolean,
})

Data Privacy Audit

Item Effort Description
VIN input fields 1 saat Tüm VIN input'larına data-private="true"
Email display 1 saat User email render edilen tüm yerlere data-private
Customer data 2 saat B2B customer info render'ları
API key display 30 dk Generated API key gösterimi
posthog-js config update 1 saat maskAllInputs, maskTextSelector ayarları (BIP PRD Bölüm 15.1)

5.2 Faz 1 — High-ROI Events (Phase 6a paralelinde, 5-7 gün)

VIN Decode Performance Context (mevcut events expansion)

Bölüm 7.1'de detaylı.

Provider Events (4 adet)

Multi-provider arsenal'inin görünür olması için:

posthog.capture('provider_response_received', {
  vehicle_id: string,
  provider: 'PL24' | 'PCAT' | 'RMEX' | 'TecDoc',
  response_time_ms: number,
  status: 'success' | 'timeout' | 'error' | 'partial',
  data_completeness: number,   // 0-1, kaç beklenen field geldi
  cached: boolean,
})

posthog.capture('provider_fallback_triggered', {
  vehicle_id: string,
  from_provider: string,
  to_provider: string,
  reason: 'timeout' | 'error' | 'incomplete_data' | 'manual',
  auto: boolean,               // otomatik fallback mi manuel mi
  attempt_number: number,      // kaçıncı denemede fallback
})

posthog.capture('provider_data_quality_flag', {
  vehicle_id: string,
  provider: string,
  quality_score: number,       // 0-100
  missing_fields: string[],    // ["weight", "year_range"] gibi
  warnings: string[],
})

posthog.capture('multi_provider_search_initiated', {
  vehicle_id: string,
  providers_queried: string[],
  parallel: boolean,           // parallel mi sequential mi
})

Search Behavior Events (5 adet)

VIN submit öncesi friction'ı yakalamak için:

posthog.capture('search_input_focused', {
  field: 'vin' | 'plate' | 'brand_model',
  empty: boolean,
})

posthog.capture('search_input_validation_failed', {
  field: 'vin' | 'plate',
  error_type: 'invalid_format' | 'too_short' | 'too_long' | 'invalid_chars' | 'check_digit_fail',
  input_length: number,        // VIN'in kendisi DEĞİL, sadece uzunluk
})

posthog.capture('search_paste_detected', {
  field: string,
  length: number,
  source_hint?: 'multiline' | 'with_spaces' | 'clean',
})

posthog.capture('search_history_opened', {
  history_count: number,
})

posthog.capture('search_history_item_selected', {
  age_days: number,            // ne kadar eski bir history item
  position: number,            // listede kaçıncı
})

Feature Discovery Events (5 adet)

posthog.capture('feature_discovered', {
  feature_name: string,        // "api_keys", "webhooks", "csv_export"
  days_since_signup: number,
  discovery_source: 'menu' | 'dashboard' | 'docs' | 'tutorial' | 'modal',
})

posthog.capture('help_clicked', {
  context: string,             // route path
  topic?: string,
})

posthog.capture('docs_link_clicked', {
  destination_url: string,     // path only, not query
  context: string,             // route
})

posthog.capture('tutorial_started', {
  tutorial_id: string,
  trigger: 'auto' | 'manual',
})

posthog.capture('tutorial_step_completed', {
  tutorial_id: string,
  step_index: number,
  step_name: string,
})

posthog.capture('tutorial_abandoned', {
  tutorial_id: string,
  last_step_index: number,
  duration_ms: number,
})

API Key / Webhook Events (4 adet, integration users için kritik)

posthog.capture('api_key_created', {
  tier: string,
  scope: string[],
  expiration_days: number | null,
})

posthog.capture('api_key_revoked', {
  age_days: number,
  reason?: 'rotation' | 'compromise' | 'unused' | 'manual',
})

posthog.capture('webhook_configured', {
  event_types: string[],
  endpoint_domain: string,     // full URL değil, sadece domain
})

posthog.capture('webhook_delivery_failed', {
  webhook_id: string,
  event_type: string,
  failure_reason: 'timeout' | 'http_error' | 'ssl_error' | 'auth',
  retry_count: number,
})

5.3 Faz 2 — Optimization Events (Phase 6c sonrası, fırsatçı)

Bu event'ler pilot'tan insight'lar geldiğinde eklenir, proaktif değil reaktif. LLM "şu event olsaydı daha iyi analiz ederdim" demeye başladığında listeye eklenir.

İlk kestirim listesi:

// Feature interaction patterns
posthog.capture('keyboard_shortcut_used', { shortcut, context })
posthog.capture('bulk_action_initiated', { action, item_count })
posthog.capture('settings_changed', { setting_key, value_changed: true })

// Engagement signals
posthog.capture('page_visibility_changed', { hidden: boolean, time_on_page_ms })
posthog.capture('long_idle_detected', { idle_ms })

// Discovery & SEO
posthog.capture('shared_link_opened', { share_source: string })
posthog.capture('search_engine_referral', { engine, query? })

6. Event Schema Standardı

6.1 Naming Convention

Pattern Kullanım Örnek
<noun>_<verb_past> Action / lifecycle event plan_selected, vin_decode_initiated
<noun>_<state> State change event subscription_paused, trial_active
<noun>_<process>_<lifecycle> Multi-step process payment_initiated, payment_completed, payment_failed
<noun>_<ui_action> Passive UI interaction banner_viewed, modal_dismissed, cta_clicked

Lifecycle Verb Standardı

Process event'leri için tutarlı lifecycle verbleri:

Lifecycle Anlamı
_initiated İşlem başlatıldı, henüz tamamlanmadı
_started _initiated ile aynı; tercih: _initiated (network/API context'inde) veya _started (user time context'inde)
_succeeded Backend confirmation ile başarılı
_completed Multi-step process'in son adımı (success ima eder)
_failed Hata ile sonlandı
_cancelled Kullanıcı tarafından iptal edildi
_abandoned Kullanıcı sessizce ayrıldı (active cancel değil)
_dismissed UI element manuel kapatıldı

6.2 Property Naming

snake_case kullan (PostHog convention)
boolean property'ler `is_`, `has_`, `was_` prefix'i ile başlamaz; doğal okunur
zamanları ISO 8601 string olarak gönder (`_at` suffix'i)
süreleri `_ms` veya `_seconds` suffix'i ile gönder
count'lar `_count` suffix'i
liste property'leri çoğul (`providers_queried`)

6.3 Required vs Optional Properties

Her event en az şu implicit property'lerle gelir (PostHog otomatik ekler):

  • $lib (posthog-js vs posthog-node)
  • $browser, $os, $device_type
  • $current_url, $pathname
  • distinct_id, $session_id
  • timestamp

Bizim event-specific property'lerimiz:

  • Required property'ler her event'te zorunlu, eksikse capture silinmez (gönderilmemiş gibi davran)
  • Optional property'ler bilinmiyorsa omit edilir (null göndermek yerine)

6.4 PII / Sensitive Data Rules

Veri İzin Saklama Şekli
VIN Property olabilir Property'de full VIN; rrweb recording'de masked
Email Full email yok email_domain property'si veya hash
Telefon Full yok Sadece operator code 5XX
TC Kimlik Asla Hiçbir event'te kullanılmaz
Plaka ⚠️ Conditional Property'de masked (34***123)
Auth token / API key Asla Hiçbir event'te kullanılmaz
Kredi kartı Asla Hiçbir event'te kullanılmaz
Password Asla Hiçbir event'te kullanılmaz
IP address PostHog otomatik Geo'ya çevrilir, raw IP saklanmaz
User Agent PostHog otomatik
URL Path Query string KVKK risk taşırsa filtrele
Query string ⚠️ Conditional ?vin=XXX gibi PII içerebilir, filtrele

Önemli: PostHog SDK config'inde property_denylist ile bazı property'ler otomatik silinir:

posthog.init(KEY, {
  property_denylist: ['$ip', 'email', 'phone', 'tc_kimlik', 'password', 'token'],
})

VIN property olarak event'te kalabilir çünkü ürünün core'u, ama rrweb recording'inde mask edilir.

6.5 Property Value Length Limits

PostHog property limit'i 8KB. Pratikte:

  • String property < 500 karakter (long text varsa truncate + _truncated: true flag)
  • Array property < 50 element
  • Nested object property mümkün ama düz tutmak tercih edilir (PostHog filter UX için)

6.6 Versioning

Event schema breaking change yapılırsa rename edilir, asla aynı isimle property değiştirmez:

v1: payment_succeeded { amount, currency }
v2: payment_succeeded_v2 { amount_cents, currency, provider }

1 ay paralel kalır, sonra v1 deprecated. PostHog'da v1 event'leri kapanır (kayıt edilmez), dashboard v2'ye migrate edilir.


7. Mevcut Event İyileştirmeleri

7.1 vin_decode_* Family Expansion

Mevcut Yeni
vin_decoded { vin } vin_decode_initiated { vin, vin_brand?, query_source: 'manual' | 'history' | 'paste' | 'qr', has_provider_preference: boolean }
vin_decode_success { vin, vehicle_id, source? } vin_decode_succeeded { vin, vehicle_id, provider, response_time_ms, cache_hit: boolean, ml_decoder_used: boolean, ml_confidence?: number, retry_count: number, partial_result: boolean, fallback_used: boolean }
vin_decode_error { vin, error, source? } vin_decode_failed { vin, error_code, error_message, provider_attempted, response_time_ms, retry_count, will_auto_retry: boolean }
vin_decode_candidates (no props) vin_decode_candidates_shown { vin, candidates_count, top_confidence: number }
vin_decode_candidate_selected (no props) vin_decode_candidate_selected { vin, selected_index: number, selected_confidence: number, time_to_select_ms: number }

Migration: Bölüm 11'deki rename stratejisi (paralel kalma → deprecate).

7.2 Subscription Funnel Granularity

Mevcut Yeni
plan_selected { plan } plan_selected { plan, period, price_usd, position_in_grid: number, source: 'pricing_page' | 'modal' | 'upgrade_prompt' }
checkout_started { plan, period } checkout_started { plan, period, coming_from, plan_comparison_viewed: boolean, time_on_pricing_page_seconds: number, trial_available: boolean }
trial_started trial_started { plan_offered, source: 'signup' | 'pricing_page' | 'modal', trial_days_granted: number }
subscription_cancelled subscription_cancelled { plan, cancellation_reason: 'too_expensive' | 'not_using_enough' | 'missing_feature' | 'found_alternative' | 'temporary' | 'other', cancellation_reason_text?: string, days_since_signup: number, total_vin_queries_lifetime: number, refund_requested: boolean }
subscription_resumed subscription_resumed { plan, days_away: number, came_back_from_offer: boolean }
downgrade_offer_shown downgrade_offer_shown { from_plan, to_plan, discount_pct: number, offer_type: 'discount' | 'plan_downgrade' | 'pause' }
downgrade_offer_accepted/declined Aynı detail seti
cancel_save_clicked cancel_save_offer_accepted { offer_type, savings_usd }

7.3 Trial Urgency Banner

Mevcut Yeni
trial_urgency_banner_viewed trial_urgency_banner_viewed { days_until_trial_end: number, banner_variant: string, plan: string }
trial_urgency_banner_cta_clicked trial_urgency_banner_cta_clicked { days_until_trial_end: number, cta_destination: string }
trial_urgency_banner_dismissed trial_urgency_banner_dismissed { days_until_trial_end: number, dismiss_method: 'x_button' | 'esc' | 'overlay_click' }

7.4 Payment Dual-Capture Strategy

Karar: Frontend + backend dual capture korunur, ama event isimleri ayrıştırılır.

Mevcut Yeni
payment_success (frontend) payment_success_ui (frontend confirmation görüntülendi)
payment_success (backend) payment_succeeded (server source of truth)
payment_failed (frontend) payment_failed_ui (kullanıcıya gösterilen hata)
payment_failed (backend) payment_failed { failure_code, failure_reason, gateway_response, amount, plan }

Pipeline kullanımı:

  • payment_succeeded (backend) conversion truth
  • payment_success_ui olmadan payment_succeeded varsa → UI bug sinyali (kullanıcı confirmation görmemiş)
  • payment_failed reason'ları cancellation_reason gibi pattern detection için zengin

7.5 Schema/Parts Layer

Mevcut Yeni (Faz 0'da eklenenler — Bölüm 5.1)
oem_code_copied { oem_code, part_id } Aynı + parts_panel_viewed, parts_filter_applied, compatibility_check_*, parts_export_initiated

7.6 Social Proof Attribution

Mevcut Yeni
social_proof_impression { page, section? } + variant_id?: string (A/B test ready)
social_proof_engaged { page, section? } Aynı
(yeni) social_proof_followed_by_action { impression_id?: string, action: 'signup' | 'plan_selected' | 'checkout_started', time_to_action_seconds: number }

Bu üçüncü event social proof'un gerçek attribution'ını ölçer.

7.7 User Lifecycle

Mevcut Yeni
user_signed_up { method } user_signed_up { method, referrer?: string, utm_source?: string, utm_campaign?: string, came_from_pricing: boolean }
user_logged_in { method } user_logged_in { method, was_remember_me: boolean, days_since_last_login: number }
user_logged_out { reason? } Aynı

8. Data Privacy ve KVKK Uyumu

8.1 data-private Attribute Audit

PostHog SDK config'inde maskTextSelector: '[data-private]' ayarlandığında rrweb recording bu element'leri mask'ler. Tüm sensitive content render'ları işaretlenmeli.

Audit Checklist (Faz 0'da yapılacak)

Component / Sayfa Sensitive Content Action
search.tsx VIN input VIN string data-private attribute
index.tsx landing VIN demo Demo VIN (gerçek değil) Skip
parts-panel.tsx Müşteri spec'i, fiyat (eğer var) data-private
settings-content.tsx User email, phone data-private
dashboard.tsx user header User email render data-private
payment-content.tsx Card form, amount? Card → data-private, amount OK
API keys view Generated key string data-private="strict" (asla rec yapılmasın)
Webhook secret view Webhook secret data-private="strict"
_auth/register.tsx, _auth/login.tsx Password input PostHog SDK maskInputOptions.password: true zaten korur, ama yine data-private

8.2 PostHog SDK Configuration

apps/web/src/lib/posthog/init.ts (veya equivalent) güncellenir:

import posthog from 'posthog-js'

export function initPostHog() {
  posthog.init(import.meta.env.VITE_POSTHOG_KEY, {
    api_host: 'https://eu.i.posthog.com',  // EU region zorunlu (KVKK)
    
    // Session recording config
    session_recording: {
      maskAllInputs: true,
      maskInputOptions: {
        password: true,
        email: false,                       // email property zaten denylist'te
        tel: true,
        number: false,
      },
      maskTextSelector: '[data-private], .sensitive',
      blockSelector: '[data-private="strict"], [data-block]',
      blockClass: 'rrweb-block',
      ignoreClass: 'rrweb-ignore',
      recordCrossOriginIframes: false,
      recordNetworkPayloads: false,         // payload yok, sadece metadata
      recordHeaders: false,                 // auth header asla
      recordBody: false,                    // request body asla
    },
    
    // PII denylist
    property_denylist: [
      '$ip',                                // PostHog handle'lar geo'ya
      'email', 'phone', 'tc_kimlik',
      'password', 'token', 'api_key',
      'credit_card', 'cvv',
    ],
    
    // Defaults
    capture_pageview: true,
    capture_pageleave: true,
    autocapture: {
      capture_copied_text: false,           // VIN copy event ayrı capture'da
    },
    
    persistence: 'localStorage',
    cross_subdomain_cookie: true,
    secure_cookie: true,
    
    // Performance
    request_batching: true,
    
    // KVKK
    opt_out_capturing_by_default: false,    // consent flow Sase.tr login öncesi
  })
}

8.3 Backend SDK (posthog-node) Configuration

// apps/api/src/lib/posthog.ts
import { PostHog } from 'posthog-node'

export const posthogServer = new PostHog(
  process.env.POSTHOG_KEY!,
  {
    host: 'https://eu.i.posthog.com',
    flushAt: 20,                            // 20 event'te bir flush
    flushInterval: 10000,                   // 10 saniyede bir flush
  }
)

// Wrapper: PII filtering at the source
export function captureFromBackend(params: {
  distinctId: string,
  event: string,
  properties: Record<string, any>,
  groups?: Record<string, string>,
}) {
  const sanitized = sanitizeProperties(params.properties)
  posthogServer.capture({
    distinctId: params.distinctId,
    event: params.event,
    properties: { ...sanitized, $lib: 'posthog-node' },
    groups: params.groups,
  })
}

function sanitizeProperties(props: Record<string, any>): Record<string, any> {
  const denylist = ['email', 'phone', 'password', 'token', 'api_key', 'credit_card']
  return Object.fromEntries(
    Object.entries(props).filter(([k]) => !denylist.includes(k))
  )
}

8.4 KVKK Aydınlatma Metni Güncelleme

Sase.tr KVKK aydınlatma metnine eklenecek madde (Bölüm 6.x):

Ürün Analitiği ve Davranış Analizi

Sase.tr kullanım deneyiminizi iyileştirmek için PostHog (PostHog Inc., Hollanda) tarafından sağlanan ürün analitiği hizmetini kullanır. Bu hizmet kapsamında:

  • Hangi sayfaları ziyaret ettiğiniz, hangi özellikleri kullandığınız
  • VIN sorgu, parça arama gibi platforma özgü etkileşimleriniz
  • Cihaz ve tarayıcı bilgileriniz
  • Anonimleştirilmiş davranış kayıtları (session recording)

verileri işlenir. Bu veriler AB Birliği'nde (Frankfurt) saklanır.

İşlenen verilerden anonimleştirilmiş özetler, ürün geliştirme amacıyla yapay zeka destekli analiz için DeepSeek (DeepSeek Inc., Çin Halk Cumhuriyeti) üzerinden işlenebilir. Bu işlemden önce kişisel veri içeriği maskelenir.

Bu işleme faaliyetinin yasal dayanağı KVKK Madde 5/2-f kapsamında meşru menfaattir.

Hukuk danışmanı ile kontrol edilmeli.

Şu an default opt_out_capturing_by_default: false. Eğer Sase.tr EU müşterileri (GDPR) çekmek istiyorsa cookie banner consent flow eklenmeli:

// Kullanıcı consent verince
posthog.opt_in_capturing()

// Reddederse
posthog.opt_out_capturing()

Bu pilot scope'unda değil, Türkiye merkezli kullanıcı varsayımı.


9. Implementation Plan

Faz 0 — Pilot Blocker (2 gün, mecburi)

Gün 1: Identification + Privacy

Sabah (4 saat)

  • Mevcut posthog.identify() çağrıları audit edilir
  • User properties schema implement edilir (Bölüm 4.1)
  • posthog.group('company') çağrısı eklenir
  • posthog.alias() signup flow'a eklenir
  • posthog.reset() logout'a eklenir

Öğlen (4 saat)

  • data-private audit (Bölüm 8.1 checklist)
  • PostHog SDK config update (Bölüm 8.2 + 8.3)
  • EU region confirmation (https://eu.i.posthog.com)
  • Local test: identify + group + recording mask

Gün 2: Parts Layer Events

Sabah (4 saat)

  • parts_panel_viewed event implementation
  • parts_filter_applied event implementation
  • compatibility_check_initiated + compatibility_check_completed

Öğlen (4 saat)

  • parts_export_initiated event
  • Existing oem_code_copied property zenginleştirme
  • Documentation: docs/posthog-events.md ilk versiyonu
  • PR review + merge

Çıkış kriteri: Faz 0 PR merge edildiğinde:

  • Tüm authenticated session'lar posthog.identify() ve posthog.group() çağırıyor
  • Parts layer'ı görünür
  • rrweb recording'lerde VIN/email mask'lenmiş
  • KVKK aydınlatma metni güncel

Faz 1 — High-ROI Events (5-7 gün, BIP Phase 6a paralelinde)

Gün Konu
1 VIN decode performance expansion (Bölüm 7.1)
2 Provider events (4 adet, Bölüm 5.2)
3 Search behavior events (5 adet, Bölüm 5.2)
4 Feature discovery events (5 adet, Bölüm 5.2)
5 API key/webhook events + Subscription funnel granularity (Bölüm 7.2)
6 Payment dual-capture rename (Bölüm 7.4) + Trial banner expansion
7 QA, documentation update, deploy

Strateji: Tek bir feature branch (feature/posthog-event-expansion-phase1), günlük commit'ler, sonunda tek büyük PR. Production'a deploy edilir, 1 hafta baseline ölçülür, sonra BIP pipeline Faz 6b'ye geçilir.

Faz 2 — Optimization (Phase 6c sonrası, ad-hoc)

BIP'ten gelen meta-insight'lara göre event ekleme. Plan değil pattern.

Effort Özeti

Faz Süre Effort Çıktı
Faz 0 2 gün Solo founder full-time Pilot blocker'lar
Faz 1 5-7 gün Solo founder full-time 30+ yeni event, mevcut iyileştirme
Faz 2 Sürekli 1-2 saat/event Insight-driven additions
Toplam (Faz 0+1) ~2 hafta Pilot için event hazır

10. Testing Strategy

10.1 Local Development

// posthog dev environment
if (import.meta.env.DEV) {
  posthog.init(import.meta.env.VITE_POSTHOG_KEY_DEV, {
    api_host: 'https://eu.i.posthog.com',
    debug: true,                  // console'da event log
    disable_session_recording: true,  // dev'de recording yok
  })
}

Browser console'da event flow gözle takip edilir.

10.2 Event Payload Validation

Type-safe wrapper ile yanlış property kullanımı compile-time'da yakalanır:

// src/lib/posthog/events.ts
import posthog from 'posthog-js'

type PostHogEvent = 
  | { name: 'vin_decode_initiated'; props: VinDecodeInitiatedProps }
  | { name: 'vin_decode_succeeded'; props: VinDecodeSucceededProps }
  | { name: 'parts_panel_viewed'; props: PartsPanelViewedProps }
  // ... 50+ event type

export function capture<E extends PostHogEvent>(event: E) {
  posthog.capture(event.name, event.props)
}

// Kullanım: compile-time safety
capture({ 
  name: 'vin_decode_initiated', 
  props: { vin: '...', query_source: 'manual' }  // missing prop → TS error
})

10.3 Production Validation

PR merge sonrası 24 saat içinde:

  • PostHog dashboard'unda her yeni event tipi en az 1 kez görünüyor
  • Event property'leri schema'ya uyuyor
  • No errors in browser console (PostHog SDK errors)
  • rrweb recordings'te masked content masked
  • User properties identify sonrası set ediliyor (PostHog person page'de görünüyor)

10.4 Regression Test (Mevcut Funnel'ları Bozmama)

Faz 1'de mevcut event'leri rename ederken (vin_decoded → vin_decode_initiated gibi):

  1. Eski event 1 ay daha capture edilir (parallel)
  2. PostHog'da mevcut funnel/dashboard duplicate edilir (v2 versiyonları)
  3. v2'ler yeni event isimleriyle kurulur
  4. 1 ay sonra v1 capture durur, v1 dashboard'lar arşivlenir

Bu adımlar Bölüm 11'de detaylı.


11. Migration ve Backward Compatibility

11.1 Rename Stratejisi

Event rename gerektiren durumlar:

  • vin_decodedvin_decode_initiated
  • vin_decode_successvin_decode_succeeded
  • vin_decode_errorvin_decode_failed
  • payment_success (FE) → payment_success_ui
  • payment_success (BE) → payment_succeeded
  • payment_failed (BE) → daha detaylı properties

Migration Steps

Adım 1: Dual-emit phase (1 ay)

// Both old and new emitted
posthog.capture('vin_decoded', { vin })  // legacy
posthog.capture('vin_decode_initiated', { 
  vin, vin_brand, query_source: 'manual', has_provider_preference: false 
})  // new

Adım 2: PostHog dashboard migration (1-3 gün, 1 ay sürecin başında)

  • Mevcut dashboard'ları duplicate et, "_v2" ekle
  • v2'leri yeni event isimleri ile re-create et
  • 1 hafta paralel izle, data tutuyor mu kontrol et
  • Eski dashboard'lar [DEPRECATED] ile prefix'lenir

Adım 3: Funnel migration

  • Mevcut funnels duplicate et
  • v2 funnels yeni event isimleriyle kurulur
  • Alert'leri v2'ye taşı

Adım 4: Legacy capture kapanır (1 ay sonra)

// Sadece new event
posthog.capture('vin_decode_initiated', { ... })

Eski dashboard'lar arşivlenir (silinmez, history için).

11.2 Payment Event Migration (Özel Durum)

Payment event'leri production critical (finansal alert'ler buna bağlı olabilir). Daha dikkatli:

Adım 1: Backend'de payment_succeeded yeni event olarak başlatılır. payment_success capture'ı korunur.

Adım 2: PostHog'da yeni alert kurulur (payment_succeeded failure rate).

Adım 3: 2 hafta paralel izle. Eski ve yeni event count'u %95+ matching olmalı.

Adım 4: Eski payment_success (backend) deprecate edilir, sadece frontend payment_success_ui kalır.

11.3 Property Addition Backward Compat

Yeni property eklemek backward compatible:

  • Eski filter'lar yeni property'siz çalışmaya devam eder
  • Yeni filter'lar property eksik event'leri sayar veya saymaz (filter behavior)

Bu adım için migration gerekmez, sadece event implementation.

11.4 Mevcut Dashboard / Funnel İnvanteri

Migration başlamadan önce mevcut PostHog asset'leri envanterlenmeli:

Asset Type Identify Action
Funnels List all v2 duplicate plan
Insights / Trends List all using affected events v2 duplicate plan
Dashboards List all Component update plan
Alerts List all Recreate on v2
Cohorts List all using affected events Verify still valid

Bu envanter Faz 1 başlamadan önce 1 saatlik audit ile çıkarılır.


12. PostHog Dashboard Setup

Yeni event'lerin maximum değer üretmesi için PostHog UI'da kurulacak dashboard ve funnel'lar:

12.1 Critical Funnels

Activation Funnel

user_signed_up
  → user_logged_in (within 1 day)
  → vin_decode_initiated
  → vin_decode_succeeded
  → parts_panel_viewed
  → oem_code_copied OR parts_export_initiated

Conversion Funnel

$pageview (/pricing)
  → plan_selected
  → checkout_started
  → payment_initiated
  → payment_succeeded

Trial → Paid Funnel

trial_started
  → vin_decode_succeeded (during trial)
  → trial_urgency_banner_cta_clicked
  → checkout_started
  → payment_succeeded

Retention Funnel (Weekly)

Week 1: user_signed_up
Week 2: vin_decode_succeeded
Week 3: vin_decode_succeeded
Week 4: vin_decode_succeeded

12.2 Critical Cohorts

Cohort Definition Use
power_users Last 30d: >100 vin_decode_succeeded BIP segment context
at_risk Last 14d: 0 vin_decode_initiated AND plan_tier != 'free' Churn prevention
new_users_week1 signup_date within last 7 days Onboarding analysis
provider_heavy_pl24 Last 30d: >70% provider = 'PL24' Provider reliability impact
multi_brand_users distinct vin_brand count >= 3 in last 30d Feature usage analysis
api_integrators api_key_created event exists Power users, different needs
failed_payment_recovery payment_failed exists, but no payment_succeeded within 7d Recovery target
Insight Description
Daily VIN queries by provider Provider load distribution
VIN decode success rate by provider Quality metric
Average response time by provider Performance metric
Onboarding completion rate (weekly) Activation health
Trial → paid conversion (monthly) Revenue health
Feature discovery rate by feature Discoverability gap
Compatibility check accuracy distribution Product quality

12.4 Alerts

Alert Trigger Notification
Payment success rate drops < 90% in last hour Telegram immediate
VIN decode failure spike > 3x baseline in 15 min Telegram
Provider PL24 timeout > 20% Continuous 30 min Email
Daily active users drop < 80% of 7-day avg Daily digest
New signup → first VIN query < 50% in 24h Weekly review

Bu alert'ler PostHog'un kendi alert sisteminden, BIP pipeline'a webhook olarak da gönderilebilir (BIP PRD Bölüm "Pattern-Level Otomatik Insight Tetikleme").


13. Documentation Standardı

13.1 Single Source of Truth

docs/posthog-events.md — tüm event taxonomy'sinin tek kaynağı:

# Sase.tr PostHog Event Taxonomy

> Last updated: [date]
> Version: 2.0

## Conventions

[Bölüm 6'dan kopyala]

## Event Catalog

### Auth & Lifecycle

#### user_signed_up
- **Description:** User completed signup
- **Trigger:** After successful account creation
- **Source:** `apps/web/src/routes/_auth/register.tsx`
- **Properties:**
  - `method` (required): "email" | "google"
  - `referrer` (optional): string
  - `utm_source` (optional): string
  - `utm_campaign` (optional): string
  - `came_from_pricing` (required): boolean
- **Example:**
  ```ts
  capture({ name: 'user_signed_up', props: { method: 'email', came_from_pricing: true } })

user_logged_in

... [her event için aynı format]


### 13.2 Inline Code Documentation

Her capture noktasııklayıcı yorumla:

```typescript
/**
 * VIN decode başlatıldığında çağrılır.
 * Pipeline kullanımı: vin_decode_initiated → vin_decode_succeeded/failed funnel.
 * 
 * @see docs/posthog-events.md#vin_decode_initiated
 */
capture({
  name: 'vin_decode_initiated',
  props: { vin, query_source: 'manual', has_provider_preference: false }
})

13.3 Schema Versioning

docs/posthog-events.md header'ında version. Breaking change'lerde version bump:

  • v1.x: Mevcut taxonomy
  • v2.0: Faz 1 sonrası

13.4 Onboarding Yeni Developer

Yeni dev (gelecekte) için checklist:

  • docs/posthog-events.md oku
  • Type-safe wrapper kullan (src/lib/posthog/events.ts)
  • Yeni event ekleyince:
    • Type tanımı events.ts'e ekle
    • docs/posthog-events.md güncelle
    • PR description'da event listele

14. Riskler

Risk Olasılık Etki Azaltma
Mevcut funnel/dashboard'lar rename ile kırılır Yüksek Orta Dual-emit phase + v2 dashboard parallel; Bölüm 11
Property denylist eksik kalır, PII PostHog'a gider Orta Yüksek Bölüm 6.4 + 8.2 review; Faz 0'da audit
Identify çağrısı login dışı yerde unutulur Orta Orta Type-safe wrapper + lint rule
Group analytics company switch'te update edilmez Yüksek Orta Multi-tenant flow test; Bölüm 4.2
Yeni event'ler PostHog cost'unu artırır Düşük Düşük Free tier 1M event/ay yeterli pilot için
Payment dual-capture geçişinde alert'ler kaybolur Orta Yüksek Alert recreate Bölüm 12.4 + audit
rrweb mask config bozulur, VIN recording'lerde görünür Düşük Yüksek Faz 0 test + production smoke test
Backend event'leri server crash'te kaybolur Düşük Düşük posthog-node flush on shutdown; SIGTERM handler
Type-safe wrapper adoption düşük olur Orta Düşük Lint rule: direct posthog.capture() block edilir
Faz 1 implementation 7 günde tamamlanmaz Orta Orta Her event independent ship edilebilir; BIP Phase 6a paralel

15. Karar Logu

Tarih Karar Gerekçe
2026-05-13 PostHog Cloud EU region kullanılacak KVKK uyumu; AWS Frankfurt veri konumu
2026-05-13 Group analytics (posthog.group('company')) zorunlu B2B insight kalitesi için belkemiği
2026-05-13 Email asla full olarak property gönderilmez, sadece domain KVKK + property denylist enforcement
2026-05-13 VIN property'de full kalır, rrweb recording'de masked Ürün analitiği için gerekli; PII risk recording'de değil property'de düşük
2026-05-13 Frontend + backend payment dual-capture korunur, rename edilir Reliability + UI bug detection sinyali
2026-05-13 Event naming: <noun>_<verb_past> convention Tutarlı arama, PostHog UI ergonomics
2026-05-13 Property naming: snake_case PostHog convention
2026-05-13 Type-safe wrapper zorunlu (src/lib/posthog/events.ts) Yanlış event/property compile-time yakalama
2026-05-13 docs/posthog-events.md single source of truth Drift önleme
2026-05-13 Faz 0 (2 gün) BIP Phase 6a önkoşul Pilot insight kalitesi için zorunlu
2026-05-13 Faz 1 (5-7 gün) BIP Phase 6a paralel Time-to-pilot kısalır
2026-05-13 Faz 2 ad-hoc, insight-driven Premature optimization önleme
2026-05-13 Rename'ler 1 ay dual-emit phase ile yapılır Production funnel'ları bozmamak

Doküman Sonu