Customization decision
Resources · cheat sheet
The vendor’s code is theirs, not yours — every in-place edit fights the next release. Route every change to a home the vendor never touches. Full method + worked examples: Implement Customizations.
Decide in one screen
Section titled “Decide in one screen”flowchart TD Q{What are you<br/>changing?} Q -->|Editing an existing<br/>vendor file| V["Vendor customization<br/>resources/vendor-customizations/"] Q -->|Adding brand-new<br/>functionality| Z["ZajModule package<br/>packages/ZajModules/"] Q -->|Adding columns to<br/>a vendor table| M["_zaj migration<br/>adds the columns"]The decision table
Section titled “The decision table”| You are… | Home | Where it lives | Mechanism |
|---|---|---|---|
| Adding brand-new functionality (feature, integration, admin tool) | ZajModule | packages/ZajModules/{Type}/{Category}/{Name}/ | Self-contained package; the vendor app never references it |
| Editing an existing vendor file — and only because no event hook or override can do the job | Vendor customization | resources/vendor-customizations/ (mirrors the vendor path) | Edit wrapped in ZAJ:BEGIN/END, re-applied after every composer install |
Adding a column to a vendor table (users, plans, …) | _zaj migration | database/migrations/{date}_add_{cols}_to_{table}_zaj.php | Schema::table('users', …) adds the marked column directly; the _zaj.php suffix + ZAJ: comment mark it as yours |
Three rules that never bend
Section titled “Three rules that never bend”- Try event-driven first. Laravel fires events for registration, login, payment, etc. A ZajModule can listen instead of editing the controller. Reach for a vendor edit only when the logic is hardcoded with no hook.
- Never edit a vendor migration, and never run raw
ALTER TABLE. Add columns through an additive_zajmigration ({date}_add_{cols}_to_{table}_zaj.php) so every schema change stays reversible and diffable. - Mark every
_zajchange. The_zaj.phpfilename + aZAJ:columncomment()make your additions auditable; the Atlas diff on vendor update catches any clash. Genuinely new data goes in azajm_{module}_{noun}table the module owns.
Mark vendor edits with ZAJ markers
Section titled “Mark vendor edits with ZAJ markers”In an overlaid vendor file, wrap only the lines you added so a future vendor diff sees exactly what is yours. Everything outside the markers stays identical to the original.
// ZAJ:BEGIN MOD-001 — extend the migration scanner to include ZajModules paths$zajCoreMigrations = collect(File::glob(database_path('migrations-zaj/*.php'))) ->map(fn ($path) => File::name($path));$migrationFiles = $migrationFiles->merge($zajCoreMigrations);// ZAJ:END MOD-001A wholly new file the overlay owns gets a ZAJ:FILE header instead. Give every edit a tracked MOD-NNN identifier.
Worked routing — three real changes
Section titled “Worked routing — three real changes”| The change | Home |
|---|---|
Send new signups to an email-marketing service (listen to the Registered event) | ZajModule at packages/ZajModules/System/EmailMarketing/Encharge/ |
The vendor dashboard’s migration scanner misses your module paths and wrongly redirects to /update | Vendor customization of app/Http/Controllers/HomeController.php, tracked as a MOD-NNN |
Store a per-plan feature limit the vendor’s plans table doesn’t have | _zaj migration add_feature_limit_to_plans_zaj.php — adds the marked column to plans |
Related
Section titled “Related” Deploy commands Ship / sync / rollback at a glance.
Vendor customizations (full) The overlay, ZAJ markers, and the restore script.