1 · The decision rule
Objective — before you change anything, answer three questions that route the change to the right update-safe home, so the next vendor update never overwrites your work.
Background
Section titled “Background”A CodeCanyon app’s code is the vendor’s, not yours. Every time you edit a vendor file in place, the next release fights you for it — merge conflicts, lost work, hours of re-debugging. The whole methodology exists to avoid that: send every change to a home the vendor never touches.
There are exactly three homes, and one question decides each. Get the routing right once and updates become a non-event.
1. Ask: am I adding something new, or editing something that exists?
Section titled “1. Ask: am I adding something new, or editing something that exists?”This is the first and biggest fork. New functionality should never live inside vendor files — it gets its own package.
-
If the change is brand-new functionality — a new integration, a new feature, a new admin tool — build it as a ZajModule package under
packages/ZajModules/{Type}/{Category}/{Name}/. The vendor app never references it, so vendor updates pass straight through.- ✅ The feature lives entirely in its own folder; no vendor file was touched.
-
If the change edits an existing vendor file — and only because no event hook or override can do the job — it becomes a vendor customization (next question).
- ✅ You have confirmed an event-driven approach genuinely won’t work before reaching for a vendor edit.
2. Ask: does this edit live in a vendor file I can’t avoid touching?
Section titled “2. Ask: does this edit live in a vendor file I can’t avoid touching?”Some vendor logic is tightly coupled — a hardcoded path scan, a flawed calculation with no override point. When there’s truly no alternative, you edit the file, but you store the edited copy where updates can’t erase it.
-
Put the edited copy in the overlay at
resources/vendor-customizations/, mirroring the vendor’s own path. After everycomposer install(which restores the vanilla vendor file), the restore script copies your version back over it.- ✅ The original vendor path is preserved inside the overlay folder, and a restore step re-applies it.
-
Give it a
MOD-NNNidentifier and log it so future-you (and the next vendor update) knows the patch exists and how to re-apply it.- ✅ The customization has a tracked
MOD-NNNentry.
- ✅ The customization has a tracked
3. Ask: am I adding columns to a vendor table?
Section titled “3. Ask: am I adding columns to a vendor table?”Database changes have their own hard rule: never edit a vendor migration. You make every change in your own migration file — and there are two safe homes for new data.
-
A new attribute on a vendor row → an additive
_zajmigration. Need a column likewhitelabel_domainonusers? Write a separate migration{date}_add_{cols}_to_{table}_zaj.phpthat adds the marked column directly to the vendor table — never touch the vendor’s own migration.Schema::table('users', fn (Blueprint $t) =>$t->string('whitelabel_domain')->nullable()->comment('ZAJ: <App> v<ver> — whitelabel'));- ✅ A new
_zaj-suffixed migration adds the column; theZAJ:comment marks it as yours in the live schema.
- ✅ A new
-
Genuinely new data → a
zajm_table. A loyalty ledger, event log, anything that isn’t just an attribute of a vendor row goes in a table your ZajModule owns, namedzajm_{module}_{noun}, inpackages/ZajModules/*/Database/Migrations/.- ✅ The new table lives outside
database/migrations/(vendor-only), so a vendor update never sees it.
- ✅ The new table lives outside
4. Worked examples — route three real changes
Section titled “4. Worked examples — route three real changes”Run the three questions against concrete requests to see the rule in action.
| The change | Question it answers | Home |
|---|---|---|
| Send new signups to an email-marketing service | New functionality (listen to the Registered event) | ZajModule at packages/ZajModules/System/EmailMarketing/Encharge/ |
The vendor’s dashboard migration scanner misses your module paths, so it wrongly redirects to /update | Editing an existing vendor file with no override point | Vendor customization of app/Http/Controllers/HomeController.php, tracked as a MOD-NNN |
Store a per-plan feature limit that the vendor’s plans table doesn’t have | Adding a column to a vendor table | _zaj migration add_feature_limit_to_plans_zaj.php — adds the marked column to plans |
Each lands in a home the vendor never touches — which is the entire point.
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 👤 New vs existing decided — you know whether the change is brand-new functionality (ZajModule) or an edit to a vendor file.
- 👤 Event-driven ruled out first — for any vendor edit, you confirmed no event hook or override could do the job.
- 👤 Database rule applied — columns are added to the vendor table via a marked additive
_zajmigration (never by editing a vendor migration); genuinely new data goes in azajm_table. - 👤 Home named — for your specific change, you can state which of the three homes it belongs in and why.