Resolve a catalog OEM code to its TecDoc equivalents on a new
/dashboard/oem/$code page: the aftermarket parts that carry it
(brand + article number + image + EAN), buyable supplier
substitutes, and OE cross-references (same part under other makes).
- API: TecdocModule (read-only postgres-js client to the imported
`td` snapshot), GET /tecdoc/oem?code=. Normalisation-based match
(TecDoc stores `1J0 973 702`, catalog gives `1J0973702`); exact
match recovers ~1/10 vs normalised ~5/10 on real codes. Self-
disables without TECDOC_DB_* env → { matched: false }.
- Web: OEM code in the parts panel is now a link (new tab) to the
detail page; "N/A" stays plain text.
- Mirrors CatalogSourceDbModule (raw queries, no Drizzle modelling).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The two things only the browser can add on top of the backend catalog-degradation
reporting:
- Replay-on-failure: when the catalog UI renders empty-tree (decoded vehicle, no
categories) or a drill loadError, capture a browser Sentry warning and flush the
Session Replay → you can WATCH the user hit the dead-end (serkan's session,
reproducible). Per-session deduped (one replay/session covers the whole journey).
- In-app feedback: a "Çalışmadı mı? Bildir" button on the empty-parts, empty-tree
and loadError states opens the Sentry feedback dialog pre-tagged with the
vehicle/category (+ session replay) — turns a parts shop's complaint into a
structured, triageable report instead of an email.
Browser events are fingerprinted source="browser" so they form their own
"what users actually saw" issues (carrying replays) next to the server-side
detections. tsc + biome + web build clean.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
parts_panel_viewed carried only opaque vehicle_id/category_id, so the
'0 parça' empty-catalog breakdown (and its rate-spike alert) couldn't say
WHICH vehicle/category was empty — useless for prioritising catalog backfill.
- parts-panel: add vehicle_label + category_name to parts_panel_viewed, and
fire a new empty_catalog_cta_clicked (with the same context) from the
empty-state button — a demand/abandonment signal per vehicle+category.
- schema-viewer: forward the two optional props to PartsPanel.
- vehicle category route: pass the existing vehicleLabel + data.name.
Best-effort labels (undefined on routes not yet threaded); parts_count
unchanged so existing insight/alert keep working.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Always-underlined, semibold, primary, larger text + arrow, with a "Tabloya
git:" verb so the cross-reference reads unmistakably as a clickable link
instead of muted inline text.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PL24 translates "see table" two ways — "bk. tablo:" and "bakınız tablo,
konum:". Detection only matched the first, so the latter rows (e.g. evaporator
housing → 820-020) stayed dead. Broaden the name regex to match either, and
strip both phrasings from the displayed label. The code-in-remark gate still
prevents flagging real parts that merely mention "tablo".
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
When a reference's target illustration isn't seeded yet (load-time index
miss → categoryId null), clicking it now calls a new resolve endpoint that
drills the relevant main-group root (its external_id = the code's first
digit; the illustration is a direct child) and re-resolves. One PL24 call in
the common case, bounded + cached; falls back to pre-filled search if not
found. UI shows a spinner on the button while drilling.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
PL24 BOM emits "see table NNN-NNN" reference rows (oem N/A, target code in
remark) with NO upstream link. Resolve the code against the vehicle's
illustration index (codes live in category names as {NNN-NNN}) and render
jump links. Unresolved targets (branch not seeded yet) deep-link a pre-filled
catalog search via ?q=.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The parts-panel wrapper used max-h-[500px] on mobile, but a max-height parent
does not give the panel's `h-full` a definite height to resolve against, so
the panel resolved to the table's full intrinsic height (~2500px) and, because
the wrapper's overflow is visible, spilled out the bottom — rendering the whole
parts list a second time below the signup CTA and the page footer (reported
"ürün kodları → kaydol kartı → footer → ürün kodları" broken structure).
Drop the mobile height cap so the parts list flows in normal document order and
the page scrolls through it (the intended mobile pattern; also resolves the
triple-scroll-trap noted in #76). Desktop is unchanged: the 40% column still
sits inside the md:h-[700px] row with its own inner overflow scroll.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
On mobile (iOS Safari, 390px), the schema viewport's one-finger touchmove
handler called setPan() unconditionally — even at zoom 1 with nothing to
pan — which makes iOS suppress the native page scroll. Users couldn't reach
the parts list below the fold (real trial session: 16 rage clicks, 0 OEM
codes copied, no purchase).
- use-schema-interaction: gate one-finger pan on zoom > 1 so the gesture
falls through to native page scroll when not zoomed in.
- schema-viewer: set touch-action (pan-y pinch-zoom at zoom 1, none when
zoomed) on the viewport; shrink mobile schema height 400px -> 280px so the
first parts rows peek below the fold and signal "more below".
- parts-panel: after a hotspot tap, scrollIntoView uses block:"start" on
mobile (panel is below the fold) and block:"center" on desktop, so the
selection is actually visible.
Tests: new Vitest hook test asserts no pan at zoom<=1, pans at zoom>1, and
pinch-zoom still works; new parts-panel scroll test asserts mobile vs desktop
block target. Also fixes a pre-existing typo in the empty-state test ("Geri
don" -> "Geri dön").
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two cosmetic fixes the founder flagged in the same browse session:
* parts-panel.tsx — the catalog parts table was missing Turkish
diacritics on every static label, while the actual part names rendered
correctly. Looked like an encoding bug; was actually hard-coded ASCII
strings. Repaired: Parcalar→Parçalar, parca listeleniyor→parça
listeleniyor, Bu kategori icin parca bulunamadi→Bu kategori için
parça bulunamadı, Yukleniyor→Yükleniyor, Parca Adi→Parça Adı,
Geri don→Geri dön. OEM Kodu was already correct.
* index.tsx hero preview — pl24 ships model names with trailing
duplicates ("Golf 1,6 GOLF"), and the card stitched year right next
to the engine "(2003 4 silindirli…)" with no clear separator. Now:
cleanModelName collapses the dup ("Golf 1,6"), year wraps in
parentheses as a softer secondary element, and the visual flex gap
guarantees breathing room before the engine pill.
PL24's bomOverviewlist widget (PR-code-filtered overview tables like
"Alternatöre genel bakış · Start-Stop modu bulunan araçlar için
[PR:7L6,7L8]") returns parts but no illustration — upstream genuinely
has no schema for these. Previously the 60% left panel rendered the
text "Sema goruntusu bulunamadi", which reads like a failure and
wastes most of the layout for what is actually a complete result.
When schemaPic is null, skip the schema panel entirely and let the
parts list take the full container width. The parts panel already
handles its own header/empty state, so no other adjustment needed.
- Add unavailable/remark/modelCodes/presel fields to categories and parts DB schema
- Pass PL24 unavailable flag through pipeline instead of filtering out records
- Show unavailable categories/parts at reduced opacity in grid, tree, and parts panel
- Display part remark and model codes as secondary info in parts table
- Move Google sign-in button above email form on login/register pages with branded icon
- Add public email existence check endpoint for better login error messages
- Update INDEX.md documentation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add oem_code_copies table and analytics module for tracking part code copies
- Integrate PostHog for frontend product analytics (VIN decode, OEM copy events)
- Switch email service from stub to Postal API with proper error handling
- Add copy button to parts panel with clipboard + server-side logging
- Add admin copy-logs page with filtering and top-copied-codes view
- Add VIN report endpoint for users to flag unrecognized chassis numbers
- Add Postal email env vars to config schema
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add OpenTelemetry SDK with tracing, metrics, and OTLP export for API and worker
- Integrate Grafana Faro for frontend real-user monitoring
- Instrument health checks, database, Bull queues, and HTTP exception filter
- Add Grafana dashboard JSON for service overview
- Remove deprecated apps/web-nj (Next.js) — fully replaced by Vite+React frontend
- Update nginx config with OTEL collector proxy
- Minor UI fixes in schema viewer, category components, and subscription flow
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move trial creation from auth hook to dedicated /subscriptions/trial endpoint
with eligibility checks (3-day Full Paket trial)
- Add animated onboarding progress (Remotion) with confetti on completion
- Register redirects to subscription page with welcome flow
- Add Google social login/signup support with config injection
- Improve hotspot overlay visibility in dark mode
- Show "Panele Git" on landing page when authenticated
- Turkish translations for API error messages
- Add toast utility wrapper, UUID generation for auth IDs
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Replace browser-based Puppeteer scraper with standalone scraper wrapper.
Add EMEX as fallback source for categories when PL24 is unavailable.
Update vehicle decoding to use new synchronous EMEX API.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add POST /admin/users endpoint with password hashing and role support
- Add user creation dialog to admin users page
- Migrate web from Next.js to Vite + TanStack Router
- Fix Dialog component positioning for Tailwind CSS v4
- Add @source directive for @sase/ui package scanning
- Add pl24 integration parsers and vehicle decode flow
- Backup old Next.js app to apps/web-nj
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>