Skip to content
prod e051e98
Browse

1 · Ship — code → test → deploy

Objective — get a finished local change live the same safe way every time: pick small-vs-big, work on develop, pass the database safety gate, then deploy developstagingproduction and tag the release.

Shipping is dangerous in exactly two ways: a migration can drop data, and a bad merge can take the site down. This workflow removes both risks by making the path identical every time — a small change and a big feature flow through the same gate, so you never improvise on the day something breaks.

For the command-only card (Patterns A–D, quick smoke checks), use the Code → test → ship runbook.

The branch model is fixed: you work on develop, promote to staging to test, promote to production to go live, then mirror production into main as a backup. staging and production are real servers; develop and main are local-only.

flowchart LR
D["develop<br/>(work here)"] --> S["staging<br/>(test server)"]
S --> P["production<br/>(live)"]
P --> M["main<br/>(backup)"]

Before touching code, size the change. A one-line fix and a multi-file feature take different paths into git — getting this right keeps your history clean and your develop branch deployable.

  1. Classify the change against the size table.

    SizeDefinitionAction
    Small1–3 commits, simple changeWork directly on develop
    Big4+ commits, multi-file featureCreate a temporary branch
    • ✅ You know whether you’re working directly on develop or on a NewFeature/... branch.

Stale or out-of-sync branches are the most common cause of a confusing deploy. Verify you’re on develop, up to date, and that staging/production carry nothing develop doesn’t.

  1. Pull develop and confirm the branches are synced.

    Terminal window
    git checkout develop && git pull origin develop
    git log --oneline develop..staging # Expected: empty (no commits)
    git log --oneline staging..production # Expected: empty (no commits)
    # Expected: on develop, up to date, both log commands print nothing
    • ✅ You’re on develop, up to date, and both range logs are empty.

If a server had admin-panel changes that aren’t in git yet, capture them with Server sync before you ship — otherwise this deploy can overwrite them.

Make the change, test it locally, and commit with the right type prefix so the history reads as a log of what kind of change shipped when.

  1. For a big change, branch first. Skip this for a small change on develop.

    Terminal window
    git checkout -b NewFeature/descriptive-name
    # Expected: switched to a new branch named NewFeature/descriptive-name
    • ✅ Big changes live on their own branch; small changes stay on develop.
  2. Make the change, test locally, then commit with a typed message. Test in the browser at your local site (e.g. PROJECT.test) before committing.

    Terminal window
    git add [files]
    git commit -m "🔨 🟪 T3 Add-Feature: [description]"
    # Bug fix instead: 🔧 🟦 T2 Fix-Bug: [description]
    # Config change: 🔧 🟦 T2 Setup-Config: [description]
    git push origin [branch]
    # Expected: the commit lands and pushes to its branch
    • ✅ The change works locally and is committed with a type prefix that matches it.

This is the non-negotiable gate before any deploy that might include migrations. A migration that drops a table or column can destroy customer data — so you inspect every pending migration and let Atlas lint flag the dangerous ones before they ever reach a server.

  1. List pending migrations, then dry-run them to read the SQL.

    Terminal window
    php artisan migrate:status # which migrations are pending
    php artisan migrate --pretend # the SQL each would run — no DB change
    # Expected: a clear list; if nothing is pending, the gate is already clear
    • ✅ You can see exactly what SQL would run — or confirm nothing is pending.
  2. Run Atlas lint and STOP on a destructive finding. Atlas flags dangerous operations by code; the two that block a deploy are DS102 (DROP TABLE) and DS103 (DROP COLUMN).

    Terminal window
    atlas migrate lint --env local --latest 1
    # Expected: no DS102 / DS103. STOP if either appears — back up the DB and get explicit approval first.
    • ✅ Lint is clean, or a destructive finding was handled (database backed up, explicit approval obtained, tested on staging first).

5. Deploy develop → staging → production

Section titled “5. Deploy develop → staging → production”

With the gate clear, run the standard deploy sequence. Each environment gets a deploy, then a human test, before the next one — staging catches what local missed; production is verified the moment it’s live.

  1. For a big change, merge the feature branch back into develop first. Skip for small changes already on develop.

    Terminal window
    git checkout develop && git merge NewFeature/descriptive-name
    # Expected: the feature branch is merged into develop
    • ✅ All the work is on develop before promotion begins.
  2. Push develop, then promote to staging and deploy.

    Terminal window
    git push origin develop
    git checkout staging && git merge develop && git push origin staging
    dep deploy staging
    # Expected: zero-downtime release completes on the staging server
    • ✅ Staging deployed cleanly — then 👤 test on the staging URL and confirm the change works.
  3. Promote staging to production and deploy. Only after staging tested clean.

    Terminal window
    git checkout production && git merge staging && git push origin production
    dep deploy production
    # Expected: zero-downtime release completes on the production server
    • ✅ Production deployed — then 👤 test critical paths on production (login, checkout, the changed feature).

A live deploy isn’t done until it’s labelled and backed up. Tag the version, mirror production into main, and return to develop so the next change starts from a clean, deployable base.

  1. Tag the release, update main, and return to develop. Version scheme: first update after a major is vX.X.X-a; subsequent ones -b, -c; a significant change gets a new vX.X.Y.

    Terminal window
    git tag -a v[VERSION] -m "[Description]"
    git push origin v[VERSION]
    git checkout main && git merge production && git push origin main
    git checkout develop
    # Expected: tag pushed, main mirrors production, you're back on develop
    • ✅ The version is tagged, main matches production, and you’re on develop again. Update CHANGELOG.md if the change was significant; delete the temp branch only with user confirmation.

Do not mark this step done until every box below is checked.

  • 🤖 Branches synced — on develop, up to date; develop..staging and staging..production both empty.
  • 🤖 Committed with type — the change is committed with the right prefix (T3 Add-Feature, T2 Fix-Bug, etc.).
  • 🔀 DB gate clearedmigrate:status reviewed, Atlas lint clean (or destructive finding backed up + approved). No DS102/DS103 shipped unguarded.
  • 👤 Staging tested — the change verified on the staging URL before promoting.
  • 👤 Production tested — critical paths verified on production after deploy.
  • 🤖 Tagged + main updated — version tag pushed, main mirrors production, back on develop.