Flask 单数据库迁移配置说明。

共享数据库安全策略：
- 在 `migrations/ownership.py` 中配置本服务拥有的表/字段范围。
- 可选环境变量：`MIGRATION_OWNED_TABLES=table_a,table_b`。
- 自动差异仅比较“模型定义 + owned 范围”内对象。
- 所有 `drop_*` 破坏性操作都会被阻断，不会自动执行删除。

迁移阶段说明：
- `expand`：新增表/字段，执行低风险结构修改。
- `contract`：执行高风险结构修改（例如收紧 nullable、缩短长度）。

推荐执行顺序（生产）：
- `flask schema-plan --phase expand`
- `flask schema-upgrade --phase expand`
- 发布应用
- `flask schema-verify --phase contract`
- `flask schema-upgrade --phase contract`

兼容别名（仍可用，但建议迁移到新命名）：
- `db-safe-plan`
- `db-safe-verify`
- `db-safe-migrate`
- `db-safe-upgrade`

“同步版本”通常有两种场景，你可以这样做。

```powershell
# 1) 设置 CLI 入口
$env:FLASK_APP = "manage:app"
```

1. **首次接管已有数据库（库里有业务表，但没有 alembic_version）**  
用这条即可，它会自动做 `stamp head` 再升级：
```powershell
flask schema-upgrade --phase expand
```

2. **你改了 models，想生成“同步变更”的新版本文件**  
先确保数据库在最新，再生成迁移版本：
```powershell
flask schema-migrate --phase expand -m "sync models"
```

3. **执行并同步到数据库**
```powershell
flask schema-upgrade --phase expand
```

4. **如果有高风险收敛变更（如 nullable 收紧、长度缩短）**
```powershell
flask schema-verify --phase contract
flask schema-upgrade --phase contract
```

自动生成迁移时的建表顺序规则：
- 新增表会按外键依赖自动重排，尽量保证被依赖表先创建。
- 循环依赖用强连通分量（SCC）识别：只把「同一 SCC 内部」的外键延后为 `op.create_foreign_key(...)`；指向 SCC 外部的外键仍内联并参与排序（避免误拆非环依赖）。
- 单表自引用也属于环，会把该自引用外键单独延后。
- 如果新增表之间存在循环外键，成环的 FK 会改写为后续 `op.create_foreign_key(...)`，先建表再补约束。
- 这项改写只影响 autogenerate 生成出的脚本结构，不改变后续 `drop_*` 安全过滤和阶段过滤行为。
