SplashLeads is a complete, lightweight, multi-tenant Sales Pipeline & Lead Tracking SaaS platform built with pure PHP and MySQL. It provides comprehensive lead management, pipeline tracking, activity management, and subscription-based multi-tenancy.
- Multi-Tenant Architecture - Isolated data per tenant with subscription-based access control
- Lead Management - Complete CRUD for leads with advanced filtering and search
- Pipeline & Stages - Customizable sales pipelines with drag-and-drop stage management
- Activity Tracking - Tasks, calls, meetings, and notes with due date reminders
- Lead Scoring - Automatic lead scoring based on source, stage, and activities
- Role-Based Access Control - 5 user roles with granular permissions
- Subscription Management - Plans, quotas, usage tracking, and billing
- RESTful API - Full API for lead creation, stage updates, and activity management
- File Uploads - Secure file attachments for leads
- Activity Logs - Comprehensive audit trail for all actions
- Notifications - In-app and email notifications
- Reports - Dashboard KPIs and exportable reports
- Platform Admin - Global SaaS owner, manages all tenants
- Tenant Admin - Company admin, manages users and settings
- Sales Manager - Manages all leads and assigns to reps
- Sales Rep - Manages assigned leads and activities
- Viewer - Read-only access
- Backend: PHP 7.0+ (compatible with PHP 8.x)
- Database: MySQL 5.7+ / MariaDB 10.2+
- Frontend: HTML5, CSS3, Vanilla JavaScript
- Architecture: Custom lightweight MVC framework
- Security: Password hashing, CSRF protection, prepared statements, input validation
- PHP 7.0 or higher (8.x compatible)
- MySQL 5.7+ or MariaDB 10.2+
- Apache or Nginx web server
- PHP Extensions:
- pdo_mysql
- mbstring
- openssl
- json
- fileinfo
- ctype
git clone <repository-url> splashleads
cd splashleadsCreate a MySQL database:
CREATE DATABASE splashleads CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Import the database schema:
mysql -u your_username -p splashleads < database.sqlCopy the example environment file:
cp .env.example .envEdit .env with your database credentials:
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=splashleads
DB_USERNAME=your_username
DB_PASSWORD=your_password
Set write permissions for storage directories:
chmod -R 755 storage/uploads
chmod -R 755 storage/logsCreate a virtual host pointing to the /public directory:
<VirtualHost *:80>
ServerName splashleads.local
DocumentRoot /path/to/splashleads/public
<Directory /path/to/splashleads/public>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/splashleads-error.log
CustomLog ${APACHE_LOG_DIR}/splashleads-access.log combined
</VirtualHost>Enable mod_rewrite:
sudo a2enmod rewrite
sudo systemctl restart apache2Configure nginx server block:
server {
listen 80;
server_name splashleads.local;
root /path/to/splashleads/public;
index index.php;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
location ~ /\.(?!well-known).* {
deny all;
}
}Open your browser and navigate to:
http://splashleads.local
Default login credentials:
Platform Admin:
- Email: admin@splashleads.com
- Password: admin123
Tenant Admin:
- Email: tenant@demo.com
- Password: admin123
Sales Manager:
- Email: manager@demo.com
- Password: admin123
Sales Rep:
- Email: rep@demo.com
- Password: admin123
IMPORTANT: Change these passwords immediately after first login!
splashleads/
├── app/
│ ├── controllers/ # Application controllers
│ ├── models/ # Database models
│ ├── views/ # View templates
│ ├── core/ # Core MVC framework
│ └── helpers/ # Helper classes
├── config/ # Configuration files
├── public/ # Public web root
│ ├── assets/ # CSS, JS, images
│ └── index.php # Application entry point
├── storage/
│ ├── uploads/ # Uploaded files
│ └── logs/ # Application logs
├── database.sql # Database schema
├── .env.example # Environment configuration template
└── README.md # This file
All API requests require an API key passed in the X-API-KEY header.
To generate an API key for a tenant:
INSERT INTO tenant_api_keys (tenant_id, api_key, name, is_active)
VALUES (1, SHA2(CONCAT('your_key', NOW(), RAND()), 256), 'My API Key', 1);Endpoint: POST /api/leads/create
Headers:
X-API-KEY: your_api_key_here
Content-Type: application/json
Request Body:
{
"first_name": "John",
"last_name": "Doe",
"company_name": "ACME Inc",
"email": "john@example.com",
"phone": "+1234567890",
"mobile": "+1234567890",
"source_code": "website",
"potential_value": 5000,
"currency": "USD",
"owner_email": "rep@demo.com",
"notes": "Interested in enterprise plan"
}Response:
{
"status": "success",
"message": "Lead created successfully",
"lead_id": 123,
"pipeline_id": 1,
"stage_id": 1
}Endpoint: POST /api/leads/stage
Headers:
X-API-KEY: your_api_key_here
Content-Type: application/json
Request Body:
{
"lead_id": 123,
"stage_id": 3,
"note": "Moving to qualified stage after demo"
}Response:
{
"status": "success",
"message": "Lead stage updated successfully",
"lead_id": 123,
"stage_id": 3
}Endpoint: POST /api/activities/create
Headers:
X-API-KEY: your_api_key_here
Content-Type: application/json
Request Body:
{
"lead_id": 123,
"activity_type": "call",
"subject": "Follow-up call",
"description": "Discussed pricing and timeline",
"due_date": "2025-01-15T10:00:00Z",
"owner_email": "rep@demo.com"
}Response:
{
"status": "success",
"message": "Activity created successfully",
"activity_id": 456
}Endpoint: GET /api/leads/list
Headers:
X-API-KEY: your_api_key_here
Query Parameters:
page- Page number (default: 1)per_page- Items per page (default: 20, max: 100)stage_id- Filter by stagesource_id- Filter by sourcestatus- Filter by status (new, working, qualified, etc.)owner_email- Filter by owner emaildate_from- Filter by creation date (YYYY-MM-DD)date_to- Filter by creation date (YYYY-MM-DD)
Response:
{
"status": "success",
"data": [
{
"id": 123,
"full_name": "John Doe",
"company_name": "ACME Inc",
"email": "john@example.com",
"status": "qualified",
"stage_name": "Qualified",
"potential_value": "5000.00",
"lead_score": 75
}
],
"pagination": {
"current_page": 1,
"per_page": 20,
"total": 150,
"total_pages": 8
}
}All API endpoints return standard error responses:
{
"status": "error",
"message": "Error description"
}HTTP Status Codes:
200- Success201- Created400- Bad Request401- Unauthorized (invalid API key)403- Forbidden (quota exceeded, feature not available)404- Not Found500- Internal Server Error
The system includes four default plans:
- Price: $0/month
- Duration: 14 days
- Max Users: 2
- Max Leads: 100
- Max Pipelines: 1
- Max Activities/Month: 50
- Storage: 50 MB
- API Access: No
- Advanced Reports: No
- Lead Scoring: No
- Price: $29/month
- Max Users: 5
- Max Leads: 1,000
- Max Pipelines: 3
- Max Activities/Month: 500
- Storage: 100 MB
- API Access: No
- Advanced Reports: No
- Lead Scoring: No
- Price: $79/month
- Max Users: 15
- Max Leads: 5,000
- Max Pipelines: 10
- Max Activities/Month: 2,000
- Storage: 500 MB
- API Access: Yes
- Advanced Reports: Yes
- Lead Scoring: Yes
- Price: $199/month
- Max Users: 100
- Max Leads: 50,000
- Max Pipelines: 50
- Max Activities/Month: 10,000
- Storage: 5 GB
- API Access: Yes
- Advanced Reports: Yes
- Lead Scoring: Yes
The system automatically enforces quotas:
- Users cannot create new leads when limit is reached
- Activities are blocked when monthly quota is exceeded
- API access requires proper plan feature
- Account enters read-only mode if subscription is inactive
Set up the following cron jobs for automated tasks:
# Send pending email notifications (every 5 minutes)
*/5 * * * * php /path/to/splashleads/scripts/send-emails.php
# Reset monthly usage counters (monthly on 1st at midnight)
0 0 1 * * php /path/to/splashleads/scripts/reset-monthly-usage.php
# Update overdue invoices (daily at midnight)
0 0 * * * php /path/to/splashleads/scripts/update-invoices.phpNote: Create these scripts in a /scripts directory based on your needs.
- Change Default Passwords - Immediately change all demo account passwords
- Use HTTPS - Always use SSL/TLS in production
- Secure .env File - Never commit
.envto version control - Database Access - Use restricted database user with minimal privileges
- File Permissions - Set proper permissions (files: 644, directories: 755)
- Regular Backups - Implement automated database and file backups
- Update PHP - Keep PHP updated to latest stable version
- Disable Debug Mode - Set
APP_DEBUG=falsein production - API Key Security - Store API keys securely, rotate regularly
- Input Validation - The system validates all inputs, but review custom code
- User login with valid credentials
- User login with invalid credentials
- Account lockout after failed attempts
- User registration and tenant creation
- Logout functionality
- Platform admin can access all tenants
- Tenant admin can manage users
- Sales manager can view all leads
- Sales rep can only view assigned leads
- Viewer has read-only access
- Create new lead
- Edit existing lead
- Delete lead
- Search and filter leads
- Lead assignment
- Lead scoring calculation
- Stage change tracking
- Create pipeline
- Add/edit/delete stages
- Reorder stages
- Lead movement between stages
- Create activity
- Mark activity as completed
- View overdue activities
- Activity reminders
- Quota enforcement (users, leads, activities)
- Plan feature restrictions
- Read-only mode for inactive subscriptions
- Usage tracking
- API authentication
- Create lead via API
- Update lead stage via API
- Create activity via API
- List leads via API
- Error handling
- Upload valid file types
- Block invalid file types
- File size restrictions
- Secure file access
- CSRF protection
- SQL injection prevention
- XSS prevention
- Tenant data isolation
- Password hashing
- All critical columns are indexed
- Foreign keys for referential integrity
- Compound indexes for common queries
idx_tenant_idon all multi-tenant tablesidx_emailon users and leadsidx_statusfor filtering- Full-text index on lead search fields
For high-traffic deployments:
- Implement PHP OpCache
- Use Redis/Memcached for session storage
- Cache frequently accessed data (plans, sources, pipelines)
- Database read replicas for reporting
- CDN for static assets
- Horizontal scaling with load balancer
- Separate background job processing
Error: Database connection failed
Solution: Check .env database credentials and ensure MySQL is running
Error: Failed to write file
Solution: chmod -R 755 storage/uploads storage/logs
Error: Page not found
Solution: Enable mod_rewrite (Apache) or check nginx configuration
Error: Invalid API key
Solution: Verify X-API-KEY header and check tenant_api_keys table
- Implement rate limiting for login attempts
- Add two-factor authentication (2FA)
- Implement API request rate limiting
- Add CAPTCHA for registration
- Implement Content Security Policy (CSP) headers
- Add query result caching for dashboard stats
- Implement database connection pooling
- Use EXPLAIN to analyze slow queries
- Consider partitioning for large tables
- Implement background job queue (Redis/Beanstalkd)
- Add asynchronous email sending
- Implement caching layer (Redis/Memcached)
- Consider microservices for API
- Implement CDN for static assets
- Email integration (SMTP/SendGrid)
- Advanced reporting with charts
- Export to PDF
- Import leads from CSV
- Webhook support
- Mobile app API
- Kanban board for pipeline visualization
- Custom fields for leads
- Email templates
- SMS notifications
This project is provided as-is for educational and commercial use.
For issues, questions, or contributions, please open an issue on the repository.
Developed as a complete multi-tenant SaaS CRM platform using pure PHP and MySQL.
SplashLeads - Streamline your sales pipeline management