From 21cb5c9c15e8cfb546bb20ad519464a73c1af05e Mon Sep 17 00:00:00 2001 From: Codex Date: Tue, 28 Apr 2026 09:04:03 +0800 Subject: [PATCH] Document local database production deployment --- REDIRECTS.md | 3 +- docs/deployment-runbook.md | 29 ++- docs/local-db-to-production-deployment.md | 227 ++++++++++++++++++++++ docs/production-release-checklist.md | 2 + next.config.mjs | 3 +- 5 files changed, 252 insertions(+), 12 deletions(-) create mode 100644 docs/local-db-to-production-deployment.md diff --git a/REDIRECTS.md b/REDIRECTS.md index efd9db5..e4d576a 100644 --- a/REDIRECTS.md +++ b/REDIRECTS.md @@ -85,7 +85,8 @@ Locale is inferred from the user's current site locale, not from the legacy URL ## Footer / Secondary Links | Legacy | New | Code | |---|---|---| -| `/Support/tutorial.html` | `/{locale}/support` (or `/{locale}/support/tutorials` TBD) | 301 | +| `/Support/tutorial.html` | `/{locale}/support/tutorial` | 301 | +| `/Support/tutorial/target/.html` | `/{locale}/support/tutorial` | 301 | | `/Contact/afterservice.html` | `/{locale}/support/warranty` | 301 | | `/Contact/distributor.html` | `/{locale}/dealers` | 301 | | `/Contact/oem.html` | `/{locale}/support/contact` | 301 | diff --git a/docs/deployment-runbook.md b/docs/deployment-runbook.md index 059a83c..47cdcb3 100644 --- a/docs/deployment-runbook.md +++ b/docs/deployment-runbook.md @@ -2,6 +2,8 @@ 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. @@ -28,16 +30,23 @@ Optional variables: ## Deployment Steps -1. Restore the approved PostgreSQL dump into the production database. -2. Copy `media/` and `files/` to the production persistent upload volume. -3. Install dependencies with `npm ci`. -4. Run `npm run generate:types` only during build validation, not as a production data mutation step. -5. Run `npm run typecheck`. -6. Run `npm run build`. -7. Run `npm run payload:migrate`. -8. Run `npm run payload:migrate:status` and confirm every migration is `Yes`. -9. Start the app with `npm run start`. -10. Run `npm run smoke -- "$NEXT_PUBLIC_SITE_URL"`. +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`. +5. Restore the approved PostgreSQL dump into the production database with `pg_restore --no-owner --no-acl`. +6. Copy `media/` and `files/` 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"`. ## Data Rules diff --git a/docs/local-db-to-production-deployment.md b/docs/local-db-to-production-deployment.md new file mode 100644 index 0000000..d88aa51 --- /dev/null +++ b/docs/local-db-to-production-deployment.md @@ -0,0 +1,227 @@ +# 本地数据库导线上部署文档 + +这份文档用于把当前本地 Payload/Next.js 站点完整搬到线上:代码、PostgreSQL 数据库、`media/` 图片库、`files/` 下载文件必须来自同一次导出。 + +## 1. 上线前原则 + +- 线上只使用迁移,不使用 schema push。 +- 线上启动不自动跑迁移,迁移必须作为单独发布步骤执行。 +- 本地导出的数据库和 `media/`、`files/` 目录必须成套,不要混用不同时间点的文件。 +- 导入线上后不要再跑 seed 脚本,seed/backfill 只应该在本地确认好,再随数据库 dump 一起带上去。 +- 如果启动或迁移时出现删除旧表、schema push、交互确认提示,先停止,不要继续确认。 + +## 2. 线上环境变量 + +线上 `.env` 至少需要: + +```bash +NODE_ENV=production +NEXT_PUBLIC_SITE_URL=https://www.eversolo.com +PAYLOAD_SECRET=<用 openssl rand -base64 48 生成的长随机字符串> +DATABASE_URI=postgres://:@:5432/ +PAYLOAD_DB_PUSH=false +PAYLOAD_RUN_MIGRATIONS_ON_START=false +``` + +说明: + +- `PAYLOAD_SECRET` 不能用示例值,也不能和本地随便共用短值。 +- `PAYLOAD_DB_PUSH=false` 是为了避免 Payload 用当前 schema 直接改库。 +- `PAYLOAD_RUN_MIGRATIONS_ON_START=false` 是为了避免应用启动时弹迁移交互提示,迁移改用 `npm run payload:migrate` 手动执行。 + +## 3. 本地导出前检查 + +在本地项目目录执行: + +```bash +set -a +source .env +set +a + +git status --short +npm run lint +npm run typecheck +npm run build +npm run payload:migrate:status +``` + +检查本地数据库里不能有 Payload dev schema push 标记: + +```bash +psql "$DATABASE_URI" -Atc "select count(*) from payload_migrations where batch = -1;" +``` + +期望输出是: + +```text +0 +``` + +如果不是 `0`,说明这个库还带有开发期 schema push 记录。不要导出这个库去线上,先在本地对齐迁移状态后再导出。 + +建议再跑一次本地 smoke: + +```bash +npm run smoke -- http://localhost:3221 +``` + +## 4. 导出本地数据库和上传目录 + +在本地项目目录执行: + +```bash +EXPORT_DIR="release-exports/$(date +%Y%m%d-%H%M%S)" +mkdir -p "$EXPORT_DIR" + +pg_dump \ + --format=custom \ + --no-owner \ + --no-acl \ + --file="$EXPORT_DIR/eversolo.payload.dump" \ + "$DATABASE_URI" + +tar -czf "$EXPORT_DIR/eversolo.uploads.tgz" media files + +shasum -a 256 "$EXPORT_DIR/eversolo.payload.dump" "$EXPORT_DIR/eversolo.uploads.tgz" \ + > "$EXPORT_DIR/SHA256SUMS.txt" +``` + +导出目录里应该有: + +```text +eversolo.payload.dump +eversolo.uploads.tgz +SHA256SUMS.txt +``` + +把整个目录传到服务器,例如: + +```bash +rsync -av "$EXPORT_DIR/" deploy@your-server:/srv/eversolo-release/ +``` + +## 5. 线上恢复数据库 + +在服务器上进入发布目录,先确认校验和: + +```bash +cd /srv/eversolo-release +shasum -a 256 -c SHA256SUMS.txt +``` + +恢复到线上 PostgreSQL。 + +如果是新空库: + +```bash +pg_restore \ + --no-owner \ + --no-acl \ + --dbname "$DATABASE_URI" \ + eversolo.payload.dump +``` + +如果是替换已有测试库或预发布库,并且你已经确认可以清掉旧数据: + +```bash +pg_restore \ + --clean \ + --if-exists \ + --no-owner \ + --no-acl \ + --dbname "$DATABASE_URI" \ + eversolo.payload.dump +``` + +恢复后检查迁移标记: + +```bash +psql "$DATABASE_URI" -Atc "select count(*) from payload_migrations where batch = -1;" +npm run payload:migrate:status +``` + +`batch = -1` 应该是 `0`,`payload:migrate:status` 应该显示迁移已应用。若代码里有比 dump 更新的迁移,再执行: + +```bash +npm run payload:migrate +npm run payload:migrate:status +``` + +## 6. 线上恢复媒体文件 + +在服务器应用目录或持久化上传卷目录执行: + +```bash +tar -xzf /srv/eversolo-release/eversolo.uploads.tgz -C /srv/eversolo-app/ +``` + +如果线上使用单独的持久化 volume,把解压后的目录同步到 volume: + +```bash +rsync -a --delete /srv/eversolo-app/media/ /srv/eversolo-uploads/media/ +rsync -a --delete /srv/eversolo-app/files/ /srv/eversolo-uploads/files/ +``` + +确认应用运行时能从项目根目录或挂载目录访问: + +```text +media/ +files/ +``` + +数据库里 media/files 记录只保存文件名和元数据,文件本体必须在对应目录里。 + +## 7. 构建和启动 + +在服务器应用目录执行: + +```bash +npm ci +npm run typecheck +npm run build +npm run payload:migrate +npm run payload:migrate:status +npm run start +``` + +如果使用 PM2/systemd/Docker,由进程管理器执行 `npm run start`,但迁移步骤仍然要在启动前单独跑。 + +健康检查: + +```bash +curl -f "$NEXT_PUBLIC_SITE_URL/api/health" +npm run smoke -- "$NEXT_PUBLIC_SITE_URL" +``` + +重点人工打开: + +```text +/en +/zh +/en/products/dmp-a10 +/en/reviews +/en/reviews?tab=reviews +/en/support +/en/support/tutorial +/en/dealers +/admin +``` + +## 8. 回滚 + +回滚要成套回滚: + +1. 切回上一版代码。 +2. 恢复上一版数据库 dump。 +3. 恢复上一版 `media/` 和 `files/`。 +4. 重新启动并跑 smoke。 + +线上不要默认执行 down migration 作为回滚方式;生产回滚优先恢复上一套数据快照。 + +## 9. 禁止操作 + +- 不要在线上设置 `PAYLOAD_DB_PUSH=true`。 +- 不要在线上用 `PAYLOAD_MIGRATING=true` 当常规启动方式。 +- 不要把数据库 dump 和不同时间点的 `media/`、`files/` 混用。 +- 不要导入线上后再跑 `npm run seed:import` 覆盖编辑内容。 +- 不要在生产已经跑过某个迁移后修改同名迁移文件;需要新建 forward migration。 diff --git a/docs/production-release-checklist.md b/docs/production-release-checklist.md index 7e73881..488964e 100644 --- a/docs/production-release-checklist.md +++ b/docs/production-release-checklist.md @@ -7,6 +7,7 @@ Use this checklist before every production deployment. - [ ] Working tree is clean. - [ ] Latest commit is the intended release commit. - [ ] `npm ci` succeeds from a clean install. +- [ ] Legacy tutorial redirects point to `/en/support/tutorial`. - [ ] `npm run typecheck` passes. - [ ] `npm run build` passes. - [ ] `npm run payload:migrate:status` shows all migrations as `Yes` on the release database. @@ -21,6 +22,7 @@ Use this checklist before every production deployment. - [ ] `PAYLOAD_DB_PUSH=false` is set. - [ ] `PAYLOAD_RUN_MIGRATIONS_ON_START=false` is set unless a one-off controlled migration boot is intentionally planned. - [ ] Upload directories `media/` and `files/` are persistent and backed up. +- [ ] Database dump and upload archive are generated from the same local release window. ## CMS Data diff --git a/next.config.mjs b/next.config.mjs index caf7067..3841253 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -28,7 +28,8 @@ const nextConfig = { { source: '/About/index.html', destination: '/en/about', permanent: true }, // Footer / secondary - { source: '/Support/tutorial.html', destination: '/en/support', permanent: true }, + { source: '/Support/tutorial.html', destination: '/en/support/tutorial', permanent: true }, + { source: '/Support/tutorial/target/:target.html', destination: '/en/support/tutorial', permanent: true }, { source: '/Contact/afterservice.html', destination: '/en/support/warranty', permanent: true }, { source: '/Contact/distributor.html', destination: '/en/dealers', permanent: true }, { source: '/Contact/oem.html', destination: '/en/support/contact', permanent: true },