

A Private Client Portal for Freelancers
Managing clients through Notion and email gets messy. I built a private portal to fix that, and you can use it too.
If you’re doing client work, someone already solved this problem for you. Dubsado, HoneyBook, Notion, even a well-organized Gmail folder. These exist, they work, and they’re cheaper than the time it takes to build something from scratch.
Why did I build my own client portal anyway?
The short answer: I wanted my client data on my server, not someone else’s.
The problem with existing tools#
Most tools in this space are either too general-purpose or too expensive. Notion gives you infinite flexibility but zero client access control. Share a Notion page with a client and they can see everything in that workspace if you’re not careful. Project management tools like Trello or Linear are built for internal teams, not external clients. And the professional CRM options are full suites with pricing to match, more than you need if you’re running a small freelance operation.
What I actually needed was straightforward: a place where I can invite a client, assign them to their project, share documents, and see a clean record of what happened and when.
What I built#
The system runs at sys.srmdn.com. Each client gets their own space and only sees their own projects, with no visibility into anyone else’s work.
Clients get an invite link by email when I add them. They set a password, land on their dashboard, and see their projects and any documents I’ve shared.
The document editor is Markdown-based. I write notes, deliverables, or reports inside the system, and when something is client-facing, I send it directly to their email with one click. That last part replaced a workflow I used to hate: draft in one app, copy to email, reformat, send, and then immediately lose track of whether I actually sent it.
There’s also an audit log. Every significant action gets recorded with a timestamp. The value of this only became clear after using it: when a client says “I never received that,” you can pull up exactly what happened.
How it’s built#
Backend is Go, using the Fiber framework. Frontend is React with Vite, served as a static SPA. Database is SQLite. Everything runs on the same VPS that serves this blog: one more nginx vhost, one more systemd service.
No Docker, no Kubernetes. Deployment is building a binary and restarting a service. The whole thing runs comfortably under 50MB of RAM.
I chose SQLite deliberately. This is a single-user system with a small number of clients. SQLite’s concurrency limits aren’t a concern at this scale, and I can back up the entire database by copying one file. For a system like this, SQLite is the right call.
What surprised me#
Building it was faster than I expected. Getting it secure took much longer.
After the initial build, I ran a self-audit and found 17 issues. Most were minor (missing security headers, too-long JWT expiry, overly verbose error messages on auth failures), but a few would have been real problems in production. None were catastrophic, but it was a useful reminder that “it works” and “it’s safe” are different checkboxes.
The invite flow was also more complex than it looks. Expired links, duplicate accepts, re-invites for existing accounts: each one has to be handled explicitly. The happy path is five lines of code. The edge cases are fifty.
The other surprise was the editor. I started with a popular rich text editor and eventually replaced it with Milkdown, a Markdown-first WYSIWYG. The reason: the original editor stored content as HTML blobs, which means documents only render correctly inside that same editor. Markdown is plain text, readable anywhere without a special tool, and it doesn’t become unreadable as software changes.
Most freelancers should use an existing tool. Building your own is only worth it if control matters more than time cost, and you’re clear-eyed about what that trade looks like over two or three years of maintenance.
For me, it was worth it. I know exactly what the system does, I own the data, and it fits my workflow precisely. But I’ve also spent more hours on it than any SaaS subscription would have cost me. That’s not a regret, just a fact worth naming.
The system is open to other freelancers at sys.srmdn.com ↗. You get the same setup I use: project workspaces, a Markdown doc editor, and invite-by-email for clients. No seat pricing or company tiers.