Repository navigation
[Core]: Company Switcher #138
Copy link
Copy link
Closed
Labels
high-priorefinedRefined with SMART plan / test suggestionsRefined with SMART plan / test suggestions
Milestone
Description
Users managing multiple companies need to switch contexts quickly, similar to Slack/Discord workspace switching.
Specific
As a user, I want to switch between companies without logging out.
- Show company name top right corner.
- Click on Company name.
- Maybe show modal with all companies user belongs to
- Maybe edit button next to each company
- Clicking on Company switches to that company
Also:
- company slug shows in address bar
- Typing in other slug switches to that company if the user belongs to it
AAA Scenarios
Scenario 1 — Basic UI Switch (top-right button)
Arrange
- User is authenticated and belongs to companies A and B.
- Current company context = A.
- User has at least one resource visible (e.g., invoices) scoped to company A.
Act
- User clicks the company name in the top-right corner and selects company B.
Assert
- The UI reflects company B (top-right label updates).
- All visible data updates to company B’s scoped data.
- No data from company A is visible after switch.
- User remains authenticated and session persists.
Scenario 2 — Modal Company Picker (many companies)
Arrange
- User belongs to 10 companies.
- Company switcher shows a modal with the list.
- User has permissions on a subset of companies.
Act
- User opens the modal, selects a company the user has access to, and confirms.
Assert
- The modal closes and the UI shows the chosen company.
- The list respects user permissions (edit buttons shown only where allowed).
- Data is fully scoped to the selected company.
- No slow full-page reload is needed unless necessary; context change is seamless.
Scenario 3 — Edit / Quick-actions from Picker
Arrange
- User has "manage company" permission for company C.
- Picker shows an edit button next to company C.
Act
- User clicks the edit button in the picker for company C.
Assert
- The edit action opens the company settings for company C (modal or page).
- User can save changes and see them applied to current context if company C is active.
- Authorization is enforced; edit button not shown where user lacks permission.
Scenario 4 — URL Slug Switch (direct navigation)
Arrange
- Route format includes company slug:
/companies/{slug}/invoices. - User is authenticated and belongs to company D.
- Browser address bar currently shows
/companies/company-x/invoices.
Act
- User types
/companies/company-d/invoicesinto the address bar and navigates.
Assert
- If user belongs to company D: the app switches context to company D and shows scoped data.
- The top-right company label updates to company D.
- No cross-tenant data leaks; user sees only company D data.
- If user does not belong to company D: the app shows an access error (403) or redirects to an allowed company.
Scenario 5 — Attempted Unauthorized Slug Switch
Arrange
- User belongs to companies E and F only.
- The user attempts to access
/companies/company-g/...(company G not in their list).
Act
- User navigates to the URL with company G’s slug.
Assert
- The system denies access (403 or redirect to a safe default).
- No company G data is exposed.
- The user is shown a clear message and a link to accessible companies.
Scenario 6 — Persistence Across Tabs & Reloads
Arrange
- User switches to company H in tab A.
- User opens tab B previously at a different company context.
Act
- User reloads tab B after switching in tab A.
Assert
- Tab B either respects a global session-level company context (if designed) or indicates the currently active company and offers to sync.
- No inconsistent data appears; choice of persistence strategy is consistent and documented.
Scenario 7 — Permissions & Feature-Gating After Switch
Arrange
- User has role changes between companies (e.g., admin in I, viewer in J).
- Both companies have resources with different accessible features.
Act
- User switches from company I to company J.
Assert
- Feature availability updates to reflect new company role (edit buttons hidden where viewer).
- Actions failing due to permissions return appropriate errors and are not shown where unauthorized.
- Logs record the switch event for audit.
Scenario 8 — Edge Case: Pending Background Syncs / Long-running Jobs
Arrange
- User triggers a long-running sync job in company K (background).
- User attempts to switch to company L during the job.
Act
- User switches context while background job for company K is still running.
Assert
- Background job continues and is scoped to company K (no cross-tenant effect).
- User sees the correct status for company L and is not blocked by K’s job.
- Operations remain isolated per tenant.
Notes (non-assertions)
- Ensure server-side authorization is the source-of-truth for all switches (client UI should not be the only guard).
- Log company switch events (user, from → to, timestamp) for audits.
- Consider UX for “default company” and initial onboarding choice.
- Decide and document session vs per-tab persistence strategy and implement consistent behavior.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
high-priorefinedRefined with SMART plan / test suggestionsRefined with SMART plan / test suggestions
Activity
refactor(#138): open company switcher in a Filament modal
nielsdrost7 commentedon Jun 14, 2026
Sprint 5 — Implementation Plan
What already works (no code needed):
ConfigureTenant+SetTenantFromQueryStringmiddleware already handles/ivplv2/dashboard→/other-co/dashboardnavigation. Typing a different slug switches tenant.EnsureUserCanAccessCompanyenforces access.What needs to be built — the UI switcher:
Filament v4 supports a custom tenant menu. Configure in
CompanyPanelProvider:For a proper modal-based switcher:
1. Create a Livewire component:
Modules/Core/Filament/Company/Components/CompanySwitcher.php2. Register it as a navigation widget or render it in the panel header.
Scope for Sprint 5 (MVP):
$user->companies()with a Switch button per rowDefer to later:
Tests: Cover Scenario 1, 4, and 5 from the issue body.
Effort: ~5 hours for MVP switcher.
Generated by Claude Code
feat(core): company switcher (InvoicePlane#138)
nielsdrost7 commentedon Jul 24, 2026
SMART Plan — [Core] Company Switcher
Specific
Implement a company context switcher in the Filament company panel UI allowing users to switch between companies they belong to without logging out. The switcher should:
Measurable
/ivplv2/dashboard→/other-code/dashboard).Achievable
Filament::getTenant().Modules/Core/Filament/Company/Components/CompanySwitcher:auth()->user()->companies().Gate::authorize('access', $company)(use existingEnsureUserCanAccessCompany::classmiddleware pattern).Filament::setTenant($company).session(['current_company_id' => $company->id]).route('filament.company.pages.dashboard', ['tenant' => Str::lower($company->search_code)]).AuditLog::create([...]).Relevant
Multi-tenant users waste significant time logging out/in to switch contexts. A seamless switcher keeps users in the app and dramatically improves workflow for agencies, accountants, and multi-company management scenarios.
Time-bound
Sprint 5.
Acceptance Criteria
nielsdrost7 commentedon Jul 24, 2026
Correction: an unmerged local branch,
feature/138-company-switcher(25 commits ahead of develop, no open PR yet), already implements a company switcher — includingresources/views/filament/pages/switch-company-modal.blade.phpandswitch-company.blade.php, matching this plan's proposed design. The SMART Plan comment above was posted in error by an automated grooming pass that didn't check this branch (its numeric-ID check should have caughtfeature/138-company-switcherbut didn't). The earlier "Sprint 5 — Implementation Plan" comment on this issue already reflects that branch's actual design. Please check that branch before implementing from scratch — it likely just needs finishing/rebasing and a PR opened.nielsdrost7 commentedon Jul 24, 2026
Already implemented —
Modules/Core/Filament/Company/Pages/MyCompanies.php(live ondevelop) covers company-switching: lists every company the user belongs to, disables the switch action for the currently active one, setssession('current_company_id')and callsFilament::setTenant()on switch. Two prior attempts at this (#583, #474) were closed as superseded by this — neither ever closed this issue since neither merged.feature/138-company-switcheris stale/redundant against this and shouldn't be pursued further.