Reward engine:
- Recurring milestones (every 3 → +7d, every 5 → +14d) instead of one-time
tiers capped at 5; idempotent + transactional grants serialised per
referrer so concurrent qualifications can't double-count.
- Rewards now gated on the referred user's email verification
(afterEmailVerification hook); already-verified referees (OAuth) qualify
at apply time.
- Reward days banked as users.referral_credit_days when the referrer has no
live subscription, consumed on next trial start / activation (no more
silently lost rewards).
- Accurate cumulative rewardDays in stats; getMyReferrals returns referee
name/masked email/status.
Hardening / cleanup:
- onConflictDoNothing makes apply idempotent (no unhandled unique violation).
- Anti-fraud: normalizeEmail blocks self-referral via gmail dot/+tag aliases.
- Collision-safe referral code generation at signup.
- Single apply path (welcome onboarding modal); removed duplicate calls in
register + subscription pages. Input validation on the apply code.
Email verification UX:
- Verification link now lands on a dedicated /email-verified confirmation
page instead of the deep-linked VIN/search page.
Schema: referrals.status + qualified_at, users.referral_credit_days (0009).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
A user who picked a plan + brands, clicked the checkout button to
create the pending subscription, then closed the tab without paying
came back to a frozen "Mevcut Plan · Bekliyor" card with no payment
button and no way to edit. Status was "pending", which my conditional
treated as an active subscription and routed away from the stepper.
Frontend
- hasActiveSub narrowed to active|cancelled only. Pending users now
see the stepper again.
- New effect pre-fills selectedPlanKey, selectedBrandIds,
billingPeriod from the pending row on first render and jumps
straight to the payment step.
- New PendingPaymentBanner at the top of the stepper with
"Odemeye devam et" (scrolls + sets step=payment) and "Vazgec"
(calls cancel-pending then resets selection).
Backend
- subscriptions.service.create() auto-expires existing pending
rows for the user before inserting a new one — abandoned checkouts
no longer accumulate and a fresh attempt with a different plan
doesn't 409.
- New PATCH /subscriptions/cancel-pending + service method for
the banner's explicit cancel action.
i18n: subscription.pendingBanner.* (tr/en).
Co-Authored-By: Claude Opus 4.7 (1M context) <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>
- 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>