geo/docs/plans/2026-06-01-005-chore-geo-te...

16 KiB
Raw Blame History

title type status date origin
chore: GEO Tech Debt Cleanup Sprint chore completed 2026-06-01 docs/brainstorms/2026-06-01-geo-tech-debt-cleanup-requirements.md

Summary

分三批清理 GEO 平台技术债Batch 1 修复 28 个模型文件中 68 个缺失 DateTime(timezone=True) 的 datetime 列(monitoring_record.py 是废弃文件不修Batch 2 统一前端 2 个页面组件的 API 客户端调用并扩展 fetchWithAuth 支持非 JSON 响应Batch 3 完成前端端到端验证和部署安全加固。

Problem Frame

Plan 004 端到端验证暴露了 asyncpg 严格时区检查的系统性问题。当前仅修复了变现闭环涉及的 4 个核心表,其余 28 个模型文件的 68 个 datetime 列仍是确定的运行时炸弹——任何写入 datetime.now(UTC) 到未标记 timezone 的列都会直接报错。同时前端 2 个页面绕过统一 API 客户端,认证 token 不被附加导致 401。Docker 部署从未验证成功Redis/PostgreSQL 安全配置缺失。这些技术债不清理,系统无法真正上线。


Requirements

时区修复Batch 1

R1. 28 个模型文件的 68 个 datetime 列添加 DateTime(timezone=True)PostgreSQL 对应列类型改为 TIMESTAMPTZ

R2. 时区修复按 API 调用路径分三批执行:核心变现路径 → Agent 框架路径 → 辅助路径

R3. 每批修复后验证对应 API 路径可正常写入和读取 datetime 数据

R4. 生成对应的 Alembic 迁移脚本

R5. 删除废弃的 monitoring_record.py 文件(无任何代码引用,与 monitoring.py 定义同名表但字段不同)

前端 API 客户端统一Batch 2

R6. reports/page.tsx 的 CSV 导出改用统一 API 客户端

R7. lifecycle/new/page.tsx 的项目创建改用统一 API 客户端

R8. 统一 API 客户端支持非 JSON 响应blob/PDF 导出)

前端端到端验证Batch 3

R9. 浏览器中可完成完整变现闭环:注册→登录→创建品牌→诊断→查看健康分→付费墙→支付→解锁

R10. 公开健康分页面无需登录即可访问

R11. Onboarding 流程在浏览器中可正常走通

部署安全加固Batch 3

R12. Redis 配置密码保护

R13. PostgreSQL 默认弱密码更换为强密码

R14. 创建 .env.production 模板

R15. Docker Compose 部署验证通过


Key Technical Decisions

KTD1. 时区修复按 API 调用路径分批,而非一次性全量迁移。 68 列同时 ALTER TABLE 风险高按实际调用路径修复风险可控。核心变现路径brand、query、content 等)最优先,因为这是用户最可能触发的路径。

KTD2. monitoring_record.py 是废弃文件,删除而非修复。 代码引用分析确认所有 import 都指向 monitoring.pymonitoring_record.py 无任何引用。两个文件定义同名表但字段结构不同,保留 monitoring.py(更完整,有 relationship 和 user_id/query_id 外键)。

KTD3. 扩展 fetchWithAuth 支持非 JSON 响应,而非新增独立函数。 reports.ts 的 PDF blob 导出被迫绕过统一客户端,因为 fetchWithAuth 只返回 JSON。扩展一个 responseType 参数比新增 fetchWithAuthBlob 更符合 DRY 原则,且对现有调用方无侵入。

KTD4. Alembic 迁移按 Batch 生成,而非一个大迁移。 每个 Batch 生成一个迁移文件便于回滚和增量部署。Batch 1 因模型数量多可能需要 2-3 个迁移文件。


Implementation Units

