> ## Documentation Index
> Fetch the complete documentation index at: https://docs.oximail.ch/llms.txt
> Use this file to discover all available pages before exploring further.

# Multi-tenant & provisionnement

> Les organisations (tenants), l'isolation dans la couche de stockage, les rôles et quotas de comptes, les comptes d'équipe partagés et leurs gardiens, les mots de passe d'application et les réglages de politique par organisation.

Un seul serveur OxiMail peut héberger plusieurs **organisations** (des *tenants* au sens du stockage). L'isolation n'est pas une vérification de permission ajoutée par-dessus : elle est construite dans la couche de stockage. `tenant_id` est un paramètre obligatoire de chaque méthode du store et chaque requête SQL filtre dessus (ADR-015). Un handler ne peut physiquement pas lire les données d'une autre organisation, même à travers un bug. Le RBAC vient par-dessus, en défense en profondeur, pas comme seule ligne.

Une installation mono-organisation n'est que le cas dégénéré : l'assistant provisionne un tenant nommé `default` et tout ce qui suit s'applique quand même.

## Les organisations

```bash theme={null}
oximail tenant create --tenant-id acme --name "ACME SA" ...
oximail tenant update --default-timezone Europe/Zurich
oximail tenant list
```

L'état par organisation comprend ses comptes, ses domaines, ses quotas, ses clés de chiffrement (la hiérarchie de clés au repos est par organisation, voir [chiffrement au repos](./encryption-at-rest)), ses [surcharges de configuration à l'exécution](./configuration), et des réglages de politique comme :

* **Le fuseau horaire par défaut** : le dernier étage de la chaîne de repli du calendrier ([travail collaboratif](./groupware)).
* **La persistance hors ligne côté client** : l'organisation autorise ou non les applications clientes à persister des données localement pour le hors-ligne (`offlinePersistenceAllowed`, réglable par la surface d'administration `Tenant/set`). Une organisation aux règles strictes de résidence des données peut la couper.
* **Les règles de journalisation et la durée du tampon de réversibilité d'effacement** : voir [conformité](./compliance).

## Comptes et rôles

```bash theme={null}
oximail account create --email jane@acme.tld --password ... --role member --tenant acme
oximail account set-role --account jane@acme.tld --role admin
oximail account disable|enable|delete ...
oximail account quota --account jane@acme.tld --mb 10240
```

Les rôles sont `admin`, `member`, `restricted`, `readonly`, `disabled` (ADR-028). Un compte **désactivé** garde ses données mais perd son agence : pas de connexion, pas de soumission SMTP (`550`), pas de réponses d'absence ; le courrier continue de lui être remis. La suppression est la [machine à phases d'effacement](./compliance), pas un simple delete.

Les quotas de stockage par compte se fixent en Mo (`0` retire la limite par compte).

### Mots de passe d'application

Les clients qui ne peuvent pas suivre le flux de connexion web (clients IMAP, agents DAV) s'authentifient avec des **mots de passe d'application** par client, générés par compte. Ils sont révocables individuellement, leur vérification est à travail constant (pas d'oracle de temps), et les échecs alimentent [fail2ban](./operations) comme sur chaque écouteur.

Chaque mot de passe d'application porte un **scope**, choisi à la création et obligatoire (pas de plein accès par défaut silencieux) : `full`, `mail`, `calendar` (qui inclut les tâches : un seul credential d'agenda couvre les clients CalDAV VTODO), `contacts` (le credential de synchronisation CardDAV), `drive`, ou une **liste personnalisée d'URN de capabilities** en tableau JSON. Une liste personnalisée est validée à la création sur les deux surfaces : chaque élément doit être une capability que ce serveur sert réellement, et le refus nomme les entrées fautives. Un credential qui revendiquerait un droit que le dispatch n'honorera jamais ne peut pas être créé. La CLI (`oximail app-password create`) valide contre le vocabulaire intégré et le dit ; pour scoper un credential sur une capability d'*extension* enregistrée au démarrage, passez par `POST /auth/app-password`, qui les connaît aussi.

Les **passkeys** (WebAuthn) suivent la même discipline de gestion : `GET /auth/passkey` et `DELETE /auth/passkey/{id}` permettent à un utilisateur connecté de lister et révoquer ses credentials, et `oximail passkey list|revoke` est la porte hors bande de l'opérateur. C'est voulu : quand le credential à révoquer est celui qui ouvre le webmail, le chemin de révocation ne doit pas être le webmail. Le listing inclut pour chaque credential l'indice *discoverable* (a-t-il été créé utilisable par une connexion sans nom d'utilisateur), enregistré à l'enrôlement.

