# 生产数据库手工上线流程

## 1. 适用场景

本文档用于君鸿卡管系统**首次生产上线**时的数据库初始化，目标是：

1. **不依赖应用启动自动建表**
2. **人工创建生产库和表结构**
3. **人工导入基础数据**
4. **人工对齐 `schema_migrations` 版本**
5. 后续继续沿用 `migrations/` 中的新增迁移

> 截至 **2026-05-06**，仓库内最新迁移版本为 **140**。  
> 当前仓库缺少可直接用于“全新环境从 0 建表”的 `000114_squash_baseline`，因此首次生产上线建议走“**手工 schema 基线 + 手工基础数据导入 + 手工迁移版本对齐**”。

---

## 2. 上线原则

### 2.1 本次建议做的事

1. 从你确认过的**源库**生成一份生产首发 schema 基线 SQL
2. 在生产环境手工创建空数据库
3. 手工执行 schema 基线 SQL 建表
4. 导入基础数据
5. 手工写入 `schema_migrations=140`
6. 启动 API / Worker

### 2.2 本次不建议做的事

1. 不依赖应用自动建表
2. 不直接把当前活跃 `migrations/` 当作全新建库链路执行
3. 不把业务数据表（订单、卡、设备、钱包流水等）从测试库整库导入生产
4. 不直接复用测试环境里的密钥、回调地址、商户配置而不做复核

---

## 3. 基础数据范围

### 3.1 建议导入的非敏感基础数据

以下表建议从已确认的源库导出，再导入生产库：

1. `tb_permission`
2. `tb_role`
3. `tb_role_permission`
4. `tb_carrier`
5. `tb_commission_withdrawal_setting`
6. `tb_polling_config`
7. `tb_polling_concurrency_config`
8. `tb_polling_alert_rule`
9. `tb_data_cleanup_config`

### 3.2 建议单独处理的敏感基础数据

以下表包含支付、公众号、小程序、证书、密钥等敏感信息，建议单独导出或手工填充：

1. `tb_wechat_config`

### 3.3 不建议首发直接导入的数据

以下数据不属于“生产首发基础数据”，通常不要从测试库带入生产：

1. `tb_account`
2. `tb_account_role`
3. `tb_shop`
4. `tb_enterprise`
5. `tb_iot_card`
6. `tb_device`
7. `tb_order`
8. 各类钱包、流水、日志、审计、导入任务表

---

## 4. 关于表结构基线

### 4.1 建议默认排除的确认遗留表

以下两张表已具备明确“遗留/保留历史”的语义，生成生产首发 schema 基线时建议默认排除：

1. `tb_data_usage_record`
2. `tb_card_replacement_record_legacy`

### 4.2 建议保守保留、后续再评估的表

以下表当前在代码里的活跃引用较少或暂无数据，但仍不建议在首次生产上线时贸然删除，先按兼容方式保留更稳：

1. `tb_card_replacement_request`
2. `tb_number_card`
3. `tb_payment_merchant_setting`
4. `tb_dev_capability_config`

---

## 5. 交付文件

本目录对应的手工上线辅助文件位于：

`scripts/manual_db_release/`

按执行顺序主要包括：

1. `01_create_database.sql`
2. `02_generate_schema_baseline.sh`
3. `03_export_base_data_from_source.sh`
4. `04_import_base_data_into_target.sh`
5. `05_repair_base_data_sequences.sql`
6. `06_mark_schema_migrations.sql`
7. `07_verify_manual_release.sql`

---

## 6. 手工上线步骤

## 6.1 第一步：确定源库

源库应满足：

1. 结构版本已确认正确
2. 基础配置完整
3. 权限、角色、运营商、轮询配置经过业务验收

建议不要临时选一个“有人随手改过但未复核”的测试库。

---

## 6.2 第二步：手工创建生产数据库

先修改：

`scripts/manual_db_release/01_create_database.sql`

将其中的占位符替换为：

1. `__DB_NAME__`
2. `__DB_USER__`
3. `__DB_PASSWORD__`

然后执行：

```bash
psql "postgres://postgres:你的密码@生产PG主机:5432/postgres?sslmode=disable" \
  -f scripts/manual_db_release/01_create_database.sql
```

---

## 6.3 第三步：生成 schema 基线 SQL

使用脚本：

```bash
SOURCE_DSN="postgres://源库账号:源库密码@源库主机:5432/源库名?sslmode=disable" \
OUTPUT_SQL="/你的目录/00_schema_baseline.sql" \
bash scripts/manual_db_release/02_generate_schema_baseline.sh
```

默认会排除：

1. `schema_migrations`
2. `tb_data_usage_record`
3. `tb_card_replacement_record_legacy`

生成后请人工复核一次：

1. 是否包含你确认不需要的历史表
2. 是否错误带入测试专用对象
3. 是否包含意外的 `OWNER TO`
4. 是否包含不应该进入生产的注释性对象

---

## 6.4 第四步：在生产库执行 schema 基线

