Skip to content
prod e051e98
Browse

ZajModules vs customizations

The core mental model

This is the most important idea in the whole handbook. Get it, and every other rule makes sense.

When you want to change a CodeCanyon app, you have a choice about where the change lives. Make the change in the vendor’s own files and you win today but lose on the next update. Make it in your space — using the patterns below — and the vendor can ship update after update while your work survives untouched.

A CodeCanyon app is someone else’s codebase that you license. The author keeps shipping new versions. The moment you edit one of their files, you have created a conflict that resurfaces on every release.

StepWhat happens
You edit RegisterController.phpWorks today
Author ships an updateGit merge conflict
You resolve the conflictRisk of new bugs
Repeat every releaseMaintenance pain that compounds

The fix is to stop editing their files and route every change into one of three of your own lanes.

Every change you want to make falls into exactly one of these:

graph TD
Start["I want to change<br/>the vendor app"]
Start --> Q1{"New behavior that<br/>can be toggled off?"}
Q1 -->|Yes| Module["ZajModule<br/>packages/ZajModules/"]
Q1 -->|No| Q2{"Just tweaking the<br/>vendor's existing UI<br/>or output?"}
Q2 -->|Yes| Custom["Vendor customization<br/>resources/vendor-customizations/"]
Q2 -->|No| Q3{"Adding data the<br/>vendor doesn't store?"}
Q3 -->|Yes| Schema["Schema extension<br/>_zaj migration adds the columns"]
Q3 -->|No| Reconsider["Reconsider — most<br/>everything fits the three above"]

Read the diagram top to bottom: each question routes you to one lane. The lanes never overlap, so there is always a single right home for a change.

Lane 1 — ZajModule (self-contained new behavior)

Section titled “Lane 1 — ZajModule (self-contained new behavior)”

A ZajModule is a feature you own, living in its own folder under packages/ZajModules/, that you can switch on or off with a single config flag. It never touches vendor files — instead it listens to events the app already fires.

Laravel fires events for almost everything (a user registers, logs in, verifies email). Your module subscribes to those events and reacts. The vendor never knows your module exists, so a git pull of their next version just works.

Vendor app fires "User Registered"
Your ZajModule LISTENS
It runs your logic (e.g. sync the user to a CRM)
Vendor update? Just pull. Nothing to merge.

A module is the right lane when the change is new behavior you’d want to be able to disable instantly — an integration, a tracking hook, an extra automation. One .env toggle kills it with zero code changes.

Lane 2 — Vendor customization (changing what the vendor already shows)

Section titled “Lane 2 — Vendor customization (changing what the vendor already shows)”

Sometimes you genuinely need to change the vendor’s existing output — reword a label, restyle a page, tweak a Blade view. That is a vendor customization, and it lives under resources/vendor-customizations/ with a clear record of what changed.

The discipline here is to keep the change marked and reversible. Customizations are wrapped in ZAJ:BEGIN / ZAJ:END marker comments so that, on a vendor update, a restore script can find your edits, re-apply them on top of the fresh vendor file, and tell you about any spot it could not place cleanly. The markers are what turn “did I change this file?” from a guess into a grep.

Lane 3 — Schema extension (data the vendor doesn’t store)

Section titled “Lane 3 — Schema extension (data the vendor doesn’t store)”

If your change needs to store new data, there are two safe homes — and both live in your own migration files, never the vendor’s. A new attribute on a vendor row (say whitelabel_domain on users) → an additive _zaj migration ({date}_add_{cols}_to_{table}_zaj.php) that adds the marked columns directly to the vendor table. Genuinely new data → a zajm_{module}_{noun} table your module owns. The one thing you never do is edit the vendor’s own migration.

This lane has its own chapter because the database has its own failure modes. For the full rules — _zaj column migrations, zajm_ tables, additive-only changes, why you never edit a vendor migration — see Schema management.

ZajModuleVendor customizationSchema extension
Lives inpackages/ZajModules/resources/vendor-customizations/a _zaj migration / zajm_ table
Touches vendor files?Never (listens to events)Yes, but marked + reversibleNever edits a vendor migration; a _zaj migration adds marked columns
Toggle off instantly?Yes (one .env flag)No (it’s edited output)N/A (data, not behavior)
Update riskNoneLow — markers + restore scriptManaged — additive + ZAJ: markers; Atlas diff catches a clash
Use whenNew, toggleable behaviorMust change vendor’s own UI/outputMust store new data

Ask these in order and stop at the first yes:

  1. Is it new behavior I’d want to disable with a switch? → ZajModule.
  2. Am I changing the vendor’s own page or output? → Vendor customization (mark it).
  3. Do I need to store data the vendor doesn’t? → Schema extension.

If you answered “no” to all three, you probably don’t need to touch vendor code at all — re-read the change and look for the module-shaped version of it.