feat(part-prices): parça kodu bazlı tedarikçi fiyat geçmişi + OEM sayfasında p50/p95/p99 grafiği
- pg: part_price_tracks + part_price_daily (0018) — (kod, kaynak, gün) başına stoktaki tekliflerin p50/p95/p99 + teklif sayısı; source='supplier' şimdilik, perakende ileride aynı tabloya 'retail' olarak girer. Tedarikçi kimliği yok. - API: GET /part-prices/series (ilk istekte takip history'sinden lazy-backfill, sonrası salt-pg + Redis) ve POST /part-prices/current-batch (sayfadaki kodlar için canlı güncel istatistik). P-servisi sözleşmesi: asla throw yok, fail-open. - Worker: part-price-refresh cron'u 19:30 Europe/Istanbul (takip sync'i 19:05'te bitiyor) — izlenen kodlara bugünün satırını upsert eder, sku_map'i artımlı bakar, Redis cache düşürür. SUPPLIER_PRICE_DB_* yoksa sessiz no-op. - Kaynak köprüsü: takip.sku_map (code_norm → product_id; tam sku / ilk-boşluk / ilk-tire sonrası normalize adayları) vmi MySQL'inde kurulu; 6,8M satır. - Web: OEM detayında "Tedarikçi fiyat analizi" kartı (güncel medyan + P95/P99 + teklif sayısı + 30g delta, 30G/90G/Tümü aralıklı step grafik, recharts) ve article/muadil/OE satırlarında fiyat çipi → dialog'da tam geçmiş. - Fix(p): td snapshot'ında gerçek üretici kodu articles.name'de (article_number %96 upstream sayısal ID) — sayfa artık kopyalanabilir gerçek kodu gösteriyor. - compose: SUPPLIER_PRICE_DB_ENABLED/URL api+worker bloklarına eklendi. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -176,6 +176,17 @@ export const envSchema = z.object({
|
||||
// verified against live OEM-by-OEM on at least 5 sampled vehicles. See
|
||||
// memory `sase-emex-source-db-safety.md` for the bridge inventory & audit.
|
||||
EMEX_SOURCE_DB_ALLOWED_CATALOGS: z.string().default(""),
|
||||
|
||||
// Tedarikçi fiyat verisi (takip MySQL, Tailscale üzerinden). Kapalı/boş URL →
|
||||
// part-prices uçları { matched: false } döner, UI fiyat bölümünü hiç çizmez.
|
||||
SUPPLIER_PRICE_DB_ENABLED: z
|
||||
.string()
|
||||
.transform((v) => v === "true")
|
||||
.default("false"),
|
||||
SUPPLIER_PRICE_DB_URL: z.preprocess(
|
||||
(v) => (typeof v === "string" && v.trim() === "" ? undefined : v),
|
||||
z.string().optional(),
|
||||
), // mysql://... — not a strict URL per WHATWG
|
||||
});
|
||||
|
||||
export type Env = z.infer<typeof envSchema>;
|
||||
|
||||
Reference in New Issue
Block a user