Bundle Upgrade, Locked Objects and Customer Extensions
A vendor ships PromoEngine 3.0 as a SuiteApp bundle to 12 customer accounts. The bundle contains a custom record, a custom list customlist_promo_channel with six values, three custom fields on Sales Order, a workflow on Sales Order, and a RESTlet, and its objects are marked Locked. In account A, the administrator added two extra list values and renamed one field label. In account B, the administrator built a second workflow on Sales Order that sends a coupon email. The 3.1 upgrade in account A fails with an error that a locked object cannot be updated, and after a support engineer unlocked and re-saved the list, account A's two extra values were gone. In account B the upgrade succeeds, but order confirmation emails now go out twice. The vendor wants a 3.2 release that does not repeat either problem.
1. Explain what Locked means for the customer and how it produced both the failed upgrade and the lost list values.
Read the worked answer
Locked is a statement about ownership: the bundle owns the object, and the customer account is not supposed to modify it. It is not a guarantee that modifications will be rejected politely or preserved.
What happened in account A:
- The administrator edited a locked object (added list values, renamed a label). Depending on the object and path, the platform may allow the edit or record it as a local modification.
- The 3.1 upgrade then tried to write the bundle's definition of that object over a locally modified, locked object, and the operation failed with a locked-object error. The upgrade is now blocked on account state, which is the worst outcome for a vendor.
- The support engineer unlocked and re-saved the list. Unlocking hands ownership back, and re-saving writes the bundle's definition, so the two local values disappeared. Once an object is unlocked, the next bundle update will overwrite it as well.
What happened in account B is the same problem from the other direction: the customer did not modify a locked object, they built a parallel one, and nothing in the bundle noticed.
The design lesson is that Locked protects the vendor's schema, but it does not create an extension point. A bundle that needs customer-specific configuration must ship one deliberately.
2. Why does account B send duplicate emails, and how should the vendor resolve it now and prevent it in 3.2?
Read the worked answer
Account B has two workflows on Sales Order: the bundled one and a locally built one, each with its own script ID, each triggered on order creation with a similar condition. The upgrade added or updated the vendor workflow; it did not detect or merge the customer's. NetSuite does not de-duplicate workflows by effect, so both send email.
Resolve now:
- Identify which workflow should own the email. Inactivate the other rather than deleting it, so intent and history remain visible.
- If the customer's workflow carries logic the vendor lacks, merge that logic into a single workflow rather than keeping both.
- Confirm the inactivated workflow has no pending state that would still fire.
Prevent in 3.2:
- Expose the email behaviour as a bundle preference or a configuration field on the bundled custom record, so customers toggle a setting instead of building a competing workflow. The most common reason customers duplicate a vendor workflow is that the vendor's version is not configurable.
- Have the bundle installation script inspect the account for user-created workflows on the same record and write a conflict warning to a log or a setup record, so the vendor learns about it at install and upgrade time rather than from a duplicate-email complaint.
- Publish an explicit extension policy: which objects are locked, which are extensible, and where customer configuration belongs.
3. List what the 3.2 release must contain, from project structure through upgrade testing, to be repeatable across all 12 accounts.
Read the worked answer
Treat the release as a product, not a zip file.
Source and structure
- Maintain the SuiteApp in a SuiteCloud Development Framework SuiteApp project as the single source of truth, versioned in the repository, built into the bundle from that project.
- Keep the bundle ID and all object script IDs stable. Rename labels, never script IDs, and deprecate rather than delete. An object that disappears between versions breaks account data that references it.
- Separate locked core objects from an explicitly unlocked extension area: a customer-owned custom record or a set of bundle preferences for configuration, and a documented copy-and-customize pattern for anything else.
Upgrade behaviour
- Ship a bundle installation script that runs on install and on update, is idempotent, reads the previous version, and performs only version-gated migration. It should seed preferences, detect drift and conflicts, and write a clear result record.
- Provide a changelog per version that names objects whose lock status or behaviour changed, since that is what breaks customer accounts.
Testing and rollout
- Test the upgrade against replicas of at least two real customer configurations, one with local list modifications and one with a competing workflow, because those are the two failure classes already observed.
- Upgrade a sandbox account per customer, or the vendor's own test account configured to match, before touching production.
- Verify after upgrade that locked objects match the bundle definition, that preferences survived, and that exactly one workflow sends email per order.