Skip to content
All projects

SaaS case study

Project Management Platform

Task, time and client-visibility tooling for a small agency running parallel projects.

Status emails
-73%
On-time milestones
+29%
Client portal usage
weekly
src/lib/pipeline.ts — VS Code
export async function run(job: Job) {
  const key = idempotencyKey(job)
  if (await seen(key)) return skip(job)
  const result = await withRetry(() =>
    provider.execute(job.payload), { max: 5 })
  await persist(result)
  return ok(result)
}

Interface reference — rendered from the real component structure, not a stock image.

The problem

Clients asked for status updates constantly because there was nowhere to see progress.

The solution

Internal task board plus a read-only client portal that shows milestones without exposing internal notes.

Hard parts

Two audiences, one dataset. Field-level visibility rules keep internal discussion private.

Outcome

Status-update emails largely disappeared, and project scope stayed visible to everyone.

Technology used

  • React
  • TypeScript
  • Supabase
  • React Query

How it was delivered

  1. 01Client problemAccount managers spent hours writing update emails.
  2. 02ResearchAsked clients what they actually wanted to know — dates and blockers, nothing else.
  3. 03PlanningSplit internal and external views at the data layer, not the UI layer.
  4. 04WireframeBoard for the team, timeline for the client.
  5. 05DevelopmentRow level security per project membership, typed API surface.
  6. 06TestingVerified no internal field could leak into the portal payload.
  7. 07DeploymentRolled out to two pilot clients before the full book.
  8. 08ResultsClients self-serve status; the team writes fewer emails.

Lessons learned

Enforce visibility in the database, not the component. UI-level hiding is not security.

More case studies