Building my personal home dashboard
Posted on
I've been working on a dashboard for myself, and this is the first devlog. Its first two modules are Lists, for todo lists, shopping lists, or anything else, and Recipes, where I can save things I've cooked, with some pictures and history.
It sounds very simple, and it is, but I had a few goals:
- Make a tool that is tailored exactly to how I want to use it
- Have it be easy to adapt and add new features (scalable to my needs)
- Have it be usable by multiple people
- Host it on my own private VPS
- Learn some interesting new tools and techniques
Modular Structure
The dashboard is organized around households. Each household can have multiple users, and each user can belong to multiple households. Every household can enable whichever modules it needs. The modular structure also makes it easy to add new functionality. Since I’m learning French, I might build a flashcard module for studying vocabulary. Or maybe I’ll add a workout tracker when I train for a race. It could be anything.
- Module 1
- Module 2
- Module 3
- Lists
- Recipes
- Lists
- Flashcards
- Workout tracker
User experience, Linear and Zero
I wanted the dashboard to feel really nice to use. At my work, we use a product development tool called Linear. Using it has felt super nice because everything about it is instant. I want to create a new issue, instant. I want to edit a piece of text, instant. I want to navigate between thirty different issues, instant. I never experience any lag while navigating the UI. So could I do the same?
Most web apps work like this: the user clicks something, the browser asks the server for some information, some loading state is displayed while the server is thinking and shortly after: data shows up in the website.
Linear's main idea is that it is local first: the browser keeps a local copy of the data it needs, allowing the UI to update immediately. In the background, a sync engine sends local changes to the server and brings remote changes back to the client. We still need the server, we simply don't make the UI wait for it.
I decided to try a similar approach using a library called Zero by Rocicorp. Zero and Linear work differently in a few ways, but the main ideas are the same.
Image pipeline
I also wanted to have images feel instant. When an image is uploaded, it is stored in Cloudflare and converted into two compressed variants: a small thumbnail.webp for recipe covers and image galleries, and a larger viewer.webp for fullscreen viewing.
For example, uploading this 2.7 MB carbonara.jpeg produced a 327 KB viewer image and a 74 KB thumbnail, which are roughly 8x and 36x smaller than the original image, resulting in faster loading times, without a meaningful loss of image quality.
CI/CD, deployment, and VPS hosting
Another thing I wanted to learn was how to set up my own infrastructure, which is something I’d never done from start to finish. I had three main goals:
- Every push and pull request runs formatting, linting, type-checking, tests, and production build checks
- Automatically deploy changes merged into the
mainbranch - Host the application on my own domain using a European VPS
I achieved exactly that by using GitHub Actions for CI/CD, Docker Compose to run the application, and Caddy for HTTPS and routing. Everything runs on an OVHcloud (🇪🇺) VPS.
Learning with AI and developing with AI
When I was first starting the project, I wrote most of the code myself and used AI more like a tutor. I created a guided learning skill that had the AI guide me through implementations and quiz me afterward. We went back and forth discussing architectural tradeoffs and the concepts that I wasn't familiar with.
Once the patterns were established and the work became repetitive, I started relying more on AI. Zero queries and mutators, for example, mostly follow the same structure. By having agents reference existing implementations, I could minimize the chance of them introducing a new pattern with every feature.
I also had AI maintain living documentation covering most aspects of the dashboard. Each feature has its own specification, giving new agents the context they need to work without getting lost. I also keep a backlog of ideas that the agents can turn into more detailed tasks and implement.
Currently, implementing new features is very fast. I’ve even started treating code as more disposable, especially when iterating on small UI and UX details. I have agents generate several options, then I evaluate them, compare them with other applications, and guide the agents through more iterations until I arrive at something that feels right.
And more
There were plenty of smaller things to learn along the way. I built my own JWT authentication, turned the dashboard into a Progressive Web App I can install on my phone, used some neat tricks to store orderings of items, etc.
In general, I'm pretty happy with the result. I recommend reading this article that inspired a lot of my architectural decisions for this project: How's Linear so fast? A technical breakdown.