U1. Batch 1a: 核心变现路径时区修复

  • Goal: 修复核心变现路径涉及的模型文件 datetime 列确保品牌创建、查询、内容管理、GEO 计划、建议生成等 API 不再触发 asyncpg 时区错误
  • Requirements: R1, R2, R3, R4
  • Dependencies: none
  • Files:
    • backend/app/models/brand.py — 4 列last_queried_at, next_query_at, created_at, updated_at
    • backend/app/models/query.py — 4 列last_queried_at, next_query_at, created_at, updated_at
    • backend/app/models/citation_record.py — 1 列queried_at
    • backend/app/models/attribution_record.py — 4 列published_at, window_end_at, created_at, updated_at
    • backend/app/models/content.py — 4 列Content: created_at, updated_at; ContentVersion: created_at; ContentReview: created_at
    • backend/app/models/geo_plan.py — 5 列GeoPlan: created_at, updated_at; GeoPlanAction: completed_at, created_at, updated_at
    • backend/app/models/suggestion.py — 2 列generated_at, updated_at
    • backend/app/models/competitor.py — 1 列created_at
    • backend/app/models/competitor_insight.py — 2 列created_at, updated_at
    • backend/app/models/distribution.py — 2 列created_at, updated_at
    • backend/app/models/brand_knowledge.py — 3 列BrandKnowledge: created_at, updated_at; Keyword: created_at
  • Approach: 每个文件添加 DateTime import如缺失将所有 Mapped[datetime] 列的 mapped_column() 添加 DateTime(timezone=True) 参数。对于已有 DateTime 但无 timezone=True 的列(如 brand.py 的 last_queried_at改为 DateTime(timezone=True)。修复后启动后端服务,通过 curl 验证品牌创建和查询 API 的 datetime 读写正常。
  • Patterns to follow: 已修复的 4 个核心表diagnosis_record.py, payment_order.py, subscription.py, user.py的修改模式
  • Test scenarios:
    • 品牌创建 API 返回的 created_at 包含时区信息
    • 查询品牌列表 API 返回的 datetime 字段包含时区信息
    • 创建 GEO 计划后 completed_at 可写入 timezone-aware datetime
    • attribution_record 的 published_at 和 window_end_at 可写入 timezone-aware datetime
  • Verification: 启动后端服务,通过 curl 调用品牌创建、查询、内容管理 API确认 datetime 读写无 asyncpg 时区错误

U2. Batch 1b: Agent 框架路径时区修复

  • Goal: 修复 Agent 框架和监控相关模型文件的 datetime 列
  • Requirements: R1, R2, R3, R4
  • Dependencies: U1
  • Files:
    • backend/app/models/agent.py — 9 列AgentRegistry: last_heartbeat, created_at, updated_at; AgentConfig: updated_at; AgentTask: scheduled_at, started_at, completed_at, created_at; AgentTaskLog: created_at
    • backend/app/models/detection_task.py — 4 列last_run_at, next_run_at, created_at, updated_at
    • backend/app/models/monitoring.py — 5 列MonitoringRecord: last_checked_at, next_check_at, created_at, updated_at; ContentBaseline: recorded_at
    • backend/app/models/trend_insight.py — 4 列period_start, period_end, created_at, updated_at
    • backend/app/models/query_task.py — 3 列scheduled_at, started_at, completed_at
    • backend/app/models/usage_record.py — 2 列timestamp, created_at
    • backend/app/models/api_key.py — 3 列last_verified_at, created_at, updated_at
  • Approach: 同 U1 模式。注意 detection_task.pynext_run_atdefault=lambda: datetime.now(timezone.utc),这已经是 timezone-aware 的,但列类型仍是 DateTime(无 timezone需要改为 DateTime(timezone=True)
  • Patterns to follow: U1 的修改模式
  • Test scenarios:
    • Agent 注册时 last_heartbeat 可写入 timezone-aware datetime
    • AgentTask 的 scheduled_at、started_at、completed_at 可写入 timezone-aware datetime
    • detection_task 的 next_run_at 默认值写入不触发时区错误
    • monitoring_record 的 last_checked_at、next_check_at 可写入 timezone-aware datetime
  • Verification: 启动后端服务,通过 curl 调用 Agent 相关 API确认 datetime 读写无错误

U3. Batch 1c: 辅助路径时区修复 + 废弃文件清理

  • Goal: 修复剩余辅助路径模型文件的 datetime 列,删除废弃的 monitoring_record.py
  • Requirements: R1, R2, R3, R4, R5
  • Dependencies: U2
  • Files:
    • backend/app/models/knowledge.py — 6 列KnowledgeBase: created_at, updated_at; KnowledgeDocument: created_at, updated_at; KnowledgeChunk: created_at; KnowledgeSearchLog: created_at
    • backend/app/models/knowledge_graph.py — 3 列KnowledgeEntity: created_at, updated_at; KnowledgeRelation: created_at
    • backend/app/models/organization.py — 3 列Organization: created_at, updated_at; OrgMember: joined_at
    • backend/app/models/lifecycle.py — 4 列LifecycleProject: created_at, updated_at; ProjectStage: started_at, completed_at
    • backend/app/models/alert.py — 1 列created_at
    • backend/app/models/alert_setting.py — 2 列created_at, updated_at
    • backend/app/models/platform_rule.py — 1 列updated_at
    • backend/app/models/platform_rule_version.py — 1 列created_at
    • backend/app/models/schema_suggestion.py — 2 列created_at, updated_at
    • backend/app/models/monitoring_record.py — 删除整个文件
    • backend/app/models/__init__.py — 移除 monitoring_record 的 import如有
  • Approach: 同 U1 模式。删除 monitoring_record.py 前确认 __init__.py 无引用(已验证无任何代码 import 此文件)。删除后检查 __init__.py 是否有相关 import 需清理。
  • Patterns to follow: U1 的修改模式
  • Test scenarios:
    • knowledge 相关 API 的 created_at/updated_at 可写入 timezone-aware datetime
    • lifecycle project 的 started_at/completed_at 可写入 timezone-aware datetime
    • 删除 monitoring_record.py 后后端服务正常启动,无 import 错误
  • Verification: 启动后端服务,确认无 import 错误;调用 knowledge 和 lifecycle API 验证 datetime 读写

U4. Alembic 迁移生成与执行

  • Goal: 为 U1-U3 的所有模型变更生成 Alembic 迁移脚本,并在本地数据库执行
  • Requirements: R4
  • Dependencies: U1, U2, U3
  • Files:
    • backend/alembic/versions/ — 新增迁移文件
  • Approach: 运行 alembic revision --autogenerate 生成迁移。检查生成的迁移脚本确认所有 ALTER COLUMN 操作正确(TIMESTAMP → TIMESTAMPTZ)。执行迁移后验证数据库列类型已更新。如果项目未配置 Alembic则通过 init_schema.py 或手动 SQL 完成数据库更新。
  • Patterns to follow: 已有的 Alembic 迁移文件(如存在)
  • Test scenarios:
    • 迁移脚本可成功执行,无错误
    • 迁移后数据库列类型为 TIMESTAMPTZ
    • 迁移可回滚downgrade
  • Verification: 执行迁移,检查数据库列类型

U5. 前端 API 客户端统一

  • Goal: 统一前端 2 个页面组件的 API 调用,扩展 fetchWithAuth 支持非 JSON 响应
  • Requirements: R6, R7, R8
  • Dependencies: none可与 U1-U4 并行)
  • Files:
    • frontend/lib/api/client.ts — 扩展 fetchWithAuth 支持 responseType 参数
    • frontend/app/(dashboard)/dashboard/reports/page.tsx — CSV 导出改用 fetchWithAuth
    • frontend/app/(dashboard)/dashboard/lifecycle/new/page.tsx — 项目创建改用 fetchWithAuth
    • frontend/lib/api/reports.ts — PDF blob 导出改用 fetchWithAuthresponseType: 'blob'
  • Approach:fetchWithAuth 中添加可选 responseType 参数,默认 'json',当为 'blob' 时返回 Response 对象而非解析 JSON。修改 reports/page.tsx 和 lifecycle/new/page.tsx 使用 fetchWithAuth 替代手动 fetch。修改 reports.ts 使用 fetchWithAuth 的 blob 模式。
  • Patterns to follow: frontend/lib/api/client.ts 现有的 fetchWithAuth 实现
  • Test scenarios:
    • fetchWithAuth 默认行为不变(返回 JSON
    • fetchWithAuth responseType='blob' 返回 Response 对象
    • reports 页面 CSV 导出认证 token 正确传递
    • lifecycle/new 页面项目创建认证 token 正确传递
    • PDF 导出通过 fetchWithAuth blob 模式正常工作
  • Verification: 前端构建通过,浏览器中访问 reports 和 lifecycle/new 页面无 401 错误

U6. 前端端到端验证

  • Goal: 在浏览器中验证完整变现闭环和关键用户流程
  • Requirements: R9, R10, R11
  • Dependencies: U4, U5
  • Files:
    • 无代码修改,纯验证
  • Approach: 启动前后端服务在浏览器中手动走通完整变现闭环。重点验证注册→登录→Onboarding→创建品牌→诊断→健康分→付费墙→支付→解锁。同时验证公开健康分页面无需登录可访问。
  • Test scenarios:
    • 完整变现闭环:注册→登录→创建品牌→诊断→健康分→付费墙→支付→解锁
    • 公开健康分页面无需登录可访问并生成报告
    • Onboarding 流程可正常走通
    • reports 页面 CSV 导出正常
    • lifecycle/new 页面项目创建正常
  • Verification: 所有流程在浏览器中走通,无 401、无页面报错

U7. 部署安全加固

  • Goal: Redis 密码保护、PostgreSQL 强密码、.env.production 模板、Docker Compose 部署验证
  • Requirements: R12, R13, R14, R15
  • Dependencies: U4
  • Files:
    • docker-compose.yml — Redis 添加密码配置、PostgreSQL 密码更新
    • backend/.env — Redis 密码和 PostgreSQL 密码同步更新
    • backend/.env.production — 新建生产环境配置模板
    • docker-compose.prod.yml — 更新生产环境配置(如存在)
  • Approach: 在 docker-compose.yml 中为 Redis 添加 --requirepass 命令和环境变量。PostgreSQL 密码从弱密码 geo123 改为强密码。创建 .env.production 模板包含所有必需配置项。后端代码中 Redis 连接需同步添加密码参数。执行 docker compose up 验证 4 个服务正常启动和通信。
  • Patterns to follow: docker-compose.yml 现有配置结构
  • Test scenarios:
    • Redis 无密码连接被拒绝
    • Redis 有密码连接成功
    • PostgreSQL 弱密码连接被拒绝
    • PostgreSQL 强密码连接成功
    • Docker Compose 4 个服务正常启动
    • 后端服务可连接 Redis 和 PostgreSQL
  • Verification: docker compose up 成功4 个服务健康检查通过,后端 API 可正常响应

Scope Boundaries

In scope:

  • 28 个模型文件的 DateTime(timezone=True) 修复
  • 废弃文件 monitoring_record.py 删除
  • Alembic 迁移生成和执行
  • 前端 2 个页面组件 API 客户端统一
  • 统一 API 客户端非 JSON 响应支持
  • 浏览器端到端验证
  • Docker Compose 部署验证
  • Redis/PostgreSQL 安全配置
  • .env.production 模板

Deferred for later:

  • 真实微信/支付宝 SDK 接入
  • CI/CD 流水线
  • 性能优化和压力测试
  • 生产环境域名和 HTTPS 配置
  • 完整测试覆盖
  • pgvector 镜像优化
  • JWT_SECRET 强密钥生成
  • UI 打磨和视觉优化

Outside this sprint:

  • 新功能开发
  • 代码重构(除时区修复和废弃文件删除外)

Risks & Dependencies

  • Alembic 未配置或配置不完整。 如果项目未正确配置 Alembic自动迁移生成可能失败。回退方案通过 init_schema.py 或手动 SQL 完成 ALTER COLUMN。
  • Docker Hub 网络问题。 Plan 004 中 Docker 部署因网络问题失败U7 可能遇到同样问题。回退方案:配置 Docker 镜像源或使用本地构建。
  • 前端构建可能暴露其他问题。 前端代码从未在浏览器中完整验证E2E 验证可能发现新的 bug这些 bug 需要额外修复。
  • Redis 密码变更影响后端连接。 后端代码中 Redis 连接配置需同步更新,否则服务启动失败。

Sources / Research

  • Plan 004 端到端验证记录:时区 bug 在 diagnosis_records 和 payment_orders 上的具体表现
  • backend/app/models/ — 28 个待修复模型文件68 个 datetime 列
  • backend/app/models/monitoring.py — 实际使用的监控模型(被 4 处代码引用)
  • backend/app/models/monitoring_record.py — 废弃文件(零引用)
  • frontend/lib/api/client.ts — 统一 API 客户端
  • frontend/app/(dashboard)/dashboard/reports/page.tsx — 绕过统一客户端
  • frontend/app/(dashboard)/dashboard/lifecycle/new/page.tsx — 绕过统一客户端
  • frontend/lib/api/reports.ts — PDF blob 导出被迫绕过
  • docker-compose.yml — Redis 无密码、PostgreSQL 弱密码