Skip to main content
RapidDev - Software Development Agency

How to Build Sales funnel app with V0

Build a sales funnel app with V0 using Next.js and Supabase that gives sales teams a visual kanban pipeline for tracking deals through stages, logs all activities, and shows conversion analytics with Recharts funnel charts — all in about 1-2 hours.

What you'll build

  • Kanban board of deals across pipeline stages with drag-and-drop powered by @dnd-kit/core
  • Deal detail page with activity timeline showing notes, calls, emails, meetings, and stage changes
  • Conversion analytics dashboard with Recharts horizontal bar funnel and revenue forecast line chart
  • Contact directory linked to deals for tracking relationships across the pipeline
  • Pipeline configuration for customizing stages, colors, and positions
  • Server Actions for deal creation, stage transitions, and activity logging
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate10 min read1-2 hoursV0 Premium or higherApril 2026RapidDev Engineering Team
TL;DR

Build a sales funnel app with V0 using Next.js and Supabase that gives sales teams a visual kanban pipeline for tracking deals through stages, logs all activities, and shows conversion analytics with Recharts funnel charts — all in about 1-2 hours.

What you're building

Sales teams need a clear view of their pipeline — which deals are in which stage, what the conversion rates are between stages, and where the revenue forecast stands. A CRM-lite funnel view gives teams the visibility they need without the bloat of enterprise CRM software.

V0 generates the kanban board, deal detail page, and analytics dashboard from prompts. The key architectural challenge is accurate conversion rate calculation between stages. A Supabase database function queries the deal_activities table where activity_type = 'stage_change', groups by from-stage and to-stage, and computes conversion percentages — exposed as an RPC endpoint that the analytics page calls.

The architecture uses Next.js App Router with Server Components for the pipeline list and analytics, a client component for the interactive kanban board, Server Actions for all deal mutations (which also log activities automatically), and Recharts for funnel and forecast visualizations.

Final result

A sales funnel app with a drag-and-drop kanban pipeline, deal detail pages with activity timelines, stage-to-stage conversion analytics, revenue forecasting, and a contact directory.

Tech stack

V0AI Code Generator
Next.jsFull-Stack Framework
Tailwind CSSStyling
shadcn/uiComponent Library
SupabaseDatabase
RechartsData Visualization

