Skip to content

018.2 — Manual Deployment Runbook (No AI Agent)

Purpose: a pure copy-paste command sequence for release history + staging deploy + production deploy, for when there's no Claude Code agent available — a bare terminal, a different operator, or a CI box. No explanation, no judgment calls beyond what's marked. 018 has the full reasoning behind every step below; 018.1 is the same work done by asking an agent instead of typing this.

Audience: whoever is at the keyboard doing the release by hand.

How to use this page: work top to bottom inside the section for what you're deploying. Every step is either a command block (run it) or an explicit manual/UI action (marked MANUAL). Three decisions can't be scripted — they're called out inline, each as one line, not a paragraph: semver bump size, highlights wording, and highlights.portal tagging.


0 — Preflight (every target, every time)

cd /Users/abadr/Documents/Laplace/Projects/odoo19/next_ecommerce
git fetch origin && git status -sb                 # how far behind origin/main?
git pull --ff-only origin main                      # only if behind AND tree is clean
git branch -a | grep -iE "bump|release/"             # leftover unmerged release branch?

cd /Users/abadr/Documents/Laplace/Projects/odoo19/addons_lp_ecommerce
git fetch origin && git status -sb
git pull --ff-only origin main
git branch -a | grep -iE "bump|release/"

If a leftover branch exists and main has moved past it: don't build on it or reuse its name — branch fresh with a different name, and tell whoever owns the other branch it's superseded. Don't force-delete or force-push over it.


1 — Frontend staging deploy (next_ecommerce)

1.1 — Decide the version bump

Bump When
Patch (1.2.0 → 1.2.1) Bug-fix-only, nothing new to use
Minor (1.2.1 → 1.3.0) Adds something a user can see (new page/button/behaviour)
Major Not used on this project

1.2 — Find the diff range for this release

