Leads
Lead CRUD Operations
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-001 | Create a new lead from existing contact | Logged in as user with `leads:manage` permission, at least one contact exists, one WhatsApp account connected | 1. Navigate to Leads view 2. Click "New Lead" button 3. Select a contact from dropdown 4. Select WhatsApp account 5. Set stage to "new" 6. Enter source (e.g., "manual") 7. Click "Save" | Lead appears in Leads list with selected contact, stage, and source. Success toast shows "Lead created". Lead ID is assigned. | High |
| LEAD-002 | Create lead with assignment to user | Logged in as user with `leads:manage` permission, at least one contact and one team member exists | 1. Navigate to create lead form 2. Select contact 3. Assign to user via "Assigned User" dropdown 4. Submit form | Lead is created with `assigned_user_id` populated. Lead appears in assigned user's view/list. | High |
| LEAD-003 | Create lead with assignment to team | Logged in as user with `leads:manage` permission, at least one contact and one team exists | 1. Navigate to create lead form 2. Select contact 3. Assign to team via "Assigned Team" dropdown 4. Submit form | Lead is created with `assigned_team_id` populated. Lead appears in team's view. | High |
| LEAD-004 | Create lead with initial score | Logged in as user with `leads:manage` permission, at least one contact exists | 1. Navigate to create lead form 2. Select contact 3. Set score field to numeric value (e.g., 75) 4. Submit form | Lead is created with score saved and visible in lead details. | Medium |
| LEAD-005 | List all leads with pagination | Logged in as user with `leads:view` permission, at least 30 leads exist in org | 1. Navigate to Leads view 2. Observe leads list showing first 25 items 3. Click "Next" or scroll to load more | First page shows 25 leads with pagination controls. Second page shows next 25 leads. Total count displays at bottom (e.g., "Showing 1-25 of 150"). | High |
| LEAD-006 | List leads filtered by stage | Logged in as user with `leads:view` permission, leads in multiple stages exist | 1. Navigate to Leads view 2. Click stage filter dropdown 3. Select "Qualified" stage 4. View results | List shows only leads with stage = "qualified". Other stages are hidden. Filter badge shows "Qualified" is active. | High |
| LEAD-007 | List leads filtered by assigned user | Logged in as user with `leads:view` permission, leads assigned to different users exist | 1. Navigate to Leads view 2. Open "Assigned User" filter 3. Select a specific user 4. View results | List shows only leads assigned to selected user. Other assigned leads hidden. Filter shows selected user name. | High |
| LEAD-008 | List leads filtered by contact | Logged in as user with `leads:view` permission, multiple leads for same contact exist | 1. Navigate to Leads view 2. Open "Contact" filter 3. Select contact 4. View results | List shows only leads linked to selected contact. Typically 1 lead per contact but test verifies filter works. | Medium |
| LEAD-009 | Search leads by contact name | Logged in as user with `leads:view` permission, leads with known contact names exist | 1. Navigate to Leads view 2. Enter contact name in search box (e.g., "John") 3. Press Enter or wait for auto-search | List filters to show only leads where contact_name contains "John". Results update in real-time (no page reload). | High |
| LEAD-010 | Search leads by contact phone | Logged in as user with `leads:view` permission, leads with known contact phones exist | 1. Navigate to Leads view 2. Enter phone number in search box (e.g., "+1234567890") 3. Press Enter or wait for auto-search | List filters to show only leads where contact_phone contains phone number. Results update in real-time. | High |
| LEAD-011 | Get lead details | Logged in as user with `leads:view` permission, at least one lead exists | 1. Navigate to Leads view 2. Click on a lead row to open detail panel 3. Observe detail panel | Detail panel opens showing: lead ID, contact name, contact phone, current stage, assigned user, assigned team, score, source, created date, lost_reason (if applicable). Contact audit log visible. | High |
| LEAD-012 | Update lead stage to next stage | Logged in as user with `leads:manage` permission, lead in "new" stage exists | 1. Open lead detail panel 2. Click stage badge 3. Select "Contacted" from stage menu 4. Confirm | Lead stage updates to "Contacted". Stage badge color changes. Detail panel reflects new stage immediately. Audit log entry created. | High |
| LEAD-013 | Update lead stage via Kanban drag-and-drop | Logged in as user with `leads:manage` permission, Kanban view active, lead in "new" column exists | 1. Navigate to Leads view in Kanban mode 2. Drag lead card from "New" column 3. Drop on "Contacted" column 4. Release | Lead card moves to "Contacted" column. Lead status updates in backend. No page refresh needed. | High |
| LEAD-014 | Update lead stage to "lost" with reason | Logged in as user with `leads:manage` permission, lead in "qualified" stage exists | 1. Open lead detail panel 2. Click stage badge 3. Select "Lost" 4. Modal opens asking for lost_reason 5. Enter reason (e.g., "Budget constraints") 6. Click "Confirm Lost" | Lead stage updates to "Lost". lost_reason field is saved with entered text. Stage badge turns red. Audit log shows lost reason. | High |
| LEAD-015 | Update lead stage — no lost reason required if not selecting lost | Logged in as user with `leads:manage` permission, lead in "contacted" stage exists | 1. Open lead detail panel 2. Click stage badge 3. Select "Qualified" 4. Confirm without entering reason | Lead updates to "Qualified" stage. No modal appears. No lost_reason field shown. | High |
| LEAD-016 | Update lead assignment to different user | Logged in as user with `leads:manage` permission, lead exists, multiple team members exist | 1. Open lead detail panel 2. Click "Assigned User" field 3. Select different user from dropdown 4. Confirm | assigned_user_id updates. Detail panel refreshes showing new assignee. Audit log entry created. | High |
| LEAD-017 | Update lead assignment to team | Logged in as user with `leads:manage` permission, lead exists, multiple teams exist | 1. Open lead detail panel 2. Click "Assigned Team" field 3. Select different team 4. Confirm | assigned_team_id updates. Detail panel shows new team. Audit log entry created. | High |
| LEAD-018 | Delete a lead | Logged in as user with `leads:manage` permission, lead exists with no active enrollments | 1. Open lead detail panel 2. Click "Delete" button 3. Confirm deletion in modal | Lead removed from list. Detail panel closes. Success toast shows "Lead deleted". Lead no longer appears in any filter/search. | High |
| LEAD-019 | Cannot delete lead with active nurture enrollment | Logged in as user with `leads:manage` permission, lead exists with active nurture enrollment | 1. Open lead detail panel with active enrollment 2. Click "Delete" button | Delete button is disabled or error toast shows "Cannot delete: active enrollments exist". Lead remains in list. | Medium |
| LEAD-020 | View lead — contact name and phone pre-filled from contact | Logged in as user with `leads:view` permission, lead linked to contact "John +1234567890" exists | 1. Navigate to Leads view 2. Click lead row 3. Open detail panel | Lead detail panel shows contact_name = "John" and contact_phone = "+1234567890" (fetched from contact record, not stored on lead). | High |
Lead Permissions & Role Boundaries
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-021 | Agent cannot create lead — no `leads:manage` permission | Logged in as Agent role (has `leads:view` but not `leads:manage`) | 1. Navigate to Leads view 2. Attempt to click "New Lead" button | Button is disabled or hidden. If clicked via dev tools, API returns 403 Forbidden. Toast shows "Permission denied: leads:manage required". | High |
| LEAD-022 | Agent cannot update lead stage | Logged in as Agent role, lead exists | 1. Navigate to Leads view 2. Open lead detail panel 3. Attempt to click stage badge and change stage | Stage badge is disabled/read-only. If attempted via API, returns 403 Forbidden. No update occurs. | High |
| LEAD-023 | Agent cannot delete lead | Logged in as Agent role, lead exists | 1. Navigate to Leads view 2. Open lead detail panel 3. Attempt to click "Delete" button | Delete button is disabled or hidden. If attempted via API, returns 403 Forbidden. | High |
| LEAD-024 | Agent can view leads | Logged in as Agent role with `leads:view` permission | 1. Navigate to Leads view 2. List loads | Leads list displays all org leads with filters/search available. Agent can read all fields. | High |
| LEAD-025 | Admin can create, update, delete leads | Logged in as Admin role | 1. Create lead 2. Update stage 3. Delete lead | All operations succeed. 201 Created, 200 OK, 204 No Content responses. | High |
| LEAD-026 | User cannot view leads from different organization | Logged in to Org A, lead exists in Org B | 1. Attempt to navigate to /leads or call GET /leads with org_id filter for Org B | List returns empty or 403 Forbidden. Lead from Org B not visible. Results scoped to current org_id only. | High |
Lead Validation & Error Handling
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-027 | Create lead — contact_id required | Logged in as user with `leads:manage`, no contact selected | 1. Navigate to create lead form 2. Leave contact field empty 3. Click "Save" | Form validation error appears under contact field: "Contact is required". Save button disabled. No API call made. | High |
| LEAD-028 | Create lead — whatsapp_account_id required | Logged in as user with `leads:manage`, contact selected but no WhatsApp account | 1. Navigate to create lead form 2. Select contact 3. Leave WhatsApp account empty 4. Click "Save" | Form validation error: "WhatsApp account is required". No API call made. | High |
| LEAD-029 | Create lead — invalid contact_id | Logged in as user with `leads:manage` | 1. Submit POST /leads with contact_id = "invalid-uuid" | API returns 422 Unprocessable Entity with validation error. Toast shows "Invalid contact ID format". | Medium |
| LEAD-030 | Create lead — contact does not exist | Logged in as user with `leads:manage` | 1. Submit POST /leads with valid UUID format but non-existent contact_id | API returns 404 Not Found. Toast shows "Contact not found". | Medium |
| LEAD-031 | Create lead — duplicate lead for same contact | Logged in as user with `leads:manage`, lead already exists for contact "John" | 1. Attempt to create another lead for same contact "John" | Depending on business rule: either allows multiple leads per contact (if permitted) or returns 409 Conflict with message "Lead already exists for this contact". | Low |
| LEAD-032 | Update lead — invalid stage value | Logged in as user with `leads:manage`, lead exists | 1. Open lead detail panel 2. Submit PATCH /leads/{id} with stage = "invalid_stage" | API returns 400 Bad Request with detail "Invalid stage value". Must be one of: new, contacted, qualified, converted, lost. | Medium |
| LEAD-033 | Update lead — lost_reason only valid when stage = "lost" | Logged in as user with `leads:manage`, lead in "contacted" stage | 1. Submit PATCH with stage = "contacted" and lost_reason = "Budget" | API accepts or ignores lost_reason when stage != "lost". No error if lost_reason ignored, or field rejected. | Low |
| LEAD-034 | Update lead — assigned_user_id must exist | Logged in as user with `leads:manage` | 1. Submit PATCH /leads/{id} with assigned_user_id = invalid-uuid | API returns 404 Not Found or 400 Bad Request. Toast shows "User not found". | Medium |
| LEAD-035 | Update lead — assigned_team_id must exist | Logged in as user with `leads:manage` | 1. Submit PATCH /leads/{id} with assigned_team_id = invalid-uuid | API returns 404 Not Found. Toast shows "Team not found". | Medium |
| LEAD-036 | Get lead — 404 if lead does not exist | Logged in as user with `leads:view` | 1. Navigate to /leads/{non-existent-id} or click lead that was deleted | API returns 404 Not Found. Toast shows "Lead not found". Detail panel closes or blank state shown. | Medium |
| LEAD-037 | Pagination — page_size minimum 1 | Logged in as user with `leads:view` | 1. Submit GET /leads?page_size=0 | API returns 422 Unprocessable Entity with validation error "page_size must be >= 1". | Low |
| LEAD-038 | Pagination — page_size maximum 500 | Logged in as user with `leads:view` | 1. Submit GET /leads?page_size=501 | API returns 422 Unprocessable Entity with validation error "page_size must be <= 500". | Low |
| LEAD-039 | Pagination — page minimum 1 | Logged in as user with `leads:view` | 1. Submit GET /leads?page=0 | API returns 422 Unprocessable Entity with validation error "page must be >= 1". | Low |
Lead Stage Transitions & Workflow
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-040 | Lead created in "new" stage by default | Logged in as user with `leads:manage`, create lead without explicit stage | 1. Create lead omitting stage field 2. Open detail panel | Lead defaults to stage = "new". | High |
| LEAD-041 | Lead can transition new → contacted → qualified → converted → lost | Logged in as user with `leads:manage` | 1. Create lead (stage = "new") 2. Update to "contacted" 3. Update to "qualified" 4. Update to "converted" | Each transition succeeds. Stage badge updates color. Audit log shows each change with timestamp. | High |
| LEAD-042 | Lead can transition backwards (e.g., qualified → contacted) | Logged in as user with `leads:manage`, lead in "qualified" stage | 1. Open lead detail panel 2. Change stage to "contacted" | Backwards transition allowed. Stage updates successfully. No error. | Medium |
| LEAD-043 | Lead can jump stages (e.g., new → qualified) | Logged in as user with `leads:manage`, lead in "new" stage | 1. Change stage directly to "qualified" without "contacted" | Jump transition allowed. No intermediate stage required. | Medium |
| LEAD-044 | Lead stage can transition to "lost" from any stage | Logged in as user with `leads:manage`, leads in various stages | 1. For each stage (new, contacted, qualified, converted): change to "lost" with reason | All transitions to "lost" succeed. Modal appears for lost_reason. | High |
| LEAD-045 | Lead already "lost" cannot transition to other stages except back to "new" | Logged in as user with `leads:manage`, lead in "lost" stage | 1. Attempt to change stage from "lost" to "contacted" | Transition allowed or blocked depending on business rule. If blocked, error message shows "Cannot transition from lost stage". | Low |
Lead List & Kanban Views
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-046 | Leads displayed in Kanban columns by stage | Logged in as user with `leads:view`, leads in all 5 stages exist | 1. Navigate to Leads view 2. Select "Kanban" view mode | Five columns displayed: "New", "Contacted", "Qualified", "Converted", "Lost". Each lead card shows in correct column by stage. | High |
| LEAD-047 | Kanban column headers show lead count per stage | Logged in as user with `leads:view`, Kanban view active | 1. Observe Kanban columns | Each column header shows count (e.g., "New (12)" for 12 leads in new stage). | Medium |
| LEAD-048 | Lead card displays contact name and stage badge in Kanban | Logged in as user with `leads:view`, Kanban view active | 1. Observe a lead card in Kanban column | Card shows: contact name, status badge with appropriate color, assigned user (if any). | High |
| LEAD-049 | Quick action buttons in Kanban: advance stage | Logged in as user with `leads:manage`, Kanban view active, lead in "new" stage | 1. Hover over lead card 2. Click "→" (advance) button | Lead moves to "Contacted" column. No modal. Immediate update. | High |
| LEAD-050 | Quick action buttons in Kanban: mark lost | Logged in as user with `leads:manage`, Kanban view active, lead in "qualified" stage | 1. Hover over lead card 2. Click "✕" (lost) button | Modal opens asking for lost_reason. After confirming, lead moves to "Lost" column. | High |
| LEAD-051 | Leads switched to List view show all columns | Logged in as user with `leads:view`, Leads in various stages | 1. Navigate to Leads view 2. Toggle to "List" view | Leads shown in table with columns: Contact Name, Phone, Stage, Assigned User, Stage Badge, Score, Source. Sortable/filterable. | High |
| LEAD-052 | Empty leads state | Logged in as user with `leads:view`, no leads exist in org | 1. Navigate to Leads view | Empty state message shown: "No leads yet. Create your first lead to get started." Create button visible. | Medium |
| LEAD-053 | Leads search/filter returns no results | Logged in as user with `leads:view`, search term matches no leads | 1. Enter search "nonexistent_name" 2. View results | Empty results message: "No leads match your search." Filters still visible for reset. | Medium |
Lead Source & WhatsApp Account
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-054 | Create lead with source field populated | Logged in as user with `leads:manage` | 1. Create lead with source = "manual" (or "imported", "api", etc.) 2. View detail | source field saved and visible in detail panel. Audit log shows source. | Medium |
| LEAD-055 | Lead WhatsApp account link validation | Logged in as user with `leads:manage`, at least 2 WhatsApp accounts connected | 1. Create lead with WhatsApp account A 2. View lead details 3. Verify account link | whatsapp_account_id saved. In detail panel, if nurture sequences or messages sent, they use this account. | Medium |
| LEAD-056 | Update lead WhatsApp account assignment | Logged in as user with `leads:manage`, lead exists, 2+ WhatsApp accounts | 1. Open lead detail 2. Change whatsapp_account_id to different account 3. Confirm | Lead whatsapp_account_id updates. Future nurture messages use new account. | Low |
Lead Audit & Activity Tracking
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-057 | Lead creation recorded in audit log | Logged in as user with `leads:manage`, create lead | 1. Create lead 2. Open detail panel 3. Scroll to "Activity" tab | Audit log entry shows: "Lead created by [user name]", timestamp, action = "create", actor_id = current user. | High |
| LEAD-058 | Lead stage change recorded in audit log | Logged in as user with `leads:manage`, lead exists | 1. Change lead stage from "new" to "contacted" 2. View activity log | Audit log entry shows: "Stage changed from 'new' to 'contacted'", timestamp, actor_id. | High |
| LEAD-059 | Lead assignment change recorded in audit log | Logged in as user with `leads:manage`, lead exists | 1. Change assigned_user_id 2. View activity log | Audit log entry shows: "Assigned to [new user name]", timestamp, previous assignee noted. | High |
| LEAD-060 | Lost reason change recorded in audit log | Logged in as user with `leads:manage`, mark lead as lost with reason | 1. Transition to "lost" stage with reason "Budget" 2. View activity log | Audit log entry shows: "Marked as lost - reason: Budget", timestamp. | Medium |
Lead Reminders
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-061 | Add reminder to lead | Logged in as user with permission, lead open in detail panel | 1. Click "Add Reminder" button 2. Enter due date/time and note (e.g., "Follow up call") 3. Click "Save" | Reminder created and appears in "Reminders" section of detail panel. Due date and note visible. Toast shows "Reminder added". | High |
| LEAD-062 | View reminders linked to lead | Logged in as user with `leads:view`, lead with existing reminders open | 1. Open lead detail panel 2. Scroll to "Reminders" section | All reminders for this lead's contact displayed: due_at, note, status (pending/completed). Ordered by due_at. | High |
| LEAD-063 | Delete reminder from lead | Logged in as user, lead detail open with reminder visible | 1. Click "Delete" button on reminder row 2. Confirm | Reminder removed from list. Toast shows "Reminder deleted". | Medium |
| LEAD-064 | Mark reminder completed | Logged in as user, lead detail with pending reminder visible | 1. Click checkbox or "Mark Complete" button on reminder | Reminder status changes to "completed". Strike-through or grayed out. Can be unmarked to return to pending. | Medium |
Lead Nurture Sequence Enrollment & Trigger Tags
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-065 | View nurture sequences available for lead enrollment | Logged in as user with `leads:manage` permission, lead exists, multiple nurture sequences configured | 1. Open lead detail panel 2. Scroll to or click "Nurture Sequences" section 3. View available sequences | List shows all active nurture sequences with names, descriptions, and trigger tags. Sequences are filterable by matching lead's current tags or stage. | High |
| LEAD-066 | Enroll lead in nurture sequence with trigger tags | Logged in as user with `leads:manage` permission, lead exists, nurture sequence with trigger_tags = ["vip", "high-intent"] exists | 1. Open lead detail 2. Navigate to "Nurture Sequences" section 3. Click "Enroll" button on sequence 4. Confirm enrollment | Enrollment created with enrollment_status = "active". Lead begins receiving sequence steps. Audit log shows "Enrolled in sequence: [name]". | High |
| LEAD-067 | Auto-enroll lead in nurture sequence based on matching trigger tags | Logged in as user with `leads:manage`, lead created with tags = ["vip"], nurture sequence configured with trigger_tags = ["vip"] set to auto-enroll | 1. Create new lead or add tag "vip" to existing lead 2. Wait for automation to process 3. Open lead detail | Lead automatically enrolled in matching sequence(s). No manual action required. Enrollment appears in "Nurture Sequences" section with status "active". Audit log shows auto-enrollment. | High |
| LEAD-068 | Nurture sequence with empty trigger_tags applies to all leads | Logged in as user with `leads:manage`, lead exists, nurture sequence with trigger_tags = [] (empty array) and auto-enroll enabled | 1. Create lead or wait for automation 2. Open lead detail 3. Check "Nurture Sequences" section | Lead is automatically enrolled regardless of lead tags. Sequence applies universally. Enrollment status shows "active". | Medium |
| LEAD-069 | Lead with multiple tags matches multiple nurture sequences | Logged in as user with `leads:manage`, lead with tags = ["vip", "hot-lead"], two sequences: seq1 with trigger_tags = ["vip"], seq2 with trigger_tags = ["hot-lead"] | 1. Create/update lead with both tags 2. Wait for automation 3. Open lead detail | Lead is enrolled in both sequences. "Nurture Sequences" section shows both enrollments as "active". Audit log shows two auto-enrollments. | Medium |
| LEAD-070 | Unenroll lead from nurture sequence | Logged in as user with `leads:manage`, lead enrolled in active nurture sequence | 1. Open lead detail 2. Navigate to "Nurture Sequences" section 3. Find active enrollment 4. Click "Unenroll" button 5. Confirm | Enrollment status changes to "unenrolled" or removed from list. Lead stops receiving future steps. Audit log shows "Unenrolled from sequence: [name]". Toast shows "Unenrolled successfully". | High |
| LEAD-071 | Cannot unenroll from paused sequence | Logged in as user with `leads:manage`, lead enrolled in paused sequence | 1. Open lead detail 2. Attempt to unenroll from paused sequence | Unenroll button disabled or message shows "Cannot unenroll from paused sequence". Enrollment remains in "paused" status. | Low |
| LEAD-072 | View enrollment status for each sequence | Logged in as user with `leads:view`, lead with multiple enrollments open | 1. Open lead detail 2. Navigate to "Nurture Sequences" section | Each enrollment shows: sequence name, current step (if active), enrollment_status (active/paused/completed/unenrolled), date enrolled. | High |
| LEAD-073 | Enrollment uses lead's WhatsApp account for message delivery | Logged in as user with `leads:manage`, lead linked to WhatsApp account A, nurture sequence created (account-agnostic) | 1. Enroll lead in sequence 2. Observe first nurture message delivery 3. Check message audit/logs | Messages are sent via lead's whatsapp_account_id (account A), ensuring delivery uses lead's preferred account. Audit log shows account_id = lead.whatsapp_account_id. | High |
| LEAD-074 | Trigger tag is case-insensitive for matching | Logged in as user with `leads:manage`, lead with tag = "VIP", sequence with trigger_tags = ["vip"] (lowercase) | 1. Create/add tag to lead 2. Wait for auto-enrollment 3. Check enrollment status | Lead matches and auto-enrolls in sequence. Matching is case-insensitive. Enrollment appears as "active". | Low |
| LEAD-075 | Trigger tags are optional in sequence creation | Logged in as user with nurture sequence create permission | 1. Create new nurture sequence 2. Leave trigger_tags field empty or not include it 3. Submit form | Sequence created successfully. trigger_tags defaults to [] (empty array). When auto-enroll is enabled, sequence applies to all leads. No validation error. | Medium |
Lead Creation with Mark-as-Lead Option
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-076 | Create contact with optional mark-as-lead checkbox | Logged in as user with `contacts:manage` permission | 1. Navigate to Contacts view 2. Click "New Contact" 3. Fill contact details (name, phone) 4. Check "Mark as Lead" checkbox 5. Click "Save" | Contact created successfully. Lead is automatically created for this contact with stage = "new". Both contact and lead appear in respective lists. Audit log shows both records created. | High |
| LEAD-077 | Create contact without mark-as-lead option | Logged in as user with `contacts:manage` permission | 1. Navigate to Contacts view 2. Click "New Contact" 3. Fill contact details 4. Leave "Mark as Lead" unchecked 5. Click "Save" | Contact created but no lead record generated. Contact appears in Contacts list only. Leads list remains unchanged. | High |
| LEAD-078 | Mark-as-lead creates lead with correct WhatsApp account | Logged in as user with `contacts:manage`, one WhatsApp account connected | 1. Create contact with "Mark as Lead" checked 2. Observe generated lead 3. Open lead detail | Lead is created with whatsapp_account_id = default/selected account. Lead detail shows correct account. | High |
| LEAD-079 | Mark-as-lead inherits contact phone number | Logged in as user with `contacts:manage`, contact phone = "+1234567890" | 1. Create contact with phone "+1234567890" and "Mark as Lead" checked 2. Open generated lead | Lead contact_phone matches contact phone with normalized format. Phone is normalized (if applicable based on #24 changes). | High |
Lead Phone Normalization
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-080 | Lead phone inherits contact's normalized phone number | Logged in as user with `leads:manage`, contact with phone = "1234567890" (no +) created | 1. Create or import contact with unnormalized phone 2. Create lead from that contact 3. View lead detail | Lead contact_phone shows normalized format (e.g., "+1234567890" if country code applied by contact normalization). Phone format is consistent with contact's stored format. | High |
| LEAD-081 | Phone normalization applied during contact creation with mark-as-lead | Logged in as user with `contacts:manage` | 1. Create contact with phone "1234567890" 2. Check "Mark as Lead" 3. Save | Contact phone normalized to standard format. Lead inherits normalized phone. Both records show consistent phone format. | High |
Lead Nurture Message Delivery Fix
| ID | Test Case | Preconditions | Steps | Expected Result | Priority |
|---|---|---|---|---|---|
| LEAD-082 | Nurture message sent when conversation does not exist (auto-create) | Logged in as user with `leads:manage`, lead exists, nurture sequence enrolled with no existing conversation | 1. Trigger nurture step execution (wait for schedule or manually execute if available) 2. Observe message delivery 3. Check conversation list for lead's contact | Message is sent successfully. Conversation is automatically created for lead's contact and WhatsApp account. Message appears in conversation. Audit log shows "nurture_step_sent". | High |
| LEAD-083 | Nurture message sent to existing conversation | Logged in as user with `leads:manage`, lead enrolled in sequence, conversation already exists | 1. Trigger nurture step execution 2. Observe message in conversation | Message is sent to existing conversation without creating duplicate. Message appears in conversation thread. Delivery status tracked. | High |
| LEAD-084 | Nurture step audit log includes enrollment ID, sequence name, step index, and template name | Logged in as user with `leads:manage`, nurture step executed | 1. Execute nurture step 2. Navigate to lead's activity/audit log | Audit log entry shows: event_type = "nurture_step_sent", enrollment_id, sequence_name, step (index), template name. Timestamp recorded. | High |
| LEAD-085 | Nurture message delivery uses lead's WhatsApp account | Logged in as user with `leads:manage`, lead with whatsapp_account_id = "account_a", nurture sequence created account-agnostic | 1. Enroll lead in sequence 2. Wait for or trigger step execution 3. Check message logs/conversation | Message sent via account_a (lead's assigned account). automation_metadata shows source_type = "nurture". | High |