# 企业资质文件迁移说明 ## 统一接口边界 企业资质的唯一真实上传入口是: ```http POST /api/merchant/v1/files/qualifications Content-Type: multipart/form-data ``` 表单字段为 `file`,可选字段为 `certificateNo`。File 服务先校验并保存真实图片,再通过内部接口通知 IAM 创建资质和审核记录。IAM 的商户资质接口只负责查询,不再提供 JSON 上传入口。 有效的商户预览地址格式为: ```text /api/merchant/v1/files/qualifications/{uuid}.jpg /api/merchant/v1/files/qualifications/{uuid}.png ``` 数据库中的 URL 不是文件本身。禁止只生成 UUID 并修改 `document_url`,也禁止用空文件或任意图片冒充营业执照。 ## 历史数据盘点 发布前先以只读方式盘点历史路径: ```sql SELECT id, tenant_id, qualification_type, document_url, status FROM baiyue_iam.iam_tenant_qualification WHERE deleted = 0 AND (document_url IS NULL OR document_url NOT REGEXP '^/api/merchant/v1/files/qualifications/[0-9a-fA-F-]{36}\\.(jpg|png)$'); ``` 盘点结果中的每条记录都必须找到原始图片。找不到原始图片时,将记录标记为“待业务补传”,不得伪造文件,也不得直接改 URL。 ## 可落地迁移步骤 1. 暂停对应资质的替换操作,记录资质 ID、租户 ID、旧 URL 和原文件校验和。 2. 从可信旧存储取得原始图片,校验文件签名、扩展名和不超过 5 MB 的大小限制。 3. 使用迁移工具按 File 服务同一规则生成 UUID 文件名,将真实文件写入共享存储的 `qualifications/{tenantId}/` 目录。 4. 写入完成后,从 File 服务平台预览接口读取新文件并核对 SHA-256;读取失败时不得修改数据库。 5. 在单条事务中按 `id + tenant_id + 旧 document_url` 条件更新 IAM 的 `document_url`。受影响行数不是 1 时立即回滚。 6. 再次通过平台预览接口验收;验收完成前保留旧文件和旧 URL 清单,以便回滚。 容器部署前必须确认 File 实例注册名为 `file-service`,Gateway 路由目标为 `lb://file-service`,并确认 `/data/files` 是持久卷且容器用户 UID 10001 可以实际创建和删除文件。镜像内的目录权限不会覆盖宿主机 bind mount 的属主;使用宿主机目录时,须先创建目录并把所有权授予 UID 10001。旧版本已创建的卷或目录可在维护窗口使用当前 File 镜像一次性修复后重启: ```sh docker compose --env-file <环境文件> -f deploy/docker-compose.yml run --rm --user 0 --entrypoint sh file -c 'chown -R 10001:10001 /data/files' ``` `/actuator/health` 通过后,还应执行一次脱敏图片上传和平台预览,验证 Gateway、Nacos、挂载和 IAM 协作的完整链路。 当前 File 服务使用本地或共享文件目录时,可先运行仓库内脚本生成真实文件、前向 SQL 和回滚 SQL: ```powershell .\scripts\migrate-local-qualification-file.ps1 ` -ImagePath D:\test-data\脱敏营业执照.png ` -StorageRoot D:\baiyue-firstleg-runtime\uploads ` -TenantId 10001 ` -QualificationId 资质ID ` -OldDocumentUrl /phase1-seed/demo-business-license.jpg ``` 脚本会校验文件大小、JPG/PNG 文件签名和复制前后 SHA-256,并生成带 `id + tenant_id + 旧 URL` 乐观条件的前向 SQL及回滚 SQL。脚本不会连接数据库,也不会在生成的 SQL 中自动提交事务;执行人员确认文件已落到 File 服务实际挂载目录后,才可人工执行前向 SQL,并在 `affected_rows = 1` 且平台预览校验成功后显式 `COMMIT`。否则必须 `ROLLBACK` 并删除本次新增文件。对象存储环境不使用该脚本,应通过 File 上传接口迁移。 数据库更新模板如下,执行时必须替换为经过文件校验的真实值: ```sql START TRANSACTION; UPDATE baiyue_iam.iam_tenant_qualification SET document_url = :verified_new_url WHERE id = :qualification_id AND tenant_id = :tenant_id AND document_url = :expected_old_url AND deleted = 0; -- 仅当 ROW_COUNT() = 1 且新文件已通过 File 预览校验时提交,否则回滚。 -- 执行人员检查后显式 COMMIT 或 ROLLBACK,模板不自动提交。 ``` ## 新环境初始化 初始化脚本不再创建 `/phase1-seed/...` 虚假资质。测试环境需要可下单的商户时,应使用脱敏但真实存在的 JPG/PNG 文件走 File 上传、平台审核完整流程,使租户达到 `ACTIVE` 且资质达到 `APPROVED`。初始化账号、文件和审核结果应作为一套环境数据验收,不得仅靠 SQL 绕过文件保存。 用于联调的样本必须在名称或图片水印中明确标注“仅供测试”,并登记租户 ID、资质 ID、文件 SHA-256 和创建时间。验收结束后按生成的回滚 SQL恢复原元数据并删除本次文件;若样本通过正常上传审核流程产生,应由测试数据清理流程按同一组标识回收,禁止直接删除仍被资质元数据引用的文件。