dev #77

Merged
root merged 5 commits from dev into main 2026-06-02 00:38:14 +03:00
Owner
No description provided.
root added 5 commits 2026-06-02 00:38:08 +03:00
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.
fix(pl24): stop .action shadowing PSA illustration/parts dispatch
Some checks failed
QA Gate (P0/P1) / Test affected app (pull_request) Has been cancelled
5e9d9050b9
isP4LegacyPath matched any ".action" path, shadowing the PSA
json-illustrations.action / image-board.action dispatch in
fetchSubGroupsByPath and fetchPartsByPath. Every PSA (Citroen/Peugeot/DS)
drill below main-group level fell through to the Ford/Fiat legacy parser,
which cannot parse PSA JSON, so it returned empty. PSA vehicles decoded
since the catalog module landed (72c0de6) showed categories but 0 parts
(41/43 affected). Exclude /psa/ from isP4LegacyPath so these paths reach
fetchPsaIllustrations / fetchPsaParts. Heals existing vehicles on demand;
no re-decode needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
root merged commit 6177f080b2 into main 2026-06-02 00:38:14 +03:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: root/sase.tr#77