feat(layout): context-switcher for multi-role users

Adds components/shared/ContextSwitcher.vue — a Vuetify menu-button
that renders only when useAuthStore.showContextSwitcher is true (i.e.
the user has both portal and organizer contexts available). Click
calls useAuthStore.setLastContext + resolveLandingRoute and pushes
the new route.

Wired into both layouts:
- PortalLayout.vue: navbar right section, before UserAvatarMenu
- DefaultLayoutWithVerticalNav.vue (organizer navbar host): before
  NavbarThemeSwitcher (OrganizerLayout.vue itself is a 10-line
  wrapper around DefaultLayoutWithVerticalNav, so the component
  wires into the actual navbar host).

Boundaries matrix update: components-shared now allows `stores` so
canonical shared chrome (ContextSwitcher, future global indicators)
can read useAuthStore directly without re-homing to
components/layout/. stores-portal stays disallowed for components-
shared by design — portal-specific state has no place in shared
chrome.

Adds 3 vitest specs covering: visibility gated by
showContextSwitcher, click invokes setLastContext + router.push.

Test count 189 → 192. Frontend lint + typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 21:35:32 +02:00
parent 473b22ac9e
commit 209e0ef682
5 changed files with 137 additions and 2 deletions

View File

@@ -238,7 +238,13 @@ module.exports = {
// previously owned the cross-zone call (WS-3 PR-B2a).
{ from: 'stores', allow: ['types', 'utils', 'lib', 'composables', 'composables-forms', 'stores', 'stores-portal'] },
{ from: 'navigation', allow: ['types', 'utils', 'navigation'] },
{ from: 'components-shared', allow: ['types', 'utils', 'lib', 'composables', 'composables-forms', 'components-shared'] },
// components-shared may read app-wide stores (useAuthStore,
// useNotificationStore — not stores-portal) so canonical shared
// chrome (ContextSwitcher, future global indicators) can stay in
// components/shared/ without re-homing to components/layout/.
// Portal-specific state stays out of shared by design (WS-3 PR-B2a).
{ from: 'components-shared', allow: ['types', 'utils', 'lib', 'composables', 'composables-forms', 'stores', 'components-shared'] },
{ from: 'components-portal', allow: ['types', 'utils', 'lib', 'composables', 'composables-forms', 'stores', 'stores-portal', 'components-shared', 'components-portal'] },
{ from: 'components-organizer', allow: ['types', 'utils', 'lib', 'composables', 'composables-forms', 'stores', 'components-shared', 'components-organizer'] },
{ from: 'components', allow: ['types', 'utils', 'lib', 'composables', 'composables-forms', 'stores', 'components', 'components-shared', 'components-organizer'] },