# Scopes et consentement de l'organisation

> Le catalogue fermé des scopes qu'une app peut demander (ressources feuilles, jamais un module entier), la phrase que voit l'administrateur, le compte de service sous lequel l'app agit, et « utiliser l'app ».
> Catégorie : Référence · mis à jour le 2026-09-02 · plateforme v1

## Le principe

Le tableau `permissions` du manifeste liste des **scopes** : un par accès
réel à des données de l'organisation. Un scope s'écrit `ressource:action`
avec une ressource **feuille** (`crm.contacts`, `shop.orders`,
`billing-fr.documents`…) et une action `read` ou `write`.

```json
{ "permissions": ["crm.contacts:read", "crm.activities:write"] }
```

Deux règles, appliquées à la validation du manifeste :

- **Jamais un module entier.** `crm:read` est refusé : par la hiérarchie des
  droits de Capibara, il donnerait tout `crm.*` d'un coup. Le message
  d'erreur nomme les scopes feuilles à demander à la place.
- **Uniquement le catalogue ci-dessous.** Chaque scope accepté ouvre au moins
  une [façade](/dev/docs/facades) ; un scope hors catalogue n'ouvrirait rien,
  il est refusé.

## Le catalogue (généré)

### CRM

| Scope | Ce que l'organisation accepte |
|---|---|
| `crm.contacts:read` | Lire vos contacts (nom, coordonnées, étiquettes, notes) |
| `crm.contacts:write` | Créer et modifier des contacts |
| `crm.companies:read` | Lire vos sociétés |
| `crm.companies:write` | Créer et modifier des sociétés |
| `crm.opportunities:read` | Lire vos opportunités (pipeline, montants) |
| `crm.opportunities:write` | Créer et faire avancer des opportunités |
| `crm.activities:read` | Lire l'historique et les tâches du CRM |
| `crm.activities:write` | Ajouter des notes et des tâches dans le CRM |

### Facturation

| Scope | Ce que l'organisation accepte |
|---|---|
| `billing-fr.documents:read` | Lire vos devis, factures et avoirs (statut, lignes, totaux) |
| `billing-fr.documents:write` | Créer des brouillons de devis et de factures, les émettre et les envoyer |
| `billing-fr.pos:read` | Lire vos encaissements par carte (statut, montant) |
| `billing-fr.pos:write` | Créer des encaissements par carte (montant + libellé) réglés sur votre page de paiement |

### Boutique

| Scope | Ce que l'organisation accepte |
|---|---|
| `shop.products:read` | Lire votre catalogue (produits, déclinaisons, stock vendable) |
| `shop.products:write` | Modifier des produits (nom, description, prix, publication) |
| `shop.orders:read` | Lire vos commandes |
| `shop.orders:write` | Faire avancer vos commandes (expédiée, livrée) et poser un numéro de suivi |

### Projets

| Scope | Ce que l'organisation accepte |
|---|---|
| `projects:read` | Lire vos projets et leurs tâches |
| `projects.tasks:write` | Créer et déplacer des tâches, commenter, enregistrer du temps |

### Planning

| Scope | Ce que l'organisation accepte |
|---|---|
| `planning.resources:read` | Lire vos ressources réservables |
| `planning.bookings:read` | Lire vos réservations |
| `planning.bookings:write` | Créer des réservations (mêmes gardes que la réservation en ligne) |

### Site

| Scope | Ce que l'organisation accepte |
|---|---|
| `site.members:read` | Lire les membres de votre site (nom, e-mail, statut) |

### Formation

| Scope | Ce que l'organisation accepte |
|---|---|
| `formation.catalogue:read` | Lire votre catalogue de formations |
| `formation.sessions:read` | Lire vos sessions inter-entreprises et leurs inscriptions |


## Ce que voit l'administrateur

À l'installation, l'écran de consentement affiche chaque scope **en français**
(la colonne de droite ci-dessus), avec son module et l'identifiant technique
en petit. Les scopes sont **tout ou rien** : l'app s'installe avec l'ensemble
ou pas du tout (patron Discord / Shopify). Une version qui **ajoute** un scope
n'est jamais appliquée automatiquement chez les organisations déjà
installées : l'administrateur voit la liste avec les nouveaux scopes marqués
« nouveau » et ré-accepte — ou reste sur sa version. Tant qu'il n'a pas
ré-accepté, vos handlers ne s'exécutent pas et vos surfaces l'expliquent.

## Le compte de service

À l'installation, Capibara crée dans l'organisation un **compte de service**
`app:<clé>` : un utilisateur technique, masqué des listes, sans connexion
possible, dont l'avatar est l'icône de votre app, et dont l'unique rôle porte
exactement les scopes accordés. **Toute écriture de votre app passe par les
services de la plateforme sous ce compte** — les mêmes que ceux d'un humain :
contrôle des droits, journal d'activité (« App Météo a créé le contact
Dupont »), notifications, événements de domaine. Il n'existe aucune seconde
porte d'écriture.

Deux contextes d'exécution :

- **contexte utilisateur** — pages, panneaux, widgets, actions : les façades
  s'exécutent sous **la personne qui interagit**, bornée par vos scopes (une
  app ne fait jamais plus que l'humain qui clique) ;
- **contexte app** — événements, planifications, HTTP entrant, backend
  externe : les façades s'exécutent sous le **compte de service**.

## « Utiliser l'app »

Chaque app installée génère une ressource `app.<clé>` : `app.<clé>:read`
= ouvrir ses pages, widgets et panneaux. Les rôles par défaut Manager et
Employé la reçoivent à l'installation (l'Administrateur a le wildcard) ; pour
un rôle personnalisé, l'administrateur coche « Utiliser l'app » dans
*Mon organisation › Rôles*. Sans ce droit, l'app n'apparaît ni dans le menu,
ni dans le sélecteur de widgets, ni sur les fiches.

## Revalidés en base, jamais en confiance

À chaque appel de façade, la plateforme vérifie : scope déclaré dans le
manifeste **et** accordé à l'installation **et** porté par l'acteur (compte de
service ou personne) dans les droits de l'organisation. Un scope retiré (app
désinstallée, module désactivé) est refusé immédiatement.

## Bonnes pratiques

- **Un scope par usage réel** — lire les contacts pour un résumé =
  `crm.contacts:read`, pas `crm.contacts:write` « au cas où ».
- **Lecture et écriture sont distinctes** — demandez `write` seulement si
  vous créez ou modifiez.
- **Moins de scopes = review plus rapide et plus d'installations** : une
  longue liste fait hésiter.
- **Expliquez les scopes inhabituels** dans votre fiche : un scope sans
  rapport visible avec l'app est un motif de refus fréquent en review.
