Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,9 @@ plein ont tous les deux été essayés et jugés trop nets avant ça.
Les PDF portent des métadonnées (titre, auteur, langue) posées par
`scripts/generate-pdf.js` via `pdf-lib`. Titres ≤ 60 caractères,
descriptions ≤ 160 (Google coupe au-delà ; textes de la mission SEO du
24/09/2026 dans `PROFILE.seo` et `results.metaDescription`) ; `favicon.ico`
24/09/2026 dans `PROFILE.seo` et `results.metaDescription`, suffixe des
pages projet et description FR de l'accueil raccourcis le 25/09 avec
l'accord d'Antoine), vérifiés sans exception par `check-seo.mjs` ; `favicon.ico`
multi-tailles à la racine, rendu depuis `assets/favicon.svg`.
- **Site considéré fonctionnellement complet** (sept. 2026) : bilingue,
PDF, Fit-Checker IA, hero cliquable + études de cas STAR, side project
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,9 @@ détail ne demande de toucher qu'à `data.js`, jamais à
le projet en ligne) comme d'habitude.
2. Ajoute une clé correspondante dans `PROJECT_DETAILS` (juste après
`SIDE_PROJECTS` dans `data.js`) : le plus simple est de **copier l'entrée
`tour-de-growth` et de remplacer les textes**. Champs : `title`,
`tour-de-growth` et de remplacer les textes**. Champs : `title` (le titre
de l'onglet devient « <title> — étude de cas · Antoine Berthaud », 60
caractères au plus : un nom de projet de plus de 26 caractères dépasse),
`tagline`, `metaDescription` (`{fr, en}`, 160 caractères au plus : ce
que Google affiche), `liveUrl`, `problem`, `whatItIs` (+ `whatItIsPoints` et
`whatItIsClosing` optionnels), `teachingMoment` (optionnel, `{title,
Expand Down
8 changes: 4 additions & 4 deletions en/projects/tour-de-growth.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
entièrement générées : on ne modifie que ce gabarit (structure) et
data.js / i18n.js (textes). Titre, description et og:/twitter: sont posés
par le générateur dans la langue de la page. -->
<title>Tour de Growth — case study · Antoine Berthaud, Product Manager</title>
<title>Tour de Growth — case study · Antoine Berthaud</title>
<meta name="description" content="Tour de Growth, a side project by Antoine Berthaud: a check-up that maps your growth strategy onto the 5 AARRR pillars, no jargon. Product approach and stack.">

<!-- URL canonique, versions linguistiques, og:url, og:locale : zone générée. -->
Expand All @@ -24,15 +24,15 @@
<!-- /static:langLinks -->

<meta property="og:type" content="article">
<meta property="og:title" content="Tour de Growth — case study · Antoine Berthaud, Product Manager">
<meta property="og:title" content="Tour de Growth — case study · Antoine Berthaud">
<meta property="og:description" content="Tour de Growth, a side project by Antoine Berthaud: a check-up that maps your growth strategy onto the 5 AARRR pillars, no jargon. Product approach and stack.">
<meta property="og:image" content="https://cv.antoine.berthaud.me/assets/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="article:author" content="https://www.linkedin.com/in/antoine-berthaud-pm/">

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Tour de Growth — case study · Antoine Berthaud, Product Manager">
<meta name="twitter:title" content="Tour de Growth — case study · Antoine Berthaud">
<meta name="twitter:description" content="Tour de Growth, a side project by Antoine Berthaud: a check-up that maps your growth strategy onto the 5 AARRR pillars, no jargon. Product approach and stack.">
<meta name="twitter:image" content="https://cv.antoine.berthaud.me/assets/og-image.png">

Expand All @@ -48,7 +48,7 @@
"@type": "WebPage",
"@id": "https://cv.antoine.berthaud.me/en/projects/tour-de-growth.html#page",
"url": "https://cv.antoine.berthaud.me/en/projects/tour-de-growth.html",
"name": "Tour de Growth — case study · Antoine Berthaud, Product Manager",
"name": "Tour de Growth — case study · Antoine Berthaud",
"description": "Tour de Growth, a side project by Antoine Berthaud: a check-up that maps your growth strategy onto the 5 AARRR pillars, no jargon. Product approach and stack.",
"inLanguage": "en",
"author": {
Expand Down
8 changes: 4 additions & 4 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
lisent les robots sans JavaScript ; app.js ne les touche plus que s'ils
diffèrent de data.js (page pas encore régénérée, signalée en console). -->
<title>Antoine Berthaud · Senior Product Manager Growth à Nantes</title>
<meta name="description" content="CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery, data.">
<meta name="description" content="CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery.">

<!-- URL canonique, versions linguistiques et og:url/og:locale : le français
à la racine (langue par défaut, x-default), l'anglais sous /en/. Chaque
Expand Down Expand Up @@ -54,7 +54,7 @@
"name": "CV d'Antoine Berthaud — Senior Product Manager à Nantes",
"inLanguage": "fr",
"dateCreated": "2026-08-22",
"dateModified": "2026-09-24",
"dateModified": "2026-09-25",
"mainEntity": {
"@type": "Person",
"@id": "https://cv.antoine.berthaud.me/#person",
Expand Down Expand Up @@ -145,14 +145,14 @@
<meta property="profile:first_name" content="Antoine">
<meta property="profile:last_name" content="Berthaud">
<meta property="og:title" content="Antoine Berthaud · Senior Product Manager Growth à Nantes">
<meta property="og:description" content="CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery, data.">
<meta property="og:description" content="CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery.">
<meta property="og:image" content="https://cv.antoine.berthaud.me/assets/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Antoine Berthaud · Senior Product Manager Growth à Nantes">
<meta name="twitter:description" content="CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery, data.">
<meta name="twitter:description" content="CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery.">
<meta name="twitter:image" content="https://cv.antoine.berthaud.me/assets/og-image.png">

<!-- Analytics respectueux de la vie privée (GoatCounter) — pas de cookies,
Expand Down
5 changes: 3 additions & 2 deletions js/data.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,13 +74,14 @@ const PROFILE = {
// en/index.html (titre, description, og:, twitter:) par
// scripts/generate-static.js : rien à recopier à la main.
seo: {
// 60 caractères au plus : Google coupe au-delà (mission SEO, sept. 2026).
// Titre : 60 caractères au plus, description : 160 (Google coupe au-delà ;
// mission SEO, sept. 2026). check-seo.mjs le vérifie.
title: {
fr: "Antoine Berthaud · Senior Product Manager Growth à Nantes",
en: "Antoine Berthaud · Senior Growth Product Manager, Nantes",
},
description: {
fr: "CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery, data.",
fr: "CV d'Antoine Berthaud, Senior Product Manager à Nantes : 10 ans de produit en SaaS B2B et grands comptes (AB Tasty, Everysens, SNCF). Growth, PLG, discovery.",
en: "Antoine Berthaud's CV, Senior Product Manager in Nantes: 10 years in B2B SaaS and enterprise product (AB Tasty, Everysens, SNCF). Growth, PLG, discovery, data.",
},
},
Expand Down
5 changes: 3 additions & 2 deletions js/i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,9 @@
"projectDetail.stack.seo": { fr: "SEO", en: "SEO" },
"projectDetail.stack.ops": { fr: "Ops", en: "Ops" },
"projectDetail.notFound": { fr: "Projet introuvable.", en: "Project not found." },
// Suffixe du <title> d'une page d'étude de cas : "Tour de Growth — étude de cas · Antoine Berthaud, Product Manager"
"projectDetail.metaTitleSuffix": { fr: "étude de cas · Antoine Berthaud, Product Manager", en: "case study · Antoine Berthaud, Product Manager" },
// Suffixe du <title> d'une page d'étude de cas : "Tour de Growth — étude de cas · Antoine Berthaud"
// (60 caractères au plus avec le nom du projet ; check-seo.mjs le vérifie).
"projectDetail.metaTitleSuffix": { fr: "étude de cas · Antoine Berthaud", en: "case study · Antoine Berthaud" },

"results.eyebrow": { fr: "Études de cas · Product Manager", en: "Case studies · Product Manager" },
// <title> et <meta name="description"> de results.html, par langue.
Expand Down
8 changes: 4 additions & 4 deletions projets/tour-de-growth.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
entièrement générées : on ne modifie que ce gabarit (structure) et
data.js / i18n.js (textes). Titre, description et og:/twitter: sont posés
par le générateur dans la langue de la page. -->
<title>Tour de Growth — étude de cas · Antoine Berthaud, Product Manager</title>
<title>Tour de Growth — étude de cas · Antoine Berthaud</title>
<meta name="description" content="Tour de Growth, side project d'Antoine Berthaud : un check-up qui situe sa stratégie growth sur les 5 piliers AARRR, sans jargon. Démarche produit et stack.">

<!-- URL canonique, versions linguistiques, og:url, og:locale : zone générée. -->
Expand All @@ -24,15 +24,15 @@
<!-- /static:langLinks -->

<meta property="og:type" content="article">
<meta property="og:title" content="Tour de Growth — étude de cas · Antoine Berthaud, Product Manager">
<meta property="og:title" content="Tour de Growth — étude de cas · Antoine Berthaud">
<meta property="og:description" content="Tour de Growth, side project d'Antoine Berthaud : un check-up qui situe sa stratégie growth sur les 5 piliers AARRR, sans jargon. Démarche produit et stack.">
<meta property="og:image" content="https://cv.antoine.berthaud.me/assets/og-image.png">
<meta property="og:image:width" content="1200">
<meta property="og:image:height" content="630">
<meta property="article:author" content="https://www.linkedin.com/in/antoine-berthaud-pm/">

<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:title" content="Tour de Growth — étude de cas · Antoine Berthaud, Product Manager">
<meta name="twitter:title" content="Tour de Growth — étude de cas · Antoine Berthaud">
<meta name="twitter:description" content="Tour de Growth, side project d'Antoine Berthaud : un check-up qui situe sa stratégie growth sur les 5 piliers AARRR, sans jargon. Démarche produit et stack.">
<meta name="twitter:image" content="https://cv.antoine.berthaud.me/assets/og-image.png">

Expand All @@ -48,7 +48,7 @@
"@type": "WebPage",
"@id": "https://cv.antoine.berthaud.me/projets/tour-de-growth.html#page",
"url": "https://cv.antoine.berthaud.me/projets/tour-de-growth.html",
"name": "Tour de Growth — étude de cas · Antoine Berthaud, Product Manager",
"name": "Tour de Growth — étude de cas · Antoine Berthaud",
"description": "Tour de Growth, side project d'Antoine Berthaud : un check-up qui situe sa stratégie growth sur les 5 piliers AARRR, sans jargon. Démarche produit et stack.",
"inLanguage": "fr",
"author": {
Expand Down
12 changes: 3 additions & 9 deletions scripts/check-seo.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -849,17 +849,11 @@ async function lot4(browser) {
const cp = ld && ld["@graph"].find((n) => n["@type"] === "CollectionPage");
check(4, "4.1-description", `${pg.path} : description de la mission dans la meta, og:, twitter: et le JSON-LD`, info.description === d && sameDesc(d) && cp && cp.description === d && cp.name === info.title, `${(info.description || "").length} car.`);
}
// Longueurs. Les textes que la mission a fixés doivent tenir ; ceux
// qu'elle ne fournit pas (titre des pages projet, description de
// l'accueil) sont signalés sans faire échouer, en attendant une décision.
const fixedTitle = pg.kind === "home" || pg.kind === "results";
const fixedDesc = pg.kind === "results" || pg.kind === "project";
// Longueurs : tous les titres et descriptions doivent tenir.
const tl = info.title.length,
dl = (info.description || "").length;
if (tl <= MAX_TITLE || fixedTitle) check(4, "4.1-len-title", `${pg.path} : titre ≤ ${MAX_TITLE} caractères`, tl <= MAX_TITLE, `${tl} car.`);
else skip(4, "4.1-len-title", `${pg.path} : titre ≤ ${MAX_TITLE} caractères`, `⚠ ${tl} car. — texte hors mission, à décider (voir le rapport)`);
if (dl <= MAX_DESCRIPTION || fixedDesc) check(4, "4.1-len-desc", `${pg.path} : description ≤ ${MAX_DESCRIPTION} caractères`, dl <= MAX_DESCRIPTION, `${dl} car.`);
else skip(4, "4.1-len-desc", `${pg.path} : description ≤ ${MAX_DESCRIPTION} caractères`, `⚠ ${dl} car. — texte hors mission, à décider (voir le rapport)`);
check(4, "4.1-len-title", `${pg.path} : titre ≤ ${MAX_TITLE} caractères`, tl <= MAX_TITLE, `${tl} car.`);
check(4, "4.1-len-desc", `${pg.path} : description ≤ ${MAX_DESCRIPTION} caractères`, dl <= MAX_DESCRIPTION, `${dl} car.`);
}
await rawCtx.close();

Expand Down
6 changes: 3 additions & 3 deletions sitemap.xml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
<!-- static:pages -->
<url>
<loc>https://cv.antoine.berthaud.me/</loc>
<lastmod>2026-09-24</lastmod>
<lastmod>2026-09-25</lastmod>
<xhtml:link rel="alternate" hreflang="fr" href="https://cv.antoine.berthaud.me/"/>
<xhtml:link rel="alternate" hreflang="en" href="https://cv.antoine.berthaud.me/en/"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://cv.antoine.berthaud.me/"/>
Expand Down Expand Up @@ -41,14 +41,14 @@
</url>
<url>
<loc>https://cv.antoine.berthaud.me/projets/tour-de-growth.html</loc>
<lastmod>2026-09-24</lastmod>
<lastmod>2026-09-25</lastmod>
<xhtml:link rel="alternate" hreflang="fr" href="https://cv.antoine.berthaud.me/projets/tour-de-growth.html"/>
<xhtml:link rel="alternate" hreflang="en" href="https://cv.antoine.berthaud.me/en/projects/tour-de-growth.html"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://cv.antoine.berthaud.me/projets/tour-de-growth.html"/>
</url>
<url>
<loc>https://cv.antoine.berthaud.me/en/projects/tour-de-growth.html</loc>
<lastmod>2026-09-24</lastmod>
<lastmod>2026-09-25</lastmod>
<xhtml:link rel="alternate" hreflang="fr" href="https://cv.antoine.berthaud.me/projets/tour-de-growth.html"/>
<xhtml:link rel="alternate" hreflang="en" href="https://cv.antoine.berthaud.me/en/projects/tour-de-growth.html"/>
<xhtml:link rel="alternate" hreflang="x-default" href="https://cv.antoine.berthaud.me/projets/tour-de-growth.html"/>
Expand Down
Loading