Migration Salesforce Classic vers Lightning Experience (Nova Manufacturing)
Migration Classic → Lightning et durcissement sécurité Apex pour un fabricant industriel international.
Contexte
> Étude de cas reconstituée : le scénario, l'entreprise et les chiffres sont fictifs. Elle s'inspire du type de travaux que je réalise en poste, dont le détail reste confidentiel, et ne décrit pas une mission client. Nova Manufacturing est un fabricant international d'équipements industriels (~150 commerciaux répartis sur 3 sites/pôles en Europe). Son CRM Salesforce, encore majoritairement sous Classic, accumulait plusieurs générations de développements : pages Visualforce, boutons JavaScript, Process Builder, profils très personnalisés, intégrations REST vers des systèmes tiers (ERP, facturation). Avec la dépréciation progressive de Classic, le scénario porte sur la modernisation de l'application — avec un mandat explicite : ne pas se contenter de migrer l'interface, mais durcir la sécurité des développements Apex historiques au passage, dont plusieurs n'avaient jamais été audités depuis leur mise en production initiale.
Composants identifiés & solutions proposées
- Page Visualforce Compte360 (objet Account) : recherche et affichage des commandes et contrats liés à un compte, requête SOQL construite dynamiquement côté contrôleur → convertie en Lightning Web Component AccountOrdersOverview, wiré à AccountOrdersController.getOrders() (6 jours)
- Bouton JavaScript UpdateContractStatus (objet Contract) : mise à jour du statut contractuel sans vérification de droits ni confirmation utilisateur → remplacé par une Quick Action déclenchant un Screen Flow avec Apex invocable (3 jours)
- Process Builder "Validation commande" : workflow d'approbation multi-niveaux déclenché à la création → migré vers un Record-Triggered Flow (before-save + after-save séparés pour respecter les Governor Limits) (4 jours)
- 4 contrôleurs Apex historiques : audit systématique, aucun test de droits CRUD/FLS en place → refonte avec pattern with sharing strict. + 4 nouveaux contrôleurs créés pour ce projet, avec sécurité intégrée dès la conception (5 jours au total)
- Estimation totale : 25 jours (audit 2j, migration Visualforce→LWC 6j, bouton JS→Quick Action/Flow 3j, Process Builder→Flow 4j, sécurité Apex 5j, tests 3j, documentation 2j), + 8h de formation utilisateurs
Développements livrés
- LWC AccountOrdersOverview : lightning-datatable avec pagination côté serveur et recherche par mot-clé, wiré à une méthode Apex @AuraEnabled(cacheable=true) en WITH SECURITY_ENFORCED
- Record-Triggered Flow "Validation commande v2" : logique bulkifiée traitant la collection complète (l'ancien Process Builder ne l'était pas et provoquait des erreurs Governor Limits sur les imports en masse), avec sous-flow réutilisable pour la partie notification
- Permission Set Groups : consolidation de 8 profils historiques quasi-dupliqués en 5 groupes, réduisant la dette de configuration et clarifiant l'audit des accès
- Named Credentials : remplacement des endpoints REST codés en dur (identifiants auparavant visibles dans des Custom Settings par tout admin) par des Named Credentials avec authentification gérée par la plateforme
Sécurité & bonnes pratiques
- ContractService.updateStatus() : avant refonte, écriture directe sur Contract sans vérification et classe en without sharing par défaut d'un ancien contrôleur Visualforce. Après refonte : Security.stripInaccessible(AccessType.UPDATABLE, records) avant tout DML, with sharing explicite sur la classe
- Test unitaire dédié simulant un utilisateur sans droit d'édition sur Contract.Statut__c pour vérifier que l'écriture est bien bloquée par stripInaccessible()
- Audit des 4 contrôleurs historiques : aucun test de droits CRUD/FLS n'existait avant ce projet — ajout systématique de vérifications explicites là où les requêtes ne sont pas éligibles à WITH SECURITY_ENFORCED. Sécurité intégrée dès la conception sur les 4 nouveaux contrôleurs créés pour le projet
- Matrice de comparaison profils → permission sets validée avec les managers métier avant bascule, pour éviter toute régression silencieuse sur les droits d'accès
Gestion des risques
- Incompatibilité de contrôleurs Apex existants (impact moyen) → tests de non-régression en sandbox avant chaque bascule, déploiement composant par composant plutôt qu'en bloc
- Adoption utilisateurs (probabilité élevée) → 8h de formation réparties sur 2 sessions, documentation courte par rôle plutôt qu'un manuel unique
- Erreurs Governor Limits sur les migrations Flow (impact faible, déjà rencontré une fois en sandbox) → bulkification systématique dès la conception, testée avec des jeux de données de 200+ enregistrements
- Régression silencieuse sur les droits d'accès pendant la consolidation des profils (impact élevé) → matrice de comparaison profils → permission sets validée avec les managers métier avant mise en production
Stack & Technologies
- Lightning Web Components, Apex, SOQL
- Flow (Record-Triggered, before-save/after-save)
- Permission Set Groups, Named Credentials
- Salesforce Security Model — CRUD/FLS, WITH SECURITY_ENFORCED, stripInaccessible()
Résultats
- Classes Apex sécurisées
- 8(4 historiques durcies + 4 nouvelles créées sécurisées dès la conception)
- Profils consolidés
- 8 → 5(Permission Set Groups)
- Charge totale
- 25 jours(audit + migration + sécurité + tests + documentation)
- Bulk testé
- 200+ enregistrements(validation Governor Limits sur les Flows migrés)
Limites connues & décisions
- Migration progressive composant par composant plutôt qu'un big-bang : plus lent, mais permet un rollback ciblé si un composant migré révèle un problème non anticipé en production
- Pages Visualforce simples (sans réelle valeur ajoutée à migrer) laissées telles quelles : Lightning Experience les supporte nativement, migrer l'ensemble du périmètre n'aurait été qu'un coût sans bénéfice utilisateur mesurable
- Named Credentials déployés uniquement sur les intégrations REST identifiées comme prioritaires lors de l'audit — les intégrations secondaires restent sur l'ancien mécanisme, migration documentée comme prochaine étape