feat(permissions) : add role-based UI guards and readonly mode for viewers

- Add usePermissions composable (isAdmin, canEdit, canView)
- Password-protected profile login with modal on profiles page
- Disable all form fields for ROLE_VIEWER across edit/create pages
- Show navigation buttons (Modifier/Consulter) for all roles, hide delete for viewers
- Add readonly prop to ModelTypeForm for category pages
- Disable modal fields (sites, constructeurs) for viewers
- Guard /admin routes in middleware

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Matthieu
2026-02-26 13:36:42 +01:00
parent 6bed715b7f
commit cc70fe2b29
46 changed files with 946 additions and 423 deletions

View File

@@ -1,8 +1,7 @@
import { useProfileSession } from "#imports";
import { useProfileSession, usePermissions } from "#imports";
export default defineNuxtRouteMiddleware(async (to) => {
const { ensureSession, fetchCurrentProfile, activeProfile } =
useProfileSession();
const { ensureSession, activeProfile } = useProfileSession();
await ensureSession();
const rawPath = to?.path ?? "";
@@ -14,11 +13,21 @@ export default defineNuxtRouteMiddleware(async (to) => {
fullPath.startsWith("/profiles") ||
routeName.startsWith("profiles");
if (process.client && !activeProfile.value) {
await fetchCurrentProfile();
}
if (process.client && !activeProfile.value && !isProfilesRoute) {
// Redirect to login if no active profile
if (!activeProfile.value && !isProfilesRoute) {
return navigateTo("/profiles");
}
// Permission checks
if (activeProfile.value) {
const { isAdmin } = usePermissions();
// Admin-only routes
if (normalizedPath.startsWith("/admin")) {
if (!isAdmin.value) {
return navigateTo("/");
}
}
}
});