The Problem I Was Trying to Solve
I'm a freelancer. And like most freelancers, I was using:
- WhatsApp to send files to clients
- PayPal to collect payments (and lose 3-5% in fees)
- Gmail for invoices (copy-pasting from a Word doc)
- DocuSign for contracts ($25/month just for e-signatures)
- Random Google Drive folders for file sharing
It looked unprofessional. Clients lost things. I chased
payments for weeks.
I couldn't find one tool that did everything at a price
that made sense for a solo freelancer.
So I built it.
What I Built
PortalFlow — a client portal for freelancers.
Each client gets a unique portal link. Inside that link they can:
- ✅ View and pay invoices online (Stripe payments)
- ✅ Download shared files
- ✅ View and sign contracts
- ✅ See everything in one professional page
You (the freelancer) get a dashboard to:
- Create and send invoices
- Upload and share files
- Write contracts and send for signature
- Get paid directly to your Stripe account
- Send automatic payment reminders
All for $7/month. Less than one DocuSign subscription.
The Tech Stack
Here's everything I used to build it:
Frontend
- React 19 (Create React App)
- TailwindCSS for styling
- React Router for navigation
- Deployed on Vercel
Backend / Database
- Supabase (PostgreSQL + Auth + File Storage)
- Row Level Security for data isolation
- Supabase Auth for user management
Payments
- Stripe Checkout for invoice payments
- Each freelancer connects their own Stripe account
- Payments go directly to the freelancer — no platform cut
Emails
- Resend for transactional emails
- Each freelancer uses their own Resend API key
- Emails sent from their own domain
Hosting
- Vercel (serverless functions for API routes)
- Zero server management
The Hardest Parts
1. Per-user API keys
The trickiest architecture decision was payments. I wanted
payments to go directly to the freelancer — not to me first.
Solution: each user stores their own Stripe secret key in
Supabase user_metadata. When a client pays, the API looks up
that freelancer's key and creates the Stripe session with it.
No platform cut. No escrow. Money goes straight to the freelancer.
2. Serverless functions on Vercel
Moving from Express to Vercel serverless functions was a
learning curve. Each file in the api/ folder becomes an
endpoint. No shared state between requests.
3. Row Level Security in Supabase
Every query in the database is automatically filtered by
the logged-in user. No freelancer can see another
freelancer's clients or invoices — enforced at the
database level, not the application level.
What I Would Do Differently
- Start with Stripe Connect instead of per-user keys (more complex but more scalable)
- Use Next.js instead of Create React App (better for SEO and serverless)
- Build the email system last — it caused the most bugs
Current Status
- ✅ Live and working
- ✅ First payments processed
- 🔍 Looking for beta users and feedback
Live at: https://frontend-orpin-theta-64.vercel.app
If you're a freelancer or know one — I'd love for you
to try it and tell me what's broken or missing.
And if you've built something similar, I'd love to know
what problems you ran into.
Top comments (0)