dev #77
Reference in New Issue
Block a user
Delete Branch "dev"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Replaces the old marketing "guided tour" /demo with a real, fully-functional catalog browsing experience for the pre-warmed example vehicle. No auth required, no upstream calls — entirely served from prod DB. Backend (apps/api/src/demo): * New @Public() controller exposing five endpoints under /api/demo: - GET /vehicle → demo vehicle metadata - GET /categories/tree → top-level category tree - GET /categories/search?q= → cross-tree search - GET /categories/:id → getCategoryWithParts (parts+schema+hotspots) - GET /categories/:id/children → drill children * DemoService validates every category id against DEMO_VEHICLE_ID before any downstream service call — the public surface can't be used to read an arbitrary vehicle's catalog (1-row SELECT, NotFound on miss or wrong owner). * Vehicle id is env-driven (DEMO_VEHICLE_ID, defaults to the pre-warmed WVWZZZ1JZ3W597935 — VW Golf 2003 with 277 cats / 9841 parts / 178 schemas fully drilled in prod). * Wires CategoriesModule (already exports CategoriesService) — zero new business logic, just a thin public façade. Frontend (apps/web): * /demo (replaces old marketing page): vehicle header + top categories grid reading /api/demo/* + sticky DemoBanner with sign-up CTA. * /demo/categories/$categoryId: drill page rendering either a children grid (parent) or the existing SchemaViewer + parts panel (leaf) — same shape the dashboard uses, so hotspot overlay, breadcrumb trail, retry on upstream loadError all just work. * DemoBanner: sticky top, "Örnek araç: {label} — Kayıt Ol" CTA. The "Yeni VIN sorgula" explicit paywall trigger lands in a follow-up task. * PostHog events: demo_loaded (source query-param-aware), demo_category_clicked, demo_category_detail_viewed, demo_to_register_click (banner / footer / category_footer placements). * usePageMeta gains an opt-in `noindex` flag — demo sets it to noindex,follow for the first 4-6 weeks per spec; cleaned up on unmount so SPA navigation doesn't carry it to the next route.Real visitors were repeatedly clicking the hero "Ara" button while only the placeholder VIN (WVWZZZ1JZ3W597935) was showing — they mistook the example for typed text. The click hit handleVinSearch's `if (!trimmed) return` early-out and did nothing, leaving them stuck. Now: empty input OR a value that exactly matches the example VIN routes to /demo (the pre-warmed VW Golf 2003 catalog) instead of /register. The button label also updates to "Örnek aracı dene" in that state so the outcome is predictable before the click. Any other typed VIN still goes through the existing /register?vin= flow unchanged. PostHog: emits hero_ara_demo_redirect with {had_value, was_example_match} so we can split the funnel by what triggered the demo entry.Founder caught two issues on the live /demo page: 1) Copy was framed as B2C ("Kendi aracınız için sınırsız erişim") but sase.tr's audience is parts shops / garages / e-commerce sellers — they decode 5-30 VINs/day for their customers, not for their own car. Rewrote banner + both footer CTAs to frame conversion around "sınırsız şase sorgulamak için ücretsiz hesap aç" — that's the actual unit they pay for. 2) Footer "Hesap Aç" button sat awkwardly on mobile: arbitrary-width inline element flex-stacked under the headline text, overlapping the Chatwoot widget in the bottom-right. Made the button `w-full sm:w-auto` so it reads as a clear primary action on mobile, and added `mb-20 sm:mb-0` to the card to clear the Chatwoot widget on small screens.