- 原 108/111/112/113/114 合并为 108_finance_cost_integrity: 成本异常归档、人工成本完整性、影子总账、商品页/模板查询索引 - 原 115 注释迁移改为 111_work_order_share_cancel_reason_comment - 新增 reconcile-migration-history.sql,用于已跑旧 112–115 的库 重建 schema_migrations 顺序,不重复执行 DDL - 已验证:001→111、101→111 两条升级路径; 旧 115 与新 111 的 pg_dump schema 完全一致 - 测试/文档迁移编号同步到 103–111 验证:backend check 853(849 pass / 4 skip);frontend check 172 + build。
10 KiB
部署启动与数据库重建
本文记录本地开发、数据库迁移、重建库和 Ubuntu 服务器部署的常用命令。
数据库迁移策略
项目使用 node-pg-migrate,迁移目录:
apps/backend/src/db/migrations/
001_init.sql 空库基线(完整结构)
002_xxx.sql 后续增量(示例命名)
003_xxx.sql
...
记录表:schema_migrations。
| 场景 | 行为 |
|---|---|
| 全新空库 | 按序号执行 001_init → 全部增量 |
| 已有库升级 | 只执行尚未记录的增量文件 |
| 改历史迁移文件内容 | 不会自动重跑;已应用文件禁止修改 |
约定:
001_init.sql只作为基线;上线后结构变更不要改它。- 每次 schema 变更新增
NNN_name.sql(三位序号)。 - 迁移与业务代码同一变更一起提交。
- 后端启动会自动
up;也可用命令手动执行。
开发常用命令
# 查看本地文件与库内已应用记录
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:status
# 手动执行未应用迁移
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate
# 创建下一份增量迁移模板
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:create -- add_column_example
宿主机直连(postgres 主机名仅在 Docker 网络内有效):
cd apps/backend
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate:status
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate
本地开发启动
首次:
cp .env.mac-docker.example .env
docker compose -f docker-compose.dev.yml up -d --build
日常:
docker compose -f docker-compose.dev.yml up -d
状态与日志:
docker compose -f docker-compose.dev.yml ps
docker compose -f docker-compose.dev.yml logs -f backend
docker compose -f docker-compose.dev.yml logs -f frontend
本地入口:
- 前端、后台、领取页:
http://localhost - 健康检查:
http://localhost/health - 就绪检查:
http://localhost/health/ready
本地重建数据库
仅在需要清空开发数据,或本地库与迁移历史严重不一致时使用。
只重建开发库 volume:
docker compose -f docker-compose.dev.yml down
docker volume rm order_site_postgres_dev_data
docker compose -f docker-compose.dev.yml up -d --build
volume 名称不确定时:
docker volume ls | grep postgres_dev_data
删除当前 dev compose 全部 volume(会重装 node_modules volume):
docker compose -f docker-compose.dev.yml down -v
docker compose -f docker-compose.dev.yml up -d --build
确认迁移记录:
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:status
或:
docker compose -f docker-compose.dev.yml exec -T backend node --input-type=module -e '
const { query, closeDb } = await import("./src/db/client.ts");
try {
const result = await query("SELECT COALESCE(filename, name) AS name FROM schema_migrations ORDER BY COALESCE(filename, name)");
console.log(result.rows.map((row) => row.name).join("\n"));
} finally {
await closeDb();
}
'
本地验证
docker compose -f docker-compose.dev.yml exec -T backend npm test
docker compose -f docker-compose.dev.yml exec -T backend npm run typecheck
docker compose -f docker-compose.dev.yml exec -T backend npm run build
docker compose -f docker-compose.dev.yml exec -T frontend npm run typecheck
docker compose -f docker-compose.dev.yml exec -T frontend npm run build
服务器首次部署
建议 Ubuntu + Docker Compose。
cp .env.server.example .env
至少配置:
APP_DOMAIN
CADDY_SITE_ADDR
WORKER_SITE_ADDR
CLAIM_BASE_URL
POSTGRES_PASSWORD
DATABASE_URL
ADMIN_SESSION_SECRET
ADMIN_DEFAULT_USERS_JSON
CORS_ALLOWED_ORIGINS
STORAGE_MODE
STORAGE_OSS_ENDPOINT
STORAGE_OSS_BUCKET
STORAGE_OSS_ACCESS_KEY_ID
STORAGE_OSS_SECRET_ACCESS_KEY
STORAGE_OSS_REGION
其中 APP_DOMAIN、CORS_ALLOWED_ORIGINS 与 STORAGE_MODE=oss / STORAGE_OSS_* 为生产必需:docker-compose.yml:95 的 STORAGE_MODE 生产默认即 oss,apps/backend/src/config/runtime-validation.ts:107-114 在生产环境强制校验 STORAGE_OSS_* 凭据并使用显式 CORS 域名白名单;.env.server.example 已给出这些变量的模板值,其中带 change-me 的占位会被 deploy/ubuntu-deploy.sh 的占位值检查拦住,需替换为真实值。
容器内连接 Compose PostgreSQL 时,主机名用 postgres:
DATABASE_URL=postgres://postgres:你的数据库密码@postgres:5432/order_site
不要写成容器内的 127.0.0.1(那会指向后端容器自己)。
部署:
bash deploy/ubuntu-deploy.sh
脚本会:检查 Docker、检查 .env 占位值、检查 DATABASE_URL、修正 apps/backend/data 权限、按改动决定重建哪一端、启动、等待健康检查、打印已应用迁移与各阶段耗时。
按需重建(默认行为)
脚本把「上次成功部署的 commit + .env 指纹」记在项目根的 .deploy-state(已 gitignore),
再按 git diff --name-only 上次commit..HEAD 判断本次要重建哪一端:
| 改动 | 结果 |
|---|---|
apps/backend/**(含 migrations) |
只重建 backend 镜像与容器 |
apps/frontend/**、deploy/caddy/**、前端 Dockerfile |
只重建 web 镜像与容器 |
README.md、docs/**、deploy/*.sh、deploy/lib/**、scripts/** |
不重建任何镜像,容器保持运行(只剩迁移 + 健康检查) |
docker-compose.yml、.env 变化、未知路径、上次 commit 不在仓库里(force push/回滚) |
两端都重建(保守兜底) |
不需要重建的一侧既不跑 Docker 构建、也不 --force-recreate;如果它恰好没在运行(服务器重启过),
脚本用现有镜像把它拉起来。首次在有 --skip-backup 之前用本脚本时没有 .deploy-state,
会按"全量重建一次"处理,之后即进入增量。
备份策略同理:本次改动不含 apps/backend/src/db/migrations/** 时自动跳过迁移前备份
(生产上 pg_dump + 传 OSS 接近 12 分钟);--backup 可强制备份,--skip-backup 可无条件跳过,
只有"能算出改动范围"时才会自动跳过。
常用参数:
| 参数 | 说明 |
|---|---|
--dry-run |
只打印计划后退出:上次部署的 commit、改动文件、要重建哪一端、是否备份、基础镜像 digest |
--all |
强制两端都重建 |
--backend-only / --web-only |
只重建指定一端 |
--backup |
强制迁移前备份 |
--skip-backup |
跳过迁移前备份 |
--reset-db / --yes |
见下文「服务器重建数据库」 |
基础镜像也只补缺:docker compose pull --ignore-buildable --policy missing
(不再每次部署重新校验 postgres tag,避免顺手把数据库镜像静默升级)。
docker compose ps
docker compose logs -f backend
财务/成本上线后的初始化(迁移 102–111)
代码与迁移只负责建表;备用金账户、积分余额、人工 SKU 配置不会自动创建。 首次上线后按 财务上线初始化与验收-2026-10-26.md 执行:
- 钱包管理 → 补建客服备用金账户 → 按需拨付;
- 商品与成本 → 积分钱包 → 给客服发放三平台积分;
- 商品与成本 → 人工 SKU 配置 → 扫描并逐项配置(保存后自动回填订单项);
- 打开「财务 → 总账与对账」,同步总账、检查试算平衡;按需关账/导入平台账单;
- 用手册 §二 的验收 SQL 检查:配置覆盖、人工成本快照、
manual_cost_missing、销售事实与总账对平。
历史人工成本不补录;人工成本监控从第一次创建人工履约配置的时间开始。 定时任务
cost-finance-sync每 5 分钟运行,负责履约归集、人工 SKU 回填、成本快照与销售事实。
服务器日常更新
cd /home/order_site && git pull
bash deploy/ubuntu-deploy.sh # 想看这次会做什么:加 --dry-run
后端启动时自动执行未应用的增量迁移,一般不必单独跑迁移。
确认:
docker compose exec -T backend node --input-type=module -e '
const { query, closeDb } = await import("./dist/db/client.js");
try {
const result = await query("SELECT COALESCE(filename, name) AS name FROM schema_migrations ORDER BY COALESCE(filename, name)");
console.log(result.rows.map((row) => row.name).join("\n"));
} finally {
await closeDb();
}
'
服务器重建数据库
会删除生产数据。仅适合新环境、测试机或确认可丢数据的场景。
docker compose down
docker volume rm order_site_postgres_data
bash deploy/ubuntu-deploy.sh
或:
bash deploy/ubuntu-deploy.sh --reset-db
volume 名不确定时:
docker volume ls | grep postgres_data
不要随手:
docker compose down -v
这会连同 caddy_data / caddy_config 一起删掉,可能触发证书重签。
常见问题
后端一直未 ready
docker compose ps
docker compose logs --tail=120 backend
常见原因:
.env仍有change-me占位值DATABASE_URL密码与已有 PostgreSQL volume 初始化密码不一致- 容器部署里
DATABASE_URL误写127.0.0.1 - 某次增量迁移 SQL 失败
改了 001_init.sql 但旧库没变
已应用过的迁移不会因文件内容变更而重跑。正确做法是 新增 002_xxx.sql 写增量。
仅本地可丢数据时,才用重建 volume 的方式对齐。
如何新增字段 / 索引
docker compose -f docker-compose.dev.yml exec -T backend \
npm run db:migrate:create -- add_orders_note
# 编辑生成的 apps/backend/src/db/migrations/00N_add_orders_note.sql
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate:status
宿主机手动跑迁移连不上 postgres
.env 里的 postgres 只在 Docker 网络有效。宿主机请临时改为 127.0.0.1 并映射端口。