Files
story/docs/data-export.md

4.6 KiB

私有数据导出开发说明

1. 功能边界

私有数据导出用于将某一长者在当前租户和家庭边界内的资料生成独立JSON文件。它与ACCESS数据盘点分离:盘点只返回分类数量,导出文件才包含用户被授权获取的正文。

可导出分类包括长者档案、授权记录、设备绑定、通话元数据、最终话轮、摘要、故事与来源、已确认记忆。未显式指定分类时生成全量导出。

2. 功能设计

  1. 家庭所有者使用Idempotency-Key提交导出任务。
  2. API在事务中验证privacy.manage、长者归属和请求摘要,写入QUEUED任务及Outbox事件。
  3. Worker将任务转为RUNNING,按固定分类SQL查询数据,生成subject-export-v1文档。
  4. Worker计算SHA-256,将文件写入MinIO私有桶,再把文件大小、摘要和过期时间提交到PostgreSQL。
  5. 用户读取READY任务时,API使用公网端点现场生成短期预签名URL,不在数据库和页面持久化URL。
  6. 到期扫描器删除对象,清空内部对象引用,把任务置为EXPIRED并记录最小审计。

3. 安全设计

  • MinIO桶private-exports保持私有,未签名的对象请求被拒绝。
  • 对象路径为tenants/{tenant-hash}/exports/{export-id}/v1.json,不把租户主键直接写入路径。
  • API不返回object_ref、对象存储凭据或长期URL。导出详情和列表使用Cache-Control: no-store。
  • 下载URL有效期取“配置的短期下载TTL”与“对象剩余有效期”的较小值。
  • 导出文件包含私密正文,仅能使用合成数据进行本地测试,生产密钥必须由密钥管理系统注入。

4. 接口设计

接口 权限 说明
POST /api/v1/subjects/{id}/exports privacy.manage 幂等创建导出,返回202;重放返回200
GET /api/v1/subjects/{id}/exports privacy.read 返回当前长者导出列表,不签发下载URL
GET /api/v1/exports/{id} privacy.read 返回任务详情;仅就绪且未过期时包含短期URL

5. 数据库设计

export_task保存租户、长者、申请人、冻结范围、任务状态、对象引用、大小、内容摘要、过期时间、尝试次数和幂等摘要。状态为QUEUED/RUNNING/READY/FAILED/EXPIRED。READY数据库约束要求对象引用、大小、摘要、过期时间和完成时间全部存在。

6. 配置

变量 用途
OBJECT_STORE_ENDPOINT API/Worker访问对象存储的内网端点
OBJECT_STORE_PUBLIC_ENDPOINT 用于生成用户可访问签名URL的端点
OBJECT_STORE_REGION 签名Region,避免使用公网地址执行内部探测
OBJECT_STORE_EXPORT_BUCKET 私有导出桶
EXPORT_DOWNLOAD_TTL 单次预签名下载地址有效期
EXPORT_OBJECT_TTL 导出对象总保留期

7. 验证

scripts/smoke-export.ps1使用本地真实OIDC令牌、PostgreSQL、Worker和MinIO验证所有者/编辑者权限、幂等重放、分类范围、私有桶拒绝直连、预签名下载、SHA-256校验、长者边界和过期后对象删除。

家庭工作台的“生成私有导出”现先打开页面内受控操作区。表单固定当前长者公开编号和八类导出范围,并明确后台将生成包含个人正文的私有JSON文件、对象与短期下载地址均有有效期、文件下载后应受控保存和销毁且操作会进入申请与导出审计。用户必须勾选私密数据影响确认后才能提交;取消或切换业务上下文会清除草稿,不创建任务,也不提前签发下载地址。

READY任务的“获取短期下载”同样不再单击即读取任务详情并触发下载。确认区固定长者、导出任务公开编号、任务冻结的分类范围、文件大小和对象过期时间,明确短期地址只会在提交时现场生成,JSON包含个人正文且离开平台后需要限制转交并按需销毁。只有显式确认后才重新读取任务;任务仍为READY、对象仍未过期且返回短期地址时才触发浏览器下载。取消或切换长者、家庭、工作台会清除草稿,不调用会签发地址的任务详情接口。

日常页面验证采用真实OIDC无提交冒烟,只检查对象/范围绑定、确认门禁、取消关闭、零导出创建请求、零任务详情地址签发请求、任务数量不变及页面布局。完整对象生成、私有桶、摘要、下载和过期清理由本节既有定向脚本承担,避免在普通前端改动中重复执行高强度全链路测试。

V10迁移已在独立临时空库完成up 1—10 → down -all → up 1—10,最终状态为10|dirty=false,验证库已删除。