Ce portfolio — concevoir et développer le site qui atteste mes compétences
Le site que vous lisez est lui-même une réalisation : 96 pages générées à partir d'un CMS, aucune ligne de texte écrite en dur dans le code. Je l'ai conçu et dirigé seul, développé avec un assistant IA, et j'assume de le dire.
Contexte
Au départ, mon portfolio était un document Word. Portfolio_TomEGE_v5.docx : 11,4 Mo, 609 lignes de texte utile, 11 visuels intégrés. Il n'était pas organisé par projet mais par année, puis par unité d'enseignement, puis par projet. Ça a l'air d'un détail de mise en page. C'en est un de fond.
Parce que dans cette organisation, un projet ne peut appartenir qu'à une seule compétence à la fois. Ma SAÉ 302, le MMI LAN, apparaît trois fois dans le document : une fois sous Comprendre, une fois sous Concevoir, une fois sous Exprimer. Trois versions du même projet, chacune amputée de ce que les deux autres racontent. Un lecteur qui tombe sur l'une des trois ne voit qu'un tiers du travail. Le format m'obligeait à découper ce qui, dans la réalité, était un seul chantier.
Le site en ligne que j'avais à côté ne réglait rien : ses fiches étaient maigres. Deux paragraphes, une image quand il y en avait une, et une liste de codes d'apprentissages critiques posés là sans que rien ne les explique. J'ai fait le compte au moment de démarrer : sur 47 rattachements entre une réalisation et un AC, 23 n'avaient aucun texte de justification, et la longueur médiane des autres était de 123 caractères. Une ligne. Devant un jury, une case cochée que rien n'explique appelle exactement la même question qu'une case vide.
D'où la commande que je me suis passée à moi-même. Un site où l'unité n'est pas la page mais le lien entre une réalisation et un apprentissage critique, avec le texte qui explique ce lien. Une réalisation, autant d'AC qu'elle mobilise réellement, et pour chacun une justification rédigée qui tient debout toute seule. Le reste — la grille, les filtres, la mise en page — découle de ça.
Trois contraintes encadraient le chantier. Je devais pouvoir modifier le contenu sans ouvrir un éditeur de code, parce qu'un portfolio se corrige la veille d'un oral et que je ne voulais pas dépendre d'un déploiement pour changer un mot. L'hébergement, un Plesk sous nginx sur tomege.wstr.fr, ne construit rien côté serveur : on y dépose des fichiers en FTP, point. Et le budget était nul, donc tout devait tenir en logiciel libre ou en palier gratuit.
Le calendrier a été court et découpé en sessions : une première nuit de travail fin juillet 2026 pour sortir une version complète et déployable, puis deux passages en août pour densifier le contenu — le dernier le 27 août, la veille de la soutenance.
Démarche
Disséquer le document Word avant d'écrire une ligne de code
J'ai commencé par extraire le .docx plutôt que de le relire. Un fichier Word est une archive ZIP qui contient un word/document.xml : un script Python le dézippe, en tire le texte brut et les visuels, et produit un fichier lisible dans docs/docx-extrait.md. Ça m'a pris moins de temps que de recopier à la main, et surtout ça m'a donné une base fixe : à partir de là, je travaillais sur une source que je pouvais relire, chercher, comparer.
Cette lecture a sorti deux choses. La première, les 14 réalisations réelles derrière les 16 entrées « PROJET » du document, avec pour chacune l'année, l'équipe, les outils, le visuel et le lien quand ils existaient — 7 sur 14 n'avaient pas de visuel, 8 sur 14 pas de lien. La seconde, un schéma rédactionnel que je suivais sans l'avoir formalisé : contexte, processus, compétences acquises, auto-évaluation, auto-critique, continuité. Six temps, systématiques. Le cahier des charges que j'avais en tête prévoyait plutôt un triptyque contexte / démarche / résultats. J'ai gardé mes six temps : réduire l'auto-critique et la continuité à un champ « résultats » aurait fait disparaître exactement ce qui est évalué en MMI.
Modéliser : la table de jonction est le cœur du projet
Le modèle compte une vingtaine de collections — réalisations, apprentissages critiques, compétences, univers, outils, types, expériences, savoir-faire, pages, ressources, SAÉ, notes, chiffres clés, liens sociaux, textes d'interface, paramètres — plus quatre tables de jonction.
Une seule décision compte vraiment. La table qui relie une réalisation à un apprentissage critique porte un champ justification. Le texte qui explique en quoi telle réalisation prouve tel AC n'est ni dans la réalisation, ni dans l'AC : il est dans le lien, parce qu'il n'existe que par le lien. C'est ce qui rend le portfolio différent d'une liste de projets avec des étiquettes. Et c'est la raison principale du choix de Directus : il expose nativement les champs d'une table de jonction dans une interface éditable, ce que beaucoup de CMS ne savent pas faire.
Deuxième décision structurante : univers est une relation multiple, pas un champ unique. Ma fiche « Auto-entrepreneur créateur de contenu » est à la fois une trace de l'UE Entreprendre de BUT 1 et une activité Nexan. La présidence de JKMC est à la fois une trace académique et l'association. Avec un univers unique, mes deux meilleures preuves d'Entreprendre disparaissaient soit du tableau de bord académique, soit des pages Nexan et JKMC. J'ai gardé en plus un univers_principal, pour savoir quoi afficher quand il n'y a la place que pour un.
Choisir la pile en partant de l'hébergement
L'hébergement ne construit rien : le site devait donc être entièrement statique. J'ai pris Eleventy 3 avec des gabarits Nunjucks pour la génération, et Directus 12 sur base SQLite en local pour l'administration. Le build interroge l'API une fois, écrit du HTML, et c'est fini. Une fois en ligne, le site ne fait plus aucun appel réseau : il reste debout même si le CMS est éteint.
J'ai écarté WordPress, que je connais pourtant et que j'ai utilisé sur d'autres projets. Pour ce besoin précis — une table de jonction éditable, un référentiel de 75 AC, des relations multiples partout — il aurait fallu un empilement d'extensions, et j'aurais fini par ne plus maîtriser ce que je livrais. Sur mon propre portfolio, c'était le mauvais compromis.
Toute la configuration de Directus est écrite dans un script plutôt que cliquée dans l'interface : schéma, champs, trois rôles, notes d'aide, icônes, marque-pages, bouton de publication. Le script est rejouable et non destructeur — il crée ce qui manque et ne touche pas à l'existant. Concrètement, je peux recréer une instance vierge et retrouver mon administration à l'identique, ce qui est ce dont j'ai eu besoin le jour où je suis passé de SQLite à une base de production.
Sortir tous les textes du code
C'est le parti pris que je défends le plus. Aucun texte visible n'est écrit en dur dans les gabarits. Pas seulement les articles et les fiches : les surtitres, les libellés de boutons, les étiquettes de formulaire, les messages d'état. Tout vit dans une collection textes_site, appelée depuis les gabarits par une clé.
Le raisonnement est simple : dès qu'une phrase est dans le code, elle est hors de ma portée quand je n'ai pas l'environnement sous la main. Un filtre absorbe les cas tordus — clé manquante, texte vide, jeton de remplacement non fourni — sans jamais interrompre la génération, mais en listant les manques à la fin du build. Un portfolio ne doit pas cesser de se construire parce qu'un libellé manque ; il doit me dire lequel manque.
J'ai buté sur un piège en chemin : mon premier filtre lisait les textes depuis le contexte du gabarit, et rendait des chaînes vides partout dès qu'il était appelé depuis une macro — une macro Nunjucks ne reçoit que ses arguments, pas les données globales. Les textes sont maintenant chargés une fois dans un cache de module, avant la génération.
La direction artistique, puis l'accessibilité qui la corrige
Direction retenue : néo-brutalisme éditorial. Fond blanc dominant, rose #FF2E88, jaune #FFD400, noir, bordures franches et ombres dures décalées. Tiré vers « propre et pro » plutôt que vers le chaos, parce que le lecteur visé est un jury, pas un feed.
L'audit de contraste a démoli une partie du premier jet, et c'est la meilleure chose qui soit arrivée à la charte. Les pastilles de compétence étaient en texte blanc sur aplat vif : 2,91:1 sur le cyan, 2,62:1 sur le vert, contre 4,5:1 exigés. Je les ai passées en texte noir sur fond clair, 13:1 au minimum, avec l'accent vif conservé en anneau intérieur — le code couleur reste lisible, le contraste passe, et je n'ai plus d'exception à gérer pour le jaune. Le rose vif avec du blanc ne donne que 3,50:1, donc dès qu'il y a du texte j'utilise un rose foncé à 4,89:1, et je garde le rose vif pour les surfaces sans texte.
L'anneau de focus m'a demandé le plus de tâtonnements. Aucune couleur unique ne ressort à la fois sur blanc, sur rose, sur jaune et sur le pied de page noir — le bleu franc que j'avais mis tombait à 1,58:1 sur le rose. La solution est un anneau noir doublé d'un halo blanc, qui s'inverse dans le pied de page. Le jaune, lui, n'est jamais utilisé pour du texte, nulle part.
Deux règles que je me suis imposées : aucun état ne repose sur la seule couleur — un AC non attesté cumule une mention écrite, une bordure en pointillés et un fond grisé — et les blocs à apparition sont visibles par défaut, c'est le JavaScript qui active l'état masqué. Jamais l'inverse. Si le script ne se charge pas, le contenu est là.
Performance : décider ce qu'on paie et ce qu'on économise
Le CSS est écrit en six couches — variables, base, mise en page, composants, pages, utilitaires — concaténées et minifiées en un seul bloc injecté directement dans le <head>. Résultat : zéro ressource bloquante, zéro décalage de mise en page. Le compromis est réel et je l'assume : pas de cache entre les pages, environ 8 Ko compressés retéléchargés à chaque navigation. Sur un site de 96 pages où la première impression compte plus que la dixième, je préfère payer ça.
Les images sont téléchargées depuis le CMS au build, converties en AVIF et WebP avec repli JPEG, en plusieurs largeurs, avec chargement différé sauf l'image d'en-tête des fiches. Les dimensions sont écrites sur chaque image, ce qui supprime tout sursaut au chargement. Les polices sont auto-hébergées en woff2 plutôt que servies par Google : une requête tierce de moins, et aucune adresse IP de visiteur transmise à un tiers.
Côté référencement : titre et description par page, URL canonique, Open Graph, sitemap, données structurées Person partout et CreativeWork sur chaque fiche. Les images de partage sont fabriquées au build et déposées sur le site, parce que mes balises pointaient d'abord sur le CMS, injoignable depuis l'extérieur — un lien partagé s'affichait sans vignette.
Se fabriquer des instruments de mesure
Trois scripts maison, et c'est peut-être ce dont je suis le plus content.
L'audit passe sur le site généré et vérifie les textes alternatifs, la hiérarchie des titres, les champs de formulaire étiquetés, les noms accessibles des zones de navigation, la validité du JSON-LD, la longueur des titres et des métadescriptions, et 24 couples de contraste de la charte. Il a attrapé des bêtises que je n'aurais jamais vues : des titres de fiches d'AC montant à 204 caractères, et son propre bug — il comptait ' pour cinq caractères, ce qui faisait paraître mes titres français bien plus longs qu'ils ne le sont réellement pour un moteur.
La matrice de couverture recalcule, à la demande, l'état de chaque AC du référentiel. J'ai refusé le découpage à trois états que j'avais prévu au départ, et j'en ai mis quatre : attesté, à renforcer, déclaré sans preuve, aucune trace. L'état « déclaré sans preuve » était invisible dans le découpage à trois, alors que c'est le plus traître — une case cochée que rien n'explique. Le fichier est réécrit à chaque exécution, c'est un instrument, pas un document.
Le script de livraison reconstruit, contrôle et emballe. Il refuse de produire l'archive si le build contient une URL localhost, ou si une seule des 1 629 références internes du site pointe dans le vide. Le premier contrôle m'a évité une mise en ligne où 60 pages avaient des liens canoniques et un sitemap pointant sur ma machine de développement.
Un système de migrations, parce que le seed ne suffisait pas
Mon script d'installation crée ce qui manque et ne touche à rien d'existant. Très bien pour installer, inutile pour corriger une donnée déjà en base. J'ai donc écrit un mécanisme de migrations : chaque évolution du contenu est un fichier numéroté qui expose une fonction pour appliquer et une pour annuler, l'historique est stocké dans le CMS, et une migration déjà passée n'est jamais rejouée. Douze à ce jour.
Règle que je me suis donnée et qui a compté : une migration ne remplit que ce qui est vide. Un champ déjà rempli dans l'administration est laissé tel quel. Le texte que j'écris à la main prime toujours sur celui d'un script.
Se regarder soi-même comme un objet de conception
C'est la partie que je n'avais pas anticipée. Concevoir un portfolio qui doit attester des compétences, ce n'est pas mettre en page des projets : c'est décider quoi montrer, dans quel ordre, avec quel niveau de détail, et vivre avec ce qu'on décide de laisser dehors.
Quelques arbitrages concrets. Le bloc réflexif « Ce que j'en retire » était replié derrière un dépliant : je l'ai ouvert par défaut, parce que c'est la seule section qui expose une démarche et que c'est ce qu'un jury retient. Les champs vides ne sont jamais remplis de faux contenu — une réalisation sans visuel affiche un bloc typographique qui dit visiblement « pas d'image » plutôt qu'un espace réservé qui ressemble à un bug, et une réalisation sans lien le dit en toutes lettres. J'ai aussi ajouté une page /parcours-guide/, volontairement hors du menu : le fil de mon oral, sept traces, dix-huit minutes, les AC de chacune. Elle n'est pas faite pour être trouvée, elle est faite pour être suivie.
Résultats
Chiffres relevés le 27 août 2026, sortis de mes propres outils : la commande d'audit, la matrice de couverture, et l'inventaire produit par le script de livraison.
Ce que le site contient
- 96 pages HTML générées, 93 URL déclarées au sitemap.
- 26 réalisations publiées, contre 14 au départ.
- 97 rattachements entre une réalisation et un apprentissage critique, contre 47 au départ.
- 0 rattachement sans justification écrite, contre 23 au départ. Longueur médiane des justifications : 465 caractères, contre 123 avant.
- 60 fiches d'apprentissage critique générées sur les 75 du référentiel en base — seuls les AC réellement attestés ont une page.
- 19 AC solidement attestés, contre 0 au moment du diagnostic initial.
Accessibilité et qualité
- Aucune anomalie sur les 96 pages au dernier passage de l'audit : pas de texte alternatif manquant, pas de niveau de titre sauté, pas de champ de formulaire sans étiquette, pas de JSON-LD invalide.
- 24 couples de contraste sur 24 conformes au niveau AA de WCAG 2.1.
Performance
- Décalage cumulé de mise en page : 0. Aucune ressource bloquante.
- Page d'accueil : 101 Ko transférés, 10 requêtes, polices servies en 3 ms.
- CSS : 39 Ko minifié, injecté en ligne. JavaScript : 15 Ko, en modules ES, zéro dépendance.
- Images : 2,06 Mo d'AVIF contre 10,88 Mo de PNG source, soit 81 % de moins.
- Testé à 375, 768 et 1440 pixels de large : aucun débordement.
Livraison
L'archive du 27 août 2026 contient 460 fichiers, 22,1 Mo compressés pour 27,2 Mo une fois déposés, avec son empreinte SHA-256 et son inventaire par type. Elle n'est produite qu'après vérification qu'aucune URL localhost ne subsiste et que les 1 629 références internes du site résolvent toutes vers un fichier réellement présent.
Un incident vaut d'être cité parce qu'il illustre ce que ces contrôles servent à attraper. La commande d'archivage native de Windows PowerShell écrit les chemins du ZIP avec des antislashs, ce qui viole le format : mesuré sur ce projet, 239 entrées sur 277. Un serveur Linux décompresse alors un fichier nommé littéralement realisations\index.html à la racine, et le site est cassé sans que rien ne l'explique. J'ai remplacé l'archivage par une bibliothèque qui normalise les séparateurs, puis testé l'extraction et navigué le site depuis l'archive.
Ce que j’en retire
Auto-évaluation
Ce que je revendique, et ce que j'ai délégué
Ce site a été développé avec un assistant de code IA. Je le dis d'entrée, parce qu'un jury MMI en 2026 sait ce qu'est un assistant de code, et parce qu'un projet de ce volume produit seul en quelques sessions pose légitimement la question. Autant y répondre avant qu'on me la pose.
Ce qui est de moi : le diagnostic du problème, le modèle de données, le choix de faire porter la justification par la table de jonction, la décision de tout générer en statique, la direction artistique, les arbitrages d'accessibilité, ce qu'on montre et ce qu'on cache, et le contenu — chaque justification d'AC est un texte que j'ai écrit ou validé, parce que c'est ce qui est évalué. Ce qui a été assisté : l'écriture du code, la configuration du CMS, les scripts d'outillage.
Piloter une production assistée est un travail, pas une absence de travail
Je ne prétends pas avoir tapé les 6 800 lignes de ce projet. Je prétends autre chose, et je crois que c'est plus intéressant.
Un assistant produit ce qu'on lui demande. Si la demande est floue, il produit quelque chose de plausible et de faux, et c'est le pire cas de figure : du code qui tourne, qui a l'air juste, et qui ne fait pas ce qu'il faut. J'ai eu l'exemple parfait sur ce projet. Une fonction de Nunjucks — selectattr avec un test d'égalité — accepte la syntaxe et ignore purement et simplement l'argument de comparaison : elle n'évalue que la présence de l'attribut. Aucune erreur, aucun avertissement. Sur une liste de trois éléments dont un seul devait ressortir, elle en renvoyait trois. Conséquences visibles avant que je ne le trouve : mes pages Nexan et JKMC affichaient « Université » en titre, les objectifs par année affichaient tous celui de la première année, les compteurs de filtres mentaient, et toutes les galeries de visuels étaient vides. Neuf usages fautifs, remplacés par trois filtres écrits à la main, et un avertissement laissé en commentaire pour que personne — moi compris — ne revienne en arrière.
Ce bug ne se trouve pas en faisant confiance. Il se trouve en regardant une page, en constatant que le titre est faux, et en descendant jusqu'à la cause. C'est exactement le travail que je considère comme le mien.
Ce que ça change au métier, et pourquoi je pense que c'est une compétence
Ma conviction après ce projet : la valeur ne se déplace pas de « savoir coder » vers « savoir demander ». Elle se déplace vers savoir spécifier, savoir vérifier, et savoir décider ce qui n'est pas négociable.
Spécifier, c'est ce que j'ai fait en modélisant avant de coder. Le modèle de données de ce site n'est pas sorti d'un assistant : il est sorti de la lecture du Word et du constat que le format m'obligeait à éclater un projet en trois. Aucun outil n'aurait trouvé ça à ma place, parce qu'il fallait connaître le contenu.
Vérifier, c'est la raison d'être des trois scripts d'outillage. Je n'ai pas écrit l'audit parce que c'était joli, je l'ai écrit parce que je savais que je ne relirais pas 96 pages à la main et que je ne voulais pas dépendre de mon coup d'œil. Les 24 couples de contraste sont dans le script pour la même raison : mon œil ne mesure pas un ratio. Le script de livraison qui refuse de produire l'archive relève du même réflexe — poser une barrière là où je sais que je vais me tromper un jour, fatigué, à minuit, avant une échéance.
Décider ce qui n'est pas négociable, enfin. Ici : aucun texte en dur, aucune donnée inventée, aucun état porté par la seule couleur, aucun contenu accessible uniquement par script. Ces règles ne viennent pas d'un outil. Elles viennent du RGAA, de ce qu'on m'a enseigné, et de la façon dont je veux que mon travail soit jugé. Un assistant les applique très bien quand on les énonce, et ne les invente jamais tout seul.
Ce que je retire de ce chantier, au fond, c'est que produire vite ne dispense de rien. Ça déplace l'effort. Le temps que je n'ai pas passé à écrire des boucles, je l'ai passé à modéliser, à mesurer, à relire et à trancher. C'est une manière de travailler que je vais retrouver en agence, et je préfère l'avoir apprise sur un projet dont je suis le seul responsable.
Auto-critique constructive
On ne maîtrise bien que ce qu'on est capable de relire
C'est la limite honnête de ce projet, et je ne vais pas la contourner.
Je suis capable de relire et d'expliquer la couche de données, les gabarits, le CSS, les scripts d'audit et de livraison, le mécanisme de migrations. Je les ai debugués, j'ai trouvé des erreurs dedans, je sais pourquoi chaque décision est là. En revanche, si on me demandait de réécrire de zéro et sans aide le script qui configure le CMS — 893 lignes de définition de schéma, de champs, de rôles et d'interface — j'en serais capable dans le principe mais pas dans le détail, et sûrement pas au même rythme. Il y a un écart entre ce que je sais faire et ce que j'ai livré, et cet écart s'appelle l'assistance.
Je le formule comme ça : ma maîtrise s'arrête là où s'arrête ma capacité à relire. Tant que je peux ouvrir un fichier, comprendre pourquoi il fait ce qu'il fait et repérer quand il ment, je réponds du résultat. Au-delà, je ne réponds plus de rien, et le risque n'est pas théorique — le bug de Nunjucks est passé sous mon nez pendant un moment avant que je ne le voie. Il ne s'annonçait pas. C'est ce que je surveille désormais en priorité : pas les erreurs qui plantent le build, mais celles qui produisent un résultat plausible.
Ce que je referais autrement
J'aurais écrit l'audit avant l'intégration, pas après. Il a démoli une partie de ma charte en attrapant des contrastes insuffisants, et j'ai repris des composants déjà intégrés partout. Si le script avait tourné dès la première maquette, ces couleurs ne seraient jamais entrées dans le CSS.
J'aurais aussi tranché le référentiel plus tôt. Ma base contient 75 apprentissages critiques : 59 viennent de mon portfolio Word, 16 d'un référentiel national d'un autre IUT que j'ai ajoutés pour combler des familles absentes. Tant que le dénominateur n'est pas confirmé sur le programme national de Toulon, aucun pourcentage de couverture n'est vraiment vérifiable, et je préfère l'annoncer plutôt que d'afficher un joli pourcentage qui reposerait sur un compte incertain. Les libellés concernés sont d'ailleurs signalés comme « à relire » dans ma matrice.
Ce qui n'est pas fait
Aucun test utilisateur. J'ai conçu les parcours en raisonnant sur ce qu'un jury cherche, pas en observant quelqu'un chercher. Sur un site dont l'ergonomie est un argument, c'est le manque le plus voyant, et je ne peux rien affirmer sur l'efficacité réelle de ma navigation.
15 apprentissages critiques n'ont aucune trace rattachée, dont sept en Développer. J'ai refusé de boucher les trous avec des rattachements de complaisance : un lien sans justification solide se voit immédiatement, et il coûte plus cher qu'une case vide assumée.
Le bouton « Publier le site » ne déclenche encore rien. Le flux existe dans l'administration, mais son adresse de déclenchement est vide, parce qu'une URL fictive donnerait un faux succès — un bouton qui affiche « publié » sans rien publier est pire que pas de bouton.
Une conséquence de mon choix de CMS reste ouverte. L'édition communautaire de Directus accepte les permissions simples mais refuse celles qui portent un filtre de lignes. Mon API publique ne peut donc pas masquer un brouillon : c'est le build qui filtre, et rien d'autre. Sur ce site, dont tout le contenu est destiné à être public, le risque est nul. Le jour où j'écrirai un brouillon que je ne veux pas voir sortir, il faudra régler ça autrement.
Enfin, huit des douze visuels tirés de mon rapport d'alternance ne sont rattachés nulle part, parce que je ne peux pas dire avec certitude ce qu'ils montrent hors contexte. Les légender au jugé produirait des textes alternatifs faux, ce qui est pire qu'une image absente. Ils attendent d'être identifiés.
Continuité et développement personnel
La différence entre ce site et mon portfolio Word, c'est qu'il ne se périme pas de la même manière. Le Word était figé à la version 5 ; celui-ci a une administration, un modèle de données qui accepte de nouvelles réalisations sans qu'on touche au code, et un mécanisme de migrations pour faire évoluer le contenu sans repartir de zéro. J'ajoute une fiche, je relance la génération, et la grille, les filtres, les fiches d'AC concernées, la matrice de couverture et le sitemap se mettent à jour tout seuls.
La matrice de couverture est l'outil que je compte garder le plus longtemps. Elle me dit, à n'importe quel moment, quels apprentissages critiques sont réellement attestés et lesquels tiennent sur du vide. Elle m'a servi à piloter la fin du chantier : elle classait « Ce portfolio » lui-même parmi les traces à créer en priorité, en indiquant qu'il bouchait plusieurs trous d'un coup en Développer. C'est en la lisant que j'ai décidé d'écrire cette fiche. Un outil qui vous dit quoi faire ensuite vaut mieux qu'un tableau de bord qui vous félicite.
Le script d'audit et le script de livraison sont réutilisables tels quels sur d'autres projets. Ce sont des fichiers autonomes qui lisent un dossier de site construit ; rien dedans n'est propre à ce portfolio, sauf la liste des couples de couleurs, qui se remplace. Je les emporte.
Sur le plan de ce que j'ai appris, deux choses me suivront. La première, la modélisation : depuis ce projet, je regarde d'abord ce qui est en relation avec quoi, avant de regarder à quoi ça ressemble. La table de jonction porteuse d'un texte n'est pas un détail technique, c'est ce qui a rendu ce portfolio possible, et ce réflexe-là sert bien au-delà d'un portfolio. La seconde, la conduite d'une production assistée : spécifier, vérifier, et poser les règles qu'aucun outil ne posera à ma place. C'est ce que je propose d'apporter en agence, plus que la vitesse de frappe.
Il reste des chantiers identifiés : confirmer le référentiel sur le programme national de Toulon, brancher l'adresse du bouton de publication, faire tester la navigation par quelqu'un d'autre que moi, et remplacer les images manquantes signalées dans mon inventaire. Ils sont écrits, datés et priorisés dans les documents du projet, pas laissés dans un coin de ma tête.
Compétences mobilisées
8 apprentissage(s) critique(s) rattaché(s) à cette réalisation.
Évaluer un site web, un produit multimédia ou un dispositif interactif existant
ComprendreCe projet a commencé par l'évaluation de mes propres supports existants, et c'est ce diagnostic qui a produit tout le reste. J'ai extrait mon portfolio Word par script plutôt que de le relire, pour travailler sur une source que je pouvais chercher et comparer, et j'en ai tiré un constat structurel : le document était organisé par année puis par unité d'enseignement, ce qui forçait chaque projet à n'exister que sous une seule compétence, au point qu'une même SAÉ y apparaissait trois fois en trois versions incomplètes. J'ai chiffré les manques plutôt que de les estimer — 7 réalisations sur 14 sans visuel, 8 sur 14 sans lien — et j'ai fait le même travail sur mon site en ligne d'alors : sur 47 rattachements à des apprentissages critiques, 23 n'avaient aucun texte et la longueur médiane des autres était de 123 caractères. J'ai aussi identifié le motif rédactionnel que je suivais sans l'avoir formalisé, en six temps dont l'auto-critique et la continuité, et j'ai refusé de le réduire au triptyque contexte-démarche-résultats prévu au départ, parce que c'est précisément la partie réflexive qui est évaluée. Chaque décision du modèle de données répond à un point de ce diagnostic ; aucune ne vient d'une préférence esthétique.
Concevoir un produit ou un service en termes d'usage et de fonctionnalité
ConcevoirJ'ai conçu ce site pour un usage précis : un jury qui dispose de peu de temps et qui cherche à vérifier une correspondance entre des travaux et un référentiel. L'unité d'usage n'est donc pas la page mais le lien entre une réalisation et un apprentissage critique, et toute la navigation en découle — on peut entrer par les projets ou par le référentiel et arriver au même texte. La grille de réalisations propose des filtres cumulables sur cinq familles, avec un ET entre familles et un OU à l'intérieur, un état reflété dans l'adresse pour qu'une sélection soit partageable et que le bouton retour fonctionne, une recherche insensible aux accents, et un repli complet sans JavaScript puisque le formulaire se soumet alors en GET. L'accessibilité a été une contrainte de conception et pas une correction : aucun état ne repose sur la seule couleur, les blocs à apparition sont visibles par défaut et c'est le script qui les masque, et le compteur de résultats est annoncé aux lecteurs d'écran avec un délai pour ne pas bavarder pendant la frappe. J'ai aussi tranché des questions d'usage inconfortables : ouvrir par défaut le bloc réflexif plutôt que de le replier, et ne jamais remplir un champ vide de faux contenu — une fiche sans visuel affiche un bloc typographique qui dit visiblement qu'il n'y a pas d'image, plutôt qu'un espace réservé qu'on prend pour un bug.
Générer des pages Web à partir de données structurées
DévelopperCette AC n'était attestée par aucune autre de mes réalisations, et c'est littéralement le principe de fonctionnement de ce site. Les 96 pages sont générées, aucune n'est écrite à la main : Eleventy interroge l'API de Directus une seule fois au moment du build, ma couche de données normalise les relations que Directus renvoie sous forme de lignes de jonction, puis les gabarits paginent — une page par réalisation, une page par apprentissage critique attesté, et jusqu'au sitemap et au robots.txt qui sont eux aussi des gabarits alimentés par la même source. Concrètement, j'ajoute une réalisation dans l'administration, je relance la génération, et sa fiche existe, la grille filtrable l'intègre, les fiches des AC concernés se mettent à jour, le compteur de couverture bouge et le sitemap la déclare — sans qu'une ligne de code change. J'ai poussé le principe jusqu'aux libellés d'interface : surtitres, boutons, étiquettes de formulaire viennent tous d'une collection de textes, appelés par une clé, avec un mécanisme qui liste les clés absentes en fin de build au lieu d'interrompre la génération. J'ai aussi décidé de ne générer une fiche d'AC que si l'AC est réellement attesté, soit 60 pages sur 75, parce qu'une page « aucune réalisation ne l'atteste » n'apporte rien au visiteur et dilue le référencement.
Modéliser les données d'une application Web
DévelopperLe modèle de données de ce site n'est pas un décalque du contenu, c'est une réponse à un problème précis que j'ai identifié en analysant mon portfolio Word. Ce document rangeait chaque projet sous une seule unité d'enseignement, ce qui obligeait ma SAÉ 302 à apparaître trois fois, amputée à chaque fois. J'ai donc modélisé une vingtaine de collections — réalisations, apprentissages critiques, compétences, univers, outils, types, expériences, SAÉ, notes, pages, textes d'interface, paramètres — et quatre tables de jonction, avec une décision structurante : la table qui relie une réalisation à un apprentissage critique porte elle-même le champ de justification. Ce texte n'appartient ni à la réalisation ni à l'AC, il n'existe que par le lien entre les deux, et le mettre ailleurs aurait obligé à le dupliquer ou à le perdre. Deuxième arbitrage : univers est une relation multiple et non un champ unique, parce que deux de mes réalisations appartiennent réellement à deux mondes à la fois — sans ça, mes deux meilleures preuves d'Entreprendre disparaissaient soit du tableau de bord académique, soit des pages Nexan et JKMC. C'est ce modèle qui a ensuite dicté le choix du CMS, et pas l'inverse.
Mettre en place ou développer un back office
DévelopperL'administration de ce site n'est pas une installation par défaut : je l'ai configurée entièrement, et cette configuration est écrite dans un script rejouable plutôt que cliquée dans une interface. Le script crée le schéma, trois rôles distincts — un rôle d'édition sans accès aux réglages système, un rôle de lecture seule avec jeton statique pour le build dont j'ai vérifié qu'il reçoit bien un refus en écriture, et un rôle public en lecture — ainsi que les notes d'aide, les icônes, les marque-pages et le bouton de publication. J'ai dû ajouter des champs à la médiathèque parce que Directus ne propose que title et description : le texte alternatif est obligatoire en RGAA, il lui fallait un champ dédié et explicite qu'on ne confonde pas avec une légende. J'ai aussi buté sur une limite réelle de l'édition communautaire, que j'ai vérifiée requête par requête : elle accepte les permissions simples mais refuse celles qui portent un filtre de lignes, ce qui rend l'API incapable de masquer un brouillon. J'ai donc déplacé le garde-fou dans la couche de données du build, et je l'ai documenté noir sur blanc pour que personne ne le retire par mégarde. Enfin, j'ai écrit un mécanisme de migrations numérotées et réversibles, parce que mon script d'installation crée ce qui manque mais ne corrige rien, avec une règle stricte : une migration ne remplit que ce qui est vide, le texte saisi dans l'administration prime toujours.
Optimiser une application web en termes de référencement et de temps de chargement
DévelopperJ'ai traité la performance et le référencement comme des décisions à arbitrer, pas comme une case à cocher en fin de projet. Le CSS est écrit en six couches puis concaténé, minifié et injecté directement dans le head : zéro ressource bloquante et zéro décalage de mise en page, contre un compromis que j'assume — environ 8 Ko compressés retéléchargés à chaque navigation, faute de cache entre les pages. Les images sont converties au build en AVIF et WebP avec repli JPEG, en plusieurs largeurs, chargement différé sauf l'en-tête des fiches, ce qui fait passer 10,88 Mo de PNG source à 2,06 Mo, soit 81 % de moins. Les polices sont auto-hébergées en woff2 plutôt que servies par Google, ce qui supprime une requête tierce et évite de transmettre l'adresse IP de mes visiteurs. Côté référencement : titre et description par page, URL canonique, sitemap de 93 URL, données structurées Person sur toutes les pages et CreativeWork sur chaque fiche. J'ai corrigé deux défauts que mon propre audit a révélés : des titres de fiches d'AC qui montaient à 204 caractères, et des images de partage qui pointaient vers le CMS injoignable de l'extérieur — elles sont désormais fabriquées au build et déposées avec le site. Mesures relevées : décalage cumulé nul, 101 Ko et 10 requêtes sur l'accueil.
Construire des outils de validation et de suivi (flux, indicateurs de performance, tableaux de bord, référencement, engagement...)
ConcevoirJe me suis fabriqué mes propres instruments de suivi au lieu de me fier à mon impression. Un script d'audit passe sur le site généré et vérifie les textes alternatifs, la hiérarchie des titres, les champs de formulaire étiquetés, les noms accessibles des zones de navigation, la validité des données structurées, la longueur des titres et des métadescriptions, plus 24 couples de contraste de ma charte — parce que mon œil ne mesure pas un ratio et que je ne relirai jamais 96 pages à la main. Un second script recalcule à la demande la couverture du référentiel et la publie sous forme de matrice. J'y ai refusé le découpage en trois états que j'avais prévu et j'en ai posé quatre, en ajoutant « déclaré sans preuve » : c'est l'état le plus traître, une case cochée que rien n'explique, et il était invisible dans le découpage précédent. Ces indicateurs ont réellement piloté la fin du chantier, et ils sont datés : 47 rattachements au départ contre 97 aujourd'hui, 23 justifications vides contre zéro, longueur médiane passée de 123 à 465 caractères. J'ai aussi accepté que l'instrument me contredise sans le trafiquer : une de mes pages dépasse d'un kilo-octet un seuil que j'avais moi-même fixé, et j'ai préféré documenter l'écart plutôt que d'amputer du contenu pour faire passer mon propre contrôle.
Maîtriser l’hébergement et le déploiement d’applications
DévelopperC'est l'hébergement qui a dicté l'architecture, pas le contraire. Le serveur cible est un Plesk sous nginx qui ne construit rien : on y dépose des fichiers en FTP. J'en ai tiré la conséquence — un site entièrement statique, qui ne fait aucun appel réseau une fois en ligne et reste debout même si le CMS est éteint. J'ai écrit un script de livraison qui reconstruit, contrôle et emballe, et qui refuse de produire l'archive si le build contient une URL localhost ou si une seule des 1 629 références internes du site pointe dans le vide ; ce premier contrôle m'a évité une mise en ligne où 60 pages portaient des liens canoniques et un sitemap pointant sur ma machine de développement. J'ai aussi dû remplacer l'archivage natif de Windows après avoir mesuré qu'il écrivait 239 chemins sur 277 avec des antislashs, ce qui produit un ZIP invalide qu'un serveur Linux décompresse en un unique fichier à la racine — panne silencieuse et incompréhensible pour qui n'a pas cherché. L'archive livrée fait 460 fichiers, 22,1 Mo compressés, avec son empreinte SHA-256 et son inventaire. Deux autres cibles sont documentées et prêtes : un fichier Docker Compose qui lance le CMS avec PostgreSQL pour un VPS, et les configurations Netlify et Vercel avec les variables d'environnement à renseigner.
