I keep a lot of projects moving — Zweek, this portfolio, freelance work — and each one needs a roadmap: what to build next, what’s in progress, what’s done. The mainstream kanban tools (Trello, Jira, Linear) are built for teams. They demand accounts, email verification, board hierarchies, workflows, billing — the whole machinery of an organization, when what I wanted was a piece of paper with columns that happens to live on the internet.
So I built Fast Kanban, and its own roadmap card says it best: “perfect for temp projects or fast projects. Easy to share and track. Privacy, no e-mails logins or names.” A kanban board should behave like a URL: you create it, you share it, and it works.
No accounts — a per-board edit key. The core decision. A board is a shareable document, not a social network. Creating one returns a random nanoid URL and a one-time edit key, shown to the creator exactly once. Anyone with the link can read; any write requires the key via an X-Edit-Key header. The key is stored only as an scrypt hash (salt:hash) and verified with timingSafeEqual — no plaintext anywhere, no sessions, nothing to reset. The frontend keeps the key in localStorage and can call a verify endpoint to check whether it still works. This single decision removes signup, login, password reset, and user management from the entire product.
Why build it at all. Existing tools are team-centric SaaS with overhead I refused to pay — in money and in friction. For personal roadmaps, the product bar was: create a board in three seconds, share the link, never think about the tool again. No existing tool felt like that. (The dogfooding loop is satisfying: this case study’s parent project runs its roadmap on this tool, and this tool’s own roadmap runs on itself.)
Hono, portable across runtimes. The API runs on Hono over @hono/node-server. The server code deliberately avoids Bun-only APIs, because the same code runs on Bun during local development and on plain Node in production — one codebase, two runtimes, zero forks. An interesting quirk surfaced along the way: Bun’s bundler inlines NODE_ENV at build time, so the production server doesn’t gate on it — it always serves both the API and the built SPA from a single Node process.
Vue 3 + Vite SPA. Vue 3 with <script setup>, vue-router, and vuedraggable for drag-and-drop columns. Card bodies are Markdown, rendered with markdown-it and sanitized with DOMPurify — user content is always scrubbed before it hits the DOM. Light/dark theme is a first-class toggle, not an afterthought.
Prisma + MySQL/MariaDB. Boring, reliable persistence. A boards table holds the nanoid URL slug, a custom prefix, the scrypt edit hash, and a next_seq counter; cards, columns, and tags hang off it. Boards get their default columns (Backlog, Todo, Doing, Done) at creation time.
Human-readable card IDs. Each board declares a prefix — FAK, ZWK, PROJ — so cards get IDs like FAK-16 instead of #482913. Sequence allocation is atomic (a transactional increment), so IDs never collide even with parallel creation. This turned out to be the most loved feature: my commit messages literally reference the ticket — [FAK-16] Prevent clickout when edit a card.
Custom columns, colors, and tags. A board can have up to eight columns, each with a color from a curated palette (gray for Backlog, blue for work, green for Done), and up to five tags per board. Enough structure to organize a roadmap, not enough to manage a team.
Deploy: GitHub Actions → CloudPanel. CI runs typecheck and both builds on every push; a deploy job on main SSHs into the CloudPanel VPS, pulls, migrates, builds, and restarts the PM2 process. One process serves the API and the SPA from dist/ — the whole product is a single Node process behind one domain.
The edit key is a single point of failure. It’s shown once and only a hash is stored — if you lose it, you can’t edit that board anymore. The verify endpoint lets the UI at least distinguish “key wrong” from “you don’t have a key,” which keeps the failure mode honest. This is the direct trade-off of removing accounts.
Cross-runtime discipline. Writing server code that must run on both Bun and Node meant auditing every API call — no Bun.serve, no Bun.password, using node:crypto scrypt instead. The production bundle also has to keep @prisma/client external because of its native bindings. Small constraints, but they had to be enforced from day one or the “runs everywhere” property quietly rots.
Markdown safety. Card bodies are free-form user content. Rendering them without sanitization would be a stored XSS hole; the answer is a two-stage pipeline — markdown-it to render, DOMPurify to strip anything dangerous — applied to every card body, every time.
vuedraggable. Two projects, two answers — here the column-reordering UX inside a settings modal justified the library, there the drag payload needed full control.Fast Kanban is live at fast-kanban.zwinglio.com and in daily use. The Zweek roadmap runs on it — the very board that produced the [ZWK-*] tickets — and its own roadmap is tracked on itself at fast-kanban.zwinglio.com/b/h62m34fw5d, the [FAK-*] board behind every commit in this project’s history. It’s the kanban that behaves like a URL: create it, share it, get back to building.