# DEPLOY — dev → prod promotion workflow

> Strict order. Skip a step → break prod.

## Pre-flight

- [ ] testing/SMOKE-TEST.md passed on dev
- [ ] You can name the change in one sentence
- [ ] You have a rollback target (the current prod md5 — capture before deploy)

## Step 1 — capture current prod md5 (rollback anchor)

```bash
PROD_BEFORE=$(ssh user@nullstone 'md5sum /opt/docker/jellyfin/web-overrides/index.html' | awk '{print $1}')
echo "rollback anchor: $PROD_BEFORE"
```

If anything goes wrong: `cp /opt/docker/jellyfin/web-overrides/index.html.bak.<latest> /opt/docker/jellyfin/web-overrides/index.html` + restart.

## Step 2 — backup prod overlay + branding

```bash
ssh user@nullstone 'set -e
TS=$(date +%s)
docker run --rm --userns=host -v /opt/docker/jellyfin/web-overrides:/d:rw alpine cp /d/index.html /d/index.html.bak.deploy.$TS
docker run --rm --userns=host -v /home/docker/jellyfin/config/config:/d:rw alpine cp /d/branding.xml /d/branding.xml.bak.deploy.$TS
'
```

## Step 3 — copy dev overlay to prod via docker shim (root-owned dest)

```bash
ssh user@nullstone 'docker run --rm --userns=host -v /opt/docker/jellyfin-dev/web-overrides:/dev:ro -v /opt/docker/jellyfin/web-overrides:/prod:rw alpine sh -c "cp /dev/index-dev.html /prod/index.html && chown root:root /prod/index.html && md5sum /prod/index.html"'
```

## Step 4 — bind-mount inode swap requires restart

```bash
ssh user@nullstone 'docker restart jellyfin && sleep 14'
```

## Step 5 — verify

```bash
ssh user@nullstone 'docker exec jellyfin md5sum /jellyfin/jellyfin-web/index.html'   # should match dev's md5
ssh user@nullstone 'docker exec jellyfin curl -s http://127.0.0.1:8096/web/index.html | grep -c ARRFLIX-MIDDLE-THEME-BEGIN'   # = 1
ssh user@nullstone 'docker exec jellyfin curl -s http://127.0.0.1:8096/Branding/Css.css | wc -c'   # ~36000
ssh user@nullstone 'docker ps --format "{{.Names}} {{.Status}}" | grep "^jellyfin "'   # healthy
```

## Step 6 — manual smoke on prod

Open arrflix.s8n.ru in incognito. Run testing/SMOKE-TEST.md manual checklist.

## Step 7 — commit + push to repo

```bash
cd /tmp/arrflix-recon
cp web-overrides/index.html snapshots/2026-05-09-v6-stable/index.html  # update snapshot
git add bin/inject-middle-theme.py web-overrides/index.html snapshots/2026-05-09-v6-stable/index.html docs/  # whatever changed
git -c user.name=s8n -c user.email=admin@s8n.ru commit -m "<one-line summary>"
git push origin main
```

## If verify fails

Run `testing/ROLLBACK.md` immediately. Don't try to fix forward on prod.

## Common deploy gotchas

- Forget `docker restart jellyfin` after `cp` → bind-mount inode swap → container serves stale
- Forget `chown root:root` → user can't write but root needs to own per host config
- Forget snapshot bump → next "what's deployed" question gets wrong answer
- Forget commit → repo drifts from prod (per doc 26 INC1 root cause)
