ITSkillsCenter
WordPress

Headless CMS : architecture moderne pour contenu

8 min de lecture
Headless CMS : architecture moderne pour contenu

Ce que vous saurez faire

À la fin de ce tutoriel, vous serez en mesure de concevoir et déployer une architecture Headless CMS moderne pour une PME sénégalaise (média, e-commerce, ONG, agence) qui sépare clairement le back-office de gestion de contenu (Strapi, Directus, Payload ou Sanity) du front-end de présentation (Next.js, Astro ou Nuxt). Vous saurez choisir le bon CMS headless selon le budget (gratuit auto-hébergé à 25 000 FCFA/mois en SaaS), modéliser des Content Types souples, exposer une API REST et GraphQL, gérer la diffusion de contenu multilingue (français, wolof, anglais) et le stockage des médias sur un bucket S3 compatible (Backblaze B2 ou Wasabi à 4 USD/To). Vous mettrez en place le rendu statique incrémental (ISR) avec revalidation, le caching CDN via Cloudflare, et un workflow éditorial avec rôles (rédacteur, relecteur, publication). À la fin, votre site charge en moins de 1 seconde sur une connexion 3G dakaroise et tient 100 000 visiteurs/mois pour moins de 18 000 FCFA.

Étape 1 : Comprendre la différence avec un CMS classique

Un CMS traditionnel (WordPress monolithique) couple le contenu, la base de données et la présentation. Un Headless CMS expose UNIQUEMENT une API :

WordPress classique : Admin -> DB -> Theme PHP -> HTML servi
Headless CMS       : Admin -> DB -> API JSON -> Frontend separe (Next.js, mobile, etc.)

Avantages : un même contenu nourrit le site web, l'app mobile, un écran d'affichage en agence, et un export newsletter. Inconvénient : plus complexe à mettre en place pour un éditeur seul.

Étape 2 : Choisir le bon CMS headless

Comparatif honnête pour une PME sénégalaise :

CMS       | Open Source | Hebergement     | Cout/mois    | Difficulte
----------|-------------|-----------------|--------------|------------
Strapi    | Oui         | Auto ou Cloud   | 0 - 60 USD   | Moyenne
Directus  | Oui         | Auto ou Cloud   | 0 - 25 USD   | Facile
Payload   | Oui         | Auto-heberge    | 0            | Moyenne
Sanity    | Non (free)  | SaaS uniquement | 0 - 99 USD   | Facile
Contentful| Non         | SaaS            | 489 USD      | Tres facile

Recommandation : Directus si vous voulez du SQL natif (PostgreSQL existant), Strapi si vous voulez une grosse communauté et plugins, Payload si TypeScript first.

Étape 3 : Installer Strapi en local

Prérequis : Node.js 20+, PostgreSQL 14+. Lancez la commande :

npx create-strapi-app@latest mon-cms --quickstart
cd mon-cms
npm run develop

L'interface admin s'ouvre sur http://localhost:1337/admin. Créez votre compte super-admin avec un mot de passe fort (12+ caractères).

Étape 4 : Modéliser les Content Types

Pour un média en ligne sénégalais, créez via Content-Type Builder :

Article
  - title (Text, requis)
  - slug (UID base sur title)
  - cover (Media, single)
  - body (Rich Text - Markdown)
  - excerpt (Text long, max 250)
  - category (Relation -> Category)
  - tags (Relation many -> Tag)
  - publishedAt (Date)
  - locale (fr, wo, en)

Author
  - name, photo, bio, role
  - articles (Relation reverse)

Activez la publication brouillon/publié et l'internationalisation (i18n) dans les paramètres.

Étape 5 : Configurer les permissions API

Dans Settings > Users & Permissions > Roles > Public :

- Article : find, findOne (autorise)
- Article : create, update, delete (REFUSE)
- Author : find, findOne

Pour le frontend authentifié (admin), créez un rôle "Editor" avec accès complet, puis générez un API Token longue durée dans Settings > API Tokens.

Étape 6 : Tester l'API REST

Vérifiez que l'API répond :

curl http://localhost:1337/api/articles?populate=cover,author
curl http://localhost:1337/api/articles/1?populate=*
curl "http://localhost:1337/api/articles?filters[category][slug][$eq]=politique&sort=publishedAt:desc&pagination[pageSize]=10"

Strapi expose automatiquement aussi GraphQL si vous installez le plugin :

npm install @strapi/plugin-graphql

Étape 7 : Stocker les médias sur S3 compatible

Le filesystem local est insuffisant en production. Configurez Backblaze B2 :

npm install @strapi/provider-upload-aws-s3

Dans config/plugins.js :

module.exports = ({ env }) => ({
  upload: {
    config: {
      provider: 'aws-s3',
      providerOptions: {
        accessKeyId: env('B2_KEY_ID'),
        secretAccessKey: env('B2_APP_KEY'),
        endpoint: env('B2_ENDPOINT'),
        params: { Bucket: env('B2_BUCKET') }
      }
    }
  }
});

Étape 8 : Créer le frontend Next.js

Dans un nouveau dossier :

npx create-next-app@latest site-public
cd site-public
npm install

Créez un client API simple lib/cms.js :

const API = process.env.CMS_URL;
export async function getArticles(locale = 'fr') {
  const r = await fetch(
    `${API}/api/articles?locale=${locale}&populate=cover&sort=publishedAt:desc`,
    { next: { revalidate: 60 } }
  );
  const json = await r.json();
  return json.data;
}

Étape 9 : Rendu statique incrémental (ISR)

Dans app/articles/[slug]/page.js :

export const revalidate = 300; // re-genere apres 5 minutes

