# 用户上传产品小册子解析与留存实施计划 > 文档版本:v1.0 > 编制日期:2026-07-30 > 适用范围:海报制作中的产品资料选择、产品小册子上传、解析、确认、留存和复用 > 建议优先级:P0 > 预计工作量:MVP 约 6 人日,建议预留 20% 风险缓冲 --- ## 一、结论 本需求不应直接把普通用户上传的小册子写入现有公共 `PptProduct` 产品库。 推荐新增“我的产品资料库”: 1. 用户可以继续选择后台已审核产品; 2. 找不到产品时,可以上传产品小册子 PDF; 3. 系统持久化保存原 PDF,并异步解析产品名称、产品卖点、保障亮点、币种、投保规则和风险提示; 4. 用户必须核对并确认解析结果,确认后才能生成文案和海报; 5. 已确认的小册子进入上传者的“我的产品资料”,以后可直接复用; 6. 用户资料默认私有,不对其他用户可见; 7. 只有显式提交并经管理员审核后,才允许转入公共产品库。 这一路径能复用现有 PDF 安全校验、小册子解析器、Celery、存储根目录和海报生成逻辑,同时避免未经审核的数据污染公共产品库。 --- ## 二、当前实现与问题定位 ### 2.1 已有能力 | 能力 | 当前实现 | 可复用结论 | |------|----------|------------| | 公共产品和小册子 | `PptProduct.manual_file_url`、`manual_parsed_rules`、`manual_parse_status` | 可作为公共产品库继续使用 | | 管理员上传小册子 | `PptAdminService.upload_manual()` | 可复用文件校验和存储思路 | | 小册子解析 | `poster/manual_parser.py::parse_manual_pdf()` | 直接复用产品规则提取 Schema | | 异步任务 | `parse_product_manual_task` + Celery | 新增用户资料解析任务,不另建队列 | | 客户计划书上传 | `/poster/case-upload`、`PosterCaseUpload` | 继续保留,不能与产品小册子混用 | | 海报文案和生成 | `PosterService.generate_copy()`、`generate_poster()` | 增加统一产品来源解析后复用 | | PDF 安全校验 | `prepare_pdf_upload()` | 直接复用大小、魔数、页数、密码处理 | | 持久化目录 | `get_storage_root()` | 用户小册子必须写入共享持久化卷 | ### 2.2 当前阻断点 1. `/poster/products` 只返回 `manual_parse_status=reviewed` 的公共产品。 2. 海报页面必须先选公共 `productId`,找不到产品时无法继续。 3. 当前 `/poster/case-upload` 上传的是客户计划书,并且强制绑定公共 `productId`。 4. `generate_copy()` 和 `generate_poster()` 都直接查询 `PptProduct`,不认识用户上传资料。 5. 普通用户没有自己的产品资料实体、列表、详情、删除和复用能力。 6. 当前小册子解析只支持管理员维护的公共产品,没有用户所有权校验。 7. 前端 `localStorage` 只保存当前草稿,不等于服务端永久留存。 ### 2.3 两类 PDF 必须分开 | 文件类型 | 主要内容 | 解析结果 | 生命周期 | |----------|----------|----------|----------| | 产品小册子 | 产品规则、卖点、币种、保障、风险提示 | `product_rules` | 可跨多个海报项目复用 | | 客户计划书 | 年龄、性别、保额、保费、缴费年期、利益表 | `customer_data` | 与本次客户和海报项目绑定 | 前端文案也应统一使用“产品小册子”和“客户计划书”,避免两者都显示为“计划书”。 --- ## 三、方案选择 ### 3.1 方案对比 | 方案 | 优点 | 风险 | 结论 | |------|------|------|------| | 直接创建全局 `PptProduct` | 改动表面较少 | 私有数据可能被其他用户看到;未经审核资料混入公共库;现有所有查询都要补权限 | 不采用 | | 给 `PptProduct` 增加 owner/visibility | 仍使用一个产品表 | 需要审计全项目中所有 `PptProduct` 查询,漏一处就可能越权 | 不建议作为首期 | | 新建用户产品资料表 | 权限边界清晰;不影响公共产品;便于留存、复用和软删除 | 海报生成需要支持两种来源 | 推荐 | | 仅保存为当前海报项目素材 | 与未来工作区模型一致 | 无法自然实现跨项目复用的“我的资料库” | 可作为项目快照,不作为主实体 | ### 3.2 推荐架构 ```text 产品资料来源 ├── 公共产品:PptProduct(管理员审核) └── 我的资料:UserProductMaterial(用户上传并确认) │ ├── 原始 PDF:持久化 storage ├── 解析结果:parsed_rules ├── 用户确认结果:confirmed_rules └── 可选提交审核:进入公共产品库 统一 ProductSourceResolver │ ├── 校验来源存在、状态和所有权 ├── 输出统一 ProductContext └── 提供给文案生成、海报生成和项目恢复 ``` 统一的 `ProductContext` 至少包含: ```json { "sourceType": "library_product", "sourceId": "aia_example", "productName": "产品名称", "companyId": "aia", "companyName": "保司名称", "planType": "savings", "rules": {}, "confirmedAt": "2026-07-30T10:00:00" } ``` `sourceType` 首期只支持: - `library_product`:后台公共产品; - `user_material`:当前用户上传的产品小册子。 --- ## 四、数据模型与存储 ### 4.1 新表 `insurance_user_product_materials` 建议新增 `api/insurance/models/user_product_material.py`。 | 字段 | 类型 | 说明 | |------|------|------| | `id` | BIGINT | 主键 | | `owner_user_id` | VARCHAR(64) | 上传者,必须建立索引 | | `tenant_id` | VARCHAR(64) | 租户隔离;无法可靠取得时首期使用 `default` | | `company_id` | VARCHAR(50) | 可为空,确认时允许选择 | | `company_name` | VARCHAR(100) | PDF 解析或用户确认的保司名称 | | `product_name` | VARCHAR(150) | 解析或用户确认的产品名称 | | `plan_type` | VARCHAR(20) | savings/ci/iul/other | | `original_name` | VARCHAR(200) | 原文件名 | | `file_key` | VARCHAR(500) | 相对 storage 根目录的对象键 | | `file_size` | BIGINT | 文件字节数 | | `page_count` | INTEGER | PDF 页数 | | `sha256` | VARCHAR(64) | 用户内去重和审计 | | `parse_status` | VARCHAR(20) | pending/queued/parsing/parsed/failed | | `parse_message` | VARCHAR(500) | 进度提示 | | `parse_error` | TEXT | 解析错误,返回前需要脱敏 | | `parse_task_id` | VARCHAR(200) | Celery 任务 ID | | `parsed_rules` | TEXT | 系统原始解析 JSON | | `confirmed_rules` | TEXT | 用户核对后的最终 JSON | | `confirmed_by` | VARCHAR(64) | 确认人 | | `confirmed_at` | TIMESTAMP | 确认时间 | | `review_status` | VARCHAR(20) | private/submitted/approved/rejected | | `status` | SMALLINT | 1=可用,0=停用 | | `created_at` / `updated_at` | TIMESTAMP | 时间字段 | | `deleted_at` | TIMESTAMP | 软删除 | 索引和约束: - `INDEX(owner_user_id, deleted_at, updated_at)`; - `INDEX(owner_user_id, sha256)`; - `INDEX(parse_status)`; - 不做跨用户重复文件提示,避免侧信道泄露; - `confirmed_rules` 为空的资料不得用于生成。 ### 4.2 现有表兼容扩展 为 `poster_case_uploads` 和 `poster_records` 增加: | 字段 | 用途 | |------|------| | `product_source_type` | `library_product` / `user_material` | | `product_source_id` | 统一使用字符串保存来源 ID | | `product_snapshot_json` | 提交生成时固化产品名称、保司、规则和确认时间 | 兼容规则: - 旧记录没有 `product_source_type` 时,按 `library_product + product_id` 读取; - 新代码继续接受旧请求中的 `productId`; - 新页面优先发送 `productSource`; - 已生成项目始终使用 `product_snapshot_json`,后台资料后续变化不能静默改变历史海报。 ### 4.3 文件存储 推荐对象键: ```text uploads/product-manuals/users/{safe_user_id}/{material_id}/{uuid}.pdf ``` 要求: - 只在数据库保存相对 `file_key`,读取时由统一存储服务拼接; - API 和 Worker 必须挂载同一个 `INSURANCE_STORAGE_ROOT` 持久化卷; - 下载接口必须鉴权并校验文件位于产品小册子目录内; - PDF 密码仅用于本次解密,不写数据库、不写日志; - 替换文件时生成新对象,不覆盖旧文件;新解析成功后再切换引用; - 删除采用软删除;被历史海报快照引用的文件不得立即物理删除。 建议默认保留策略: - 活跃资料:保留至用户主动删除; - 用户删除:进入 30 天回收期; - 已被海报使用:至少保留到相关海报项目过期; - 最终期限需要由业务、法务和存储成本负责人确认。 --- ## 五、后端接口 ### 5.1 用户产品资料接口 | 方法 | URL | 用途 | |------|-----|------| | GET | `/insurance/poster/product-materials` | 查询“我的产品资料” | | POST | `/insurance/poster/product-materials` | 上传 PDF,创建记录并自动投递解析 | | GET | `/insurance/poster/product-materials/{id}` | 查询详情和解析状态 | | PUT | `/insurance/poster/product-materials/{id}/confirm` | 保存修正结果并确认 | | POST | `/insurance/poster/product-materials/{id}/retry` | 解析失败后重试 | | GET | `/insurance/poster/product-materials/{id}/file` | 鉴权预览原 PDF | | DELETE | `/insurance/poster/product-materials/{id}` | 软删除本人资料 | | POST | `/insurance/poster/product-materials/{id}/submit-review` | 可选:提交进入公共库审核 | 上传使用 `multipart/form-data`: | 字段 | 必填 | 说明 | |------|:----:|------| | `file` | 是 | PDF | | `password` | 否 | PDF 打开密码,不保存 | | `companyId` | 否 | 用户已知时可传 | | `planType` | 否 | 用户已知时可传 | ### 5.2 产品来源接口 保留现有 `GET /poster/products`,新增: ```text GET /insurance/poster/product-sources ``` 返回: ```json { "code": 0, "message": "success", "data": { "libraryProducts": [], "myMaterials": [] } } ``` “我的资料”只返回: - 当前用户所有; - 未删除且启用; - `parse_status=parsed` 或已确认; - 生成时仍必须再次检查 `confirmed_rules`。 ### 5.3 生成接口兼容 新请求: ```json { "productSource": { "type": "user_material", "id": "123" }, "caseUploadId": 456, "templateId": 1 } ``` 兼容逻辑: 1. 有 `productSource` 时使用新逻辑; 2. 只有 `productId` 时映射为 `library_product`; 3. `ProductSourceResolver` 完成所有权、状态、确认状态和公司状态检查; 4. `generate_copy()`、`generate_poster()` 不再直接各自拼装产品规则; 5. 创建 `PosterRecord` 时保存产品快照。 建议错误码: | 错误码 | 含义 | |--------|------| | 4101 | 小册子文件不合法 | | 4102 | 小册子需要密码或密码错误 | | 4103 | 小册子解析中 | | 4104 | 小册子解析失败 | | 4105 | 小册子尚未确认 | | 4106 | 产品资料不存在或无权访问 | | 4107 | 产品资料已删除或停用 | --- ## 六、解析与确认流程 ```text 上传 PDF → prepare_pdf_upload 安全校验和解密 → 计算 sha256 → 持久化原文件 → 创建 material,状态 queued → Celery 解析 → parse_manual_pdf → 保存 parsed_rules,状态 parsed → 用户查看原 PDF + 修改结构化字段 → 服务端 Schema 校验 → 保存 confirmed_rules、确认人和确认时间 → 可用于海报并进入“我的资料” ``` ### 6.1 解析复用 直接复用: - `insurance.utils.security.prepare_pdf_upload`; - `insurance.poster.manual_parser.parse_manual_pdf`; - `insurance.generation.celery_tasks` 的 Celery 基础设施; - `insurance.config.get_storage_root`; - BaoDan 数据库、Redis、日志和认证。 新增 `parse_user_product_material_task(material_id)`,状态流转: ```text pending → queued → parsing → parsed → confirmed └→ failed ``` 数据库字段仍使用 `parsed + confirmed_at` 表示最终确认,不必为了展示再增加 `confirmed` 状态值。 ### 6.2 确认 Schema 首期至少要求: - `product_name` 非空; - `features` 为 1~8 项; - 每项卖点包括 `title`、`summary`,尽量保留 `source_page`; - `currency_options` 为字符串数组; - `coverage_highlights` 为字符串数组; - `risk_warnings` 为字符串数组; - `investment_rules` 为对象; - 所有字符串限制长度,禁止把整份 PDF 原文写入结构化字段。 用户替换原 PDF 或重新解析后,必须清空旧 `confirmed_rules` 和 `confirmed_at`,强制重新确认。 ### 6.3 Prompt 安全 - PDF 内容一律视为待抽取数据,不视为系统指令; - 系统 Prompt 明确忽略 PDF 内的指令、链接和要求; - 结构化输出必须做服务端 Schema 校验; - 不把 PDF 全文、密码、客户敏感数据或模型密钥写入日志; - 对超长 PDF 使用页级筛选和最大上下文限制; - 解析失败应返回结构化错误,不向前端暴露内部堆栈。 --- ## 七、前端交互 ### 7.1 产品资料面板 将当前“选择产品”抽屉改为两个标签: 1. `系统产品`:现有后台已审核产品; 2. `我的资料`:当前用户已上传并确认的小册子。 固定提供: - “上传产品小册子”按钮; - 搜索无结果时显示“没有找到?上传小册子”; - 我的资料卡片展示产品名、保司、解析状态、更新时间; - 支持查看原 PDF、编辑确认结果、替换、删除。 ### 7.2 上传对话框 步骤: 1. 选择 PDF,可选输入密码; 2. 上传并显示真实解析状态; 3. 左侧预览 PDF,右侧核对解析字段; 4. 点击“确认并使用”; 5. 自动加入“我的资料”并选中。 解析可能超过页面停留时间,用户关闭弹窗后任务仍应继续;再次进入“我的资料”可恢复状态。 ### 7.3 草稿状态调整 `PosterDraft` 增加: ```ts productSourceType: 'library_product' | 'user_material' | '' productSourceId: string productSourceConfirmedAt: string ``` 兼容保留 `productId`,但新流程不再仅以 `productId` 判断是否完成产品选择。 当用户更换产品来源时: - 清空已生成文案; - 将合规确认置为未确认; - 如果客户计划书与旧产品绑定,提示并要求重新确认; - 不直接删除已上传客户计划书。 ### 7.4 文案调整 当前“计划书与数据”建议改为“客户计划书与数据”,上传提示明确写“客户计划书 PDF”。 产品资料区域明确写“产品小册子”,避免用户把同一个文件传错入口。 --- ## 八、代码改动清单 ### 8.1 后端 | 文件 | 改动 | |------|------| | `api/insurance/db/migrate_026.py`(以开发分支启动时的下一个可用编号为准) | 新表、兼容字段、索引和幂等迁移 | | `api/insurance/models/user_product_material.py` | 用户产品资料模型 | | `api/insurance/models/__init__.py` | 注册模型 | | `api/insurance/poster/product_material_service.py` | 上传、查询、确认、删除和所有权校验 | | `api/insurance/poster/product_source_resolver.py` | 统一公共产品与用户资料 | | `api/insurance/poster/routes.py` | 新增产品资料和产品来源接口 | | `api/insurance/poster/service.py` | 文案/海报生成改用统一 resolver | | `api/insurance/generation/celery_tasks.py` | 新增用户小册子解析任务 | | `api/insurance/models/poster_case_upload.py` | 保存产品来源引用 | | `api/insurance/models/poster_record.py` | 保存产品来源和产品快照 | | `api/insurance/utils/security.py` | 仅在现有能力不足时补充限制,不重写上传校验 | 当前仓库的下一个迁移编号是 026,但《海报生成工作台完整重构修复计划》也预留了该编号。若两项工作进入同一发布版本,应合并为一个迁移;若分支独立交付,后合并的分支必须顺延编号。海报工作台 V2 的 `poster_project_assets` 已落地时,在生成项目时把用户资料注册为: ```text asset_type=product_manual source_type=library source_ref_id={user_material_id} ``` ### 8.2 前端 | 文件 | 改动 | |------|------| | `frontend/src/utils/poster-api.ts` | 产品资料上传、查询、确认、删除、重试接口 | | `frontend/src/composables/usePosterWorkspace.ts` | 增加产品来源状态和兼容恢复 | | `frontend/src/components/poster/workspace/PosterProductPanel.vue` | 系统产品/我的资料双标签 | | `frontend/src/components/poster/workspace/UserProductMaterialDialog.vue` | 新增上传、轮询、核对弹窗 | | `frontend/src/components/poster/workspace/PosterSourcePanel.vue` | 文案改为客户计划书,解除“必须先选公共 productId”假设 | | `frontend/src/pages/PosterPage.vue` | 生成请求发送 `productSource` | ### 8.3 测试 建议新增: ```text tests/poster_product_material_model_test.py tests/poster_product_material_api_test.py tests/poster_product_material_parse_test.py tests/poster_product_source_resolver_test.py tests/poster_product_material_permission_test.py tests/poster_product_material_storage_test.py tests/poster_user_manual_e2e_test.py ``` --- ## 九、可执行排期 ### Phase 0:需求冻结和样例准备(0.5 人日) - [x] MANUAL-0001 确认“用户资料默认私有”; - [x] MANUAL-0002 确认是否允许用户确认后立即生成; - [ ] MANUAL-0003 准备 3 份脱敏样例:文本 PDF、扫描 PDF、加密 PDF; - [x] MANUAL-0004 固化解析字段 Schema 和验收期望; - [ ] MANUAL-0005 确认保留期、单文件大小和页数上限。 完成标准:三份样例和预期 JSON 入库到测试夹具,关键产品决策有书面结论。 ### Phase 1:数据、存储和基础 API(1.5 人日) - [x] MANUAL-0101 编写幂等迁移; - [x] MANUAL-0102 新增模型和 `to_dict()`; - [x] MANUAL-0103 实现用户内 SHA-256 去重; - [x] MANUAL-0104 实现上传、列表、详情、预览和软删除; - [x] MANUAL-0105 实现文件路径和所有权校验; - [x] MANUAL-0106 增加迁移、存储和权限单元测试。 完成标准:重启 API/Worker 后文件仍存在,用户 A 无法查看、下载或删除用户 B 的资料。 ### Phase 2:异步解析和人工确认(1.5 人日) - [x] MANUAL-0201 新增用户资料 Celery 任务; - [x] MANUAL-0202 复用 `parse_manual_pdf()`; - [x] MANUAL-0203 增加 Prompt 注入防护和输出 Schema 校验; - [x] MANUAL-0204 实现轮询、失败原因和重试; - [x] MANUAL-0205 实现确认接口和确认失效规则; - [ ] MANUAL-0206 覆盖加密、损坏、空文本、超限和扫描件场景。 完成标准:上传后异步完成解析;失败可重试;未确认资料不能进入生成。 ### Phase 3:海报链路接入(1.0 人日) - [x] MANUAL-0301 实现 `ProductSourceResolver`; - [x] MANUAL-0302 改造 `generate_copy()`; - [x] MANUAL-0303 改造 `generate_poster()`; - [x] MANUAL-0304 为计划书和海报记录保存产品来源与快照; - [x] MANUAL-0305 验证旧 `productId` 请求保持兼容; - [x] MANUAL-0306 增加跨用户引用和历史快照测试。 完成标准:公共产品和本人资料均可生成;用户资料更新不改变已生成海报的产品快照。 ### Phase 4:前端交互(1.0 人日) - [x] MANUAL-0401 产品选择抽屉增加双标签; - [x] MANUAL-0402 新增上传、解析进度、预览和核对弹窗; - [x] MANUAL-0403 支持从“我的资料”复用、替换和删除; - [x] MANUAL-0404 修正产品小册子/客户计划书文案; - [x] MANUAL-0405 产品来源变化时清理失效草稿状态; - [ ] MANUAL-0406 PC 和移动端基本回归。 完成标准:用户无需管理员帮助即可完成“上传小册子 → 解析 → 确认 → 生成海报 → 下次复用”。 ### Phase 5:测试、灰度和上线(0.5 人日) - [x] MANUAL-0501 执行后端权限、存储和兼容回归; - [ ] MANUAL-0502 执行前端端到端流程; - [x] MANUAL-0503 增加 `POSTER_USER_MANUAL_UPLOAD_ENABLED` 功能开关; - [ ] MANUAL-0504 管理员和 5% 用户灰度; - [ ] MANUAL-0505 观察解析成功率、耗时、重试率和存储增长; - [x] MANUAL-0506 更新 API、测试、部署和任务清单文档。 完成标准:P0/P1 用例通过;关闭功能开关可立即回到旧产品选择流程;旧海报可继续查看和下载。 ### 可选 Phase 6:提交公共库审核(1.5~2 人日) - [ ] MANUAL-0601 用户提交审核; - [ ] MANUAL-0602 管理端待审列表和 PDF/解析结果对照; - [ ] MANUAL-0603 管理员修改、批准和驳回; - [ ] MANUAL-0604 批准后创建或合并 `PptProduct`; - [ ] MANUAL-0605 记录来源资料、审核人和审核时间; - [ ] MANUAL-0606 同产品重复提交检测。 首期不应把该阶段作为“用户能生成海报”的阻断项,除非合规制度明确要求所有产品必须管理员预审。 --- ## 十、测试与验收 ### 10.1 P0 验收 - [ ] 不选择公共产品也能上传产品小册子; - [ ] 原 PDF 保存在持久化 storage,服务重启后仍可预览; - [ ] 加密 PDF 密码只用于本次请求; - [ ] 解析任务页面关闭后继续执行; - [ ] 用户可以修改并确认解析结果; - [ ] 未确认资料不能生成文案或海报; - [ ] 确认后的资料出现在“我的资料”并可跨项目复用; - [ ] 用户 A 无法枚举、预览、引用、修改或删除用户 B 的资料; - [ ] 公共产品原流程保持可用; - [ ] 旧 `productId` API 调用保持兼容; - [ ] 历史海报使用产品快照,不受资料后续修改影响。 ### 10.2 P1 验收 - [ ] 同一用户重复上传相同 PDF 不重复调用模型; - [ ] 替换 PDF 后旧确认自动失效; - [ ] 解析失败可查看可理解原因并重试; - [ ] 危险 PDF、伪造扩展名、超大小和超页数被拒绝; - [ ] PDF 中的 Prompt 注入文本不会改变解析任务; - [ ] 日志中没有 PDF 密码、完整正文和模型密钥; - [ ] 删除资料不会破坏历史海报; - [ ] 解析成功率、P95 耗时和存储增长可监控。 ### 10.3 建议性能指标 | 指标 | 建议目标 | |------|----------| | 上传接口 P95 | 小于 3 秒,不含客户端网络上传时间 | | 解析任务成功率 | 大于 95%,扫描件单独统计 | | 文本 PDF 解析 P95 | 小于 120 秒 | | 重复上传模型调用 | 0 次 | | 跨用户访问成功数 | 0 | | 服务重启后文件丢失 | 0 | --- ## 十一、风险与处理 | 风险 | 影响 | 应对 | |------|------|------| | 用户资料被误当公共产品 | 数据泄露、合规风险 | 独立表、默认私有、所有权校验 | | PDF 解析结果不准确 | 错误产品卖点进入文案 | 人工确认、来源页、未确认阻断 | | 扫描 PDF 无文本 | 解析失败率高 | 首期明确提示;P1 接入 OCR | | 重复上传导致模型成本增加 | 成本浪费 | 用户内 SHA-256 去重 | | 文件只存容器临时盘 | 重启后丢失 | 强制共享持久化卷和 readiness 检查 | | 资料修改影响历史海报 | 审计不可追溯 | 生成时保存产品快照 | | 用户删除资料导致历史断链 | 旧项目无法恢复 | 软删除、引用保护、延迟物理清理 | | 在现有 `PptProduct` 上补权限遗漏 | 跨用户暴露 | 不复用全局产品表保存私有资料 | | 与海报工作台 V2 迁移冲突 | 重复表和迁移编号 | 用户资料作为长期资料库,项目素材只保存引用和快照 | --- ## 十二、上线决策项 开发开始前必须确认: | 编号 | 决策 | 推荐默认值 | |------|------|------------| | D-01 | 用户资料是否默认私有 | 是 | | D-02 | 用户确认后能否立即生成 | 能,仅限本人使用 | | D-03 | 是否自动进入公共产品库 | 否,必须显式提交并管理员审核 | | D-04 | 扫描 PDF 是否首期支持 OCR | 否,先提示用户上传可检索 PDF | | D-05 | 文件默认保留期 | 活跃资料保留至用户删除,删除后 30 天回收 | | D-06 | 单文件大小和页数 | 沿用 `prepare_pdf_upload()` 当前配置 | | D-07 | 是否允许无保司资料 | 允许上传,确认前必须补齐或选择“其他” | | D-08 | 删除后历史海报是否保留文件 | 是,保留至项目生命周期结束 | --- ## 十三、完成定义 只有以下条件全部满足,本需求才可标记完成: - 用户能在海报产品选择区上传系统中不存在的小册子; - 小册子原文件、解析结果、确认结果和确认信息均保存在服务端; - 上传资料默认只对本人可见; - 用户确认后可以立即用于文案和海报生成; - 下次新建海报时可以从“我的资料”直接选择; - 公共产品和旧接口不受影响; - 生成记录保存产品快照; - 文件、权限、解析、兼容和端到端自动化测试通过; - 生产环境 API 与 Worker 使用同一持久化存储; - 功能支持灰度开关和无损回退。