Skip to content

CRM (Prospects & Clients)

Customer Relationship Management module for tracking prospects through the sales pipeline, managing client follow-ups, and coordinating sales team activities.

Overview

The CRM module provides the sales and operations teams with a unified workspace to manage the full lifecycle of potential customers — from initial lead capture through qualification, negotiation, and conversion to active client. It combines three complementary views (Kanban board, data table, and activity calendar) with a detailed side panel for managing contacts, notes, locations, and follow-up data.

The module supports two entity types that share a common interface: prospects (leads without a company account) and clients (companies already registered on the platform). This dual-entity design allows the same pipeline tools to be used regardless of whether a lead has converted.

Key Concepts

ConceptDescription
ProspectA lead without a company account on the platform. Stored in prospection_users with company_id = NULL
ClientAn existing company on the platform being tracked for follow-up. Linked via prospection_users.company_id
Partner ProspectA special prospect type (type 3) for partner channel leads, with separate follow-up data
Follow-up CategoryA hierarchical status system organized into groups (e.g., "New", "Contacted", "Qualified"). Drives the Kanban columns
ActivityA follow-up note with an associated action type (call, email, WhatsApp, meeting, SMS, other) and optional scheduled date
NoteA timestamped comment attached to a prospect or client, recording an interaction or status change
ContactAn additional person associated with a prospect or client (beyond the primary contact)
LocationA physical address (office, warehouse, branch, headquarters, distribution center) linked to a prospect or client

Architecture

System Overview

Backend Structure

backend/
├── routes/
│   └── prospects.routes.js         # All prospect + client route definitions
├── controllers/
│   └── prospects.controller.js     # Request handlers for all CRM operations
├── libraries/
│   ├── prospects.util.js           # Prospect processing, filters, notifications
│   └── locationsProspects.util.js  # Location CRUD operations
├── constants/
│   ├── prospects.constants.js      # Ecommerce filter values
│   └── onboarding.constants.js     # Onboarding question IDs
└── jobs/
    └── repondio.jobs.js            # Respondio integration job processor

Frontend Structure

frontend/client/src/
├── views/crm/
│   ├── index.vue                           # Main view with view switcher
│   ├── components/
│   │   ├── Kamban.vue                      # Kanban board view
│   │   ├── ListView.vue                    # Data table view
│   │   ├── CalendarView.vue                # Calendar view
│   │   ├── Sidepanel.vue                   # Detail side panel
│   │   ├── AddProspect.modal.vue           # Add prospect modal
│   │   ├── CsvUpload.modal.vue             # CSV upload modal
│   │   └── ProcessCsv.offcanvas.vue        # CSV processing results
│   └── constants/
│       ├── table.defaults.js               # Default column/filter configuration
│       ├── account.constants.js            # Account type enum
│       ├── ecommerce.constants.js          # Ecommerce filter options
│       ├── prospect.services.js            # Service type definitions
│       └── roles.js                        # Role-based filter definitions
├── services/
│   ├── prospects.service.js                # Prospect API client
│   └── clients.service.js                  # Client API client
└── components/Forms/Follow/
    ├── Details.form.vue                    # Follow-up details form
    ├── Prospect.form.vue                   # Executive assignment form
    ├── Contact.form.vue                    # Contact create/edit form
    ├── Location.form.vue                   # Location create/edit form
    └── Note.form.vue                       # Follow-up note form

Data Flow

Prospect Creation

CSV Bulk Import

Kanban Drag-and-Drop

Follow-up Note Creation

Database

Tables

TablePurpose
prospection_usersPrimary prospect/client records with contact info, type, and status
follow_up_dataFollow-up metadata: channel, account value, shipments, ecommerce, weight, content
prospect_follow_up_commentsNotes/comments for prospects (linked by prospect_id)
follow_up_commentsNotes/comments for companies/clients (linked by company_id)
extra_contactsAdditional contacts beyond the primary, for both prospects and clients
company_locationsPhysical locations (office, warehouse, etc.) for prospects and clients
partner_follow_up_dataExtended data for partner-type prospects (URL, rating, social network)
catalog_follow_up_statusesFollow-up status catalog used for Kanban columns

Entity Relationship

Key Fields

prospection_users

ColumnTypeDescription
idINT (PK)Auto-increment
nameVARCHARContact person name
company_nameVARCHARCompany/organization name
emailVARCHARPrimary email address
phone_codeVARCHARCountry phone code
phoneVARCHARPhone number
company_idINT (FK, nullable)NULL for prospects, set for clients
follow_up_idINT (FK)Current follow-up status
locale_idINT (FK)Country/locale
monthly_shipment_idINTEstimated monthly shipment volume
typeTINYINT1 = prospect, 2 = client, 3 = partner prospect
statusTINYINT0 = removed, 1 = in process, 2 = registered
created_byINT (FK)Admin user who created the record
created_atDATETIMECreation timestamp

