
PIL OS est écrit en Lua dans Minecraft. Mon dashboard et mon portfolio sont en TypeScript avec Next.js. Je ne peux pas déplacer un composant de l’un vers l’autre. Même les interfaces n’ont rien en commun.
Pourtant, je retrouve ces deux projets dans plusieurs changements récents du portfolio. Pas sous forme de code réutilisé. Sous forme de contraintes déjà rencontrées.
## PIL OS m’a appris à me méfier du trajet
Dans PIL OS, des téléphones et des bornes ATM communiquent avec un serveur central par modem sans fil. CC:Tweaked permet à ses ordinateurs d’échanger des messages avec Rednet, mais il ne fournit pas le protocole de mon application.
C’était à moi de décider ce qu’était une demande, une réponse et une erreur. Il fallait aussi accepter qu’une machine puisse décrocher. Le serveur pouvait fonctionner pendant qu’un téléphone ne recevait rien. Un message envoyé n’était pas forcément un message traité.
Cette séparation est devenue importante dans ma manière de penser une API. Je ne regarde plus seulement la fonction appelée. Je regarde tout le trajet : qui construit la requête, quelle origine elle utilise, ce que reçoit le serveur et ce que le client voit réellement.
Le portfolio m’a récemment rappelé pourquoi.
Les routes de confirmation et de désabonnement à la newsletter construisaient leur redirection avec req.nextUrl.origin. En local, rien d’anormal. Sur le VPS, derrière nginx, cette origine valait localhost:3004, l’adresse interne où écoute Next.js. Le lien reçu par le visiteur était public, mais la redirection finale repartait vers l’adresse privée du serveur.
Le problème n’était pas dans la page de confirmation. Il était entre les couches.
J’avais aussi utilisé SITE_ORIGIN pour deux besoins différents : appeler le portfolio localement depuis un cron et produire les liens publics placés dans les emails. Une seule variable représentait deux vérités incompatibles. Je les ai séparées.
Les Route Handlers de Next.js utilisent les API Web `Request` et `Response`. C’est pratique, mais cela ne retire pas le reverse proxy, les ports internes ou les origines publiques de l’équation. PIL OS m’avait déjà montré qu’un protocole ne s’arrête pas à la ligne qui envoie le message.
J’ai aussi rendu bruyant le cas où aucun email ne part. Avant, une configuration SMTP absente ne produisait rien. Impossible de distinguer un serveur qui refuse le message d’une fonction qui n’a même pas essayé. Dans un réseau Lua comme dans une API Next.js, le silence est un état ambigu.
## Le dashboard m’a appris à retirer
Le dashboard m’a donné une autre contrainte : un outil ouvert des dizaines de fois par jour ne peut pas demander d’effort inutile.
Un widget peut être intéressant à coder. S’il ralentit l’ouverture ou ne sert pas assez, il saute. Le critère n’est plus la quantité de travail investie. C’est ce qu’il apporte à chaque utilisation.
J’ai réutilisé ce filtre dans le portfolio.
Le formulaire d’abonnement occupait toute une bande entre le haut de la page blog et les articles. Il était visible, mais il repoussait le contenu principal. Je l’ai déplacé en bas et remplacé en haut par un simple lien vers une ancre. Même fonction. Moins de présence.
J’ai fait quelque chose de similaire dans l’admin. L’édition des articles se faisait directement dans l’onglet blog. L’espace était trop étroit. Au lieu de continuer à compacter les champs, j’ai déplacé la création et l’édition vers leurs propres pages, avec l’éditeur et l’aperçu côte à côte.
Ce ne sont pas des décisions spectaculaires. Elles viennent d’un outil personnel que personne ne me force à ouvrir. Si mon dashboard m’agace, je cesse de l’utiliser. Cette absence de politesse est utile : elle montre vite où se trouve la friction.
## Le pont entre les projets
PIL OS m’a appris à supposer que le transport peut mentir, échouer ou disparaître. Le dashboard m’a appris qu’une interface peut fonctionner tout en étant trop pénible pour rester.
Dans le portfolio, les deux se rejoignent. Une route doit produire la bonne réponse dans l’environnement réel du VPS. Une interface doit placer chaque action là où elle gêne le moins. Le contrat technique et le coût d’usage comptent davantage que le fait d’avoir terminé la fonctionnalité.
Je ne vais pas extraire une librairie commune entre Lua et Next.js. Le prochain travail reste plus simple : surveiller les prochains ajouts au portfolio et vérifier deux choses. Ce qui se passe quand une couche décroche. Et ce que je peux encore enlever avant qu’une action devienne une corvée.