Vehicle Listing Page

Public-facing vehicle detail page for “Vehicles Stripping For Spares” listings. Shows vehicle information, images, supplier details, and enquiry form. Handles contact tracking, view analytics, and stripping alert subscriptions.

Overview

Route: /vehicles/[id].astro URL Parameter: Accepts both slug or vehicle ID Cache Control: No-store (dynamic content, prevents stale data) Listing Expiration: 4 months from date_listed

Key Features

1. Dynamic Vehicle Lookup

3. Vehicle Details Display

4. Contact Options

5. Enquiry Form (VehicleEnquiryForm)

6. View Tracking

Two separate tracking systems:

  1. Vehicle-level tracking - /api/track-vehicle-view (vehicle_views table)
  2. Supplier-level tracking - /api/supplier/track-view (supplier_analytics table)

Both track only once per session per vehicle to avoid inflation.

7. Subscription Widget (VehicleSubscriptionWidget)

8. Internal Linking (SEO)

9. Supplier Information Card

10. Breadcrumb Navigation

Home > Vehicles Stripping For Spares > {Make} Spares > {Year} {Make} {Model}

11. Report Listing Feature

Components Used

ComponentTypeLocationPurpose
VehicleEnquiryFormReact (.tsx)src/components/VehicleEnquiryForm.tsxSubmit enquiry to supplier
VehicleSubscriptionWidgetReact (.tsx)src/components/VehicleSubscriptionWidget.tsxEmail alert subscription
VehicleViewTrackerAstro (.astro)src/components/VehicleViewTracker.astroTrack page views with UTM params
BreadcrumbAstro (.astro)src/components/Breadcrumb.astroNavigation breadcrumb
ReportListingButtonReact (.tsx)src/components/ReportListingButton.tsxOpens report modal
ReportListingModalReact (.tsx)src/components/ReportListingModal.tsxReport submission form

Database Tables

vehicles

Vehicle stripping listings.

ColumnTypeDescription
iduuidPrimary key
slugtextURL-friendly identifier (unique)
supplier_iduuidFK to suppliers
yearintegerModel year
maketextVehicle make
modeltextVehicle model
engine_codetextEngine identifier
engine_sizetextDisplacement (e.g., “2.0L”)
transmissiontextManual/Automatic/CVT
mileageintegerOdometer reading
colortextVehicle color
statustextavailable/sold/expired
featured_imagetextMain image URL (Cloudinary)
gallery_imagestext[]Array of image URLs
reference_numbertextSupplier’s stock code
descriptiontextLong-form vehicle notes
date_listedtimestampWhen listing created

vehicle_views

View analytics per vehicle (one record per view).

ColumnTypeDescription
iduuidPrimary key
vehicle_iduuidFK to vehicles
supplier_iduuidFK to suppliers
sourcetextdirect/search/social/newsletter/supplier_page/other
ip_hashtextSHA256 hash of visitor IP
user_agenttextBrowser/device info
created_attimestampView timestamp

Tracking Behavior:

supplier_analytics

Daily aggregated metrics per supplier.

ColumnTypeDescription
iduuidPrimary key
supplier_iduuidFK to suppliers
datedateAnalytics date (daily rollup)
profile_viewsintegerSupplier profile page views
listing_viewsintegerVehicle detail page views (this page)
inquiriesintegerEnquiry form submissions
phone_clicksintegerPhone button clicks
whatsapp_clicksintegerWhatsApp link clicks

Note: Records created/updated once per view type per day per supplier

suppliers

Supplier master data.

