Build a complete CRM system with lead tracking, deal pipeline, and contact management for SMEs
* Preview is for reference only. Actual results may vary depending on the AI model, variable values, and tools used.
You are a senior full-stack engineer specializing in business applications for Malaysian SMEs. Build a complete Customer Relationship Management (CRM) system for {{company_name}} that replaces paid tools like Salesforce, HubSpot, or Zoho CRM.
## Tech Stack
- Framework: Next.js 14 (App Router) + TypeScript
- Styling: Tailwind CSS + shadcn/ui component library
- Database: Supabase (PostgreSQL) with Row Level Security
- Hosting: Vercel
- Drag and drop: @dnd-kit/core + @dnd-kit/sortable
- Charts: Recharts
- Form validation: react-hook-form + zod
## Database Schema
Create all tables with columns, types, relationships, and indexes:
**companies table**
- id: uuid PRIMARY KEY DEFAULT gen_random_uuid()
- name: text NOT NULL (e.g. 'Sunrise Bakery Sdn Bhd')
- registration_no: text (SSM registration number)
- industry: text
- website: text
- address: text
- city: text (e.g. Kuala Lumpur, Penang, Johor Bahru)
- state: text (Malaysian state)
- annual_revenue: numeric (RM)
- employee_count: integer
- source: text (lead source: {{lead_sources}})
- assigned_to: uuid REFERENCES sales_team(id)
- created_at / updated_at: timestamptz
- Indexes: (assigned_to), (industry), (city)
**contacts table**
- id: uuid PRIMARY KEY DEFAULT gen_random_uuid()
- company_id: uuid REFERENCES companies(id) ON DELETE SET NULL
- first_name / last_name: text NOT NULL
- title: text (job title, e.g. 'General Manager', 'Purchasing Director')
- email: text
- phone: text (format: +60-12-3456789)
- whatsapp: text
- preferred_language: text DEFAULT 'zh' (zh/en/ms)
- is_primary: boolean DEFAULT false
- lead_score: integer DEFAULT 0 (0-100)
- assigned_to: uuid REFERENCES sales_team(id)
- last_contacted_at: timestamptz
- created_at / updated_at: timestamptz
- Indexes: (company_id), (assigned_to), (email)
**deals table**
- id: uuid PRIMARY KEY DEFAULT gen_random_uuid()
- title: text NOT NULL
- company_id: uuid REFERENCES companies(id)
- contact_id: uuid REFERENCES contacts(id)
- stage: text NOT NULL (pipeline stages: {{sales_stages}})
- stage_order: integer (for kanban column ordering)
- value: numeric NOT NULL DEFAULT 0 (deal amount in RM)
- probability: integer DEFAULT 20 (win probability 0-100%)
- weighted_value: numeric GENERATED ALWAYS AS (value * probability / 100) STORED
- expected_close_date: date
- actual_close_date: date
- lost_reason: text
- win_reason: text
- assigned_to: uuid REFERENCES sales_team(id)
- source: text
- days_in_stage: integer (calculated by trigger)
- is_overdue: boolean GENERATED ALWAYS AS (expected_close_date < CURRENT_DATE AND stage NOT IN ('Closed Won','Closed Lost')) STORED
- created_at / updated_at / stage_changed_at: timestamptz
- Indexes: (company_id), (contact_id), (assigned_to), (stage), (expected_close_date)
**deal_products table**
- id: uuid PRIMARY KEY
- deal_id: uuid REFERENCES deals(id) ON DELETE CASCADE
- product_name: text NOT NULL
- quantity: integer DEFAULT 1
- unit_price: numeric NOT NULL
- discount_pct: numeric DEFAULT 0
- line_total: numeric GENERATED ALWAYS AS (quantity * unit_price * (1 - discount_pct/100)) STORED
**activities table**
- id: uuid PRIMARY KEY
- deal_id: uuid REFERENCES deals(id) ON DELETE CASCADE
- contact_id: uuid REFERENCES contacts(id)
- company_id: uuid REFERENCES companies(id)
- type: text NOT NULL (call/email/meeting/whatsapp/note/stage_change)
- subject: text NOT NULL
- description: text
- outcome: text (e.g. 'Requested quote', 'Follow up next week')
- duration_minutes: integer (for calls and meetings)
- performed_by: uuid REFERENCES sales_team(id)
- performed_at: timestamptz DEFAULT now()
- Indexes: (deal_id), (contact_id), (company_id), (performed_at)
**tasks table**
- id: uuid PRIMARY KEY
- deal_id: uuid REFERENCES deals(id) ON DELETE CASCADE
- contact_id: uuid REFERENCES contacts(id)
- title: text NOT NULL
- description: text
- due_date: timestamptz NOT NULL
- priority: text DEFAULT 'medium' (low/medium/high/urgent)
- status: text DEFAULT 'pending' (pending/in_progress/completed/cancelled)
- assigned_to: uuid REFERENCES sales_team(id)
- completed_at: timestamptz
- Indexes: (deal_id), (assigned_to), (due_date), (status)
**sales_team table**
- id: uuid PRIMARY KEY
- user_id: uuid REFERENCES auth.users(id)
- name: text NOT NULL
- email: text NOT NULL
- phone: text
- role: text DEFAULT 'sales_rep' (sales_rep/team_lead/manager)
- target_monthly: numeric DEFAULT 0 (monthly sales target in RM)
- is_active: boolean DEFAULT true
## Core Feature Modules
### 1. Deal Pipeline Kanban Board
Implement drag-and-drop using @dnd-kit:
- Columns for each pipeline stage: {{sales_stages}}
- Each deal card shows: company name, contact name, deal value (RM), win probability %, expected close date, assignee avatar, days stalled in current stage
- Deals stalled over 14 days show an orange 'Stalled' badge
- Overdue deals (past expected close date) show a red warning indicator
- Column footer shows: deal count, total value, weighted pipeline value
- On drag to new stage: update stage and stage_changed_at, show a dialog requiring a stage-change note, update probability to stage default, write an activity record of type 'stage_change'
- Filter by assignee, sort by value or close date
### 2. Contact and Company Management
Contacts list page:
- Table view: name, title, company, phone/WhatsApp, last contacted date, lead score badge
- Contact detail: profile info, linked company, related deals, activity timeline
- Bulk import via CSV with field mapping UI
- Quick-add form: name + phone minimum required fields
Company detail page:
- Company info (name, industry, SSM reg no, address)
- All contacts list
- All related deals grouped by status
- Activity timeline in reverse chronological order
- Total pipeline value across all company deals
### 3. Activity Logging System
Quick-log activity from deal detail, contact detail, or company detail pages:
- Types: Call (log duration and outcome), Email, Meeting, WhatsApp message, Note, Stage Change
- Timeline view: all interactions shown in reverse chronological order
- Each entry shows: type icon, timestamp, rep name, subject, description
- Logging a call automatically updates contact's last_contacted_at
### 4. Tasks and Follow-up Reminders
- Create follow-up tasks linked to deals or contacts
- Priority levels: Low / Medium / High / Urgent (color-coded)
- Due date highlighting: today's tasks highlighted yellow, overdue tasks highlighted red
- 'My Tasks' view: sorted by priority then due date
- Completing a task automatically creates an activity record
### 5. Sales Dashboard
Summary metric cards at the top:
- Total pipeline value this month (RM) vs previous month change
- Closed won this month (RM) vs monthly target % attainment
- Active deal count
- Win rate this month (%)
Charts section using Recharts:
- Deal count and value by pipeline stage (bar chart)
- Daily closed-won trend for current month (line chart)
- Lead source distribution pie chart (based on {{lead_sources}})
- Sales team leaderboard: {{team_size}} reps ranked by closed-won amount
Activity metrics:
- Calls made this week
- Meetings held this week
- Pending tasks count
- Average deal cycle length in days
### 6. Global Search
- Cmd+K keyboard shortcut opens search panel using shadcn/ui Command component
- Search simultaneously across: contact names, company names, deal titles
- Results displayed in categorized sections: Contacts / Companies / Deals
- Clicking a result navigates directly to the detail page
## UI/UX Design Specifications
Color system:
- Top navigation: dark navy (#0F172A) background, white text
- Content area: white background, dark slate text
- Primary CTA buttons: gold yellow (#FCD34D) with dark text
- Success / Closed Won: green (#22C55E)
- Warning / Stalled: orange (#F97316)
- Danger / Closed Lost: red (#EF4444)
- Borders and dividers: light gray (#E2E8F0)
Layout structure:
- Left sidebar (240px wide): Logo + company name, main nav menu, user info footer
- Top breadcrumb bar with global search button
- Main content area: responsive grid, sidebar collapses on mobile
Navigation menu:
- Dashboard
- Pipeline (Kanban board)
- Contacts
- Companies
- Activities
- My Tasks
- Analytics
- Settings
## Business Rules
1. Lead score auto-calculation: +10 if company has website, +15 if email on file, +10 if phone on file, +20 if has active deal, +15 if activity in last 7 days, +20 if deal value over RM 50,000, -10 if no activity in last 30 days
2. Deal stall alerts: yellow warning after 7 days in same stage, orange after 14 days, red critical alert after 30 days
3. Stage gate validation: moving to 'Proposal Sent' requires deal value filled; moving to 'Negotiation' requires a customer requirement note; closing a deal (won or lost) requires a reason
4. Sales forecast: automatically calculate projected close amount for the month using weighted pipeline (value x probability) for all active deals
5. Malaysian localization: all amounts formatted as 'RM XX,XXX.00', phone numbers as '+60-XX-XXXXXXX', dates as 'DD MMM YYYY'
## Deployment and Configuration
- All Supabase RLS policies must use (select auth.uid()) instead of auth.uid() for performance
- Create explicit indexes on all foreign key columns
- Implement Supabase Realtime subscriptions on the deals table to refresh the kanban board in real time when multiple reps are logged in simultaneously
- Required env vars: NEXT_PUBLIC_SUPABASE_URL, NEXT_PUBLIC_SUPABASE_ANON_KEY, SUPABASE_SERVICE_ROLE_KEY
- Use next/font to load Inter (Latin) and Noto Sans SC (Chinese characters)
Start by building the kanban pipeline board and ensuring drag-and-drop is fully functional before moving to other modules.