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
| Couche | Choix | Raison |
|---|---|---|
| Framework | Next.js 16 (App Router) | Rendu statique + Server Components |
| Langage | TypeScript strict | Pas de any, typage des données projets |
| Style | Tailwind CSS | Design system par tokens, zéro CSS mort |
| Contenu | MDX (next-mdx-remote) | Articles riches : code, tableaux, callouts |
| Conteneur | Docker linux/arm64 | Aligné sur le VPS Ampere |
| Reverse proxy | Traefik v2.11 | Routing par labels + TLS Let's Encrypt |
| CI/CD | GitHub Actions | Pipeline scan → build → deploy |
| Infra | Oracle Cloud ARM64 | VPS 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]) viagenerateStaticParams; - 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 :
- É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.
| Action | Effet mesuré |
|---|---|
| Animations JS → CSS pur | LCP 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,sameAsvers GitHub/LinkedIn) etWebSite, 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.xmlgénéré automatiquement +llms.txtpour 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-labelsur 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
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
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
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