A multi-tenant project management SaaS: workspaces with roles, a real-time Kanban board and Stripe subscriptions — designed, built, tested and deployed by me.
The project board. Drag a card and every teammate's board updates live.
The goal
Build a Linear/Trello-style tool that includes the parts tutorials usually skip — multi-tenancy, permissions, billing and real-time sync — and prove they work with automated tests.
What it does
Teams sign up, create a workspace and invite people by email as an Owner, Admin or Member.
Every project gets a Kanban board — To Do, In Progress, Done. Cards move by drag and drop and sync live for everyone.
Each card shows who last updated it, since any member can move tasks.
The Free plan allows 1 project and 3 members; Pro unlocks unlimited projects and members through Stripe Checkout.
New accounts confirm their email through a verification link.
Members and invites. Roles are checked on the server.Workspace home, with the Free plan's limits in the sidebar.
How it's deployed
Next.js app
Vercel
Pages, API routes and Stripe webhooks
Socket.IO server
Railway
Holds the WebSocket connections that Vercel's serverless functions can't keep open
PostgreSQL
Neon
Separate databases for tests and production
Payments
Stripe
Checkout for upgrades, webhooks to switch a workspace's plan
Email
Resend
Verification and invite emails sent from my own domain
Key decisions
A separate real-time server
Vercel runs code as short-lived serverless functions, which can't hold WebSocket connections open. So the Socket.IO server runs on its own on Railway, and the Next.js app stays on Vercel.
Roles read from the database, every time
Permission checks read the member's role from the database on every API call, not from the login token, so a role change takes effect immediately.
Task status checked in the API
Status is a plain string in the database, and Zod enforces the allowed values in the API. Adding a new column later needs no database migration.
Instant drag, safe rollback
A card moves the moment you drop it, the change saves in the background, and the card snaps back if the save fails.
Bugs worth telling
The invite API accepted the role “OWNER”
What happened: the role check only existed in the invite form, so a direct API call could invite someone as an Owner. An integration test caught it.
Fix: moved the validation to the server, where nobody can skip it.
Dropping a card on an empty column did nothing
What happened: only the cards were drop targets, so an empty column had nothing to drop onto.
Fix: made every column a drop target too, and used the column's status when a card lands on it.
Drag and drop wouldn't start
What happened: the browser's text selection grabbed the mouse before dnd-kit could.
Fix: turned off text selection and native dragging on cards.
Testing
Vitest integration tests, run against a real test database
32
Playwright end-to-end tests: signup, invites, the board and Stripe checkout
11
bugs found by these tests, then fixed
4
GitHub Actions runs both suites on every push.
What I'd do next
Let one person belong to several workspaces, with a workspace switcher.
Reorder cards within a column, which needs a position field on tasks.
Switch to database sessions, so changes like email verification show up without logging in again.
Try it yourself
Try the live demo
Shared Admin account
Emaildelivered+flowboard-demo@resend.dev
Password12345678
Tip: open it in two browser windows and drag a card — the other window updates live.