1071 Commits

Author SHA1 Message Date
51eec60c6c Merge pull request 'fix: MB katalog-kodu regex çıplak-koda sabit' (#166) from dev into main 2026-07-05 11:08:50 +03:00
f1f36d8cf1 fix(canonical-lexicon): MB katalog-kodu regex'ini çıplak-koda sabitle
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
^[cd]\d{3,} fazla genişti — "D765300(22H), LS 7 F, MB SERVO DİREKSİYON" gibi
parça bilgisi taşıyan düğümleri yapısal yapıp Direksiyon eşleşmesini bozuyordu
(Mercedes ham kapsama %79→%49). $ ile sabitle → sadece çıplak kod (C442,
C105011). Açıklamalı düğümler keyword'le eşleşmeye devam eder. 19/19 test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 11:08:47 +03:00
bf259f3d79 Merge pull request 'canonical: Mercedes C/D katalog kodları yapısal' (#165) from dev into main 2026-07-05 10:52:44 +03:00
25cf0fa670 feat(canonical-lexicon): Mercedes C/D katalog kodları yapısal + doküman sayfaları çöp
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Mercedes'in düşük kapsaması büyük ölçüde metrik yanılsaması: 175 dağınık kök,
C/D katalog-kodu düğümleri (C371211, C442, D308802(811),308,COWL) yapısal ama
classifyNode kaçırıyordu → denominatörde. Ekle: ^[cd]\d{3,} → structural;
"SA LİSTESİ"/"…resim açıklama sayfası" → junk. 19/19 test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 10:52:42 +03:00
c9f96f8666 Merge pull request 'canonical: Opel yazım varyantları + serving yapısal-atla' (#164) from dev into main 2026-07-05 10:30:31 +03:00
82793a8257 feat(canonical): Opel model-öncelikli — yazım varyantları + serving yapısal-atla
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Opel gerçek parça-kat kapsaması zaten %85; %38 model-kodu köklerin (yapısal)
denominatörde olmasından. Lexicon: sanzuman/disli→sanziman, suspensiyon/dingil→
suspansiyon (Opel yazımları). Serving: groupCategoriesByCanonical yapısal/çöp
düğümleri "Diğer"e sokmadan atlar (Opel model kökleri Birleşik'te görünmez).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 10:25:46 +03:00
51032342b8 Merge pull request 'canonical: parent-inheritance (kod-yaprak → parent kovası)' (#163) from dev into main 2026-07-05 10:16:21 +03:00
aba1bfc126 feat(canonical-backfill): parent-inheritance (kod-yaprak → parent kovası)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Kendi adı eşleşmeyen kategori (Renault P5 X1318_ plaka kodları, figür
illustration'ları) parent'ının kanonik kovasını miras alır ("Alternatör"→
Elektrik). Materyalizasyondan sonra birkaç seviye kaskad. Re-scrape gerektirmez.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 10:11:22 +03:00
3fb7fa1aa3 Merge pull request 'fix(pl24): Hyundai/Kia illustration açıklaması' (#162) from dev into main 2026-07-05 10:05:10 +03:00
c70b9b61b9 fix(pl24): Hyundai/Kia illustration açıklamasını kod-yaprağa ekle
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Upstream doğrulandı: illustration satırında td[0]=figür kodu ("20-201A .1"),
td[1]=açıklama ("SUB ENGINE ASSY") — parser ilk td'yi (kod) alıp açıklamayı
düşürüyordu. Artık ilk td figür-koduysa (\d\d-\d\d\d[A-Z]?) açıklamalı sonraki
td eklenir → "20-201A .1 SUB ENGINE ASSY", canonical eşleşir (engine→motor).
Diğer markalar etkilenmez (yalnız kod-only ilk td'de tetiklenir). 10/10 test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 10:02:01 +03:00
6bbc32d9c6 debug(pl24): TEMP Hyundai illustration rows + td dump 2026-07-05 09:55:30 +03:00
05951f9853 debug(pl24): TEMP Hyundai/Kia raw HTML row log (katalogJob Faz 2 upstream doğrulama) 2026-07-05 09:51:46 +03:00
50c7d91707 Merge pull request 'canonical Faz 2: İngilizce kategori adları' (#161) from dev into main 2026-07-05 09:30:36 +03:00
4b6642a78a feat(canonical-lexicon): Faz 2 — İngilizce kategori adları
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
pl24 Asyalı markaları (Hyundai/Kia/Nissan/Toyota) ve çevrilmemiş emex/pcat
yaprakları İngilizce kategori adı taşıyor (ENGINE/BODY/BRAKE/TRANSMISSION…) →
%0 kapsama. Sistem kelimeleri strong (engine→motor, brake→fren, transmission→
sanziman, electrical→elektrik…), konum kelimeleri weak (body/chassis/floor/axle)
ki "BODY ELECTRICAL"→elektrik olsun. 17/17 test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:30:34 +03:00
ef8240a012 Merge pull request 'canonical: Jant/Lastik + Aksesuar kovaları + pcat kararları' (#160) from dev into main 2026-07-05 09:24:49 +03:00
b547140eb1 feat(canonical): Jant ve Lastik + Aksesuar kovaları + pcat kararları
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
migration 0025: 2 yeni kanonik kova (jant-lastik #19, aksesuar #20).
lexicon: jant/lastik/tekerlek/göbek→jant-lastik, aksesuar→aksesuar (catch-all,
en düşük öncelik). Kullanıcı kararları: Hava Sistemi→Soğutma (hava weak),
Bakım parçaları→Filtreler (bakim weak). "hava yastığı"→direksiyon için yastigi
strong'a alındı. 16/16 test. Yorumlar 18→20 kova güncellendi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:24:29 +03:00
5abdc6f628 feat(canonical-lexicon): Faz 1 pcat kök eşlemeleri
pcat paylaşımlı taksonomisinin eşleşmeyen köklerinden net olanları ekledim:
jenerator→elektrik, yaglama→yaglar, karo/cerceve→panjur-panel, aktarim→
sanziman, aks→suspansiyon(weak). sasi weak (süspansiyon+şasi net kalsın).
15/15 test. Kova-kararı gerektirenler (jant-lastik, aksesuar) katalogJob.md'de.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:18:58 +03:00
efa395b7b5 Merge pull request 'web: birleşik görünüm default + Orijinal Katalog seçeneği' (#159) from dev into main 2026-07-05 09:09:39 +03:00
b96ca78942 feat(web): birleşik görünüm varsayılan + "Orijinal Katalog" seçeneği
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Araç sayfasında browse varsayılanı "canonical" (Birleşik) oldu; toggle
"Birleşik | Orijinal Katalog" — Orijinal Katalog seçilince ham OEM ağacı
gösterilir. Kullanıcı isteği: birleşik katalog default, orijinal opsiyonel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:09:37 +03:00
5a74a0e552 Merge pull request 'canonical: kova-adı lexicon fix (süspansiyon/elektrik/aydınlatma)' (#158) from dev into main 2026-07-05 09:05:50 +03:00
643e1d923c fix(canonical-lexicon): kova adının kendisini anahtar kelime yap
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Kök tam da kanonik başlıkla anılınca ("Süspansiyon, şasi", "Elektrik",
"Aydınlatma") lexicon'da o kelime yoktu → "Diğer"e düşüyordu. suspansiyon/
elektrik/aydinlatma kendi kovalarına strong olarak eklendi. Serving on-the-fly
fallback aynı lexicon'u kullandığı için taze araçlarda backfill'siz düzelir.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:00:33 +03:00
dedcf71419 Merge pull request 'dev' (#157) from dev into main
Reviewed-on: #157
2026-07-05 08:43:44 +03:00
07d4bf7e69 feat(canonical-lexicon): 3-harfli kök stem çekimlerini ekle
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
"yag/mil/far/aku" gibi 3-harfli kökler ≥4 prefix kuralı yüzünden çekimli
hallerine (yagi/yaglar, mili, farlar/fari, akusu) eşleşmiyordu — "HPS yağı",
"Kardan Mili", "araba aküsü" "Diğer"e düşüyordu. Çekimleri açıkça ekledim +
sanziman'a "kardan". Global düşürmek riskli (sis→sistemi). 13/13 test.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:42:06 +03:00
cc1d22a7d4 feat(catalog): kök-seviye canonical fallback + araç sayfası "Birleşik" toggle
Backend: groupCategoriesByCanonical'a requireParts opsiyonu; her iki serving
metodu artık parça-içeren yaprak yoksa (taze/drill-edilmemiş araç) kök
kategorileri kovalayarak boş dönmüyor.

Frontend: araç sayfasına "Katalog | Birleşik" toggle'ı; Birleşik seçilince
CanonicalView aracın kataloğunu 18 kanonik başlık altında gösterir, her kova
CategoryGrid ile normal drill'e bağlanır. canonical_view_opened event'i.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:28:07 +03:00
af2b35e6e2 feat(catalog): pl24 catalog-vehicle canonical gezinme variantı
GET /api/catalog/vehicles/:id/canonical → catalog_vehicle_id akışının canonical
karşılığı; pl24 markaları (VW/Opel/Renault) emex/pcat ile aynı 18 başlıktan
gezilir. Parça sayısı category_id ile join'lenir (pl24 parçaları çoğu zaman
vehicle_id taşır, catalog_vehicle_id değil). Gruplama mantığı iki servisin
paylaştığı canonical-grouping.ts helper'ına çıkarıldı (categories.service da
bunu kullanacak şekilde refactor edildi).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:08:59 +03:00
3c26f00a19 feat(categories): canonical taksonomiyle birleşik gezinme endpoint'i
GET /categories/canonical → 18 kanonik üst kova (browse landing).
GET /categories/canonical/:vehicleId → aracın parça-içeren leaf kategorilerini
18 kova altında gruplar; VW ve Opel gibi kökten farklı OEM ağaçları tek/aynı
başlık setinden gezilir. Kovalama materyalize canonical_category_id'yi
kullanır, son backfill'den sonra decode edilmiş kategoriler için ortak
canonical-lexicon ile on-the-fly fallback yapar; kovasız olanlar "Diğer"e düşer.
foldName() NORMALIZE_SQL'in JS karşılığı olarak eklendi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:58:17 +03:00
cd66947303 feat(canonical-backfill): reset/prune modu (global re-run için)
reset:true → non-manual keyword katmanını sıfırdan kurar: kapsamdaki
materyalize id'leri NULL'lar + stale non-manual map satırlarını siler,
sonra yeniden eşler. Manuel satırlar korunur. Sadece GLOBAL run'da (marka
scope'suz) geçerli — map isim-düzeyi/marka-bağımsız olduğu için marka-scope'lu
silme başka markaların paylaşılan eşlemelerini bozardı. Böylece lexicon/
sınıflandırıcı değişince eski eşlemeler dangling kalmaz.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:36:35 +03:00
c3d0dbaa0b fix(canonical-backfill): ">>" marker'ını yapısal sayma
Gerçek VW parça adları geçerlilik-tarihi marker'ı taşıyor ("pencere camlari
d >> - 14.07.2019"); bare ">>" onları yanlışlıkla yapısal işaretliyordu (VW
kapsamı düşüyordu). Gerçek VIN düğümlerini zaten VIN_LIKE yakalıyor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:29:29 +03:00
8b88ccd238 feat(canonical-backfill): ağırlıklı skorlama + genişletilmiş lexicon
- Belirsizlik skorlaması: strong head-noun ×3 / weak ×1; kazanan skor
  marjıyla belirlenir, ≤1 marj = ambiguous (eski eşit-sayı tie-break'i
  fazla ambiguous işaretliyordu). confidence marja göre (0.5–0.95).
- Lexicon genişletildi: egzoz/egz/konvertor/katalitik/susturucu (yakıt),
  karoser (panjur-panel), bcm/ecu (elektrik) + strong/weak ayrımı.
- classifyNode sıkılaştırıldı: VIN markerları (wvwzzz, >>), bare motor/
  sipariş kodları (z16dt[lfu]) artık yapısal.
- map.confidence artık per-eşleşme marjdan yazılıyor.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:24:42 +03:00
754f1af61c fix(canonical-backfill): brand/source filtresini inArray ile kur
`= ANY($1)` postgres-js'te parametreyi Postgres array olarak bağlamıyor
("op ANY/ALL (array) requires array on right side") → job'lar fail'liyordu.
inArray() IN-listesine açar, sürücü-güvenli.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:12:49 +03:00
0ae7c3ceb6 fix(worker): canonical-backfill Worker'ını worker.ts'e bağla
Önceki commit'te (7b5e678) src/worker.ts git add kapsamı dışında kaldı
(apps/api/src/jobs/ eklendi ama worker.ts src/ altında). Queue/processor
deploy oldu ama tüketici Worker yoktu → enqueue edilen job'lar 'waiting'de
takıldı. Bu commit Worker instance'ını ekler.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 17:02:37 +03:00
7b5e678c55 feat(catalog): kanonik taksonomi şeması + backfill job'ı
Kaynak/marka-bağımsız tek parça taksonomisi. Ham OEM ağaçları (categories.parent_id
+ pl24/emex/pcat aynaları) dokunulmadan kalır; kanonik omurga onlara dik.

- migration 0024: canonical_categories (18 üst kova seed) + category_canonical_map
  (isim-düzeyi eşleme) + categories.canonical_category_id kolonu
- canonical-lexicon.ts: iki-aşamalı eşleme (classifyNode: parça/yapısal/çöp;
  mapToCanonical: 18-kova keyword). VW+Opel pilotunda kanıtlandı — Opel ağacının
  %87'si model-seçici düğüm, bunlar kovaya girmez.
- canonical-backfill BullMQ job'ı (on-demand): distinct foldlanmış adları
  sınıflandırır, category_canonical_map'e upsert eder (is_manual korumalı),
  categories.canonical_category_id'yi join ile materyalize eder. brands/sources/
  dryRun parametreli.
- 8 unit test (classifyNode/mapToCanonical)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 16:54:24 +03:00
d2f42af935 Merge pull request 'dev' (#156) from dev into main
Reviewed-on: #156
2026-07-04 06:42:02 +03:00
ec95ab025d Merge branch 'feature/api-key-admin' into dev
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
2026-07-04 06:26:44 +03:00
8f6894eecb feat(api): api-key admin uçları — PATCH güncelleme, Redis kota usage, global liste
Süper Panel'den tam anahtar yönetimi için:
- GET /internal/admin/api-keys artık userId/email'siz TÜM anahtarları
  kullanıcı e-postasıyla birlikte döner
- GET /internal/admin/api-keys/usage — günlük decode kotasının anlık
  Redis durumu (limit/used/remaining), ids ile filtrelenebilir
- PATCH /internal/admin/api-keys/:id — name, dailyDecodeLimit(null=varsayılan),
  domains (yalnız publishable), rateLimitMax(null=plugin varsayılanı),
  expiresInDays(null=süresiz)
- PublicApiQuotaService internal-admin'e provider olarak eklendi

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-04 06:20:05 +03:00
123b701ed7 Merge branch 'feature/pcat-jwt-resilience' into dev 2026-07-03 18:33:48 +03:00
cd30278ad9 feat(pcat): JWT capture proxy-outage resilience + pool cap
JWT sitelerinin (parts-catalogs v3 widget'ını gömen partner mağazalar) sağlık
incelemesinden çıkan iki iyileştirme:

1) Direct-capture fallback (PCAT_CAPTURE_ALLOW_DIRECT, default açık): proxied
   capture tünel/connect hatasıyla ölürse (Floxy bakiye 402 / tünel down,
   DataImpulse portları ölü — 2026-06-11 ve 2026-07-03'te yaşandı) aynı siteyi
   sunucu IP'sinden DIRECT yeniden dener. Güvenli: TWS- token IP-bound DEĞİL +
   capture düşük frekans (≤MAX_POOL_SIZE refresh/~8.5dk). Doğrulandı: Floxy down
   iken direct 1.4s'de gerçek TWS- token yakaladı → warm pool artık tam proxy
   kesintisinde bile açlığa girmez.

2) Sert havuz üst-sınırı (enforcePoolCap): refresh yolundaki slot-muhasebe
   yarışı havuzu MAX_POOL_SIZE=5'in üstüne şişiriyordu (prod'da 32-39 gözlendi
   → gereksiz capture yükü + partner-site ban riski). Her push'tan sonra en eski
   slot(lar) çıkarılıp cap uygulanıyor, timer'ları temizleniyor.

6 JWT sitesinin hepsi canlı (direct 1.3-2s) — liste budanmadı. Birim testler +
canlı Floxy-down doğal deneyiyle doğrulandı.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:33:43 +03:00
f586b2f9c2 fix(api): widget şema görseli schemaPics[0].url okusun
schemaPics öğeleri {id,url,label} nesneleri; src'ye nesnenin kendisi
verilince kırık görsel ikonu çıkıyordu. + yüklenemeyen görsel gizlenir.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:09:38 +03:00
da2eaecd47 fix(api): public API parça cevabını beyaz-listeye indir + widget pozisyon alanı
- Kategori-detay parçalarında iç alanlar (source=upstream sağlayıcı adı,
  presel, ham price/currency, catalogVehicleId...) public API'den sızıyordu —
  decode kontratı disipliniyle beyaz-liste: id/name/description/oemCode/
  position/quantity/remark/unavailable/categoryId
- Widget parça tablosu positionNumber yerine gerçek alanı (position ??
  hotspotIndex) okuyor

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:05:21 +03:00
d46a463076 fix(api): widget Sorgula butonu MouseEvent'i candidate sanıyordu
onclick handler'ına doğrudan decode verilince click event'i candidate
parametresine düşüyor, sunucu da onu aday anahtarı sanıp 'araç seçimi
zaman aşımı' dönüyordu. Sarmalayıcı + typeof string guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 18:00:56 +03:00
e952687710 fix(api): widget loader.js global response-interceptor'a takılmasın
String dönüş {success,data} JSON'una sarılıyordu; Content-Type JS ama gövde
JSON olunca tarayıcı ERR_BLOCKED_BY_ORB ile script'i blokladı. @Res ile ham
send'e geçildi (shell zaten öyleydi).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:55:52 +03:00
ae61ac055e feat(api): gömülebilir katalog widget'ı (Faz 2 POC)
- GET /widget/loader.js: müşterinin yapıştırdığı tek script — iframe kurar,
  postMessage köprüsü (yükseklik + sase:partClick/sase:decoded olayları),
  parça tıklamasını data-part-click-url şablonuna ({code},{brand}) yönlendirir,
  window.saseWidget.onPartClick/onDecode callback'leri; CORP cross-origin
  (helmet same-origin varsayılanı müşteri sitesinde script'i bloklardı)
- GET /widget?key=sase_pk_...: iframe shell — vanilla JS katalog uygulaması
  (VIN formu, çok-aday seçimi, kategori grid + breadcrumb, parça tablosu,
  şema görseli, açık/koyu tema). Domain kilidi = anahtarın metadata.domains
  listesinden üretilen frame-ancestors CSP'si (tarayıcı zorlar); publishable
  olmayan anahtar 403; X-Frame-Options bu cevapta kaldırılır
- internal-admin: publishable:true + domains[] ile sase_pk_ anahtar üretimi
- api.sase.tr kısa yolu: /widget* → /api/widget*

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:50:29 +03:00
acadd84e4a fix(api): createApiKey expiresIn saniye cinsinden (ms değil)
30 günlük pilot anahtarı üretimi 'expiresIn is larger than the predefined
maximum value' hatasıyla düşüyordu — plugin expiresIn'i saniye bekliyor,
gün→ms çevriliyordu.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:27:59 +03:00
773e9c35fa feat(api): public API v1 katalog endpoint'leri
- GET /v1/vehicles/:vehicleId/categories — kategori ağacı (rollup parça sayılı)
- GET /v1/vehicles/:vehicleId/categories/:categoryId — kategori detayı + parça
  listesi + şema görselleri (lazy drill/heal aynen çalışır)
- GET /v1/vehicles/:vehicleId/search?q= — araç kataloğunda serbest arama
Hepsi gezinme sayılır, decode kotasından düşmez; Swagger anotasyonlu.
Dashboard'daki kuralla aynı: decode edilmiş araçlar paylaşımlı, varlık
kontrolü 404 için.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 17:25:38 +03:00
06f247beb7 feat(api): public API docs (Swagger) + api.sase.tr kısa yolları
- Swagger/OpenAPI yalnız PublicApiModule'ü kapsar (iç dashboard yüzeyi spec'e
  girmez); UI /api/v1/docs, JSON /api/v1/docs-json; bearer auth + kota
  açıklamaları TR
- api.sase.tr host'unda /v1/* → /api/v1/* ve /docs* → /api/v1/docs* rewrite —
  müşteriye dokümante edilen taban https://api.sase.tr/v1
- Controller'lara ApiOperation/ApiBody/ApiOkResponse anotasyonları (decode
  tek-eşleşme + çok-aday şemaları, OEM xref)
- Coolify: api.sase.tr dev app'in api servisine ikinci domain olarak eklendi
  (docker_compose_domains)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 16:40:17 +03:00
c9c33d58e1 Merge branch 'feature/public-api' into dev 2026-07-03 16:15:30 +03:00
7a4fe51d09 feat(api): public API POC — API-key auth + /api/v1 decode & OEM xref
Kapalı-beta public API temeli (rapor: api-widget-analizi-2026-07-03):
- better-auth apiKey plugin (defaultPrefix sase_, enableMetadata, anahtar
  başına 120 istek/dk); enableSessionForAPIKeys KAPALI — anahtar dashboard
  oturumu yerine geçmez, cookie AuthGuard davranışı değişmez
- apikeys tablosu (migration 0023, plugin şemasının birebir karşılığı)
- ApiKeyGuard: Authorization Bearer / x-api-key → verifyApiKey → kullanıcı
  yüklenir (status kontrolü), request.user + request.apiKey doldurulur
- /api/v1/vin/decode: mevcut slim kontrat + aday akışı; günlük başarılı-decode
  kotası (Redis, TR günü, aynı VIN idempotent; limit: key metadata
  dailyDecodeLimit → PUBLIC_API_DAILY_DECODE_LIMIT → 100) ve
  X-Decode-Quota-* header'ları
- /api/v1/oem/:code: P çapraz-referans (kotasız)
- internal/admin/api-keys: x-internal-token ile anahtar üret/listele/kapat
  (düz metin yalnız create cevabında)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-03 16:15:17 +03:00
4614d79d77 Merge pull request 'dev' (#155) from dev into main
Reviewed-on: #155
2026-07-01 18:15:57 +03:00
371aed3645 chore(build): wire VITE_GOOGLE_ADS_* build args for conversion tracking
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 18:11:45 +03:00
98c21fa30e feat(web): Google Ads conversion tracking (gtag + Enhanced Conversions)
Add lib/google-ads.ts (lazy gtag init, gclid capture, Enhanced Conversions,
trackGoogleAdsConversion). Fire sign-up conversion on email registration and
purchase conversion on Stripe success. Gated on VITE_GOOGLE_ADS_* env; no-op
when unset. Mirrors the Meta Pixel/CAPI pattern.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 18:11:44 +03:00