kevin-dev.com

July 2026Ongoing

Le siteCode source

This is the site you're reading right now: portfolio, blog, résumé, contact form, and behind it a full admin area so I can manage everything myself. It's the third version, and the first I didn't copy from anyone.

The two before it

The first one dates from 2021. HTML, CSS, a bit of JavaScript, all followed step by step from a video tutorial. I take no technical pride in it, but it's very concretely what taught me those three languages: reproduce, break, understand why it broke, start again. I even hosted my projects of the time in it, a Java minesweeper and a small platform game, straight in the repository.

The second one, in 2022, still followed a ready-made template, but I was starting to move away from it. I added interactivity: a mobile menu, a skills accordion, tabs for my education, a project carousel, the nav link highlighting itself as you scroll. It served me for nearly four years, and I maintained it until recently.

Both were static. To change one line, I opened an HTML file, edited the text by hand, pushed to Git and waited for the redeploy. That works when you update your résumé once a year. It stops working the moment you want to write.

What I actually wanted

Somewhere I could add a project, write an article, fix a sentence, from an interface, without touching code or redeploying.

That's the starting point of this version, and it's also the part that took the most work: the part nobody sees.

The admin area

The back office covers about a dozen sections: projects, articles, talks, technologies, categories, media, contact form messages, legal pages, home page content, security, sessions, and a dashboard.

The content editor offers two modes over the same Markdown source. A visual mode to write normally, with tables, images and lists, and a raw mode with syntax highlighting when I want to see exactly what I'm writing. Content is stored twice, as Markdown to stay readable and recoverable, and as pre-rendered HTML so the display isn't recomputed on every visit. Rendering goes through unified, remark and rehype, with code highlighting and diagrams.

Uploaded images are converted to WebP and generated in several sizes, so a page serves the right variant rather than a two-megabyte image.

Access is protected by a second factor, and the contact form sends its notifications through a mail gateway running on my own server.

One detail I'm happy with: scheduled publishing. An entry can carry a future date, and the rule deciding what is publicly visible lives in exactly one place in the code, shared by projects, articles and talks. Not a condition copy-pasted into every controller, with the risk of missing one and exposing a draft.

A style that's finally mine

After two versions built on templates, I wanted a design I could defend line by line.

The result is deliberately plain: light by default, very airy, a single accent colour, a deep red, and three typefaces with clearly separated roles. No flourishes, no animation that draws attention to itself, no concept design. The tone of the text follows the same logic, factual rather than promotional.

It's a deliberate stance: the site should make you want to read what's in it, not admire its layout. The fonts are self-hosted too, like everything else.

On the technical side

The site runs on AdonisJS, largely because I wanted to try something else. I'd already done several projects with Next.js, and I was curious what a more classical framework felt like, with its ORM, validation, sessions and file storage provided out of the box.

The part I take away is the bridge between server and interface. The front end is React, but there's no API between the two: controllers hand their data straight to the React page, with types shared end to end. No API layer to maintain, no duplicated types, one source of truth. For a content site, it's the best trade-off I know.

Hosting it all myself

The site runs on my own server, deployed automatically on every push to the main branch. The database is isolated on an internal network: it's reachable neither from the internet nor from the other projects running on the same machine.

Visit statistics are self-hosted as well, and so is mail delivery. Nothing this site does depends on a third-party service I don't control, and that was the intention from the start.

Where I am

The content is being filled in, in a specific order: projects first, one by one, going back through each codebase to check what I claim about it. Then the blog, for which I already have ideas.

It's roughly the opposite of the usual order, I built the tool before having the content. But that's exactly why I built it: I wasn't writing because writing meant editing HTML by hand. Now there's no excuse left.

Technologies used