← Back to projects
LopezCars

Capabilities

  • Back office
  • Audit log
  • CDN images
  • Transactional email

Frontend

Next.jsNext.js
TypeScriptTypeScript
TailwindTailwind

Backend

PostgreSQLPostgreSQL
DrizzleDrizzle
CloudinaryCloudinary
ResendResend

LopezCars

Completed

López Cars is a used-car dealership in Carabanchel (Madrid) whose site lived inside a third-party multi-tenant CRM. I rebuilt the whole thing as a Next.js 16 project they own — filterable catalog, vehicle pages, collections, services, valuation and contact — and put a back office behind it where they manage inventory, photos, brands, leads, valuations and bookkeeping without calling anyone.

The challenge

The client was paying for a platform they didn't control: they couldn't touch the design, export their data or add anything the CRM didn't offer. The brief was to migrate without losing content or rankings, matching what already worked, and finally hand them the keys to their own site.

Screenshots

Architecture

Architecture diagram for LopezCars

Implementation

  • Migration off a third-party CRM

    I inventoried assets, copy and structure from the old site before writing any code, so pages, URLs and tone stayed on parity and the SEO already earned survived the switch.

  • Back office built on Server Actions

    A bespoke admin covering vehicles and galleries, brands, collections, bookkeeping, leads, valuations, users and site settings. Every mutation is a Next Server Action validated with Zod — no intermediate REST layer.

  • Role-based admin access

    Auth.js v5 with credentials over bcrypt and a JWT session, split into two roles (owner and admin). Login returns the same message whether the email does not exist or the password is wrong, so accounts cannot be enumerated, and password resets go out by email through Resend.

  • Drizzle ORM over PostgreSQL

    Fully typed schema with Drizzle (vehicles, images, brands, transactions, collections, leads, valuations, settings, audit) with versioned migrations plus database snapshot and import utilities.

  • Images on Cloudinary

    Vehicle photos upload to Cloudinary through a dedicated preset and are served optimised via next-cloudinary, so detail pages stay fast even with long galleries.

  • End-to-end lead capture

    Contact and free-valuation forms use React Hook Form + Zod, are rate limited, notify the dealership by email and land as manageable records in the admin panel.

  • Read-only deployment mode

    One environment variable (ADMIN_READONLY) freezes the admin: the public site and its forms keep working, but every mutation is ignored and flagged with a banner. Built so the site stays up if the client ever moves hosting.

  • Traceability and SEO

    Audit events record admin actions, while the public side is server-rendered with code-generated metadata, sitemap and robots.