```bash
psql "postgres://junhong_cmp:CtCom1zBzPQbpVNf3rCNxH@cxd.whcxd.cn:16159/junhong_cmp_prod?sslmode=disable" \
  -v ON_ERROR_STOP=1 \
  -f /你的目录/00_schema_baseline.sql
```

执行后先不要急着启动应用，先导入基础数据。

---

## 6.5 第五步：导出基础数据

导出非敏感基础数据：

```bash
SOURCE_DSN="postgres://erp_pgsql:erp_2025@cxd.whcxd.cn:16159/junhong_cmp_test?sslmode=disable" \
bash scripts/manual_db_release/03_export_base_data_from_source.sh
```

如需连同微信配置一起导出：

```bash
SOURCE_DSN="postgres://erp_pgsql:erp_2025@cxd.whcxd.cn:16159/junhong_cmp_test?sslmode=disable" \
INCLUDE_SENSITIVE=1 \
bash scripts/manual_db_release/03_export_base_data_from_source.sh
```

导出结果会放到：

`scripts/manual_db_release/generated/`

> 注意：`generated/` 下的 SQL 可能包含密钥和证书内容，不要提交到 Git。

---

## 6.6 第六步：导入基础数据

在生产库执行：

```bash
TARGET_DSN="postgres://junhong_cmp:CtCom1zBzPQbpVNf3rCNxH@cxd.whcxd.cn:16159/junhong_cmp_prod?sslmode=disable" \
bash scripts/manual_db_release/04_import_base_data_into_target.sh
```

如需导入敏感配置：

```bash
TARGET_DSN="postgres://生产库账号:生产库密码@生产库主机:5432/生产库名?sslmode=disable" \
INCLUDE_SENSITIVE=1 \
bash scripts/manual_db_release/04_import_base_data_into_target.sh
```

---

## 6.7 第七步：修正序列值

```bash
psql "postgres://junhong_cmp:CtCom1zBzPQbpVNf3rCNxH@cxd.whcxd.cn:16159/junhong_cmp_prod?sslmode=disable" \
  -v ON_ERROR_STOP=1 \
  -f scripts/manual_db_release/05_repair_base_data_sequences.sql
```

这一步用于避免显式插入 ID 后，自增序列仍停留在旧值。

---

## 6.8 第八步：手工对齐迁移版本

```bash
psql "postgres://生产库账号:生产库密码@生产库主机:5432/生产库名?sslmode=disable" \
  -v ON_ERROR_STOP=1 \
  -f scripts/manual_db_release/06_mark_schema_migrations.sql
```

执行后，生产库会被视为已处于 `140` 版本。  
后续如果仓库新增 `141+` 迁移，就可以继续正常执行 `migrate up`。

> 如果你上线时仓库最新迁移版本已经不是 `140`，记得同步修改 `06_mark_schema_migrations.sql`。

---

## 6.9 第九步：上线前校验

```bash
psql "postgres://生产库账号:生产库密码@生产库主机:5432/生产库名?sslmode=disable" \
  -f scripts/manual_db_release/07_verify_manual_release.sql
```

重点关注：

1. `schema_migrations.version=140`
2. 权限、角色、角色权限数量不为 0
3. 运营商配置数量不为 0
4. 轮询配置数量不为 0
5. `tb_wechat_config` 是否按预期导入

---

## 6.10 第十步：启动应用

确认以下环境变量改为生产值：

1. `JUNHONG_DATABASE_HOST`
2. `JUNHONG_DATABASE_PORT`
3. `JUNHONG_DATABASE_USER`
4. `JUNHONG_DATABASE_PASSWORD`
5. `JUNHONG_DATABASE_DBNAME`
6. `JUNHONG_REDIS_*`
7. `JUNHONG_JWT_SECRET_KEY`

特别注意：

1. 当前仓库里的 `docker-compose.prod.yml` 示例仍是测试库参数，不能原样直接用于生产
2. 如果生产库里没有超级管理员账号，应用启动时会自动创建一个超级管理员账号
3. 如不希望使用默认超管账号，请提前设置 `JUNHONG_DEFAULT_ADMIN_USERNAME`、`JUNHONG_DEFAULT_ADMIN_PASSWORD`、`JUNHONG_DEFAULT_ADMIN_PHONE`

---

## 7. 推荐执行顺序汇总

```text
手工创建生产库
  -> 生成 schema 基线 SQL
  -> 执行 schema 基线 SQL
  -> 导出基础数据
  -> 导入基础数据
  -> 修正序列
  -> 写入 schema_migrations=140
  -> 校验
  -> 启动 API / Worker
```

---

## 8. 风险提醒

### 8.1 关于 `tb_wechat_config`

该表包含敏感配置，建议：

1. 单独导出
2. 单独传输
3. 单独审批
4. 导入后立刻校验回调地址、商户号、证书内容

### 8.2 关于账号初始化

本次流程**不建议**直接从测试库导入 `tb_account`。  
首发生产环境建议只导入权限体系和系统配置，让生产超管账号在受控条件下独立创建。

### 8.3 关于后续迁移

本次只是首次生产上线的“人工基线落地”。  
后续版本发布仍应继续补齐正式的 `000114_squash_baseline`，避免长期依赖手工基线流程。
