- Reference docs: known issues, user journey, location redesign, mission merge plan - Scripts: fill_location_state, merge_missions, migrate_location, migrate_state - Tests: e2e test suite, asset entries unit tests - Demo: location board, hifi prototypes, test screenshots - Data backup: asset log entries and state nodes - Update .gitignore Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
3.1 KiB
3.1 KiB
Location & State Label 从 Interval 迁移到 State Node
设计决策
location 和 state_label 不再绑定到 asset_log_entries(state interval),而绑定到 asset_state_nodes(state node)。
动机
合并 Outbound/Operations/Inbound 后,一个任务条目会跨越多个 location 和 state:
- 出发段 → location=Transfer, state=Transfer
- 到达后 → location=Mars, state=Surface Expedition
- 返航段 → location=Transfer, state=Transfer
如果把 location/state_label 保留在 interval 级别,合并后的条目只能有一个 location 和一个 state_label,无法表达任务过程中的变化。
移到 state node 后,每个时间节点可以独立标注位置和状态,时间线渲染也更精准。
数据库变更
asset_log_entries — 删除列
ALTER TABLE asset_log_entries DROP COLUMN location;
ALTER TABLE asset_log_entries DROP COLUMN state_label;
asset_state_nodes — 新增列
ALTER TABLE asset_state_nodes ADD COLUMN location VARCHAR(255);
ALTER TABLE asset_state_nodes ADD COLUMN state_label VARCHAR(120);
数据迁移
现有 interval 的 location 和 state_label 迁移到该 interval 的第一个 state node:
- 如果 interval 已有 state node → 将 location/state_label 写入按时间排序的第一个 node
- 如果 interval 无 state node → 创建一个 state node(at_time = interval.start_at, title = interval.title),写入 location/state_label
后端变更
Model 层 (app/models.py)
# AssetLogEntry: 删除 location 和 state_label 字段
class AssetLogEntry(TimestampMixin, db.Model):
# 删除: location, state_label
...
# AssetStateNode: 新增 location 和 state_label 字段
class AssetStateNode(TimestampMixin, db.Model):
...
location: Mapped[str | None] = mapped_column(String(255))
state_label: Mapped[str | None] = mapped_column(String(120))
表单 (app/templates/asset_entry_form.html)
- 移除 interval 级别的 location / state_label 输入
- 在 state node 行内增加 location / state_label 输入(每个 node 独立设置)
- Event point 保留 location 字段(作为该时间点的快照)
资产详情 (app/templates/asset_detail.html)
- 当前位置:从最近的一个 state node 的 location 派生(而非当前活跃 interval)
- 当前状态:同上,从最近 state node 的 state_label 派生
看板 / 时间线
- 时间线上每个 state node 显示其自身的 location 和 state_label
- 看板按 location/state 分组时,以最新 state node 为准
对现有数据的影响
| 表 | 操作 |
|---|---|
asset_log_entries |
DROP location, state_label |
asset_state_nodes |
ADD location, state_label |
| 现有 interval 数据 | 迁移到首个 state node |
| 表单模板 | 重构 |
| 详情/看板/时间线 | 改为从 state node 读取 |
实施顺序
- 先做合并(mission_merge_plan.md)— 减少条目数,简化后续迁移
- 再做列迁移(本文档)— 将 location/state_label 下沉到 state node
- 最后改前端— 表单、详情、看板、时间线逐一适配