3 · Restore customizations
Objective — put your work back on top of the new vendor base: re-apply the vendor-customizations overlay, confirm your ZajModules and schema additions are intact, then prove nothing was lost before deploying.
Background
Section titled “Background”A vendor update is only safe if your customizations come back. Three kinds of change live in three different places, and they survive the update differently:
- ZajModules (your new features, in their own packages) — the vendor update never touches them. They survive automatically; you just confirm they’re still loaded.
- Your schema additions —
zajm_module tables and the_zajcolumns you added to vendor tables. Your_zajmigrations already ran (recorded in themigrationstable), so they’re skipped on update and your columns/tables persist untouched. - The vendor-customizations overlay (your edits to vendor files) — this is the fragile one.
composer installin the previous step revertedvendor/to vanilla, so the overlay must be re-applied by the restore script. That’s the work of this page.
flowchart LR V["vanilla vendor/<br/>after composer install"] --> S["restore script<br/>copies overlay → vendor/"] O["_CUSTOMIZATIONS log<br/>MOD-NNN registry"] --> S S --> C["re-run each patch's<br/>own verification"] C --> D["deploy staging,<br/>then production"]1. Review the MOD-NNN log before restoring
Section titled “1. Review the MOD-NNN log before restoring”The log is the registry of every vendor file you patched. After an update, walk it once: a patch may now be redundant if the vendor fixed the underlying bug, or it may need re-checking against the new vendor code.
-
Walk each
MOD-NNNrow and confirm it’s still required against the new vendor base.- ✅ Each patch is marked still-needed or now-redundant; redundant patches are queued for removal from the overlay.
Keep the list short on purpose. If the log is growing past MOD-003, MOD-004, that’s a signal to refactor those edits into event-driven ZajModules instead — fewer vendor-file patches means fewer things to restore on the next update.
2. Run the restore script
Section titled “2. Run the restore script”The restore script reads your overlay and copies every customized file back over its now-vanilla vendor counterpart. Run it after composer install — every time vendor/ is rewritten.
-
Run the restore script and read its per-package summary.
Terminal window php Admin-Local/.../restore-vendor-customizations.php# Expected: "Found N customized package(s)" then a per-package "Restored N file(s)" summary- ✅ The summary lists each customized package and the count of files it restored.
The script scans resources/vendor-customizations/, finds each customized package folder, and recursively copies its files onto the matching package inside vendor/. A package missing from vendor/ (removed or renamed in this release) is skipped with a warning rather than failing the run — which is itself a useful signal that a vendor file you patched no longer exists.
3. Confirm your ZajModules and schema additions survived
Section titled “3. Confirm your ZajModules and schema additions survived”These should be untouched — but “should be” isn’t “verified”. A quick check confirms your module tables (zajm_*) are present and your _zaj columns (added to vendor tables) survived the update.
-
List your module-owned tables — your data tables are
zajm_*; the registry iszajmanager_*.Terminal window php artisan optimize:clearphp artisan tinker --execute="collect(DB::select('SHOW TABLES'))->pluck('Tables_in_'.env('DB_DATABASE'))->filter(fn(\$t) => str_starts_with(\$t, 'zajm_') || str_starts_with(\$t, 'zajmanager_'))->each(fn(\$t) => print(\$t.PHP_EOL));"# Expected: your zajm_ module tables print — none missing after the update- ✅ Every
zajm_table you expected prints, and your ZajModule features load without error.
- ✅ Every
-
Confirm your
_zajcolumns survived — they live on vendor tables and are found by theZAJ:marker comment in the live schema.Terminal window php artisan tinker --execute="collect(DB::select(\"SELECT CONCAT(table_name,'.',column_name) c FROM information_schema.columnsWHERE table_schema = DATABASE() AND column_comment LIKE 'ZAJ:%'\"))->each(fn(\$r) => print(\$r->c.PHP_EOL));"# Expected: every ZAJ:-marked column you added (e.g. users.whitelabel_domain) prints- ✅ Each
_zajcolumn you added still appears with itsZAJ:marker intact.
- ✅ Each
4. Verify the patches actually landed
Section titled “4. Verify the patches actually landed”A restore that reports “files copied” still needs a behavioural check — confirm the patched logic produces the right result, not just that the bytes are in place.
-
Re-run each patch’s own verification. For the
MOD-001migration-scanner example, confirm the file count now matches the database count.Terminal window php artisan tinker --execute="\$files = count(File::glob(database_path('migrations/*.php')));\$files += count(File::glob(database_path('migrations-zaj/*.php')));\$files += count(File::glob(base_path('packages/ZajModules/*/src/Database/Migrations/*.php')));\$db = DB::table('migrations')->count();echo 'Files: '.\$files.' | DB: '.\$db.' | Diff: '.(\$files - \$db);"# Expected: Diff: 0 (or close to 0)- ✅ The diff is
0(or near it), confirming the patched scanner sees every migration path again.
- ✅ The diff is
-
Smoke-test the critical paths before trusting the update.
Path Confirms Login + dashboard The core app boots on the new base Your custom features The overlay + ZajModules work end-to-end Payments (Stripe test mode) Billing survived the update Email (Mailtrap / logs) Notifications still fire - ✅ Every critical path works on the updated, restored app.
5. Deploy staging-first, then production
Section titled “5. Deploy staging-first, then production”Never send a vendor update straight to production. Ship to staging, watch it, and only promote once it’s stable — running the same restore + schema-diff confidence checks at each hop.
-
Promote to staging and verify the schema synced.
Terminal window git checkout develop && git push origin developdep deploy stagingatlas schema diff --from "$ATLAS_LOCAL_URL" --to "$ATLAS_STAGING_URL"# Expected: deploy succeeds; the diff afterwards reports "Schemas are synced, no changes"- ✅ Staging deploys, the restore ran in the deploy, and the post-deploy Atlas diff reports synced.
-
After the soak window, promote to production and tag the release.
Terminal window git checkout production && git merge develop && git push origin productiondep deploy productiongit tag vY.Y.Y && git push origin vY.Y.Yatlas schema diff --from "$ATLAS_STAGING_URL" --to "$ATLAS_PRODUCTION_URL"# Expected: production deploys; the final diff reports "Schemas are synced"- ✅ Production runs the new version, the release is tagged, and staging/production schemas are synced.
Checklist
Section titled “Checklist”Do not mark this step done until every box below is checked.
- 👤 MOD log reviewed — each
MOD-NNNpatch confirmed still-needed (or queued for removal) against the new vendor base. - 🤖 Overlay restored —
restore-vendor-customizations.phpran aftercomposer installand reported each package restored. - 🤖 ZajModules + schema intact — packages load; every expected
zajm_table andZAJ:-marked_zajcolumn is present. - 🤖 Patches verified — each patch’s own check passes (e.g. migration
Diff: 0); critical paths smoke-tested. - 🔀 Shipped staging-first — deployed to staging, soaked, then promoted to production and tagged
vY.Y.Y; Atlas reports synced.
Continuous Develop & Deploy — the everyday loop now that the update is live: code, test, ship, and sync server changes back to git.