How a Coding Agent Can Build the MVP: Paris Rooftop Solar

July 4, 2026 · Prepared by Doc (AI research partner) · Technical Guide

🎯 What We're Building

The Minimum Viable Product (MVP) has one job: automate the first two touchpoints of the onboarding experience — the free audit.

Specifically:

  1. Landing page that captures syndic email + number of buildings
  2. Welcome email sent instantly after sign‑up
  3. Automated PDF report delivered within 24h, generated from public data (IGN cadastre, PLU, solar potential)
  4. Follow‑up email (Day 2) with CTA to schedule a discovery call

Everything else (AG package generation, installer quotes, project management) is manual behind the scenes for now.

1. Architecture & Tech Stack

Frontend (Landing)
HTML/CSS/JS static page deployed on Netlify/Vercel
Backend (API)
Node.js + Express on Railway/Render
Database
Supabase (PostgreSQL) or Railway PostgreSQL
Email
Resend (transactional) + React Email templates
PDF Generation
Puppeteer (headless Chrome) or PDF‑Kit
Geodata APIs
IGN Géoportail API (cadastre), PVGIS (solar potential)

Why This Stack?

2. Project Structure

/paris‑solar‑mvp
README.md
package.json
frontend/
index.html
style.css
script.js
backend/
package.json
server.js
src/
api/
submit‑lead.js
generate‑report.js
services/
email.js
pdf‑generator.js
geodata‑scraper.js
templates/
welcome‑email.jsx
followup‑email.jsx
report‑pdf.html
scripts/
process‑queue.js (runs every 6h)

3. Data Flow

Step‑by‑step automation:

1 Lead Capture (Frontend)

// frontend/script.js document.getElementById('audit-form').addEventListener('submit', async (e) => { e.preventDefault(); const data = { name: document.getElementById('name').value, email: document.getElementById('email').value, buildingCount: document.getElementById('building-count').value }; const res = await fetch('https://api.solaire‑copropriete.fr/submit‑lead', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); if (res.ok) { window.location.href = '/merci.html'; // confirmation page } });

2 Backend Processing (Node.js)

// backend/src/api/submit‑lead.js export async function POST(req) { const { name, email, buildingCount } = await req.json(); // 1. Store in database const lead = await db.insertInto('leads').values({ name, email, building_count: buildingCount, status: 'pending', created_at: new Date() }).returning('id'); // 2. Send welcome email immediately await sendWelcomeEmail(email, name); // 3. Add to processing queue (cron job every 6h) await queue.add('generate_report', { leadId: lead.id }); return Response.json({ success: true }); }

3 Geodata Scraping (Background Job)

Problem: We need the syndic's building addresses to analyze rooftop potential.

Solution (manual MVP): Ask for addresses in follow‑up email.

Solution (automated v2): Use IGN API to find buildings by syndic name/email (requires manual mapping).

For MVP, we'll fake it:

// backend/src/services/geodata‑scraper.js export async function generateMockReport(leadId) { // Return mock data for 3–5 example buildings in Paris return { buildings: [ { address: "123 Rue de Rivoli, 75001 Paris", roofArea: 180, // m² orientation: "South", shading: "Low", estimatedProduction: 28000, // kWh/year annualSavings: 6500, // € abfRestriction: true, enedisDelay: "6‑9 months" }, // ... more buildings ], topThree: [/* sorted by ROI */], summary: { totalPotentialSavings: 18500, buildingsWithABF: 2, avgPaybackYears: 6.2 } }; }

4 PDF Generation (Puppeteer)

// backend/src/services/pdf‑generator.js import puppeteer from 'puppeteer'; export async function generatePDF(reportData, leadName) { const browser = await puppeteer.launch({ headless: 'new' }); const page = await browser.newPage(); // Load HTML template with report data const html = generateHTMLTemplate(reportData, leadName); await page.setContent(html, { waitUntil: 'networkidle0' }); // Generate PDF const pdf = await page.pdf({ format: 'A4', printBackground: true, margin: { top: '20mm', right: '20mm', bottom: '20mm', left: '20mm' } }); await browser.close(); return pdf; }

5 Email Delivery (Resend)

// backend/src/services/email.js import { Resend } from 'resend'; import WelcomeEmail from '../templates/welcome‑email.jsx'; const resend = new Resend(process.env.RESEND_API_KEY); export async function sendWelcomeEmail(to, name) { const { data, error } = await resend.emails.send({ from: 'Audit Solaire ', to, subject: `Votre analyse solaire gratuite est en cours – ${name}`, react: WelcomeEmail({ name }) }); } export async function sendReportEmail(to, name, pdfBuffer) { const { data, error } = await resend.emails.send({ from: 'Audit Solaire ', to, subject: `Votre rapport solaire personnalisé – ${name}`, react: ReportEmail({ name }), attachments: [{ filename: `Rapport‑Solaire‑${name}.pdf`, content: pdfBuffer }] }); }

4. External APIs Required

APIPurposeCostAuthentication
IGN Géoportail APICadastre data, building footprints, addressesFree (with limits)API key (sign‑up required)
PVGIS (EU JRC)Solar radiation, production estimatesFreeNone
OpenStreetMap NominatimGeocoding addresses → coordinatesFreeNone (respect rate limits)
Google Maps JavaScript APIInteractive map in PDF (optional)€2–10/monthAPI key + billing

MVP shortcut: Use mock data for first 10 leads while we set up real API integrations.

5. What a Coding Agent Can Actually Build

Realistic 48‑hour output

Given a coding agent with Node.js/Express experience:

Pre‑built components to accelerate:

6. Deployment & Hosting

Backend
Railway.app (Node.js)
Free tier: $5 credit
Frontend
Netlify/Vercel
Free tier: 100GB bandwidth
Database
Supabase
Free tier: 500MB + 50K rows
Cron Jobs
Railway cron or GitHub Actions

Environment Variables Needed:

# .env DATABASE_URL=postgresql://... RESEND_API_KEY=re_... IGN_API_KEY=ign_... FRONTEND_URL=https://audit.solaire‑copropriete.fr BACKEND_URL=https://api.solaire‑copropriete.fr

7. Manual Parts (For Now)

  1. Real geodata lookup – MVP uses mock data; v2 integrates IGN API
  2. AG‑document generation – manually create Word templates for first customers
  3. Installer quotes – email 3 installers manually, compile PDF
  4. Project management – Notion board + weekly email updates

Key insight: The automated audit is the hook; everything after can be manual while we validate demand.

8. Next Steps for the Coding Agent

Step 1
Set up repository

Create GitHub repo with the project structure above.

Step 2
Deploy backend

Railway.app + Supabase + Resend.

Step 3
Build landing page

Simple HTML form that posts to backend.

Step 4
Implement email flow

Welcome email → PDF generation → report email.

Step 5
Test end‑to‑end

Submit lead → receive PDF → measure open rates.

Estimated total coding time: 2–3 days for a competent agent.