Custom Models
Place your Eloquent models in app/Models/Custom/ to keep them separate from the core SaasKitFy models. This makes upgrades straightforward since you never modify core files.
Namespace
namespace App\Models\Custom;
Org-Scoped Models
Most custom models should be scoped to an organization. Add an organization_id foreign key with cascading deletes:
<?php
namespace App\Models\Custom;
use App\Models\Organization;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
class Project extends Model
{
protected $fillable = [
'organization_id', 'created_by', 'name',
'description', 'status', 'due_date',
];
public function organization(): BelongsTo
{
return $this->belongsTo(Organization::class);
}
public function creator(): BelongsTo
{
return $this->belongsTo(User::class, 'created_by');
}
}
Migration
Create your migration in database/migrations/ with a numbered prefix. Use constrained()->cascadeOnDelete() on the organization foreign key so that deleting an organization cleans up all related records:
// database/migrations/0005_01_01_000000_create_example_module_tables.php
Schema::create('projects', function (Blueprint $table) {
$table->id();
$table->foreignId('organization_id')
->constrained()
->cascadeOnDelete();
$table->foreignId('created_by')
->constrained('users')
->cascadeOnDelete();
$table->string('name');
$table->text('description')->nullable();
$table->string('status')->default('backlog');
$table->timestamp('due_date')->nullable();
$table->timestamps();
$table->index(['organization_id', 'status']);
});
Querying with Org Scope
Always scope queries to the current organization in your controllers:
$org = $request->user()->activeOrganization();
$projects = Project::where('organization_id', $org->id)
->orderByDesc('updated_at')
->get();
Verifying Ownership
When accessing a single record via route model binding, verify it belongs to the current org:
public function show(Request $request, Project $project): JsonResponse
{
$org = $request->user()->activeOrganization();
abort_if($project->organization_id !== $org->id, 403);
return response()->json($project);
}