Aller au contenu principal

Organisations (Admin Système)

Endpoints de gestion des organisations. Réservés aux administrateurs plateforme (permission organization.manage).


Architecture multi-tenant​

Chaque organisation est isolée dans son propre schéma PostgreSQL nommé tenant_{slug}. Le middleware Tenant positionne le search_path via une variable task_local avant chaque requête, garantissant une isolation totale des données.

flowchart LR
A[Requête API] --> B[Tenant middleware]
B --> C[Résoudre org depuis header/jwt]
C --> D[SET search_path = tenant_slug]
D --> E[Requête exécutée<br/>dans le bon schéma]

Structure de données​

Une organisation contient les champs suivants dans la table public.organizations :

ChampTypeDescription
iduuidIdentifiant unique
slugstringIdentifiant URL unique (ex: cours-lumiere)
short_codestringCode court 2-5 caractères majuscules (ex: CL)
namestringNom d'affichage (ex: Cours Lumière)
legal_namestring?Nom légal / raison sociale
tax_idstring?Numéro IFU / tax ID
contact_emailstring?Email de contact
contact_phonestring?Téléphone de contact
websitestring?Site web
statusenumactive, suspended
currencystringDevise ISO 4217 (défaut: XOF)
default_anomaly_threshold_centsintegerSeuil anomalie solde faible en centimes (défaut: 30000)
card_number_range_startintegerDébut plage numéros de carte (défaut: 1)
card_number_range_endintegerFin plage numéros de carte (défaut: 99999)
schema_namestringNom du schéma PostgreSQL (tenant_{slug})
settingsjsonbConfiguration typée de l'organisation
notification_configjsonbConfiguration des canaux de notification
created_atdatetimeDate de création
updated_atdatetimeDate de dernière modification

GET /admin/system/organizations​

Liste paginée des organisations.

Permissions : organization.manage

ParamTypeDescription
limitintegerÉléments par page (défaut: 20)
offsetintegerDécalage (défaut: 0)

Réponse :

{
"items": [
{
"id": "550e8400-e29b-41d4-a716-446655440001",
"slug": "cours-lumiere",
"short_code": "CL",
"name": "Cours Lumière",
"legal_name": null,
"tax_id": null,
"contact_email": "contact@courslumiere.com",
"contact_phone": "+22890123456",
"website": null,
"status": "active",
"currency": "XOF",
"default_anomaly_threshold_cents": 30000,
"card_number_range_start": 1,
"card_number_range_end": 99999,
"schema_name": "tenant_cours_lumiere",
"settings": {},
"notification_config": {
"channels": {
"email": { "enabled": true },
"sms": { "enabled": false },
"whatsapp": { "enabled": false }
},
"event_routing": {
"anomaly_detected": ["email"],
"recharge_completed": ["email"],
"low_balance": ["email"]
},
"email_default_from": "noreply@caffette.app"
},
"created_at": "2025-01-15T10:00:00Z",
"updated_at": "2025-06-01T14:30:00Z"
}
],
"total": 5
}

POST /admin/system/organizations​

Créer une organisation. Cette opération provisionne automatiquement :

  1. Un enregistrement dans public.organizations
  2. Un schéma dédié tenant_{slug} avec toutes les tables du tenant
  3. La configuration de notification par défaut
  4. Les rôles système par défaut (administrateur, gestionnaire, caissier, etc.)

Permissions : organization.manage

Corps de la requête :

{
"slug": "nouvelle-ecole",
"short_code": "NE",
"name": "Nouvelle École",
"legal_name": "Nouvelle École SARL",
"contact_email": "dir@nouvelleecole.com",
"contact_phone": "+22890123456",
"card_range_start": 1,
"card_range_end": 99999
}
ChampTypeRequisDescription
slugstringOuiIdentifiant URL unique (sans espaces, sans majuscules)
short_codestringOuiCode court (2-5 caractères, converti en majuscules)
namestringOuiNom d'affichage
legal_namestringNonNom légal / raison sociale
contact_emailstringNonEmail de contact
contact_phonestringNonTéléphone
card_range_startintegerNonDébut plage numéros de carte (défaut: 1)
card_range_endintegerNonFin plage numéros de carte (défaut: 99999)
astuce
  • Le slug sert de base au nom du schéma : tenant_{slug}. Il doit être unique et valide comme nom de schéma PostgreSQL.
  • Le short_code est utilisé dans les codes d'identification publique (ex: cartes CL-001, NE-042). Il est automatiquement converti en majuscules.
  • Les plages de numéros de carte (card_range_start/card_range_end) définissent l'espace de numérotation pour l'organisation.

Réponse (201) :

{
"message": "Organisation créée avec succès",
"organization": {
"id": "550e8400-e29b-41d4-a716-446655440099",
"slug": "nouvelle-ecole",
"short_code": "NE",
"name": "Nouvelle École",
"schema_name": "tenant_nouvelle_ecole",
"status": "active",
"currency": "XOF",
"default_anomaly_threshold_cents": 30000,
"card_number_range_start": 1,
"card_number_range_end": 99999,
"created_at": "2025-07-01T08:00:00Z"
}
}

GET /admin/system/organizations/{id}​

Détails d'une organisation. Retourne l'objet Organization complet (mêmes champs que dans la liste).

Permissions : organization.manage


PUT /admin/system/organizations/{id}​

Mettre à jour les métadonnées d'une organisation. Tous les champs sont optionnels — seuls les champs fournis sont modifiés.

Permissions : organization.manage

Corps de la requête :

{
"name": "Nouvelle École Internationale",
"short_code": "NEI",
"contact_email": "admin@nei.com",
"contact_phone": "+22890987654"
}
attention

La modification du short_code a un impact sur les codes d'identification publique déjà émis (cartes, agents). Assurez-vous que les opérateurs sont informés du changement.

Réponse :

{
"message": "Organisation mise à jour",
"organization": {
"id": "uuid",
"name": "Nouvelle École Internationale",
"short_code": "NEI",
"updated_at": "2025-07-02T10:00:00Z"
}
}

POST /admin/system/organizations/{id}/suspend​

Suspendre une organisation. Passe le statut à suspended et empêche l'accès à l'API pour tous les utilisateurs de cette organisation.

Permissions : organization.manage

Réponse :

{
"message": "Organisation suspendue"
}

POST /admin/system/organizations/{id}/activate​

Réactiver une organisation précédemment suspendue. Passe le statut à active.

Permissions : organization.manage

Réponse :

{
"message": "Organisation activée"
}

Cycle de vie d'une organisation​

stateDiagram-v2
[*] --> provisioning: POST /organizations
provisioning --> active: Schema créé<br/>Config initiale
active --> suspended: POST /suspend
suspended --> active: POST /activate
active --> [*]

Bonnes pratiques​

  • Plage de numéros de carte : Commencez avec une plage large (1-99999) et réduisez-la si nécessaire. Vous ne pouvez pas étendre la plage une fois des cartes émises sans risque de collision.
  • Seuil d'anomalie : Le seuil par défaut (30000 centimes = 300 FCFA) est conservateur. Ajustez-le en fonction de votre panier moyen après quelques semaines d'exploitation.
  • Slug : Une fois défini, le slug ne peut pas être changé (il est lié au nom du schéma PostgreSQL). Choisissez-le avec soin.
  • Notification config : La configuration par défaut n'active que l'email. Pour activer SMS ou WhatsApp, modifiez notification_config dans les settings de l'organisation.