ColumnTypeDescription
iduuidPrimary key
nametextBusiness name
statustextactive/suspended/inactive
makestext[]Array of vehicle makes
featured_imagetextSupplier logo/image
phonetextPrimary contact number
whats_apptextWhatsApp link (https://wa.me/…)
addresstextPhysical location
emailstext[]Array of supplier emails
coordinatesjsonb{lat, lng} for map
websitetextWebsite URL
descriptiontextBusiness description

marketing_emails

Email subscription records (for stripping alerts).

ColumnTypeDescription
iduuidPrimary key
emailtextSubscriber email (unique with make)
vehicle_maketextSubscribed make (e.g., BMW)
vehicle_modelstext[]Subscribed models
is_activebooleanSubscription status
consent_sourcetextwidget/manual/import
consent_ipinetIP address when subscribing
segment_tagstext[]For email segmentation
consent_timestamptimestampWhen consent given
created_attimestampRecord creation
updated_attimestampLast update

API Endpoints

/api/send-vehicle-enquiry (POST)

Purpose: Send vehicle enquiry to supplier

Request:

{
  "to": "supplier@email.com",
  "bcc": "info@enginefinder.co.za",
  "vehicleDetails": {
    "make": "BMW",
    "model": "E46",
    "year": "2005",
    "engineCode": "M54B30",
    "reference": "STOCK-001"
  },
  "customerDetails": {
    "name": "John Doe",
    "phone": "0712345678",
    "email": "john@example.com",
    "city": "Cape Town",
    "message": "Looking for this specific model"
  }
}

Response:

{
  "success": true,
  "data": { "id": "resend-message-id" }
}

Email Template:

Error Handling:

/api/track-vehicle-view (POST)

Purpose: Record individual vehicle view

Request:

{
  "vehicle_id": "uuid",
  "source": "direct|search|social|newsletter|supplier_page|other"
}

Response:

{ "success": true }

Behavior:

/api/supplier/track-view (POST)

Purpose: Record supplier-level engagement (listing view, phone click, etc.)

Request:

{
  "supplier_id": "uuid",
  "view_type": "listing|phone_click|whatsapp_click"
}

Response:

{ "success": true }

Behavior:

/api/reports/listing (POST)

Purpose: Submit a report about a vehicle listing

Request:

{
  "vehicleId": "uuid",
  "vehicleSlug": "slug-string",
  "reason": "Vehicle no longer available|Incorrect information|Suspicious listing|Duplicate listing|Other",
  "details": "Optional additional details",
  "reporterEmail": "optional@email.com"
}

Response (Success):

{
  "success": true,
  "message": "Report submitted successfully",
  "data": { "id": "resend-email-id" }
}

Response (Rate Limited):

{
  "success": false,
  "message": "Rate limit exceeded. Maximum 3 reports per hour per IP address."
}

Behavior:

Error Handling:

URL Structure

Slug-based (Preferred)

/vehicles/2005-bmw-e46-m54b30-stripping-for-spares

ID-based (Fallback)

/vehicles/550e8400-e29b-41d4-a716-446655440000

Data Flow

1. User visits /vehicles/[slug-or-id]

2. Page looks up by slug, falls back to ID

3. Validates supplier is active, listing not expired

4. Fetches related supplier data

5. Renders vehicle details + gallery + forms

6. JavaScript runs:
   - VehicleViewTracker sends view to /api/track-vehicle-view
   - Supplier tracking sends to /api/supplier/track-view
   - VehicleEnquiryForm ready for submission
   - VehicleSubscriptionWidget ready for subscription

Text Formatting Rules

The page includes custom formatting for vehicle specifications:

// Camel case splitting
E82E82 (letter+number kept together)
BMWBMW (kept together)
EngineCode → Engine Code (space inserted)

// Known patterns handled specially
"E82""E82" (not split)
"not provided""" (filtered out)
"not available""" (filtered out)

Each page generates contextual breadcrumbs:

SEO Features

  1. Meta Title: {Year} {Make} {Model} {EngineCode} Stripping For Spares
  2. Meta Description: Full vehicle specs with supplier guarantee promise
  3. OG URL: https://www.enginefinder.co.za/vehicles/{slug}
  4. Breadcrumb Schema: JSON-LD via Breadcrumb component
  5. Internal Linking: 16 variations of SEO-optimized links within page
  6. Slug Consistency: URL-friendly identifiers support indexing

Caching & Performance

HTTP Headers:

Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
Expires: 0
Surrogate-Control: no-store

Image Optimization:

Client-side Tracking:

Recent Updates (December 2024)

Parts WhatsApp Enhancement (Dec 12, 2024)

Updated WhatsApp Message Format:

Hi, I found this {year} {make} {model} on Engine Finder (enginefinder.co.za). I'm looking for a {part}. Is it still available?

Redesign Completed (Earlier Dec 2024)

New Components Added

ComponentLocationPurpose
PartsAvailability.astrosrc/components/PartsAvailability.astroStatic parts checklist with WhatsApp links
SimilarVehicles.astrosrc/components/SimilarVehicles.astroRelated vehicles grid/scroll
whatsappNormalizer.tssrc/lib/normalizers/whatsappNormalizer.tsNormalize SA phone numbers for wa.me links

Layout Changes

Future Enhancements

Testing

Manual Testing

Listing Expiration:

# Create vehicle with date_listed > 4 months ago
# Navigate to /vehicles/{id}
# Should redirect to home

View Tracking:

# Visit /vehicles/{id}
# Check vehicle_views table - should have 1 record
# Visit again same session - no new records added
# New session - creates new record

Enquiry Form:

# Fill enquiry form with valid data
# Check supplier inbox for email
# BCC should arrive at info@enginefinder.co.za
# Resend dashboard should show delivered event

Subscription Widget:

# Select make, model(s), enter email
# Check marketing_emails table for new subscription
# Verify is_active=true, consent_source='widget'

Performance Testing

Page Load:

Image Gallery (Swiper.js):

Troubleshooting

IssueCauseSolution
Page redirects to homeSupplier inactive or listing expiredCheck supplier.status and date_listed
Images not loadingCloudinary URL invalid or domain blockedVerify image URLs in database, check Cloudinary account
Enquiry not receivedEmail domain not verifiedVerify info@enginefinder.co.za in Resend dashboard
View not trackedSession already tracked or API failedCheck sessionStorage, browser console for errors
Subscription failsInvalid email or privacy consent uncheckedCheck validation errors in widget UI
Make link brokennormalizeMake() output incorrectVerify make name in database matches normalization rules

Dependencies

PackagePurpose
swiperTouch-enabled image slider (mobile-first)

Key Files


🤖 Subagent Rule

Before modifying any files in this feature:

  1. Spawn a subagent with subagent_type: "general-purpose"
  2. Include this CLAUDE.md path in the prompt
  3. After work is complete, update this CLAUDE.md with changes