follow_up_data

ColumnTypeDescription
company_idINT (FK, nullable)Reference to companies (for clients)
prospect_idINT (FK, nullable)Reference to prospection_users (for prospects)
channelVARCHARAcquisition channel
account_valueDECIMALEstimated account value
monthly_shipmentsINTMonthly shipment estimate
ecommerce_type_idINT (FK)E-commerce platform type
weight_idINT (FK)Weight range category
content_idINT (FK)Package content type
account_typeVARCHARAccount size: individual, startup, sme, enterprise, corporate
estimated_close_dateDATEExpected deal close date
annotationsTEXTFree-form notes

prospect_follow_up_comments / follow_up_comments

ColumnTypeDescription
prospect_id / company_idINT (FK)Parent entity reference
status_id / follow_up_status_idINT (FK)Follow-up status at time of note
commentTEXTNote content
actionVARCHARAction type: call, whatsapp, email, meeting, sms, other
scheduled_dateDATETIMEOptional scheduled follow-up date
created_byINT (FK)Admin user who created the note

Role-Based Access

The CRM implements a multi-level permission system that controls both data visibility and available actions.

Permission Matrix

PermissionScopeEffect
319Base CRM accessRequired for all CRM endpoints
all-prospectsManager viewSee all prospects, date range filter, salesman filter, role filters
crm-edit-salesman-prospectExecutive reassignmentAllows changing the assigned salesman on a prospect
crm-partnersPartner managementAccess to partner prospect data endpoints
crm-menuLocation managementAccess to location CRUD endpoints
147Manager roleOverrides SDR/MDR restrictions to see all records

Role-Based Filters

When all-prospects permission is active, additional filters appear for each sales role:

RolePermission KeyDescription
KAEkaeKey Account Executive
KAE LTLkae_ltlKAE for Less-Than-Truckload
CSRcsrCustomer Service Representative
CSR LTLcsr_ltlCSR for LTL
FulfillmentfullfilmentFulfillment specialist
WMSwmsWarehouse Management
EcartpayecartpayEcartpay platform specialist
ParapaquetesparapaquetesParapaquetes service specialist

Data Visibility Rules

  • SDR users: See only their own prospects (filtered by created_by)
  • MDR users: See company-based records
  • Managers (permission 147): See all records regardless of assignment

Background Jobs

JobQueueTriggerDescription
respondio_add_prospectrespondioOn prospect creation (POST /prospects)Upserts contact in Respondio, assigns conversation, changes lifecycle to "New Lead", opens conversation

Key Decisions

DecisionReasoningAlternatives Considered
Unified route file for prospects and clientsBoth entities share most operations (notes, contacts, locations). A single controller reduces duplication.Separate controllers per entity (more code, harder to maintain shared logic)
Separate comment tables for prospects vs companiesProspects use prospect_follow_up_comments (by prospect_id), clients use follow_up_comments (by company_id). Required because prospects may not have a company_id.Single table with nullable foreign keys (query complexity, index inefficiency)
Provide/inject for cross-component communicationSidepanel, Kanban, and modals need to communicate without prop drilling. Vue's provide/inject is lightweight and avoids a dedicated store.Pinia store (overhead for ephemeral UI state), event bus (harder to trace)
useTablePreferences composable for all viewsStandardizes column/filter customization across Kanban, List, and Calendar. Persists to both localStorage and API.Per-view settings (inconsistent UX), global store (couples unrelated views)
Dual validation for CSV import (process then create)POST /prospects/process validates without writing; POST /prospects performs the actual insert. Gives users a preview before committing.Single endpoint with rollback (complex transactions), client-side only (misses server duplicate checks)
Client-side view switching with v-ifOnly one view is mounted at a time, keeping memory usage low. Each view fetches its own data on mount.Vue Router sub-routes (adds URL complexity), keep-alive (memory overhead for three large views)

Dependencies

  • Internal: Auth module (permissions, user context), Catalogs module (follow-up statuses, locales, phone codes, ecommerce types), Tasks module (TodoForm for reminders), Mailing module (email tab in sidepanel)
  • External: Respondio (lead conversation automation via Bull queue), FullCalendar (calendar view), vuedraggable (Kanban drag-and-drop), Vuelidate (form validation)

Envia Admin