Skip to content
acceptedAudienceDevAudit banqueComplianceOwner@kyc-teamDernière revue2026-05-21

ADR-0004 — Modèle multi-utilisateurs marchand via merchant_members

Status : Accepted Date : 2026-04 Deciders : équipe Nex (ticket NEX-500) Tickets : NEX-500

Contexte

Le modèle initial couplait un marchand 1:1 à un utilisateur via merchants.user_id UNIQUE NOT NULL. Limitations :

  • Impossible d’avoir plusieurs collaborateurs sur un même marchand (owner, caissiers, comptable).
  • Le sujet KYC (représentant légal) était confondu avec le propriétaire du compte.
  • Impossible de transférer la propriété d’un marchand sans casser le ledger historique.

L’app Nex Business cible précisément des marchands multi-utilisateurs (commerçant + caissiers).

Décision

  1. Découpler marchand et utilisateur par une table customer.merchant_members(merchantId, userId, role, posId, status, …) (mirror du pattern organization_members).
  2. Rôles : owner, admin, operator, cashier, accountant.
  3. cashier requiert un posId (DB CHECK), rattaché à un POS spécifique.
  4. Invariant : au moins un owner actif par marchand en permanence (enforced via MerchantMembersService.assertNotLastActiveOwner).
  5. merchants.user_id déprécié (nullable, plus de UNIQUE). Lectures legacy uniquement, plus d’écriture.
  6. merchants.legal_representative_person_id — FK vers customer.people, le sujet KYC indépendant du propriétaire compte.
  7. Création = flow 2 étapes : POST /merchants (standalone) puis POST /merchants/:id/members pour assigner au moins un owner.
  8. mobile-business sélectionne un marchand actif via header X-Merchant-Id. Le endpoint auth business-context renvoie les memberships[] de l’utilisateur.

Conséquences

Positives

  • Multi-utilisateurs natif.
  • KYC subject indépendant du propriétaire (cas du gérant qui n’est pas le représentant légal).
  • Audit trail riche : qui a fait quoi en tant que membre du marchand.
  • Évolutivité : ajout de nouveaux rôles sans schema breaking.

Négatives / risques

  • Migration des marchands existants nécessaire (script back-fill).
  • Plus de jointures dans les queries marchands (mitigation : index sur (merchantId, userId)).
  • L’endpoint legacy POST /auth/register/merchant a été supprimé : ruptures côté clients qui l’utilisaient.

Alternatives écartées

  • Garder merchants.user_id + table merchant_collaborators — confusion entre propriétaire et membres, deux sources de vérité.
  • Multi-tenant strict via tenant_id — surdimensionné pour le besoin, pas adapté au modèle CEMAC.

Suivi

  • RegisterMerchantUseCase historique supprimé.
  • Voir /services/customer-profiles-kyc/.
  • L’app mobile-business utilise authStore mono-compte aujourd’hui ; refactor multi-marchands à venir.

Nex — Plateforme fintech CEMAC