Shipping a Bilingual Marketing Site That a Quebec Team Can Own
Roofing and solar buyers don't read marketing copy linearly. They scan for trust signals, hours, and 'does this person know what I have on my roof?' The AL Pro build is tuned for that, bilingual, scannable, and SEO-hardened against AI-driven audits.

Quebec roofing buyers behave differently from the marketing-blog stereotype. They're scanning the page for: do you understand my building, do you serve my city, can I get a feasibility study, and is your French copy actually French or is it Google Translate.
Why I built it
The existing site was a WordPress theme with a French toggle that was 80% English under the hood. The contact form lived three clicks away from the hero. The audit tool the team paid for scored the site 61/100 and listed missing structured data, missing meta, and thin content on pages that visibly had content. I took the project to rebuild the front end as a bilingual SPA with proper prerendering, then bolt WordPress back on for the blog only.
What it does
The site is a bilingual marketing front for a roofing and solar contractor serving Greater Montreal. It surfaces services per building type, lists past projects per city, and routes every CTA to a single feasibility-study form that captures roof type, square footage, and target install window.
- Bilingual EN/FR routes with locale-aware metadata and hreflang.
- Per-city service pages, each with its own areaServed schema.
- Project gallery filtered by building type (residential, commercial, industrial).
- Lead form that posts to the team's CRM with the form locale attached.
- WordPress headless feed for blog posts, queried at build time.

Architecture decisions
A React SPA built on Vite gave the brand the animations and the lead-capture polish they wanted, while a WordPress integration on the side gives the team a friendly content workflow for blog posts and updates. The split (SPA for the hero/services/projects, WordPress for evolving content) keeps the marketing site fast without making the team learn React.
I picked Vite over Next because the team did not want server hosting and was happy on a static CDN. Prerendering via vite-plugin-prerender writes one HTML file per route, including French variants, so a crawler that never executes JavaScript still sees the full page. WordPress runs on its own subdomain and is pulled in at build time via the REST API, so the production site has zero runtime dependency on the CMS being up.
The SEO audit that retargeted the build
An external auditor scored the site 61/100, with most of the points lost on items that were actually present but invisible to a non-JS crawler. The fix wasn't to argue with the audit, it was to make sure a re-audit could find the content without executing JavaScript. I added per-route prerendering, a noscript layer with real content, FAQPage and BlogPosting JSON-LD, an OfferCatalog of services with city-level areaServed, and a sitemap that regenerates from blog data at build time.
Estimated score after the rework: 92 to 96. The bigger lesson: AI-driven audit tools read the rendered HTML, not the React shell. If you want them to grade you on what's actually on your site, you have to ship the content in the HTML.

What was hard
Bilingual routing was the part I underestimated. Every page had to exist twice with stable URLs (/services/toiture and /en/services/roofing), and the language switcher had to land on the equivalent page, not the home. I ended up keeping a small route map keyed by a stable slug so the toggle knows that /projets/montreal maps to /en/projects/montreal even when the localized slugs diverge.
The other hard part was getting the WordPress feed and the prerender step to agree on timing. The prerender runs during the build, so a blog post published five minutes after a deploy would not appear until the next build. I added a webhook on the WordPress side that triggers a redeploy when a post is published, which keeps the static site within a few minutes of the CMS.
What I learned
Auditors and search engines do not reward intent, they reward bytes. The same content that scored 61 in a React shell scored in the low 90s once it was sitting in the prerendered HTML. The second lesson is that French copy written by a native Quebec speaker reads completely differently from translated marketing English, and the lead form completion rate on the French side noticeably tracks that quality.
What's next
- Per-city landing pages prerendered from a single template, one per service area.
- A solar savings calculator that posts the result into the feasibility form.
- A CRM webhook that scores leads by city and roof type before they hit the inbox.
- A re-audit pass to confirm the estimated 92 to 96 score in the real tool.

Five MCP Tools That See a Pregnancy as One Clinical Unit
Winner of Prompt Opinion's Agents Assemble: The Healthcare AI Endgame, out of 4,335 participants. US maternal mortality keeps rising and over 80% of pregnancy-related deaths are preventable, but the predictive signals live across completely different parts of the chart. I built an MCP server that aggregates them, and a Triage agent that delegates to it.

50 Screens, 25 Tables, One Solo Developer, One Month
Building a real social platform for the RevenueCat Shipyard hackathon meant treating it like a startup, not a demo. Swipe-based discovery, real-time chat, convergence detection, RevenueCat-gated features, all behind Supabase Row Level Security.
