fix(portal): race-safe owner-seat initialization (firstOrCreate + catch)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>feat/portal-design
parent
3bf0dfb548
commit
01383e7e5e
|
|
@ -4,6 +4,7 @@ namespace App\Livewire;
|
||||||
|
|
||||||
use App\Models\Customer;
|
use App\Models\Customer;
|
||||||
use App\Models\Seat;
|
use App\Models\Seat;
|
||||||
|
use Illuminate\Database\UniqueConstraintViolationException;
|
||||||
use Illuminate\Support\Facades\DB;
|
use Illuminate\Support\Facades\DB;
|
||||||
use Livewire\Attributes\Layout;
|
use Livewire\Attributes\Layout;
|
||||||
use Livewire\Attributes\Validate;
|
use Livewire\Attributes\Validate;
|
||||||
|
|
@ -23,16 +24,19 @@ class Users extends Component
|
||||||
|
|
||||||
public function mount(): void
|
public function mount(): void
|
||||||
{
|
{
|
||||||
// Every customer starts with themselves as the owner seat.
|
// Every customer starts with themselves as the owner seat. firstOrCreate
|
||||||
|
// keyed on (customer_id, email) is idempotent; the catch covers the
|
||||||
|
// concurrent-first-visit race against the unique index.
|
||||||
$customer = $this->customer();
|
$customer = $this->customer();
|
||||||
if ($customer !== null && $customer->seats()->count() === 0) {
|
if ($customer !== null && $customer->seats()->count() === 0) {
|
||||||
$customer->seats()->create([
|
try {
|
||||||
'email' => $customer->email,
|
$customer->seats()->firstOrCreate(
|
||||||
'name' => $customer->name,
|
['email' => $customer->email],
|
||||||
'role' => 'owner',
|
['name' => $customer->name, 'role' => 'owner', 'status' => 'active', 'invited_at' => now()],
|
||||||
'status' => 'active',
|
);
|
||||||
'invited_at' => now(),
|
} catch (UniqueConstraintViolationException) {
|
||||||
]);
|
// Another concurrent first visit created it — fine.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue