feat: landing page CRO revision, demo page, auto-trial, multi-catalog messaging

- Rewrite landing page copy with Jobs-to-be-Done and loss framing
- Add VIN live preview via backend pl24+emex decode chain
- Add comparison table (mobile-responsive), stats, pricing teaser, referral banner
- Replace testimonials with aggregate social proof stats
- Create demo page with 3-step VIN decode flow for unregistered users
- Add public /vehicles/preview/:vin endpoint (no auth required)
- Auto-create 7-day trial subscription on user registration
- Highlight multi-catalog cross-querying advantage in OEM feature and comparison
- Update register page with trial messaging and VIN param support

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Sase Dev
2026-02-15 00:38:52 +00:00
parent 4a06ba5fdb
commit 25278d386a
13 changed files with 1800 additions and 72 deletions

View File

@@ -5,7 +5,7 @@ import {
Injectable,
NotFoundException,
} from "@nestjs/common";
import { eq, and, desc } from "drizzle-orm";
import { eq, and, desc, or, inArray } from "drizzle-orm";
import { DATABASE, Database } from "../database/database.provider";
import { userSubscriptions, userBrands, plans, brands } from "../database/schema/core";
@@ -25,6 +25,12 @@ export class SubscriptionsService {
throw new ConflictException("Already have an active subscription");
}
// Expire any existing trial subscription
await this.db
.update(userSubscriptions)
.set({ status: "expired", updatedAt: new Date() })
.where(and(eq(userSubscriptions.userId, userId), eq(userSubscriptions.status, "trial")));
// Validate plan
const plan = await this.db.select().from(plans).where(eq(plans.id, data.planId)).limit(1);
if (plan.length === 0) throw new NotFoundException("Plan not found");
@@ -198,7 +204,12 @@ export class SubscriptionsService {
const [sub] = await this.db
.select()
.from(userSubscriptions)
.where(and(eq(userSubscriptions.userId, userId), eq(userSubscriptions.status, "active")))
.where(
and(
eq(userSubscriptions.userId, userId),
or(eq(userSubscriptions.status, "active"), eq(userSubscriptions.status, "trial")),
),
)
.limit(1);
if (!sub || !sub.endDate) return;