Hazır CRM’ler, HubSpot veya Salesforce gibi, birçok özellik sunar; ancak genellikle yüksek fiyat katmanları, karmaşık arayüzler ve özel iş modelinize uymayan katı iş akışları ile gelirler.
İşinizin özel lead boru hatlarına, özelleştirilmiş raporlara ve ayrıntılı rol izinlerine ihtiyacı olduğunda, Laravel ile özel bir CRM oluşturmak, alabileceğiniz en maliyet etkin ve ölçeklenebilir yolardan biridir.
Laravel 12 sürümü ile, kurumsal düzeyde araçlar oluşturmak her zamankinden daha hızlı ve temizdir. Bu kapsamlı kılavuzda, kimlik doğrulama, çoklu kiracı lead boru hatları, dinamik durum yönetimi ve otomatik takip planlaması ile özel bir CRM temeli oluşturacağız.
1. CRM Veri Tabanı Mimarisi
1. CRM Veri Tabanı Mimarisi
Özel bir CRM, üç ana sütun etrafında döner: Kullanıcılar (Satış Temsilcileri/Yöneticiler), Şirketler (Hesaplar) ve Leads (Fırsatlar).
+---------------+ +---------------+ +---------------+
| Users | 1 M| Leads |M 1 | Companies |
+---------------+ +---------------+ +---------------+
| id | | id | | id |
| name | | title | | name |
| email | | value | | industry |
| role | | status | | phone |
+---------------+ | user_id | +---------------+
| company_id |
+---------------+
Modelleri ve migration’ları oluşturalım:
php artisan make:model Company -m
php artisan make:model Lead -mf
Şirketler Migration (create_companies_table.php)
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create('companies', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string()->nullable();
$table->string()->nullable();
$table->string()->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists();
}
};
Leads Migration (create_leads_table.php)
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::create(, function (Blueprint $table) {
$table->id();
$table->foreignId()->constrained()->cascadeOnDelete();
$table->foreignId()->nullable()->constrained()->nullOnDelete();$table->string();
$table->decimal(, 12, 2)->default();$table->string()->default(); // new, contacted, qualified, won, lost
$table->timestamp()->nullable();
$table->timestamps();
});
}
public function down(): void
{
Schema::dropIfExists();
}
};
2. Eloquent İlişkilerini ve Enum’ları Tanımlama
2. Eloquent İlişkilerini ve Enum’ları Tanımlama
Lead durumu için PHP 8 Enum’larının kullanımı, katı tiplerin korunmasını sağlar ve API uç noktalarınız ile Blade/Vue görünümlerinde geçersiz veri girişlerini önler.
Lead Durumu Enum’ını Tanımlayın (app/Enums/LeadStatus.php)
namespace App\Enums;
enum LeadStatus: string
{
case NEW = ;
case CONTACTED = ;
case QUALIFIED = ;
case WON = ;
case LOST = ;
public function label(): string
{
return match($this) {
self::NEW => ,
self::CONTACTED => ,
self::QUALIFIED => ,
self::WON => ,
self::LOST => ,
};
}
}
Lead Model’ını Güncelleyin (app/Models/Lead.php)
namespace App\Models;
use App\Enums\LeadStatus;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Lead extends Model
{
use HasFactory;
protected $fillable = [
,
,
,
,
,
,
];
protected function casts(): array
{
return [
=> LeadStatus::class,
=> ,
=> ,
];
}
public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function company(): BelongsTo
{
return $this->belongsTo(Company::class);
}
}
3. Lead Erişimini Politika Yetkilendirmesi ile Güvence Altına Alma
3. Lead Erişimini Politika Yetkilendirmesi ile Güvence Altına Alma
Satış ekiplerinin net erişim sınırlarına ihtiyacı vardır: Satış Temsilcileri yalnızca atanmış lead’leri görebilmeli, yöneticiler ise tüm anlaşmaları görebilmeli ve yeniden atayabilmelidir.
Lead Politikasını oluşturun:
app/Policies/LeadPolicy.php
namespace App\Policies;
use App\Models\Lead;
use App\Models\User;
class LeadPolicy
{
public function viewAny(User $user): bool
{
return true;
}
public function view(User $user, Lead$lead): bool
{
return $user->role === || $lead->user_id === $user->id;
}
public function update(User $user, Lead$lead): bool
{
return $user->role === || $lead->user_id === $user->id;
}
public function delete(User $user, Lead $lead): bool
{
return $user->role === ;
}
}
4. Lead Yönetim Kontrolcüsünü Oluşturma
4. Lead Yönetim Kontrolcüsünü Oluşturma
Form İstekleri için doğrulama kullanarak temiz, üretim hazır bir kontrolcü oluşturalım.
php artisan make:request StoreLeadRequest
php artisan make:controller LeadController
Doğrulama İsteği (app/Http/Requests/StoreLeadRequest.php)
namespace App\Http\Requests;
use App\Enums\LeadStatus;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rules\Enum;
class StoreLeadRequest extends FormRequest
{
public function authorize(): bool
{
return true;
}
public function rules(): array
{
return [
=> [, ],
=> [, , ],
=> [, , ],
=> [, new Enum(LeadStatus::class)],
];
}
app/Http/Controllers/LeadController.php
namespace App\Http\Controllers;
use App\Http\Requests\StoreLeadRequest;
use App\Models\Lead;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class LeadController extends Controller
{
public function index(Request $request)
{
$query = Lead::with([, ]);
// kullanıcı roluna göre lead’leri filtrele
if ($request->user()->role !== ) {
$query->where(,$request->user()->id);
}
$leads =$query->latest()->paginate(15);
return view(, compact());
}
public function store(StoreLeadRequest $request): RedirectResponse
{
$request->user()->leads()->create($request->validated());
return redirect()->route()
->with(, );
}
public function updateStatus(Request $request, Lead $lead): RedirectResponse
{
Gate::authorize(, $lead);
$request->validate([=> [, new Enum(LeadStatus::class)],
]);
$lead->update([=> $request->status,
=> $request->status === LeadStatus::CONTACTED->value ? now() : $lead->contacted_at,
]);
return back()->with(,);
}
}
5. Otomatik Lead Takibi için Zamanlanmış Görevler
5. Otomatik Lead Takibi için Zamanlanmış Görevler
Bir CRM ortamında, lead’ler, temsilcilerin zamanında geri dönüş yapmaması durumunda hızla soğur. 48 saatten fazla bekleyen, iletişime geçilmemiş lead’ler hakkında temsilcileri bilgilendirmek için otomatik bir komut oluşturalım.
php artisan make:command SendLeadFollowUpAlerts
app/Console/Commands/SendLeadFollowUpAlerts.php
namespace App\Console\Commands;
use App\Enums\LeadStatus;
use App\Models\Lead;
use App\Notifications\LeadFollowUpNotification;
use Illuminate\Console\Command;
class SendLeadFollowUpAlerts extends Command
{
protected $signature = ;
protected $description = ;
public function handle(): void
{
$staleLeads = Lead::where(, LeadStatus::NEW)
->where(, , now()->subHours(48))
->with()
->get();
foreach ($staleLeads as$lead) {
$lead->user->notify(new LeadFollowUpNotification($lead));
}
$this->info({$staleLeads->count()}' stale lead için.');
}
}
Bu görevi Laravel 12 içinde routes/console.php dosyasına planlayın:
use Illuminate\Support\Facades\Schedule;
Schedule::command()->dailyAt();
Özel CRM Oluşturma için Temel Noktalar
- Enum’ları Kullanın: Lead durumları, anlaşma aşamaları ve kullanıcı rolleri arasında tip güvenliğini koruyun.
- Sıkı Yetkilendirme Politikaları: Temsilcilerin yalnızca onlara atanan anlaşmaları görebilmeleri için ince görünürlük kontrolleri uygulayın.
- Görevleri Otomatikleştirin: E-posta takipleri, eski lead bildirimleri ve haftalık boru hatı özetleri için Laravel’in Zamanlayıcı ve Kuyruk sistemlerini kullanın.
Ölçeklenebilir Özel CRM’iniz mi Gerekli?
Kurumsal web platformları oluşturmak, sağlam veri tabanı tasarımı, güvenli rol tabanlı izinler ve ölçeklenebilir sunucu mimarisi gerektirir.
Özel PHP & Laravel geliştirme, kurumsal yazılım mühendisliği, CRM inşası ve büyüme hedeflerinize uygun bulut çözümleri için Software Solutions ile iş birliği yapın.
Ekibinizin CRM iş akışında hangi özellikler önemlidir? Aşağıdaki yorumlarda düşüncelerinizi paylaşın!
Kaynak: Orijinal Makale