export async function generateStaticParams() {
  const articles = await getArticles();
  return articles.map(a => ({ slug: a.attributes.slug }));
}

export default async function Article({ params }) {
  const article = await getArticleBySlug(params.slug);
  return (
    <article>
      <h1>{article.attributes.title}</h1>
      <div dangerouslySetInnerHTML={{ __html: article.attributes.body }} />
    </article>
  );
}

Étape 10 : Webhooks pour publication instantanée

Au lieu d'attendre la revalidation de 5 minutes, déclenchez la rebuild dès la publication. Dans Strapi Settings > Webhooks :

URL : https://site-public.sn/api/revalidate?secret=XXX
Events : entry.publish, entry.unpublish

Côté Next.js dans app/api/revalidate/route.js :

import { revalidatePath } from 'next/cache';
export async function POST(request) {
  const { searchParams } = new URL(request.url);
  if (searchParams.get('secret') !== process.env.REVAL_SECRET) {
    return Response.json({ error: 'invalid' }, { status: 401 });
  }
  revalidatePath('/');
  revalidatePath('/articles/[slug]', 'page');
  return Response.json({ revalidated: true });
}

Étape 11 : Multilingue (français, wolof, anglais)

Activez i18n dans Strapi puis dans Next.js, créez la structure de routes :

app/
  [locale]/
    page.js
    articles/
      [slug]/page.js
middleware.js  // detecte la langue depuis Accept-Language

Pour le wolof, ajoutez le code wo dans Strapi (locale custom). N'oubliez pas les balises hreflang SEO :

<link rel="alternate" hreflang="fr" href="https://media.sn/fr/article" />
<link rel="alternate" hreflang="wo" href="https://media.sn/wo/article" />

Étape 12 : Workflow éditorial

Dans Strapi Enterprise (ou via plugin gratuit pour communauté), configurez les rôles :

Redacteur  : peut creer/editer SES articles, statut DRAFT
Relecteur  : peut relire, demander corrections, statut READY
Editeur    : peut publier (statut PUBLISHED)
Admin      : tout

Ajoutez un champ editorial_status et utilisez les hooks Strapi pour notifier par email à chaque changement.

Étape 13 : Performance et CDN

Mettez Cloudflare devant tout :

1. Domaine -> Cloudflare DNS (gratuit)
2. Cache niveau Standard
3. Page Rule : *.media.sn/api/* -> Bypass Cache
4. Page Rule : *.media.sn/* -> Cache Everything (1h)
5. Auto Minify : HTML, CSS, JS
6. Brotli : ON
7. Polish (images) : Lossless

Mesurez avec WebPageTest depuis un noeud africain : objectif Time To First Byte < 400ms, LCP < 2.5s.

Étape 14 : Déploiement et coûts en FCFA

Architecture finale recommandée pour 100 000 visiteurs/mois :

Composant         | Service          | Cout mensuel
------------------|------------------|-------------
Strapi (back)     | VPS Contabo 4Go  | 6 000 FCFA
PostgreSQL        | Inclus VPS       | 0
Frontend Next.js  | Vercel Hobby     | 0 (gratuit)
Stockage medias   | Backblaze B2     | 3 600 FCFA (1To)
CDN               | Cloudflare Free  | 0
Domaine .sn       | Annuel           | 1 250 FCFA/mois
TOTAL             |                  | ~12 000 FCFA

Comparaison : un Contentful équivalent coûterait 489 USD/mois soit 295 000 FCFA. Économie : 96 % avec un setup auto-hébergé maîtrisé.

Erreurs

Erreur 1 : Modèle de données trop rigide. Si vous mettez 50 champs obligatoires, vos rédacteurs ne publieront jamais. Démarrez minimaliste, ajoutez au besoin.

Erreur 2 : Oublier la pagination. Charger 5000 articles d'un coup tue le serveur. Toujours paginer (10-20 par page).

Erreur 3 : Médias non optimisés. Une photo de 8 Mo en première page = 30 secondes de chargement en 3G. Imposez WebP/AVIF avec compression.

Erreur 4 : API exposée publiquement avec écriture. Vérifiez TROIS FOIS que les permissions Public sont en lecture seule.

Erreur 5 : Pas de cache HTTP. Sans Cache-Control headers, votre CMS encaisse tous les visiteurs au lieu du CDN.

Erreur 6 : Backup oublié. Sauvegardez la base PostgreSQL ET le bucket S3 séparément. Une suppression accidentelle de média n'est pas dans la base.

Erreur 7 : Vendor lock-in SaaS. Si vous démarrez avec Contentful, exporter 100 000 entrées vers un autre CMS est un projet de 2 mois. Préférez open source.

Checklist

  • CMS headless choisi selon budget et compétences
  • Strapi/Directus installé avec PostgreSQL
  • Content Types modélisés simplement
  • Permissions Public en lecture seule uniquement
  • API Tokens créés pour chaque consommateur
  • Médias stockés sur S3 compatible (B2 ou Wasabi)
  • Frontend Next.js avec ISR et revalidate < 5 min
  • Webhooks de publication configurés
  • i18n actif pour fr/wo/en avec hreflang
  • Workflow éditorial avec rôles définis
  • Cloudflare CDN en frontal
  • WebPageTest validé : LCP < 2.5s en 3G Dakar
  • Backup automatisé base + médias
  • Coût mensuel total < 18 000 FCFA confirmé
Besoin d'un site web ?

Confiez-nous la Création de Votre Site Web

Site vitrine, e-commerce ou application web — nous transformons votre vision en réalité digitale. Accompagnement personnalisé de A à Z.

À partir de 250.000 FCFA
Parlons de Votre Projet
Publicité