etouch docs
API GraphQL

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.

RoleDescription
SUPER_ADMINAcces complet (technique / plateforme)
ADMINAncien role admin (compatibilite)
PLATFORM_ADMINAdmin de la plateforme
STUDIO_ADMINResponsable studio (creation projets, assignations)
STUDIO_USERCollaborateur studio (operations limitees)
CLIENT_ADMINAdministrateur cote client (validation, commentaires)
CLIENT_USERCollaborateur client
RETOUCH_ADMINResponsable retouche (assignations internes)
RETOUCH_USERRetoucheur 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).

PermissionActionAttribuee a
platform:manageAcces complet plateforme (bypass scopes)SUPER_ADMIN, PLATFORM_ADMIN, ADMIN
organization:manageGestion de l'organisation couranteSTUDIO_ADMIN, ADMIN, PLATFORM_ADMIN
project:createCreation de projetsSTUDIO_ADMIN
project:updateMise a jour des projetsSTUDIO_ADMIN, STUDIO_USER
project:transitionChangement d'etape workflowSTUDIO_ADMIN, CLIENT_ADMIN
project:assignAssignation des membresSTUDIO_ADMIN
asset:uploadUpload de mediasSTUDIO_ADMIN, STUDIO_USER, RETOUCH_ADMIN, RETOUCH_USER
asset:downloadTelechargement des originaux/livrablesSTUDIO_ADMIN, CLIENT_ADMIN, CLIENT_USER
asset:commentCommentaires client/studioSTUDIO_ADMIN, STUDIO_USER, CLIENT_ADMIN, CLIENT_USER
asset:annotateAnnotations retoucheurs/studioSTUDIO_ADMIN, STUDIO_USER, RETOUCH_ADMIN, RETOUCH_USER
retouch:assignAssignation des retouchersSTUDIO_ADMIN, RETOUCH_ADMIN
notification:manageGestion des notificationsSTUDIO_ADMIN, CLIENT_ADMIN, RETOUCH_ADMIN
billing:viewConsultation facturationSTUDIO_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 activeAcces projetsAcces utilisateursSpecificites
STUDIOProjets du studio + clients associes + retoucheurs actifsMembres studio + membres clients rattachesSuppression projet reservee aux STUDIO_ADMIN
CLIENTProjets ou l'org client est expliciteMembres du client uniquementLecture seule pour la plupart des actions
RETOUCHERProjets assignes via projectRetouchVendorMembres de l'org retouche uniquementTableau projets en lecture seule
PLATFORMPas de restriction (via platform:manage)Toute la base utilisateurs/projetsToutes les actions d'admin plateforme

Confidentialite des donnees clients

Les membres d'organisations clientes ne peuvent pas acceder a certaines informations sensibles :

Champ GraphQLValeur pour clientsVisible pour
Project.guidelineFilenullStudios, Retoucheurs, Admins
Project.guidelines[]Studios, Retoucheurs, Admins
Project.retouchVendors[]Studios, Retoucheurs, Admins
ProjectBilling.retoucherUnitPricenullStudios, Retoucheurs, Admins
ProjectBilling.estimatedTotalCostnullStudios, Retoucheurs, Admins
ProjectBilling.estimatedMarginnullStudios, Retoucheurs, Admins
ProjectBilling.estimatedMarginPercentnullStudios, Retoucheurs, Admins
ProjectPricingItem.retoucherUnitPrice0Studios, Retoucheurs, Admins
ProjectPricingItem.totalRetoucherCost0Studios, 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 401
  • apps/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. Lance forbidden() si non autorise.
  • ensureProjectViewerAccess(projectId) (apps/web/lib/project-access-guard.ts) -- Confirme que l'utilisateur est rattache au projet.

Pages protegees

PageGarde
/[locale]/(dashboard)/layoutSession obligatoire
/[locale]/(dashboard)/projectsensureViewerAccess
/[locale]/(dashboard)/projects/[id]ensureProjectViewerAccess
/[locale]/(dashboard)/clientsensureViewerAccess + 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

  1. Declarer dans packages/shared/src/types.ts
  2. Ajouter le mapping dans ROLE_PERMISSIONS
  3. Mettre a jour les gardes (API + Next.js) et la documentation

Ajouter un role

  1. Ajouter dans ROLE_HIERARCHY et ROLE_PERMISSIONS
  2. Mettre a jour les RoleGuard et la navigation (sidebar)