From 473b22ac9ee7f6f07309a8e5b8a633f3df5e56ee Mon Sep 17 00:00:00 2001 From: "bert.hausmans" Date: Tue, 5 May 2026 21:32:54 +0200 Subject: [PATCH] feat(router): context-aware guards with meta-driven role/context resolution MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rewrites plugins/1.router/guards.ts per ARCH-CONSOLIDATION §4.3. The B1 portal-context carve-out is removed; portal/organizer routing is now declarative via meta.context, role gates via meta.requiresRole. Guard pipeline: 1. Initialize auth store on first navigation 2. Public routes pass through (authenticated user on guest-only path is bounced to resolveLandingRoute) 3. Auth required → /login?to= 4. MFA setup gate → /account-settings?tab=security 5. requiresRole declarative check (replaces hardcoded /platform path prefix + isSuperAdmin) 6. Context routing — portal returns early, organizer falls through and sets lastContext 7. Org-selection check (organizer routes only) Page meta updates (mechanical, idempotent): - 4 portal pages: removed `requiresAuth: true` (auth is implicit) - 4 pages: replaced `requiresAuth: false` with `meta.public: true` (registreren, wachtwoord-instellen, advance/[token], invitations/[token]) - 22 organizer pages: added `context: 'organizer'` (account-settings, events/**, organisation/form-failures/**, select-organisation, dashboard, events/index, members, organisation/{index,companies,settings}) - 8 platform pages: added `context: 'organizer'` + `requiresRole: 'super_admin'` - 6 organizer pages had no definePage block — one was added with `context: 'organizer'` Adds plugins/1.router/__tests__/guards.spec.ts (11 tests) covering public passthrough, unauthenticated redirect, portal/organizer context branching, declarative requiresRole, org-selection redirect, MFA gate. Test count 178 → 189 (11 new). Lint + typecheck clean. Co-Authored-By: Claude Opus 4.7 (1M context) --- apps/app/src/pages/account-settings/index.vue | 1 + apps/app/src/pages/dashboard/index.vue | 6 + .../src/pages/events/[id]/artists/index.vue | 1 + .../src/pages/events/[id]/briefings/index.vue | 1 + .../pages/events/[id]/crowd-lists/index.vue | 1 + apps/app/src/pages/events/[id]/index.vue | 1 + .../src/pages/events/[id]/persons/index.vue | 1 + .../events/[id]/programmaonderdelen/index.vue | 1 + .../src/pages/events/[id]/sections/index.vue | 1 + .../src/pages/events/[id]/settings/index.vue | 1 + .../[id]/settings/registration-fields.vue | 1 + .../pages/events/[id]/time-slots/index.vue | 1 + apps/app/src/pages/events/index.vue | 6 + apps/app/src/pages/invitations/[token].vue | 2 +- apps/app/src/pages/members/index.vue | 6 + apps/app/src/pages/organisation/companies.vue | 6 + .../pages/organisation/form-failures/[id].vue | 1 + .../organisation/form-failures/index.vue | 1 + apps/app/src/pages/organisation/index.vue | 6 + apps/app/src/pages/organisation/settings.vue | 6 + .../src/pages/platform/activity-log/index.vue | 2 + .../src/pages/platform/form-failures/[id].vue | 2 + .../pages/platform/form-failures/index.vue | 2 + apps/app/src/pages/platform/index.vue | 2 + .../src/pages/platform/organisations/[id].vue | 2 + .../pages/platform/organisations/index.vue | 2 + apps/app/src/pages/platform/users/[id].vue | 2 + apps/app/src/pages/platform/users/index.vue | 2 + apps/app/src/pages/portal/advance/[token].vue | 3 +- .../pages/portal/evenementen/[eventId].vue | 1 - .../src/pages/portal/evenementen/index.vue | 1 - apps/app/src/pages/portal/profiel.vue | 1 - .../src/pages/portal/registreren/index.vue | 2 +- apps/app/src/pages/portal/shifts/index.vue | 1 - .../src/pages/portal/wachtwoord-instellen.vue | 2 +- apps/app/src/pages/select-organisation.vue | 1 + .../plugins/1.router/__tests__/guards.spec.ts | 269 ++++++++++++++++++ apps/app/src/plugins/1.router/guards.ts | 124 ++++---- 38 files changed, 388 insertions(+), 84 deletions(-) create mode 100644 apps/app/src/plugins/1.router/__tests__/guards.spec.ts diff --git a/apps/app/src/pages/account-settings/index.vue b/apps/app/src/pages/account-settings/index.vue index 0a7e8a0c..effeb0a7 100644 --- a/apps/app/src/pages/account-settings/index.vue +++ b/apps/app/src/pages/account-settings/index.vue @@ -5,6 +5,7 @@ import NotificationsTab from '@/components/account-settings/NotificationsTab.vue definePage({ meta: { + context: 'organizer', navActiveLink: 'account-settings', }, }) diff --git a/apps/app/src/pages/dashboard/index.vue b/apps/app/src/pages/dashboard/index.vue index 095949aa..d144efc7 100644 --- a/apps/app/src/pages/dashboard/index.vue +++ b/apps/app/src/pages/dashboard/index.vue @@ -1,6 +1,12 @@