Dev Log
Fonctionnalités livrées et correctifs appliqués, version par version.
Dernière mise à jour : 04/05/2026
PERF FIX NEW FEAT — type de changement
Patch 4 mai 2026
Umami Analytics & mise à jour des mentions légales
1 new 1 fix
Ajout de l'outil d'analyse d'audience Umami (sans cookies, sans données personnelles, conforme RGPD) et mise à jour des pages légales pour documenter cette collecte de statistiques anonymes.
NEW
Umami Analytics — suivi d'audience respectueux de la vie privée
layouts/Layout.astro
Intégration du script Umami Analytics (cloud.umami.is) dans le <head> du layout global via is:inline defer. Umami ne pose aucun cookie, ne collecte aucune donnée personnelle identifiable (pas d'IP stockée, pas de fingerprinting) et est conforme RGPD sans bandeau de consentement requis. Mesure uniquement des statistiques agrégées et anonymes : pages vues, référents, type d'appareil, navigateur.
FIX
Mentions légales & politique de confidentialité — ajout de la mention Umami
pages/mentionlega.astro pages/confidentialite.astro
Mise à jour de la section Données personnelles (mentions légales) et des sections Cookies/traceurs et Partage des données (politique de confidentialité) pour documenter l'usage d'Umami Analytics : outil sans cookies, sans collecte de données personnelles, conforme RGPD. Ajout d'Umami dans la liste des prestataires techniques.
Patch 28 mars 2026
Migration VPS, sécurité renforcée & optimisations CDN
3 new 2 perf 3 fix
Migration complète de Netlify vers un VPS Node + Apache proxy, renforcement de la sécurité (middleware headers, rate limiting), suppression des CDN externes au profit de bundles npm, et corrections de compatibilité cross-browser.
NEW
Déploiement VPS — migration Netlify → Node standalone + Apache proxy
astro.config.mjs deploy.js
Remplacement de l'adapter @astrojs/netlify par @astrojs/node en mode standalone. Création d'un script deploy.js (Node.js cross-platform) qui build localement, envoie via scp et redémarre le service systemd sur le VPS. Ajout de security: { checkOrigin: false } dans astro.config.mjs pour contourner la vérification CSRF cassée par le proxy Apache (les headers X-Forwarded-Host et X-Forwarded-Proto sont transmis côté Apache). Ajout de getPublicOrigin() dans contact.ts pour reconstruire l'URL publique derrière le proxy.
NEW
Middleware sécurité — headers HTTP sur chaque réponse SSR
src/middleware.ts
Création de middleware.ts avec defineMiddleware. Ajoute systématiquement X-Frame-Options: DENY, X-Content-Type-Options: nosniff, Referrer-Policy: strict-origin-when-cross-origin et Permissions-Policy: camera=(), microphone=(), geolocation=() sur toutes les réponses SSR.
NEW
Rate limiting en mémoire — /api/contact et /api/chat
pages/api/contact.ts pages/api/chat.ts
Rate limiting par IP via une Map en mémoire. Limite : 5 req/min sur /api/contact, 20 req/min sur /api/chat. Réponse 429 Too Many Requests si dépassé. Pas de dépendance externe — logique embarquée directement dans chaque endpoint SSR.
PERF
Migration CDN → npm — Three.js importmap, GSAP et Lenis supprimés du <head>
layouts/Layout.astro js/lenis-init.js js/TDscript.js pages/index.astro
Suppression de l'importmap Three.js, des 4 balises <script> CDN GSAP/ScrollTrigger et du script CDN Lenis dans Layout.astro. Création de lenis-init.js (import Lenis npm, expose window.lenis). Ajout des imports gsap et ScrollTrigger en tête de TDscript.js. Scripts index.astro passés de <script type='module' src={url}> à <script>import '...'</script> pour être bundlés par Vite. Les preconnects jsdelivr/cdnjs/unpkg sont supprimés.
PERF
Loader coordonné avec le chargement du modèle GLB — 4 phases de progression
js/loader.js js/TDscript.js
Refonte du loader.js avec 4 phases : montée rapide 0→85% (800 ms), plateau, ease-out 85→95% (500 ms), puis attente du modèle 3D. TDscript.js dispatch l'événement custom modelLoaded à la fin du chargement GLB (success et error). Pendant l'attente, glissement lent 95→99% (CREEP_RATE). Quand modelReady, rush final 95→100% en 350 ms (easeOutCubic). Safety timer 10 s si le modèle ne se charge jamais.
FIX
Scroll projets cross-browser — compatibilité Lenis + getBoundingClientRect
js/GlobalIndex.js
Le scroll horizontal des projets était cassé sur Firefox et Safari car getBoundingClientRect() retourne des positions relatives à la viewport quand Lenis intercepte le scroll. Correction : cache de la position absolue sectionTop = getBoundingClientRect().top + window.scrollY (recalculé uniquement au resize), scroll calculé depuis window.scrollY. Hook Lenis direct via window.lenis.on('scroll', ...) avec flag lenisHooked pour éviter l'écoute double native/Lenis.
FIX
Chatbot mobile — fullscreen, bouton fermer et gestion du clavier natif
components/Chatbot.astro
Sur mobile (< 640 px) la fenêtre passe en fullscreen (inset: 0, height: 100dvh avec fallback 100vh). Le bouton toggle flottant est masqué quand le chat est ouvert (toggle.style.display = 'none'). Ajout d'un bouton fermer dans le header (visible uniquement sur mobile). La zone messages passe en flex-1 pour absorber l'espace restant quand le clavier natif réduit la viewport (dvh se contracte dynamiquement). Padding safe-area iOS via env(safe-area-inset-bottom).
FIX
Firefox — fallback backdrop-filter via @supports (sans !important)
styles/global.css
Firefox ne supporte pas backdrop-filter. Ajout d'un bloc @supports not (backdrop-filter: blur(1px)) dans global.css qui applique un fond opaque de substitution sur #header-inner, #mobile-overlay et #chatbot-window. Les sélecteurs ID ont une spécificité suffisante pour surcharger les classes Tailwind sans recourir à !important.
Patch 14 mars 2026
Chatbot IA & sécurisation des variables d'environnement
1 new 1 fix
Intégration d'un assistant IA conversationnel dans le portfolio et migration des credentials sensibles en variables d'environnement.
NEW
Chatbot IA — bouton flottant + fenêtre de conversation
components/Chatbot.astro pages/api/chat.ts
Bouton cercle fixe en bas à droite avec icône chat. Au clic, une fenêtre de conversation apparaît en slide-up. L'historique des messages est conservé en mémoire JS côté client et renvoyé à chaque requête pour maintenir le contexte. Un sessionId est généré via crypto.randomUUID() au chargement. L'endpoint SSR /api/chat relaie les messages vers l'API externe en injectant la clé depuis les variables d'environnement — la clé ne transite jamais côté client. Le system prompt du chatbot est configuré directement dans PocketBase côté API.
FIX
Sécurisation — credentials Gmail migrés en variables d'environnement
pages/api/contact.ts .env
GMAIL_USER et GMAIL_APP_PASS étaient codés en dur dans le fichier source, exposant les credentials dans le dépôt git. Migrés en variables d'environnement lues via import.meta.env. À déclarer dans Netlify → Site settings → Environment variables pour la production.
Patch 07 mars 2026
Correction du bug de la barre & amélioration du menu mobile
2 fix
Correctif du responsive header sur la page À propos et refonte de la disposition du menu mobile.
FIX
Header non responsive sur /apropos — ajout de `relative` sur la section
pages/apropos.astro
La <section> de la page À propos n'avait pas de position: relative. Les divs de glow (absolute inset-0) se positionnaient donc par rapport au body/viewport. L'élément interne w-[980px] débordait hors du viewport, ce qui empêchait les breakpoints md: de Tailwind de se déclencher correctement. Résultat : le header restait en mode desktop même sur mobile, uniquement sur cette page. Correction : ajout de la classe `relative` sur la section pour contenir les absolus.
FIX
Menu mobile — liens en haut, boutons réseaux en bas
components/Header.astro
Refonte de la disposition du menu mobile fullscreen. L'overlay passe en flex flex-col avec shrink-0 sur la top bar. La zone de contenu utilise flex-1 + justify-between pour placer les liens de navigation en haut (pt-16) et les boutons LinkedIn / Contact en bas (pb-12). Correction du bug d'overflow qui rendait les boutons CTA invisibles (h-full remplacé par flex-1).
Patch 06 mars 2026
Correctifs & optimisations
4 perf 6 fix 5 new
Patch de performance et nettoyage de code. Zéro modification visuelle ou fonctionnelle — optimisations internes uniquement.
PERF
Google Fonts : @import CSS → <link> dans le <head>
TDstyles.css Layout.astro
La police Golos Text était chargée via @import dans TDstyles.css. Le navigateur ne peut découvrir cet import qu'après avoir parsé le CSS, créant une chaîne bloquante. Déplacé en <link rel="stylesheet"> dans le <head> avec deux preconnect sur fonts.googleapis.com et fonts.gstatic.com.
PERF
willChange sorti de la boucle de scroll
GlobalIndex.js
panel.style.willChange = "transform" était appliqué à chaque event scroll sur chaque panneau de projet. Déplacé à l'initialisation : exécuté une seule fois après la sélection des éléments.
PERF
Cache de getLoop() — élimination du reflow forcé à 60 fps
skills.js
getLoop() accédait à track.offsetWidth à chaque frame d'animation, forçant un recalcul de layout synchrone 60 fois par seconde. Remplacé par un cache cachedLoop mis à jour via computeLoop() uniquement à l'init et au resize (ResizeObserver).
PERF
Cache de trackWidth — élimination du reflow forcé dans le loader
js/loader.js
track.offsetWidth était lu à l'intérieur de la fonction render() appelée à chaque frame RAF du loader (environ 90 frames sur 1500 ms). Chaque lecture de offsetWidth force un recalcul de layout synchrone. Extrait en variable trackWidth initialisée une seule fois avant la boucle d'animation.
FIX
Suppression de dat.gui du import map
Layout.astro
dat.gui était déclaré dans l'import map Three.js mais jamais importé dans le code. Supprimé avec le preconnect unpkg.com devenu inutile.
FIX
Suppression de export const normalize (dead code)
menu.js
Une fonction normalize était exportée en tête du fichier mais jamais consommée : le script étant chargé via <script src>, ses exports ne sont pas accessibles à l'extérieur.
FIX
Corrections TypeScript — paramètres implicitement any
components/competences_card.astro components/projetscrol.astro pages/competences.astro pages/projets.astro
19 erreurs TypeScript liées à des paramètres sans annotation de type (implicit any) et à des tableaux initialisés en never[]. Ajout d'annotations explicites : any[], (v: any), (record: any, field: string). Remplacement de .filter(Boolean) par un type predicate .filter((x): x is T => x !== null) pour corriger le narrowing de type.
FIX
Correction TypeScript — dataset sur Element
pages/index.astro
document.querySelector retourne Element | null. La propriété .dataset n'existe que sur HTMLElement. Correction en utilisant querySelector<HTMLElement>() pour inférer le bon type et éviter les erreurs à la compilation.
FIX
Installation @types/nodemailer
pages/api/contact.ts package.json
Nodemailer v8 ne fournit pas de déclarations TypeScript intégrées. Installation du paquet @types/nodemailer en devDependency pour résoudre l'erreur « Could not find a declaration file for module 'nodemailer' ».
NEW
Page détail projet /projets/[id]
pages/projets/[id].astro
Page de détail dynamique SSR par ID PocketBase. Hero avec fond flou du premier mockup en arrière-plan + overlay gradient. Galerie adaptive : 1 image pleine largeur, 2 côte à côte, 3 avec grande image + 2 vignettes. Layout deux colonnes (description + cards collaborateurs / sidebar sticky technologies + lien). Collaborateur expand PocketBase avec avatar photo ou initiales, nom, lien profil. Redirection /404 si ID inconnu.
NEW
Cards projets cliquables — stretched link
pages/projets/index.astro
Chaque card de la grille /projets navigue vers /projets/[id] via un <a> en position absolute inset-0 z-0 (stretched link). Les liens internes (tags technologies, bouton Voir en ligne) passent en relative z-10 pour rester accessibles au-dessus de l'overlay.
FIX
Mockup champ Multiple — extraction de la première image
pages/projets/index.astro components/projetscrol.astro
Le champ mockup est passé en Multiple dans PocketBase (tableau de noms de fichiers). L'ancien code passait le tableau entier à pb.files.getURL(), générant une URL invalide. Correction : extraction du premier élément via asArray(p.mockup)[0] dans les cards et helper firstImg() dans le carousel.
NEW
Nouveau modèle 3D — saxophone + refonte de l'éclairage
js/TDscript.js public/models/MonModel.glb
Remplacement du modèle GLB par un saxophone. Auto-fit Box3 pour centrer et scaler automatiquement tout nouveau modèle quelle que soit sa taille native. Refonte de l'éclairage en 6 sources : ambiance chaude, key light blanc-crème haut-gauche, front fill, contre-jour rimlight, fill bleu froid, accent pavillon ambré. Tore principal bleu → rouge au scroll conservé ; ajout de 2 tori secondaires (incliné milieu corps + petit vertical près du pavillon) avec contra-rotation indépendante dans la boucle RAF.
NEW
Page /devlog — journal des versions
pages/devlog.astro
Historique des releases du portfolio, listant fonctionnalités et correctifs appliqués par version.
NEW
Page 404 personnalisée avec animation Three.js
pages/404.astro js/404script.js
Page d'erreur 404 dans le style du site avec canvas Three.js (tori flottants + bloom), wave effect et fade-in CSS. Gérée par Netlify via le routage SSR Astro.
Release 23 février 2026
Lancement initial
14 feat
Première version publique du portfolio. Socle complet avec scène 3D, jeu Snake, canvas physique, filtres, formulaire de contact et SEO.
FEAT
Scène 3D — Three.js + Unreal Bloom
js/TDscript.js
Modèle GLB chargé via GLTFLoader avec post-processing Unreal Bloom. Tore animé emissive. Lumières multiples (spot, fill, rim). Animation de scroll GSAP ScrollTrigger (rotation, position, couleur). Pause sur onglet caché et canvas hors écran via IntersectionObserver.
FEAT
Jeu Snake intégré
pages/snake.astro js/snake.js
Jeu Snake complet jouable depuis /snake. Les compétences chargées depuis PocketBase constituent les collectibles de la partie.
FEAT
Canvas bulles compétences — physique + drag
js/skills.js
Canvas physique avec logos de compétences en bulles. Collisions, rebonds, drag pointer (PC + mobile via Pointer Events), propulsion au clic. Pause sur onglet caché.
FEAT
Stack scroll projets (défilement horizontal par scroll vertical)
components/projetscrol.astro js/GlobalIndex.js
Les 3 derniers projets défilent horizontalement, pilotés par le scroll vertical via un spacer sticky. Transition fluide par translate3d.
FEAT
Transitions organiques SVG animées
js/GlobalIndex.js
Deux chemins SVG (ink-path, ink-path-2) animés avec mouvement sinusoïdal par points de contrôle. Fallback statique si prefers-reduced-motion activé.
FEAT
Loader animé — logo P.M.L + barre de progression
components/loader.astro js/loader.js
Préchargeur avec animation séquentielle du logo (lettres P, M, L), barre de progression avec spark, horloge Europe/Paris en temps réel, et phases d'ease-out.
FEAT
Header adaptatif glass / blanc (IntersectionObserver)
components/Header.astro js/menu.js
Header fixe détectant automatiquement la section visible pour basculer entre mode glass (fond sombre) et mode blanc (fond clair). Menu mobile fullscreen avec stagger CSS et gestion du focus (inert, aria-expanded).
FEAT
Carousel compétences — auto-scroll, drag et flèches
js/skills.js
Carousel infini auto-scroll avec pause hover, navigation par flèches, drag pointer et wheel vertical → horizontal. Delta-time pour vitesse constante.
FEAT
Wave effect lettre par lettre
js/TDscript.js styles/TDstyles.css
Effet de vague par lettre au survol des titres .wave-auto. Animation CSS waveLetter avec délai staggeré par span.
FEAT
Typed.js — hero animé
pages/index.astro
Rotation animée des rôles dans le hero (créateur web, UI/UX designer, full-stack, jeux vidéo) via Typed.js avec smartBackspace.
FEAT
Filtre + autocomplete compétences
js/filtre.js
Filtrage client par catégorie et niveau. Autocomplete avec highlight sur les noms. Pré-calcul des données à l'init. Lecture des paramètres URL (?search=, ?tech=). Toggle Voir plus / moins par mot.
FEAT
Formulaire de contact — API route Astro + Nodemailer
pages/api/contact.ts components/formulaire_contacte.astro
Formulaire avec validation front, envoi via API route Astro et Nodemailer. Feedback visuel sur l'état d'envoi.
FEAT
SEO complet — Open Graph, Twitter Cards, canonical
layouts/Layout.astro
Balises title, description, canonical, og:*, twitter:* dans le layout global. noIndex configurable par page. Sitemap automatique via @astrojs/sitemap.
FEAT
Pages légales — Mentions légales & Confidentialité
pages/mentionlega.astro pages/confidentialite.astro
Pages /mentionlega et /confidentialite conformes RGPD : responsable du traitement, données collectées, droits, hébergement.