CakePHP → Next.js migration: how we relaunched nova-fit.ro without losing anything
A gym website on a 2015-era stack, fully moved to Next.js: performance score from 25 to 97, LCP from 8s to 2.6s, same URLs, zero mail downtime and a custom admin. The full story, with real numbers.

NovaFit, the Câmpina fitness club we built the presentation website for, was running on CakePHP 2.6 + Croogo CMS — a 2015-era stack, on PHP that no longer receives security updates. The site did its job, but it was aging badly: mobile performance score 25/100, an 8-second LCP, layout jumping around on load (CLS 0.5) and a CMS nobody dared touch anymore.
We moved it entirely to Next.js 16 + Tailwind + MongoDB Atlas, keeping the design, the content and — critically for SEO — every URL. Here's what we actually did and how it turned out.
The audit: what you find in a 10-year-old CakePHP
Before writing a single line of code, we did recon on the whole legacy project. We found what you usually find in inherited codebases:
- an unused e-commerce schema — a shop built at some point, disabled in the UI, but carried along on every request
- payment private keys committed to the repo — the mobilPay certificates, private key included, in Git
- demo content mixed with real content — 12 test products next to the real legal pages
- zero analytics, zero structured data, missing meta descriptions
That audit decided the scope: we don't port everything, we port what's alive — the real pages, the real membership plans, the visual identity — and cut the rest.
Visual fidelity, new stack
The client loved the existing design (rightly so — the hero with athlete cutouts on pink shapes is memorable). So we didn't "redesign", we rebuilt it faithfully in Tailwind + shadcn/ui: the mouse-parallax slider (no Slider Revolution, no jQuery — just CSS variables + requestAnimationFrame), the BMI calculator, the services and gallery sections.
The difference is under the hood: zero Bootstrap, zero jQuery, zero slider libraries — the JavaScript bundle is a fraction of what it was, and images went from 13MB to 2.3MB (resizing + recompression + WebP for cutouts).
SEO: same URLs or a 301
The golden rule of migrations: you don't lose a single indexed URL. Pages we kept stayed on the same paths, and everything restructured (including new localized URLs like /termeni-si-conditii instead of /page/terms-and-conditions) gets a 301 redirect from the old path. We added a database-generated sitemap, JSON-LD (HealthClub, with address and hours), Open Graph and a robots.txt with Content-Signal — the site is ready for AI crawlers too.
The product decision: no online payments, vetted signups
My favourite part of this project isn't technical. The gym had problems with bogus signups, so together with the owner we replaced the classic checkout with a membership application flow: the visitor applies (name, phone, social profile link), the owner manually vets the application in the admin, and the membership is finalized at the gym. Declined applications block re-applying.
Good technology doesn't always mean "more features" — sometimes it means exactly the right feature.
Custom admin, notifications, infrastructure
- Custom admin (replacing Croogo): membership applications with approve/decline, contact form messages, plans with custom periods and student pricing, an editor for the legal pages
- Email notifications via Resend, with a branded HTML template and the logo embedded inline (CID — no "blocked images" in webmail)
- Images on S3, database on MongoDB Atlas, deployed on Vercel
- DNS moved to Cloudflare while fully preserving the existing mail setup (MX, SPF, DKIM) — zero minutes of email downtime on launch day
The results, measured
Plus what the numbers don't show: security updates that are current, deploys in minutes instead of FTP, and an admin the owner can actually work in.
See the original design project too: NovaFit — presentation website.
Running a site on an aging stack? Get a quote — we audit first, then talk migration. See our services too.