Skip to content

Bloc 95 — 📱 Manifeste PWA + icônes mobiles (audit SEO F1) - #120

Merged
magicgg91 merged 2 commits into
devfrom
claude/bloc-95-pwa
Sep 8, 2026
Merged

magicgg91 merged 2 commits into
devfrom
claude/bloc-95-pwa

Conversation

@magicgg91

@magicgg91 magicgg91 commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Ce qui change

ML-Helper devient installable sur l'écran d'accueil d'un téléphone : icône, nom court, ouverture en plein écran sans barre d'adresse. Reprend le point F1 de l'audit SEO (Bloc 91), volontairement différé jusqu'ici.

  • src/app/icon.png — 192Ă—192 (23 Ko)
  • src/app/apple-icon.png — 512Ă—512 (136 Ko)
  • src/app/manifest.ts — servi en /manifest.webmanifest
  • src/app/[locale]/manifest.webmanifest/route.ts — un manifeste par langue (voir la revue Codex plus bas)
  • src/lib/web-manifest.ts — la partie du manifeste identique dans les 5 langues

Les deux noms de fichiers d'icônes sont les conventions que Next.js détecte pour émettre <link rel="icon"> et <link rel="apple-touch-icon">.

⚠️ Écarts au brief, vérifiés

1. La route. Le brief indique que src/app/manifest.ts est servi en /manifest.json. C'est /manifest.webmanifest — route confirmée par la sortie de build. Seul un fichier statique manifest.json serait servi en .json ; la convention .ts émet toujours .webmanifest.

Sans conséquence sur l'installabilité : Next injecte <link rel="manifest"> vers cette route, et les navigateurs suivent ce lien au lieu de deviner un nom de fichier. Le test e2e lit d'ailleurs l'URL depuis la balise plutôt que de la coder en dur — ce qui lui fait aussi remarquer un éventuel déplacement de route. Dis-moi si tu veux quand même un alias /manifest.json.

2. Le nom affiché, suite à la revue Codex. Le name du brief (« ML-Helper — Outils Million Lords ») était figé en français pour les 5 langues, alors que c'est le libellé que l'invite d'installation affiche — donc du texte visible qui doit passer par next-intl (AGENTS.md). Il vient maintenant de Public.meta.siteTitle, le nom du site déjà traduit dans les 5 fichiers de messages : en FR l'app s'appelle donc « ML-Helper — Outils et guides Million Lords ». J'ai préféré réutiliser cette clé plutôt qu'en créer une seconde quasi identique à traduire 5 fois — dis-moi si tu veux exactement le libellé du brief à la place.

