Table of Contents
Why a portal beats email
Three things change the moment a client lands on a branded portal instead of a Notion page or an email thread.
They stop asking "any updates?" because the answer is on the dashboard. They stop losing files because there's one place. And they stop comparing you to other freelancers, because you look like a software company that also does the work.
The third one is what lets you raise rates. A portal is a brand asset.
The 5 features that matter
Skip portals with 50 features. Five do almost all the work:
1. Project list with status (Discovery / In progress / Review / Shipped).
2. File library, scoped per project (PDFs, mockups, exports).
3. Approval workflow — client clicks Approve on a deliverable, you get notified.
4. Invoices — view, download, pay (Stripe).
5. Notes / messages — one thread per project, not 15 emails.
Anything else is icing. Build the cake first.
If your business has a sixth thing your clients always ask about (e.g. timesheets for hourly work, brand guidelines for design retainers), add it. Otherwise — five.
Step 1 · Scaffold the portal (10 min)
One prompt creates the whole shell. Replace the bracketed bits with your business.
Build a client portal for <my agency, FabricLabs>. Pages: /login, /dashboard (list of projects with status badge), /project/:id (file list, notes thread, approvals list, invoice list). Use Clerk auth. Persist projects, files, notes, invoices to D1. Include a settings page where the agency owner can add new clients and assign projects to them. Brand it dark with violet accents.
You'll get a working portal with empty data in about 5–8 credits. The structure is right; you fill it with real client work in step 5.
Ready to Build?
Start building your full-stack application with Fabricate. Free tier available — no credit card required.
Start Building FreeStep 2 · Per-client auth (20 min)
By default Clerk users see everything. You want each client to see only their own projects.
Test the cross-client block before you onboard a real client. Open the portal as Client A, then in another browser as Client B. If you can read each other's files, the filter isn't applied — re-prompt Fabricate to enforce it on every endpoint.
Add a `clientId` column to projects, files, notes, and invoices in D1. On every read endpoint, filter by `clientId === currentUser.publicMetadata.clientId`. Add an admin role (set in Clerk publicMetadata.role = 'admin') that can see everything and assign clientId on user invite. Block non-admins from any cross-client read.
Two prompts here are normal — the first scaffolds, the second tightens. Test by inviting yourself as a non-admin and confirming you only see one client's data.
Step 3 · Files + approvals (30 min)
Files go to Cloudflare R2 (Fabricate wires this for you). The approval workflow is one boolean column + a notification.
Add file upload to /project/:id using R2 storage, scoped by clientId + projectId. Show a list of files with download links. Add a `deliverables` table: title, fileId, status (pending | approved | changes_requested), client_comment. On the client side, an Approve button sets status=approved and emails me via Resend. On the agency side, I can see all pending approvals on the dashboard.
The Resend email is the magic — you no longer ask "have you approved the latest design?" because Resend tells you the moment they click.
Step 4 · White-label it (20 min)
Two changes turn 'a Fabricate app' into 'your portal':
1. Custom domain. In the Fabricate project settings → Custom domain → add `clients.youragency.com` and follow the CNAME instructions. ~10 minutes including DNS propagation.
2. Logo + colour. Drop your logo into the project, then prompt: "Replace the placeholder logo on the sidebar and login page with /assets/logo.svg. Use my brand violet (#6D28D9) as the primary accent."
Custom domain is a Pro feature. If you're on Free, do steps 1–3 first to make sure the portal works, then upgrade just before onboarding your first client.
Ready to Build?
Start building your full-stack application with Fabricate. Free tier available — no credit card required.
Start Building FreeStep 5 · Migrate your first client (1 hour)
Pick the client most likely to love it — usually the one who emails you the most often. Email them: "I've built a private portal for our work — projects, files, approvals, invoices. Sending you a login now. Same fee, less email."
Copy their existing project status from Notion / spreadsheets / wherever, upload the last three deliverables to the portal, and post one note in the messages thread saying "All your stuff is here from now on." That's the migration.
Repeat for client 2 and 3 over the next week. By client 5 the migration takes 20 minutes.
How to charge for it
You have two pricing moves once the portal is real.
• Bundle it. Add 10–20% to your retainer next renewal cycle, framed as "includes our private client portal." Most clients don't push back if you ship the value first.
• Productise it. Sell the portal access for $49–$99/month on top of project fees, especially to clients who keep asking for status updates. The portal pays for itself across 3 clients in two months.
Don't charge existing clients separately mid-contract. Roll it into the next renewal — no friction, no negotiation. New clients see the portal as part of the offering from day one and pay the higher rate naturally.
What's next
You shipped the portal. Two natural next moves:
• Add Stripe invoices via the playbook "Add Stripe in 30 Minutes" so clients pay directly from the portal. Reduces invoice-chasing time to zero.
• Productise further — once 3+ clients are on the portal, package the same setup as a sub-SaaS for other freelancers in your niche. We've seen this turn into $1–5K MRR for agency owners within a quarter.
Ready to Build?
Start building your full-stack application with Fabricate. Free tier available — no credit card required.
Start Building FreeFrequently Asked Questions
I'm a solo freelancer, not an agency. Is this overkill?
No — solos benefit more, not less. The portal is what lets a solo charge agency rates without hiring. The 5 features take a weekend; from then on you're competing on output, not on email response time.
Can clients comment on specific files like Figma?
Add a `file_comments` table in step 3 with one extra prompt. For most agencies the Approve / Request changes binary is enough; per-file threaded comments tend to be premature unless you're a design studio.
What about white-label email — can the portal send from my domain?
Yes. Add a Resend domain (DNS) in your Resend dashboard and prompt Fabricate: "Send all portal emails (approvals, invoices) via Resend from notifications@youragency.com." Clients see your domain, not Fabricate's.
Can I let clients self-onboard or invite their teammates?
Yes — extend Clerk to allow invite-only team members under a clientId. One prompt: "Allow admins of each client account to invite teammates by email. Teammates get the same scope as the inviting client." Most agencies eventually want this once their clients are organisations, not individuals.
Will the portal scale if I onboard 50 clients?
D1 + Cloudflare Workers easily handle thousands of clients on this shape. You'll hit organisational complexity (managing 50 clients) long before technical limits. If you do scale that far, we have agency users running 100+ clients on a single portal.