## Comptes d'équipe partagés

Un **compte partagé** est une identité d'équipe non connectable (`comptabilite@`, `equipe@`) qui possède une boîte et des ressources d'équipe sans être une personne :

```bash theme={null}
oximail account create-shared --email comptabilite@acme.tld --tenant acme
```

Personne ne s'y connecte ; les humains l'atteignent par des droits. Trois invariants gardent le modèle honnête :

* **Un compte partagé ne peut jamais être bénéficiaire.** Une entrée `shareWith` dont le principal est adossé à un compte partagé est rejetée à l'écriture sur tous les domaines : une identité non connectable ne peut jamais *exercer* un droit, l'accepter créerait des entrées d'ACL mortes.
* **Son drive a toujours un gardien.** La racine de fichiers du compte partagé n'est pas modifiable en JMAP ; la garde est une surface CLI explicite. `oximail account custodian show` liste les gardiens actuels et indique si le repli sur les administrateurs humains du tenant tient ; `custodian reattach --principal <p> [--replace]` accorde à un principal **adossé à un humain** les pleins droits sur la racine, avec audit (l'état antérieur est conservé dans l'entrée d'audit, un transfert est donc restaurable). Les commandes qui modifient les rôles refusent de retirer le dernier administrateur humain de l'organisation tant qu'un drive partagé n'a pas de gardien explicite.
* **Dans l'annuaire, il est typé honnêtement.** Le principal d'un compte partagé est émis en `type: "other"`, pas `individual` : les sélecteurs de personnes ne le proposent pas comme un humain.

## Annuaires de contacts partagés

Une organisation peut publier des jeux de contacts partagés (une liste de clients, une liste du personnel) qui apparaissent dans le carnet d'adresses de chaque membre sans que personne ne recopie de fiche. C'est un objet du **plan d'administration** : il est créé et nommé par un administrateur de tenant, et les entrées du quotidien sont tenues par les principaux inscrits comme éditeurs, groupes compris.

Deux conséquences comptent pour l'exploitation :

* **Les membres reçoivent des contacts, pas un dossier.** Les entrées arrivent chez un membre en fiches lisibles seulement, marquées comme provenant de l'organisation, sur le plan même qu'utiliserait un flux LDAP ou SCIM externe. Il n'y a rien qu'un utilisateur puisse renommer, déplacer ou supprimer par mégarde, et rien à départager quand quelqu'un s'en va.
* **Le contenu appartient à l'organisation, pas au membre.** Un annuaire se purge en retirant ses entrées ; il ne suit pas l'effacement d'un compte individuel, puisqu'il n'a jamais été la donnée de cette personne.

La surface est servie en JMAP pour les sessions d'administration et d'édition. Il n'existe volontairement aucun verbe en ligne de commande : c'est du contenu d'annuaire, pas de la configuration de serveur. Le détail des méthodes et des propriétés est sur la [page contacts](../developer/jmap-contacts#les-annuaires-de-tenant).

## Plafonds de capacité

La capacité du chat est bornée par organisation via la section TOML `[chat]`, et les valeurs appliquées sont annoncées dans l'objet de capacité du chat, pour que les clients les respectent avant de rencontrer l'erreur :

| Plafond                       | Défaut | Erreur au dépassement |
| ----------------------------- | ------ | --------------------- |
| Salons par compte             | 100    | `overQuota`           |
| Participants par salon        | 200    | `tooLarge`            |
| Taille de message (sérialisé) | 64 Kio | `tooLarge`            |

Ces plafonds bornent le produit d'écriture de la diffusion (chaque message de salon écrit une ligne par membre).

## Un serveur, plusieurs organisations : les frontières

* Les domaines de courrier appartiennent aux organisations ; l'adresse d'un compte doit être dans un domaine que son organisation possède.
* Les blobs sont stockés sous des chemins par organisation et chiffrés avec des hiérarchies de clés par organisation ; la déduplication inter-organisations n'existe pas, à dessein.
* Les destinations de journalisation, les droits de partage et chaque objet JMAP se résolvent strictement dans l'organisation.
* L'API d'administration et la CLI opèrent par organisation (`--tenant-id`) ; il n'existe volontairement pas de vue de données « tous tenants ».
