Authentification et Permissions
Systeme d'authentification Better Auth, roles RBAC et regles d'acces dans etouch
etouch utilise Better Auth pour l'authentification et un systeme RBAC (Role-Based Access Control) pour les autorisations.
Roles
Les roles sont stockes dans la table user_organization. La logique metier est dans packages/shared/src/auth.
| Role | Description |
|---|---|
SUPER_ADMIN | Acces complet (technique / plateforme) |
ADMIN | Ancien role admin (compatibilite) |
PLATFORM_ADMIN | Admin de la plateforme |
STUDIO_ADMIN | Responsable studio (creation projets, assignations) |
STUDIO_USER | Collaborateur studio (operations limitees) |
CLIENT_ADMIN | Administrateur cote client (validation, commentaires) |
CLIENT_USER | Collaborateur client |
RETOUCH_ADMIN | Responsable retouche (assignations internes) |
RETOUCH_USER | Retoucheur operant sur les livrables |
SUPER_ADMIN herite de toutes les permissions existantes (via flattenPermissions).
Permissions
Chaque role correspond a un ensemble de permissions defini dans ROLE_PERMISSIONS (packages/shared/src/auth/roles.ts).
| Permission | Action | Attribuee a |
|---|---|---|
platform:manage | Acces complet plateforme (bypass scopes) | SUPER_ADMIN, PLATFORM_ADMIN, ADMIN |
organization:manage | Gestion de l'organisation courante | STUDIO_ADMIN, ADMIN, PLATFORM_ADMIN |
project:create | Creation de projets | STUDIO_ADMIN |
project:update | Mise a jour des projets | STUDIO_ADMIN, STUDIO_USER |
project:transition | Changement d'etape workflow | STUDIO_ADMIN, CLIENT_ADMIN |
project:assign | Assignation des membres | STUDIO_ADMIN |
asset:upload | Upload de medias | STUDIO_ADMIN, STUDIO_USER, RETOUCH_ADMIN, RETOUCH_USER |
asset:download | Telechargement des originaux/livrables | STUDIO_ADMIN, CLIENT_ADMIN, CLIENT_USER |
asset:comment | Commentaires client/studio | STUDIO_ADMIN, STUDIO_USER, CLIENT_ADMIN, CLIENT_USER |
asset:annotate | Annotations retoucheurs/studio | STUDIO_ADMIN, STUDIO_USER, RETOUCH_ADMIN, RETOUCH_USER |
retouch:assign | Assignation des retouchers | STUDIO_ADMIN, RETOUCH_ADMIN |
notification:manage | Gestion des notifications | STUDIO_ADMIN, CLIENT_ADMIN, RETOUCH_ADMIN |
billing:view | Consultation facturation | STUDIO_ADMIN, ADMIN, PLATFORM_ADMIN |
Il n'y a pas de project:delete : la suppression est basee directement sur le role (STUDIO_ADMIN ou SUPER_ADMIN).
Scopes par type d'organisation
Quand un utilisateur change d'organisation active, les donnees filtrees cote API se limitent au scope correspondant.
| Type org active | Acces projets | Acces utilisateurs | Specificites |
|---|---|---|---|
STUDIO | Projets du studio + clients associes + retoucheurs actifs | Membres studio + membres clients rattaches | Suppression projet reservee aux STUDIO_ADMIN |
CLIENT | Projets ou l'org client est explicite | Membres du client uniquement | Lecture seule pour la plupart des actions |
RETOUCHER | Projets assignes via projectRetouchVendor | Membres de l'org retouche uniquement | Tableau projets en lecture seule |
PLATFORM | Pas de restriction (via platform:manage) | Toute la base utilisateurs/projets | Toutes les actions d'admin plateforme |
Confidentialite des donnees clients
Les membres d'organisations clientes ne peuvent pas acceder a certaines informations sensibles :
| Champ GraphQL | Valeur pour clients | Visible pour |
|---|---|---|
Project.guidelineFile | null | Studios, Retoucheurs, Admins |
Project.guidelines | [] | Studios, Retoucheurs, Admins |
Project.retouchVendors | [] | Studios, Retoucheurs, Admins |
ProjectBilling.retoucherUnitPrice | null | Studios, Retoucheurs, Admins |
ProjectBilling.estimatedTotalCost | null | Studios, Retoucheurs, Admins |
ProjectBilling.estimatedMargin | null | Studios, Retoucheurs, Admins |
ProjectBilling.estimatedMarginPercent | null | Studios, Retoucheurs, Admins |
ProjectPricingItem.retoucherUnitPrice | 0 | Studios, Retoucheurs, Admins |
ProjectPricingItem.totalRetoucherCost | 0 | Studios, Retoucheurs, Admins |
La detection est effectuee via isViewerClientOnly() dans les resolvers GraphQL.
Gardes cote serveur (Next.js)
Auth Interrupts
Next.js 15 experimental.authInterrupts declenche des pages 401/403 sans redirection :
apps/web/app/[locale]/unauthorized.tsx-- ecran 401apps/web/app/[locale]/forbidden.tsx-- ecran 403
Fonctions utilitaires
ensureViewerAccess(options)(apps/web/lib/viewer-access-guard.ts) -- Verifie la session, compare roles/permissions/organisation active. Lanceforbidden()si non autorise.ensureProjectViewerAccess(projectId)(apps/web/lib/project-access-guard.ts) -- Confirme que l'utilisateur est rattache au projet.
Pages protegees
| Page | Garde |
|---|---|
/[locale]/(dashboard)/layout | Session obligatoire |
/[locale]/(dashboard)/projects | ensureViewerAccess |
/[locale]/(dashboard)/projects/[id] | ensureProjectViewerAccess |
/[locale]/(dashboard)/clients | ensureViewerAccess + RoleGuard |
/[locale]/(dashboard)/clients/[id] | Studio admin uniquement |
/[locale]/(dashboard)/retouchers/[id] | Studio + retoucher parent |
/[locale]/(dashboard)/studio/[id] | Plateforme uniquement |
Verification des permissions dans le code
API (resolvers)
import { can } from '@etouch/shared/auth/permissions';
// Dans un resolver
if (!can(ctx.viewer, 'project:create', { organizationId })) {
throw new GraphQLError('Forbidden', {
extensions: { http: { status: 403 } },
});
}Frontend (React)
import { useViewerQuery } from '@/hooks/use-viewer-query';
// Conditionner l'affichage
const { data: viewer } = useViewerQuery();
const canCreate = viewer?.permissions.includes('project:create');Ajouter une permission
- Declarer dans
packages/shared/src/types.ts - Ajouter le mapping dans
ROLE_PERMISSIONS - Mettre a jour les gardes (API + Next.js) et la documentation
Ajouter un role
- Ajouter dans
ROLE_HIERARCHYetROLE_PERMISSIONS - Mettre a jour les
RoleGuardet la navigation (sidebar)