Database Tables
This document describes the core database tables supporting the telecaller module, including lead management, call logging, follow-ups, and AI interactions.
Entity Relationship Diagram
Table Descriptions
ExternalLeads
The primary table for managing lead records in the system.
CREATE TABLE ExternalLeads (
LeadId INT PRIMARY KEY IDENTITY(1,1),
Mobile NVARCHAR(20) NOT NULL,
Name NVARCHAR(100),
Email NVARCHAR(100),
StaffId INT,
CallSourceId INT NOT NULL,
Status NVARCHAR(50) NOT NULL DEFAULT 'NEW',
IsActive BIT NOT NULL DEFAULT 1,
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDate DATETIME NOT NULL DEFAULT GETDATE(),
AICallStatus NVARCHAR(50) NULL,
AIPostRetryCount INT DEFAULT 0,
AIProviderType NVARCHAR(50),
AICallId NVARCHAR(100),
PostedToAIDate DATETIME NULL,
LastAIAttempt DATETIME NULL,
AIFailureReason NVARCHAR(MAX),
FOREIGN KEY (StaffId) REFERENCES Staff(StaffId),
FOREIGN KEY (CallSourceId) REFERENCES CallSource(SourceId)
);
CREATE INDEX idx_ExternalLeads_Mobile ON ExternalLeads(Mobile);
CREATE INDEX idx_ExternalLeads_StaffId ON ExternalLeads(StaffId);
CREATE INDEX idx_ExternalLeads_Status ON ExternalLeads(Status);
CREATE INDEX idx_ExternalLeads_IsActive ON ExternalLeads(IsActive);
CREATE INDEX idx_ExternalLeads_CreatedDate ON ExternalLeads(CreatedDate);
CREATE INDEX idx_ExternalLeads_AIStatus ON ExternalLeads(AICallStatus);Lead Status Values
| Status | Description | From | To | Auto-close? |
|---|---|---|---|---|
| NEW | Uncontacted lead | System | CP, Call Back, Trashed | No (< 30 days) |
| CP (Call Progress) | Promising lead, follow-up planned | Manual/AI | Follow-up/SV Fixed | No (protected) |
| SV_FIXED | Successful conversion | Manual | None | No (protected) |
| TRASHED | Invalid/uninterested | Manual/Auto | None | Yes (immediate) |
| NO_RESPONSE | No answer after attempts | Manual/AI | Follow-up/Trashed | Yes (30+ days) |
| PENDING_AI_CALL | Queued for AI auto-caller | System | Processing/AI_FAILED | No (< 7 days) |
| PROCESSING | AI call in progress | AI Scheduler | Completed/Failed | No |
| AI_FAILED | AI calling failed permanently | AI Scheduler | Assigned/Manual Queue | No |
| AUTO_CLOSED | Closed by auto-close job | Auto-close Scheduler | Archive | Yes (immediate) |
CallLog
Records every call attempt (manual or AI) for audit and performance tracking.
CREATE TABLE CallLog (
LogId INT PRIMARY KEY IDENTITY(1,1),
LeadId INT NOT NULL,
StaffId INT,
Mobile NVARCHAR(20),
CallStatus NVARCHAR(50) NOT NULL,
-- Values: ANSWERED, NOT_ANSWERED, INVALID, BUSY, DO_NOT_CALL
Notes NVARCHAR(MAX),
DurationSeconds INT DEFAULT 0,
CallDate DATETIME NOT NULL,
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
FOREIGN KEY (LeadId) REFERENCES ExternalLeads(LeadId),
FOREIGN KEY (StaffId) REFERENCES Staff(StaffId)
);
CREATE INDEX idx_CallLog_LeadId ON CallLog(LeadId);
CREATE INDEX idx_CallLog_StaffId ON CallLog(StaffId);
CREATE INDEX idx_CallLog_CallDate ON CallLog(CallDate);
CREATE INDEX idx_CallLog_CallStatus ON CallLog(CallStatus);CallStatus Values
| Status | Meaning | Duration | Next Action |
|---|---|---|---|
| ANSWERED | Lead picked up | Variable | Log conversation outcome |
| NOT_ANSWERED | No answer/ring | 0-60 sec | Schedule follow-up |
| INVALID | Bad number/disconnected | 0 sec | Mark as Trashed |
| BUSY | Line busy | 0 sec | Retry later |
| DO_NOT_CALL | Lead opted out | 0 sec | Immediate Trashed |
| VOICEMAIL | Message left | Variable | Schedule follow-up |
| SWITCHED | Transferred to another party | Variable | Follow conversation |
FollowupCalls
Tracks all follow-up calls scheduled and their completion status.
CREATE TABLE FollowupCalls (
FollowupId INT PRIMARY KEY IDENTITY(1,1),
LeadId INT NOT NULL,
StaffId INT NOT NULL,
ReviewDateTime DATETIME NOT NULL,
-- When this follow-up should be reviewed
IsCompleted BIT NOT NULL DEFAULT 0,
CompletedDate DATETIME NULL,
Notes NVARCHAR(MAX),
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDate DATETIME NOT NULL DEFAULT GETDATE(),
FOREIGN KEY (LeadId) REFERENCES ExternalLeads(LeadId),
FOREIGN KEY (StaffId) REFERENCES Staff(StaffId)
);
CREATE INDEX idx_FollowupCalls_StaffId ON FollowupCalls(StaffId);
CREATE INDEX idx_FollowupCalls_ReviewDateTime ON FollowupCalls(ReviewDateTime);
CREATE INDEX idx_FollowupCalls_IsCompleted ON FollowupCalls(IsCompleted);
CREATE INDEX idx_FollowupCalls_StaffReview ON FollowupCalls(StaffId, ReviewDateTime)
WHERE IsCompleted = 0;CallSource
Defines the sources/channels from which leads originate (e.g., website form, purchased list, referral).
CREATE TABLE CallSource (
SourceId INT PRIMARY KEY IDENTITY(1,1),
SourceName NVARCHAR(100) NOT NULL,
-- Values: Website, PurchasedList, Referral, Inbound, etc.
DIDNumber NVARCHAR(20),
-- Direct Inbound Dialing number if applicable
IsActive BIT NOT NULL DEFAULT 1,
ProjectId INT,
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDate DATETIME NOT NULL DEFAULT GETDATE()
);
CREATE INDEX idx_CallSource_SourceName ON CallSource(SourceName);Source Types
| Source | Channel | Lead Volume | Quality |
|---|---|---|---|
| Website | Inbound web form | High | High |
| PurchasedList | Third-party provider | Very High | Medium |
| Referral | Existing customer reference | Low | Very High |
| Inbound | Direct phone calls | Medium | High |
| Campaign | Marketing campaign response | High | Medium-High |
| Partner | Business partner | Low | Variable |
WeeklyLeadHistory
Aggregated historical metrics at each hierarchy level, generated weekly.
CREATE TABLE WeeklyLeadHistory (
HistoryId INT PRIMARY KEY IDENTITY(1,1),
WeekStartDate DATETIME NOT NULL,
StaffId INT NOT NULL,
ManagerId INT,
HierarchyLevel NVARCHAR(50) NOT NULL,
-- Values: Telecaller, BDO, SeniorManager, GM, AVP
NewLeadsAssigned INT NOT NULL DEFAULT 0,
SVFixed INT NOT NULL DEFAULT 0,
CallProgress INT NOT NULL DEFAULT 0,
Trashed INT NOT NULL DEFAULT 0,
NoResponse INT NOT NULL DEFAULT 0,
FollowupCreated INT NOT NULL DEFAULT 0,
FollowupCompleted INT NOT NULL DEFAULT 0,
ConversionRate DECIMAL(5,2) NOT NULL DEFAULT 0,
FollowupCompletionRate DECIMAL(5,2) NOT NULL DEFAULT 0,
AvgResponseHours DECIMAL(8,2) NOT NULL DEFAULT 0,
ActivityRate DECIMAL(5,2) NOT NULL DEFAULT 0,
WasteRate DECIMAL(5,2) NOT NULL DEFAULT 0,
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
FOREIGN KEY (StaffId) REFERENCES Staff(StaffId),
FOREIGN KEY (ManagerId) REFERENCES Staff(StaffId)
);
CREATE INDEX idx_WeeklyLeadHistory_StaffId ON WeeklyLeadHistory(StaffId);
CREATE INDEX idx_WeeklyLeadHistory_WeekStart ON WeeklyLeadHistory(WeekStartDate);
CREATE INDEX idx_WeeklyLeadHistory_HierarchyLevel ON WeeklyLeadHistory(HierarchyLevel);
CREATE INDEX idx_WeeklyLeadHistory_StaffWeek ON WeeklyLeadHistory(StaffId, WeekStartDate);AICallLog
Complete record of all AI auto-calling interactions.
CREATE TABLE AICallLog (
AILogId INT PRIMARY KEY IDENTITY(1,1),
LeadId INT NOT NULL,
ProviderId NVARCHAR(50) NOT NULL,
-- AI provider: VoiceAPI, Twilio, CustomProvider
CallId NVARCHAR(100) NOT NULL UNIQUE,
-- Provider's call identifier
Status NVARCHAR(50) NOT NULL,
-- Values: INITIATED, IN_PROGRESS, COMPLETED, FAILED
DurationSeconds INT DEFAULT 0,
RecordingUrl NVARCHAR(MAX),
TranscriptText NVARCHAR(MAX),
CallResult NVARCHAR(50),
-- Values: INTERESTED, NOT_INTERESTED, CALLBACK, ERROR
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
CompletedDate DATETIME NULL,
FOREIGN KEY (LeadId) REFERENCES ExternalLeads(LeadId)
);
CREATE INDEX idx_AICallLog_LeadId ON AICallLog(LeadId);
CREATE INDEX idx_AICallLog_ProviderId ON AICallLog(ProviderId);
CREATE INDEX idx_AICallLog_Status ON AICallLog(Status);
CREATE INDEX idx_AICallLog_CreatedDate ON AICallLog(CreatedDate);TeleLeaderMapping
Maps managers to their assigned team members with periodic cache refresh.
CREATE TABLE TeleLeaderMapping (
MappingId INT PRIMARY KEY IDENTITY(1,1),
LeaderId INT NOT NULL,
-- Manager (BDO, Senior Manager, GM, AVP)
StaffId INT NOT NULL,
-- Direct report (TC or BDO)
IsActive BIT NOT NULL DEFAULT 1,
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDate DATETIME NOT NULL DEFAULT GETDATE(),
FOREIGN KEY (LeaderId) REFERENCES Staff(StaffId),
FOREIGN KEY (StaffId) REFERENCES Staff(StaffId),
CONSTRAINT chk_SelfMapping CHECK (LeaderId <> StaffId)
);
CREATE INDEX idx_TeleLeaderMapping_LeaderId ON TeleLeaderMapping(LeaderId);
CREATE INDEX idx_TeleLeaderMapping_StaffId ON TeleLeaderMapping(StaffId);
CREATE INDEX idx_TeleLeaderMapping_Active ON TeleLeaderMapping(IsActive);Staff (Reference)
Core staff/user table (simplified view for context).
CREATE TABLE Staff (
StaffId INT PRIMARY KEY IDENTITY(1,1),
StaffName NVARCHAR(100) NOT NULL,
Email NVARCHAR(100) UNIQUE,
Phone NVARCHAR(20),
Role NVARCHAR(50),
-- Values: Telecaller, BDO, SeniorManager, GM, AVP
IsActive BIT NOT NULL DEFAULT 1,
CreatedDate DATETIME NOT NULL DEFAULT GETDATE(),
ModifiedDate DATETIME NOT NULL DEFAULT GETDATE()
);
CREATE INDEX idx_Staff_StaffName ON Staff(StaffName);
CREATE INDEX idx_Staff_Role ON Staff(Role);Data Size & Retention
Estimated data volumes and retention policies:
| Table | Annual Rows | GB/Year | Retention |
|---|---|---|---|
| ExternalLeads | 4K-18K | 0.1-0.5 | 2 years |
| CallLog | 4K-55K | 0.2-1.5 | 3 years |
| FollowupCalls | 1K-6K | 0.05-0.2 | 1 year |
| AICallLog | 2K-9K | 0.2-0.8 | 2 years |
| WeeklyLeadHistory | 5K-26K | 0.1-0.3 | 7 years |
| Total Estimated | 16K-114K | 0.65-3.3 |
Query Performance Indexes
All critical queries have indexes defined:
| Table | Query Pattern | Index | Impact |
|---|---|---|---|
| ExternalLeads | Pending AI leads | Status, IsActive, CreatedDate | Critical |
| ExternalLeads | TC's active leads | StaffId, Status, IsActive | Critical |
| CallLog | Lead history | LeadId, CallDate | High |
| FollowupCalls | TC's due follow-ups | StaffId, ReviewDateTime, IsCompleted | Critical |
| FollowupCalls | Manager's overdue | StaffId, ReviewDateTime, IsCompleted | High |
| WeeklyLeadHistory | Manager dashboard | StaffId, WeekStartDate, HierarchyLevel | High |
| AICallLog | AI success rate | ProviderId, Status, CreatedDate | Medium |
Archival Strategy
To maintain performance as data grows:
-- Archive old data to separate table
CREATE TABLE ExternalLeads_Archive (
-- Same schema as ExternalLeads
);
-- Monthly job to archive leads older than 2 years
INSERT INTO ExternalLeads_Archive
SELECT * FROM ExternalLeads
WHERE DATEDIFF(YEAR, CreatedDate, GETDATE()) > 2
AND IsActive = 0;
DELETE FROM ExternalLeads
WHERE DATEDIFF(YEAR, CreatedDate, GETDATE()) > 2
AND IsActive = 0;Data Integrity Rules
Critical constraints and business rules:
| Rule | Enforcement | Consequence |
|---|---|---|
| LeadId uniqueness | PRIMARY KEY | Cannot create duplicate leads |
| Mobile format | CHECK constraint (20 chars) | Invalid numbers rejected |
| ReviewDateTime > Now | Application logic | Cannot schedule past follow-ups |
| Status enum | CHECK constraint | Only valid statuses allowed |
| AI retry limit | Application logic | Failed leads moved to manual queue |
| Follow-up completion | Cannot be null date if IsCompleted = 1 | Ensures audit trail |
| Manager-Staff mapping | No self-mapping | Cannot assign person as own manager |
Performance Considerations
Clustered Indexes
-- Optimize for most common queries
ALTER TABLE ExternalLeads
ADD CONSTRAINT pk_ExternalLeads PRIMARY KEY CLUSTERED (LeadId);
ALTER TABLE CallLog
ADD CONSTRAINT pk_CallLog PRIMARY KEY CLUSTERED (LeadId, CallDate);
ALTER TABLE FollowupCalls
ADD CONSTRAINT pk_FollowupCalls PRIMARY KEY CLUSTERED (StaffId, ReviewDateTime);Non-Clustered Covering Indexes
-- For "due soon" follow-up query
CREATE NONCLUSTERED INDEX idx_FollowupDueSoon
ON FollowupCalls (StaffId, IsCompleted)
INCLUDE (ReviewDateTime, FollowupId, LeadId)
WHERE IsCompleted = 0;Backup & Disaster Recovery
- Backup Frequency: Daily full, hourly transaction log
- Retention: 30 days on-site, 90 days off-site
- Recovery Time: < 1 hour (RTO)
- Recovery Point: < 5 minutes (RPO)
Monitoring & Alerts
Database health monitoring:
- Table fragmentation > 30% → Auto-rebuild indexes
- Query execution time > 5 sec → Log and investigate
- Backup failures → Immediate alert
- Replication lag > 1 min → Monitoring escalation