cd next_ecommerce
ls -t _docs/releases/*.json | grep -v _TEMPLATE | head -1        # latest release file
jq -r '.headCommit, .headCommitBackend' <that file>               # previous baseline SHAs

git log --oneline <headCommit>..HEAD                               # frontend commits shipping now
cd ../addons_lp_ecommerce && git log --oneline <headCommitBackend>..HEAD   # backend commits since

headCommit/headCommitBackend are the previous release's branch-off point, not its own tip — the range includes that release's own bump commit. Cross-check against the previous file's changes array and drop anything already listed there.

1.3 — Write the release-note file

cp _docs/releases/_TEMPLATE.json _docs/releases/<new-version>.json

Fill in by hand: - version, date, environments (the env(s) you're deploying), pr (fill in after the PR exists) - headCommit = current git rev-parse HEAD (before this release's own bump commit) - headCommitBackend = git -C ../addons_lp_ecommerce rev-parse HEAD - changes — one bullet per commit from step 1.2, prefixed [frontend] or [backend] - highlights — business language, not commit-message jargon. "You can now…" / "Fixed an issue where…". Omit entirely for purely internal/technical changes. - highlights[].portal — check which files the commit actually touched (git diff-tree --no-commit-id --name-only -r <sha>), don't guess from the message: - client → files under client-portal routes (served from /) - amp → files under admin/** (served from /admin/*) - general → genuinely spans both, or portal-agnostic infra — a shared common/ui/** file alone does not make a fix general if every other touched file sits under one portal - backoffice → the change is actually in addons_lp_ecommerce, not next_ecommerce

1.4 — Bump the version in both places

Edit both (they must agree):

vim docker/<env>/.env.<env>                 # NEXT_PUBLIC_APP_VERSION=<new-version>
vim docker/<env>/docker-compose.yml         # services.next-portal.environment.NEXT_PUBLIC_APP_VERSION

<env> = one of training, pre-prod, staging-b2b, training-b2b. Edit only the environment(s) actually shipping.

1.5 — Build, upload, push to the server's registry

# single environment
bash docker/<env>/build_upload_amd64.sh --deploy

# all three staging envs at once (not `training` — deploy that one on its own)
bash docker/build_deploy_all_staging.sh
bash docker/build_deploy_all_staging.sh pre-prod staging-b2b     # subset

# re-push an already-built tar without rebuilding
TAR_PATH="$PWD/docker/build_releases/<env>/<env>_<version>_amd64.tar" \
  bash docker/<env>/build_upload_amd64.sh --no-build --deploy

This builds a linux/amd64 image tagged both <env> and <env>-<version>, saves a tar under docker/build_releases/<env>/, scps it to the server, then loads/retags/pushes both tags to 127.0.0.1:5000. It does not restart the running container.

1.6 — Redeploy the running stack — MANUAL, Portainer only

  1. Stacks → the stack for that environment → Editor.
  2. Update the stack with Re-pull image and redeploy enabled.
  3. If Portainer doesn't re-pull: remove the container and redeploy the stack to force it.

1.7 — Commit and sync GitHub

git add docker/<env>/.env.<env> docker/<env>/docker-compose.yml _docs/releases/<new-version>.json
git commit -m "release: <new-version> — <env>"
git push origin <branch>
# open the Azure DevOps PR, get it merged, then on main:
bash scripts/sync_github_from_azure.sh

1.8 — Verify

curl -s https://<env-portal-host>/release-history.json | jq '.[0]'   # new entry present
Also confirm in Portainer the stack is running the new image tag.


2 — Frontend production deploy (next_ecommerce)

Production has no manual build step and no review gate — pushing GitHub main is the deploy action itself, live within minutes. Do this only once validated on staging-b2b and pre-prod, and once any backend dependency has already reached Odoo.sh production.

2.1 — Write the release note and bump the version

Same as steps 1.2–1.3 above, but edit .env.production at the repo root instead of a docker/<env>/ file:

vim .env.production      # NEXT_PUBLIC_APP_VERSION=<new-version>

2.2 — Rehearse locally (the Worker build differs from the container build)

npm run preview:cloudflare

2.3 — Deploy — this command is the live production deploy

git add .env.production _docs/releases/<new-version>.json
git commit -m "release: <new-version> — production"
git push github main

2.4 — Sync the GitHub mirror going forward

bash scripts/sync_github_from_azure.sh

2.5 — Verify

curl -s https://b2b.samtia.com/release-history.json | jq '.[0]'
Confirm the Cloudflare Workers Build succeeded in the dashboard and the site serves the new version.


3 — Backend staging deploy (addons_lp_ecommerce)

The B2B team's own responsibility ends at the GitHub mirror sync in step 3.5 — from there, promotion onto any Odoo.sh branch (staging-b2b → pre-prod → training → production) is done exclusively by the ERP Team. There is no command below that does that promotion; don't look for one.

3.1 — Find the diff range

cd addons_lp_ecommerce
ls -t _docs/releases/*.md | grep -v _TEMPLATE | head -1     # latest release file
grep "Head commit" <that file>

git log --oneline <that-sha>..HEAD

Same caveat as the frontend: Head commit is the previous release's branch-off point, not its tip — cross-check against that file's own ## Changes and exclude anything already listed.

3.2 — Bump BUILD_NUMBER (mandatory, every deployable change)

grep -n BUILD_NUMBER ecommerce/controllers/build_info_api.py
# edit the constant, increment by 1

This is the only way to verify from outside whether a submodule update actually picked up this code.

3.3 — Check before bumping the manifest version

grep version ecommerce/__manifest__.py
grep "Module version" <latest release file>

If the manifest is already ahead of the latest release file (a feature/migration PR raised it already), leave it as-is — only move BUILD_NUMBER. Bumping it again skips a version for no reason.

3.4 — Write the release-note file

cp _docs/releases/_TEMPLATE.md _docs/releases/<module_version>_build<N>.md

Fill in: date, module version, build number, Head commit = git rev-parse HEAD (before this release's own bump commit), PR URL once known. ## Changes in plain business language, PR number in parentheses — not commit-message jargon.

3.5 — Commit, PR, merge, sync GitHub

git add ecommerce/controllers/build_info_api.py ecommerce/__manifest__.py \
        _docs/releases/<module_version>_build<N>.md
git commit -m "release: <module_version> build<N>"
git push origin <branch>

Direct push to main is rejected (TF402455) — open the PR:

https://dev.azure.com/TechnicalUnitedSA/ERP-Odoo/_git/addons_lp_ecommerce/pullrequestcreate?sourceRef=<branch>&targetRef=main

After it merges:

bash _docs/scripts/sync_github_from_azure.sh

3.6 — Verify once the ERP Team confirms promotion

curl -s https://staging-b2b-odoo.adv-photonx.com/ecommerce/api/build-info
- Matching build_number → live on that build. - Older number → submodule still points at an old SHA, or the custom domain is serving a stale numbered build (each push makes a new build; the custom domain must follow the branch). - 404 → build-info endpoint predates this deploy.


4 — Backend production

Not a command sequence — this is entirely the ERP Team's manual branch-promotion process (training → production, with Training-team UAT go/no-go in between). See 017 — Release Workflow Step Sequence. The only thing to run from this side is the same verification command as 3.6, pointed at https://www.samtia.com/ecommerce/api/build-info once told it shipped.


Quick copy block — frontend staging, start to finish

cd next_ecommerce
git fetch origin && git pull --ff-only origin main
#  ...write _docs/releases/<version>.json (step 1.3)
#  ...bump NEXT_PUBLIC_APP_VERSION in docker/<env>/.env.<env> + docker-compose.yml
bash docker/build_deploy_all_staging.sh
#  ...Portainer: Re-pull image and redeploy (MANUAL)
git add -A && git commit -m "release: <version> — <env>" && git push origin <branch>
#  ...merge PR, then:
bash scripts/sync_github_from_azure.sh

Quick copy block — backend staging, start to finish

cd addons_lp_ecommerce
git fetch origin && git pull --ff-only origin main
#  ...bump BUILD_NUMBER (and manifest version only if not already raised)
#  ...write _docs/releases/<module_version>_build<N>.md
git add -A && git commit -m "release: <module_version> build<N>" && git push origin <branch>
# open PR -> merge -> then:
bash _docs/scripts/sync_github_from_azure.sh
curl -s https://staging-b2b-odoo.adv-photonx.com/ecommerce/api/build-info

Troubleshooting

Symptom Fix
No such image: moby/buildkit:buildx-stable-1 docker pull moby/buildkit:buildx-stable-1
no space left on device during build docker builder prune -af && docker system prune -af
SCP/SSH auth failure confirm the public key is on the server (ssh-copy-id a.badr@192.168.2.32) or fix SSH_KEY_PATH in that env's .ssh.local
network lp-apps not found in Portainer create an external network named lp-apps
Frontend build-info/release-history.json doesn't show the new version confirm Portainer actually re-pulled (image digest, not just the tag)
Backend build-info returns an old number after a push ask the ERP Team to confirm the submodule SHA: git -C lp log --oneline -1