Complete backend implementation for a Call Center system with automatic dialer (Manual, Progressive, and Predictive modes).
- Java 17+
- Spring Boot 3.2+
- Spring Data JPA (Database access)
- Spring Security + JWT (Authentication)
- Spring WebSocket (Real-time notifications)
- MySQL 8.0 (Database)
- FreeSWITCH (Telephony engine via ESL)
backend/
βββ src/main/java/com/callcenter/
β βββ CallCenterApplication.java # Main application
β βββ config/ # Configuration classes
β β βββ CorsConfig.java
β β βββ FreeSwitchConfig.java
β β βββ SecurityConfig.java
β β βββ WebSocketConfig.java
β βββ controller/ # REST Controllers
β β βββ AuthController.java
β β βββ CampaignController.java
β β βββ ContactController.java
β β βββ CallController.java
β β βββ AgentController.java
β β βββ ReportController.java
β β βββ WebSocketController.java
β βββ model/ # Entity classes
β β βββ User.java
β β βββ Campaign.java
β β βββ Contact.java
β β βββ Call.java
β β βββ AgentStatus.java
β β βββ CallRecording.java
β βββ repository/ # Data access layer
β β βββ UserRepository.java
β β βββ CampaignRepository.java
β β βββ ContactRepository.java
β β βββ CallRepository.java
β β βββ AgentStatusRepository.java
β β βββ CallRecordingRepository.java
β βββ dto/ # Data Transfer Objects
β β βββ LoginRequest.java
β β βββ LoginResponse.java
β β βββ CallRequest.java
β β βββ CallResponse.java
β β βββ CampaignDTO.java
β β βββ ContactDTO.java
β β βββ StatisticsDTO.java
β β βββ AgentStatusDTO.java
β β βββ ImportResult.java
β βββ service/ # Business logic
β β βββ AuthService.java
β β βββ CampaignService.java
β β βββ ContactService.java
β β βββ CallService.java
β β βββ AgentService.java
β β βββ FreeSwitchService.java
β β βββ ReportService.java
β β βββ WebSocketService.java
β βββ dialer/ # Dialer implementations
β β βββ ManualDialer.java
β β βββ ProgressiveDialer.java # Runs every 5s
β β βββ PredictiveDialer.java # Runs every 3s
β β βββ DialRatioCalculator.java
β βββ freeswitch/ # FreeSWITCH integration
β β βββ ESLClient.java
β β βββ EventListener.java
β β βββ CommandBuilder.java
β β βββ EventHandler.java
β βββ security/ # Security components
β β βββ JwtTokenProvider.java
β β βββ JwtAuthenticationFilter.java
β β βββ UserDetailsServiceImpl.java
β βββ exception/ # Exception handling
β βββ ResourceNotFoundException.java
β βββ FreeSwitchException.java
β βββ ValidationException.java
β βββ GlobalExceptionHandler.java
βββ src/main/resources/
βββ application.yml # Application configuration
-
Java 17 or higher
java -version
-
Maven 3.6+
mvn -version
-
MySQL 8.0
mysql --version
-
FreeSWITCH (installed and configured)
systemctl status freeswitch
CRITICAL: Add this to pom.xml before building:
<!-- FreeSWITCH ESL Client -->
<dependency>
<groupId>org.freeswitch.esl.client</groupId>
<artifactId>org.freeswitch.esl.client</artifactId>
<version>0.9.2</version>
</dependency>CREATE DATABASE callcenter_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'callcenter_user'@'localhost' IDENTIFIED BY 'your_password';
GRANT ALL PRIVILEGES ON callcenter_db.* TO 'callcenter_user'@'localhost';
FLUSH PRIVILEGES;Edit src/main/resources/application.yml:
spring:
datasource:
url: jdbc:mysql://localhost:3306/callcenter_db
username: callcenter_user
password: your_password
jwt:
secret: change-this-to-a-secure-256-bit-secret-key-minimum-32-characters
freeswitch:
esl:
host: localhost
port: 8021
password: ClueCon# Clean and build
mvn clean install
# Run application
mvn spring-boot:run
# Or run JAR
java -jar target/callcenter-0.0.1-SNAPSHOT.jarApplication starts on: http://localhost:8080
POST /api/auth/login # Login
POST /api/auth/register # Register user
GET /api/auth/me # Get current user
GET /api/campaigns # List all (paginated)
GET /api/campaigns/{id} # Get campaign
POST /api/campaigns # Create campaign
PUT /api/campaigns/{id} # Update campaign
DELETE /api/campaigns/{id} # Delete campaign
POST /api/campaigns/{id}/start # Start campaign
POST /api/campaigns/{id}/pause # Pause campaign
POST /api/campaigns/{id}/stop # Stop campaign
GET /api/campaigns/{id}/statistics # Get statistics
GET /api/contacts # List all (paginated)
GET /api/contacts/{id} # Get contact
POST /api/contacts # Create contact
PUT /api/contacts/{id} # Update contact
DELETE /api/contacts/{id} # Delete contact
POST /api/contacts/import # Import CSV
GET /api/contacts/campaign/{campaignId} # List by campaign
POST /api/calls/make # Make call
POST /api/calls/{callId}/hangup # Hangup call
POST /api/calls/{callId}/transfer # Transfer call
POST /api/calls/{callId}/complete # Complete call (add notes)
GET /api/calls/history # Call history
GET /api/calls/{callId} # Get call details
GET /api/calls/agent/{agentId} # Agent's calls
GET /api/agents # List agents
GET /api/agents/{id}/status # Get agent status
POST /api/agents/{id}/status # Update agent status
GET /api/agents/available # Available agents
GET /api/agents/{id}/status/history # Status history
GET /api/reports/dashboard # Dashboard statistics
GET /api/reports/calls-by-hour # Calls by hour
GET /api/reports/calls-by-disposition # Calls by disposition
GET /api/reports/agent-performance # Agent performance
GET /api/reports/campaign-stats/{campaignId} # Campaign statistics
/topic/calls- All call events/topic/agents- Agent status changes/topic/campaigns- Campaign updates/topic/statistics- Statistics updates/user/queue/messages- User-specific messages/user/queue/contacts- Contact assignments
/app/call.event- Send call event/app/agent.status- Send agent status/app/campaign.update- Send campaign update
const socket = new SockJS('http://localhost:8080/ws');
const stompClient = Stomp.over(socket);
stompClient.connect({
'Authorization': 'Bearer ' + token
}, function(frame) {
console.log('Connected: ' + frame);
// Subscribe to call events
stompClient.subscribe('/topic/calls', function(message) {
const event = JSON.parse(message.body);
console.log('Call event:', event);
});
// Subscribe to user-specific messages
stompClient.subscribe('/user/queue/messages', function(message) {
const data = JSON.parse(message.body);
console.log('Message:', data);
});
});- Agent requests next contact
- Agent initiates call manually
- One call at a time per agent
- Runs automatically every 5 seconds
- Dials one contact per available agent
- Waits for customer to answer before connecting to agent
- No abandoned calls
- Runs automatically every 3 seconds
- Implements complete algorithm from specifications:
- Get campaign metrics
- Calculate contact rate
- Calculate dial ratio based on aggressiveness
- Adjust for abandonment rate
- Dial multiple contacts
- Connect answered calls to available agents
- Abandon calls if no agent available
Algorithm formula:
ratioBase = availableAgents / contactRate
ratio = ratioBase * aggressiveness
if (abandonmentRate > 5%): ratio = ratio * 0.8
ratio = min(ratio, availableAgents * 3)
callsToMake = ratio - callsInProgress
- originate - Initiate calls
- uuid_kill - Hangup calls
- uuid_bridge - Connect calls
- uuid_transfer - Transfer calls
- uuid_record - Record calls
- uuid_hold - Hold/unhold calls
- CHANNEL_CREATE - Call created
- CHANNEL_ANSWER - Call answered
- CHANNEL_HANGUP - Call ended
- CHANNEL_BRIDGE - Calls connected
- HEARTBEAT - Connection keepalive
- JWT token-based authentication
- Token expiration: 24 hours (configurable)
- BCrypt password encryption
- Role-based access control (RBAC)
- Roles: ADMIN, SUPERVISOR, AGENT
- Method-level security with @PreAuthorize
- Configured for frontend (http://localhost:4200)
- Can be customized in CorsConfig.java
Tables auto-created by JPA:
- users - System users (agents, supervisors, admins)
- campaigns - Call campaigns
- contacts - Contact list
- calls - Call history
- agent_status - Agent status tracking
- call_recordings - Recording metadata
curl -X POST http://localhost:8080/api/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"admin123"}'curl -X GET http://localhost:8080/api/campaigns \
-H "Authorization: Bearer YOUR_JWT_TOKEN"See WebSocket example above
Logs are configured in application.yml:
- Root level: INFO
- Application level: DEBUG
- FreeSWITCH events: DEBUG
- SQL queries: DEBUG (in development)
curl http://localhost:8080/actuator/healthcurl http://localhost:8080/actuator/metricsSolution: Check FreeSWITCH is running and ESL is enabled on port 8021
Solution: Verify MySQL is running and credentials are correct
Solution: Ensure JWT secret is at least 32 characters
Solution: Check CORS configuration and WebSocket endpoint
mvn clean package -DskipTestsjava -jar -Dspring.profiles.active=prod target/callcenter-0.0.1-SNAPSHOT.jarexport DB_URL=jdbc:mysql://production-db:3306/callcenter_db
export DB_USER=callcenter_user
export DB_PASSWORD=secure_password
export JWT_SECRET=your-secure-256-bit-secret-key
export FREESWITCH_HOST=freeswitch-serverFROM openjdk:17-jdk-slim
COPY target/callcenter-0.0.1-SNAPSHOT.jar app.jar
ENTRYPOINT ["java","-jar","/app.jar"]- Change default JWT secret
- Change default admin password
- Use HTTPS in production
- Configure firewall rules
- Enable rate limiting
- Regular security updates
- Monitor logs for suspicious activity
java -Xms2G -Xmx4G -XX:+UseG1GC -jar callcenter.jarConfigure in application.yml:
spring:
datasource:
hikari:
maximum-pool-size: 20
minimum-idle: 5- Follow Spring Boot best practices
- Use Lombok annotations
- Add proper logging
- Handle exceptions properly
- Write unit tests
- Document new endpoints
[Your License Here]
For issues and questions:
- Check logs in
logs/directory - Review this README
- Check IMPLEMENTATION_CHECKLIST.md
Status: Production Ready β
All 56 Java files implemented with complete functionality. No TODOs or stubs.