SPEC — Correction Composant 2 : Blog Listing + Typage
SPEC — Correction Composant 2 : Blog Listing + Typage
Documentation technique
Cycle : DOC → SPEC → CODE → TEST
Scope : 3 corrections ciblées, sans refonte complète
Statut : En attente d’approbation avant CODE
1. Problème 1 — blog/index.astro ne lit pas depuis Sanity [BLOQUANT]
1.1 Situation actuelle
// blog/index.astro — ACTUEL (INCORRECT)const posts = (await getCollection('blog')).sort(...)// → Lit des fichiers Markdown locaux, pas Sanity1.2 Correction ciblée1/2
Fichier : apps/web/src/pages/blog/index.astro
Changements :
- Remplacer
getCollection('blog')parloadQuery()avec GROQ - Conserver
export const prerender = false(SSR — même raison queindex.astro: accès cookies pour Visual Editing) - Garder le même template HTML (juste changer la source de données)
- Utiliser
MainLayoutà la place du layout inline actuel (cohérence avec le reste)
1.2 Correction ciblée2/2
Query GROQ (triée par publishedAt desc, même ordre que le tri actuel par date) :
*[_type == "post"] | order(publishedAt desc) { _id, _type, title, slug, publishedAt, mainImage { asset->{ _id, url, metadata { lqip, dimensions } }, alt }, author->{ _id, name }, categories[]->{ _id, title }}Type de retour : PostListItem[] (type local défini dans le fichier)
2. Problème 2 — Typage as any dans blog/[slug].astro [NON BLOQUANT]
2.1 Situation actuelle
// blog/[slug].astro — ACTUEL (INCORRECT)const { data: post } = await loadQuery({...})// → post est `unknown`, tout casté `as any`2.2 Correction ciblée1/2
Fichier : apps/web/src/pages/blog/[slug].astro
Changements :
- Définir un type local
SanityPostqui reflète exactement la projection GROQ existante - Passer le type générique à
loadQuery<SanityPost>({...}) - Remplacer les
(post as any)?.xparpost?.x - Pas de changement fonctionnel — uniquement typage
2.2 Correction ciblée2/2
Note : On n’importe pas Post depuis apps/studio/sanity.types.ts car le type brut ne correspond pas à la projection GROQ (les références sont résolues via -> dans la query). On définit un type local correspondant exactement à la projection.
3. Problème 3 — SEO description = titre [NON BLOQUANT]
3.1 Situation actuelle
// blog/[slug].astro ligne 142 — ACTUEL (INCORRECT)description={(post as any)?.title || contentPost?.data.title}// → description SEO = titre de l'article3.2 Correction ciblée1/2
Fichier : apps/web/src/pages/blog/[slug].astro
Changements :
- Ajouter un champ
excerpt(string, optionnel) au schéma Sanitypost.ts - Ajouter
excerptà la query GROQ de[slug].astro - Utiliser
post?.excerptcomme description, fallback sur le titre - Régénérer
sanity.types.tsavectask typegen(si disponible) ou manuellement
3.2 Correction ciblée2/2
Schéma Sanity (apps/studio/schemaTypes/post.ts) :
defineField({ name: 'excerpt', title: 'Excerpt', type: 'text', rows: 3, description: 'Short description for SEO and listing previews',}),4. Ordre d’implémentation
- Problème 3d (schéma Sanity
excerpt) — d’abord car ça touche le studio - Problème 1 (
blog/index.astro→ Sanity) — correction principale - Problème 2 (typage
[slug].astro) — amélioration qualité
5. Ce qu’on ne touche PAS
loadQuery.ts— fonctionne parfaitement, pas de changementMainLayout.astro— pas de changementBlogPost.astrolayout — conservé pour le fallback content collections- Le fallback content collections dans
[slug].astro— conservé (utile en dev) astro.config.mjs— pas de changement
6. Critères de validation (TEST)
-
curl http://localhost:4321/blog/liste les posts Sanity (pas les Markdown) - Les posts Sanity ont titre, date, auteur, image visible dans le listing
-
curl http://localhost:4321/blog/<slug-sanity>affiche l’article complet - La
<meta name="description">contient l’excerpt, pas le titre -
task typecheck→ 0 erreurs - Pas de régression sur les posts Markdown (fallback dans
[slug].astro)