Problem
Developer portfolio templates tend to be either static pages with no way to manage content, or JavaScript frameworks that make a simple site heavy and harder for search engines to index. The goal was a site that is fast, works without JavaScript, is easy to keep up to date and is built to rank for its blog.
Approach
Server-rendered Django
Every page is rendered by Django and works without JavaScript; scripts only add search, theme switching and smooth transitions between pages. The Django admin is the CMS: projects with architecture diagrams and key decisions, a Markdown blog with code highlighting and an “On this page” list, resume entries and per-page SEO text.
SEO from the start
Unique titles and descriptions on every page, canonical links, a sitemap, RSS, structured data (Person, WebSite, BlogPosting and breadcrumbs) and generated social preview cards. One setting hides the whole site from search engines until the content is ready.
Easy to adapt
Colours live in one file per theme, content lives in the admin, and deployment is Docker Compose behind Nginx. Content can also be edited by AI agents through django-agent-content.
Swipe sideways to see the whole diagram.
Key decisions
-
A multi-page site instead of a single-page app
- Why
- Every page is real HTML that search engines index directly, and the site works without JavaScript.
- Trade-off
- Navigation loads a new page; view transitions make it feel smooth in Chrome, Edge and Safari.
-
The Django admin as the CMS
- Why
- No custom CMS to build or maintain, and every content type is editable from day one.
- Trade-off
- Editing happens in the admin, improved with a Markdown toolbar and live preview.
-
Themes in code, content in the admin
- Why
- Colours are versioned and reviewed like code, and the admin stays focused on content that changes often.
- Trade-off
- Changing the look needs a code change and a deploy.
-
Page texts with generated fallbacks
- Why
- Every page has its own search description even before it is customised.
- Trade-off
- The defaults stay generic until they are edited.
-
A plain page background instead of a fixed decorative layer
- Why
- A fixed, masked background made Firefox show a blank frame on every page change; removing it fixed the flicker.
- Trade-off
- A plainer look, carried by typography and spacing.
Result
Open source on GitHub under the MIT licence, and the site you are reading runs on it.