Appearance
BDD-168 — Entreprises manquantes dans le sélecteur super-admin
🔧 Fix technique
Entreprises manquantes dans le sélecteur super-admin
GET /enterprise-api-keys/enterprises ne renvoyait que les entreprises ayant déjà une fiche locale sur l'environnement consulté. Sur un environnement peu utilisé (ex: staging), le sélecteur d'entreprise du super-admin n'affichait quasiment que sa propre entreprise. Le endpoint provisionne maintenant la fiche locale à la volée au lieu de masquer l'entreprise.
1. Contexte
Le switcher d'entreprise du super-admin (MainLayout.vue, header de la sidebar) appelle GET /enterprise-api-keys/enterprises, implémenté dans EnterpriseApiKeysService.listEnterprises().
Ce endpoint :
- Récupère la liste brute des entreprises via
ConsoleAdminService.getEnterprises()(API console admin,{ id, name }, sans uuid). - Fait correspondre chaque entreprise à sa fiche locale
prisma.tool.enterprisesparid, pour récupérer l'uuidlocal attendu par le reste de l'application (adminScopeStore, résolution du dossier racine, etc.). - Filtrait toute entreprise sans correspondance locale (
uuid: null).
Or une ligne tool.enterprises n'est créée que lorsqu'un utilisateur de cette entreprise se connecte à Outil BDD sur cet environnement précis (authGuard.upsertLocalUser). Sur un environnement neuf ou peu utilisé, la table locale ne contient donc que les entreprises dont un membre s'est déjà connecté — la plupart des entreprises existant côté console-admin étaient filtrées silencieusement, sans erreur.
Symptôme observé : sur staging.api.bdd.heriade.fr, un super-admin connecté ne voyait dans le sélecteur qu'une seule entreprise (la sienne), alors que console-admin en référence bien davantage. Un même code déployé sur un environnement plus ancien (avec plus de logins historiques) ne présentait pas le problème — d'où la confusion initiale sur une possible différence de configuration entre les deux environnements.
2. Solution
listEnterprises() ne filtre plus les entreprises sans uuid local : il provisionne la fiche locale à la volée (ensureLocalUuid), avec le même upsert que celui déjà utilisé à la connexion (authGuard.upsertLocalUser), keyed sur l'id numérique console-admin.
ts
async listEnterprises(): Promise<Array<{ uuid: string; name: string | null }>> {
const consoleEnterprises = await this.consoleAdmin.getEnterprises();
const enterprises = await Promise.all(
consoleEnterprises.map((e) => this.ensureLocalUuid(e)),
);
return enterprises.sort((a, b) =>
(a.name ?? '').localeCompare(b.name ?? '', 'fr', { sensitivity: 'base' }),
);
}
private async ensureLocalUuid(enterprise: { id: number; name: string | null; uuid?: string | null }) {
if (enterprise.uuid) return { uuid: enterprise.uuid, name: enterprise.name ?? null };
const row = await this.prisma.tool.enterprises.upsert({
where: { id: enterprise.id },
create: { id: enterprise.id, name: enterprise.name ?? null },
update: { name: enterprise.name ?? null },
select: { uuid: true },
});
return { uuid: row.uuid, name: enterprise.name ?? null };
}3. Périmètre technique
Backend
| Fichier | Changement |
|---|---|
back/src/api/enterprise-api-keys/enterprise-api-keys.service.ts | listEnterprises() provisionne au lieu de filtrer ; nouvelle méthode privée ensureLocalUuid() |
back/src/api/enterprise-api-keys/enterprise-api-keys.service.spec.ts | Tests mis à jour : provisioning à la volée, tri simple, liste vide |
Aucun changement front — enterprises-store.js et MainLayout.vue consomment déjà le tableau { uuid, name }[] tel quel.
4. Règles métier implémentées
- La clé de correspondance reste l'
idnumérique console-admin, jamais l'uuid. L'upsert est keyé surwhere: { id }: la première "rencontre" d'une entreprise (que ce soit via ce endpoint ou via un login classique) génère l'uuid local (@default(uuid())en base) ; toutes les rencontres suivantes ne mettent à jour que lename. Pas de risque de doublon ni de divergence d'uuid, même en cas de login concurrent sur une entreprise jamais vue sur cet environnement. - Aucune entreprise console-admin n'est plus masquée du sélecteur super-admin, indépendamment de l'historique de connexions sur l'environnement consulté.
5. Points de vérification
GET /enterprise-api-keys/enterprisesen tant que super-admin sur un environnement avec peu/pas de logins locaux retourne bien toutes les entreprises console-admin, pas seulement celle de l'utilisateur connecté.- Après ce premier appel,
tool.enterprisescontient une ligne par entreprise console-admin retournée, avec un uuid stable. - Un login ultérieur d'un utilisateur d'une de ces entreprises ne crée pas de doublon et ne change pas l'uuid déjà provisionné.
6. Tests associés
Unitaires back
enterprise-api-keys.service.spec.ts—describe('listEnterprises'):- tri par nom des entreprises ayant déjà un uuid local (pas d'appel
upsert) ; - provisioning à la volée d'une entreprise sans uuid (assertion sur les paramètres exacts de l'
upsert), sans qu'elle soit masquée du résultat ; - tableau vide si console-admin ne renvoie aucune entreprise.
- tri par nom des entreprises ayant déjà un uuid local (pas d'appel
7. Notes d'implémentation
- Origine : signalé par Pierre Espieux sur
staging.bdd.heriade.fr(déploiement dédié, même code quedev.bdd.heriade.fr) — le sélecteur n'affichait que l'entreprise Heriade. Diagnostic confirmé en inspectant la réponse réseau ([{ uuid, name: "Heriade" }]uniquement) et le code delistEnterprises(). - Hors scope (volontairement) : le filtrage par environnement console-admin (Cloud / MVP / Déclaration EI…) introduit par BDD-113 sur un endpoint distinct (
FolderService.listEnterprises(),GET /folders/enterprises) n'est plus câblé — ce endpoint n'existe plus dansfolder.service.tsactuel, etConsoleAdminService.getEnterprisesByEnvironment()/CONSOLE_ADMIN_ENVIRONMENT_SLUGsont aujourd'hui du code mort (testés mais jamais appelés en production). Si un filtrage par environnement redevient nécessaire pour/enterprise-api-keys/enterprises, ce sera l'objet d'un ticket dédié plutôt que d'être mélangé à ce correctif.
8. Variables d'environnement
Aucune nouvelle variable.
