Features

Lead Funnel

A 6-column Kanban board that tracks every lead from first contact to collected payment. Drag cards between columns to update status instantly.

The 6 Columns

Each column represents a stage in your sales pipeline. Leads flow left-to-right as they progress, or drop into Rejected at any point.

New

Fresh leads that just came in. These need initial outreach or a discovery call before you send a proposal.

Proposal Sent

You have sent a proposal and are waiting for the client to review and accept one of the pricing tiers.

Working On

The client accepted your proposal and work is actively in progress. A project record has been created.

Outstanding

Work is complete and an invoice has been sent, but payment has not been received yet.

Paid

Payment collected. The lead lifecycle is complete. This column feeds your revenue dashboard.

Rejected

The lead declined, went silent, or was disqualified. Kept for analytics so you can track your win rate.

Drag-and-Drop

The funnel uses HTML5 drag-and-drop to move leads between columns. When you drop a card into a new column, a server action fires to update the lead status in the database. The UI updates optimistically so there is no visible delay.

  • *Grab any lead card and drag it to the target column
  • *Drop zones highlight as you hover over a valid column
  • *Status updates are persisted immediately via server action
  • *Cards show the estimated value, client name, and days in current status

Status Lifecycle

Leads follow a defined lifecycle. While you can drag to any column, the typical happy path flows like this:

New → Proposal Sent → Working On → Outstanding → Paid

A lead can move to Rejected from any stage

prisma/schema.prisma
// Lead status enum in Prisma schema
enum LeadStatus {
  NEW           // Just added — needs follow-up
  PROPOSAL_SENT // Proposal delivered, waiting for response
  WORKING_ON    // Client accepted, project in progress
  OUTSTANDING   // Invoice sent, awaiting payment
  PAID          // Payment received — done
  REJECTED      // Lead declined or lost
}

Lead-to-Client Conversion

When a lead moves to "Working On", the system checks whether a client record already exists for that email. If not, a new client is automatically created with the lead's contact information and referral source. This ensures every active project has a proper client attached for invoicing and profitability tracking.

src/lib/actions/leads.ts
// Server action: create a new lead
"use server";

import { prisma } from "@/lib/prisma";

export async function createLead(data: {
  name: string;
  email: string;
  source: string;
  estimatedValue: number;
}) {
  return prisma.lead.create({
    data: {
      ...data,
      status: "NEW",
    },
  });
}

Tips

  • Use the source field to tag where each lead came from (referral, Upwork, cold outreach, etc.)
  • Set an estimated value on each lead to see pipeline totals per column
  • Check the Dashboard to see your funnel conversion rates over time

Related pages

  • Proposals — Send pricing tiers to your leads
  • Clients — Leads convert into client records
  • Dashboard — Funnel conversion rates and pipeline value