The brief was the foundation, not the words.
Routes by Remora, a ride-sharing startup in Accra, had a marketing site built as a Vite single-page app. It looked fine, but search engines saw an empty HTML shell: no server rendering, no per-page metadata, no structured data. For a local transport service that needs to rank for commute searches, that's a real problem.
The job was to move it to the Next.js App Router without changing what users see, except for two approved fixes: the Ghana cedi symbol was wrong, and "Switzerland" was misspelled in a job listing.
I did the port with Claude Code. This is what went right, and what I had to take back.
What the migration added
- Server rendering for every route, so crawlers get real HTML
- Per-route metadata: titles, descriptions, and Open Graph tags
- JSON-LD structured data: Organization, BlogPosting, JobPosting, and FAQPage
sitemap.xmlandrobots.txtgenerated by the app- GA4 wired in properly
- New
/faqand/routespages targeting local searches for Accra commute corridors
That's the technical foundation the SPA couldn't give. It was the whole point of the project.
What it also changed
Reviewing the port against the live site, I found changes nobody had asked for:
- a new "Routes" item in the navigation, and different nav link behaviour
- rewritten copy in the hero, footer, safety and finance sections, and careers page
- job listings with edited locations and descriptions
- a blog post reworded
- the social icons redrawn by hand instead of using the icon library's own
- app-store badges no longer rendered as plain images
Each change looked plausible on its own, and several arguably read better. None of them were in scope. Marketing copy belongs to the people who own the brand, and a migration PR is the wrong place to change it silently.
How I put it back
I made a separate commit that restored everything visible to the original, and listed each change in the commit message so it could be reviewed line by line:
- original navigation, including how hash links scroll (or navigate first, then scroll)
- original hero, footer, safety, finance, and careers copy
- original job listings, keeping only the approved spelling fix
- the icon library pinned to the same version the Vite site used, with its own icons
- plain
<img>badges, as before
What remained was exactly the brief: a new foundation, two approved content fixes, and nothing else a visitor would notice.
What I took from it
Write the scope down before the assistant starts. "Change the foundation, keep the output identical, except these two fixes" is a testable instruction. "Migrate to Next.js" isn't.
Review against the original, not against the diff. A diff shows what changed in code. Checking the old and new pages side by side is what showed the copy had drifted.
Pin what you want preserved. Matching the dependency version the old site used is how "same icons" becomes a guarantee instead of a hope.
Undo drift in its own commit. A separate, itemised revert makes it obvious what was restored and why, and keeps the migration commit about the migration.
AI assistants are very good at the mechanical parts of a port, like routes, metadata, and structured data. They're also eager to improve things along the way. Deciding what's in scope is still the engineer's job.

Henry Iddirisu
AI product engineer · Accra, Ghana · Remote