A complete Laravel 12 CRM REST API built as a portfolio demonstration. This API provides comprehensive customer relationship management functionality with multi-tenant architecture, role-based permissions, and modern Laravel features.
- Multi-tenant Architecture: Complete team isolation with
team_idscoping - Authentication: Laravel Sanctum for API authentication
- Authorization: Role-based permissions using Spatie Laravel Permission
- Resources: User, Company, Contact, Deal, Activity, Note management
- Deal Pipeline: Complete deal lifecycle with stages (prospect β qualified β proposal β won/lost)
- Advanced Querying: Filtering, sorting, and pagination with Spatie Query Builder
- Event System: Deal stage change events with listeners and jobs
- API Documentation: Auto-generated documentation with Scramble
- Testing: Comprehensive feature tests included
- Demo Data: Rich seeded data for testing and demonstration
- Access Control: Configurable read/write permissions for public demos
- PHP 8.2+
- Composer
- MySQL/PostgreSQL
- Laravel 12.x
- Node.js & NPM (for frontend assets, if needed)
-
Clone the repository
git clone <repository-url> cd LeanCRM
-
Install PHP dependencies
composer install
-
Environment setup
cp .env.example .env php artisan key:generate
-
Configure database (update
.envfile)DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=leancrm DB_USERNAME=your_username DB_PASSWORD=your_password -
Run migrations and seed the database
php artisan migrate --seed
-
Start the development server
php artisan serve
The API will be available at http://localhost:8000
The application comes with comprehensive seeders that create realistic demo data for testing and demonstration purposes.
After running php artisan migrate --seed, you can use these demo accounts:
| Password | Role | Description | |
|---|---|---|---|
admin@team1.com |
password123 |
Admin | Team 1 Administrator |
admin@team2.com |
password123 |
Admin | Team 2 Administrator |
demo@leancrm.com |
demo123 |
Sales Rep | Demo Sales Representative |
manager@leancrm.com |
demo123 |
Manager | Demo Sales Manager |
- 9 Users: Admins, demo users, and additional team members
- 30 Companies: Realistic companies with proper contact details
- 70+ Contacts: Individual contacts linked to companies
- 80+ Deals: Sales opportunities in various pipeline stages ($15k-$75k range)
- 200+ Activities: Calls, meetings, emails, tasks, and follow-ups
- 150+ Notes: Realistic CRM notes attached to deals
The seeders create:
- 5 Featured Demo Companies: TechCorp Solutions, Global Marketing Inc, Startup Ventures LLC, etc.
- Deal Pipeline Examples: Prospects, qualified leads, proposals, won/lost deals
- Realistic CRM Activities: Discovery calls, proposal presentations, contract negotiations
- Multi-team Isolation: Data properly separated between Team 1 and Team 2
# Seed with existing database
php artisan db:seed
# Fresh migration with seeding (recommended for demo setup)
php artisan migrate:fresh --seed
# Run specific seeder
php artisan db:seed --class=CompanySeederThe API includes configurable read/write access controls, perfect for public demonstrations while maintaining security.
Add these variables to your .env file:
# CRM Access Control
CRM_READ_ENABLED=true
CRM_WRITE_ENABLED=true
CRM_PUBLIC_DEMO_MODE=false| Variable | Default | Description |
|---|---|---|
CRM_READ_ENABLED |
true |
Enable/disable GET endpoints |
CRM_WRITE_ENABLED |
true |
Enable/disable POST/PUT/DELETE endpoints |
CRM_PUBLIC_DEMO_MODE |
false |
Special mode for public demonstrations |
For Public Demo (Read-Only):
CRM_READ_ENABLED=true
CRM_WRITE_ENABLED=false
CRM_PUBLIC_DEMO_MODE=trueFor Maintenance Mode:
CRM_READ_ENABLED=false
CRM_WRITE_ENABLED=false
CRM_PUBLIC_DEMO_MODE=falseFor Full Access:
CRM_READ_ENABLED=true
CRM_WRITE_ENABLED=true
CRM_PUBLIC_DEMO_MODE=falseWhen access is disabled, the API returns 503 Service Unavailable with appropriate messages:
- Demo mode: "Write operations are disabled in demo mode. This is a read-only demonstration."
- Maintenance mode: "This service is temporarily unavailable for maintenance."
The API is documented using Scramble and is available at:
http://localhost:8000/docs/api
Scramble automatically generates interactive API documentation from your controller annotations and request classes. The documentation includes:
- Complete API Reference: All endpoints with detailed descriptions
- Request/Response Examples: Real-world examples for each endpoint
- Authentication Guide: How to authenticate and use Bearer tokens
- Interactive Testing: "Try It" feature to test endpoints directly
- Query Parameters: Filtering, sorting, pagination documentation
- Validation Rules: Complete validation requirements
- Response Schemas: Detailed response structure documentation
- Start your Laravel development server:
php artisan serve - Visit
http://localhost:8000/docs/apiin your browser - Browse through the organized sections:
- Authentication - Register, login, logout endpoints
- Deal Management - Complete CRUD for deals with pipeline
- Company Management - Client company management
- Contact Management - Individual contact management
- Activity Management - Tasks and activities
- Note Management - Notes attached to any resource
- Use the interactive "Try It" buttons to test endpoints
- View real-time request/response examples
curl -X POST http://localhost:8000/api/auth/register \
-H "Content-Type: application/json" \
-d '{
"name": "John Doe",
"email": "john@example.com",
"password": "password",
"password_confirmation": "password"
}'curl -X POST http://localhost:8000/api/auth/login \
-H "Content-Type: application/json" \
-d '{
"email": "john@example.com",
"password": "password"
}'Response:
{
"access_token": "1|abc123...",
"token_type": "Bearer",
"user": {
"id": 1,
"name": "John Doe",
"email": "john@example.com"
}
}curl -X GET http://localhost:8000/api/companies \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"curl -X POST http://localhost:8000/api/companies \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "Acme Corporation",
"email": "contact@acme.com",
"phone": "+1-555-0123",
"website": "https://acme.com"
}'curl -X POST http://localhost:8000/api/deals \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"title": "Website Redesign Project",
"description": "Complete website overhaul with modern design",
"amount": 15000.00,
"stage": "prospect",
"expected_close_date": "2024-12-31"
}'# Filter by stage and sort by amount
curl -X GET "http://localhost:8000/api/deals?filter[stage]=qualified&sort=-amount" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"
# Include related models
curl -X GET "http://localhost:8000/api/deals?include=company,contact,user" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Accept: application/json"- User: System users with team association
- Company: Client companies
- Contact: Individual contacts within companies
- Deal: Sales opportunities with pipeline stages
- Activity: Tasks and activities linked to any model
- Note: Notes that can be attached to any model
All models are scoped by team_id to ensure complete data isolation between teams. The API automatically filters all queries by the authenticated user's team.
When a deal's stage changes, the system triggers:
- DealStageChanged Event: Captures the stage change
- SendDealStageNotification Listener: Queues notification job
- SendDealStageChangeNotification Job: Handles notification delivery
Run the comprehensive test suite to ensure everything is working correctly:
# Run all tests
php artisan test
# Run specific test file
php artisan test tests/Feature/ApiEndpointsTest.php
# Run tests with coverage (requires Xdebug)
php artisan test --coverage
# Run tests with detailed output
php artisan test --verboseThe test suite includes 139+ assertions covering:
- Authentication Flow: Registration, login, logout, and token validation
- CRUD Operations: Complete create, read, update, delete for all resources
- Multi-tenant Isolation: Ensures teams can't access each other's data
- Authorization: Policy-based access control verification
- Query Features: Filtering, sorting, pagination, and includes
- Validation: Request validation for all endpoints
- API Response Format: Proper JSON structure and status codes
- Error Handling: 401 unauthorized, 403 forbidden, 404 not found responses
PASS Tests\Feature\ApiEndpointsTest
β test authentication endpoints
β test companies crud endpoints
β test contacts crud endpoints
β test deals crud endpoints
β test activities crud endpoints
β test notes crud endpoints
β test unauthorized access returns 401
β test multi tenancy isolation
β test filtering and sorting
Tests: 9 passed
Assertions: 139 passed
Time: 2.34s
app/
βββ Events/
β βββ DealStageChanged.php
βββ Http/
β βββ Controllers/Api/
β β βββ AuthController.php
β β βββ DealController.php
β βββ Requests/
β β βββ DealStoreRequest.php
β β βββ DealUpdateRequest.php
β βββ Resources/
β βββ DealResource.php
βββ Jobs/
β βββ SendDealStageChangeNotification.php
βββ Listeners/
β βββ SendDealStageNotification.php
βββ Models/
β βββ Deal.php
β βββ Company.php
β βββ Contact.php
βββ Policies/
βββ DealPolicy.php
- API Token Authentication: Secure token-based authentication
- Authorization Policies: Fine-grained permissions for all resources
- Multi-tenant Isolation: Complete data separation between teams
- Input Validation: Comprehensive request validation
- Rate Limiting: Built-in Laravel rate limiting
For production, configure a proper queue driver in .env:
QUEUE_CONNECTION=redis
# or
QUEUE_CONNECTION=databaseThe system uses Spatie Laravel Permission for role-based access control. Default roles and permissions are set up through seeders.
- Eager Loading: Optimized database queries with relationship loading
- Pagination: Built-in pagination for all list endpoints
- Database Indexing: Proper database indexes for team-based queries
- Query Optimization: Efficient filtering and sorting with Query Builder
This is a portfolio project, but feedback and suggestions are welcome! Feel free to open issues or submit pull requests.
This project is open-sourced software licensed under the MIT license.