105 lines
5.2 KiB
Markdown
105 lines
5.2 KiB
Markdown
# Deployment Runbook
|
|
|
|
This runbook is the source of truth for taking the Eversolo Payload/Next.js site from a local database and media folder to a production deployment.
|
|
|
|
For the command-level Chinese handoff guide, see `docs/local-db-to-production-deployment.md`.
|
|
|
|
## Release Inputs
|
|
|
|
- Git commit to deploy.
|
|
- PostgreSQL database dump exported from the approved local database.
|
|
- `media/`, `files/`, and `videos/` directories exported from the same local workspace as the database dump.
|
|
- Production environment variables from `.env.example`, filled with production values.
|
|
|
|
## Required Environment
|
|
|
|
Use Node.js 22 LTS or newer. The project declares `>=20.9.0`, but production should use one pinned LTS line.
|
|
|
|
Required variables:
|
|
|
|
- `NEXT_PUBLIC_SITE_URL`: public canonical origin, for example `https://www.eversolo.com`.
|
|
- `PAYLOAD_SECRET`: long random secret, never use the example value.
|
|
- `DATABASE_URI`: PostgreSQL connection string.
|
|
- `PAYLOAD_DB_PUSH=false`: production must use migrations, not schema push.
|
|
- `PAYLOAD_RUN_MIGRATIONS_ON_START=false`: production startup should not run migrations interactively.
|
|
|
|
Optional variables:
|
|
|
|
- `PORT`: runtime port for `next start`.
|
|
- `SMOKE_BASE_URL`: base URL used by `npm run smoke`.
|
|
|
|
## Deployment Steps
|
|
|
|
1. Run local release checks: `npm run lint`, `npm run typecheck`, `npm run build`, and `npm run payload:migrate:status`.
|
|
2. Load the local release environment with `set -a; source .env; set +a`, then confirm the local release database has no dev marker:
|
|
`psql "$DATABASE_URI" -Atc "select count(*) from payload_migrations where batch = -1;"`.
|
|
3. Export the approved PostgreSQL database:
|
|
`pg_dump --format=custom --no-owner --no-acl --file=eversolo.payload.dump "$DATABASE_URI"`.
|
|
4. Export matching uploads:
|
|
`tar -czf eversolo.uploads.tgz media files videos`.
|
|
5. Restore the approved PostgreSQL dump into the production database with `pg_restore --no-owner --no-acl`.
|
|
6. Copy `media/`, `files/`, and `videos/` to the production persistent upload volume.
|
|
7. Install dependencies with `npm ci`.
|
|
8. Run `npm run generate:types` only during build validation, not as a production data mutation step.
|
|
9. Run `npm run typecheck`.
|
|
10. Run `npm run build`.
|
|
11. Run `npm run payload:migrate`.
|
|
12. Run `npm run payload:migrate:status` and confirm every migration is `Yes`.
|
|
13. Start the app with `npm run start`.
|
|
14. Run `npm run smoke -- "$NEXT_PUBLIC_SITE_URL"`.
|
|
15. Log out of the admin, open `/admin/login`, and confirm the verification code is required before password validation.
|
|
|
|
## Deployment Package
|
|
|
|
Use `scripts/package-deploy.sh` when a server-ready source and build archive is needed.
|
|
|
|
```bash
|
|
NEXT_PUBLIC_SITE_URL=https://www.eversolo.com ./scripts/package-deploy.sh
|
|
```
|
|
|
|
The script runs `npm run build`, creates `deploy-packages/<timestamp>-deploy-nopublic-noenv/eversoloweb-deploy-nopublic-noenv-<timestamp>.tar.gz`, and writes a matching `manifest.txt`.
|
|
|
|
The archive intentionally excludes:
|
|
|
|
- `public/`
|
|
- upload/data directories that are deployed separately: `media/`, `files/`, and `videos/`
|
|
- `.env`, `.env.*`, and `.env.example`
|
|
- `node_modules/`
|
|
- `.git/`
|
|
- `deploy-packages/`
|
|
- `.next/cache/` and `.next-dev/`
|
|
- macOS metadata inside the archive, such as `._*`, `.DS_Store`, and `__MACOSX`
|
|
- common local logs, cache folders, test output, and temporary files
|
|
|
|
On APFS, macOS may still attach `com.apple.provenance` to the outer `.tar.gz` file even after `xattr -c`. The script prints that as a warning, but still fails if Apple metadata appears inside the archive contents.
|
|
|
|
`NEXT_PUBLIC_SITE_URL` must be the final public origin when the package is built. Do not build a deployment package with `localhost`, because sitemap, robots, canonical URLs, and metadata can be generated from this value.
|
|
|
|
If the build has already been run with the correct public URL and only the tarball needs to be recreated:
|
|
|
|
```bash
|
|
NEXT_PUBLIC_SITE_URL=https://www.eversolo.com SKIP_BUILD=1 ./scripts/package-deploy.sh
|
|
```
|
|
|
|
## Data Rules
|
|
|
|
- Do not run `PAYLOAD_DB_PUSH=true` against production.
|
|
- Do not rely on application startup to run migrations. Use the explicit migration step.
|
|
- Before exporting a local database for production, confirm `payload_migrations` has no `batch = -1` dev marker. That marker means schema push history is still recorded and production migration commands can prompt interactively.
|
|
- Do not edit migrations after they have shipped to production. Add a new forward migration instead.
|
|
- Keep schema migrations and data backfills separate. Backfill scripts in `src/scripts/` are manual operational tools, not automatic boot steps.
|
|
- The deployed database and upload directories must come from the same local export, otherwise media/video/file relationships can point at missing files.
|
|
- Admin login captcha is stateless and signed with `PAYLOAD_SECRET`; changing that secret invalidates existing login sessions and outstanding captcha tokens.
|
|
|
|
## Rollback
|
|
|
|
Rollback means switching code and data together:
|
|
|
|
1. Stop traffic or move traffic back to the previous deployment.
|
|
2. Restore the previous database dump.
|
|
3. Restore the matching previous `media/`, `files/`, and `videos/` directories.
|
|
4. Deploy the previous Git commit.
|
|
5. Re-run smoke checks before reopening traffic.
|
|
|
|
Do not run migration down scripts on production as the default rollback path.
|