# BEMRIX Release & Recovery Runbook

Status: local deployment preparation. Public domain and hosting provider are not selected.
This is a stateless website release procedure, not a database backup or uptime guarantee.

## 1. Build and retain

Use Node 24 and the committed package-lock.json. Build on the same operating system and architecture as the target host: native image dependencies make a Windows artifact unsuitable for Linux. The prepared GitHub workflow builds on Linux; it has not been executed remotely.

```
npm ci
npm run test:seo
npm run test:deployment
node --test artifacts/relaydesk/domain.test.mjs
npm run build
npm run typecheck
npm run release:package
npm run release:smoke
```

The package command creates a new `releases/<Next-build-id>/` directory and refuses to overwrite an existing release. It copies the standalone server, public assets and `.next/static`. Source environment files are excluded. A SHA-256 inventory verifies the package contents before each smoke run; it detects changes but is not a signature or provenance certificate. The generated `.next/cache/` and `.next/server/route-cache/` directories are excluded because image processing and route responses write runtime caches. Compiled route code and build-time assets remain verified.

`artifacts/deployment/latest-release.json` records the new directory. Smoke results are saved as `artifacts/deployment/smoke-<build-id>.json`. Each run starts and stops its own loopback-only process on an available port. The output is a point-in-time check, not a continuous monitor.

The health endpoint tests process liveness only. Static pages, downloads, styles, image optimization, indexing rules and a missing route are tested separately. This application currently has no connected production database or email provider.

## 2. Configure the real environment

Leave NEXT_PUBLIC_SITE_URL blank until the public HTTPS origin is confirmed. Preview builds intentionally have no canonicals and an empty sitemap, and request no indexing. Set the confirmed origin before building the public release: public environment variables and page metadata are build-time values. Recheck all external demo links before launch.

Never put credentials into NEXT_PUBLIC variables. Inject server secrets through the chosen host's secret manager only when integrations actually need them. Review the resulting artifact before transferring it: build output can contain values embedded by application code even though raw .env files are excluded.

For a Node host, launch `node server.js` from the release directory using the provider's process manager with NODE_ENV=production, a chosen PORT and HOSTNAME=127.0.0.1 behind a reverse proxy. On a managed platform follow its binding requirements. Configure HTTPS, request limits, log retention, automatic restart and graceful traffic draining there. None of that infrastructure is provisioned by these scripts.

Next.js output reference: https://nextjs.org/docs/app/api-reference/config/next-config-js/output
Self-hosting reference: https://nextjs.org/docs/app/guides/self-hosting

## 3. Promote only after verification

Keep the current release active. Start the candidate on a separate port/environment, verify its manifest and run the smoke checks. Record the current and candidate build IDs. Test the public proxy path, HTTPS, mobile navigation and contact journey. Only then switch the provider's routing to the candidate using that host's documented mechanism. Keep the old release available through the agreed observation period.

Check `/api/health/` from outside the hosting network after promotion. Run `npm run check:health -- https://YOUR_CONFIRMED_DOMAIN` from an operator checkout. This is a one-shot command and returns nonzero for a failed health response; scheduling and alerts are not installed. Configure an external monitor and verify alert delivery with the account owner before promising coverage.

The custom server-error hook writes a small JSON event to stderr without request headers, query values or error text. Next.js may emit its own diagnostic logs; configure access and retention accordingly. No remote log service is connected.

## 4. Roll back deliberately

If the candidate fails key journeys, the health signal or asset delivery, pause promotion (or route traffic back if already promoted). Do not rebuild the previous revision in place. Select the retained known-good release, verify its file manifest, start it under the process manager and repeat the smoke checks against it. Restore routing using the host's release switch, then check the public URL and record the incident and release IDs. Keep the failed candidate for investigation.

Local rehearsal: after two distinct builds have been packaged and passed, run `node scripts/deployment/recovery.mjs releases/PREVIOUS_ID releases/CANDIDATE_ID`. This checks candidate then retained previous package and records the order. It proves retained-package recovery locally, not a load-balancer switch, zero downtime or recovery time on a live host.

This rollback restores application files only. If a database, uploaded files or an external integration is introduced, design a compatible migration and data backup/restore procedure first. Browser-local RelayDesk records are not server backups.

## 5. Before public launch

- Confirm domain ownership, DNS, HTTPS and hosting account access.
- Build and verify on the target platform; configure the public origin and check sitemap/canonicals.
- Verify the enquiry journey and intended destination; do not assume message delivery is connected.
- Configure process restart, protected logs, external monitoring and an alert recipient.
- Decide artifact retention and off-host backup needs; rehearse restoring them.
- Repeat the rollback drill through the real hosting/routing layer.

CI reference: https://docs.github.com/en/actions/tutorials/build-and-test-code/nodejs
Artifact reference: https://github.com/actions/upload-artifact
