← Work

Case Study

Client Room

Client portal for freelancers — one room per client, no client accounts required

Status

Live · clientroom.app

Client auth

Token URL, no login

Payments

Stripe Checkout

React 19 · TypeScript · Vite · Firebase · Firestore · Stripe · Cloud Functions · Cloudflare Pages

Client Room

Problem

Freelancers managing multiple clients lose time to scattered email threads, misplaced files, and chasing invoice payments — with no single place to track where a project actually stands.

What Was Built

A full-stack client portal where freelancers create a private room per client — with real-time messaging, file sharing, milestone tracking, and Stripe-powered invoice payments. Clients access their room via a unique token URL with no account or login required. Built on Firebase, Stripe, and Cloudflare Pages.

Outcome

A production app at clientroom.app, used by freelancers and event vendors who work one-on-one with clients. Demonstrates real-time architecture, secure accountless access, Stripe payment integration, and full-stack Firebase development.

Background

Freelancers send too many emails. Project updates in Gmail, files in Google Drive, invoices in Wave, milestone check-ins in Notion. Clients bounce between five tools and still reply to the wrong thread.

Client Room gives each client a single private URL that holds everything related to their project — messages, files, milestones, and invoices — in one place.

The Problem

Off-the-shelf client portals either require clients to create accounts (friction that kills adoption) or bundle so many features they stop feeling lightweight. The goal was a minimal, opinionated tool: one room per client, accessible by link, with exactly what a freelance engagement needs and nothing else.

What I Built

A full-stack client portal on Firebase:

  • Token-gated rooms — each client gets a unique link with a 24-character token. Click the link, you're in. No signup, no password, no app to install.
  • Real-time messaging via Firestore onSnapshot, feeding React Query's cache directly — messages appear instantly without a separate fetch layer
  • File sharing — both sides can upload; files live in Firebase Storage with the client token encoded in the path as a server-side guard
  • Milestone tracking — ordered milestones with status progression to keep projects on track
  • Invoice payments — line-item invoices with Stripe Checkout; a Cloud Function webhook marks invoices paid automatically on completion
  • Link recovery — clients who lose their room link submit their email; a Cloud Function looks up matching rooms and resends the links via email
  • Freelancer dashboard — activity badges surface overdue invoices and unread client messages across all rooms

Key Technical Decision

Accountless clients via token URLs instead of magic links or guest authentication. Requiring clients to create accounts — even frictionless ones — adds a step that kills adoption for a tool built around simplicity. The token is a cryptographically random 24-character string. Firestore security rules verify it on every client write by looking up the parent room. Storage paths encode the token as a path segment since Storage rules can't read Firestore — a deliberate tradeoff that keeps file uploads fast without routing them through Cloud Functions.

Stack

React 19 + TypeScript + Vite · Firebase Auth · Firestore · Firebase Storage · Cloud Functions · Stripe Checkout · Cloudflare Pages

Visit clientroom.app →
Next ProjectCDR Dashboard

Got something in mind?

Let's figure out if it's a good fit.