# 部署启动与数据库重建

本文记录本地开发、数据库重建和 Ubuntu 服务器部署的常用命令。

项目当前数据库迁移以新库初始化为主，主要结构在：

```text
apps/backend/src/db/migrations/001_init.sql
```

后端启动时会自动执行数据库迁移。迁移记录保存在数据库表 `schema_migrations`。

## 本地开发启动

首次启动：

```bash
cp .env.mac-docker.example .env
docker compose -f docker-compose.dev.yml up -d --build
```

日常启动：

```bash
docker compose -f docker-compose.dev.yml up -d
```

查看服务状态：

```bash
docker compose -f docker-compose.dev.yml ps
```

查看日志：

```bash
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`

## 本地重建数据库

如果迁移基线变化，或者需要清空本地测试数据，可以重建本地开发库。

只重建开发数据库，保留源码文件：

```bash
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 不存在，说明本地数据库 volume 名称可能不同，可以先查看：

```bash
docker volume ls | grep postgres_dev_data
```

也可以直接删除当前 dev compose 创建的所有 volume：

```bash
docker compose -f docker-compose.dev.yml down -v
docker compose -f docker-compose.dev.yml up -d --build
```

注意：`down -v` 会同时删除开发环境里的 `postgres_dev_data`、`backend_node_modules`、`frontend_node_modules` 等 volume。下次启动会重新安装依赖。

确认迁移结果：

```bash
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 filename FROM schema_migrations ORDER BY filename");
  console.log(result.rows.map((row) => row.filename).join("\n"));
} finally {
  await closeDb();
}
'
```

## 本地验证

后端：

```bash
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
```

前端：

```bash
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 lint
docker compose -f docker-compose.dev.yml exec -T frontend npm run build
```

手动执行迁移：

```bash
docker compose -f docker-compose.dev.yml exec -T backend npm run db:migrate
```

## 服务器首次部署

服务器建议使用 Ubuntu + Docker Compose。

进入项目目录后执行：

```bash
cp .env.server.example .env
```

编辑 `.env`，至少替换这些值：

```text
CADDY_SITE_ADDR
CLAIM_BASE_URL
POSTGRES_PASSWORD
DATABASE_URL
ADMIN_SESSION_SECRET
ADMIN_DEFAULT_USERS_JSON
```

生产 Docker 部署时，`DATABASE_URL` 如果连接 compose 内置 PostgreSQL，主机名应使用 `postgres`：

```text
DATABASE_URL=postgres://postgres:你的数据库密码@postgres:5432/order_site
```

不要写成：

```text
DATABASE_URL=postgres://postgres:你的数据库密码@127.0.0.1:5432/order_site
```

因为后端运行在容器内，容器内的 `127.0.0.1` 指向后端容器自己，不是 PostgreSQL 容器。

执行部署：

```bash
bash deploy/ubuntu-deploy.sh
```

脚本会自动：

- 检查 Docker 和 Docker Compose
- 检查 `.env` 是否仍有占位值
- 检查容器部署时 `DATABASE_URL` 是否误写成本机地址
- 修正 `apps/backend/data` 目录权限
- 构建并启动服务
- 等待健康检查通过
- 打印已应用数据库迁移

部署完成后查看服务：

```bash
docker compose ps
```

查看后端日志：

```bash
docker compose logs -f backend
```

## 服务器日常更新

拉取或上传新代码后，在项目目录执行：

```bash
bash deploy/ubuntu-deploy.sh
```

后端容器启动时会自动执行迁移，不需要单独手动跑迁移。

确认迁移记录：

```bash
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 filename FROM schema_migrations ORDER BY filename");
  console.log(result.rows.map((row) => row.filename).join("\n"));
} finally {
  await closeDb();
}
'
```

## 服务器重建数据库

下面命令会删除生产数据库数据。只适合新开发、测试服务器或确认不需要保留数据的场景。

停止服务：

```bash
docker compose down
```

只删除 PostgreSQL 数据 volume，保留 Caddy 证书和配置 volume：

```bash
docker volume rm order_site_postgres_data
```

重新部署：

```bash
bash deploy/ubuntu-deploy.sh
```

如果 volume 名称不确定，可以查看：

```bash
docker volume ls | grep postgres_data
```

不建议在生产服务器随手执行：

```bash
docker compose down -v
```

因为它会同时删除 `postgres_data`、`caddy_data`、`caddy_config`。这会清空数据库，并可能让 Caddy 重新申请证书。

## 常见问题

### 后端一直未 ready

查看诊断：

```bash
docker compose ps
docker compose logs --tail=120 backend
```

常见原因：

- `.env` 仍有 `change-me` 占位值
- `DATABASE_URL` 密码和已有 PostgreSQL volume 初始化密码不一致
- `DATABASE_URL` 在容器部署中误写成 `127.0.0.1`
- 后端迁移失败

### 修改了 `001_init.sql` 但旧库没有变化

`schema_migrations` 只记录迁移文件是否执行过。已经执行过 `001_init.sql` 的数据库，不会因为文件内容变化自动重跑。

新开发阶段如果不需要保留数据，直接重建数据库即可。

### 宿主机手动跑迁移连不上 `postgres`

`.env` 里的 `postgres` 主机名只在 Docker 网络里有效。宿主机直接跑迁移时需要临时使用宿主机地址：

```bash
cd apps/backend
DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/order_site npm run db:migrate
```

容器内执行迁移时继续使用 `.env` 中的 `postgres` 服务名即可。
