Tous les projets

Ce portfolio : Next.js, MDX et déploiement continu

Le site que vous lisez : Next.js 16 et fichiers MDX, redéployé automatiquement sur un VPS ARM64 à chaque push, avec des contrôles de sécurité dans le pipeline.

L'objectif
Un portfolio qui reste simple à faire évoluer, où ajouter un projet ne demande pas de coder.
Ma solution
Next.js piloté par des fichiers MDX, déployé en continu sur un VPS ARM64 via un pipeline avec contrôles de sécurité.
Le résultat
Ajouter un projet revient à écrire un fichier ; performance, accessibilité et SEO sont mesurés.

Contexte

Ce portfolio est à la fois une vitrine pour des recruteurs et un outil personnel que je fais évoluer. Plutôt que de coder chaque projet en dur, j'ai conçu le site comme une petite plateforme : le contenu est séparé du code, la mise en ligne est automatique, et la performance, l'accessibilité et le SEO sont mesurés.

Le projet que vous lisez en ce moment est lui-même décrit par un fichier MDX, c'est sa propre démonstration.


Objectifs

  • Une architecture data-driven : ajouter un projet = écrire un fichier, pas modifier du code
  • Un déploiement continu avec des contrôles de sécurité bloquants
  • Une performance mesurée et optimisée (Lighthouse > 90)
  • Un SEO soigné, jusqu'à la donnée structurée et l'identité numérique
  • Le tout cohérent avec mon infra ARM64 existante (Docker + Traefik)

Stack technique

CoucheChoixRaison
FrameworkNext.js 16 (App Router)Rendu statique + Server Components
LangageTypeScript strictPas de any, typage des données projets
StyleTailwind CSSDesign system par tokens, zéro CSS mort
ContenuMDX (next-mdx-remote)Articles riches : code, tableaux, callouts
ConteneurDocker linux/arm64Aligné sur le VPS Ampere
Reverse proxyTraefik v2.11Routing par labels + TLS Let's Encrypt
CI/CDGitHub ActionsPipeline scan → build → deploy
InfraOracle Cloud ARM64VPS personnel

Architecture data-driven

Le principe central : aucune donnée projet n'est codée en dur. Chaque projet est un fichier MDX dans content/projects/, avec un frontmatter typé :

id: mon-projet
title: …
domains: [cybersecurity, devsecops]
tags: [Docker, …]

Au build, une fonction readProjects() lit ces fichiers, valide le frontmatter contre le type Project, et génère :

  • la liste filtrable sur /projects ;
  • une page détail par projet (/projects/[id]) via generateStaticParams ;
  • les entrées du sitemap.

Pipeline CI/CD

Chaque push sur main déclenche un workflow GitHub Actions en trois étages, avec des gates de sécurité bloquants :

Pipeline en trois étages : sécurité, build, déploiement ; un échec de sécurité arrête tout
Pipeline en trois étages : sécurité, build, déploiement ; un échec de sécurité arrête tout
  • Étage 1 échoue → rien n'est construit ni déployé. Une CVE critique ou une dépendance vulnérable bloque la chaîne.
  • Étage 2 compile une image ARM64 (via QEMU sur runner x86) poussée sur le registre.
  • Étage 3 met à jour le conteneur derrière Traefik, sans interruption visible.

Performance

J'ai mesuré la performance avec Lighthouse à chaque étape. Le plus gros gain est venu du retrait de Framer Motion.

ActionEffet mesuré
Animations JS → CSS purLCP 2.7s → 2.3s, TBT −76 %
Suppression de Framer Motion (lib JS)LCP 2.3s → 2.2s, Performance 99
Nom du hero rendu en SSR (statique)Contenu critique présent dès le HTML
Polices next/font (self-host + swap)Pas de FOIT, pas de requête tierce

SEO & identité numérique

En plus des balises title/description, j'ai ajouté les signaux que Google utilise pour construire une entité :

  • Donnée structurée JSON-LD : un schéma Person (formation, compétences, sameAs vers GitHub/LinkedIn) et WebSite, pour lier mon nom à mes profils.
  • Maillage interne : projets liés entre eux (ce projet pointe vers d'autres), bon pour le crawl et l'utilisateur.
  • Signature auteur E-E-A-T sur chaque projet (qui écrit, son cursus).
  • sitemap.xml généré automatiquement + llms.txt pour les assistants IA.
  • Titres et descriptions courts et ciblés par page.

Accessibilité & design system

  • Dark mode soigné, palette définie par tokens Tailwind (couleur par domaine).
  • aria-label sur tous les boutons-icônes, structure de titres cohérente.
  • Typographie : IBM Plex Sans pour le texte, JetBrains Mono pour le code. Depuis la refonte de septembre 2026, le site n'a plus d'animations et tient sur une colonne de lecture.
  • Composants réutilisables : ProjectCard, DomainBadge, TechTag, Callout, CodeBlock…

Limites

  • Nœud unique : un seul VPS, pas de haute disponibilité.
  • Contenu en français uniquement : pas d'i18n pour l'instant.
  • Pas de CMS : l'édition passe par Git (choix assumé, mais moins accessible qu'un back-office).

Évolutions envisagées

  • Analytics : intégration d'un compteur de vues par projet (déjà branché sur mon Umami auto-hébergé).
  • Recherche plein-texte côté client sur les projets.
  • Internationalisation (FR/EN) via les routes App Router.
  • Mode clair complet en complément du dark mode.

Ce que ce projet m'a appris

Le choix qui m'a le plus servi a été de séparer le contenu (MDX) du code dès le départ : ajouter un projet revient à écrire un fichier, sans toucher au code.

L'autre enseignement est venu de la mesure : sans Lighthouse, j'aurais gardé une librairie d'animation « parce que c'est pratique ». Les chiffres ont tranché.

Projets proches

DevSecOpsCybersécurité

Indian Food : pipeline DevSecOps pour un site vitrine

Site vitrine statique d'un restaurant, déployé sur Oracle Cloud ARM64 derrière une chaîne DevSecOps : analyse statique, scan de dépendances, tests dynamiques et déploiement automatisé.

2026DevSecOpsDockerNginxCI/CD

DevSecOps

Supervision du VPS avec Prometheus et Grafana

Prometheus et Grafana auto-hébergés sur mon VPS ARM64 pour suivre l'état du serveur et de chaque conteneur Docker. Les dashboards ne sont accessibles que par le VPN.

2026PrometheusGrafanaNode ExportercAdvisor

CybersécuritéDevSecOps

Mon budget : une application de prévision de solde

Application web qui répond à "combien j'aurai à telle date ?" et "quand est-ce que ça coince ?", avec un moteur de calcul testé, plusieurs budgets étanches et une authentification à double vérification. Déployée sur mon VPS ARM64.

2026Next.jsTypeScriptSQLiteargon2id