# Production Deployment

ByteLift interactives are served as static files at:

```text
https://bytelift.ph/interactives/<game-directory>/
```

Nginx serves an immutable release snapshot. It does not serve the Git checkout,
repository documentation, deployment scripts, or Git metadata.

## Server Layout

```text
/srv/bytelift-interactives/repo
/var/www/bytelift-interactives/releases/<commit-sha>
/var/www/interactives -> /var/www/bytelift-interactives/releases/<commit-sha>
```

The server retains the active release and the two most recent releases.

## Initial Provisioning

Run these commands as `root` on `bytelift.ph`:

```sh
install -d -m 0755 /srv/bytelift-interactives
git clone git@github.com:nodalsense-apps/bytelift-interactives.git /srv/bytelift-interactives/repo

install -m 0644 \
  /srv/bytelift-interactives/repo/deploy/nginx/interactives-log-format.conf \
  /etc/nginx/conf.d/interactives-log-format.conf

install -d -m 0755 /etc/nginx/snippets
install -m 0644 \
  /srv/bytelift-interactives/repo/deploy/nginx/interactives-location.conf \
  /etc/nginx/snippets/interactives-location.conf
```

Add this line inside the HTTPS `server` block for `bytelift.ph`, before the
existing `location /` block:

```nginx
include /etc/nginx/snippets/interactives-location.conf;
```

Validate and reload Nginx:

```sh
nginx -t
systemctl reload nginx
```

## Deploy a Release

Deploy only reviewed commits that are reachable from `origin/master`:

```sh
/srv/bytelift-interactives/repo/scripts/deploy_production.sh <full-commit-sha>
```

The script fetches the commit, builds a static-only release, atomically updates
the active symlink, runs HTTPS smoke tests, and restores the previous release if
a smoke test fails.

## Verify

```sh
curl -fsSI https://bytelift.ph/
curl -fsSI https://bytelift.ph/interactives/adventure_time/
curl -fsSI https://bytelift.ph/interactives/connection/env.js
curl -sS -o /dev/null -w '%{http_code}\n' https://bytelift.ph/interactives/
```

The first three requests must return `200`; `/interactives/` must return `404`.

Access logs are written to `/var/log/nginx/interactives_access.log` using a
format that excludes query strings and referrers so launch tokens are not
recorded.

## Roll Back

Deploy one of the retained commit SHAs:

```sh
/srv/bytelift-interactives/repo/scripts/deploy_production.sh <previous-commit-sha>
```

No Nginx reload is required when switching releases.

## Synchronize Production Game Records

Generate the expanded catalog from a local repository checkout, then upload the
catalog and importer to the ignored Rails temporary directory:

```sh
node scripts/generate_game_manifest.js \
  --output /tmp/bytelift-interactive-games-manifest.json
ssh root@bytelift.ph \
  'install -d -m 0755 /root/bytelift-web/tmp/interactive_games_sync'
scp /tmp/bytelift-interactive-games-manifest.json \
  root@bytelift.ph:/root/bytelift-web/tmp/interactive_games_sync/manifest.json
scp scripts/sync_game_records.rb \
  root@bytelift.ph:/root/bytelift-web/tmp/interactive_games_sync/sync_game_records.rb
```

Run an idempotent dry run inside the Rails container:

```sh
cd /root/bytelift-web
docker compose exec -T \
  -e INTERACTIVE_GAMES_MANIFEST=/app/tmp/interactive_games_sync/manifest.json \
  app bin/rails runner /app/tmp/interactive_games_sync/sync_game_records.rb
```

Apply the validated catalog by adding `-e APPLY=1` to the same command. Re-run
without `APPLY=1` afterward; a successful idempotency check reports zero creates
and zero updates.
