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
- Découpler marchand et utilisateur par une table
customer.merchant_members(merchantId, userId, role, posId, status, …)(mirror du patternorganization_members). - Rôles :
owner,admin,operator,cashier,accountant. cashierrequiert unposId(DB CHECK), rattaché à un POS spécifique.- Invariant : au moins un
owneractif par marchand en permanence (enforced viaMerchantMembersService.assertNotLastActiveOwner). merchants.user_iddéprécié (nullable, plus de UNIQUE). Lectures legacy uniquement, plus d’écriture.merchants.legal_representative_person_id— FK verscustomer.people, le sujet KYC indépendant du propriétaire compte.- Création = flow 2 étapes :
POST /merchants(standalone) puisPOST /merchants/:id/memberspour assigner au moins un owner. mobile-businesssélectionne un marchand actif via headerX-Merchant-Id. Le endpoint authbusiness-contextrenvoie lesmemberships[]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/merchanta été supprimé : ruptures côté clients qui l’utilisaient.
Alternatives écartées
- Garder
merchants.user_id+ tablemerchant_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
RegisterMerchantUseCasehistorique supprimé.- Voir /services/customer-profiles-kyc/.
- L’app
mobile-businessutiliseauthStoremono-compte aujourd’hui ; refactor multi-marchands à venir.