Companies
Reshape is multi-tenant: a Company is a workspace that users belong to, switch between, and act within. Tenancy is powered by spatie/laravel-multitenancy using a single shared database — every tenant's data lives in the same tables, scoped by company_id, rather than separate databases or schemas.

The current tenant
Company implements Spatie's IsTenant contract. A middleware resolves "the current company" from the authenticated user on every request and calls Company::makeCurrent(), so tenant-aware queues dispatch jobs in that company's context automatically (config/multitenancy.php). This is also what scopes authorization checks — $user->in($company)->hasPermissionTo(...) uses exactly this "current company" concept.
A user isn't required to belong to a company at all — User::tenant falls back to the user themselves, so personal accounts work the same way individual features do.
Actions
// Create a company, make it current, assign the creator as CompanyOwner...
App\Actions\CreateCompany::create(User $user, array $input) : App\Models\Company
// Update a company's name and information record...
App\Actions\UpdateCompany::update(User $user, Company $company, array $input) : void
// Purge a company (detach members, soft-delete)...
App\Actions\DeleteCompany::delete(Company $company) : voidCompany Object
// Access the company's owner...
$company->owner : App\Models\User
// Get every user belonging to the company, via the Membership pivot...
$company->users() : Illuminate\Database\Eloquent\Relations\BelongsToMany
// Detach every member, then soft-delete the company...
$company->purge() : voidTrait Methods (HasCompanies)
// Access a user's currently selected company, or null...
$user->currentCompany : App\Models\Company|null
// The companies a user owns, and the companies they're a member of...
$user->ownedCompanies() : Illuminate\Database\Eloquent\Relations\HasMany
$user->companies() : Illuminate\Database\Eloquent\Relations\BelongsToMany
// Switch the user's current company, if they belong to it...
$user->switchCompany(Company $company) : bool
// Determine if a given company is the user's current one...
$user->isCurrentCompany(Company|int|null $company) : bool
// Determine if a user owns a given company...
$user->ownsCompany(?Company $company) : bool
// Determine if a user belongs to (owns or is a member of) a company...
$user->belongsToCompany(Company|int|null $company) : boolThe frontend's sidebar company-switcher.vue component lists every company a user belongs to and switches on selection, clearing back to a personal context when no company is chosen.
Members
A company's members are tracked through a Membership pivot (company.users()), separate from ownership (company.owner(), via user_id). Adding a member both syncs the pivot and assigns roles scoped to that company in one transaction, then fires CompanyMemberAdded — which triggers a real-time notification to the new member.
Actions
// Add an existing user to a company and assign roles, firing CompanyMemberAdded...
App\Actions\AddCompanyMember::add(User $user, Company $company, string $email, Collection $roles) : App\Models\User
// Change a member's company-scoped roles...
App\Actions\UpdateCompanyMember::update(User $user, Company $company, User $member, array $roles) : void
// Remove a member (refuses to remove the company's creator)...
App\Actions\RemoveCompanyMember::remove(User $user, Company $company, User $companyMember) : voidInvitations
Inviting someone who doesn't have an account yet (or hasn't joined the company) sends an email with a signed acceptance link, carrying the roles they'll be granted on acceptance. The acceptance link is signed and unauthenticated (so it works from a cold email click) — accepting delegates to the same member-adding logic used for direct member creation, then redirects back into the app.
Action
// Create a pending invitation, attach roles, and email the invite...
App\Actions\InviteCompanyMember::invite(User $user, Company $company, string $email, array $roles) : voidCompany profile
Company carries a CompanyInformation relation (legal name, structure type, registration details), plus logo and banner media collections via HasMedia. It also implements CommentableInterface, so comments can attach directly to a company. Companies own contacts, addresses, customers, and announcements the same way users do, through the shared Has* traits.