Salesforce Classic to Lightning Experience Migration (Nova Manufacturing)
Classic to Lightning migration and Apex security hardening for an international industrial equipment manufacturer.
Context
> Reconstructed case study: the scenario, company and figures are fictional. It is inspired by the kind of work I do in my role, whose specifics remain confidential, and does not describe a client engagement. Nova Manufacturing is an international manufacturer of industrial equipment (~150 sales reps spread across 3 sites/hubs in Europe). Its Salesforce CRM, still mostly running on Classic, had accumulated several generations of development: Visualforce pages, JavaScript buttons, Process Builder, heavily customized profiles, and REST integrations with third-party systems (ERP, billing). With Classic being progressively deprecated, the scenario is the modernization of the application — with an explicit mandate: don't just migrate the interface, harden the security of the legacy Apex code along the way, some of which had never been audited since its initial release.
Identified Components & Proposed Solutions
- Visualforce page Compte360 (Account object): search and display orders and contracts linked to an account, SOQL query built dynamically in the controller → converted to a Lightning Web Component AccountOrdersOverview, wired to AccountOrdersController.getOrders() (6 days)
- JavaScript button UpdateContractStatus (Contract object): updated contract status with no rights check or user confirmation → replaced by a Quick Action triggering a Screen Flow with an invocable Apex method (3 days)
- Process Builder "Order Validation": multi-level approval workflow triggered on creation → migrated to a Record-Triggered Flow (separate before-save/after-save to respect Governor Limits) (4 days)
- 4 legacy Apex controllers: systematic audit, no CRUD/FLS rights testing in place → rebuilt with a strict with sharing pattern. Plus 4 new controllers built for this project, with security designed in from the start (5 days total)
- Total estimate: 25 days (audit 2d, Visualforce→LWC migration 6d, JS button→Quick Action/Flow 3d, Process Builder→Flow 4d, Apex security 5d, testing 3d, documentation 2d), plus 8h of user training
Delivered Development
- LWC AccountOrdersOverview: lightning-datatable with server-side pagination and keyword search, wired to an @AuraEnabled(cacheable=true) Apex method using WITH SECURITY_ENFORCED
- Record-Triggered Flow "Order Validation v2": bulkified logic processing the full collection (the old Process Builder wasn't, and caused Governor Limit errors on bulk imports), with a reusable sub-flow for the notification step
- Permission Set Groups: consolidated 8 near-duplicate legacy profiles into 5 groups, reducing configuration debt and clarifying access audits
- Named Credentials: replaced hardcoded REST endpoints (credentials previously visible in Custom Settings to any admin) with Named Credentials, authentication managed by the platform
Security & Best Practices
- ContractService.updateStatus(): before the rebuild, it wrote directly to Contract with no checks, and the class ran without sharing by default from an old Visualforce controller. After: Security.stripInaccessible(AccessType.UPDATABLE, records) before every DML, explicit with sharing on the class
- Dedicated unit test simulating a user without edit rights on Contract.Statut__c to verify the write is correctly blocked by stripInaccessible()
- Audit of the 4 legacy controllers: no CRUD/FLS rights test existed before this project — systematic addition of explicit checks wherever queries weren't eligible for WITH SECURITY_ENFORCED. Security designed in from the start on the 4 new controllers built for the project
- Profile-to-permission-set mapping matrix validated with business managers before cutover, to avoid any silent regression on access rights
Risk Management
- Legacy Apex controller incompatibility (medium impact) → sandbox regression testing before each cutover, component-by-component deployment rather than a single big-bang release
- User adoption (high probability) → 8h of training split across 2 sessions, short role-based documentation instead of a single manual
- Governor Limit errors on migrated Flows (low impact, already hit once in sandbox) → bulkification built in from the design stage, tested with 200+ record datasets
- Silent access-rights regression during profile consolidation (high impact) → profile-to-permission-set mapping matrix validated with business managers before production rollout
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()
Results
Known Limitations & Decisions
- Progressive, component-by-component migration rather than a big bang: slower, but allows a targeted rollback if a migrated component reveals an unanticipated production issue
- Simple Visualforce pages with no real migration upside left as-is: Lightning Experience supports them natively, migrating the entire scope would have been cost with no measurable user benefit
- Named Credentials deployed only on the REST integrations flagged as priority during the audit — secondary integrations remain on the old mechanism, migration documented as a next step