Prerequisites

  • A V0 account (Premium recommended for the kanban and analytics complexity)
  • A Supabase project (free tier works — connect via V0's Connect panel)
  • Sample deal data for testing the pipeline and analytics

Build steps

1

Set up the project and sales pipeline schema

Open V0 and create a new project. Use the Connect panel to add Supabase. Create the schema for pipelines, stages, deals, activities, and contacts.

prompt.txt
1// Paste this prompt into V0's AI chat:
2// Build a sales funnel app. Create a Supabase schema with:
3// 1. pipelines: id (uuid PK), owner_id (uuid FK), name (text), created_at (timestamptz)
4// 2. stages: id (uuid PK), pipeline_id (uuid FK), name (text), position (integer), color (text), created_at (timestamptz)
5// 3. deals: id (uuid PK), pipeline_id (uuid FK), stage_id (uuid FK), owner_id (uuid FK), contact_name (text), contact_email (text), company (text), value (integer), currency (text DEFAULT 'USD'), expected_close_date (date), probability (integer CHECK 0-100), status (text CHECK open/won/lost), lost_reason (text), created_at (timestamptz), updated_at (timestamptz)
6// 4. deal_activities: id (uuid PK), deal_id (uuid FK), user_id (uuid FK), activity_type (text CHECK note/call/email/meeting/stage_change), description (text), metadata (jsonb), created_at (timestamptz)
7// 5. contacts: id (uuid PK), owner_id (uuid FK), name (text), email (text), company (text), phone (text), created_at (timestamptz)
8// RLS: users see only deals where owner_id = auth.uid().
9// Create a default pipeline with stages: Lead, Qualified, Proposal, Negotiation, Closed Won, Closed Lost.
10// Generate SQL migration and TypeScript types.

Pro tip: Use V0's prompt queuing — queue the schema prompt first, then immediately queue the kanban board, analytics dashboard, and deal detail prompts while the schema generates.

Expected result: Supabase is connected with pipelines, stages, deals, activities, and contacts tables. A default pipeline with six stages is seeded. RLS policies restrict deals to their owners.

2

Build the kanban pipeline board

Create the main pipeline page with a kanban board showing deals as Cards across stage columns. Deals can be dragged between stages, which logs a stage_change activity automatically.

prompt.txt
1// Paste this prompt into V0's AI chat:
2// Build a sales pipeline page at app/pipeline/page.tsx.
3// Requirements:
4// - Kanban board with columns for each stage, ordered by position
5// - Each column header shows stage name with colored Badge, deal count, and total value
6// - Deal Cards showing: contact_name, company, value (formatted as currency), probability Badge, expected_close_date
7// - Drag-and-drop deals between columns using @dnd-kit/core
8// - On drop: call Server Action moveDealToStage() which:
9// 1. Updates deal's stage_id
10// 2. Inserts a deal_activities record with activity_type 'stage_change' and metadata {from_stage, to_stage}
11// - Deal Card DropdownMenu: View Details, Mark Won, Mark Lost (opens Dialog for lost_reason)
12// - "Add Deal" Button per column opens Sheet with deal form (contact_name, company, value, probability, expected_close_date)
13// - Tabs for switching between Pipeline (kanban), List (Table view), and Analytics
14// - 'use client' for the kanban board
15// - Use shadcn/ui Card, Badge, Avatar, Sheet, DropdownMenu, Tabs, Table, Button, Dialog

Expected result: A kanban pipeline board with draggable deal Cards across stage columns. Dropping a deal into a new stage updates the database and logs the transition.

3

Create the deal detail page with activity timeline

Build the deal detail page showing all information about a deal, with an activity timeline that logs notes, calls, emails, meetings, and stage changes.

prompt.txt
1// Paste this prompt into V0's AI chat:
2// Build a deal detail page at app/deals/[id]/page.tsx.
3// Requirements:
4// - Header: contact_name, company, value (large), stage Badge (colored), probability
5// - Quick actions: DropdownMenu with Move to Stage (nested menu of all stages), Mark Won, Mark Lost, Edit
6// - Two-column layout:
7// - Left: Activity timeline (deal_activities ordered by created_at DESC)
8// - Each activity: Avatar, activity_type Badge (note=blue, call=green, email=purple, meeting=orange, stage_change=gray), description, timestamp
9// - Stage change activities show "Moved from {from_stage} to {to_stage}" from metadata
10// - "Add Activity" form at top with activity_type Select, description Textarea, "Log" Button
11// - Right: Deal details Card (contact info, value, probability, dates) + Contact Card
12// - Server Actions: logActivity(), updateDeal()
13// - Server Components for data fetching
14// - Use shadcn/ui Card, Badge, Avatar, Select, Textarea, Button, DropdownMenu, Separator

Expected result: A deal detail page with all deal information, a chronological activity timeline with type-specific Badges, and a form for logging new activities.

4

Build the conversion analytics dashboard

Create the analytics page showing stage-to-stage conversion rates as a funnel chart, revenue forecast, and pipeline health metrics. Uses a Supabase RPC function for accurate conversion calculations.

prompt.txt
1// Paste this prompt into V0's AI chat:
2// Build a pipeline analytics page at app/pipeline/analytics/page.tsx.
3// Requirements:
4// - Top row: metric Cards showing total pipeline value, average deal size, win rate %, average time to close
5// - Conversion funnel: horizontal bar chart (Recharts BarChart) showing deal count at each stage
6// - Labels between bars showing conversion percentage from one stage to the next
7// - Data comes from a Supabase RPC function 'get_conversion_stats' that:
8// - Queries deal_activities WHERE activity_type = 'stage_change'
9// - Groups by from_stage and to_stage
10// - Computes conversion percentage for each transition
11// - Revenue forecast: Recharts LineChart showing expected revenue by month
12// - Based on deals' expected_close_date and value * (probability / 100)
13// - Stage breakdown: Table showing each stage's deal count, total value, average time in stage
14// - Date range filter with Calendar + Popover DatePicker
15// - Server Components for data fetching — call the RPC function directly
16// - Use shadcn/ui Card, Table, Badge, Calendar, Popover, Button

Pro tip: The Supabase RPC function for conversion stats avoids expensive client-side calculations. It runs the aggregation in PostgreSQL where it's fastest, and returns pre-computed percentages ready for Recharts.

Expected result: An analytics dashboard with conversion funnel bars, revenue forecast line chart, pipeline metric Cards, and stage breakdown Table.

Complete code

app/actions/deals.ts
1'use server'
2
3import { createClient } from '@/lib/supabase/server'
4import { revalidatePath } from 'next/cache'
5
6export async function createDeal(formData: FormData) {
7 const supabase = await createClient()
8 const { data: { user } } = await supabase.auth.getUser()
9 if (!user) throw new Error('Must be logged in')
10
11 const { data: deal } = await supabase
12 .from('deals')
13 .insert({
14 pipeline_id: formData.get('pipeline_id') as string,
15 stage_id: formData.get('stage_id') as string,
16 owner_id: user.id,
17 contact_name: formData.get('contact_name') as string,
18 contact_email: formData.get('contact_email') as string,
19 company: formData.get('company') as string,
20 value: parseInt(formData.get('value') as string),
21 probability: parseInt(formData.get('probability') as string),
22 expected_close_date: formData.get('expected_close_date') as string,
23 status: 'open',
24 })
25 .select()
26 .single()
27
28 if (!deal) throw new Error('Failed to create deal')
29
30 await supabase.from('deal_activities').insert({
31 deal_id: deal.id,
32 user_id: user.id,
33 activity_type: 'note',
34 description: 'Deal created',
35 })
36
37 revalidatePath('/pipeline')
38 return deal
39}
40
41export async function moveDealToStage(
42 dealId: string,
43 fromStageId: string,
44 toStageId: string
45) {
46 const supabase = await createClient()
47 const { data: { user } } = await supabase.auth.getUser()
48 if (!user) throw new Error('Must be logged in')
49
50 await supabase
51 .from('deals')
52 .update({ stage_id: toStageId, updated_at: new Date().toISOString() })
53 .eq('id', dealId)
54
55 await supabase.from('deal_activities').insert({
56 deal_id: dealId,
57 user_id: user.id,
58 activity_type: 'stage_change',
59 description: 'Deal moved to new stage',
60 metadata: { from_stage: fromStageId, to_stage: toStageId },
61 })
62
63 revalidatePath('/pipeline')
64}
65
66export async function logActivity(formData: FormData) {
67 const supabase = await createClient()
68 const { data: { user } } = await supabase.auth.getUser()
69 if (!user) throw new Error('Must be logged in')
70
71 const dealId = formData.get('deal_id') as string
72
73 await supabase.from('deal_activities').insert({
74 deal_id: dealId,
75 user_id: user.id,
76 activity_type: formData.get('activity_type') as string,
77 description: formData.get('description') as string,
78 })
79
80 revalidatePath(`/deals/${dealId}`)
81}

Customization ideas

Add deal automation rules

Create automation triggers like 'when a deal stays in Proposal for 7 days, send a follow-up reminder' using Supabase cron jobs and edge functions.

Build email integration

Connect Gmail or Outlook to automatically log sent/received emails as deal activities when the contact email matches a deal's contact_email.

Add team collaboration

Extend deals with multiple assignees, @mention notifications in activity notes, and team-level pipeline views with shared visibility.

Build lead scoring

Use deal activity frequency, email engagement, and meeting count to auto-calculate a lead score that updates the deal's probability field.

Common pitfalls

Pitfall: Not logging stage changes in deal_activities when moving deals

How to avoid: Always insert a deal_activities record with activity_type = 'stage_change' and metadata containing from_stage and to_stage whenever a deal's stage_id changes. The moveDealToStage Server Action handles this automatically.

Pitfall: Computing conversion rates on the client side from deal counts per stage

How to avoid: Use a Supabase RPC function that queries deal_activities WHERE activity_type = 'stage_change', groups by from-stage and to-stage, and computes actual transition percentages based on recorded movements.

Pitfall: Using client-side drag-and-drop without optimistic updates

How to avoid: Update the local state immediately on drop (optimistic), then call the Server Action. If the action fails, revert the local state and show a Toast error.

Best practices

  • Log every deal interaction as a deal_activity to build an accurate audit trail for conversion analytics
  • Use a Supabase RPC function for conversion rate calculations — run aggregation in PostgreSQL, not in the browser
  • Apply optimistic updates on kanban drag-and-drop for instant visual feedback while the Server Action processes
  • Use V0's prompt queuing to generate the kanban board, analytics dashboard, and deal detail page sequentially
  • Use V0's Design Mode (Option+D) to visually adjust stage column colors and deal Card spacing without spending credits
  • Seed a default pipeline with standard sales stages (Lead, Qualified, Proposal, Negotiation, Won, Lost) for immediate usability

AI prompts to try

Copy these prompts to build this project faster.

ChatGPT Prompt

I'm building a sales funnel app with Next.js and Supabase. Write a PostgreSQL function called get_conversion_stats that takes a pipeline_id as input. It should query the deal_activities table where activity_type = 'stage_change', join with stages to get stage names, group by from_stage and to_stage, and return each transition with the count and conversion percentage. Include the CREATE FUNCTION statement.

Build Prompt

Create a pipeline conversion funnel component. Accept an array of stage conversion data (stage_name, deal_count, conversion_to_next_percent). Render a Recharts horizontal BarChart where each bar represents a stage's deal count. Between bars, show the conversion percentage with an arrow. Color bars using each stage's color. Use Server Components for data fetching from the Supabase RPC function.

Frequently asked questions

Can I build this on V0's free tier?

V0 Free provides enough credits for the basic pipeline board. Premium ($20/month) is recommended because this project has a kanban board, analytics dashboard, and deal detail page that benefit from prompt queuing.

How does the conversion funnel calculate accurate percentages?

A Supabase RPC function queries the deal_activities table for stage_change events, groups them by from-stage and to-stage, and computes the actual percentage of deals that transitioned between each pair of stages. This is more accurate than counting current deals per stage.

Can I customize the pipeline stages?

Yes. Stages are stored in the stages table with name, position, and color fields. You can add, rename, reorder, or remove stages through the pipeline settings page. Deals will retain their stage assignment even if stage names change.

How does drag-and-drop work without being slow?

The kanban uses optimistic updates — when you drop a deal Card onto a new stage column, the UI updates immediately. The Server Action runs in the background to update the database and log the stage change. If it fails, the Card reverts and shows an error Toast.

How do I deploy the sales funnel app?

Click Share then Publish to Production in V0. Supabase credentials are auto-configured from the Connect panel. No additional env vars are needed beyond the Supabase connection.

Can RapidDev help build a custom sales platform?

Yes. RapidDev has built 600+ apps including CRM systems with pipeline management, AI-powered lead scoring, and email integration. Book a free consultation to discuss your requirements.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help building your app?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.