Concrètement : la convention app/manifest n'existe qu'à la racine et produit un document statique unique, qui ne peut pas varier par visiteur. Elle garde donc le libellé anglais (le repli documenté par la même ligne d'AGENTS.md) et couvre les routes non préfixées (/admin, /login) ; chaque langue sert le sien via /[locale]/manifest.webmanifest, prérendu, vers lequel generateMetadata du layout de locale fait pointer son <link rel="manifest">. Tout ce qui ne dépend pas de la langue vient d'un seul buildWebManifest, pour que les deux entrées ne divergent pas.

Décisions prises

Encodage en palette plutôt qu'en RGB. 136 Ko au lieu de 475 Ko pour le 512 — non négligeable pour un fichier récupéré au moment de l'installation. Erreur de quantification mesurée à RMSE 2,0/255 (moins de 1 %), puis vérifiée à l'œil : aucune bande visible dans les dégradés dorés ni sur le fond bleu nuit.

Pas de purpose: "maskable". Le blason occupe ~83 % du carré, au-delà de la zone sûre de 80 % à laquelle Android recadre une icône maskable — le déclarer en rognerait les bords. Un test épingle ce choix pour qu'il ne soit pas ajouté par réflexe plus tard.

Couleurs reprises des jetons, pas inventées. background_color = --bg (#1b2029), le fond du thème sombre, pour que l'écran de démarrage corresponde à ce qui s'affiche juste après ; theme_color = --accent (#8b6bb8, résolu à travers son alias var(--violet)), qui teinte l'interface du navigateur. Si tu préfères une barre d'état qui se fond dans le fond sombre plutôt qu'une teinte violette, c'est une ligne à changer.

start_url: "/" et non /fr. src/proxy.ts redirige la racine nue vers la langue du visiteur : l'app installée n'est donc pas figée sur la locale du jour de l'installation.

Tests

15 tests unitaires (src/app/manifest.test.ts) : champs attendus, tailles PNG lues dans le chunk IHDR des fichiers réels (la taille annoncée est comparée aux octets, pas à elle-même), absence de maskable, couleurs comparées aux jetons de globals.css (un changement de palette ne peut pas laisser ce fichier en arrière), et le manifeste de chacune des 5 locales. Le mock next-intl lit les vrais messages/*.json, donc le nom servi est comparé aux vraies traductions. Contre-vérifié dans les deux sens : désaccorder theme_color rougit ; recoder un nom en dur rougit 6 tests.

4 tests e2e : balise <link rel="manifest"> présente et manifeste servi valide (content-type manifest+json compris), chaque locale lie le sien et trois locales donnent trois noms différents, les 2 icônes servies aux dimensions qu'elles annoncent (dimensions relues dans les octets servis), et apple-touch-icon exposée pour iOS.

Validation

  • pnpm lint + typecheck : propres
  • pnpm test : 1261 tests verts
  • pnpm build : succès — routes /manifest.webmanifest, les 5 /[locale]/manifest.webmanifest prĂ©rendues, /icon.png, /apple-icon.png confirmĂ©es
  • pnpm test:e2e : 85/85 verts (3,9 min)

🤖 Generated with Claude Code

https://claude.ai/code/session_01HJgsDSfsCbbn8cochFGwe2


Generated by Claude Code

ML-Helper devient installable sur l'écran d'accueil d'un téléphone :
icône, nom court, ouverture en plein écran sans barre d'adresse.

Icônes générées depuis l'image source fournie (1254×1254) avec sharp :
src/app/icon.png (192Ă—192) et src/app/apple-icon.png (512Ă—512), les deux
conventions de nommage que Next.js détecte pour émettre <link rel="icon">
et <link rel="apple-touch-icon">.

Encodage en palette plutĂ´t qu'en RGB : 136 Ko au lieu de 475 Ko pour le
512, pour une erreur de quantification mesurée à 2,0/255 (RMSE, soit
moins de 1 %) et vérifiée à l'œil — aucune bande visible dans les
dégradés dorés ni sur le fond bleu nuit.

Les icônes ne sont volontairement PAS déclarées `maskable` : le blason
occupe ~83 % du carré, au-delà de la zone sûre de 80 % à laquelle Android
recadre une icĂ´ne maskable, ce qui en rognerait les bords.

Couleurs reprises des jetons du site, pas inventées : background_color
= --bg (#1b2029), le fond du thème sombre, pour que l'écran de démarrage
corresponde à ce qui s'affiche juste après ; theme_color = --accent
(#8b6bb8, résolu à travers son alias var(--violet)). Un test les compare
Ă  globals.css, donc un changement de palette ne peut pas laisser ce
fichier en arrière — contre-vérifié en désaccordant la valeur.

start_url vaut "/" et non "/fr" : src/proxy.ts redirige la racine nue
vers la langue du visiteur, donc l'app installée n'est pas figée sur une
locale au moment de l'installation.

⚠️ Écart au brief, vérifié : le brief indique que Next.js sert
src/app/manifest.ts en /manifest.json. C'est /manifest.webmanifest — la
route confirmée par la sortie de build (seul un fichier statique
manifest.json serait servi en .json). Sans conséquence sur
l'installabilité : Next injecte <link rel="manifest"> vers cette route et
les navigateurs suivent ce lien au lieu de deviner un nom de fichier. Le
test e2e lit d'ailleurs l'URL depuis la balise plutĂ´t que de la coder en
dur, ce qui lui fait aussi remarquer un déplacement de route.

Tests : 6 tests unitaires (champs, couleurs liées aux jetons CSS, tailles
PNG lues dans le chunk IHDR, absence de maskable) et 3 tests e2e (balise
link + manifeste servi et valide, les 2 icĂ´nes servies aux dimensions
qu'elles annoncent, apple-touch-icon exposée).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgsDSfsCbbn8cochFGwe2

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

đź’ˇ Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e222670846

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/app/manifest.ts Outdated
Le `name` du manifeste est le texte que l'invite d'installation affiche —
donc du texte visible par l'utilisateur, qui doit passer par next-intl
(AGENTS.md) au lieu d'être figé en français pour les 5 langues.

Le nom réutilise `Public.meta.siteTitle`, le nom du site déjà traduit dans
les 5 fichiers de messages — pas de nouvelle clé quasi-dupliquée.

La convention de fichier `app/manifest` n'existe qu'Ă  la racine et produit
un document statique unique, qui ne peut pas varier par visiteur : elle
garde donc le libellé anglais (le repli documenté) et couvre les routes non
préfixées (/admin, /login). Chaque langue sert le sien via une route
`/[locale]/manifest.webmanifest` prérendue, vers laquelle le layout de
locale pointe par `generateMetadata` — vérifié sur le HTML rendu en e2e.
Tout ce qui ne dépend pas de la langue vient d'un seul `buildWebManifest`,
pour que les deux entrées ne divergent pas.

Tests : le mock next-intl des tests unitaires lit les vrais fichiers
`messages/*.json`, donc les assertions comparent le nom servi aux vraies
traductions ; un nom figé fait rougir 6 tests (vérifié en le recodant en
dur). E2E : chaque locale lie bien son propre manifeste et trois locales
donnent trois noms différents.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HJgsDSfsCbbn8cochFGwe2
@magicgg91
magicgg91 merged commit 3ffceda into dev Sep 8, 2026
2 checks passed
@magicgg91
magicgg91 deleted the claude/bloc-95-pwa branch September 8, 2026 22:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants