# Upgrading a WebX11 instance

One command, with a safety net:

```bash
sudo deploy/update.sh --conf deploy/wx11.conf.local
```

## What it does, in order

1. `git pull --ff-only --autostash` (refuses a dirty tree unless `--force-dirty`).
2. Rebuilds the newOS4 bundles if `spaces/newos4/scripts/rebuild-bundles.py` exists.
3. Backs up the users DB with `sqlite3 .backup` (a plain `cp` can capture a torn database).
4. Re-renders `deploy/templates` and **reinstalls the systemd units** — a fork that only
   pulls code never receives unit or rate-limit fixes otherwise.
5. `nginx -t` on the rendered config before touching anything live.
6. Restarts the platform units.
7. Runs `deploy/verify.sh`; a non-zero exit means the upgrade is not finished.

## Pre-flight

```bash
cd $WX11_ROOT
git status --short          # must be clean, or stash deliberately
git log --oneline HEAD..@{u}  # what you are about to take
sqlite3 admin/security-test/users.db ".backup /var/lib/webx11/backups/pre-upgrade.db"
```

Read the target `CHANGELOG.md` entry. Anything marked **breaking** (unit names, env file
keys, vhost locations, DB columns) needs the release note followed by hand.

## Rollback

```bash
cd $WX11_ROOT
git checkout <previous-sha>          # or: git reset --hard <previous-sha>
sudo deploy/install-units.py         # regenerate units from the older tree
sudo deploy/update.sh --force-dirty
```

If only the units are wrong (not the code):

```bash
sudo tar xzf /home/<user>/wx11-backups/units-<stamp>.tgz -C /
sudo systemctl daemon-reload && sudo deploy/update.sh --force-dirty
```

`install.sh` keeps a vhost backup next to the live file (`sites-enabled/<domain>.bak-*`) and
`update.sh` never replaces the live vhost — only the `conf.d` snippet — so an upgrade cannot
take nginx down without `nginx -t` passing first.

## Migrations

One-shot scripts live in `api/` and are **not** run automatically:

```bash
python3 api/migrate-users.py
python3 api/migrate-marketplace.py
python3 api/migrate-skills.py
python3 api/migrate-feedback.py
python3 api/migrate-seller-billing.py
```

They are idempotent for the data they target, but run them by hand after a pull, one at a
time, checking the output. Always take the `.backup` first.

## newOS4 bundle rule (the classic "my change didn't appear")

Production loads `spaces/newos4/modules/core/core-bundle.js`, not the individual
`modules/**` files. After editing anything under `spaces/newos4/modules/core/`:

```bash
python3 spaces/newos4/scripts/rebuild-bundles.py
# then bump BOTH:
#   spaces/newos4/modules/core/module-loader.js  → LATEST_VER
#   spaces/newos4/main.html                      → ?v=<same value>
```

Skipping the version bump leaves browsers on cached modules. `update.sh` runs the rebuild
for you; the version bump is still manual by design (it is a user-visible cache key).

## Version

`deploy/VERSION` carries the release number. `federation_api` (in `node.json`) is the
protocol version — they move independently.
