Mon site perso : SvelteKit, blog et terminal
Pourquoi ce site ?
J’avais besoin d’un endroit pour expliquer mes projets et raconter ce que je fais, ainsi que mes expériences. Tout ce que je n’avais pas la place de mettre sur LinkedIn ou qui n’y aurait pas forcément sa place, c’est un site pour moi avant tout : des articles, des projets et un petit terminal interactif, parce que sinon ça fait un peu trop simple, même si j’aime bien le style minimaliste.
Avant ça, j’avais déjà fait des sites plus simples, au début avec HTML + JS vanilla et Flask, puis avec Svelte. J’essaie de faire quelque chose de propre, que je puisse faire évoluer facilement et qui tourne sur mon cluster comme le reste.
Repo : github.com/BaptTF/bapttf-front
Vue d’ensemble
Le site, c’est un frontend SvelteKit en TypeScript, servi en statique. Le contenu vit dans des fichiers Markdown. Sur la home, il y a un terminal qui parle à un backend Go via WebSocket.
| Brique | Choix | Rôle |
|---|---|---|
| Frontend | SvelteKit + TypeScript | App, routing, pages |
| Contenu | Markdown + mdsvex | Articles et pages projet |
| Style | Tailwind CSS 4 | UI |
| Build | adapter-static | Export HTML/CSS/JS |
| Serveur | static-web-server | Servir le build en prod |
| Backend terminal | Go (API + WebSocket) | Easter egg / Hall of Root |
| Deploy | Docker → GHCR → ArgoCD | GitOps sur mon K3S |
Le frontend est volontairement simple. Pas de CMS, pas de base de données pour le blog. Un dossier src/posts/, des fichiers .md, et c’est tout.
Stack frontend
SvelteKit
J’ai choisi SvelteKit parce que j’en avais déjà fait et que j’aime bien. C’est léger, c’est super intuitif. Le modèle avec les +page.svelte / +page.ts, le routage par fichiers et le fait de pouvoir générer du statique, c’est vraiment bien.
Le site tourne avec Svelte 5 ($props(), $state(), $effect()). Au début il faut comprendre, mais une fois pris en main c’est agréable.
Contenu en Markdown
Les articles sont des fichiers Markdown avec du frontmatter. mdsvex les transforme en composants Svelte. Un article “classique”, c’est juste un titre, une date et des tags. Un article de projet a en plus un bloc project :
project:
slug: bapttf-front
link: "https://github.com/BaptTF/bapttf-front"
description: "Mon site perso, portfolio, blog et terminal interactif."
featured: true C’est ce qui permet d’avoir à la fois un blog et une page projets sans dupliquer le contenu. Un projet = un article. Si je veux parler d’un repo, j’écris l’article, je mets le frontmatter project, et il apparaît automatiquement.
Design
L’UI est volontairement sobre : navbar, footer, dark mode via prefers-color-scheme, pas de framework de composants trop lourd. L’idée, c’était que le contenu passe avant le design. Le terminal est le seul élément un peu lourd de la home.
Le terminal et le Hall of Root
En cours : le terminal interactif n’est pas encore sur la page d’accueil (backend Go à finir).
Sur la page d’accueil, il y a un faux terminal. Il se connecte en WebSocket à mon API Go ; tu peux taper des commandes et, si tu trouves le mot de passe root… tu rentres dans le Hall of Root.
C’est un easter egg. Tu obtiens les privilèges, tu entres un pseudo et tu apparais sur /root avec les autres qui ont réussi. Rien d’utile, c’est juste un petit challenge de cybersécurité parce que j’aime bien les CTF.
Côté frontend, c’est un composant Svelte qui gère :
- la connexion WebSocket
- l’affichage des lignes
- le prompt
$/# - la popup du pseudo une fois root obtenu
Les URLs API/WS passent par des variables d’environnement (PUBLIC_API_URL, PUBLIC_WS_URL) injectées au build Docker.
Build et déploiement
Le site est généré en statique. Pas de Node en prod côté frontend : SvelteKit génère les pages, et static-web-server les sert dans le conteneur.
Le Dockerfile est en multi-stage :
node:22-alpine→npm ci+npm run build- image finale légère avec le dossier
build/
La CI GitHub Actions fonctionne ainsi :
- check + lint + build
- sur
main, build de l’image Docker - push sur GHCR (
latest+ tag sha) - ArgoCD côté cluster récupère la nouvelle image
Autrement dit : un push sur main, et le site se met à jour tout seul. Même logique que le reste de mon infra, décrite dans l’article vps-infra.
Choix techniques
Pourquoi du statique ?
Un site perso n’a pas besoin d’un runtime Node. De l’HTML pré-généré, c’est plus simple à héberger, plus rapide, et ça consomme quasi rien sur le cluster. Les seules parties dynamiques (terminal, Hall of Root) passent par l’API Go à côté.
Pourquoi Markdown plutôt qu’un CMS ?
Parce que je veux écrire dans mon éditeur, versionner le contenu avec le code, et ouvrir une PR si j’ai envie. Pas de panneau d’admin, pas de plugin qui casse, pas de base à sauvegarder pour trois articles.
Pourquoi un backend séparé pour le terminal ?
Le frontend ne doit pas connaître le mot de passe root ni gérer la liste des rooters. Ça vit côté backend. Le site reste statique, les secrets doivent rester dynamiques. Et ça me donne une raison d’avoir un petit backend dans la stack.
Ce que j’aimerais améliorer
C’est un premier jet qui marche, mais il y a clairement de la marge :
- Plus de contenu — le site existe, maintenant il faut écrire
- Le backend Go — mieux documenter l’API du terminal / Hall of Root, peut-être la lier plus clairement depuis cet article
- SEO / métadonnées — Open Graph, descriptions propres par page
- Quelques améliorations UX — navigation au clavier dans le terminal, meilleurs états de chargement sur
/root - Tests — aujourd’hui la CI fait check/lint/build, pas encore de vrais tests
En résumé
Mes choix
- SvelteKit + adapter-static : simple, rapide, parfait pour un site perso self-hosté
- Articles = source de vérité pour le blog et les projets
- GitOps jusqu’au bout : même pipeline que le reste de mon infra
- Le terminal : un petit aspect fun du site, et ça permet d’avoir un frontend + backend
Choix discutables
- Deux repos / deux services (front + API Go) pour un site perso, c’est peut-être overkill, mais j’aime que ce soit propre.
Ce que je changerais
- Clarifier le lien entre ce repo et le backend terminal dans la doc
En résumé : c’est mon petit site sur internet. C’est pas révolutionnaire, mais c’est à moi, c’est propre, ça tourne sur mon cluster et ça me permet d’écrire sur ce que je veux.