1079 Commits

Author SHA1 Message Date
24716d03a9 Merge pull request 'revert(build): drop ineffective cache-bust (#219)' (#220) from revert/build-cache-web into dev 2026-07-14 08:13:46 +03:00
6de7839107 revert(build): drop ineffective per-commit cache-bust (#219)
SOURCE_COMMIT isn't substituted into docker-compose build args by Coolify
(resolved to a constant "unknown"), so the cache-bust never fired. Removing the
dead ARG/RUN + compose arg. Web-only deploys use a Coolify force-rebuild instead.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 08:13:44 +03:00
edcd168d48 Merge pull request 'fix(build): per-commit cache-bust for web-only deploys' (#219) from fix/build-cache-web into dev 2026-07-14 07:43:07 +03:00
c20fc5462a fix(build): per-commit cache-bust so web-only changes actually deploy
Auto-deploys (docker build with cache) were reusing a stale build layer, so
web-only commits shipped an old bundle — the switcher removal (#216) and the
canonical fix (#217) only appeared after a manual --no-cache/force rebuild.
Reference SOURCE_COMMIT (substituted by Coolify) right before `COPY . .`, so the
build layer's cache key changes every commit and COPY + `pnpm build` re-run. The
deps stage stays cached on the lockfile, so installs aren't repeated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 07:43:05 +03:00
4bba42fc13 Merge pull request 'promote: Fiat eper-default katalog (Orijinal→ePER, Birleşik→kanonik)' (#218) from dev into main 2026-07-14 07:35:32 +03:00
2bf7525fe2 Merge pull request 'fix(catalog): Fiat Birleşik = canonical view (not raw pcat)' (#217) from feat/fiat-birlesik-canonical into dev
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
2026-07-14 07:11:53 +03:00
bf49900b57 fix(catalog): Fiat "Birleşik" stays the canonical view, not the raw pcat tree
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Correction to #216: "Birleşik" must fold the catalog into OUR canonical 20-bucket
structure (pcat + eper), not show parts-catalogs' raw tree. Only "Orijinal
Katalog" swaps to the native ePER tree for Fiat.

- treeSource → eper-pekidi for Fiat (Orijinal); canonical tab renders CanonicalView
- reverts #216's "canonical tab → pcat source tree"

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 07:11:50 +03:00
ff96dcac1c Merge pull request 'feat(catalog): Fiat tabs → eper/pcat, drop extra switcher' (#216) from feat/fiat-eper-simplify into dev 2026-07-14 06:56:14 +03:00
5a3e1a2299 feat(catalog): map the two Fiat catalog tabs onto eper/pcat, drop the extra switcher
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Simplify the previous change: instead of a third source-switcher pill, reuse the
two tabs that are already there. For an eper (Fiat) vehicle:
  "Orijinal Katalog" → the native ePER tree (default)
  "Birleşik"         → parts-catalogs
Non-eper vehicles keep the original source/canonical tabs untouched.

- web: derive treeSource from browseMode when the vehicle has eper; canonical
  tab renders the pcat source tree (not CanonicalView) for eper vehicles
- removes the ePER/Diğer switcher, SOURCE_LABELS, and the activeSource state
Net −27 lines.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 06:56:12 +03:00
24495d8970 Merge pull request 'feat(catalog): eper as default Fiat catalog source (pcat switchable)' (#215) from feat/fiat-eper-default into dev 2026-07-14 06:42:06 +03:00
de960a0dd4 feat(catalog): eper as the default Fiat catalog source, pcat one tap away
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Fiat dealers know the native ePER tree; parts-catalogs' broader-but-lazy folders
are where they hit gaps (a motor OEM missing under "Motor" — the reason we
crawled pekidi ePER). So for a multi-source decoded vehicle, default the
"Orijinal Katalog" view to eper-pekidi — fully populated with parts + diagrams —
instead of showing every source's roots mixed together.

- categories.service.getCategoryTree(vehicleId, source?): prefer eper-pekidi when
  present; ?source= overrides; cache keyed per source
- categories: getCatalogSources(vehicleId) → sources present, default (eper) first
- controller: tree/:id/sources endpoint + ?source query
- web: source switcher pill (ePER ⇄ Diğer) in source mode when >1 source;
  defaults to the first (eper). pcat never hidden, just one tap away.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-14 06:42:04 +03:00
cee11b5769 Merge pull request 'fix(vinpin): reject stale-breadcrumb decodes + harden matcher' (#214) from fix/vinpin-false-positive into dev 2026-07-13 12:09:49 +03:00
5697447988 Merge pull request 'fix(vinpin): reject stale-breadcrumb decodes (require SINCOM) + harden matcher' (#213) from fix/vinpin-false-positive into main 2026-07-13 12:09:15 +03:00
70d901f9f5 fix(vinpin): reject stale-breadcrumb decodes (require SINCOM) + harden matcher
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
A failed ePER VIN lookup ("vehicle not found") whose Cyrillic "не найден" alert
OCRs to garbage ("He HaaeHs") slipped the not-found check; the parser then
grabbed the operator's last-browsed catalog from the breadcrumb
("FIAT » TIPO-EGEA") and false-mapped it to a catalog — NM4131 landed on the
ancient "Tipo 1100-1370-1580 (1987-1993)", plus 2× PANDA. Every genuine decode
carries a SINCOM; the breadcrumb false positives never do.

- parser: isUsableParse now requires a SINCOM (a model alone is not a decode)
- matcher: modelTokens keeps 4-digit engine displacements (1100/1370/1580) —
  only 1950-2039 count as years — so ancient catalogs no longer collapse to
  ["TIPO"] and win the fewest-extra-tokens tiebreak
- matcher: recency tiebreak on equal score — never fall back to an ancient
  generation for a bare / year-less model

15 unit tests (parser + matcher) pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 12:08:40 +03:00
731ac93a55 Merge pull request 'public-api: katalog gezinme (VIN'siz araç ağacı) endpoint'leri /v1/catalog/* — marka→model→motor→kategori, API-key auth' (#212) from dev into main
Reviewed-on: #212
2026-07-10 12:44:09 +03:00
oyp
0e8b2ab294 public-api: katalog gezinme (VIN'siz araç ağacı) endpoint'leri /v1/catalog/* — marka→model→motor→kategori, API-key auth
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:27:36 +03:00
814b798b3f Merge pull request 'feat(internal-admin): extend limiti 90 → 3650 gün' (#211) from fix/extend-days-cap into main
Reviewed-on: #211
2026-07-09 11:27:23 +03:00
c51b7b4e78 feat(internal-admin): extend limiti 90 → 3650 gün
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Panelin 'Bonus süre ekle (goodwill)' aksiyonu 360 gün gibi süreler
gerektiriyor; 90 gün sınırı iş ihtiyacını karşılamıyordu. Üst sınır
3650 (10 yıl) parmak-kayması koruması olarak kalıyor. Panel tarafı
(sp) aynı limite güncellendi.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 10:35:28 +03:00
ff81b244b7 Merge pull request 'fix: şerit-bazlı rate bütçesi' (#209) from dev into main 2026-07-09 10:01:55 +03:00
8dd2d223e9 fix(prefetch): şerit-bazlı kaynak bütçesi — fast lane açlığını bitir
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Fast worker canlıydı ama pcat'in 90/dk penceresini ana worker yiyordu → fast
işler sürekli 18s source-rate defer (BMW init'i slot bulamadı). checkSourceRate
artık şerit-bazlı: fast = total/3 (pcat 30), main = kalan (60); toplam
değişmedi → upstream yükü aynı. Cooldown pause'u da doğru worker'ı duraklatıyor.
Spec fast-queue davranışına güncellendi (17/17).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 10:01:47 +03:00
36ed37d5c0 Merge pull request 'feat: prefetch fast kuyruk' (#208) from dev into main 2026-07-09 09:13:34 +03:00
c8803ada35 feat(prefetch): ayrı FAST kuyruk — taze araçlar backlog'la yarışmasın
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Kök neden: ana kuyruk saatlerce üretim>tüketim rejiminde (children patlaması);
lifo'da sonradan eklenen HER iş bir öncekini gömer → taze araç init'leri bile
açlığa düşer (BMW 320i 58dk 0 parça). Fix: catalog-prefetch-fast kuyruğu +
ikinci worker (conc=4, 120/dk) — decode-tetiği ve fast:true işler (children
zinciri dahil) buraya akar; per-source redis rate gate iki worker'ı da ortak
sınırlar (upstream korunur). vehicles.service fast kuyruğa bağlandı.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 09:13:26 +03:00
ccc2cd75a5 Merge pull request 'feat: birleşikte görünüm değiştiriciler' (#207) from dev into main 2026-07-09 08:11:24 +03:00
f2a37b78cb feat(web): Birleşik görünümde grid/ağaç/kolon değiştiricileri çalışsın
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
CanonicalView viewMode prop'u: tree/columns için kanonik veriden sentetik
hiyerarşi (kova → alt-yaprak → gerçek kategoriler; sentetik düğümler children'lı
geldiğinden lazy-fetch tetiklenmez, gerçek kategoriler children'sız geçip normal
drill yapar; tpl-* placeholder'lar bu görünümlere alınmaz — grid'de kalır).
vehicles sayfasında CategoryViewToggle artık canonical'da da görünür; katalog
sayfası viewMode'u geçirir.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 08:11:16 +03:00
0e2871c964 Merge pull request 'feat: katalog sayfası Birleşik toggle' (#206) from dev into main 2026-07-09 08:07:21 +03:00
116def2c79 feat(web): pl24 katalog sayfasına Birleşik/Orijinal toggle
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
/dashboard/catalog/:brand/:modelId sayfasında birleşik görünüm yoktu — backend
endpoint'i (/catalog/vehicles/:id/canonical) hazırdı ama web'e hiç bağlanmamıştı.
CanonicalView'a endpoint/catalogMode/brandName/variantSearch prop'ları eklendi
(varyant qs dahil); sayfaya vehicles/$id ile aynı toggle. Varsayılan Orijinal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 08:07:13 +03:00
bcf8bb38cd Merge pull request 'fix: kanonik sayaç + entry cap' (#205) from dev into main 2026-07-09 07:45:09 +03:00
d38bcaa36f fix(canonical): kova başlık sayacı subgroup'ları da saysın + entry cap 40/kova
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
(1) Placeholder'lar subgroup içinde olduğundan başlık "0 kategori" diyordu —
sayaç artık flat+subgroup birleşik unique. (2) Kalabalık markalar (pl24 BMW
elektrik 537 entry) görünümü boğuyordu — kova başına en-paylaşılan 40 entry
(vehicle_count desc).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 07:45:02 +03:00
25965717c3 Merge pull request 'fix: entries ambiguity' (#204) from dev into main 2026-07-09 07:28:15 +03:00
671e9af15b fix(canonical-backfill): entries GROUP BY'da name'i c.name ile nitele (parent join ambiguity)
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 07:28:07 +03:00
da95b0484d Merge pull request 'canonical: şablon entry-seviyesi' (#203) from dev into main 2026-07-09 07:23:51 +03:00
5ed3959a12 feat(canonical): şablon ENTRY-seviyesi — decode anında tam gezinilebilir yapı
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Kullanıcının orijinal tasarımı: aynı (kaynak, marka)da kategori yapısı birebir
aynı — değişen yalnız parça kodları/şemalar. Önceki şablon sadece kova/alt-yaprak
BAŞLIKLARINI overlay ediyordu → taze araçta "Aydınlatma — 0 kategori". Yeni:
canonical_template_entries (migration 0031) — markanın paylaşılan kaynak-kategori
ADLARI (≥2 araç); backfill'de rebuild. overlayTemplate eksik adları disabled
placeholder olarak basar (unavailable=true, CategoryGrid zaten soluk+tıklanamaz
render ediyor) → decode anında her kova tam adlarıyla dolu; drill tamamlanınca
placeholder'lar gerçek satıra dönüşür.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 07:23:43 +03:00
eb92c5c5f8 Merge pull request 'fix: orijinal default' (#202) from dev into main 2026-07-09 07:12:00 +03:00
8a079d84f8 fix(web): Orijinal Katalog tekrar varsayılan — taze araçta boş kanonik kovalar çözülene dek
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 07:11:52 +03:00
1c4c896d64 Merge pull request 'feature/vin-ocr' (#201) from feature/vin-ocr into main
Reviewed-on: #201
2026-07-09 07:05:10 +03:00
3c6c27cb00 fix(vin-ocr): sunucu hata mesajını toast'ta göster
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
"Fotoğraf okunamadı" genel metni gerçek nedeni (örn. 503 "görselden şase
okuma şu anda kullanılamıyor", 400 "desteklenmeyen tür") yutuyordu — dev'de
OPENROUTER_API_KEY boş kaldığında teşhisi zorlaştırdı. ApiError mesajı artık
toast açıklamasında; 429 için Türkçe "çok fazla deneme" metni; PostHog
reason artık http_<status> taşıyor.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 06:52:14 +03:00
8d11ae7400 feat: fotoğraftan şase okuma (VIN foto-OCR)
Dashboard şase kutusunun sağına kamera butonu: kullanıcı fotoğraf yükler
(mobilde kamera), görsel istemcide ~1800px'e küçültülüp JPEG'e çevrilir,
POST /vehicles/decode/ocr OpenRouter üzerinden vision modeline gönderir
(varsayılan google/gemini-2.5-flash; bulamazsa openai/gpt-5.4-nano yedeği),
dönen VIN kutuya yazılır. Decode HER ZAMAN kullanıcının "Şase Çöz"
tıklamasıyla başlar — OCR yalnızca yazma zahmetini alır.

Model seçimi 2026-07-09 canlı bake-off'una dayanır (Commons'tan gerçek VIN
fotoğrafları): flash plaka/etiketleri doğru okudu; flash-lite rakam bozdu,
Haiku 4.5 olmayan VIN uydurdu, OCR.space damgalı şasede 8→S hatası verdi.
Sunucu tarafı katı doğrulama (17 karakter, I→1 O→0 Q→9, aksan ayrıştırma)
"regex'ten geçen ama yanlış" VIN'leri keser; okunaksızsa vin:null döner.

- throttle: kullanıcı başına 10 istek/dk; görsel sınırı 5MB (mevcut multipart
  middleware'iyle uyumlu), sadece JPEG/PNG/WebP
- compose: OPENROUTER_API_KEY api VE worker bloklarına eklendi (worker çeviri
  işçisi bu anahtarı bekliyordu ama compose'a hiç enjekte edilmemişti),
  VIN_OCR_MODEL / VIN_OCR_FALLBACK_MODEL api bloğuna eklendi
- analitik: vin_ocr_used eventi (success/reason/confidence/duration_ms),
  query_source="ocr"
- i18n: search.ocr.* (tr+en)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-09 06:41:33 +03:00
cafe206001 Merge pull request 'Merge branch 'feature/widget-canonical' into dev' (#199) from dev into main 2026-07-08 06:48:39 +03:00
a803d9da10 Merge pull request 'fix(vinpin): query_logs muhasebesi — pending poll'lar failure satırı yazmasın' (#200) from fix/vinpin-query-log-accounting into main 2026-07-08 06:47:50 +03:00
Semih
8054e2faf3 fix(vinpin): query_logs muhasebesi — poll'lar failure satırı yazmasın
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Vinpin fallback'i failure logQuery'sinden ÖNCE denenir oldu:

- Pending decode'un her 3sn'lik frontend poll'u 'No catalog — identified
  as Fiat' failure satırı yazıyordu: vinpin'in 10sn'de ÇÖZDÜĞÜ tek Egea
  VIN'i 17 failure satırı üretti, ham 24h success -20.7pp okundu
  (2026-07-07, 4 kullanıcı/4 VIN, gerçek infra hatası 0).
- Resolved VIN'lerde her decode kalıcı olarak fail+success çifti
  yazıyordu (failure log vinpin lookup'tan önceydi ve negatif cache
  vinpin çözümünden haberdar değil).

Yeni muhasebe: VIN başına TEK coverage-gap failure satırı (ilk görüş,
enqueue anı — coverage backlog sinyali korunur); pending poll'lar hiç
loglanmaz; resolved decode tek success satırı loglar; not_found/failed
eskisi gibi caller'ın failure log'una düşer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-08 06:40:23 +03:00
7956fc9e9b feat: kategori sağlık paketi — dedup+index, prefetch throughput, v1 taxonomy, Birleşik default
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
(1) migration 0030: 57.780 duplike kategori merge (prod'da uygulandı, idempotent)
+ categories unique index NULLS NOT DISTINCT → decode retry duplike üretimi
KALICI olarak durdu (onConflictDoNothing artık NULL sınıflarında da çalışıyor).
(2) prefetch throughput: backlog %89 pcat + net-büyüyordu (82k→94k). pcat
20→90/dk (DataImpulse rotating gateway), pace 5s→1.5s, conc 3→8, global 180.
pl24/emex dokunulmadı (ban riski).
(3) GET /v1/taxonomy: araçtan bağımsız kanonik yapı kontratı (B2C navigasyon).
(4) Birleşik tekrar varsayılan görünüm (edge-case'ler çözüldü).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 06:26:54 +03:00
006cf1fd63 Merge pull request 'feat(widget): kanonik (birleşik) kategori görünümü' (#198) from feature/widget-canonical into main
Reviewed-on: #198
2026-07-06 11:47:33 +03:00
6fb27d9509 Merge branch 'feature/widget-canonical' into dev 2026-07-06 11:32:55 +03:00
394e71e269 feat(widget): kanonik (birleşik) kategori görünümü
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Widget artık /categories varsayılan kanonik cevabını render eder (view=raw
kaldırıldı): kaynak-bağımsız kova → alt-grup → yaprak kategori → parça gezinme.
Frame-tabanlı breadcrumb (her seviye kendi render'ını taşır), ortak gridEl/grid
çizici, leafItem drill'i /categories/:id ile parça+şema. Dashboard'daki
'Birleşik' varsayılanıyla aynı deneyim.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:32:55 +03:00
454eab6b0e Merge pull request 'dev' (#197) from dev into main
Reviewed-on: #197
2026-07-06 11:10:03 +03:00
6585412932 Merge remote-tracking branch 'origin/dev' into dev
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
2026-07-06 11:02:55 +03:00
df04784ddb fix(widget): kategori ağacını ?view=raw ile çağır (API default kanonik oldu)
/v1/vehicles/:id/categories artık varsayılan kanonik kova görünümü döndüğü
için, ham ağaç şeklini render eden widget shell'i açıkça view=raw ister —
yoksa {canonical:{name},categories[]} şeklini {name,partCount,id} sanıp
kırılırdı. Kanonik-kova görünümünü widget'a getirmek ayrı iş.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 11:02:08 +03:00
239a46451d Merge pull request 'main' (#196) from main into dev
Reviewed-on: #196
2026-07-06 11:01:30 +03:00
d167c15c5e Merge pull request 'feature/public-canonical-categories' (#195) from feature/public-canonical-categories into main
Reviewed-on: #195
2026-07-06 11:01:04 +03:00
ae31a7b61a feat(jobs): kanonik backfill gecelik cron + artımlı (keep-fresh) mod
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
Faz 2 — decode edilen yeni araçların kategorilerini materyalize tutar:
- Processor'a incremental mod: step-2 yalnız HENÜZ map satırı olmayan yeni
  isimleri sınıflandırır (tüm ~113k değil). Materialize (step-5) differential +
  inheritance NULL-only olduğundan, adı zaten map'li yeni kategori de id'sini
  alır — hiçbir şey atlanmaz. is_manual korunur. reset varsa yok sayılır
  (reset tam yeniden-eşleme demek).
- Gecelik cron: 05:00 İstanbul, { incremental: true }. Dev+prod'da güvenli
  (harici yan-etki yok, kendi DB'sine yazar). Lexicon iyileştirmesi sonrası
  tam yeniden-eşleme hâlâ ELLE { reset:true } global run.
- Dokümante edilen 'backfill trigger yok' boşluğunu kapatır; serving zaten
  anlık lexicon fallback yapıyordu, bu cron materyalizasyonu güncel tutar.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-06 10:59:19 +03:00