- CatalogModule: VIN-less PL24 catalog browser (brands, models, categories, parts) - Supports P5 Modern (REST) and P4 Legacy (Ford, PSA) catalog architectures - Ford variant selector (model-year/engine/gearbox), PSA variant selector (body/engine/gearbox) - New API endpoints: ford-config, psa-bodies, psa-engines, psa-gearboxes, brands/:name/catalogs - Shared vehicles: vehicles table decoupled from users via userVehicles junction table - PL24 Ford Legacy service: comprehensive HTML-scraping for Ford/PSA/Hyundai/Kia/Nissan/Opel/Volvo - PL24 types and service updated for P4 Legacy brand support - Categories/parts service updated for dual FK (vehicleId + catalogVehicleId) pattern - Catalog browser frontend routes and components - docs/INDEX.md: updated with all new endpoints, components, hooks, routes (2026-03-02) - docs/pl24-catalog/: per-brand catalog exploration docs - scripts/migration-shared-vehicles.sql, pl24-catalog-explorer.js, posthog-dashboards.sh Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
281 lines
8.3 KiB
Bash
Executable File
281 lines
8.3 KiB
Bash
Executable File
#!/usr/bin/env bash
|
||
set -euo pipefail
|
||
|
||
API_KEY="${POSTHOG_API_KEY:?Set POSTHOG_API_KEY env var}"
|
||
BASE="https://eu.posthog.com/api/projects/127747"
|
||
HEADERS=(-H "Authorization: Bearer $API_KEY" -H "Content-Type: application/json")
|
||
|
||
create_insight() {
|
||
local payload="$1"
|
||
local response
|
||
response=$(curl -s -X POST "$BASE/insights/" "${HEADERS[@]}" -d "$payload")
|
||
local id
|
||
id=$(echo "$response" | jq -r '.id')
|
||
if [[ "$id" == "null" || -z "$id" ]]; then
|
||
echo "ERROR creating insight: $response" >&2
|
||
exit 1
|
||
fi
|
||
echo "$id"
|
||
}
|
||
|
||
add_to_dashboard() {
|
||
local insight_id="$1"
|
||
local dashboard_id="$2"
|
||
curl -s -X PATCH "$BASE/insights/$insight_id/" "${HEADERS[@]}" \
|
||
-d "{\"dashboards\":[$dashboard_id]}" | jq -r '.id' > /dev/null
|
||
}
|
||
|
||
create_dashboard() {
|
||
local name="$1"
|
||
local response
|
||
response=$(curl -s -X POST "$BASE/dashboards/" "${HEADERS[@]}" \
|
||
-d "{\"name\":\"$name\"}")
|
||
local id
|
||
id=$(echo "$response" | jq -r '.id')
|
||
if [[ "$id" == "null" || -z "$id" ]]; then
|
||
echo "ERROR creating dashboard: $response" >&2
|
||
exit 1
|
||
fi
|
||
echo "$id"
|
||
}
|
||
|
||
echo "=== PostHog Dashboard Oluşturucu ==="
|
||
echo ""
|
||
|
||
# ─── Insight'lar ─────────────────────────────────────────────────────
|
||
|
||
echo "--- Insight'lar oluşturuluyor ---"
|
||
|
||
I1=$(create_insight '{
|
||
"name": "Günlük Aktif Kullanıcılar",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "TrendsQuery",
|
||
"series": [{"kind":"EventsNode","event":"$pageview","math":"dau","name":"DAU"}],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"interval": "day"
|
||
}
|
||
}
|
||
}')
|
||
echo " [1/11] Günlük Aktif Kullanıcılar → $I1"
|
||
|
||
I2=$(create_insight '{
|
||
"name": "Kayıt Trendi",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "TrendsQuery",
|
||
"series": [{"kind":"EventsNode","event":"user_signed_up","math":"total","name":"Kayıt"}],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"interval": "day"
|
||
}
|
||
}
|
||
}')
|
||
echo " [2/11] Kayıt Trendi → $I2"
|
||
|
||
I3=$(create_insight '{
|
||
"name": "Giriş / Çıkış",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "TrendsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"user_logged_in","math":"total","name":"Giriş"},
|
||
{"kind":"EventsNode","event":"user_logged_out","math":"total","name":"Çıkış"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"interval": "day"
|
||
}
|
||
}
|
||
}')
|
||
echo " [3/11] Giriş / Çıkış → $I3"
|
||
|
||
I4=$(create_insight '{
|
||
"name": "VIN Arama Hacmi",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "TrendsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"vin_decoded","math":"total","name":"Arama"},
|
||
{"kind":"EventsNode","event":"vin_decode_success","math":"total","name":"Başarılı"},
|
||
{"kind":"EventsNode","event":"vin_decode_error","math":"total","name":"Hata"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"interval": "day"
|
||
}
|
||
}
|
||
}')
|
||
echo " [4/11] VIN Arama Hacmi → $I4"
|
||
|
||
I5=$(create_insight '{
|
||
"name": "Onboarding Funnel",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "FunnelsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"user_signed_up","name":"Kayıt"},
|
||
{"kind":"EventsNode","event":"trial_started","name":"Trial"},
|
||
{"kind":"EventsNode","event":"vin_decoded","name":"VIN Arama"},
|
||
{"kind":"EventsNode","event":"vin_decode_success","name":"Başarılı Sonuç"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"funnelsFilter": {"funnelWindowInterval": 14, "funnelWindowIntervalUnit": "day"}
|
||
}
|
||
}
|
||
}')
|
||
echo " [5/11] Onboarding Funnel → $I5"
|
||
|
||
I6=$(create_insight '{
|
||
"name": "Monetization Funnel",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "FunnelsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"vin_decoded","name":"VIN Arama"},
|
||
{"kind":"EventsNode","event":"plan_selected","name":"Plan Seçimi"},
|
||
{"kind":"EventsNode","event":"checkout_started","name":"Checkout"},
|
||
{"kind":"EventsNode","event":"payment_initiated","name":"Ödeme"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"funnelsFilter": {"funnelWindowInterval": 14, "funnelWindowIntervalUnit": "day"}
|
||
}
|
||
}
|
||
}')
|
||
echo " [6/11] Monetization Funnel → $I6"
|
||
|
||
I7=$(create_insight '{
|
||
"name": "Core Value Funnel",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "FunnelsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"user_logged_in","name":"Giriş"},
|
||
{"kind":"EventsNode","event":"vin_decoded","name":"VIN Arama"},
|
||
{"kind":"EventsNode","event":"vin_decode_success","name":"Başarılı Sonuç"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"funnelsFilter": {"funnelWindowInterval": 7, "funnelWindowIntervalUnit": "day"}
|
||
}
|
||
}
|
||
}')
|
||
echo " [7/11] Core Value Funnel → $I7"
|
||
|
||
I8=$(create_insight '{
|
||
"name": "Ödeme Trendi",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "TrendsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"payment_initiated","math":"total","name":"Ödeme Başlatıldı"},
|
||
{"kind":"EventsNode","event":"receipt_uploaded","math":"total","name":"Dekont Yüklendi"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"interval": "day"
|
||
}
|
||
}
|
||
}')
|
||
echo " [8/11] Ödeme Trendi → $I8"
|
||
|
||
I9=$(create_insight '{
|
||
"name": "Trial Başlatma Trendi",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "TrendsQuery",
|
||
"series": [{"kind":"EventsNode","event":"trial_started","math":"total","name":"Trial"}],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"interval": "day"
|
||
}
|
||
}
|
||
}')
|
||
echo " [9/11] Trial Başlatma Trendi → $I9"
|
||
|
||
I10=$(create_insight '{
|
||
"name": "İptal / Devam",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "TrendsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"subscription_cancelled","math":"total","name":"İptal"},
|
||
{"kind":"EventsNode","event":"subscription_resumed","math":"total","name":"Devam"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"interval": "day"
|
||
}
|
||
}
|
||
}')
|
||
echo " [10/11] İptal / Devam → $I10"
|
||
|
||
I11=$(create_insight '{
|
||
"name": "Ödeme Funnel",
|
||
"query": {
|
||
"kind": "InsightVizNode",
|
||
"source": {
|
||
"kind": "FunnelsQuery",
|
||
"series": [
|
||
{"kind":"EventsNode","event":"plan_selected","name":"Plan Seçimi"},
|
||
{"kind":"EventsNode","event":"checkout_started","name":"Checkout"},
|
||
{"kind":"EventsNode","event":"payment_initiated","name":"Ödeme"},
|
||
{"kind":"EventsNode","event":"receipt_uploaded","name":"Dekont"}
|
||
],
|
||
"dateRange": {"date_from": "-30d"},
|
||
"funnelsFilter": {"funnelWindowInterval": 7, "funnelWindowIntervalUnit": "day"}
|
||
}
|
||
}
|
||
}')
|
||
echo " [11/11] Ödeme Funnel → $I11"
|
||
|
||
# ─── Dashboard'lar ───────────────────────────────────────────────────
|
||
|
||
echo ""
|
||
echo "--- Dashboard'lar oluşturuluyor ---"
|
||
|
||
D1=$(create_dashboard "SASE — Genel Bakış")
|
||
echo " Dashboard 1: SASE — Genel Bakış → $D1"
|
||
|
||
D2=$(create_dashboard "SASE — Funnel'lar")
|
||
echo " Dashboard 2: SASE — Funnel'lar → $D2"
|
||
|
||
D3=$(create_dashboard "SASE — Abonelik")
|
||
echo " Dashboard 3: SASE — Abonelik → $D3"
|
||
|
||
# ─── Insight → Dashboard bağlantıları ────────────────────────────────
|
||
|
||
echo ""
|
||
echo "--- Insight'lar dashboard'lara bağlanıyor ---"
|
||
|
||
# Dashboard 1: Genel Bakış
|
||
for id in "$I1" "$I2" "$I3" "$I4"; do
|
||
add_to_dashboard "$id" "$D1"
|
||
done
|
||
echo " Genel Bakış: 4 insight bağlandı"
|
||
|
||
# Dashboard 2: Funnel'lar
|
||
for id in "$I5" "$I6" "$I7" "$I8"; do
|
||
add_to_dashboard "$id" "$D2"
|
||
done
|
||
echo " Funnel'lar: 4 insight bağlandı"
|
||
|
||
# Dashboard 3: Abonelik
|
||
for id in "$I9" "$I10" "$I11"; do
|
||
add_to_dashboard "$id" "$D3"
|
||
done
|
||
echo " Abonelik: 3 insight bağlandı"
|
||
|
||
echo ""
|
||
echo "=== Tamamlandı ==="
|
||
echo ""
|
||
echo "Dashboard URL'leri:"
|
||
echo " https://eu.posthog.com/project/127747/dashboard/$D1 (Genel Bakış)"
|
||
echo " https://eu.posthog.com/project/127747/dashboard/$D2 (Funnel'lar)"
|
||
echo " https://eu.posthog.com/project/127747/dashboard/$D3 (Abonelik)"
|
||
echo ""
|
||
echo "Toplam: 11 insight + 3 dashboard oluşturuldu."
|