
Capabilities
- Back office
- Audit log
- CDN images
- Transactional email
Frontend
Backend
LopezCars
CompletedLó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

Desktop 
Mobile
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.