feat(auth): add contexts + platform.is_super_admin to /auth/me, factory role-category states

Additive enrichment to MeResource — existing fields untouched, MeTest stays green.
New fields:
- contexts.available: list<'portal'|'organizer'> derived from Person + Organisation memberships
- contexts.default: precedence super_admin > organizer > portal > fallback portal
- platform.is_super_admin: bool promoted from app_roles
- organisations[].roles: 1-element array form alongside the legacy scalar role,
  forward-compatible for the multi-role pivot work tracked in TECH-PIVOT-ROLES-MULTI

UserFactory gains volunteer(), orgAdmin(), volunteerAndOrganizer(), superAdmin()
state methods — codified role categories for reuse across future workstreams.

Adds forbidden.vue placeholder (PublicLayout) for the context-failure landing in
the upcoming guard rewrite.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-05 21:15:10 +02:00
parent b5a2140517
commit a2760ffd64
6 changed files with 272 additions and 19 deletions

View File

@@ -0,0 +1,23 @@
<script setup lang="ts">
definePage({
name: 'forbidden',
meta: { layout: 'PublicLayout', public: true },
})
</script>
<template>
<div class="d-flex flex-column align-center justify-center pa-12">
<h1 class="text-h3 mb-4">
Geen toegang
</h1>
<p class="text-body-1 mb-6">
Je hebt geen toegang tot deze pagina.
</p>
<VBtn
:to="{ name: 'login' }"
color="primary"
>
Naar inloggen
</VBtn>
</div>
</template>

View File

@@ -33,6 +33,7 @@ declare module 'vue-router/auto-routes' {
'events-id-settings': RouteRecordInfo<'events-id-settings', '/events/:id/settings', { id: ParamValue<true> }, { id: ParamValue<false> }>,
'events-id-settings-registration-fields': RouteRecordInfo<'events-id-settings-registration-fields', '/events/:id/settings/registration-fields', { id: ParamValue<true> }, { id: ParamValue<false> }>,
'events-id-time-slots': RouteRecordInfo<'events-id-time-slots', '/events/:id/time-slots', { id: ParamValue<true> }, { id: ParamValue<false> }>,
'forbidden': RouteRecordInfo<'forbidden', '/forbidden', Record<never, never>, Record<never, never>>,
'forgot-password': RouteRecordInfo<'forgot-password', '/forgot-password', Record<never, never>, Record<never, never>>,
'invitations-token': RouteRecordInfo<'invitations-token', '/invitations/:token', { token: ParamValue<true> }, { token: ParamValue<false> }>,
'login': RouteRecordInfo<'login', '/login', Record<never, never>, Record<never, never>>,