Architecting Teams and Invitations in a Laravel SaaS

Overview

Implementing team management is a foundational requirement for modern B2B SaaS applications. This technique allows users to group under a shared organization, share data, and manage administrative permissions. While

previously provided these features out-of-the-box, modern starter kits favor a custom approach. Building your own team logic ensures you can tailor billing and data isolation—the core pillars of multi-tenancy—to your specific business model without unnecessary bloat.

Architecting Teams and Invitations in a Laravel SaaS
Building Laravel Saas: Part 3/5 - Teams and User Invitations

Prerequisites

To follow this implementation, you should be comfortable with

and the
Laravel
framework. Familiarity with database migrations, Eloquent relationships, and
Livewire
components is essential. You should also understand how
Fortify
handles authentication actions.

Key Libraries & Tools

  • Fortify
    : Handles headless authentication and registration logic.
  • Livewire
    : A full-stack framework for building dynamic interfaces like the invitation form.
  • Flux UI
    : A component library used for accessible and consistent UI elements.
  • Mailtrap
    : An email testing tool for verifying invitation delivery.

Code Walkthrough

Database Schema

First, we define the organizations table and an invitations table to track pending members. We also add an organization_id to the users table.

Schema::create('organizations', function (Blueprint $table) {
    $table->id();
    $table->string('name');
    $table->timestamps();
});

Schema::create('invitations', function (Blueprint $table) {
    $table->id();
    $table->foreignId('organization_id')->constrained();
    $table->string('email');
    $table->string('token')->unique();
    $table->string('role');
    $table->timestamps();
});

Automatic Organization Creation

When a user registers via

, we automatically create a default organization using their name. This ensures every user starts with a team context immediately.

public function create(array $input): User
{
    return DB::transaction(function () use ($input) {
        $org = Organization::create(['name' => $input['name'] . "'s Team"]);
        return User::create([
            'name' => $input['name'],
            'email' => $input['email'],
            'password' => Hash::make($input['password']),
            'organization_id' => $org->id,
            'is_admin' => true,
        ]);
    });
}

Invitation Logic

The invitation model uses the token as the route key for secure, obscure URLs. When a recipient clicks the link, they are directed to a specialized registration form that binds them to the existing organization.

Syntax Notes

We utilize

to manage roles like Admin and Collaborator. This prevents "magic strings" from littering the codebase. Additionally, using Eloquent’s getRouteKeyName() method on the Invitation model allows Laravel to automatically resolve the invitation by its token in the URL rather than a predictable integer ID.

Tips & Gotchas

Do not treat invitations as users. A common mistake is creating a user record with a null password for invited guests; instead, keep them in a separate invitations table until they successfully complete the signup. Also, always use database transactions when creating an organization and a user simultaneously to prevent orphaned records if part of the process fails.

3 min read