# 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` — 删除列 ```sql ALTER TABLE asset_log_entries DROP COLUMN location; ALTER TABLE asset_log_entries DROP COLUMN state_label; ``` #### `asset_state_nodes` — 新增列 ```sql 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`) ```python # 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 读取 | ### 实施顺序 1. **先做合并**(mission_merge_plan.md)— 减少条目数,简化后续迁移 2. **再做列迁移**(本文档)— 将 location/state_label 下沉到 state node 3. **最后改前端**— 表单、详情、看板、时间线逐一适配