diff --git a/.gitignore b/.gitignore
index 7359121..5528a3f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,3 +7,4 @@ instance/
.idea/
.pytest_cache/
.mypy_cache/
+user_input/
diff --git a/data_backup/asset_log_entries.json b/data_backup/asset_log_entries.json
new file mode 100644
index 0000000..882abe0
--- /dev/null
+++ b/data_backup/asset_log_entries.json
@@ -0,0 +1,2462 @@
+[
+ {
+ "id": "10030cb4-2626-483a-8682-db9eed90da71",
+ "asset_id": "00499acf-ce38-4e52-b672-caba96f81a2c",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2056-02-13T16:00:00+08:00",
+ "end_at": "2059-07-07T08:00:00+08:00",
+ "summary": "ST-03 Muelsyse Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.920852+08:00",
+ "updated_at": "2026-04-25T22:35:58.920852+08:00"
+ },
+ {
+ "id": "520e5ad4-e79c-458d-8387-76ba0a120b2e",
+ "asset_id": "00499acf-ce38-4e52-b672-caba96f81a2c",
+ "entry_kind": "state",
+ "title": "Assembly Complete",
+ "state_label": "Assembly Complete",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2059-07-07T08:00:00+08:00",
+ "end_at": "2059-08-12T08:00:00+08:00",
+ "summary": "Assembly complete, preparing for commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Assembly Complete",
+ "created_at": "2026-04-25T22:35:58.920852+08:00",
+ "updated_at": "2026-04-25T22:35:58.920852+08:00"
+ },
+ {
+ "id": "068b82d8-e107-465b-98b8-eba39739ee63",
+ "asset_id": "00499acf-ce38-4e52-b672-caba96f81a2c",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Lunar Orbit",
+ "start_at": "2059-08-12T08:00:00+08:00",
+ "end_at": "2060-03-07T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.920852+08:00",
+ "updated_at": "2026-04-25T22:35:58.920852+08:00"
+ },
+ {
+ "id": "16e6ce3d-d2ef-4910-a1ff-4670cbb63fb7",
+ "asset_id": "00499acf-ce38-4e52-b672-caba96f81a2c",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2060-03-07T08:00:00+08:00",
+ "end_at": "2060-06-10T08:00:00+08:00",
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.920852+08:00",
+ "updated_at": "2026-05-29T23:34:37.891588+08:00"
+ },
+ {
+ "id": "e61bb0d2-ab64-4f79-a18a-77dea92eb3ab",
+ "asset_id": "00499acf-ce38-4e52-b672-caba96f81a2c",
+ "entry_kind": "state",
+ "title": "Deep Space Test",
+ "state_label": "Deep Space Test",
+ "mission_label": null,
+ "location": "Sun-Earth L2",
+ "start_at": "2060-06-15T08:00:00+08:00",
+ "end_at": "2060-09-10T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-05-29T23:34:26.229065+08:00",
+ "updated_at": "2026-05-29T23:34:26.229065+08:00"
+ },
+ {
+ "id": "2f391faf-4061-45cc-bcd5-ce5956cff9bd",
+ "asset_id": "00499acf-ce38-4e52-b672-caba96f81a2c",
+ "entry_kind": "state",
+ "title": "Pre-commissioning Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2060-09-10T08:00:00+08:00",
+ "end_at": "2060-10-25T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-05-29T23:34:26.229065+08:00",
+ "updated_at": "2026-05-29T23:34:26.229065+08:00"
+ },
+ {
+ "id": "86055939-185d-476b-afc5-1a60a69a1ccb",
+ "asset_id": "02ee5188-f110-4121-883e-f2ecdbb121c4",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2059-09-16T16:00:00+08:00",
+ "end_at": "2061-08-10T08:00:00+08:00",
+ "summary": "XH-04 Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.955988+08:00",
+ "updated_at": "2026-04-25T22:35:58.955988+08:00"
+ },
+ {
+ "id": "d9b91820-7ea9-4f79-bca6-1fd450862c17",
+ "asset_id": "02ee5188-f110-4121-883e-f2ecdbb121c4",
+ "entry_kind": "state",
+ "title": "Assembly Complete",
+ "state_label": "Assembly Complete",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2061-08-10T08:00:00+08:00",
+ "end_at": "2061-09-15T08:00:00+08:00",
+ "summary": "Assembly complete, preparing for commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Assembly Complete",
+ "created_at": "2026-04-25T22:35:58.955988+08:00",
+ "updated_at": "2026-04-25T22:35:58.955988+08:00"
+ },
+ {
+ "id": "952a415e-408b-42a4-8dd8-24940e745d65",
+ "asset_id": "02ee5188-f110-4121-883e-f2ecdbb121c4",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2061-09-15T08:00:00+08:00",
+ "end_at": "2062-02-10T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.955988+08:00",
+ "updated_at": "2026-04-25T22:35:58.955988+08:00"
+ },
+ {
+ "id": "85aa5084-4c7a-4863-8bcc-ee9238d95d2c",
+ "asset_id": "02ee5188-f110-4121-883e-f2ecdbb121c4",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2062-02-10T08:00:00+08:00",
+ "end_at": null,
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.955988+08:00",
+ "updated_at": "2026-04-25T22:35:58.955988+08:00"
+ },
+ {
+ "id": "1934e3f4-0d0c-4699-b4bd-753744ab29a1",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2050-03-16T00:00:00+08:00",
+ "end_at": "2052-02-07T00:00:00+08:00",
+ "summary": "Xihe XH-01 Construction",
+ "note": "2050-03-15 First module delivered to LEO via Vulture Shuttle\r\n2052-02-06 Assembly completed in LEO",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.639519+08:00"
+ },
+ {
+ "id": "a0a3bed9-91a2-45c7-be54-7216e33f87b3",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Fitting",
+ "state_label": "Fitting",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2052-02-07T08:00:00+08:00",
+ "end_at": "2052-05-31T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "8ee54d7e-4310-43dc-a703-f633c1013405",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2052-06-01T08:00:00+08:00",
+ "end_at": "2052-11-30T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "2052-06-01 Begin Trial Run in Earth Orbit, testing all systems\n2052-11-30 Trial Run complete, all systems perform as expected. Including multiple run to GEO and Lunar Orbit before returning to LEO.",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "4464a892-910e-416c-b044-0683b6516003",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2052-12-01T08:00:00+08:00",
+ "end_at": "2053-01-05T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.660545+08:00"
+ },
+ {
+ "id": "d103bc92-da3a-4ba6-965e-a9385e208581",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Deep Space Test Mission",
+ "state_label": "Deep Space Test Mission",
+ "mission_label": null,
+ "location": "Earth-Sun L2",
+ "start_at": "2053-01-12T08:00:00+08:00",
+ "end_at": "2053-12-18T08:00:00+08:00",
+ "summary": "Long term uncrewed test",
+ "note": "2053-01-12 Uncrewed mission to Earth-Sun L2 point to test deep space operations\n2053-12-18 Back to LEO",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.709146+08:00"
+ },
+ {
+ "id": "80931042-da68-435b-94f5-da2d1b79e801",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Maintenance and Upgrades",
+ "state_label": "Maintenance and Upgrades",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2054-01-07T08:00:00+08:00",
+ "end_at": "2054-06-28T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "e54817e0-6809-404d-be62-c6017d143362",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MMD Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Mission Demo",
+ "location": "Sun",
+ "start_at": "2054-07-10T08:00:00+08:00",
+ "end_at": "2054-08-21T08:00:00+08:00",
+ "summary": "Earth-Mars transfer, Uses standard trajectory with 102km/s of departure burn",
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.709146+08:00"
+ },
+ {
+ "id": "23b4304f-8fca-4d78-8a93-c9f78fab51e0",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MMD Mars Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Mars Mission Demo",
+ "location": "Mars",
+ "start_at": "2054-08-21T08:00:00+08:00",
+ "end_at": "2055-01-10T08:00:00+08:00",
+ "summary": "Uncrewed, Deliver the first Mars-One base construction equipment package to Mars orbit.",
+ "note": "2054-08-21 Mars Orbit Arrival, deploy equipment package to Mars surface via lander\n2055-01-10 Mars Departure, return to Earth",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.645029+08:00"
+ },
+ {
+ "id": "ded06cd6-f9a4-4646-9be4-2f01cf067334",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MMD Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Mission Demo",
+ "location": "Sun",
+ "start_at": "2055-01-10T08:00:00+08:00",
+ "end_at": "2055-02-28T08:00:00+08:00",
+ "summary": "Uses standard trajectory with 97km/s of departure burn",
+ "note": "2055-02-28 Earth Arrival, demo run complete, all systems perform as expected.",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.709146+08:00"
+ },
+ {
+ "id": "fecc4450-ba77-4bc6-b794-164766a0c8b8",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Maintenance and Upgrades",
+ "state_label": "Maintenance and Upgrades",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2055-03-01T08:00:00+08:00",
+ "end_at": "2055-05-14T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.717638+08:00"
+ },
+ {
+ "id": "aab3125c-c99e-4af5-ab64-ffe7fda48ad7",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MOCM-1 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Base Construction Mission 1",
+ "location": "Sun",
+ "start_at": "2055-06-15T08:00:00+08:00",
+ "end_at": "2055-07-30T08:00:00+08:00",
+ "summary": "Earth-Mars transfer, Uses standard trajectory with 115km/s of departure burn",
+ "note": "2055-06-15 Picking up crew for Mars One base Construction Mission 1\n2055-06-18 Earth Departure for Mars",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "ec34d68b-4728-42eb-af79-b3e8805aa253",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MOCM-1 Mars Operations",
+ "state_label": "Base Construction",
+ "mission_label": "Mars One Base Construction Mission 1",
+ "location": "Mars",
+ "start_at": "2055-07-30T08:00:00+08:00",
+ "end_at": "2056-02-07T08:00:00+08:00",
+ "summary": "First Crewed mission to Mars. Construction for Mars One base begin",
+ "note": "2055-07-30 Mars Arrival, begin base construction\n2056-02-07 Mars Departure, return to Earth. First to use quick return trajectory.",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.709146+08:00"
+ },
+ {
+ "id": "bdf99335-d329-4bd2-8e17-27ac1f097ca9",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MOCM-1 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Base Construction Mission 1",
+ "location": "Sun",
+ "start_at": "2056-02-07T08:00:00+08:00",
+ "end_at": "2056-03-18T08:00:00+08:00",
+ "summary": "Mars-Earth transfer. Uses Fast-travel trajectory with 207km/s of departure burn",
+ "note": "2056-03-18 Earth Arrival, crew return",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.701350+08:00"
+ },
+ {
+ "id": "8e1be891-57ec-4551-b114-232f4681b2b1",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Maintenance and Upgrades",
+ "state_label": "Maintenance and Upgrades",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2056-03-25T08:00:00+08:00",
+ "end_at": "2056-06-20T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "ea2024c5-95e6-4acc-a88d-998183a35a5a",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MOCM-3 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Base Construction Mission 3",
+ "location": "Sun",
+ "start_at": "2056-07-30T08:00:00+08:00",
+ "end_at": "2056-09-15T08:00:00+08:00",
+ "summary": "Earth-Mars transfer. Uses standard trajectory with 95km/s of departure burn",
+ "note": "2056-07-30 Picking up crew for Mars One base Construction Mission 3\n2056-08-02 Earth Departure for Mars",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.709146+08:00"
+ },
+ {
+ "id": "fd22c4b2-4938-4c01-ae92-e84f14d8b8dd",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MOCM-3 Operations",
+ "state_label": "Base Construction",
+ "mission_label": "Mars One Base Construction Mission 3",
+ "location": "Mars",
+ "start_at": "2056-09-15T08:00:00+08:00",
+ "end_at": "2057-02-12T08:00:00+08:00",
+ "summary": "Third Mars One base construction. First crew hand-off on Mars(with Mars One base construction 2).",
+ "note": "2056-09-15 Mars Arrival, continue base construction\n2057-02-12 Mars Departure, return to Earth.",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.717638+08:00"
+ },
+ {
+ "id": "e5f549b9-0446-48be-a606-d9c1ada664b7",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "MOCM-3 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Base Construction Mission 3",
+ "location": "Sun",
+ "start_at": "2057-02-12T08:00:00+08:00",
+ "end_at": "2057-03-25T08:00:00+08:00",
+ "summary": "Mars-Earth transfer. Uses standard trajectory with 122km/s of departure burn",
+ "note": "2037-03-25 Earth Arrivasl, crew return",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.709146+08:00"
+ },
+ {
+ "id": "6d57910a-7459-4b74-b0ea-e10ee7cab87b",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2057-03-26T08:00:00+08:00",
+ "end_at": "2057-04-25T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.669628+08:00"
+ },
+ {
+ "id": "30c84287-e5d1-473c-93fb-9d36d426516e",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "ME-2 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Expedition 2",
+ "location": "Sun",
+ "start_at": "2057-05-05T08:00:00+08:00",
+ "end_at": "2057-06-22T08:00:00+08:00",
+ "summary": "Earth-Mars transfer using standard trajectory with 110km/s of departure burn",
+ "note": "2027-05-05 Picking up crew for Mars Expedition 2\n2027-05-09 Earth Departure for Mars",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.648632+08:00"
+ },
+ {
+ "id": "7f5da9b3-94fa-4bd5-a6bd-94f6841c71a2",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "ME-2 Mars Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Mars Expedition 2",
+ "location": "Mars",
+ "start_at": "2057-06-22T08:00:00+08:00",
+ "end_at": "2058-04-18T08:00:00+08:00",
+ "summary": "Second long term Mars Expedition, first mission to Mars One base after the construction is completed.\nFirst mission involving space tourism to Mars.",
+ "note": "2057-06-22 Mars Arrival\n2057-06-25 Mars EDL and surface operations begin\n2058-04-10 Begin Mars Departure preparations\n2058-04-18 Mars Departure for Earth",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "058bbf6d-5c51-49c4-8516-8b6931db53c1",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "ME-2 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Expedition 2",
+ "location": "Sun",
+ "start_at": "2058-04-18T08:00:00+08:00",
+ "end_at": "2058-05-20T08:00:00+08:00",
+ "summary": "Mars-Earth transfer using standard trajectory with 115km/s of departure burn",
+ "note": "2058-04-18 Mars Departure for Earth\n2058-05-20 Earth Arrival, crew return",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.623205+08:00"
+ },
+ {
+ "id": "161bb9f0-3d2a-46da-9044-9184e0704413",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2058-05-21T08:00:00+08:00",
+ "end_at": "2058-06-18T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.636520+08:00"
+ },
+ {
+ "id": "4ff368c4-503b-42ce-9e82-b4da291d3203",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "EE-1 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Expedition 1",
+ "location": "Sun",
+ "start_at": "2058-07-10T08:00:00+08:00",
+ "end_at": "2058-09-25T08:00:00+08:00",
+ "summary": "Earth-Jupiter transfer using standard trajectory with 160km/s of departure burn",
+ "note": "2058-07-10 Picking up crew for Europa Expedition 1\n2058-07-12 Earth Departure for Jupiter system\n2058-09-25 Europa Arrival",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.660545+08:00"
+ },
+ {
+ "id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "EE-1 Jupiter System Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Europa Expedition 1",
+ "location": "Jupiter System",
+ "start_at": "2058-09-25T08:00:00+08:00",
+ "end_at": "2059-07-10T08:00:00+08:00",
+ "summary": "First standard crew expedition to Europa Outpost to begin exploration of Jupiter system\nLong term surface operation at Europa Outpost, followed by exploration of IO and Ganymede",
+ "note": "2058-09-25 Europa Arrival\n2058-09-27 Europa descend, begin surface operation at Europa Outpost\n2058-12-15 Europa ascend, begin Jupiter system exploration\n2058-12-20 Begin IO exploration\n2059-01-20 Return to Europa Outpost\n2059-06-20 Begin Europa Outpost departure preparations\n2059-06-25 Europa Expedition 1 crew ascend from Europa Outpost\n2059-07-05 begin Ganymede exploration\n2059-07-10 Departure for Earth, upgrade planned.",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.717638+08:00"
+ },
+ {
+ "id": "92315017-7011-4930-aabb-d00a6f3f4994",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "EE-1 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Expedition 1",
+ "location": "Sun",
+ "start_at": "2059-07-10T08:00:00+08:00",
+ "end_at": "2059-11-15T08:00:00+08:00",
+ "summary": "Uses standard trajectory with 112km/s of departure burn\r\nParked to Star Port",
+ "note": "2059-07-10 Departure for Earth.\r\n2059-11-15 Earth Arrival, Park to Star Port.",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "21a37859-aa16-4c29-b17a-8012f6037478",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "Maintenance and Upgrades",
+ "state_label": "Maintenance and Upgrades",
+ "mission_label": null,
+ "location": "Star Port",
+ "start_at": "2059-11-16T08:00:00+08:00",
+ "end_at": "2060-02-19T08:00:00+08:00",
+ "summary": "Greenhouse upgrade to support long term deep space missions",
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.645029+08:00"
+ },
+ {
+ "id": "ee52cc53-7d9c-4134-ba1b-4f7cfb8fdce9",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "EE-3 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Expedition 3",
+ "location": "Sun",
+ "start_at": "2060-02-20T08:00:00+08:00",
+ "end_at": "2060-05-01T08:00:00+08:00",
+ "summary": "Uses standard trajectory with 163km/s of departure burn",
+ "note": "2060-02-20 Picking up Europa Expedition 3 crew, On its way to explore Jupiter systems before sending crew to Europa Outpost",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.716420+08:00"
+ },
+ {
+ "id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "asset_id": "0476b549-c13d-496d-81d4-dad3327ed070",
+ "entry_kind": "state",
+ "title": "EE-3 Jupiter System Operations",
+ "state_label": "Jupiter Exploration; Outpost Rotation",
+ "mission_label": "Europa Expedition 3",
+ "location": "Jupiter System",
+ "start_at": "2060-05-01T08:00:00+08:00",
+ "end_at": null,
+ "summary": "Crew Rotation to Euorpa Outpost. First to explore Jupiter's moons, then to Europa Outpost",
+ "note": "2060-05-01 Jupiter Arrival\r\n2060-05-02 Io Arrival\r\n2060-05-07 Io descend\r\n2060-05-09 Io departure\r\n2060-05-11 Ganymede Arrival\r\n2060-05-12 Ganymede descend\r\n2060-05-21 Ganymede Departure for Callisto\r\n2060-05-25 Callisto Arrival",
+ "created_at": "2026-04-24T17:22:19.272240+08:00",
+ "updated_at": "2026-04-25T18:31:36.684969+08:00"
+ },
+ {
+ "id": "505255ab-902e-4586-9905-8ecad10353e7",
+ "asset_id": "2036b4dc-860e-450a-9e16-d81c9b912847",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2058-02-15T16:00:00+08:00",
+ "end_at": "2059-12-09T08:00:00+08:00",
+ "summary": "XH-03 \u5e38\u66e6 Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.908202+08:00",
+ "updated_at": "2026-04-25T22:35:58.908202+08:00"
+ },
+ {
+ "id": "b0848762-4f30-45fa-9e5f-5e53a0a7aba3",
+ "asset_id": "2036b4dc-860e-450a-9e16-d81c9b912847",
+ "entry_kind": "state",
+ "title": "Assembly Complete",
+ "state_label": "Assembly Complete",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2059-12-09T08:00:00+08:00",
+ "end_at": "2060-01-14T08:00:00+08:00",
+ "summary": "Assembly complete, preparing for commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Assembly Complete",
+ "created_at": "2026-04-25T22:35:58.908202+08:00",
+ "updated_at": "2026-04-25T22:35:58.908202+08:00"
+ },
+ {
+ "id": "b87ea1ef-b240-48f7-aba8-0af7566bd6be",
+ "asset_id": "2036b4dc-860e-450a-9e16-d81c9b912847",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2060-01-14T08:00:00+08:00",
+ "end_at": "2060-06-09T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.908202+08:00",
+ "updated_at": "2026-04-25T22:35:58.908202+08:00"
+ },
+ {
+ "id": "bdc91489-7c65-45c2-bd78-4a37edc9dd4e",
+ "asset_id": "2036b4dc-860e-450a-9e16-d81c9b912847",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2060-06-09T08:00:00+08:00",
+ "end_at": null,
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.908202+08:00",
+ "updated_at": "2026-04-25T22:35:58.908202+08:00"
+ },
+ {
+ "id": "219355f0-1399-49af-b352-6728f0d4c82b",
+ "asset_id": "404a1002-0f77-4d43-8c53-73698829c362",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "Star Port",
+ "start_at": "2059-01-14T16:00:00+08:00",
+ "end_at": "2059-12-14T08:00:00+08:00",
+ "summary": "Solar Shuttle 3 Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.942491+08:00",
+ "updated_at": "2026-04-25T23:37:43.445756+08:00"
+ },
+ {
+ "id": "aac31a1a-45c7-47f4-add3-fbfa30f9011f",
+ "asset_id": "404a1002-0f77-4d43-8c53-73698829c362",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2059-12-14T08:00:00+08:00",
+ "end_at": "2060-02-20T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.942491+08:00",
+ "updated_at": "2026-04-25T23:26:09.158415+08:00"
+ },
+ {
+ "id": "7deb1192-d6f0-4635-9a6d-39ab0c2adcfe",
+ "asset_id": "404a1002-0f77-4d43-8c53-73698829c362",
+ "entry_kind": "state",
+ "title": "Mars One Rover Delivery",
+ "state_label": "Cargo Delivery",
+ "mission_label": "Mars One Rover Delivery",
+ "location": "Mars",
+ "start_at": "2060-02-23T08:00:00+08:00",
+ "end_at": "2060-05-23T08:00:00+08:00",
+ "summary": "Mars One Rover Delivery",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Mars One Rover Delivery",
+ "created_at": "2026-04-25T22:35:58.942491+08:00",
+ "updated_at": "2026-04-25T23:27:06.181776+08:00"
+ },
+ {
+ "id": "d33a6759-0f54-4e71-909b-6d3916ca13dc",
+ "asset_id": "404a1002-0f77-4d43-8c53-73698829c362",
+ "entry_kind": "state",
+ "title": "Mars Return",
+ "state_label": "Transfer",
+ "mission_label": null,
+ "location": "Sun",
+ "start_at": "2060-11-05T04:07:00+08:00",
+ "end_at": null,
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T23:37:22.116139+08:00",
+ "updated_at": "2026-04-25T23:37:22.116139+08:00"
+ },
+ {
+ "id": "5df95fe3-5f0d-4dc1-ad37-508adcf2eef2",
+ "asset_id": "aab27974-0fc9-439e-9d6d-0a607cd5e5fb",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "Star Port",
+ "start_at": "2058-03-14T16:00:00+08:00",
+ "end_at": "2059-03-08T08:00:00+08:00",
+ "summary": "Solar Shuttle 1 Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.927718+08:00",
+ "updated_at": "2026-04-25T23:38:03.603460+08:00"
+ },
+ {
+ "id": "e306c665-07c0-46dc-8127-b96775d616b9",
+ "asset_id": "aab27974-0fc9-439e-9d6d-0a607cd5e5fb",
+ "entry_kind": "state",
+ "title": "Assembly Complete",
+ "state_label": "Assembly Complete",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2059-03-08T08:00:00+08:00",
+ "end_at": "2059-04-13T08:00:00+08:00",
+ "summary": "Assembly complete, preparing for commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Assembly Complete",
+ "created_at": "2026-04-25T22:35:58.927718+08:00",
+ "updated_at": "2026-04-25T22:35:58.927718+08:00"
+ },
+ {
+ "id": "543dabdc-e61b-4a1c-8c4b-3e753d17cbbd",
+ "asset_id": "aab27974-0fc9-439e-9d6d-0a607cd5e5fb",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2059-04-13T08:00:00+08:00",
+ "end_at": "2059-08-06T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.927718+08:00",
+ "updated_at": "2026-04-25T22:35:58.927718+08:00"
+ },
+ {
+ "id": "b99062ea-4547-4cdc-8bf1-3b1f0c28a4be",
+ "asset_id": "aab27974-0fc9-439e-9d6d-0a607cd5e5fb",
+ "entry_kind": "state",
+ "title": "Mars One Expansion Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Expansion",
+ "location": "Sun",
+ "start_at": "2059-08-06T08:00:00+08:00",
+ "end_at": "2059-10-24T08:00:00+08:00",
+ "summary": "Earth-Mars transfer",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Earth-Mars",
+ "created_at": "2026-04-25T22:35:58.927718+08:00",
+ "updated_at": "2026-04-25T23:38:25.818242+08:00"
+ },
+ {
+ "id": "30930d1b-d32b-4ef6-97ae-6d11c777ad53",
+ "asset_id": "aab27974-0fc9-439e-9d6d-0a607cd5e5fb",
+ "entry_kind": "state",
+ "title": "Mars One Expansion",
+ "state_label": "Base Expansion",
+ "mission_label": "Mars One Expansion",
+ "location": "Mars",
+ "start_at": "2059-10-19T08:00:00+08:00",
+ "end_at": "2060-08-09T05:10:00+08:00",
+ "summary": "Mars One Expansion",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Mars One Expansion",
+ "created_at": "2026-04-25T22:35:58.927718+08:00",
+ "updated_at": "2026-04-25T23:39:17.397334+08:00"
+ },
+ {
+ "id": "00c8b5c6-e363-4aee-a768-2fc3fa7a0138",
+ "asset_id": "aab27974-0fc9-439e-9d6d-0a607cd5e5fb",
+ "entry_kind": "state",
+ "title": "Mars Return",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Expansion",
+ "location": "Sun",
+ "start_at": "2060-08-09T05:10:00+08:00",
+ "end_at": "2060-10-26T10:03:00+08:00",
+ "summary": "Back to Earth with Qingtian",
+ "note": "Carrying Mars One component back",
+ "created_at": "2026-04-25T23:40:01.538925+08:00",
+ "updated_at": "2026-05-10T15:31:44.067131+08:00"
+ },
+ {
+ "id": "ae003c1f-f74e-459b-ade2-74fcdae48605",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2050-09-15T16:00:00+08:00",
+ "end_at": "2054-04-28T16:00:00+08:00",
+ "summary": "Construction",
+ "note": "2050-09-15 First module delivered to LEO via Vulture Shuttle\r\n2053-02-02 Assembly Halted",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T21:48:29.034208+08:00"
+ },
+ {
+ "id": "105a5eac-4ca1-4a5a-a9ad-bc2278d46f01",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Lunar Orbit",
+ "start_at": "2054-05-12T08:00:00+08:00",
+ "end_at": "2054-08-22T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "2054-05-12 Begin Trial Run in Earth Orbit, testing all systems\n2054-08-22 Trial Run complete, all systems perform as expected. Including multiple run to GEO and Lunar Orbit before returning to LEO.",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.626203+08:00"
+ },
+ {
+ "id": "f6ae082d-5c36-44f9-92da-d5e568a71fea",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Deep Space Test Mission",
+ "state_label": "Deep Space Test Mission",
+ "mission_label": null,
+ "location": "Earth-Sun L2",
+ "start_at": "2054-09-07T08:00:00+08:00",
+ "end_at": "2054-11-28T08:00:00+08:00",
+ "summary": "Uncrewed mission to Earth-Sun Lagrange Point 2 to test long-duration operations",
+ "note": "2054-09-07 Begin Deep Space Test Mission\n2054-11-28 Test Mission Complete, all systems nominal. Returning to LEO.",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.717638+08:00"
+ },
+ {
+ "id": "503a0035-1cd7-4e8e-9bc6-922c2e5c3171",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Maintenance before Commissioning",
+ "state_label": "Maintenance before Commissioning",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2054-12-01T08:00:00+08:00",
+ "end_at": "2055-02-28T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.669628+08:00"
+ },
+ {
+ "id": "4bfddc84-dfec-43e3-b534-4fb798bcc73f",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "ISSEM-1 Mercury Transfer",
+ "state_label": "Transfer",
+ "mission_label": "Inner Solar System Exploration Mission 1",
+ "location": "Sun",
+ "start_at": "2055-03-20T08:00:00+08:00",
+ "end_at": "2055-04-17T08:00:00+08:00",
+ "summary": "Earth-Mecury transfer, using standard trajectory with 127km/s of departure burn",
+ "note": "2055-03-20 Picking up crew for Inner Solar System Exploration Mission 1\n2055-03-22 Earth Departure for Mecury\n2055-04-17 Mercury Arrival",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.660545+08:00"
+ },
+ {
+ "id": "42698c8c-a1cc-4742-9885-7b9e650f9867",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "ISSEM-1 Mercury Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Inner Solar System Exploration Mission 1",
+ "location": "Mercury",
+ "start_at": "2055-04-18T08:00:00+08:00",
+ "end_at": "2055-08-14T08:00:00+08:00",
+ "summary": "First crewed mission to Mercury",
+ "note": "2055-04-17 Mercury Arrival\n2055-04-18 Orbital Survey of Mercury begins\n2055-06-14 First Crewed Surface Landing on Mercury\n2055-06-15 EVA operations commence\n2055-06-30 Surface operations complete, returning to orbit\n2055-08-15 Departure from Mercury for Venus",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.648632+08:00"
+ },
+ {
+ "id": "2adfa016-b23a-4459-af6e-a84da2aa2469",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "ISSEM-1 Venus Transfer",
+ "state_label": "Transfer",
+ "mission_label": "Inner Solar System Exploration Mission 1",
+ "location": "Sun",
+ "start_at": "2055-08-15T08:00:00+08:00",
+ "end_at": "2055-10-01T08:00:00+08:00",
+ "summary": "Mecury-Venus transfer, using standard trajectory with 85km/s of departure burn",
+ "note": "2055-08-15 Departure from Mercury for Venus\n2055-10-01 Venus Arrival",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.648632+08:00"
+ },
+ {
+ "id": "f28469ee-1dbc-4232-98ff-91f7abcb9d59",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "ISSEM-1 Venus Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Inner Solar System Exploration Mission 1",
+ "location": "Venus",
+ "start_at": "2055-10-01T08:00:00+08:00",
+ "end_at": "2056-03-24T08:00:00+08:00",
+ "summary": "First crewed mission to Venus, no crewed landing attempted due to extreme surface conditions. Probe deployment only.",
+ "note": "2055-10-01 Venus Arrival\n2055-10-02 Orbital Survey of Venus begins\n2055-10-10 Landing Probe Deployment\n2055-11-10 Begin Upper Atmosphere Survey via Callisto MPV\n2056-03-24 Departure from Venus for Earth",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.717638+08:00"
+ },
+ {
+ "id": "1f6e85aa-121a-4f47-95b6-35f040da055c",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "ISSEM-1 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Inner Solar System Exploration Mission 1",
+ "location": "Sun",
+ "start_at": "2056-03-24T08:00:00+08:00",
+ "end_at": "2056-04-12T08:00:00+08:00",
+ "summary": "Venus-Earth transfer, using standard trajectory with 75km/s of departure burn",
+ "note": "2056-03-24 Departure from Venus for Earth\n2056-04-12 Earth Arrival",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.642529+08:00"
+ },
+ {
+ "id": "540c146e-0d48-4735-8eb4-6fe08506b705",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2056-04-15T08:00:00+08:00",
+ "end_at": "2056-05-31T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.669628+08:00"
+ },
+ {
+ "id": "ffd625b0-0de4-4f47-8c8d-36669a1675f6",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "MOCM-2 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Construction Mission 2",
+ "location": "Sun",
+ "start_at": "2056-06-02T08:00:00+08:00",
+ "end_at": "2056-07-01T08:00:00+08:00",
+ "summary": "Earth-Mars transfer, using standard trajectory with 126km/s of departure burn",
+ "note": "2056-06-02 Picking up crew for Mars One Construction Mission 2\n2056-06-04 Picking up Mars One construction cargo\n2056-06-06 Earth Departure for Mars\n2056-07-01 Mars Arrival, First crewed mission to Mars using Stellaria",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.717638+08:00"
+ },
+ {
+ "id": "12059276-d10a-4a37-9b8c-6a6183768504",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "MOCM-2 Mars Operations",
+ "state_label": "Base Construction",
+ "mission_label": "Mars One Construction Mission 2",
+ "location": "Mars",
+ "start_at": "2056-07-03T08:00:00+08:00",
+ "end_at": "2056-10-12T08:00:00+08:00",
+ "summary": "Continuing the construction of Mars One Base",
+ "note": "2056-07-03 Crew descend to Martian Surface, Continuing the construction of Mars One Base\n2056-07-20 Heavy Cargo Delivery to Surface via Callisto MPV\n2056-09-17 Mars One Construction Mission 3 Crew Arrival via XH-01, joining Stellaria crew. First Crew Handover on Mars.\n2056-10-12 Mars One Construction Mission 2 Crew ascend to Stellaria\n2056-10-15 Departure from Mars for Earth",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.632520+08:00"
+ },
+ {
+ "id": "cf351aa5-4149-4938-939b-edcb846f4b14",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "MOCM-2 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars One Construction Mission 2",
+ "location": "Sun",
+ "start_at": "2056-10-15T08:00:00+08:00",
+ "end_at": "2056-11-03T08:00:00+08:00",
+ "summary": "Mars-Earth transfer, using Fast Return trajectory with 212km/s of departure burn",
+ "note": "2056-10-15 Departure from Mars for Earth\n2056-11-03 Earth Arrival",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.709146+08:00"
+ },
+ {
+ "id": "fd8fba0b-82bb-4ad3-bc38-58745291627b",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2056-11-04T08:00:00+08:00",
+ "end_at": "2056-12-10T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.717638+08:00"
+ },
+ {
+ "id": "7747339c-f602-4ddf-8511-6862006f789b",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "EOCM-1 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Outpost Construction Mission 1",
+ "location": "Sun",
+ "start_at": "2056-12-15T08:00:00+08:00",
+ "end_at": "2057-02-25T08:00:00+08:00",
+ "summary": "Earth-Europa transfer, using standard trajectory with 165km/s of departure burn",
+ "note": "2056-12-15 Start preparations for Europa Outpost Construction Mission 1\n2056-12-20 Europa Outpost Construction Package arrival via Qingtian Cargo Shuttle\n2056-12-31 Picking up crew for Europa Outpost Construction Mission 1 \n2057-01-02 Earth Departure for Europa",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.669628+08:00"
+ },
+ {
+ "id": "545f687e-bd2c-409a-8fb8-186a6dead67e",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "EOCM-1 Europa Operations",
+ "state_label": "Outpost Construction",
+ "mission_label": "Europa Outpost Construction Mission 1",
+ "location": "Europa",
+ "start_at": "2057-02-27T08:00:00+08:00",
+ "end_at": "2057-10-01T08:00:00+08:00",
+ "summary": "First crewed mission to Europa",
+ "note": "2057-02-27 Heavy Cargo Delivery to Surface via Qingtian Cargo Shuttle\n2057-03-15 Crew descend to Europan Surface, Beginning construction of Europa Outpost\n6 crewed ascend and descend operations to Europa Surface via Callisto MPV between 2057-03-15 and 2057-09-15\n2057-10-01 Europa Outpost Construction Mission 1 Crew ascend to Stellaria, wrapping up construction phase 1\n2057-10-04 Europa Departure for Earth",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:31:36.669628+08:00"
+ },
+ {
+ "id": "43f2ece9-283b-4484-b838-d684b9ada4d6",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "EOCM-1 return to Earth",
+ "state_label": "Transfer",
+ "mission_label": "Europa Outpost Construction Mission 1",
+ "location": "Europa",
+ "start_at": "2057-10-04T08:00:00+08:00",
+ "end_at": "2057-12-20T08:00:00+08:00",
+ "summary": "Europa-Earth transfer, using Fast trajectory with 216km/s of departure burn",
+ "note": "2057-10-04 Europa Departure for Earth\r\n2057-12-20 Earth Arrival",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:16:48.251361+08:00"
+ },
+ {
+ "id": "7d6a56c8-9ebc-4940-813b-54ee2c9711f4",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Maintenance and Upgrades",
+ "state_label": "Maintenance and Upgrades",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2058-01-05T08:00:00+08:00",
+ "end_at": "2058-05-15T08:00:00+08:00",
+ "summary": "Extensive overhauls to bring ST-01 closer to full Stellaria specifications. Add more greenhouse modules, upgrade life support systems, add another Rotating Habitat Ring",
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:18:22.608112+08:00"
+ },
+ {
+ "id": "cad8537e-1966-4b3c-abed-35c511950ac8",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "SEM-1 outbound",
+ "state_label": "Transfer",
+ "mission_label": "Saturn Exploration Mission 1",
+ "location": "Sun",
+ "start_at": "2058-06-01T08:00:00+08:00",
+ "end_at": "2058-10-12T08:00:00+08:00",
+ "summary": "Earth-Saturn transfer, using Fast trajectory with 210km/s of departure burn",
+ "note": "First crewed mission to Saturn",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:14:23.329000+08:00"
+ },
+ {
+ "id": "022b0296-5c1a-41f8-8634-97dc663b05d9",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "SEM-1 Saturn Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Saturn Exploration Mission 1",
+ "location": "Saturn System",
+ "start_at": "2058-10-12T08:00:00+08:00",
+ "end_at": "2059-07-01T08:00:00+08:00",
+ "summary": "First crewed mission to Saturn",
+ "note": "2059-05-31 Parked into Iapetus orbit, orbital science completed\r\n2059-06-15 Start Iapetus Surface operation",
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:15:48.795002+08:00"
+ },
+ {
+ "id": "f536e950-a024-45e3-95ff-da5f77772119",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "SEM-1 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Saturn Exploration Mission 1",
+ "location": "Sun",
+ "start_at": "2059-07-01T08:00:00+08:00",
+ "end_at": "2059-11-24T08:00:00+08:00",
+ "summary": "Saturn-Earth transfer, using standard trajectory with 162km/s of departure burn",
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:10:08.247577+08:00"
+ },
+ {
+ "id": "3fce336c-7ac9-4117-9239-bf939dfe1ad1",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "Maintenance and Upgrades",
+ "state_label": "Maintenance and Upgrades",
+ "mission_label": null,
+ "location": "Star Port",
+ "start_at": "2059-11-25T08:00:00+08:00",
+ "end_at": "2060-02-10T08:00:00+08:00",
+ "summary": "Upgrades complete, ST-01 now fully meets Stellaria specifications.",
+ "note": null,
+ "created_at": "2026-04-24T17:22:19.347840+08:00",
+ "updated_at": "2026-04-25T18:18:09.129398+08:00"
+ },
+ {
+ "id": "8a9de074-6348-4190-bd27-e3bdeddb70f7",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "OSSEM-1 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Outer Solar System Exploration Mission 1",
+ "location": "Sun",
+ "start_at": "2060-02-11T08:00:00+08:00",
+ "end_at": "2060-07-24T20:11:00+08:00",
+ "summary": "\u5730\u7403\u51fa\u53d1\u524d\u5f80\u6d77\u738b\u661f",
+ "note": "23 crew on board",
+ "created_at": "2026-04-25T17:18:14.434702+08:00",
+ "updated_at": "2026-05-10T00:24:16.860537+08:00"
+ },
+ {
+ "id": "18b3429e-28d3-489c-b65c-35e0e9775a0d",
+ "asset_id": "b789365d-8427-4f3b-8be7-7cf43d553202",
+ "entry_kind": "state",
+ "title": "OSSEM-1 Neptune Exploration",
+ "state_label": "Exploration",
+ "mission_label": "OSSEM-1; Neptune",
+ "location": "Neptune",
+ "start_at": "2060-07-25T06:40:00+08:00",
+ "end_at": null,
+ "summary": null,
+ "note": null,
+ "created_at": "2026-05-10T00:27:51.926875+08:00",
+ "updated_at": "2026-05-10T00:27:51.926875+08:00"
+ },
+ {
+ "id": "d190cc9e-e230-4299-8f13-1bda0f6b1aac",
+ "asset_id": "c1f641ab-cd34-4894-bc38-eb66a11681d6",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2058-09-17T16:00:00+08:00",
+ "end_at": "2059-09-11T08:00:00+08:00",
+ "summary": "Solar Shuttle 2 Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.935718+08:00",
+ "updated_at": "2026-04-25T22:35:58.935718+08:00"
+ },
+ {
+ "id": "8e33ce9e-2409-4b1c-af09-6a931fbe2d49",
+ "asset_id": "c1f641ab-cd34-4894-bc38-eb66a11681d6",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2059-09-11T08:00:00+08:00",
+ "end_at": "2059-12-01T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.935718+08:00",
+ "updated_at": "2026-04-25T23:18:46.585239+08:00"
+ },
+ {
+ "id": "5a2092a8-ddad-41b3-9819-fa52557332ed",
+ "asset_id": "c1f641ab-cd34-4894-bc38-eb66a11681d6",
+ "entry_kind": "state",
+ "title": "EOEM Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Outpost Expansion Mission",
+ "location": "Sun",
+ "start_at": "2059-12-09T08:00:00+08:00",
+ "end_at": "2060-05-01T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T23:21:18.903453+08:00",
+ "updated_at": "2026-04-27T10:29:55.306589+08:00"
+ },
+ {
+ "id": "c0271f19-e604-4c15-9c00-7118fec1928e",
+ "asset_id": "c1f641ab-cd34-4894-bc38-eb66a11681d6",
+ "entry_kind": "state",
+ "title": "Europa Outpost Expansion Mission",
+ "state_label": "Outpost Expansion",
+ "mission_label": "Europa Outpost Expansion Mission",
+ "location": "Europa",
+ "start_at": "2060-05-01T08:00:00+08:00",
+ "end_at": "2060-05-06T07:25:00+08:00",
+ "summary": "Europa Outpost Expansion Package delivered via Qingtian Cargo Spacecraft",
+ "note": null,
+ "created_at": "2026-04-25T22:35:58.935718+08:00",
+ "updated_at": "2026-04-25T23:23:22.197409+08:00"
+ },
+ {
+ "id": "687615b6-144f-4fd5-b3ee-709e4eaea6aa",
+ "asset_id": "c1f641ab-cd34-4894-bc38-eb66a11681d6",
+ "entry_kind": "state",
+ "title": "EOEM Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Outpost Expansion Mission",
+ "location": "Sun",
+ "start_at": "2060-05-06T07:25:00+08:00",
+ "end_at": "2060-06-26T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T23:25:17.145157+08:00",
+ "updated_at": "2026-04-25T23:25:17.145157+08:00"
+ },
+ {
+ "id": "00aec49b-6dc1-4b58-bbf1-96086b93ff0e",
+ "asset_id": "c5bc9c32-6bb1-46af-9cb6-580b3ba47074",
+ "entry_kind": "state",
+ "title": "Expedition 11",
+ "state_label": "Standard Rotation",
+ "mission_label": "Expedition 11",
+ "location": "LEO",
+ "start_at": "2059-05-04T01:02:00+08:00",
+ "end_at": "2059-11-16T20:55:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T12:48:39.947435+08:00",
+ "updated_at": "2026-04-25T12:48:39.947435+08:00"
+ },
+ {
+ "id": "1c346955-ba6b-4f54-9308-d088fa99f766",
+ "asset_id": "c5bc9c32-6bb1-46af-9cb6-580b3ba47074",
+ "entry_kind": "state",
+ "title": "Expedition 12",
+ "state_label": "Standard Rotation",
+ "mission_label": "Expedition 12",
+ "location": "LEO",
+ "start_at": "2059-11-16T16:00:00+08:00",
+ "end_at": "2060-05-15T01:44:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T12:50:31.817700+08:00",
+ "updated_at": "2026-04-25T12:50:31.817700+08:00"
+ },
+ {
+ "id": "7c74d703-98bc-486d-b06f-591f38661181",
+ "asset_id": "c5bc9c32-6bb1-46af-9cb6-580b3ba47074",
+ "entry_kind": "state",
+ "title": "Expedition 13",
+ "state_label": "Standard Rotation",
+ "mission_label": "Expedition 13",
+ "location": "LEO",
+ "start_at": "2060-05-12T15:40:00+08:00",
+ "end_at": "2060-11-12T15:40:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T12:51:19.178729+08:00",
+ "updated_at": "2026-04-25T12:52:20.250876+08:00"
+ },
+ {
+ "id": "3c81a7b5-4f86-4f48-aa6f-99dec955dc42",
+ "asset_id": "c5bc9c32-6bb1-46af-9cb6-580b3ba47074",
+ "entry_kind": "event",
+ "title": "Reconfigure to \u542f\u660e\u7a7a\u95f4\u7ad9",
+ "state_label": null,
+ "mission_label": "\u542f\u660e\u8f7d\u4eba\u822a\u5929\u8ba1\u5212",
+ "location": "LEO",
+ "start_at": "2060-07-06T17:15:00+08:00",
+ "end_at": null,
+ "summary": "\u51c6\u5907\u8fdb\u884c\u7a7a\u95f4\u7ad9\u683c\u5c40\u8c03\u6574\uff0c\u5229\u7528\u73b0\u6709\u57fa\u7840\u8bbe\u65bd\u6784\u5efa\u542f\u660e\u7a7a\u95f4\u7ad9",
+ "note": null,
+ "created_at": "2026-04-24T21:04:35.651089+08:00",
+ "updated_at": "2026-04-25T12:49:13.937315+08:00"
+ },
+ {
+ "id": "4d14317f-3e78-4e9e-9a9c-a9555ef15b24",
+ "asset_id": "c5bc9c32-6bb1-46af-9cb6-580b3ba47074",
+ "entry_kind": "state",
+ "title": "\u542f\u660e\u7a7a\u95f4\u7ad9\u91cd\u529b\u6a21\u5757\u5347\u7ea7",
+ "state_label": "\u542f\u660e\u7a7a\u95f4\u7ad9\u91cd\u529b\u6a21\u5757\u5347\u7ea7",
+ "mission_label": "\u542f\u660e\u8f7d\u4eba\u822a\u5929\u8ba1\u5212",
+ "location": "LEO",
+ "start_at": "2060-07-06T20:40:00+08:00",
+ "end_at": "2060-09-15T20:55:00+08:00",
+ "summary": "\u64ce\u5929E3\u53d1\u5c04\uff0c\u8fd0\u9001\u4e86\u5168\u65b0\u7684\u8282\u70b9\u8231\u548c\u4eba\u5de5\u91cd\u529b\u6a21\u5757\uff0c\u7531Expedition 13\u4e58\u7ec4\u5b8c\u6210\u5b89\u88c5",
+ "note": null,
+ "created_at": "2026-04-24T22:40:14.736688+08:00",
+ "updated_at": "2026-04-24T22:42:28.050488+08:00"
+ },
+ {
+ "id": "b5fceb9b-264c-4842-a329-0a7c4ccc9779",
+ "asset_id": "cacec9d5-5f6f-48fa-a09e-53a1eae9dd62",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2059-07-12T16:00:00+08:00",
+ "end_at": "2063-01-07T08:00:00+08:00",
+ "summary": "ST-04 Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.966695+08:00",
+ "updated_at": "2026-04-25T22:35:58.966695+08:00"
+ },
+ {
+ "id": "4dfd3584-ad5c-4d6d-9c86-d337d627fb9e",
+ "asset_id": "cacec9d5-5f6f-48fa-a09e-53a1eae9dd62",
+ "entry_kind": "state",
+ "title": "Assembly Complete",
+ "state_label": "Assembly Complete",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2063-01-07T08:00:00+08:00",
+ "end_at": "2063-02-12T08:00:00+08:00",
+ "summary": "Assembly complete, preparing for commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Assembly Complete",
+ "created_at": "2026-04-25T22:35:58.966695+08:00",
+ "updated_at": "2026-04-25T22:35:58.966695+08:00"
+ },
+ {
+ "id": "93f7700f-d0be-48a9-8fdf-f1d0a824ac86",
+ "asset_id": "cacec9d5-5f6f-48fa-a09e-53a1eae9dd62",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Lunar Orbit",
+ "start_at": "2063-02-12T08:00:00+08:00",
+ "end_at": "2063-09-06T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.966695+08:00",
+ "updated_at": "2026-04-25T22:35:58.966695+08:00"
+ },
+ {
+ "id": "c6ac0899-e235-4de6-8a9e-89ff98e725fa",
+ "asset_id": "cacec9d5-5f6f-48fa-a09e-53a1eae9dd62",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2063-09-06T16:00:00+08:00",
+ "end_at": null,
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.966695+08:00",
+ "updated_at": "2026-05-09T23:57:24.013205+08:00"
+ },
+ {
+ "id": "eefd7712-b6f4-496c-9bc8-8eb9546887b8",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2052-01-14T16:00:00+08:00",
+ "end_at": "2053-02-10T08:00:00+08:00",
+ "summary": "ST-02 Kristen Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "721dec30-3c58-4885-8fda-22e2960ef4a0",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Assembly Halted",
+ "state_label": "Assembly Halted",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2053-02-10T08:00:00+08:00",
+ "end_at": "2053-05-12T08:00:00+08:00",
+ "summary": "Assembly halted pending redesign and program review",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Assembly Halted",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "8226a3aa-1896-42e2-9e5e-0fca750d229d",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Reconfiguring to ST-02",
+ "state_label": "Reconfiguring to ST-02",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2053-05-12T08:00:00+08:00",
+ "end_at": "2055-10-13T08:00:00+08:00",
+ "summary": "Vehicle reconfiguration and systems integration",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Reconfiguring to ST-02",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "826e67d8-e876-41e5-9551-a80f700e90cd",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Lunar Orbit",
+ "start_at": "2055-10-13T08:00:00+08:00",
+ "end_at": "2056-03-10T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "b5a01aed-7a98-4f81-a84f-efb59b8f2479",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Deep Space Test Mission",
+ "state_label": "Deep Space Test Mission",
+ "mission_label": null,
+ "location": "Earth-Sun L2",
+ "start_at": "2056-03-10T08:00:00+08:00",
+ "end_at": "2056-06-08T08:00:00+08:00",
+ "summary": "Uncrewed Mission to Earth-Sun L2",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Deep Space Test Mission / Uncrewed Mission to Earth-Sun L2",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "7b7fd38f-2647-4ed8-b1bc-27e94861b15d",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2056-06-08T08:00:00+08:00",
+ "end_at": "2056-11-19T08:00:00+08:00",
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "ca8f8223-800b-4562-8405-a270d3960a6e",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "ME-1 Mars Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Mars Expedition 1",
+ "location": "Mars",
+ "start_at": "2056-11-19T08:00:00+08:00",
+ "end_at": "2057-09-08T08:00:00+08:00",
+ "summary": "Mars Expedition 1",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Mars Expedition 1",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "a7c43eae-31fc-451d-8bbc-fd6f3da63f22",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2057-09-08T08:00:00+08:00",
+ "end_at": "2057-10-06T08:00:00+08:00",
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "a61ee6fc-5495-4b5b-a505-968669b81b18",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "EOCM-2 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Outpost Construction Mission 2",
+ "location": "Sun",
+ "start_at": "2057-10-06T08:00:00+08:00",
+ "end_at": "2058-01-19T08:00:00+08:00",
+ "summary": "Earth-Europa transfer",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Earth-Europa",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "fb17cab1-dcbc-4814-83e9-5fb81a73f869",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "EOCM-2 Europa Operations",
+ "state_label": "Outpost Construction",
+ "mission_label": "Europa Outpost Construction Mission 2",
+ "location": "Europa",
+ "start_at": "2058-01-19T08:00:00+08:00",
+ "end_at": "2058-09-06T08:00:00+08:00",
+ "summary": "Europa Outpost Construction Mission 2",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Europa Outpost Construction Mission 2",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "efdb28dd-3e02-4b16-80e8-7a2d4df76825",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "EOCM-2 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Outpost Construction Mission 2",
+ "location": "Sun",
+ "start_at": "2058-09-06T08:00:00+08:00",
+ "end_at": "2058-11-08T08:00:00+08:00",
+ "summary": "Europa-Earth transfer",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Europa-Earth",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "77c71061-354d-4045-b5cd-5cd6b1e8dd65",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Maintenance and Upgrades",
+ "state_label": "Maintenance and Upgrades",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2058-11-08T08:00:00+08:00",
+ "end_at": "2059-04-06T08:00:00+08:00",
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance and Upgrades",
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T22:35:58.886747+08:00"
+ },
+ {
+ "id": "fe21560f-60f4-48bb-bbdb-e2c1ab6fe3af",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "EE-2 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Expedition 2",
+ "location": "Sun",
+ "start_at": "2059-04-06T08:00:00+08:00",
+ "end_at": "2059-06-25T08:00:00+08:00",
+ "summary": "Earth-Europa transfer",
+ "note": null,
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T23:04:37.198110+08:00"
+ },
+ {
+ "id": "65910288-0c2a-4800-bfce-39495efafce2",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "EE-2 Europa Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Europa Expedition 2",
+ "location": "Europa",
+ "start_at": "2059-06-25T08:00:00+08:00",
+ "end_at": "2060-06-28T02:47:00+08:00",
+ "summary": "Supporting Europa Expedition 2",
+ "note": null,
+ "created_at": "2026-04-25T22:35:58.886747+08:00",
+ "updated_at": "2026-04-25T23:11:25.845497+08:00"
+ },
+ {
+ "id": "e77cd6b5-a2e2-479b-817b-67c1c59bfdee",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "EE-2 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Europa Expedition 2",
+ "location": "Sun",
+ "start_at": "2060-06-28T02:47:00+08:00",
+ "end_at": "2060-08-30T06:11:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T23:11:04.873817+08:00",
+ "updated_at": "2026-05-29T23:51:25.725195+08:00"
+ },
+ {
+ "id": "6c7a8724-1324-4a68-81e1-3dc2ce1ce980",
+ "asset_id": "e339217c-75d4-42c7-9f89-512a2f18b59c",
+ "entry_kind": "state",
+ "title": "Upgrade to Stellaria Class",
+ "state_label": "Upgrade",
+ "mission_label": null,
+ "location": "Star Ring Station",
+ "start_at": "2060-08-30T07:26:00+08:00",
+ "end_at": "2061-06-30T08:00:00+08:00",
+ "summary": "A full overhaul to bring ST-02 to full Stellaria standard",
+ "note": null,
+ "created_at": "2026-04-25T23:15:01.140768+08:00",
+ "updated_at": "2026-05-30T00:36:39.684069+08:00"
+ },
+ {
+ "id": "97b3a860-03c6-4ca3-a9c8-f94fd05adbe0",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "event",
+ "title": "Initial Cargo Landed",
+ "state_label": null,
+ "mission_label": "Mars Mission Demo",
+ "location": "Mars One Base",
+ "start_at": "2054-08-23T10:30:00+08:00",
+ "end_at": null,
+ "summary": "Cargo from Mars Mission Demo was landed at the future Mars One site for robotic setup.",
+ "note": "Backfilled from XH-01 Mars Mission Demo support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "dc082672-52a2-4142-a2b8-737991ee542f",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "MMD Surface Activation",
+ "state_label": "Surface Activation",
+ "mission_label": "Mars Mission Demo",
+ "location": "Mars One Base",
+ "start_at": "2054-08-23T12:00:00+08:00",
+ "end_at": "2055-07-30T08:00:00+08:00",
+ "summary": "Robotic systems activated the first surface power, comms, and cargo handling stack delivered by Mars Mission Demo.",
+ "note": "Backfilled from XH-01 Mars Mission Demo support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "3141e93d-1e47-4264-864b-378815d8e871",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "event",
+ "title": "First Crewed Landing",
+ "state_label": null,
+ "mission_label": "Mars One Base Construction Mission 1",
+ "location": "Mars One Base",
+ "start_at": "2055-07-30T09:30:00+08:00",
+ "end_at": null,
+ "summary": "The first crewed Mars One construction team landed and began surface assembly.",
+ "note": "Backfilled from XH-01 MOCM-1 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "9399f5f6-9412-455f-8683-b237bcdeab7b",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "MOCM-1 Initial Construction",
+ "state_label": "Base Construction",
+ "mission_label": "Mars One Base Construction Mission 1",
+ "location": "Mars One Base",
+ "start_at": "2055-07-30T10:00:00+08:00",
+ "end_at": "2056-02-07T08:00:00+08:00",
+ "summary": "The first crewed construction campaign assembled the core habitat, power systems, and ascent support infrastructure.",
+ "note": "Backfilled from XH-01 MOCM-1 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "afe0f5fe-6909-4351-8003-b3f78e9145d1",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "MOCM-1 Autonomous Commissioning",
+ "state_label": "Autonomous Standby",
+ "mission_label": "Mars One Base Construction Mission 1",
+ "location": "Mars One Base",
+ "start_at": "2056-02-07T08:00:00+08:00",
+ "end_at": "2056-07-03T08:00:00+08:00",
+ "summary": "After the first construction crew departed, the outpost remained in autonomous checkout ahead of the next build window.",
+ "note": "Bridging interval inferred from the first and second Mars One construction campaigns.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "0fd356d5-71ce-4219-a7fd-b9ff077f4f39",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "MOCM-2 Base Construction",
+ "state_label": "Base Construction",
+ "mission_label": "Mars One Construction Mission 2",
+ "location": "Mars One Base",
+ "start_at": "2056-07-03T08:00:00+08:00",
+ "end_at": "2056-09-15T08:00:00+08:00",
+ "summary": "Mission 2 expanded the surface habitat and continued utility trenching and storage build-out.",
+ "note": "Backfilled from ST-01 MOCM-2 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "d96bd772-45eb-4010-96c2-1c942f4efc96",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "MOCM-2/MOCM-3 Crew Handoff",
+ "state_label": "Base Construction; Crew Handoff",
+ "mission_label": "Mars One Construction Mission 2; Mars One Base Construction Mission 3",
+ "location": "Mars One Base",
+ "start_at": "2056-09-15T08:00:00+08:00",
+ "end_at": "2056-10-12T08:00:00+08:00",
+ "summary": "Construction Mission 3 arrived before Mission 2 departed, enabling the first on-surface Mars One crew handoff.",
+ "note": "Backfilled from ST-01 MOCM-2 and XH-01 MOCM-3 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "a05e86bb-77e5-4b99-a7d2-16a1dc810150",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "MOCM-3 Base Construction",
+ "state_label": "Base Construction",
+ "mission_label": "Mars One Base Construction Mission 3",
+ "location": "Mars One Base",
+ "start_at": "2056-10-12T08:00:00+08:00",
+ "end_at": "2056-11-19T08:00:00+08:00",
+ "summary": "The third construction campaign completed surface integration and prepared the outpost for continuous expedition occupancy.",
+ "note": "Backfilled from XH-01 MOCM-3 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "2b0a2dbf-3f28-449e-af86-75ebf87b408e",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "MOCM-3 and ME-1 Surface Operations",
+ "state_label": "Base Construction; Surface Expedition",
+ "mission_label": "Mars One Base Construction Mission 3; Mars Expedition 1",
+ "location": "Mars One Base",
+ "start_at": "2056-11-19T08:00:00+08:00",
+ "end_at": "2057-02-12T08:00:00+08:00",
+ "summary": "Final construction work continued while Mars Expedition 1 began long-duration surface operations from the outpost.",
+ "note": "Overlap inferred from XH-01 MOCM-3 and ST-02 ME-1 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "edfbaea5-331b-4a93-9458-044d3016eb7f",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "event",
+ "title": "Phase 1 Construction Complete",
+ "state_label": null,
+ "mission_label": "Mars One Base Construction Mission 3; Mars Expedition 1",
+ "location": "Mars One Base",
+ "start_at": "2057-02-12T09:00:00+08:00",
+ "end_at": null,
+ "summary": "Mars One entered sustained expedition service after the third construction wave wrapped up.",
+ "note": "Completion milestone inferred from XH-01 MOCM-3 return window.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "e8003196-d035-49be-a721-144fec91a678",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "ME-1 Surface Operations",
+ "state_label": "Surface Expedition",
+ "mission_label": "Mars Expedition 1",
+ "location": "Mars One Base",
+ "start_at": "2057-02-12T09:00:00+08:00",
+ "end_at": "2057-06-22T08:00:00+08:00",
+ "summary": "Mars Expedition 1 operated the newly completed outpost and stabilized its life-support and logistics cadence.",
+ "note": "Backfilled from ST-02 ME-1 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "fb511ee5-3343-4884-a094-59241d1d28e0",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "ME-1/ME-2 Crew Handoff",
+ "state_label": "Surface Expedition; Crew Handoff",
+ "mission_label": "Mars Expedition 1; Mars Expedition 2",
+ "location": "Mars One Base",
+ "start_at": "2057-06-22T08:00:00+08:00",
+ "end_at": "2057-09-08T08:00:00+08:00",
+ "summary": "Mars Expedition 2 arrived while Expedition 1 completed return preparations, overlapping on the surface during handoff.",
+ "note": "Overlap inferred from ST-02 ME-1 and XH-01 ME-2 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "5109f226-b843-4173-97cf-bb3b740927ed",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "ME-2 Surface Operations",
+ "state_label": "Surface Expedition",
+ "mission_label": "Mars Expedition 2",
+ "location": "Mars One Base",
+ "start_at": "2057-09-08T08:00:00+08:00",
+ "end_at": "2058-04-17T08:00:00+08:00",
+ "summary": "Mars Expedition 2 took over continuous surface operations after the Expedition 1 crew departed.",
+ "note": "Backfilled from XH-01 ME-2 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "9c4ef55d-a472-4e19-b582-8f872e6c854a",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "ME-2/ME-3 Crew Handoff",
+ "state_label": "Surface Expedition; Crew Handoff",
+ "mission_label": "Mars Expedition 2; Mars Expedition 3",
+ "location": "Mars One Base",
+ "start_at": "2058-04-17T08:00:00+08:00",
+ "end_at": "2058-04-18T08:00:00+08:00",
+ "summary": "Mars Expedition 3 overlapped briefly with Expedition 2 during the next surface crew handoff.",
+ "note": "Overlap inferred from XH-01 ME-2 return and XH-02 ME-3 arrival timing.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "66d8bc17-70e4-4c18-9c00-a8a2ffb4c1d3",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "ME-3 Surface Operations",
+ "state_label": "Surface Expedition",
+ "mission_label": "Mars Expedition 3",
+ "location": "Mars One Base",
+ "start_at": "2058-04-18T08:00:00+08:00",
+ "end_at": "2059-10-19T08:00:00+08:00",
+ "summary": "Mars Expedition 3 sustained the base through the long pre-expansion interval and remained on Mars after XH-02 departed uncrewed.",
+ "note": "Backfilled from XH-02 ME-3 support logs and uncrewed return timing.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "faf59da6-de11-4f77-892a-5483f17a30e0",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "event",
+ "title": "Expansion Cargo Arrival",
+ "state_label": null,
+ "mission_label": "Mars One Expansion",
+ "location": "Mars One Base",
+ "start_at": "2059-10-19T09:00:00+08:00",
+ "end_at": null,
+ "summary": "Solar Shuttle 1 delivered the first Mars One expansion package to the surface site.",
+ "note": "Backfilled from Solar Shuttle 1 Mars One Expansion support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "5112903a-12bb-4529-afa5-1e37eade53d3",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "Mars One Expansion and ME-3 Surface Operations",
+ "state_label": "Base Expansion; Surface Expedition",
+ "mission_label": "Mars One Expansion; Mars Expedition 3",
+ "location": "Mars One Base",
+ "start_at": "2059-10-19T09:00:00+08:00",
+ "end_at": "2059-10-24T14:00:00+08:00",
+ "summary": "Expansion work began while Mars Expedition 3 kept the outpost occupied ahead of the next crew arrival.",
+ "note": "Overlap inferred from Solar Shuttle 1 expansion and XH-02 ME-4 arrival windows.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "e890d519-64ac-4152-902f-42c69a553b84",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "ME-3/ME-4 Crew Handoff with Expansion Package",
+ "state_label": "Base Expansion; Crew Handoff",
+ "mission_label": "Mars One Expansion; Mars Expedition 3; Mars Expedition 4",
+ "location": "Mars One Base",
+ "start_at": "2059-10-24T14:00:00+08:00",
+ "end_at": "2059-11-04T08:00:00+08:00",
+ "summary": "Mars Expedition 4 arrived with the expansion package while Mars Expedition 3 prepared for ascent and departure.",
+ "note": "Overlap inferred from XH-02 ME-4 Part 1, Solar Shuttle 1 expansion, and XH-02 ME-3 return timing.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "292bb2fc-4688-49e6-94e4-598da921d3e5",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "Mars One Expansion and ME-4 Surface Operations",
+ "state_label": "Base Expansion; Surface Expedition",
+ "mission_label": "Mars One Expansion; Mars Expedition 4",
+ "location": "Mars One Base",
+ "start_at": "2059-11-04T08:00:00+08:00",
+ "end_at": "2060-02-23T08:00:00+08:00",
+ "summary": "After Expedition 3 departed, Mars Expedition 4 continued surface operations alongside the active expansion campaign.",
+ "note": "Backfilled from XH-02 ME-4 and Solar Shuttle 1 expansion support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "16e6a85a-2c04-4dc5-8132-b7cd16a104da",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "Expansion, ME-4, and Rover Delivery",
+ "state_label": "Base Expansion; Surface Expedition; Cargo Delivery",
+ "mission_label": "Mars One Expansion; Mars Expedition 4; Mars One Rover Delivery",
+ "location": "Mars One Base",
+ "start_at": "2060-02-23T08:00:00+08:00",
+ "end_at": "2060-05-23T08:00:00+08:00",
+ "summary": "The rover delivery campaign overlapped with base expansion and Expedition 4 surface operations.",
+ "note": "Overlap inferred from Solar Shuttle 3 rover delivery, Solar Shuttle 1 expansion, and XH-02 ME-4 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "8fc9c2b3-6272-44cb-a942-8bd4c83a6d05",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "Mars One Expansion and ME-4 Surface Operations",
+ "state_label": "Base Expansion; Surface Expedition",
+ "mission_label": "Mars One Expansion; Mars Expedition 4",
+ "location": "Mars One Base",
+ "start_at": "2060-05-23T09:30:00+08:00",
+ "end_at": "2060-08-09T05:10:00+08:00",
+ "summary": "Expansion work continued after rover deployment while Mars Expedition 4 remained the resident surface crew.",
+ "note": "Backfilled from Solar Shuttle 1 expansion and XH-02 ME-4 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "0d811cfd-1358-46de-b637-3d0b230da76e",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "event",
+ "title": "Rover Deployment Complete",
+ "state_label": null,
+ "mission_label": "Mars One Rover Delivery; Mars Expedition 4",
+ "location": "Mars One Base",
+ "start_at": "2060-05-23T09:30:00+08:00",
+ "end_at": null,
+ "summary": "The new Mars One surface rover entered service after the cargo delivery campaign wrapped up.",
+ "note": "Backfilled from Solar Shuttle 3 rover delivery support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "1b798abc-10bb-40cc-a517-4593512b0495",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "event",
+ "title": "Expansion Phase Complete",
+ "state_label": null,
+ "mission_label": "Mars One Expansion; Mars Expedition 4",
+ "location": "Mars One Base",
+ "start_at": "2060-08-09T06:00:00+08:00",
+ "end_at": null,
+ "summary": "The main Mars One expansion phase was completed and Solar Shuttle 1 departed on the return leg.",
+ "note": "Backfilled from Solar Shuttle 1 expansion return timing.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "d86f43a9-ae09-4319-8905-98b35c1d585b",
+ "asset_id": "e6a4c9bc-3e22-4814-a125-1394d018bf6c",
+ "entry_kind": "state",
+ "title": "ME-4 Surface Operations",
+ "state_label": "Surface Expedition",
+ "mission_label": "Mars Expedition 4",
+ "location": "Mars One Base",
+ "start_at": "2060-08-09T06:00:00+08:00",
+ "end_at": "2060-10-30T08:00:00+08:00",
+ "summary": "After expansion wrapped up, Mars Expedition 4 continued normal surface operations from the upgraded outpost.",
+ "note": "Backfilled from XH-02 ME-4 support logs.",
+ "created_at": "2026-04-27T10:58:30.787866+08:00",
+ "updated_at": "2026-04-27T10:58:30.787866+08:00"
+ },
+ {
+ "id": "4958ffd7-2e23-40a6-9b96-e46c61943028",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Construction",
+ "state_label": "Construction",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2054-12-11T08:00:00+08:00",
+ "end_at": "2056-10-04T08:00:00+08:00",
+ "summary": "XH-02 \u592a\u767d Construction",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Construction",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "b99a2638-7560-45ec-9328-6a4a0e4cf685",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Assembly Complete",
+ "state_label": "Assembly Complete",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2056-10-04T08:00:00+08:00",
+ "end_at": "2056-11-11T08:00:00+08:00",
+ "summary": "Assembly complete, preparing for commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Assembly Complete",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "6ec7033c-e711-4148-ab7d-e075f3288021",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Trial Run",
+ "state_label": "Trial Run",
+ "mission_label": null,
+ "location": "Earth",
+ "start_at": "2056-11-11T08:00:00+08:00",
+ "end_at": "2057-03-12T08:00:00+08:00",
+ "summary": "Trial Run before commissioning",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Trial Run",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "669a993c-fe3d-4126-b066-2650e98dfb3e",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2057-03-12T08:00:00+08:00",
+ "end_at": "2057-04-25T08:00:00+08:00",
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "7c166ff7-df3b-495d-a7df-9b99949e23f0",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "AEM Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Asteroid Exploration Mission",
+ "location": "Sun",
+ "start_at": "2057-05-04T08:00:00+08:00",
+ "end_at": "2057-07-17T08:00:00+08:00",
+ "summary": "Earth-Vesta transfer",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Earth-Vesta",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "99eb75ba-e02b-4cdc-a5f1-3ea547cc7d4a",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "AEM Vesta Operations",
+ "state_label": "Asteroid Operations",
+ "mission_label": "Asteroid Exploration Mission",
+ "location": "Vesta",
+ "start_at": "2057-07-17T08:00:00+08:00",
+ "end_at": "2058-01-04T08:00:00+08:00",
+ "summary": "Asteroid exploration mission at Vesta",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Vesta Mission",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "d74dfb61-fd3a-492c-b019-253ec9cd826d",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "AEM Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Asteroid Exploration Mission",
+ "location": "Sun",
+ "start_at": "2058-01-04T08:00:00+08:00",
+ "end_at": "2058-04-17T08:00:00+08:00",
+ "summary": "Vesta-Earth transfer",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Vesta-Earth",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "956cc319-668e-45d1-ab7c-9f0aa408c5f7",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "ME-3 Mars Operations",
+ "state_label": "Planetary Operations",
+ "mission_label": "Mars Expedition 3",
+ "location": "Mars",
+ "start_at": "2058-04-17T08:00:00+08:00",
+ "end_at": "2059-05-04T08:00:00+08:00",
+ "summary": "Mars Expedition 3",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Mars Expedition 3",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "f43aa249-80d1-426c-9aca-a341411be98d",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Uncrewed Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Expedition 3",
+ "location": "Sun",
+ "start_at": "2059-05-04T08:00:00+08:00",
+ "end_at": "2059-07-06T08:00:00+08:00",
+ "summary": "Uncrewed Inbound for TH-02. Mars Expedition 3 Crew remaining on Mars",
+ "note": null,
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:50:51.395619+08:00"
+ },
+ {
+ "id": "2ae7438b-a2a2-44ee-a084-a76bc1e94114",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "Star Port",
+ "start_at": "2059-07-06T08:00:00+08:00",
+ "end_at": "2059-08-04T08:00:00+08:00",
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:46:49.335930+08:00"
+ },
+ {
+ "id": "fcb05995-823e-4a63-9cf8-44ea953e2e9a",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "ME-4 Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Expedition 4",
+ "location": "Sun",
+ "start_at": "2059-08-04T08:00:00+08:00",
+ "end_at": "2059-10-24T08:00:00+08:00",
+ "summary": "Earth-Mars transfer",
+ "note": "Carrying Mars Expedition 4 crew and Mars One Expansion Package to Mars",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:48:10.206772+08:00"
+ },
+ {
+ "id": "c00366fd-6b1d-46e0-8163-4bd6b510f374",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "ME-4 Mars Operations Part 1",
+ "state_label": "Planetary Operations",
+ "mission_label": "Mars Expedition 4",
+ "location": "Mars",
+ "start_at": "2059-10-24T14:00:00+08:00",
+ "end_at": "2059-11-04T08:00:00+08:00",
+ "summary": "ME-4 Crew to Mars One with Mars One Expansion Package. Mars Expedition 3 ascend.",
+ "note": null,
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:49:51.451475+08:00"
+ },
+ {
+ "id": "33a45210-3497-4826-ba6e-291b384ebe7e",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "ME-3 Inbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Expedition 3",
+ "location": "Sun",
+ "start_at": "2059-11-04T08:00:00+08:00",
+ "end_at": "2060-01-06T08:00:00+08:00",
+ "summary": "Carrying ME-3 Crew home",
+ "note": null,
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:50:34.527345+08:00"
+ },
+ {
+ "id": "5562aa60-8d62-4ed9-b1cc-51ff99c49d18",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Maintenance",
+ "state_label": "Maintenance",
+ "mission_label": null,
+ "location": "LEO",
+ "start_at": "2060-01-06T08:00:00+08:00",
+ "end_at": "2060-02-17T08:00:00+08:00",
+ "summary": null,
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Maintenance",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:35:58.899704+08:00"
+ },
+ {
+ "id": "76cd99ba-c259-4969-a8ae-2fa14e303974",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "Uncrewed Outbound",
+ "state_label": "Transfer",
+ "mission_label": "Mars Expedition 4",
+ "location": "Sun",
+ "start_at": "2060-01-22T08:00:00+08:00",
+ "end_at": "2060-02-27T08:00:00+08:00",
+ "summary": null,
+ "note": null,
+ "created_at": "2026-04-25T22:56:22.810309+08:00",
+ "updated_at": "2026-04-25T22:56:22.810309+08:00"
+ },
+ {
+ "id": "c7e777fd-c7d8-4d01-be07-871862829983",
+ "asset_id": "e9e6d99f-964a-478d-bcac-9748390d385c",
+ "entry_kind": "state",
+ "title": "ME-4 Mars Operations Part 2",
+ "state_label": "Planetary Operations",
+ "mission_label": "Mars Expedition 4",
+ "location": "Mars",
+ "start_at": "2060-02-28T08:00:00+08:00",
+ "end_at": "2060-10-30T08:00:00+08:00",
+ "summary": "Uncrewed Mars mission segment",
+ "note": "Timeline.xlsx inferred monthly phase. Raw: Uncrewed to Mars, Mars Expedition 4 Part 2",
+ "created_at": "2026-04-25T22:35:58.899704+08:00",
+ "updated_at": "2026-04-25T22:58:16.084259+08:00"
+ },
+ {
+ "id": "bf68c161-7303-44da-bf6e-72373d2e54d5",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EOCM-1 Outpost Deployment",
+ "state_label": "Outpost Construction",
+ "mission_label": "Europa Outpost Construction Mission 1",
+ "location": "Europa Outpost",
+ "start_at": "2057-02-27T08:00:00+08:00",
+ "end_at": "2057-03-15T09:00:00+08:00",
+ "summary": "The first crewed Europa construction campaign assembled the initial habitat, power spine, and life-support core.",
+ "note": "Backfilled from ST-01 EOCM-1 support logs.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "6ffeda07-93fb-4d17-9efc-817555771d35",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EOCM-1 Initial Outpost Operations",
+ "state_label": "Outpost Commissioning",
+ "mission_label": "Europa Outpost Construction Mission 1",
+ "location": "Europa Outpost",
+ "start_at": "2057-03-15T09:00:00+08:00",
+ "end_at": "2057-10-01T08:00:00+08:00",
+ "summary": "The outpost remained crewed while the first construction team brought core systems to sustained operational readiness.",
+ "note": "Backfilled from ST-01 EOCM-1 support logs.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "53ee9bf9-27c3-47c2-94f3-656a8eea64f2",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "event",
+ "title": "Enter into Service",
+ "state_label": null,
+ "mission_label": "Europa Outpost Construction Mission 1",
+ "location": "Europa Outpost",
+ "start_at": "2057-03-15T09:00:00+08:00",
+ "end_at": null,
+ "summary": "Europa Outpost entered operational service after the initial construction stack passed habitability review.",
+ "note": "User-provided milestone, consistent with ST-01 EOCM-1 operation window.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "d548ded1-232d-4e68-875b-290092c7c0b8",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "Autonomous Standby",
+ "state_label": "Autonomous Standby",
+ "mission_label": "Europa Outpost Construction Mission 1",
+ "location": "Europa Outpost",
+ "start_at": "2057-10-01T08:00:00+08:00",
+ "end_at": "2058-01-19T08:00:00+08:00",
+ "summary": "After the first construction crew departed, Europa Outpost stayed in autonomous survival mode while awaiting the second construction mission.",
+ "note": "Bridging interval inferred from EOCM-1 return and EOCM-2 arrival windows.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "83dcded1-c57c-49c8-b94b-5430c2fe4d4d",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EOCM-2 Outpost Expansion",
+ "state_label": "Outpost Construction",
+ "mission_label": "Europa Outpost Construction Mission 2",
+ "location": "Europa Outpost",
+ "start_at": "2058-01-19T08:00:00+08:00",
+ "end_at": "2058-09-06T08:00:00+08:00",
+ "summary": "The second construction campaign expanded the habitat ring, utility corridors, and long-duration expedition support spaces.",
+ "note": "Backfilled from ST-02 EOCM-2 support logs.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "50c4b9a3-644d-4dd6-85c7-cd40f1d32667",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "Post-Construction Readiness",
+ "state_label": "Autonomous Standby",
+ "mission_label": "Europa Outpost Construction Mission 2",
+ "location": "Europa Outpost",
+ "start_at": "2058-09-06T08:00:00+08:00",
+ "end_at": "2058-09-25T08:00:00+08:00",
+ "summary": "Europa Outpost remained uncrewed briefly after Construction Mission 2 while final expedition supplies were staged.",
+ "note": "Bridging interval inferred from ST-02 EOCM-2 departure and XH-01 EE-1 arrival.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "188eb0ca-df35-4644-92d3-6952bae3dbe8",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "event",
+ "title": "Europa Expedition 1 Arrived",
+ "state_label": null,
+ "mission_label": "Europa Expedition 1",
+ "location": "Europa Outpost",
+ "start_at": "2058-09-25T10:00:00+08:00",
+ "end_at": null,
+ "summary": "Europa Expedition 1 docked at the outpost and began the first standard long-duration occupation cycle.",
+ "note": "Backfilled from XH-01 EE-1 support logs.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "f034826a-77fc-4070-84a6-0f419d0910bb",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EE-1 Surface Operations",
+ "state_label": "Surface Expedition",
+ "mission_label": "Europa Expedition 1",
+ "location": "Europa Outpost",
+ "start_at": "2058-09-25T10:00:00+08:00",
+ "end_at": "2059-06-25T08:30:00+08:00",
+ "summary": "Europa Expedition 1 occupied the outpost and supported early Jupiter system science operations based from Europa.",
+ "note": "Backfilled from XH-01 EE-1 Jupiter System Operations.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "a5da1a52-0c59-423a-b41e-2e646783bb67",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "event",
+ "title": "Europa Expedition 2 Arrived",
+ "state_label": null,
+ "mission_label": "Europa Expedition 2",
+ "location": "Europa Outpost",
+ "start_at": "2059-06-25T08:30:00+08:00",
+ "end_at": null,
+ "summary": "Europa Expedition 2 arrived via ST-02 Kristen with 12 crew and 1 Echo Shuttle Block 1.",
+ "note": "User-provided crew manifest and arrival vehicle; consistent with ST-02 EE-2 arrival window.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "f17eb842-8870-431d-9280-1b5fde97b48b",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EE-1/EE-2 Crew Handoff",
+ "state_label": "Crew Handoff; Surface Expedition",
+ "mission_label": "Europa Expedition 1; Europa Expedition 2",
+ "location": "Europa Outpost",
+ "start_at": "2059-06-25T08:30:00+08:00",
+ "end_at": "2059-06-25T16:00:00+08:00",
+ "summary": "Europa Expedition 2 overlapped with Expedition 1 during crew transfer, cargo sorting, and outpost handover.",
+ "note": "Outpost-level handoff interval inferred from same-day EE-2 arrival and EE-1 departure notes.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "906f6248-fd84-4211-a0eb-74c39e59ce86",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "event",
+ "title": "Europa Expedition 1 Departed",
+ "state_label": null,
+ "mission_label": "Europa Expedition 1",
+ "location": "Europa Outpost",
+ "start_at": "2059-06-25T16:00:00+08:00",
+ "end_at": null,
+ "summary": "Europa Expedition 1 departed the outpost via Xihe Station with 9 crew and 1 Callisto MPV Block 1.",
+ "note": "User-provided departure note; treated as outpost departure milestone within XH-01 EE-1 broader return window.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "a51cd5a1-3ef1-430a-87f7-71ce9db44714",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EE-2 Surface Operations",
+ "state_label": "Surface Expedition",
+ "mission_label": "Europa Expedition 2",
+ "location": "Europa Outpost",
+ "start_at": "2059-06-25T16:00:00+08:00",
+ "end_at": "2060-05-03T09:00:00+08:00",
+ "summary": "Europa Expedition 2 assumed continuous occupation of the outpost after the first crew rotation completed.",
+ "note": "Backfilled from ST-02 EE-2 support logs.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "15f8aae6-45f8-43d9-a3d6-9a2585ddeed2",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "event",
+ "title": "Expansion Module Arrived",
+ "state_label": null,
+ "mission_label": "Europa Outpost Expansion Mission; Europa Expedition 2",
+ "location": "Europa Outpost",
+ "start_at": "2060-05-03T11:00:00+08:00",
+ "end_at": null,
+ "summary": "The Europa Outpost expansion module arrived while Expedition 2 remained on station.",
+ "note": "User-provided date; consistent with Solar Shuttle 2 expansion delivery window at Europa.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "82509df3-ad30-483f-a0f7-b05ff4497435",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EE-2 Operations with Expansion Module Integration",
+ "state_label": "Surface Expedition; Outpost Expansion",
+ "mission_label": "Europa Expedition 2; Europa Outpost Expansion Mission",
+ "location": "Europa Outpost",
+ "start_at": "2060-05-03T11:00:00+08:00",
+ "end_at": "2060-06-23T09:00:00+08:00",
+ "summary": "Europa Expedition 2 supported installation and activation of the new expansion module after it reached the outpost.",
+ "note": "Backfilled from Solar Shuttle 2 expansion delivery and ST-02 EE-2 operation windows.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "d7a1d501-ed5f-4065-a773-aa4ef101dede",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "event",
+ "title": "Europa Expedition 3 Arrived",
+ "state_label": null,
+ "mission_label": "Europa Expedition 3",
+ "location": "Europa Outpost",
+ "start_at": "2060-06-23T09:00:00+08:00",
+ "end_at": null,
+ "summary": "Europa Expedition 3 arrived via XH-01 to begin the next outpost rotation.",
+ "note": "User-provided arrival date; treated as outpost arrival milestone within XH-01 EE-3 Jupiter System Operations.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "db70ac3b-1035-4066-8e74-928e656bc39a",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EE-2/EE-3 Crew Handoff",
+ "state_label": "Crew Handoff; Surface Expedition",
+ "mission_label": "Europa Expedition 2; Europa Expedition 3",
+ "location": "Europa Outpost",
+ "start_at": "2060-06-23T09:00:00+08:00",
+ "end_at": "2060-06-24T15:00:00+08:00",
+ "summary": "Europa Expedition 3 overlapped with Expedition 2 during crew turnover and transfer of outpost responsibility.",
+ "note": "Outpost-level handoff interval inferred from user-provided EE-3 arrival and EE-2 departure dates.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "a7c9d010-5aed-43fc-a744-1a86ad9b15c8",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "state",
+ "title": "EE-3 Surface Operations",
+ "state_label": "Surface Expedition",
+ "mission_label": "Europa Expedition 3",
+ "location": "Europa Outpost",
+ "start_at": "2060-06-24T15:00:00+08:00",
+ "end_at": null,
+ "summary": "Europa Expedition 3 is the current resident crew. Crew status on 2060-06-24: 6 scientists at Lab, 2 medical at center hub, 1 commander and 1 pilot at observation station, 2 engineers at greenhouse.",
+ "note": "User-provided current crew distribution for 2060-06-24.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ },
+ {
+ "id": "8649cb17-0bcb-4ba4-9f91-e9c441ff9793",
+ "asset_id": "fba95050-ca89-4e67-b796-66b7e1c40764",
+ "entry_kind": "event",
+ "title": "Europa Expedition 2 Departed",
+ "state_label": null,
+ "mission_label": "Europa Expedition 2",
+ "location": "Europa Outpost",
+ "start_at": "2060-06-24T15:00:00+08:00",
+ "end_at": null,
+ "summary": "Europa Expedition 2 departed the outpost via ST-02 Kristen after completing crew handoff to Expedition 3.",
+ "note": "User-provided departure date; treated as outpost departure milestone slightly ahead of ST-02 EE-2 system departure.",
+ "created_at": "2026-04-27T14:40:09.019231+08:00",
+ "updated_at": "2026-04-27T14:40:09.019231+08:00"
+ }
+]
\ No newline at end of file
diff --git a/data_backup/asset_state_nodes.json b/data_backup/asset_state_nodes.json
new file mode 100644
index 0000000..5c22b5b
--- /dev/null
+++ b/data_backup/asset_state_nodes.json
@@ -0,0 +1,1118 @@
+[
+ {
+ "id": "0567dcf4-2c56-4587-a0d5-86f01f27e25b",
+ "entry_id": "00aec49b-6dc1-4b58-bbf1-96086b93ff0e",
+ "title": "Expedition 11 Crew Departure",
+ "at_time": "2059-11-16T20:55:00+08:00",
+ "created_at": "2026-04-25T13:46:58.167224+08:00",
+ "updated_at": "2026-04-25T13:46:58.167224+08:00",
+ "detail": null
+ },
+ {
+ "id": "4e48888d-9468-4c9d-affe-8bf2055672ca",
+ "entry_id": "00c8b5c6-e363-4aee-a768-2fc3fa7a0138",
+ "title": "Mars Departure for Earth",
+ "at_time": "2060-08-10T04:56:00+08:00",
+ "created_at": "2026-05-10T15:30:07.102771+08:00",
+ "updated_at": "2026-05-10T15:30:07.102771+08:00",
+ "detail": "19km/s burn\uff0c 78day transit"
+ },
+ {
+ "id": "4b36f165-5765-47e5-8204-2ee01ae9622a",
+ "entry_id": "00c8b5c6-e363-4aee-a768-2fc3fa7a0138",
+ "title": "Earth Arrival",
+ "at_time": "2060-10-26T10:03:00+08:00",
+ "created_at": "2026-05-10T15:30:58.768105+08:00",
+ "updated_at": "2026-05-10T15:30:58.768105+08:00",
+ "detail": "25km/s burn"
+ },
+ {
+ "id": "4760eecb-d346-456c-97ec-95d86d299549",
+ "entry_id": "022b0296-5c1a-41f8-8634-97dc663b05d9",
+ "title": "Iapetus Arrival",
+ "at_time": "2059-05-31T08:00:00+08:00",
+ "created_at": "2026-04-25T14:01:03.909056+08:00",
+ "updated_at": "2026-04-25T18:11:39.304602+08:00",
+ "detail": "Parked into Iapetus orbit, orbital science completed"
+ },
+ {
+ "id": "bab5ff7d-6bce-4dbb-9919-6db50d99d370",
+ "entry_id": "022b0296-5c1a-41f8-8634-97dc663b05d9",
+ "title": "Iapetus Surface operation",
+ "at_time": "2059-06-15T08:00:00+08:00",
+ "created_at": "2026-04-25T14:01:03.909056+08:00",
+ "updated_at": "2026-04-25T14:01:03.909056+08:00",
+ "detail": null
+ },
+ {
+ "id": "0f841674-dbef-47e0-8b46-6e216cba180a",
+ "entry_id": "058bbf6d-5c51-49c4-8516-8b6931db53c1",
+ "title": "Mars Departure for Earth",
+ "at_time": "2058-04-18T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "dac8a650-cd39-4aa5-8ca7-99e2c7bed369",
+ "entry_id": "058bbf6d-5c51-49c4-8516-8b6931db53c1",
+ "title": "Earth Arrival",
+ "at_time": "2058-05-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "crew return"
+ },
+ {
+ "id": "8362f191-7a23-4320-b362-b4da57528321",
+ "entry_id": "105a5eac-4ca1-4a5a-a9ad-bc2278d46f01",
+ "title": "Begin Trial Run in Earth Orbit",
+ "at_time": "2054-05-12T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "testing all systems"
+ },
+ {
+ "id": "5021f5fd-37a0-4cb9-8229-8b22ebe14a6e",
+ "entry_id": "105a5eac-4ca1-4a5a-a9ad-bc2278d46f01",
+ "title": "Trial Run complete",
+ "at_time": "2054-08-22T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "all systems perform as expected. Including multiple run to GEO and Lunar Orbit before returning to LEO."
+ },
+ {
+ "id": "2e013e09-8150-4bcc-b8ff-f32535a0480f",
+ "entry_id": "12059276-d10a-4a37-9b8c-6a6183768504",
+ "title": "Crew descend to Martian Surface",
+ "at_time": "2056-07-03T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Continuing the construction of Mars One Base"
+ },
+ {
+ "id": "fc813181-1092-4076-95fb-a374227eb07d",
+ "entry_id": "12059276-d10a-4a37-9b8c-6a6183768504",
+ "title": "Heavy Cargo Delivery to Surface via Callisto MPV",
+ "at_time": "2056-07-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "ff64da53-4364-4860-ba45-b11c4df939dc",
+ "entry_id": "12059276-d10a-4a37-9b8c-6a6183768504",
+ "title": "Mars One Construction Mission 3 Crew Arrival via XH-01",
+ "at_time": "2056-09-17T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "joining Stellaria crew. First Crew Handover on Mars."
+ },
+ {
+ "id": "425032da-dd2b-488f-9a82-d5714c2f5665",
+ "entry_id": "12059276-d10a-4a37-9b8c-6a6183768504",
+ "title": "Mars One Construction Mission 2 Crew ascend to Stellaria",
+ "at_time": "2056-10-12T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "c820d890-b4fb-4b9e-96d8-2c04e299e72a",
+ "entry_id": "18b3429e-28d3-489c-b65c-35e0e9775a0d",
+ "title": "Course Correction Burn",
+ "at_time": "2060-07-25T07:40:00+08:00",
+ "created_at": "2026-05-10T00:27:51.940944+08:00",
+ "updated_at": "2026-05-10T00:31:33.897628+08:00",
+ "detail": "5km/s burn for Triton interception"
+ },
+ {
+ "id": "d0d42300-675d-4830-9633-9c7ba201a053",
+ "entry_id": "18b3429e-28d3-489c-b65c-35e0e9775a0d",
+ "title": "Triton Arrival",
+ "at_time": "2060-07-25T17:17:00+08:00",
+ "created_at": "2026-05-10T00:27:51.940944+08:00",
+ "updated_at": "2026-05-10T00:31:33.897628+08:00",
+ "detail": "Triton Arrival Burn 7km/s\r\n200*2100km orbit"
+ },
+ {
+ "id": "5d3b922b-dfcd-4996-bfb6-ce414581c796",
+ "entry_id": "18b3429e-28d3-489c-b65c-35e0e9775a0d",
+ "title": "Triton Surface Operation",
+ "at_time": "2060-08-13T06:49:00+08:00",
+ "created_at": "2026-05-10T00:31:33.900628+08:00",
+ "updated_at": "2026-05-11T22:59:00.023796+08:00",
+ "detail": "First Crewed Landing on Triton\r\n3 Total landing, including 2 to the polar region"
+ },
+ {
+ "id": "c07d44e4-8599-4e36-9a6c-0051876d7cfb",
+ "entry_id": "18b3429e-28d3-489c-b65c-35e0e9775a0d",
+ "title": "Triton Departure",
+ "at_time": "2060-11-01T10:03:35+08:00",
+ "created_at": "2026-05-11T22:59:00.025806+08:00",
+ "updated_at": "2026-05-11T22:59:00.025806+08:00",
+ "detail": "Leave Triton to begin Neptune Exploration"
+ },
+ {
+ "id": "71caaa56-774a-4d00-abec-cd562db2ef53",
+ "entry_id": "1c346955-ba6b-4f54-9308-d088fa99f766",
+ "title": "Expedition 12 Crew Arrival",
+ "at_time": "2059-11-16T16:00:00+08:00",
+ "created_at": "2026-04-25T13:46:58.167224+08:00",
+ "updated_at": "2026-04-25T13:46:58.167224+08:00",
+ "detail": null
+ },
+ {
+ "id": "cfb35f94-ae15-441f-803a-ef1e81fc7c3e",
+ "entry_id": "1c346955-ba6b-4f54-9308-d088fa99f766",
+ "title": "Expedition 12 Crew Departure",
+ "at_time": "2060-05-15T01:44:00+08:00",
+ "created_at": "2026-04-25T13:46:58.167224+08:00",
+ "updated_at": "2026-04-25T13:46:58.167224+08:00",
+ "detail": null
+ },
+ {
+ "id": "f09b8391-0464-4c40-b691-d6cb1581c747",
+ "entry_id": "1f6e85aa-121a-4f47-95b6-35f040da055c",
+ "title": "Departure from Venus for Earth",
+ "at_time": "2056-03-24T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "ac713d38-ff36-415e-bb96-e07fef01c38a",
+ "entry_id": "1f6e85aa-121a-4f47-95b6-35f040da055c",
+ "title": "Earth Arrival",
+ "at_time": "2056-04-12T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "e817cf12-95cc-419a-b467-fd9ed2bb5fae",
+ "entry_id": "2adfa016-b23a-4459-af6e-a84da2aa2469",
+ "title": "Departure from Mercury for Venus",
+ "at_time": "2055-08-15T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "63c0770e-7a93-4e93-a9a9-205483b0936f",
+ "entry_id": "2adfa016-b23a-4459-af6e-a84da2aa2469",
+ "title": "Venus Arrival",
+ "at_time": "2055-10-01T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "5ad9ae1e-93e1-4e6f-a726-759a8171deb8",
+ "entry_id": "30c84287-e5d1-473c-93fb-9d36d426516e",
+ "title": "Crew Arrival",
+ "at_time": "2057-05-05T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Picking up crew for Mars Expedition 2"
+ },
+ {
+ "id": "ca2ac57d-50cf-4fd8-869a-44d9cf2ed186",
+ "entry_id": "30c84287-e5d1-473c-93fb-9d36d426516e",
+ "title": "Earth Departure for Mars",
+ "at_time": "2057-05-09T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "32f23ede-fad9-4756-bf46-16eb00d5c3dc",
+ "entry_id": "42698c8c-a1cc-4742-9885-7b9e650f9867",
+ "title": "Orbital Survey of Mercury begins",
+ "at_time": "2055-04-18T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "3a562501-2147-48d1-aecc-ff2a4c96f87d",
+ "entry_id": "42698c8c-a1cc-4742-9885-7b9e650f9867",
+ "title": "First Crewed Surface Landing on Mercury",
+ "at_time": "2055-06-14T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "f48f3e2a-e288-43f7-b0d9-3dea13914a91",
+ "entry_id": "42698c8c-a1cc-4742-9885-7b9e650f9867",
+ "title": "EVA operations commence",
+ "at_time": "2055-06-15T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "5b6f9628-4e4a-4c63-991f-03a9ec7797c2",
+ "entry_id": "42698c8c-a1cc-4742-9885-7b9e650f9867",
+ "title": "Surface operations complete",
+ "at_time": "2055-06-30T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "returning to orbit"
+ },
+ {
+ "id": "abf4ad7e-8a88-4196-842a-a85810a3d203",
+ "entry_id": "43f2ece9-283b-4484-b838-d684b9ada4d6",
+ "title": "Europa Departure for Earth",
+ "at_time": "2057-10-04T08:00:00+08:00",
+ "created_at": "2026-04-25T18:16:48.251361+08:00",
+ "updated_at": "2026-04-25T18:16:48.251361+08:00",
+ "detail": null
+ },
+ {
+ "id": "d13a9963-67a3-4d8a-88e6-a44f1555719e",
+ "entry_id": "43f2ece9-283b-4484-b838-d684b9ada4d6",
+ "title": "Earth Arrival",
+ "at_time": "2057-12-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:16:48.251361+08:00",
+ "updated_at": "2026-04-25T18:17:01.842025+08:00",
+ "detail": "Europa-Earth transfer, using Fast trajectory with 216km/s of departure burn"
+ },
+ {
+ "id": "a909b303-1196-42bc-bd14-0633eccbee23",
+ "entry_id": "4bfddc84-dfec-43e3-b534-4fb798bcc73f",
+ "title": "Crew Arrival",
+ "at_time": "2055-03-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Picking up crew for Inner Solar System Exploration Mission 1"
+ },
+ {
+ "id": "4ce15b4c-a128-404a-9dcf-2c823e342428",
+ "entry_id": "4bfddc84-dfec-43e3-b534-4fb798bcc73f",
+ "title": "Earth Departure for Mercury",
+ "at_time": "2055-03-22T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "3a31e794-5bcb-4c9f-9ec2-b23134b8e27e",
+ "entry_id": "4bfddc84-dfec-43e3-b534-4fb798bcc73f",
+ "title": "Mercury Arrival",
+ "at_time": "2055-04-17T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "2f3e02c3-7317-49aa-a368-67e07886598d",
+ "entry_id": "4ff368c4-503b-42ce-9e82-b4da291d3203",
+ "title": "Crew Arrival",
+ "at_time": "2058-07-10T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Picking up crew for Europa Expedition 1"
+ },
+ {
+ "id": "bcb49a41-e969-4075-9f41-ad212f1423f6",
+ "entry_id": "4ff368c4-503b-42ce-9e82-b4da291d3203",
+ "title": "Earth Departure for Jupiter system",
+ "at_time": "2058-07-12T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "e8c723a4-04d9-4467-8ac7-261227fa3c64",
+ "entry_id": "4ff368c4-503b-42ce-9e82-b4da291d3203",
+ "title": "Europa Arrival",
+ "at_time": "2058-09-25T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "b9e75eca-5040-48f3-a6cd-c577cd830530",
+ "entry_id": "545f687e-bd2c-409a-8fb8-186a6dead67e",
+ "title": "Heavy Cargo Delivery to Surface via Qingtian Cargo Shuttle",
+ "at_time": "2057-02-27T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "1e919537-047c-4480-b468-2331e5634dd9",
+ "entry_id": "545f687e-bd2c-409a-8fb8-186a6dead67e",
+ "title": "Crew descend to Europan Surface",
+ "at_time": "2057-03-15T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Beginning construction of Europa Outpost"
+ },
+ {
+ "id": "1f3b1172-a17e-435f-ab3f-97edf4ec2aef",
+ "entry_id": "545f687e-bd2c-409a-8fb8-186a6dead67e",
+ "title": "Europa Outpost Construction Mission 1 Crew ascend to Stellaria",
+ "at_time": "2057-10-01T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "wrapping up construction phase 1"
+ },
+ {
+ "id": "7a872292-1993-41a6-98c7-af0d76ffe811",
+ "entry_id": "5a2092a8-ddad-41b3-9819-fa52557332ed",
+ "title": "Earth Departure",
+ "at_time": "2059-12-09T08:00:00+08:00",
+ "created_at": "2026-04-25T23:21:18.913303+08:00",
+ "updated_at": "2026-04-25T23:21:18.913303+08:00",
+ "detail": "Out of Star Port, depart to Europa for Europa Outpost Expansion Mission"
+ },
+ {
+ "id": "991e4915-d7bc-4016-8c1a-dad504a8b7fd",
+ "entry_id": "5a2092a8-ddad-41b3-9819-fa52557332ed",
+ "title": "Jupiter Arrival",
+ "at_time": "2060-04-29T08:00:00+08:00",
+ "created_at": "2026-04-25T23:21:18.913303+08:00",
+ "updated_at": "2026-04-25T23:21:18.913303+08:00",
+ "detail": "Jupiter Braking Burn"
+ },
+ {
+ "id": "097c034d-ed84-41f8-8d82-f1e630d5f0be",
+ "entry_id": "5a2092a8-ddad-41b3-9819-fa52557332ed",
+ "title": "Europa Arrival",
+ "at_time": "2060-05-01T08:00:00+08:00",
+ "created_at": "2026-04-25T23:21:18.913303+08:00",
+ "updated_at": "2026-04-25T23:21:18.913303+08:00",
+ "detail": null
+ },
+ {
+ "id": "72ec2a4c-8d84-4f3a-b70a-befc302b1462",
+ "entry_id": "65910288-0c2a-4800-bfce-39495efafce2",
+ "title": "EE-2 Descend",
+ "at_time": "2059-06-25T12:27:00+08:00",
+ "created_at": "2026-04-25T23:09:13.866609+08:00",
+ "updated_at": "2026-04-25T23:09:13.866609+08:00",
+ "detail": "Europa Expedition 2 crew descend via Echo Shuttle"
+ },
+ {
+ "id": "c2521441-5fba-4774-b0d6-8622a0cb79cd",
+ "entry_id": "65910288-0c2a-4800-bfce-39495efafce2",
+ "title": "EE-2 Ascend",
+ "at_time": "2060-06-25T02:27:00+08:00",
+ "created_at": "2026-04-25T23:09:13.866609+08:00",
+ "updated_at": "2026-04-25T23:09:13.866609+08:00",
+ "detail": "Europa Expedition 2 crew dock via Echo Shuttle"
+ },
+ {
+ "id": "4ea14534-7c4c-4575-8219-d354b9664b56",
+ "entry_id": "65910288-0c2a-4800-bfce-39495efafce2",
+ "title": "Europa Departure",
+ "at_time": "2060-06-28T02:47:00+08:00",
+ "created_at": "2026-04-25T23:09:13.866609+08:00",
+ "updated_at": "2026-04-25T23:09:13.866609+08:00",
+ "detail": "122km/s burn, 60 day transfer time"
+ },
+ {
+ "id": "f3b57181-4ea9-468b-a281-d368ae9212cb",
+ "entry_id": "687615b6-144f-4fd5-b3ee-709e4eaea6aa",
+ "title": "Earth Arrival",
+ "at_time": "2060-06-25T08:00:00+08:00",
+ "created_at": "2026-04-25T23:25:17.148320+08:00",
+ "updated_at": "2026-04-25T23:25:17.148320+08:00",
+ "detail": null
+ },
+ {
+ "id": "3db6ae11-6e54-4ba5-84f1-ccf757faa4b9",
+ "entry_id": "687615b6-144f-4fd5-b3ee-709e4eaea6aa",
+ "title": "Parked to Star Port",
+ "at_time": "2060-06-26T08:00:00+08:00",
+ "created_at": "2026-04-25T23:25:17.148320+08:00",
+ "updated_at": "2026-04-25T23:25:17.148320+08:00",
+ "detail": null
+ },
+ {
+ "id": "0f92e1d2-f402-4ff2-adc4-368cd401081b",
+ "entry_id": "6c7a8724-1324-4a68-81e1-3dc2ce1ce980",
+ "title": "Transfer to Star Ring Station",
+ "at_time": "2060-08-30T09:06:00+08:00",
+ "created_at": "2026-05-30T00:36:39.689070+08:00",
+ "updated_at": "2026-05-30T00:36:39.689070+08:00",
+ "detail": "Finished Earth Arrival Burn, getting ready to park to Star Ring Station"
+ },
+ {
+ "id": "e3bdb039-accb-487c-9ac4-d652af5bf350",
+ "entry_id": "6c7a8724-1324-4a68-81e1-3dc2ce1ce980",
+ "title": "Parked to Star Ring Station",
+ "at_time": "2060-08-30T11:08:00+08:00",
+ "created_at": "2026-05-30T00:45:24.014963+08:00",
+ "updated_at": "2026-05-30T00:45:24.014963+08:00",
+ "detail": null
+ },
+ {
+ "id": "7c3b4860-2819-4bd3-adec-ad9d81b38efc",
+ "entry_id": "6c7a8724-1324-4a68-81e1-3dc2ce1ce980",
+ "title": "Europa Expedition 2 return",
+ "at_time": "2060-08-30T18:49:00+08:00",
+ "created_at": "2026-05-30T13:05:21.793263+08:00",
+ "updated_at": "2026-05-30T13:05:21.793263+08:00",
+ "detail": "23 crew return via Echo Shuttle"
+ },
+ {
+ "id": "68afb989-6047-4165-8eba-0debdb85eec7",
+ "entry_id": "7747339c-f602-4ddf-8511-6862006f789b",
+ "title": "Start preparations for Europa Outpost Construction Mission 1",
+ "at_time": "2056-12-15T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "0fef6698-dc9d-4839-ac8c-8d827485b147",
+ "entry_id": "7747339c-f602-4ddf-8511-6862006f789b",
+ "title": "Europa Outpost Construction Package arrival via Qingtian Cargo Shuttle",
+ "at_time": "2056-12-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "234f893d-260a-4b16-b5ed-50087f550369",
+ "entry_id": "7747339c-f602-4ddf-8511-6862006f789b",
+ "title": "Crew Arrival",
+ "at_time": "2056-12-31T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Picking up crew for Europa Outpost Construction Mission 1"
+ },
+ {
+ "id": "28a8424e-6fa9-4429-8838-ecfda43a6ab9",
+ "entry_id": "7747339c-f602-4ddf-8511-6862006f789b",
+ "title": "Earth Departure for Europa",
+ "at_time": "2057-01-02T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "108095d7-3883-4b46-bd7b-c9346da1a432",
+ "entry_id": "7c74d703-98bc-486d-b06f-591f38661181",
+ "title": "Expedition 13 Crew Arrival",
+ "at_time": "2060-05-12T15:40:00+08:00",
+ "created_at": "2026-04-25T13:38:01.592903+08:00",
+ "updated_at": "2026-04-25T13:52:35.450595+08:00",
+ "detail": null
+ },
+ {
+ "id": "28d8af35-aa27-4cae-9e2f-aeb4dea52d91",
+ "entry_id": "7deb1192-d6f0-4635-9a6d-39ab0c2adcfe",
+ "title": "Earth Departure",
+ "at_time": "2060-02-23T08:00:00+08:00",
+ "created_at": "2026-04-25T23:27:06.185283+08:00",
+ "updated_at": "2026-04-25T23:27:06.185283+08:00",
+ "detail": null
+ },
+ {
+ "id": "8150713c-2f63-4464-81ff-ff21d979b120",
+ "entry_id": "7deb1192-d6f0-4635-9a6d-39ab0c2adcfe",
+ "title": "Mars Arrival",
+ "at_time": "2060-05-23T08:00:00+08:00",
+ "created_at": "2026-04-25T23:27:06.185283+08:00",
+ "updated_at": "2026-04-25T23:27:06.185283+08:00",
+ "detail": null
+ },
+ {
+ "id": "e12e41fb-9fd7-448d-bb8c-802e3000f8e8",
+ "entry_id": "7f5da9b3-94fa-4bd5-a6bd-94f6841c71a2",
+ "title": "Mars EDL and surface operations begin",
+ "at_time": "2057-06-25T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "6f9abd06-08ea-44fa-96a4-836da2cd383d",
+ "entry_id": "7f5da9b3-94fa-4bd5-a6bd-94f6841c71a2",
+ "title": "Begin Mars Departure preparations",
+ "at_time": "2058-04-10T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "87bb76c8-1a14-42aa-877f-2fe1dfa61e9e",
+ "entry_id": "8a9de074-6348-4190-bd27-e3bdeddb70f7",
+ "title": "Leave Star Port",
+ "at_time": "2060-02-11T08:00:00+08:00",
+ "created_at": "2026-04-25T17:18:14.451297+08:00",
+ "updated_at": "2026-04-25T18:13:02.919813+08:00",
+ "detail": "Out of Star Port, config for Outer Solar System Exploration"
+ },
+ {
+ "id": "2a158fa0-ab8a-4203-8907-09ee50ba2889",
+ "entry_id": "8a9de074-6348-4190-bd27-e3bdeddb70f7",
+ "title": "Crew and Supply",
+ "at_time": "2060-02-12T09:22:00+08:00",
+ "created_at": "2026-04-25T17:18:14.451297+08:00",
+ "updated_at": "2026-04-25T18:13:02.919813+08:00",
+ "detail": "Pick up Outer Solar System Exploration Crew 1 and supply"
+ },
+ {
+ "id": "cd59ec0f-7e26-4e5b-9a2f-cd1d442e9932",
+ "entry_id": "8a9de074-6348-4190-bd27-e3bdeddb70f7",
+ "title": "Earth Departure for Neptune",
+ "at_time": "2060-02-13T07:55:00+08:00",
+ "created_at": "2026-04-25T17:18:14.451297+08:00",
+ "updated_at": "2026-04-25T17:18:14.451297+08:00",
+ "detail": null
+ },
+ {
+ "id": "6badedb2-f59b-4f19-a3d2-692e11add51b",
+ "entry_id": "8a9de074-6348-4190-bd27-e3bdeddb70f7",
+ "title": "Neptune SOI",
+ "at_time": "2060-07-21T22:40:08+08:00",
+ "created_at": "2026-05-10T00:24:16.874601+08:00",
+ "updated_at": "2026-05-10T00:24:16.874601+08:00",
+ "detail": null
+ },
+ {
+ "id": "7023f159-3e95-4f2c-a1ab-89fc5c37d03e",
+ "entry_id": "8a9de074-6348-4190-bd27-e3bdeddb70f7",
+ "title": "Neptune Arrival Burn",
+ "at_time": "2060-07-24T20:11:00+08:00",
+ "created_at": "2026-04-25T17:18:14.451297+08:00",
+ "updated_at": "2026-05-10T00:24:16.866537+08:00",
+ "detail": "309km/s burn to park in Neptune orbit."
+ },
+ {
+ "id": "e360230f-f6fc-4a5f-80c0-f546b099ccc9",
+ "entry_id": "8ee54d7e-4310-43dc-a703-f633c1013405",
+ "title": "Begin Trial Run in Earth Orbit",
+ "at_time": "2052-06-01T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "testing all systems"
+ },
+ {
+ "id": "1f7f8b32-13f6-4bad-8f1a-e4457410a92b",
+ "entry_id": "8ee54d7e-4310-43dc-a703-f633c1013405",
+ "title": "Trial Run complete",
+ "at_time": "2052-11-30T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "all systems perform as expected. Including multiple run to GEO and Lunar Orbit before returning to LEO."
+ },
+ {
+ "id": "7b9e8440-3c7f-478b-9d88-a6f2b45d248c",
+ "entry_id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "title": "Io Arrival",
+ "at_time": "2060-05-02T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "d48c477d-4c1f-4fc2-b8b8-440c8bacabe3",
+ "entry_id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "title": "Io descend",
+ "at_time": "2060-05-07T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "26800ac6-2e0d-4a7e-9be6-a697dce7bb20",
+ "entry_id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "title": "Io departure",
+ "at_time": "2060-05-09T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "08223472-e3e6-4552-b7b5-34d6c46baab5",
+ "entry_id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "title": "Ganymede Arrival",
+ "at_time": "2060-05-11T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "342c53b1-d089-405a-9e81-4511e974f8d8",
+ "entry_id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "title": "Ganymede descend",
+ "at_time": "2060-05-12T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "39f9ba61-e8ac-4fc6-a17b-9b2cc7aa3fd8",
+ "entry_id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "title": "Ganymede Departure for Callisto",
+ "at_time": "2060-05-21T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "ac5f16c0-ab7e-4b36-8cf1-677aaa65d07f",
+ "entry_id": "91d4948a-ae04-43a8-ac3b-def9caecc8e5",
+ "title": "Callisto Arrival",
+ "at_time": "2060-05-25T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "05486f13-8852-42a2-a7cf-b570dc798c29",
+ "entry_id": "aab3125c-c99e-4af5-ab64-ffe7fda48ad7",
+ "title": "Crew Arrival",
+ "at_time": "2055-06-15T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Picking up crew for Mars One base Construction Mission 1"
+ },
+ {
+ "id": "fb460dbf-3367-43dc-b3ba-c410392339ca",
+ "entry_id": "aab3125c-c99e-4af5-ab64-ffe7fda48ad7",
+ "title": "Earth Departure for Mars",
+ "at_time": "2055-06-18T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "1824ee4e-68da-40bc-bc3c-3860f7aacbab",
+ "entry_id": "ae003c1f-f74e-459b-ade2-74fcdae48605",
+ "title": "First module delivered to LEO via Vulture Shuttle",
+ "at_time": "2050-09-15T16:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "e5f24b56-2f43-43e0-9682-3568626746fe",
+ "entry_id": "ae003c1f-f74e-459b-ade2-74fcdae48605",
+ "title": "Assembly Halted",
+ "at_time": "2053-02-02T16:00:00+08:00",
+ "created_at": "2026-04-25T21:48:29.038210+08:00",
+ "updated_at": "2026-04-25T21:48:29.038210+08:00",
+ "detail": "Reconfigure as ST-01 Stellaria (From XH-02)"
+ },
+ {
+ "id": "1dbc419c-db52-4a69-85a8-ae5a68e7aa09",
+ "entry_id": "ae003c1f-f74e-459b-ade2-74fcdae48605",
+ "title": "Resume Construction",
+ "at_time": "2053-05-11T08:00:00+08:00",
+ "created_at": "2026-04-25T21:48:29.038210+08:00",
+ "updated_at": "2026-04-25T21:48:29.038210+08:00",
+ "detail": "Only fitted with the Light Speed Engine. Other systems are still Xihe standard. Awaiting further upgrades."
+ },
+ {
+ "id": "1b4916e0-1876-41e9-9cbb-c94a14d4ed85",
+ "entry_id": "ae003c1f-f74e-459b-ade2-74fcdae48605",
+ "title": "Construction Completed",
+ "at_time": "2054-04-28T16:00:00+08:00",
+ "created_at": "2026-04-25T21:48:29.038210+08:00",
+ "updated_at": "2026-04-25T21:48:29.038210+08:00",
+ "detail": null
+ },
+ {
+ "id": "f5233496-f454-4cd3-bd92-aa8cb4b2e458",
+ "entry_id": "bdf99335-d329-4bd2-8e17-27ac1f097ca9",
+ "title": "Earth Arrival",
+ "at_time": "2056-03-18T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "crew return"
+ },
+ {
+ "id": "0aa0a311-00f9-48d9-b7bf-1a46d6d0ef31",
+ "entry_id": "c00366fd-6b1d-46e0-8163-4bd6b510f374",
+ "title": "ME-4 decend",
+ "at_time": "2059-10-25T15:33:00+08:00",
+ "created_at": "2026-04-25T22:49:51.454486+08:00",
+ "updated_at": "2026-04-25T22:49:51.454486+08:00",
+ "detail": "Mars One Package delivery"
+ },
+ {
+ "id": "66f2b8cb-b95e-4cd3-93e1-8be3fee713f5",
+ "entry_id": "c00366fd-6b1d-46e0-8163-4bd6b510f374",
+ "title": "ME-3 ascend",
+ "at_time": "2059-11-03T10:05:00+08:00",
+ "created_at": "2026-04-25T22:49:51.454486+08:00",
+ "updated_at": "2026-04-25T22:49:51.454486+08:00",
+ "detail": null
+ },
+ {
+ "id": "2e30a54c-d6b2-4a5b-b52a-86d342c46f3d",
+ "entry_id": "c0271f19-e604-4c15-9c00-7118fec1928e",
+ "title": "Qingtian Descend",
+ "at_time": "2060-05-02T20:11:00+08:00",
+ "created_at": "2026-04-25T23:23:22.197409+08:00",
+ "updated_at": "2026-04-25T23:23:22.197409+08:00",
+ "detail": null
+ },
+ {
+ "id": "fa494922-eae4-4265-830e-c345dfd64d04",
+ "entry_id": "c0271f19-e604-4c15-9c00-7118fec1928e",
+ "title": "Qingtian Ascend",
+ "at_time": "2060-05-05T07:11:00+08:00",
+ "created_at": "2026-04-25T23:23:22.197409+08:00",
+ "updated_at": "2026-04-25T23:23:22.197409+08:00",
+ "detail": null
+ },
+ {
+ "id": "8b41cc44-572e-4da2-b125-8c219cfcbda9",
+ "entry_id": "c0271f19-e604-4c15-9c00-7118fec1928e",
+ "title": "Europa Departure",
+ "at_time": "2060-05-06T07:25:00+08:00",
+ "created_at": "2026-04-25T23:23:22.197409+08:00",
+ "updated_at": "2026-04-25T23:23:22.197409+08:00",
+ "detail": "131km/s burn, 51 day transition"
+ },
+ {
+ "id": "b464643e-da60-464b-bcc6-dcb14fd8d492",
+ "entry_id": "c7e777fd-c7d8-4d01-be07-871862829983",
+ "title": "Mars Arrival",
+ "at_time": "2060-02-28T08:00:00+08:00",
+ "created_at": "2026-04-25T22:58:16.086766+08:00",
+ "updated_at": "2026-04-25T22:58:16.086766+08:00",
+ "detail": null
+ },
+ {
+ "id": "415f716b-156c-4ebc-aa95-5a17cc01c759",
+ "entry_id": "c7e777fd-c7d8-4d01-be07-871862829983",
+ "title": "ME-4 Ascend",
+ "at_time": "2060-10-30T08:00:00+08:00",
+ "created_at": "2026-04-25T22:58:16.086766+08:00",
+ "updated_at": "2026-04-25T22:58:16.086766+08:00",
+ "detail": null
+ },
+ {
+ "id": "b49a23fd-111c-44d3-bee4-85301e34a731",
+ "entry_id": "cad8537e-1966-4b3c-abed-35c511950ac8",
+ "title": "Crew Arrival",
+ "at_time": "2058-06-01T08:00:00+08:00",
+ "created_at": "2026-04-25T18:14:23.332005+08:00",
+ "updated_at": "2026-04-25T18:14:23.332005+08:00",
+ "detail": "Picking up crew for Saturn Exploration Mission 1"
+ },
+ {
+ "id": "5f906dd3-2ecb-4a22-930c-518b493ef4ff",
+ "entry_id": "cad8537e-1966-4b3c-abed-35c511950ac8",
+ "title": "Earth Departure for Saturn",
+ "at_time": "2058-06-03T08:00:00+08:00",
+ "created_at": "2026-04-25T18:14:23.332005+08:00",
+ "updated_at": "2026-04-25T18:14:23.332005+08:00",
+ "detail": null
+ },
+ {
+ "id": "c731aaf6-7630-40fe-bc03-b23fe94bd1df",
+ "entry_id": "cad8537e-1966-4b3c-abed-35c511950ac8",
+ "title": "Saturn Arrival",
+ "at_time": "2058-10-12T08:00:00+08:00",
+ "created_at": "2026-04-25T18:14:23.332005+08:00",
+ "updated_at": "2026-04-25T18:14:23.332005+08:00",
+ "detail": null
+ },
+ {
+ "id": "a498df02-b254-4177-8944-2d9559de26d4",
+ "entry_id": "cf351aa5-4149-4938-939b-edcb846f4b14",
+ "title": "Departure from Mars for Earth",
+ "at_time": "2056-10-15T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "b5fe8484-8659-452a-83a7-d4846afbead2",
+ "entry_id": "cf351aa5-4149-4938-939b-edcb846f4b14",
+ "title": "Earth Arrival",
+ "at_time": "2056-11-03T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "29b4bfc3-e0fb-47a7-98ad-333346566813",
+ "entry_id": "d103bc92-da3a-4ba6-965e-a9385e208581",
+ "title": "Uncrewed mission to Earth-Sun L2 point to test deep space operations",
+ "at_time": "2053-01-12T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "430e8abf-c387-4c8d-a260-a5bff355edef",
+ "entry_id": "d103bc92-da3a-4ba6-965e-a9385e208581",
+ "title": "Back to LEO",
+ "at_time": "2053-12-18T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "9273b5eb-3990-4778-804a-0c596705e7ff",
+ "entry_id": "ded06cd6-f9a4-4646-9be4-2f01cf067334",
+ "title": "Earth Arrival",
+ "at_time": "2055-02-28T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "demo run complete, all systems perform as expected."
+ },
+ {
+ "id": "d37202fb-af66-469a-baaa-3744e0a5bdb7",
+ "entry_id": "e5f549b9-0446-48be-a606-d9c1ada664b7",
+ "title": "Earth Arrivasl",
+ "at_time": "2057-03-25T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "crew return"
+ },
+ {
+ "id": "cd31f63c-8f52-4b77-91c0-a220d4d86e12",
+ "entry_id": "e77cd6b5-a2e2-479b-817b-67c1c59bfdee",
+ "title": "Braking Burn",
+ "at_time": "2060-08-24T20:22:00+08:00",
+ "created_at": "2026-05-29T23:51:25.733307+08:00",
+ "updated_at": "2026-05-29T23:51:25.733307+08:00",
+ "detail": "Did a 50km/s braking burn before entering Earth SOI"
+ },
+ {
+ "id": "a617e707-affd-4774-bd5b-3a8c3224728b",
+ "entry_id": "e77cd6b5-a2e2-479b-817b-67c1c59bfdee",
+ "title": "Earth Arrival",
+ "at_time": "2060-08-30T06:11:00+08:00",
+ "created_at": "2026-04-25T23:11:04.877355+08:00",
+ "updated_at": "2026-05-29T23:51:25.728676+08:00",
+ "detail": null
+ },
+ {
+ "id": "70c98e5a-1d4c-471d-9df2-63ed0f35d43a",
+ "entry_id": "ea2024c5-95e6-4acc-a88d-998183a35a5a",
+ "title": "Crew Arrival",
+ "at_time": "2056-07-30T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Picking up crew for Mars One base Construction Mission 3"
+ },
+ {
+ "id": "881f23d3-bf56-44f5-8add-1155899db036",
+ "entry_id": "ea2024c5-95e6-4acc-a88d-998183a35a5a",
+ "title": "Earth Departure for Mars",
+ "at_time": "2056-08-02T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "6c48f489-4c53-4c48-9948-5fdfd79a924d",
+ "entry_id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "title": "Europa descend",
+ "at_time": "2058-09-27T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "begin surface operation at Europa Outpost"
+ },
+ {
+ "id": "ce1ae8e6-450e-447f-b5ce-9106d2dde24f",
+ "entry_id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "title": "Europa ascend",
+ "at_time": "2058-12-15T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "begin Jupiter system exploration"
+ },
+ {
+ "id": "b5d3177c-9da5-4e19-ba0e-4c4bc88624d1",
+ "entry_id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "title": "Begin IO exploration",
+ "at_time": "2058-12-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "d03a6826-aa48-4fc2-bb74-0660da2bfe1a",
+ "entry_id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "title": "Return to Europa Outpost",
+ "at_time": "2059-01-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "9c8ed78a-c7a9-4645-8737-c7f60724e208",
+ "entry_id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "title": "Begin Europa Outpost departure preparations",
+ "at_time": "2059-06-20T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "267214e8-7a99-4e77-81af-0266cc3e0a82",
+ "entry_id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "title": "Europa Expedition 1 crew ascend from Europa Outpost",
+ "at_time": "2059-06-25T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "0fde412b-c722-4530-be94-3fa8b919f306",
+ "entry_id": "f01bfb99-f981-45f6-808b-7c5222503715",
+ "title": "begin Ganymede exploration",
+ "at_time": "2059-07-05T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "46855d25-1bad-4e9f-98e4-82c644e42bd9",
+ "entry_id": "f28469ee-1dbc-4232-98ff-91f7abcb9d59",
+ "title": "Orbital Survey of Venus begins",
+ "at_time": "2055-10-02T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "d34d1ce0-bd6c-4539-8011-9c5c9e9fce24",
+ "entry_id": "f28469ee-1dbc-4232-98ff-91f7abcb9d59",
+ "title": "Landing Probe Deployment",
+ "at_time": "2055-10-10T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "abc0bc97-a67c-4182-83f8-1b4363650d2b",
+ "entry_id": "f28469ee-1dbc-4232-98ff-91f7abcb9d59",
+ "title": "Begin Upper Atmosphere Survey via Callisto MPV",
+ "at_time": "2055-11-10T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "5048bed5-66a8-46b6-96f8-b87a03bfcdf7",
+ "entry_id": "f536e950-a024-45e3-95ff-da5f77772119",
+ "title": "Saturn Departure",
+ "at_time": "2059-07-01T08:00:00+08:00",
+ "created_at": "2026-04-25T18:09:51.030100+08:00",
+ "updated_at": "2026-04-25T18:09:51.030100+08:00",
+ "detail": "Wrapping up Saturn Exploration Mission. Saturn Departure for Earth. Saturn-Earth transfer, using standard trajectory with 162km/s of departure burn"
+ },
+ {
+ "id": "62c30fc4-d3f3-45a7-ba15-c6378970067c",
+ "entry_id": "f536e950-a024-45e3-95ff-da5f77772119",
+ "title": "Earth Arrival",
+ "at_time": "2059-11-24T08:00:00+08:00",
+ "created_at": "2026-04-25T18:09:51.030100+08:00",
+ "updated_at": "2026-04-25T18:09:51.030100+08:00",
+ "detail": "Park to Star Port"
+ },
+ {
+ "id": "9830ad0c-9bdc-4f29-9846-3dcde21d4f9c",
+ "entry_id": "f6ae082d-5c36-44f9-92da-d5e568a71fea",
+ "title": "Begin Deep Space Test Mission",
+ "at_time": "2054-09-07T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "efdbe927-58dc-4396-acae-7c088216dadb",
+ "entry_id": "f6ae082d-5c36-44f9-92da-d5e568a71fea",
+ "title": "Test Mission Complete",
+ "at_time": "2054-11-28T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "all systems nominal. Returning to LEO."
+ },
+ {
+ "id": "6ab448c7-424e-425d-a070-00e667d2b221",
+ "entry_id": "fcb05995-823e-4a63-9cf8-44ea953e2e9a",
+ "title": "Earth Departure",
+ "at_time": "2059-08-04T08:00:00+08:00",
+ "created_at": "2026-04-25T22:41:30.362986+08:00",
+ "updated_at": "2026-04-25T22:41:30.362986+08:00",
+ "detail": null
+ },
+ {
+ "id": "18582c31-46f2-4a70-9a09-41f9078ed78f",
+ "entry_id": "fcb05995-823e-4a63-9cf8-44ea953e2e9a",
+ "title": "Mars Arrival",
+ "at_time": "2059-10-24T08:00:00+08:00",
+ "created_at": "2026-04-25T22:41:30.362986+08:00",
+ "updated_at": "2026-04-25T22:41:30.362986+08:00",
+ "detail": null
+ },
+ {
+ "id": "786d1428-21cd-439d-9fe0-12b447655a53",
+ "entry_id": "fe21560f-60f4-48bb-bbdb-e2c1ab6fe3af",
+ "title": "Earth Departure",
+ "at_time": "2059-04-06T08:00:00+08:00",
+ "created_at": "2026-04-25T23:04:37.201108+08:00",
+ "updated_at": "2026-04-25T23:04:37.201108+08:00",
+ "detail": null
+ },
+ {
+ "id": "7ce3048d-8349-4b8e-88f3-917f7e2e2723",
+ "entry_id": "fe21560f-60f4-48bb-bbdb-e2c1ab6fe3af",
+ "title": "Jupiter Arrival",
+ "at_time": "2059-06-20T08:00:00+08:00",
+ "created_at": "2026-04-25T23:04:37.201108+08:00",
+ "updated_at": "2026-04-25T23:04:37.201108+08:00",
+ "detail": null
+ },
+ {
+ "id": "1ac38be8-6593-43de-a729-61cb77cb5d8d",
+ "entry_id": "fe21560f-60f4-48bb-bbdb-e2c1ab6fe3af",
+ "title": "Europa Arrival",
+ "at_time": "2059-06-25T08:00:00+08:00",
+ "created_at": "2026-04-25T23:04:37.201108+08:00",
+ "updated_at": "2026-04-25T23:04:37.201108+08:00",
+ "detail": null
+ },
+ {
+ "id": "7637cde5-7140-40c8-abe6-1d4477806bd8",
+ "entry_id": "ffd625b0-0de4-4f47-8c8d-36669a1675f6",
+ "title": "Crew Arrival",
+ "at_time": "2056-06-02T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "Picking up crew for Mars One Construction Mission 2"
+ },
+ {
+ "id": "b045dc35-f68d-4b7c-999f-6eafd75e6d4f",
+ "entry_id": "ffd625b0-0de4-4f47-8c8d-36669a1675f6",
+ "title": "Picking up Mars One construction cargo",
+ "at_time": "2056-06-04T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "94b4db9b-27c6-431b-b8bf-2c038bb0f07f",
+ "entry_id": "ffd625b0-0de4-4f47-8c8d-36669a1675f6",
+ "title": "Earth Departure for Mars",
+ "at_time": "2056-06-06T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": null
+ },
+ {
+ "id": "7887519b-828d-4921-adeb-79ef9ec04b3f",
+ "entry_id": "ffd625b0-0de4-4f47-8c8d-36669a1675f6",
+ "title": "Mars Arrival",
+ "at_time": "2056-07-01T08:00:00+08:00",
+ "created_at": "2026-04-25T18:31:36.732498+08:00",
+ "updated_at": "2026-04-25T18:31:36.732498+08:00",
+ "detail": "First crewed mission to Mars using Stellaria"
+ }
+]
\ No newline at end of file
diff --git a/data_backup/entries_before.csv b/data_backup/entries_before.csv
new file mode 100644
index 0000000..c494c09
--- /dev/null
+++ b/data_backup/entries_before.csv
@@ -0,0 +1,232 @@
+asset|id|kind|title|mission|start|end|state|location|summary|note
+Europa Outpost|bf68c161-7303-44da-bf6e-72373d2e54d5|state|EOCM-1 Outpost Deployment|Europa Outpost Construction Mission 1|2057-02-27 08:00:00+08:00|2057-03-15 09:00:00+08:00|Outpost Construction|Europa Outpost|The first crewed Europa construction campaign assembled the initial habitat, power spine, and life-support core.|Backfilled from ST-01 EOCM-1 support logs.
+Europa Outpost|53ee9bf9-27c3-47c2-94f3-656a8eea64f2|event|Enter into Service|Europa Outpost Construction Mission 1|2057-03-15 09:00:00+08:00|||Europa Outpost|Europa Outpost entered operational service after the initial construction stack passed habitability review.|User-provided milestone, consistent with ST-01 EOCM-1 operation window.
+Europa Outpost|6ffeda07-93fb-4d17-9efc-817555771d35|state|EOCM-1 Initial Outpost Operations|Europa Outpost Construction Mission 1|2057-03-15 09:00:00+08:00|2057-10-01 08:00:00+08:00|Outpost Commissioning|Europa Outpost|The outpost remained crewed while the first construction team brought core systems to sustained operational readiness.|Backfilled from ST-01 EOCM-1 support logs.
+Europa Outpost|d548ded1-232d-4e68-875b-290092c7c0b8|state|Autonomous Standby|Europa Outpost Construction Mission 1|2057-10-01 08:00:00+08:00|2058-01-19 08:00:00+08:00|Autonomous Standby|Europa Outpost|After the first construction crew departed, Europa Outpost stayed in autonomous survival mode while awaiting the second construction mission.|Bridging interval inferred from EOCM-1 return and EOCM-2 arrival windows.
+Europa Outpost|83dcded1-c57c-49c8-b94b-5430c2fe4d4d|state|EOCM-2 Outpost Expansion|Europa Outpost Construction Mission 2|2058-01-19 08:00:00+08:00|2058-09-06 08:00:00+08:00|Outpost Construction|Europa Outpost|The second construction campaign expanded the habitat ring, utility corridors, and long-duration expedition support spaces.|Backfilled from ST-02 EOCM-2 support logs.
+Europa Outpost|50c4b9a3-644d-4dd6-85c7-cd40f1d32667|state|Post-Construction Readiness|Europa Outpost Construction Mission 2|2058-09-06 08:00:00+08:00|2058-09-25 08:00:00+08:00|Autonomous Standby|Europa Outpost|Europa Outpost remained uncrewed briefly after Construction Mission 2 while final expedition supplies were staged.|Bridging interval inferred from ST-02 EOCM-2 departure and XH-01 EE-1 arrival.
+Europa Outpost|188eb0ca-df35-4644-92d3-6952bae3dbe8|event|Europa Expedition 1 Arrived|Europa Expedition 1|2058-09-25 10:00:00+08:00|||Europa Outpost|Europa Expedition 1 docked at the outpost and began the first standard long-duration occupation cycle.|Backfilled from XH-01 EE-1 support logs.
+Europa Outpost|f034826a-77fc-4070-84a6-0f419d0910bb|state|EE-1 Surface Operations|Europa Expedition 1|2058-09-25 10:00:00+08:00|2059-06-25 08:30:00+08:00|Surface Expedition|Europa Outpost|Europa Expedition 1 occupied the outpost and supported early Jupiter system science operations based from Europa.|Backfilled from XH-01 EE-1 Jupiter System Operations.
+Europa Outpost|a5da1a52-0c59-423a-b41e-2e646783bb67|event|Europa Expedition 2 Arrived|Europa Expedition 2|2059-06-25 08:30:00+08:00|||Europa Outpost|Europa Expedition 2 arrived via ST-02 Kristen with 12 crew and 1 Echo Shuttle Block 1.|User-provided crew manifest and arrival vehicle; consistent with ST-02 EE-2 arrival window.
+Europa Outpost|f17eb842-8870-431d-9280-1b5fde97b48b|state|EE-1/EE-2 Crew Handoff|Europa Expedition 1; Europa Expedition 2|2059-06-25 08:30:00+08:00|2059-06-25 16:00:00+08:00|Crew Handoff; Surface Expedition|Europa Outpost|Europa Expedition 2 overlapped with Expedition 1 during crew transfer, cargo sorting, and outpost handover.|Outpost-level handoff interval inferred from same-day EE-2 arrival and EE-1 departure notes.
+Europa Outpost|a51cd5a1-3ef1-430a-87f7-71ce9db44714|state|EE-2 Surface Operations|Europa Expedition 2|2059-06-25 16:00:00+08:00|2060-05-03 09:00:00+08:00|Surface Expedition|Europa Outpost|Europa Expedition 2 assumed continuous occupation of the outpost after the first crew rotation completed.|Backfilled from ST-02 EE-2 support logs.
+Europa Outpost|906f6248-fd84-4211-a0eb-74c39e59ce86|event|Europa Expedition 1 Departed|Europa Expedition 1|2059-06-25 16:00:00+08:00|||Europa Outpost|Europa Expedition 1 departed the outpost via Xihe Station with 9 crew and 1 Callisto MPV Block 1.|User-provided departure note; treated as outpost departure milestone within XH-01 EE-1 broader return window.
+Europa Outpost|15f8aae6-45f8-43d9-a3d6-9a2585ddeed2|event|Expansion Module Arrived|Europa Outpost Expansion Mission; Europa Expedition 2|2060-05-03 11:00:00+08:00|||Europa Outpost|The Europa Outpost expansion module arrived while Expedition 2 remained on station.|User-provided date; consistent with Solar Shuttle 2 expansion delivery window at Europa.
+Europa Outpost|82509df3-ad30-483f-a0f7-b05ff4497435|state|EE-2 Operations with Expansion Module Integration|Europa Expedition 2; Europa Outpost Expansion Mission|2060-05-03 11:00:00+08:00|2060-06-23 09:00:00+08:00|Surface Expedition; Outpost Expansion|Europa Outpost|Europa Expedition 2 supported installation and activation of the new expansion module after it reached the outpost.|Backfilled from Solar Shuttle 2 expansion delivery and ST-02 EE-2 operation windows.
+Europa Outpost|db70ac3b-1035-4066-8e74-928e656bc39a|state|EE-2/EE-3 Crew Handoff|Europa Expedition 2; Europa Expedition 3|2060-06-23 09:00:00+08:00|2060-06-24 15:00:00+08:00|Crew Handoff; Surface Expedition|Europa Outpost|Europa Expedition 3 overlapped with Expedition 2 during crew turnover and transfer of outpost responsibility.|Outpost-level handoff interval inferred from user-provided EE-3 arrival and EE-2 departure dates.
+Europa Outpost|d7a1d501-ed5f-4065-a773-aa4ef101dede|event|Europa Expedition 3 Arrived|Europa Expedition 3|2060-06-23 09:00:00+08:00|||Europa Outpost|Europa Expedition 3 arrived via XH-01 to begin the next outpost rotation.|User-provided arrival date; treated as outpost arrival milestone within XH-01 EE-3 Jupiter System Operations.
+Europa Outpost|8649cb17-0bcb-4ba4-9f91-e9c441ff9793|event|Europa Expedition 2 Departed|Europa Expedition 2|2060-06-24 15:00:00+08:00|||Europa Outpost|Europa Expedition 2 departed the outpost via ST-02 Kristen after completing crew handoff to Expedition 3.|User-provided departure date; treated as outpost departure milestone slightly ahead of ST-02 EE-2 system departure.
+Europa Outpost|a7c9d010-5aed-43fc-a744-1a86ad9b15c8|state|EE-3 Surface Operations|Europa Expedition 3|2060-06-24 15:00:00+08:00||Surface Expedition|Europa Outpost|Europa Expedition 3 is the current resident crew. Crew status on 2060-06-24: 6 scientists at Lab, 2 medical at center hub, 1 commander and 1 pilot at observation station, 2 engineers at greenhouse.|User-provided current crew distribution for 2060-06-24.
+JW-01 һ|5df95fe3-5f0d-4dc1-ad37-508adcf2eef2|state|Construction||2058-03-14 16:00:00+08:00|2059-03-08 08:00:00+08:00|Construction|Star Port|Solar Shuttle 1 Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+JW-01 һ|e306c665-07c0-46dc-8127-b96775d616b9|state|Assembly Complete||2059-03-08 08:00:00+08:00|2059-04-13 08:00:00+08:00|Assembly Complete|LEO|Assembly complete, preparing for commissioning|Timeline.xlsx inferred monthly phase. Raw: Assembly Complete
+JW-01 һ|543dabdc-e61b-4a1c-8c4b-3e753d17cbbd|state|Trial Run||2059-04-13 08:00:00+08:00|2059-08-06 08:00:00+08:00|Trial Run|Earth|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+JW-01 һ|b99062ea-4547-4cdc-8bf1-3b1f0c28a4be|state|Mars One Expansion Outbound|Mars One Expansion|2059-08-06 08:00:00+08:00|2059-10-24 08:00:00+08:00|Transfer|Sun|Earth-Mars transfer|Timeline.xlsx inferred monthly phase. Raw: Earth-Mars
+JW-01 һ|30930d1b-d32b-4ef6-97ae-6d11c777ad53|state|Mars One Expansion|Mars One Expansion|2059-10-19 08:00:00+08:00|2060-08-09 05:10:00+08:00|Base Expansion|Mars|Mars One Expansion|Timeline.xlsx inferred monthly phase. Raw: Mars One Expansion
+JW-01 һ|00c8b5c6-e363-4aee-a768-2fc3fa7a0138|state|Mars Return|Mars One Expansion|2060-08-09 05:10:00+08:00|2060-10-26 10:03:00+08:00|Transfer|Sun|Back to Earth with Qingtian|Carrying Mars One component back
+Mars One Base|97b3a860-03c6-4ca3-a9c8-f94fd05adbe0|event|Initial Cargo Landed|Mars Mission Demo|2054-08-23 10:30:00+08:00|||Mars One Base|Cargo from Mars Mission Demo was landed at the future Mars One site for robotic setup.|Backfilled from XH-01 Mars Mission Demo support logs.
+Mars One Base|dc082672-52a2-4142-a2b8-737991ee542f|state|MMD Surface Activation|Mars Mission Demo|2054-08-23 12:00:00+08:00|2055-07-30 08:00:00+08:00|Surface Activation|Mars One Base|Robotic systems activated the first surface power, comms, and cargo handling stack delivered by Mars Mission Demo.|Backfilled from XH-01 Mars Mission Demo support logs.
+Mars One Base|3141e93d-1e47-4264-864b-378815d8e871|event|First Crewed Landing|Mars One Base Construction Mission 1|2055-07-30 09:30:00+08:00|||Mars One Base|The first crewed Mars One construction team landed and began surface assembly.|Backfilled from XH-01 MOCM-1 support logs.
+Mars One Base|9399f5f6-9412-455f-8683-b237bcdeab7b|state|MOCM-1 Initial Construction|Mars One Base Construction Mission 1|2055-07-30 10:00:00+08:00|2056-02-07 08:00:00+08:00|Base Construction|Mars One Base|The first crewed construction campaign assembled the core habitat, power systems, and ascent support infrastructure.|Backfilled from XH-01 MOCM-1 support logs.
+Mars One Base|afe0f5fe-6909-4351-8003-b3f78e9145d1|state|MOCM-1 Autonomous Commissioning|Mars One Base Construction Mission 1|2056-02-07 08:00:00+08:00|2056-07-03 08:00:00+08:00|Autonomous Standby|Mars One Base|After the first construction crew departed, the outpost remained in autonomous checkout ahead of the next build window.|Bridging interval inferred from the first and second Mars One construction campaigns.
+Mars One Base|0fd356d5-71ce-4219-a7fd-b9ff077f4f39|state|MOCM-2 Base Construction|Mars One Construction Mission 2|2056-07-03 08:00:00+08:00|2056-09-15 08:00:00+08:00|Base Construction|Mars One Base|Mission 2 expanded the surface habitat and continued utility trenching and storage build-out.|Backfilled from ST-01 MOCM-2 support logs.
+Mars One Base|d96bd772-45eb-4010-96c2-1c942f4efc96|state|MOCM-2/MOCM-3 Crew Handoff|Mars One Construction Mission 2; Mars One Base Construction Mission 3|2056-09-15 08:00:00+08:00|2056-10-12 08:00:00+08:00|Base Construction; Crew Handoff|Mars One Base|Construction Mission 3 arrived before Mission 2 departed, enabling the first on-surface Mars One crew handoff.|Backfilled from ST-01 MOCM-2 and XH-01 MOCM-3 support logs.
+Mars One Base|a05e86bb-77e5-4b99-a7d2-16a1dc810150|state|MOCM-3 Base Construction|Mars One Base Construction Mission 3|2056-10-12 08:00:00+08:00|2056-11-19 08:00:00+08:00|Base Construction|Mars One Base|The third construction campaign completed surface integration and prepared the outpost for continuous expedition occupancy.|Backfilled from XH-01 MOCM-3 support logs.
+Mars One Base|2b0a2dbf-3f28-449e-af86-75ebf87b408e|state|MOCM-3 and ME-1 Surface Operations|Mars One Base Construction Mission 3; Mars Expedition 1|2056-11-19 08:00:00+08:00|2057-02-12 08:00:00+08:00|Base Construction; Surface Expedition|Mars One Base|Final construction work continued while Mars Expedition 1 began long-duration surface operations from the outpost.|Overlap inferred from XH-01 MOCM-3 and ST-02 ME-1 support logs.
+Mars One Base|edfbaea5-331b-4a93-9458-044d3016eb7f|event|Phase 1 Construction Complete|Mars One Base Construction Mission 3; Mars Expedition 1|2057-02-12 09:00:00+08:00|||Mars One Base|Mars One entered sustained expedition service after the third construction wave wrapped up.|Completion milestone inferred from XH-01 MOCM-3 return window.
+Mars One Base|e8003196-d035-49be-a721-144fec91a678|state|ME-1 Surface Operations|Mars Expedition 1|2057-02-12 09:00:00+08:00|2057-06-22 08:00:00+08:00|Surface Expedition|Mars One Base|Mars Expedition 1 operated the newly completed outpost and stabilized its life-support and logistics cadence.|Backfilled from ST-02 ME-1 support logs.
+Mars One Base|fb511ee5-3343-4884-a094-59241d1d28e0|state|ME-1/ME-2 Crew Handoff|Mars Expedition 1; Mars Expedition 2|2057-06-22 08:00:00+08:00|2057-09-08 08:00:00+08:00|Surface Expedition; Crew Handoff|Mars One Base|Mars Expedition 2 arrived while Expedition 1 completed return preparations, overlapping on the surface during handoff.|Overlap inferred from ST-02 ME-1 and XH-01 ME-2 support logs.
+Mars One Base|5109f226-b843-4173-97cf-bb3b740927ed|state|ME-2 Surface Operations|Mars Expedition 2|2057-09-08 08:00:00+08:00|2058-04-17 08:00:00+08:00|Surface Expedition|Mars One Base|Mars Expedition 2 took over continuous surface operations after the Expedition 1 crew departed.|Backfilled from XH-01 ME-2 support logs.
+Mars One Base|9c4ef55d-a472-4e19-b582-8f872e6c854a|state|ME-2/ME-3 Crew Handoff|Mars Expedition 2; Mars Expedition 3|2058-04-17 08:00:00+08:00|2058-04-18 08:00:00+08:00|Surface Expedition; Crew Handoff|Mars One Base|Mars Expedition 3 overlapped briefly with Expedition 2 during the next surface crew handoff.|Overlap inferred from XH-01 ME-2 return and XH-02 ME-3 arrival timing.
+Mars One Base|66d8bc17-70e4-4c18-9c00-a8a2ffb4c1d3|state|ME-3 Surface Operations|Mars Expedition 3|2058-04-18 08:00:00+08:00|2059-10-19 08:00:00+08:00|Surface Expedition|Mars One Base|Mars Expedition 3 sustained the base through the long pre-expansion interval and remained on Mars after XH-02 departed uncrewed.|Backfilled from XH-02 ME-3 support logs and uncrewed return timing.
+Mars One Base|faf59da6-de11-4f77-892a-5483f17a30e0|event|Expansion Cargo Arrival|Mars One Expansion|2059-10-19 09:00:00+08:00|||Mars One Base|Solar Shuttle 1 delivered the first Mars One expansion package to the surface site.|Backfilled from Solar Shuttle 1 Mars One Expansion support logs.
+Mars One Base|5112903a-12bb-4529-afa5-1e37eade53d3|state|Mars One Expansion and ME-3 Surface Operations|Mars One Expansion; Mars Expedition 3|2059-10-19 09:00:00+08:00|2059-10-24 14:00:00+08:00|Base Expansion; Surface Expedition|Mars One Base|Expansion work began while Mars Expedition 3 kept the outpost occupied ahead of the next crew arrival.|Overlap inferred from Solar Shuttle 1 expansion and XH-02 ME-4 arrival windows.
+Mars One Base|e890d519-64ac-4152-902f-42c69a553b84|state|ME-3/ME-4 Crew Handoff with Expansion Package|Mars One Expansion; Mars Expedition 3; Mars Expedition 4|2059-10-24 14:00:00+08:00|2059-11-04 08:00:00+08:00|Base Expansion; Crew Handoff|Mars One Base|Mars Expedition 4 arrived with the expansion package while Mars Expedition 3 prepared for ascent and departure.|Overlap inferred from XH-02 ME-4 Part 1, Solar Shuttle 1 expansion, and XH-02 ME-3 return timing.
+Mars One Base|292bb2fc-4688-49e6-94e4-598da921d3e5|state|Mars One Expansion and ME-4 Surface Operations|Mars One Expansion; Mars Expedition 4|2059-11-04 08:00:00+08:00|2060-02-23 08:00:00+08:00|Base Expansion; Surface Expedition|Mars One Base|After Expedition 3 departed, Mars Expedition 4 continued surface operations alongside the active expansion campaign.|Backfilled from XH-02 ME-4 and Solar Shuttle 1 expansion support logs.
+Mars One Base|16e6a85a-2c04-4dc5-8132-b7cd16a104da|state|Expansion, ME-4, and Rover Delivery|Mars One Expansion; Mars Expedition 4; Mars One Rover Delivery|2060-02-23 08:00:00+08:00|2060-05-23 08:00:00+08:00|Base Expansion; Surface Expedition; Cargo Delivery|Mars One Base|The rover delivery campaign overlapped with base expansion and Expedition 4 surface operations.|Overlap inferred from Solar Shuttle 3 rover delivery, Solar Shuttle 1 expansion, and XH-02 ME-4 support logs.
+Mars One Base|8fc9c2b3-6272-44cb-a942-8bd4c83a6d05|state|Mars One Expansion and ME-4 Surface Operations|Mars One Expansion; Mars Expedition 4|2060-05-23 09:30:00+08:00|2060-08-09 05:10:00+08:00|Base Expansion; Surface Expedition|Mars One Base|Expansion work continued after rover deployment while Mars Expedition 4 remained the resident surface crew.|Backfilled from Solar Shuttle 1 expansion and XH-02 ME-4 support logs.
+Mars One Base|0d811cfd-1358-46de-b637-3d0b230da76e|event|Rover Deployment Complete|Mars One Rover Delivery; Mars Expedition 4|2060-05-23 09:30:00+08:00|||Mars One Base|The new Mars One surface rover entered service after the cargo delivery campaign wrapped up.|Backfilled from Solar Shuttle 3 rover delivery support logs.
+Mars One Base|d86f43a9-ae09-4319-8905-98b35c1d585b|state|ME-4 Surface Operations|Mars Expedition 4|2060-08-09 06:00:00+08:00|2060-10-30 08:00:00+08:00|Surface Expedition|Mars One Base|After expansion wrapped up, Mars Expedition 4 continued normal surface operations from the upgraded outpost.|Backfilled from XH-02 ME-4 support logs.
+Mars One Base|1b798abc-10bb-40cc-a517-4593512b0495|event|Expansion Phase Complete|Mars One Expansion; Mars Expedition 4|2060-08-09 06:00:00+08:00|||Mars One Base|The main Mars One expansion phase was completed and Solar Shuttle 1 departed on the return leg.|Backfilled from Solar Shuttle 1 expansion return timing.
+Solar Shuttle 2|d190cc9e-e230-4299-8f13-1bda0f6b1aac|state|Construction||2058-09-17 16:00:00+08:00|2059-09-11 08:00:00+08:00|Construction|LEO|Solar Shuttle 2 Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+Solar Shuttle 2|8e33ce9e-2409-4b1c-af09-6a931fbe2d49|state|Trial Run||2059-09-11 08:00:00+08:00|2059-12-01 08:00:00+08:00|Trial Run|Earth|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+Solar Shuttle 2|5a2092a8-ddad-41b3-9819-fa52557332ed|state|EOEM Outbound|Europa Outpost Expansion Mission|2059-12-09 08:00:00+08:00|2060-05-01 08:00:00+08:00|Transfer|Sun||
+Solar Shuttle 2|c0271f19-e604-4c15-9c00-7118fec1928e|state|Europa Outpost Expansion Mission|Europa Outpost Expansion Mission|2060-05-01 08:00:00+08:00|2060-05-06 07:25:00+08:00|Outpost Expansion|Europa|Europa Outpost Expansion Package delivered via Qingtian Cargo Spacecraft|
+Solar Shuttle 2|687615b6-144f-4fd5-b3ee-709e4eaea6aa|state|EOEM Inbound|Europa Outpost Expansion Mission|2060-05-06 07:25:00+08:00|2060-06-26 08:00:00+08:00|Transfer|Sun||
+Solar Shuttle 3|219355f0-1399-49af-b352-6728f0d4c82b|state|Construction||2059-01-14 16:00:00+08:00|2059-12-14 08:00:00+08:00|Construction|Star Port|Solar Shuttle 3 Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+Solar Shuttle 3|aac31a1a-45c7-47f4-add3-fbfa30f9011f|state|Trial Run||2059-12-14 08:00:00+08:00|2060-02-20 08:00:00+08:00|Trial Run|Earth|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+Solar Shuttle 3|7deb1192-d6f0-4635-9a6d-39ab0c2adcfe|state|Mars One Rover Delivery|Mars One Rover Delivery|2060-02-23 08:00:00+08:00|2060-05-23 08:00:00+08:00|Cargo Delivery|Mars|Mars One Rover Delivery|Timeline.xlsx inferred monthly phase. Raw: Mars One Rover Delivery
+Solar Shuttle 3|d33a6759-0f54-4e71-909b-6d3916ca13dc|state|Mars Return||2060-11-05 04:07:00+08:00||Transfer|Sun||
+ST-01 Դ|ae003c1f-f74e-459b-ade2-74fcdae48605|state|Construction||2050-09-15 16:00:00+08:00|2054-04-28 16:00:00+08:00|Construction|LEO|Construction|2050-09-15 First module delivered to LEO via Vulture Shuttle
+2053-02-02 Assembly Halted
+ST-01 Դ|105a5eac-4ca1-4a5a-a9ad-bc2278d46f01|state|Trial Run||2054-05-12 08:00:00+08:00|2054-08-22 08:00:00+08:00|Trial Run|Lunar Orbit|Trial Run before commissioning|2054-05-12 Begin Trial Run in Earth Orbit, testing all systems
+2054-08-22 Trial Run complete, all systems perform as expected. Including multiple run to GEO and Lunar Orbit before returning to LEO.
+ST-01 Դ|f6ae082d-5c36-44f9-92da-d5e568a71fea|state|Deep Space Test Mission||2054-09-07 08:00:00+08:00|2054-11-28 08:00:00+08:00|Deep Space Test Mission|Earth-Sun L2|Uncrewed mission to Earth-Sun Lagrange Point 2 to test long-duration operations|2054-09-07 Begin Deep Space Test Mission
+2054-11-28 Test Mission Complete, all systems nominal. Returning to LEO.
+ST-01 Դ|503a0035-1cd7-4e8e-9bc6-922c2e5c3171|state|Maintenance before Commissioning||2054-12-01 08:00:00+08:00|2055-02-28 08:00:00+08:00|Maintenance before Commissioning|LEO||
+ST-01 Դ|4bfddc84-dfec-43e3-b534-4fb798bcc73f|state|ISSEM-1 Mercury Transfer|Inner Solar System Exploration Mission 1|2055-03-20 08:00:00+08:00|2055-04-17 08:00:00+08:00|Transfer|Sun|Earth-Mecury transfer, using standard trajectory with 127km/s of departure burn|2055-03-20 Picking up crew for Inner Solar System Exploration Mission 1
+2055-03-22 Earth Departure for Mecury
+2055-04-17 Mercury Arrival
+ST-01 Դ|42698c8c-a1cc-4742-9885-7b9e650f9867|state|ISSEM-1 Mercury Operations|Inner Solar System Exploration Mission 1|2055-04-18 08:00:00+08:00|2055-08-14 08:00:00+08:00|Planetary Operations|Mercury|First crewed mission to Mercury|2055-04-17 Mercury Arrival
+2055-04-18 Orbital Survey of Mercury begins
+2055-06-14 First Crewed Surface Landing on Mercury
+2055-06-15 EVA operations commence
+2055-06-30 Surface operations complete, returning to orbit
+2055-08-15 Departure from Mercury for Venus
+ST-01 Դ|2adfa016-b23a-4459-af6e-a84da2aa2469|state|ISSEM-1 Venus Transfer|Inner Solar System Exploration Mission 1|2055-08-15 08:00:00+08:00|2055-10-01 08:00:00+08:00|Transfer|Sun|Mecury-Venus transfer, using standard trajectory with 85km/s of departure burn|2055-08-15 Departure from Mercury for Venus
+2055-10-01 Venus Arrival
+ST-01 Դ|f28469ee-1dbc-4232-98ff-91f7abcb9d59|state|ISSEM-1 Venus Operations|Inner Solar System Exploration Mission 1|2055-10-01 08:00:00+08:00|2056-03-24 08:00:00+08:00|Planetary Operations|Venus|First crewed mission to Venus, no crewed landing attempted due to extreme surface conditions. Probe deployment only.|2055-10-01 Venus Arrival
+2055-10-02 Orbital Survey of Venus begins
+2055-10-10 Landing Probe Deployment
+2055-11-10 Begin Upper Atmosphere Survey via Callisto MPV
+2056-03-24 Departure from Venus for Earth
+ST-01 Դ|1f6e85aa-121a-4f47-95b6-35f040da055c|state|ISSEM-1 Inbound|Inner Solar System Exploration Mission 1|2056-03-24 08:00:00+08:00|2056-04-12 08:00:00+08:00|Transfer|Sun|Venus-Earth transfer, using standard trajectory with 75km/s of departure burn|2056-03-24 Departure from Venus for Earth
+2056-04-12 Earth Arrival
+ST-01 Դ|540c146e-0d48-4735-8eb4-6fe08506b705|state|Maintenance||2056-04-15 08:00:00+08:00|2056-05-31 08:00:00+08:00|Maintenance|LEO||
+ST-01 Դ|ffd625b0-0de4-4f47-8c8d-36669a1675f6|state|MOCM-2 Outbound|Mars One Construction Mission 2|2056-06-02 08:00:00+08:00|2056-07-01 08:00:00+08:00|Transfer|Sun|Earth-Mars transfer, using standard trajectory with 126km/s of departure burn|2056-06-02 Picking up crew for Mars One Construction Mission 2
+2056-06-04 Picking up Mars One construction cargo
+2056-06-06 Earth Departure for Mars
+2056-07-01 Mars Arrival, First crewed mission to Mars using Stellaria
+ST-01 Դ|12059276-d10a-4a37-9b8c-6a6183768504|state|MOCM-2 Mars Operations|Mars One Construction Mission 2|2056-07-03 08:00:00+08:00|2056-10-12 08:00:00+08:00|Base Construction|Mars|Continuing the construction of Mars One Base|2056-07-03 Crew descend to Martian Surface, Continuing the construction of Mars One Base
+2056-07-20 Heavy Cargo Delivery to Surface via Callisto MPV
+2056-09-17 Mars One Construction Mission 3 Crew Arrival via XH-01, joining Stellaria crew. First Crew Handover on Mars.
+2056-10-12 Mars One Construction Mission 2 Crew ascend to Stellaria
+2056-10-15 Departure from Mars for Earth
+ST-01 Դ|cf351aa5-4149-4938-939b-edcb846f4b14|state|MOCM-2 Inbound|Mars One Construction Mission 2|2056-10-15 08:00:00+08:00|2056-11-03 08:00:00+08:00|Transfer|Sun|Mars-Earth transfer, using Fast Return trajectory with 212km/s of departure burn|2056-10-15 Departure from Mars for Earth
+2056-11-03 Earth Arrival
+ST-01 Դ|fd8fba0b-82bb-4ad3-bc38-58745291627b|state|Maintenance||2056-11-04 08:00:00+08:00|2056-12-10 08:00:00+08:00|Maintenance|LEO||
+ST-01 Դ|7747339c-f602-4ddf-8511-6862006f789b|state|EOCM-1 Outbound|Europa Outpost Construction Mission 1|2056-12-15 08:00:00+08:00|2057-02-25 08:00:00+08:00|Transfer|Sun|Earth-Europa transfer, using standard trajectory with 165km/s of departure burn|2056-12-15 Start preparations for Europa Outpost Construction Mission 1
+2056-12-20 Europa Outpost Construction Package arrival via Qingtian Cargo Shuttle
+2056-12-31 Picking up crew for Europa Outpost Construction Mission 1
+2057-01-02 Earth Departure for Europa
+ST-01 Դ|545f687e-bd2c-409a-8fb8-186a6dead67e|state|EOCM-1 Europa Operations|Europa Outpost Construction Mission 1|2057-02-27 08:00:00+08:00|2057-10-01 08:00:00+08:00|Outpost Construction|Europa|First crewed mission to Europa|2057-02-27 Heavy Cargo Delivery to Surface via Qingtian Cargo Shuttle
+2057-03-15 Crew descend to Europan Surface, Beginning construction of Europa Outpost
+6 crewed ascend and descend operations to Europa Surface via Callisto MPV between 2057-03-15 and 2057-09-15
+2057-10-01 Europa Outpost Construction Mission 1 Crew ascend to Stellaria, wrapping up construction phase 1
+2057-10-04 Europa Departure for Earth
+ST-01 Դ|43f2ece9-283b-4484-b838-d684b9ada4d6|state|EOCM-1 return to Earth|Europa Outpost Construction Mission 1|2057-10-04 08:00:00+08:00|2057-12-20 08:00:00+08:00|Transfer|Europa|Europa-Earth transfer, using Fast trajectory with 216km/s of departure burn|2057-10-04 Europa Departure for Earth
+2057-12-20 Earth Arrival
+ST-01 Դ|7d6a56c8-9ebc-4940-813b-54ee2c9711f4|state|Maintenance and Upgrades||2058-01-05 08:00:00+08:00|2058-05-15 08:00:00+08:00|Maintenance and Upgrades|LEO|Extensive overhauls to bring ST-01 closer to full Stellaria specifications. Add more greenhouse modules, upgrade life support systems, add another Rotating Habitat Ring|
+ST-01 Դ|cad8537e-1966-4b3c-abed-35c511950ac8|state|SEM-1 outbound|Saturn Exploration Mission 1|2058-06-01 08:00:00+08:00|2058-10-12 08:00:00+08:00|Transfer|Sun|Earth-Saturn transfer, using Fast trajectory with 210km/s of departure burn|First crewed mission to Saturn
+ST-01 Դ|022b0296-5c1a-41f8-8634-97dc663b05d9|state|SEM-1 Saturn Operations|Saturn Exploration Mission 1|2058-10-12 08:00:00+08:00|2059-07-01 08:00:00+08:00|Planetary Operations|Saturn System|First crewed mission to Saturn|2059-05-31 Parked into Iapetus orbit, orbital science completed
+2059-06-15 Start Iapetus Surface operation
+ST-01 Դ|f536e950-a024-45e3-95ff-da5f77772119|state|SEM-1 Inbound|Saturn Exploration Mission 1|2059-07-01 08:00:00+08:00|2059-11-24 08:00:00+08:00|Transfer|Sun|Saturn-Earth transfer, using standard trajectory with 162km/s of departure burn|
+ST-01 Դ|3fce336c-7ac9-4117-9239-bf939dfe1ad1|state|Maintenance and Upgrades||2059-11-25 08:00:00+08:00|2060-02-10 08:00:00+08:00|Maintenance and Upgrades|Star Port|Upgrades complete, ST-01 now fully meets Stellaria specifications.|
+ST-01 Դ|8a9de074-6348-4190-bd27-e3bdeddb70f7|state|OSSEM-1 Outbound|Outer Solar System Exploration Mission 1|2060-02-11 08:00:00+08:00|2060-07-24 20:11:00+08:00|Transfer|Sun|ǰ|23 crew on board
+ST-01 Դ|18b3429e-28d3-489c-b65c-35e0e9775a0d|state|OSSEM-1 Neptune Exploration|OSSEM-1; Neptune|2060-07-25 06:40:00+08:00||Exploration|Neptune||
+ST-02 Kristen|eefd7712-b6f4-496c-9bc8-8eb9546887b8|state|Construction||2052-01-14 16:00:00+08:00|2053-02-10 08:00:00+08:00|Construction|LEO|ST-02 Kristen Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+ST-02 Kristen|721dec30-3c58-4885-8fda-22e2960ef4a0|state|Assembly Halted||2053-02-10 08:00:00+08:00|2053-05-12 08:00:00+08:00|Assembly Halted|LEO|Assembly halted pending redesign and program review|Timeline.xlsx inferred monthly phase. Raw: Assembly Halted
+ST-02 Kristen|8226a3aa-1896-42e2-9e5e-0fca750d229d|state|Reconfiguring to ST-02||2053-05-12 08:00:00+08:00|2055-10-13 08:00:00+08:00|Reconfiguring to ST-02|LEO|Vehicle reconfiguration and systems integration|Timeline.xlsx inferred monthly phase. Raw: Reconfiguring to ST-02
+ST-02 Kristen|826e67d8-e876-41e5-9551-a80f700e90cd|state|Trial Run||2055-10-13 08:00:00+08:00|2056-03-10 08:00:00+08:00|Trial Run|Lunar Orbit|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+ST-02 Kristen|b5a01aed-7a98-4f81-a84f-efb59b8f2479|state|Deep Space Test Mission||2056-03-10 08:00:00+08:00|2056-06-08 08:00:00+08:00|Deep Space Test Mission|Earth-Sun L2|Uncrewed Mission to Earth-Sun L2|Timeline.xlsx inferred monthly phase. Raw: Deep Space Test Mission / Uncrewed Mission to Earth-Sun L2
+ST-02 Kristen|7b7fd38f-2647-4ed8-b1bc-27e94861b15d|state|Maintenance||2056-06-08 08:00:00+08:00|2056-11-19 08:00:00+08:00|Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+ST-02 Kristen|ca8f8223-800b-4562-8405-a270d3960a6e|state|ME-1 Mars Operations|Mars Expedition 1|2056-11-19 08:00:00+08:00|2057-09-08 08:00:00+08:00|Planetary Operations|Mars|Mars Expedition 1|Timeline.xlsx inferred monthly phase. Raw: Mars Expedition 1
+ST-02 Kristen|a7c43eae-31fc-451d-8bbc-fd6f3da63f22|state|Maintenance||2057-09-08 08:00:00+08:00|2057-10-06 08:00:00+08:00|Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+ST-02 Kristen|a61ee6fc-5495-4b5b-a505-968669b81b18|state|EOCM-2 Outbound|Europa Outpost Construction Mission 2|2057-10-06 08:00:00+08:00|2058-01-19 08:00:00+08:00|Transfer|Sun|Earth-Europa transfer|Timeline.xlsx inferred monthly phase. Raw: Earth-Europa
+ST-02 Kristen|fb17cab1-dcbc-4814-83e9-5fb81a73f869|state|EOCM-2 Europa Operations|Europa Outpost Construction Mission 2|2058-01-19 08:00:00+08:00|2058-09-06 08:00:00+08:00|Outpost Construction|Europa|Europa Outpost Construction Mission 2|Timeline.xlsx inferred monthly phase. Raw: Europa Outpost Construction Mission 2
+ST-02 Kristen|efdb28dd-3e02-4b16-80e8-7a2d4df76825|state|EOCM-2 Inbound|Europa Outpost Construction Mission 2|2058-09-06 08:00:00+08:00|2058-11-08 08:00:00+08:00|Transfer|Sun|Europa-Earth transfer|Timeline.xlsx inferred monthly phase. Raw: Europa-Earth
+ST-02 Kristen|77c71061-354d-4045-b5cd-5cd6b1e8dd65|state|Maintenance and Upgrades||2058-11-08 08:00:00+08:00|2059-04-06 08:00:00+08:00|Maintenance and Upgrades|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance and Upgrades
+ST-02 Kristen|fe21560f-60f4-48bb-bbdb-e2c1ab6fe3af|state|EE-2 Outbound|Europa Expedition 2|2059-04-06 08:00:00+08:00|2059-06-25 08:00:00+08:00|Transfer|Sun|Earth-Europa transfer|
+ST-02 Kristen|65910288-0c2a-4800-bfce-39495efafce2|state|EE-2 Europa Operations|Europa Expedition 2|2059-06-25 08:00:00+08:00|2060-06-28 02:47:00+08:00|Planetary Operations|Europa|Supporting Europa Expedition 2|
+ST-02 Kristen|e77cd6b5-a2e2-479b-817b-67c1c59bfdee|state|EE-2 Inbound|Europa Expedition 2|2060-06-28 02:47:00+08:00|2060-08-30 06:11:00+08:00|Transfer|Sun||
+ST-02 Kristen|6c7a8724-1324-4a68-81e1-3dc2ce1ce980|state|Upgrade to Stellaria Class||2060-08-30 07:26:00+08:00|2061-06-30 08:00:00+08:00|Upgrade|Star Ring Station|A full overhaul to bring ST-02 to full Stellaria standard|
+ST-03 Muelsyse|10030cb4-2626-483a-8682-db9eed90da71|state|Construction||2056-02-13 16:00:00+08:00|2059-07-07 08:00:00+08:00|Construction|LEO|ST-03 Muelsyse Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+ST-03 Muelsyse|520e5ad4-e79c-458d-8387-76ba0a120b2e|state|Assembly Complete||2059-07-07 08:00:00+08:00|2059-08-12 08:00:00+08:00|Assembly Complete|LEO|Assembly complete, preparing for commissioning|Timeline.xlsx inferred monthly phase. Raw: Assembly Complete
+ST-03 Muelsyse|068b82d8-e107-465b-98b8-eba39739ee63|state|Trial Run||2059-08-12 08:00:00+08:00|2060-03-07 08:00:00+08:00|Trial Run|Lunar Orbit|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+ST-03 Muelsyse|16e6ce3d-d2ef-4910-a1ff-4670cbb63fb7|state|Maintenance||2060-03-07 08:00:00+08:00|2060-06-10 08:00:00+08:00|Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+ST-03 Muelsyse|e61bb0d2-ab64-4f79-a18a-77dea92eb3ab|state|Deep Space Test||2060-06-15 08:00:00+08:00|2060-09-10 08:00:00+08:00|Deep Space Test|Sun-Earth L2||
+ST-03 Muelsyse|2f391faf-4061-45cc-bcd5-ce5956cff9bd|state|Pre-commissioning Maintenance||2060-09-10 08:00:00+08:00|2060-10-25 08:00:00+08:00|Maintenance|LEO||
+ST-04|b5fceb9b-264c-4842-a329-0a7c4ccc9779|state|Construction||2059-07-12 16:00:00+08:00|2063-01-07 08:00:00+08:00|Construction|LEO|ST-04 Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+ST-04|4dfd3584-ad5c-4d6d-9c86-d337d627fb9e|state|Assembly Complete||2063-01-07 08:00:00+08:00|2063-02-12 08:00:00+08:00|Assembly Complete|LEO|Assembly complete, preparing for commissioning|Timeline.xlsx inferred monthly phase. Raw: Assembly Complete
+ST-04|93f7700f-d0be-48a9-8fdf-f1d0a824ac86|state|Trial Run||2063-02-12 08:00:00+08:00|2063-09-06 08:00:00+08:00|Trial Run|Lunar Orbit|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+ST-04|c6ac0899-e235-4de6-8a9e-89ff98e725fa|state|Maintenance||2063-09-06 16:00:00+08:00||Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+XH-01 ˺|1934e3f4-0d0c-4699-b4bd-753744ab29a1|state|Construction||2050-03-16 00:00:00+08:00|2052-02-07 00:00:00+08:00|Construction|LEO|Xihe XH-01 Construction|2050-03-15 First module delivered to LEO via Vulture Shuttle
+2052-02-06 Assembly completed in LEO
+XH-01 ˺|a0a3bed9-91a2-45c7-be54-7216e33f87b3|state|Fitting||2052-02-07 08:00:00+08:00|2052-05-31 08:00:00+08:00|Fitting|LEO||
+XH-01 ˺|8ee54d7e-4310-43dc-a703-f633c1013405|state|Trial Run||2052-06-01 08:00:00+08:00|2052-11-30 08:00:00+08:00|Trial Run|Earth|Trial Run before commissioning|2052-06-01 Begin Trial Run in Earth Orbit, testing all systems
+2052-11-30 Trial Run complete, all systems perform as expected. Including multiple run to GEO and Lunar Orbit before returning to LEO.
+XH-01 ˺|4464a892-910e-416c-b044-0683b6516003|state|Maintenance||2052-12-01 08:00:00+08:00|2053-01-05 08:00:00+08:00|Maintenance|Earth||
+XH-01 ˺|d103bc92-da3a-4ba6-965e-a9385e208581|state|Deep Space Test Mission||2053-01-12 08:00:00+08:00|2053-12-18 08:00:00+08:00|Deep Space Test Mission|Earth-Sun L2|Long term uncrewed test|2053-01-12 Uncrewed mission to Earth-Sun L2 point to test deep space operations
+2053-12-18 Back to LEO
+XH-01 ˺|80931042-da68-435b-94f5-da2d1b79e801|state|Maintenance and Upgrades||2054-01-07 08:00:00+08:00|2054-06-28 08:00:00+08:00|Maintenance and Upgrades|LEO||
+XH-01 ˺|e54817e0-6809-404d-be62-c6017d143362|state|MMD Outbound|Mars Mission Demo|2054-07-10 08:00:00+08:00|2054-08-21 08:00:00+08:00|Transfer|Sun|Earth-Mars transfer, Uses standard trajectory with 102km/s of departure burn|
+XH-01 ˺|23b4304f-8fca-4d78-8a93-c9f78fab51e0|state|MMD Mars Operations|Mars Mission Demo|2054-08-21 08:00:00+08:00|2055-01-10 08:00:00+08:00|Planetary Operations|Mars|Uncrewed, Deliver the first Mars-One base construction equipment package to Mars orbit.|2054-08-21 Mars Orbit Arrival, deploy equipment package to Mars surface via lander
+2055-01-10 Mars Departure, return to Earth
+XH-01 ˺|ded06cd6-f9a4-4646-9be4-2f01cf067334|state|MMD Inbound|Mars Mission Demo|2055-01-10 08:00:00+08:00|2055-02-28 08:00:00+08:00|Transfer|Sun|Uses standard trajectory with 97km/s of departure burn|2055-02-28 Earth Arrival, demo run complete, all systems perform as expected.
+XH-01 ˺|fecc4450-ba77-4bc6-b794-164766a0c8b8|state|Maintenance and Upgrades||2055-03-01 08:00:00+08:00|2055-05-14 08:00:00+08:00|Maintenance and Upgrades|LEO||
+XH-01 ˺|aab3125c-c99e-4af5-ab64-ffe7fda48ad7|state|MOCM-1 Outbound|Mars One Base Construction Mission 1|2055-06-15 08:00:00+08:00|2055-07-30 08:00:00+08:00|Transfer|Sun|Earth-Mars transfer, Uses standard trajectory with 115km/s of departure burn|2055-06-15 Picking up crew for Mars One base Construction Mission 1
+2055-06-18 Earth Departure for Mars
+XH-01 ˺|ec34d68b-4728-42eb-af79-b3e8805aa253|state|MOCM-1 Mars Operations|Mars One Base Construction Mission 1|2055-07-30 08:00:00+08:00|2056-02-07 08:00:00+08:00|Base Construction|Mars|First Crewed mission to Mars. Construction for Mars One base begin|2055-07-30 Mars Arrival, begin base construction
+2056-02-07 Mars Departure, return to Earth. First to use quick return trajectory.
+XH-01 ˺|bdf99335-d329-4bd2-8e17-27ac1f097ca9|state|MOCM-1 Inbound|Mars One Base Construction Mission 1|2056-02-07 08:00:00+08:00|2056-03-18 08:00:00+08:00|Transfer|Sun|Mars-Earth transfer. Uses Fast-travel trajectory with 207km/s of departure burn|2056-03-18 Earth Arrival, crew return
+XH-01 ˺|8e1be891-57ec-4551-b114-232f4681b2b1|state|Maintenance and Upgrades||2056-03-25 08:00:00+08:00|2056-06-20 08:00:00+08:00|Maintenance and Upgrades|LEO||
+XH-01 ˺|ea2024c5-95e6-4acc-a88d-998183a35a5a|state|MOCM-3 Outbound|Mars One Base Construction Mission 3|2056-07-30 08:00:00+08:00|2056-09-15 08:00:00+08:00|Transfer|Sun|Earth-Mars transfer. Uses standard trajectory with 95km/s of departure burn|2056-07-30 Picking up crew for Mars One base Construction Mission 3
+2056-08-02 Earth Departure for Mars
+XH-01 ˺|fd22c4b2-4938-4c01-ae92-e84f14d8b8dd|state|MOCM-3 Operations|Mars One Base Construction Mission 3|2056-09-15 08:00:00+08:00|2057-02-12 08:00:00+08:00|Base Construction|Mars|Third Mars One base construction. First crew hand-off on Mars(with Mars One base construction 2).|2056-09-15 Mars Arrival, continue base construction
+2057-02-12 Mars Departure, return to Earth.
+XH-01 ˺|e5f549b9-0446-48be-a606-d9c1ada664b7|state|MOCM-3 Inbound|Mars One Base Construction Mission 3|2057-02-12 08:00:00+08:00|2057-03-25 08:00:00+08:00|Transfer|Sun|Mars-Earth transfer. Uses standard trajectory with 122km/s of departure burn|2037-03-25 Earth Arrivasl, crew return
+XH-01 ˺|6d57910a-7459-4b74-b0ea-e10ee7cab87b|state|Maintenance||2057-03-26 08:00:00+08:00|2057-04-25 08:00:00+08:00|Maintenance|LEO||
+XH-01 ˺|30c84287-e5d1-473c-93fb-9d36d426516e|state|ME-2 Outbound|Mars Expedition 2|2057-05-05 08:00:00+08:00|2057-06-22 08:00:00+08:00|Transfer|Sun|Earth-Mars transfer using standard trajectory with 110km/s of departure burn|2027-05-05 Picking up crew for Mars Expedition 2
+2027-05-09 Earth Departure for Mars
+XH-01 ˺|7f5da9b3-94fa-4bd5-a6bd-94f6841c71a2|state|ME-2 Mars Operations|Mars Expedition 2|2057-06-22 08:00:00+08:00|2058-04-18 08:00:00+08:00|Planetary Operations|Mars|Second long term Mars Expedition, first mission to Mars One base after the construction is completed.
+First mission involving space tourism to Mars.|2057-06-22 Mars Arrival
+2057-06-25 Mars EDL and surface operations begin
+2058-04-10 Begin Mars Departure preparations
+2058-04-18 Mars Departure for Earth
+XH-01 ˺|058bbf6d-5c51-49c4-8516-8b6931db53c1|state|ME-2 Inbound|Mars Expedition 2|2058-04-18 08:00:00+08:00|2058-05-20 08:00:00+08:00|Transfer|Sun|Mars-Earth transfer using standard trajectory with 115km/s of departure burn|2058-04-18 Mars Departure for Earth
+2058-05-20 Earth Arrival, crew return
+XH-01 ˺|161bb9f0-3d2a-46da-9044-9184e0704413|state|Maintenance||2058-05-21 08:00:00+08:00|2058-06-18 08:00:00+08:00|Maintenance|LEO||
+XH-01 ˺|4ff368c4-503b-42ce-9e82-b4da291d3203|state|EE-1 Outbound|Europa Expedition 1|2058-07-10 08:00:00+08:00|2058-09-25 08:00:00+08:00|Transfer|Sun|Earth-Jupiter transfer using standard trajectory with 160km/s of departure burn|2058-07-10 Picking up crew for Europa Expedition 1
+2058-07-12 Earth Departure for Jupiter system
+2058-09-25 Europa Arrival
+XH-01 ˺|f01bfb99-f981-45f6-808b-7c5222503715|state|EE-1 Jupiter System Operations|Europa Expedition 1|2058-09-25 08:00:00+08:00|2059-07-10 08:00:00+08:00|Planetary Operations|Jupiter System|First standard crew expedition to Europa Outpost to begin exploration of Jupiter system
+Long term surface operation at Europa Outpost, followed by exploration of IO and Ganymede|2058-09-25 Europa Arrival
+2058-09-27 Europa descend, begin surface operation at Europa Outpost
+2058-12-15 Europa ascend, begin Jupiter system exploration
+2058-12-20 Begin IO exploration
+2059-01-20 Return to Europa Outpost
+2059-06-20 Begin Europa Outpost departure preparations
+2059-06-25 Europa Expedition 1 crew ascend from Europa Outpost
+2059-07-05 begin Ganymede exploration
+2059-07-10 Departure for Earth, upgrade planned.
+XH-01 ˺|92315017-7011-4930-aabb-d00a6f3f4994|state|EE-1 Inbound|Europa Expedition 1|2059-07-10 08:00:00+08:00|2059-11-15 08:00:00+08:00|Transfer|Sun|Uses standard trajectory with 112km/s of departure burn
+Parked to Star Port|2059-07-10 Departure for Earth.
+2059-11-15 Earth Arrival, Park to Star Port.
+XH-01 ˺|21a37859-aa16-4c29-b17a-8012f6037478|state|Maintenance and Upgrades||2059-11-16 08:00:00+08:00|2060-02-19 08:00:00+08:00|Maintenance and Upgrades|Star Port|Greenhouse upgrade to support long term deep space missions|
+XH-01 ˺|ee52cc53-7d9c-4134-ba1b-4f7cfb8fdce9|state|EE-3 Outbound|Europa Expedition 3|2060-02-20 08:00:00+08:00|2060-05-01 08:00:00+08:00|Transfer|Sun|Uses standard trajectory with 163km/s of departure burn|2060-02-20 Picking up Europa Expedition 3 crew, On its way to explore Jupiter systems before sending crew to Europa Outpost
+XH-01 ˺|91d4948a-ae04-43a8-ac3b-def9caecc8e5|state|EE-3 Jupiter System Operations|Europa Expedition 3|2060-05-01 08:00:00+08:00||Jupiter Exploration; Outpost Rotation|Jupiter System|Crew Rotation to Euorpa Outpost. First to explore Jupiter's moons, then to Europa Outpost|2060-05-01 Jupiter Arrival
+2060-05-02 Io Arrival
+2060-05-07 Io descend
+2060-05-09 Io departure
+2060-05-11 Ganymede Arrival
+2060-05-12 Ganymede descend
+2060-05-21 Ganymede Departure for Callisto
+2060-05-25 Callisto Arrival
+XH-02 ̫|4958ffd7-2e23-40a6-9b96-e46c61943028|state|Construction||2054-12-11 08:00:00+08:00|2056-10-04 08:00:00+08:00|Construction|LEO|XH-02 ̫ Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+XH-02 ̫|b99a2638-7560-45ec-9328-6a4a0e4cf685|state|Assembly Complete||2056-10-04 08:00:00+08:00|2056-11-11 08:00:00+08:00|Assembly Complete|LEO|Assembly complete, preparing for commissioning|Timeline.xlsx inferred monthly phase. Raw: Assembly Complete
+XH-02 ̫|6ec7033c-e711-4148-ab7d-e075f3288021|state|Trial Run||2056-11-11 08:00:00+08:00|2057-03-12 08:00:00+08:00|Trial Run|Earth|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+XH-02 ̫|669a993c-fe3d-4126-b066-2650e98dfb3e|state|Maintenance||2057-03-12 08:00:00+08:00|2057-04-25 08:00:00+08:00|Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+XH-02 ̫|7c166ff7-df3b-495d-a7df-9b99949e23f0|state|AEM Outbound|Asteroid Exploration Mission|2057-05-04 08:00:00+08:00|2057-07-17 08:00:00+08:00|Transfer|Sun|Earth-Vesta transfer|Timeline.xlsx inferred monthly phase. Raw: Earth-Vesta
+XH-02 ̫|99eb75ba-e02b-4cdc-a5f1-3ea547cc7d4a|state|AEM Vesta Operations|Asteroid Exploration Mission|2057-07-17 08:00:00+08:00|2058-01-04 08:00:00+08:00|Asteroid Operations|Vesta|Asteroid exploration mission at Vesta|Timeline.xlsx inferred monthly phase. Raw: Vesta Mission
+XH-02 ̫|d74dfb61-fd3a-492c-b019-253ec9cd826d|state|AEM Inbound|Asteroid Exploration Mission|2058-01-04 08:00:00+08:00|2058-04-17 08:00:00+08:00|Transfer|Sun|Vesta-Earth transfer|Timeline.xlsx inferred monthly phase. Raw: Vesta-Earth
+XH-02 ̫|956cc319-668e-45d1-ab7c-9f0aa408c5f7|state|ME-3 Mars Operations|Mars Expedition 3|2058-04-17 08:00:00+08:00|2059-05-04 08:00:00+08:00|Planetary Operations|Mars|Mars Expedition 3|Timeline.xlsx inferred monthly phase. Raw: Mars Expedition 3
+XH-02 ̫|f43aa249-80d1-426c-9aca-a341411be98d|state|Uncrewed Inbound|Mars Expedition 3|2059-05-04 08:00:00+08:00|2059-07-06 08:00:00+08:00|Transfer|Sun|Uncrewed Inbound for TH-02. Mars Expedition 3 Crew remaining on Mars|
+XH-02 ̫|2ae7438b-a2a2-44ee-a084-a76bc1e94114|state|Maintenance||2059-07-06 08:00:00+08:00|2059-08-04 08:00:00+08:00|Maintenance|Star Port||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+XH-02 ̫|fcb05995-823e-4a63-9cf8-44ea953e2e9a|state|ME-4 Outbound|Mars Expedition 4|2059-08-04 08:00:00+08:00|2059-10-24 08:00:00+08:00|Transfer|Sun|Earth-Mars transfer|Carrying Mars Expedition 4 crew and Mars One Expansion Package to Mars
+XH-02 ̫|c00366fd-6b1d-46e0-8163-4bd6b510f374|state|ME-4 Mars Operations Part 1|Mars Expedition 4|2059-10-24 14:00:00+08:00|2059-11-04 08:00:00+08:00|Planetary Operations|Mars|ME-4 Crew to Mars One with Mars One Expansion Package. Mars Expedition 3 ascend.|
+XH-02 ̫|33a45210-3497-4826-ba6e-291b384ebe7e|state|ME-3 Inbound|Mars Expedition 3|2059-11-04 08:00:00+08:00|2060-01-06 08:00:00+08:00|Transfer|Sun|Carrying ME-3 Crew home|
+XH-02 ̫|5562aa60-8d62-4ed9-b1cc-51ff99c49d18|state|Maintenance||2060-01-06 08:00:00+08:00|2060-02-17 08:00:00+08:00|Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+XH-02 ̫|76cd99ba-c259-4969-a8ae-2fa14e303974|state|Uncrewed Outbound|Mars Expedition 4|2060-01-22 08:00:00+08:00|2060-02-27 08:00:00+08:00|Transfer|Sun||
+XH-02 ̫|c7e777fd-c7d8-4d01-be07-871862829983|state|ME-4 Mars Operations Part 2|Mars Expedition 4|2060-02-28 08:00:00+08:00|2060-10-30 08:00:00+08:00|Planetary Operations|Mars|Uncrewed Mars mission segment|Timeline.xlsx inferred monthly phase. Raw: Uncrewed to Mars, Mars Expedition 4 Part 2
+XH-03 |505255ab-902e-4586-9905-8ecad10353e7|state|Construction||2058-02-15 16:00:00+08:00|2059-12-09 08:00:00+08:00|Construction|LEO|XH-03 Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+XH-03 |b0848762-4f30-45fa-9e5f-5e53a0a7aba3|state|Assembly Complete||2059-12-09 08:00:00+08:00|2060-01-14 08:00:00+08:00|Assembly Complete|LEO|Assembly complete, preparing for commissioning|Timeline.xlsx inferred monthly phase. Raw: Assembly Complete
+XH-03 |b87ea1ef-b240-48f7-aba8-0af7566bd6be|state|Trial Run||2060-01-14 08:00:00+08:00|2060-06-09 08:00:00+08:00|Trial Run|Earth|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+XH-03 |bdc91489-7c65-45c2-bd78-4a37edc9dd4e|state|Maintenance||2060-06-09 08:00:00+08:00||Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+XH-04|86055939-185d-476b-afc5-1a60a69a1ccb|state|Construction||2059-09-16 16:00:00+08:00|2061-08-10 08:00:00+08:00|Construction|LEO|XH-04 Construction|Timeline.xlsx inferred monthly phase. Raw: Construction
+XH-04|d9b91820-7ea9-4f79-bca6-1fd450862c17|state|Assembly Complete||2061-08-10 08:00:00+08:00|2061-09-15 08:00:00+08:00|Assembly Complete|LEO|Assembly complete, preparing for commissioning|Timeline.xlsx inferred monthly phase. Raw: Assembly Complete
+XH-04|952a415e-408b-42a4-8dd8-24940e745d65|state|Trial Run||2061-09-15 08:00:00+08:00|2062-02-10 08:00:00+08:00|Trial Run|Earth|Trial Run before commissioning|Timeline.xlsx inferred monthly phase. Raw: Trial Run
+XH-04|85aa5084-4c7a-4863-8bcc-ee9238d95d2c|state|Maintenance||2062-02-10 08:00:00+08:00||Maintenance|LEO||Timeline.xlsx inferred monthly phase. Raw: Maintenance
+ռվ|00aec49b-6dc1-4b58-bbf1-96086b93ff0e|state|Expedition 11|Expedition 11|2059-05-04 01:02:00+08:00|2059-11-16 20:55:00+08:00|Standard Rotation|LEO||
+ռվ|1c346955-ba6b-4f54-9308-d088fa99f766|state|Expedition 12|Expedition 12|2059-11-16 16:00:00+08:00|2060-05-15 01:44:00+08:00|Standard Rotation|LEO||
+ռվ|7c74d703-98bc-486d-b06f-591f38661181|state|Expedition 13|Expedition 13|2060-05-12 15:40:00+08:00|2060-11-12 15:40:00+08:00|Standard Rotation|LEO||
+ռվ|3c81a7b5-4f86-4f48-aa6f-99dec955dc42|event|Reconfigure to ռվ|˺ƻ|2060-07-06 17:15:00+08:00|||LEO|пռվֵлʩռվ|
+ռվ|4d14317f-3e78-4e9e-9a9c-a9555ef15b24|state|ռվģ|˺ƻ|2060-07-06 20:40:00+08:00|2060-09-15 20:55:00+08:00|ռվģ|LEO|E3䣬ȫµĽڵպ˹ģ飬Expedition 13ɰװ|
diff --git a/demo/asset_detail_v2.png b/demo/asset_detail_v2.png
new file mode 100644
index 0000000..8d9c8bc
Binary files /dev/null and b/demo/asset_detail_v2.png differ
diff --git a/demo/asset_hifi_server.err b/demo/asset_hifi_server.err
new file mode 100644
index 0000000..e69de29
diff --git a/demo/asset_hifi_server.out b/demo/asset_hifi_server.out
new file mode 100644
index 0000000..e69de29
diff --git a/demo/dock_modal.png b/demo/dock_modal.png
new file mode 100644
index 0000000..ba72ee6
Binary files /dev/null and b/demo/dock_modal.png differ
diff --git a/demo/e2e_1.png b/demo/e2e_1.png
new file mode 100644
index 0000000..b1a9214
Binary files /dev/null and b/demo/e2e_1.png differ
diff --git a/demo/e2e_1_stardock.png b/demo/e2e_1_stardock.png
new file mode 100644
index 0000000..1b7f6cb
Binary files /dev/null and b/demo/e2e_1_stardock.png differ
diff --git a/demo/e2e_2.png b/demo/e2e_2.png
new file mode 100644
index 0000000..6e1533b
Binary files /dev/null and b/demo/e2e_2.png differ
diff --git a/demo/e2e_3.png b/demo/e2e_3.png
new file mode 100644
index 0000000..9b32590
Binary files /dev/null and b/demo/e2e_3.png differ
diff --git a/demo/e2e_3_undock_target.png b/demo/e2e_3_undock_target.png
new file mode 100644
index 0000000..fb169bb
Binary files /dev/null and b/demo/e2e_3_undock_target.png differ
diff --git a/demo/e2e_4.png b/demo/e2e_4.png
new file mode 100644
index 0000000..4186bca
Binary files /dev/null and b/demo/e2e_4.png differ
diff --git a/demo/e2e_5.png b/demo/e2e_5.png
new file mode 100644
index 0000000..b83b505
Binary files /dev/null and b/demo/e2e_5.png differ
diff --git a/demo/e2e_6.png b/demo/e2e_6.png
new file mode 100644
index 0000000..1884769
Binary files /dev/null and b/demo/e2e_6.png differ
diff --git a/demo/final_comms.png b/demo/final_comms.png
new file mode 100644
index 0000000..3f84217
Binary files /dev/null and b/demo/final_comms.png differ
diff --git a/demo/final_converter.png b/demo/final_converter.png
new file mode 100644
index 0000000..b89c60d
Binary files /dev/null and b/demo/final_converter.png differ
diff --git a/demo/final_dark.png b/demo/final_dark.png
new file mode 100644
index 0000000..1ce9a94
Binary files /dev/null and b/demo/final_dark.png differ
diff --git a/demo/final_dark2.png b/demo/final_dark2.png
new file mode 100644
index 0000000..1ce9a94
Binary files /dev/null and b/demo/final_dark2.png differ
diff --git a/demo/final_dark_ok.png b/demo/final_dark_ok.png
new file mode 100644
index 0000000..d2206ed
Binary files /dev/null and b/demo/final_dark_ok.png differ
diff --git a/demo/final_engines.png b/demo/final_engines.png
new file mode 100644
index 0000000..a8021df
Binary files /dev/null and b/demo/final_engines.png differ
diff --git a/demo/final_light2.png b/demo/final_light2.png
new file mode 100644
index 0000000..82d6a31
Binary files /dev/null and b/demo/final_light2.png differ
diff --git a/demo/final_light_ok.png b/demo/final_light_ok.png
new file mode 100644
index 0000000..1ce9a94
Binary files /dev/null and b/demo/final_light_ok.png differ
diff --git a/demo/final_overview.png b/demo/final_overview.png
new file mode 100644
index 0000000..1ce9a94
Binary files /dev/null and b/demo/final_overview.png differ
diff --git a/demo/final_tanks.png b/demo/final_tanks.png
new file mode 100644
index 0000000..ca3b702
Binary files /dev/null and b/demo/final_tanks.png differ
diff --git a/demo/final_vehicles.png b/demo/final_vehicles.png
new file mode 100644
index 0000000..eb3c176
Binary files /dev/null and b/demo/final_vehicles.png differ
diff --git a/demo/hifi3_assets.png b/demo/hifi3_assets.png
new file mode 100644
index 0000000..f7908aa
Binary files /dev/null and b/demo/hifi3_assets.png differ
diff --git a/demo/hifi3_engines.png b/demo/hifi3_engines.png
new file mode 100644
index 0000000..8c70bfe
Binary files /dev/null and b/demo/hifi3_engines.png differ
diff --git a/demo/hifi3_light.png b/demo/hifi3_light.png
new file mode 100644
index 0000000..f5c6088
Binary files /dev/null and b/demo/hifi3_light.png differ
diff --git a/demo/hifi3_location.png b/demo/hifi3_location.png
new file mode 100644
index 0000000..4b262a2
Binary files /dev/null and b/demo/hifi3_location.png differ
diff --git a/demo/hifi3_location2.png b/demo/hifi3_location2.png
new file mode 100644
index 0000000..f6c9d12
Binary files /dev/null and b/demo/hifi3_location2.png differ
diff --git a/demo/hifi3_overview.png b/demo/hifi3_overview.png
new file mode 100644
index 0000000..a1a4b25
Binary files /dev/null and b/demo/hifi3_overview.png differ
diff --git a/demo/hifi3_timeline.png b/demo/hifi3_timeline.png
new file mode 100644
index 0000000..c088fb8
Binary files /dev/null and b/demo/hifi3_timeline.png differ
diff --git a/demo/hifi5_asset_detail.png b/demo/hifi5_asset_detail.png
new file mode 100644
index 0000000..e7d1759
Binary files /dev/null and b/demo/hifi5_asset_detail.png differ
diff --git a/demo/hifi5_location.png b/demo/hifi5_location.png
new file mode 100644
index 0000000..9a66b22
Binary files /dev/null and b/demo/hifi5_location.png differ
diff --git a/demo/hifi5_overview.png b/demo/hifi5_overview.png
new file mode 100644
index 0000000..e195c7f
Binary files /dev/null and b/demo/hifi5_overview.png differ
diff --git a/demo/hifi5_timeline.png b/demo/hifi5_timeline.png
new file mode 100644
index 0000000..dd68496
Binary files /dev/null and b/demo/hifi5_timeline.png differ
diff --git a/demo/hifi6_detail_docked.png b/demo/hifi6_detail_docked.png
new file mode 100644
index 0000000..a0c7194
Binary files /dev/null and b/demo/hifi6_detail_docked.png differ
diff --git a/demo/hifi6_detail_target.png b/demo/hifi6_detail_target.png
new file mode 100644
index 0000000..865590d
Binary files /dev/null and b/demo/hifi6_detail_target.png differ
diff --git a/demo/hifi7_stardock.png b/demo/hifi7_stardock.png
new file mode 100644
index 0000000..1b7f6cb
Binary files /dev/null and b/demo/hifi7_stardock.png differ
diff --git a/demo/hifi7_xh02.png b/demo/hifi7_xh02.png
new file mode 100644
index 0000000..af9c847
Binary files /dev/null and b/demo/hifi7_xh02.png differ
diff --git a/demo/hifi_dark.png b/demo/hifi_dark.png
new file mode 100644
index 0000000..d9718f8
Binary files /dev/null and b/demo/hifi_dark.png differ
diff --git a/demo/hifi_light.png b/demo/hifi_light.png
new file mode 100644
index 0000000..4c7fe71
Binary files /dev/null and b/demo/hifi_light.png differ
diff --git a/demo/hifi_v1.png b/demo/hifi_v1.png
new file mode 100644
index 0000000..fd6a806
Binary files /dev/null and b/demo/hifi_v1.png differ
diff --git a/demo/io_test.png b/demo/io_test.png
new file mode 100644
index 0000000..1c13f34
Binary files /dev/null and b/demo/io_test.png differ
diff --git a/demo/ksp_admin_hifi.html b/demo/ksp_admin_hifi.html
new file mode 100644
index 0000000..ca70cb3
--- /dev/null
+++ b/demo/ksp_admin_hifi.html
@@ -0,0 +1,734 @@
+
+
+
+
+KSP管理后台
+
+
+
+
+
KSP 管理后台
+
+
Sim Time 2060-08-11 10:00
+
−1d +1d +7d Today
+
◐
+
+
+
+
+◉ 任务总览
+▾ 任务运营
+
+▾ 数据中心
+
+⇄ 燃料换算
+
+
+
+
+
+
Mission Operations
任务总览 Simulation: · All metrics derived from asset logs
+
+
Status Board
+
Upcoming Events
+
+
+
+
+
+
All Types Exploration Mothership Space Shuttle Station Base Cargo Ship All Locations Earth System Mars System Jupiter System Transfer Hide retired
+
+Name
+Type
+Location
+Current Event Entries Action
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Docked Vehicles
++ Dock
+
+
+
+
+
+
+
+
Log Entries
+
++ State Interval
++ Event Point
+
+
+
All Types State Interval Event Point
+
Date Type Title State Location Action
+
+
+
+
+
Upcoming Events
+
+
+
Quick Info
+
+
Retired: No
+
Created: —
+
Updated: —
+
+
+
+
+
+
+
+
+
All Locations Earth System Mars System Jupiter System Transfer
+
+
+
+
+
+
+
+
+
+Active
+This Month
+Next 90d
+All
+
+
+Scale:
+Year Month Day
+
+
+
+
+
Type: All Exploration Mothership Space Shuttle Station Base Cargo Ship
+
Location: All Earth System Mars System Jupiter System Transfer
+
State: All Transfer Exploration Maintenance Docked
+
+From:
+To:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
All Fuel LF/O Nuclear Electric
+
Name Cycle Mass Vac Thrust Vac ISP Fuel Mod Action
+
+
+
+
+
+
Name Range Mass Type Source Action
+
+
+
+
+
+
Name Volume Dry Mass Fuel Source Action
+
+
+
+
+
+
Name Launch Cost Source Action
+
+
+
+
+
+
+
+
+
+New Entry
Delete Cancel Save
+
+
+
+
+
+
diff --git a/demo/location_board_demo.html b/demo/location_board_demo.html
new file mode 100644
index 0000000..3cbee2d
--- /dev/null
+++ b/demo/location_board_demo.html
@@ -0,0 +1,420 @@
+
+
+
+
+KSP管理后台 — Location Board
+
+
+
+
+
+
KSP 管理后台
+
/
+
Solar System
+
+
+ ◀◀
+ ◀
+
+ ▶
+ ▶▶
+ Today
+
+
+
+
+
+
+
← Back
+
Solar System
+
+ Flat
+ Realistic
+
+
click planet to focus · drag to pan · scroll to zoom
+
+
+
+
+
+
+
+
diff --git a/demo/migration_location.png b/demo/migration_location.png
new file mode 100644
index 0000000..f17a259
Binary files /dev/null and b/demo/migration_location.png differ
diff --git a/demo/migration_overview.png b/demo/migration_overview.png
new file mode 100644
index 0000000..1ce9a94
Binary files /dev/null and b/demo/migration_overview.png differ
diff --git a/demo/migration_test.png b/demo/migration_test.png
new file mode 100644
index 0000000..a0c4b3c
Binary files /dev/null and b/demo/migration_test.png differ
diff --git a/demo/new_log_modal.png b/demo/new_log_modal.png
new file mode 100644
index 0000000..1e5f243
Binary files /dev/null and b/demo/new_log_modal.png differ
diff --git a/demo/new_log_nodes.png b/demo/new_log_nodes.png
new file mode 100644
index 0000000..f911d97
Binary files /dev/null and b/demo/new_log_nodes.png differ
diff --git a/demo/post_click.png b/demo/post_click.png
new file mode 100644
index 0000000..fcdbd3c
Binary files /dev/null and b/demo/post_click.png differ
diff --git a/demo/pre_click.png b/demo/pre_click.png
new file mode 100644
index 0000000..84c97f1
Binary files /dev/null and b/demo/pre_click.png differ
diff --git a/demo/shot_io_single.png b/demo/shot_io_single.png
new file mode 100644
index 0000000..bf3fd8d
Binary files /dev/null and b/demo/shot_io_single.png differ
diff --git a/demo/shot_jupiter_system.png b/demo/shot_jupiter_system.png
new file mode 100644
index 0000000..e718719
Binary files /dev/null and b/demo/shot_jupiter_system.png differ
diff --git a/demo/shot_solar_flat.png b/demo/shot_solar_flat.png
new file mode 100644
index 0000000..7ceb0b1
Binary files /dev/null and b/demo/shot_solar_flat.png differ
diff --git a/demo/shot_solar_realistic.png b/demo/shot_solar_realistic.png
new file mode 100644
index 0000000..362e24e
Binary files /dev/null and b/demo/shot_solar_realistic.png differ
diff --git a/demo/sidebar_check.png b/demo/sidebar_check.png
new file mode 100644
index 0000000..d2206ed
Binary files /dev/null and b/demo/sidebar_check.png differ
diff --git a/demo/sidebar_final.png b/demo/sidebar_final.png
new file mode 100644
index 0000000..807acc6
Binary files /dev/null and b/demo/sidebar_final.png differ
diff --git a/demo/sidebar_v2.png b/demo/sidebar_v2.png
new file mode 100644
index 0000000..30ed259
Binary files /dev/null and b/demo/sidebar_v2.png differ
diff --git a/demo/test_click.py b/demo/test_click.py
new file mode 100644
index 0000000..d8b2684
--- /dev/null
+++ b/demo/test_click.py
@@ -0,0 +1,140 @@
+"""Test the location board demo click functionality using Playwright."""
+import asyncio
+from pathlib import Path
+from playwright.async_api import async_playwright
+
+DEMO_PATH = Path(__file__).resolve().parent / "location_board_demo.html"
+FILE_URL = f"file:///{DEMO_PATH.as_posix()}"
+
+
+async def main():
+ async with async_playwright() as p:
+ browser = await p.chromium.launch(headless=True)
+ page = await browser.new_page(viewport={"width": 1400, "height": 900})
+ await page.goto(FILE_URL, wait_until="commit", timeout=10000)
+ await page.wait_for_timeout(3000) # let canvas render (skip font loading)
+
+ # --- Test 1: Check initial state ---
+ scope = await page.text_content("#scope-indicator")
+ print(f"Test 1 - Initial scope: {scope}")
+
+ # --- Test 2: Get canvas bounding box and try clicking a planet ---
+ canvas = page.locator("#map-canvas")
+ box = await canvas.bounding_box()
+ if not box:
+ print("ERROR: Canvas not found!")
+ await browser.close()
+ return
+
+ print(f"Canvas: x={box['x']:.0f} y={box['y']:.0f} w={box['width']:.0f} h={box['height']:.0f}")
+
+ # The solar system view has the sun at center of canvas
+ # Planets orbit around it. Let's log JS state to see where bodies are.
+ body_positions = await page.evaluate("""
+ () => {
+ const result = [];
+ const keys = ['sun','mercury','venus','earth','mars','jupiter','saturn','uranus','neptune','pluto'];
+ for (const k of keys) {
+ const b = BD[k];
+ if (b) result.push({
+ key: k,
+ name: b.n,
+ sx: b._x,
+ sy: b._y,
+ r: b.r,
+ hasMoons: (b.moons && typeof b.moons==='object') ? Object.keys(b.moons).join(',') : 'none'
+ });
+ }
+ return result;
+ }
+ """)
+ print("\nBody positions (CSS pixels from canvas top-left):")
+ for bp in body_positions:
+ sx = bp['sx']
+ sy = bp['sy']
+ if sx is not None and sy is not None:
+ # Convert to page coordinates (add canvas offset)
+ px = sx + box['x']
+ py = sy + box['y']
+ print(f" {bp['name']:12s} screen=({sx:6.1f},{sy:6.1f}) page=({px:6.1f},{py:6.1f}) r={bp['r']} moons={bp['hasMoons']}")
+ else:
+ print(f" {bp['name']:12s} screen=(undefined) - NOT RENDERED")
+
+ # --- Test 3: Try clicking Jupiter ---
+ jupiter = [b for b in body_positions if b['key'] == 'jupiter']
+ if jupiter and jupiter[0]['sx'] is not None:
+ jx = jupiter[0]['sx'] + box['x']
+ jy = jupiter[0]['sy'] + box['y']
+ jr = jupiter[0]['r'] + 5 # hit radius
+ print(f"\nTest 3 - Clicking Jupiter at page ({jx:.0f}, {jy:.0f}) r={jr}")
+
+ # Take pre-click screenshot
+ await page.screenshot(path=str(DEMO_PATH.parent / "pre_click.png"))
+ print(" Screenshot: pre_click.png")
+
+ # Click
+ await page.mouse.click(jx, jy)
+ await page.wait_for_timeout(500)
+
+ scope_after = await page.text_content("#scope-indicator")
+ back_visible = await page.evaluate("() => document.getElementById('back-btn').classList.contains('visible')")
+ print(f" After click - scope: {scope_after}")
+ print(f" Back button visible: {back_visible}")
+ print(f" View stack: {await page.evaluate('() => JSON.stringify(viewStack)')}")
+
+ await page.screenshot(path=str(DEMO_PATH.parent / "post_click.png"))
+ print(" Screenshot: post_click.png")
+ else:
+ print("\nTest 3 - Jupiter not found in rendered bodies!")
+
+ # --- Test 4: Check JS console for errors ---
+ console_msgs = []
+ page.on("console", lambda msg: console_msgs.append(f"[{msg.type}] {msg.text}"))
+ # Trigger a re-render
+ await page.evaluate("() => { render(); }")
+ await page.wait_for_timeout(300)
+ errors = [m for m in console_msgs if 'error' in m.lower() or 'Error' in m]
+ if errors:
+ print(f"\nJS errors: {errors}")
+ else:
+ print("\nNo JS errors detected")
+
+ # --- Test 5: Check didDrag state and event flow ---
+ print("\n--- Event Debug ---")
+ # Inject debug listener
+ await page.evaluate("""
+ () => {
+ const canvas = document.getElementById('map-canvas');
+ canvas.addEventListener('click', (e) => {
+ console.log('CLICK on canvas at', e.clientX, e.clientY, 'didDrag=', window._didDrag || didDrag);
+ }, true); // capture phase
+
+ // Store for inspection
+ window._debugClick = (x, y) => {
+ const r = canvas.getBoundingClientRect();
+ const t = hitTest(x - r.left, y - r.top);
+ console.log('hitTest result:', t, 'didDrag=', didDrag, 'dragOn=', dragOn);
+ return t;
+ };
+ }
+ """)
+
+ # Try click with explicit coordinates
+ if jupiter and jupiter[0]['sx'] is not None:
+ result = await page.evaluate(f"() => window._debugClick({jx - box['x']}, {jy - box['y']})")
+ print(f"hitTest at Jupiter position result: {result}")
+
+ # Also try clicking center of canvas minus offset
+ cx = box['width'] / 2
+ cy = box['height'] / 2
+ for offset_y in [0, -20, -50, -100, 50, 100]:
+ test_x = cx
+ test_y = cy + offset_y
+ r = await page.evaluate(f"() => window._debugClick({test_x}, {test_y})")
+ print(f" hitTest at canvas({test_x:.0f}, {test_y:.0f}): {r}")
+
+ await browser.close()
+
+
+if __name__ == "__main__":
+ asyncio.run(main())
diff --git a/demo/test_edit_log.png b/demo/test_edit_log.png
new file mode 100644
index 0000000..9b9bf5b
Binary files /dev/null and b/demo/test_edit_log.png differ
diff --git a/demo/test_edit_nodes.png b/demo/test_edit_nodes.png
new file mode 100644
index 0000000..2cc6365
Binary files /dev/null and b/demo/test_edit_nodes.png differ
diff --git a/demo/test_edit_page.png b/demo/test_edit_page.png
new file mode 100644
index 0000000..aeca6dd
Binary files /dev/null and b/demo/test_edit_page.png differ
diff --git a/demo/test_edit_v2.png b/demo/test_edit_v2.png
new file mode 100644
index 0000000..886db97
Binary files /dev/null and b/demo/test_edit_v2.png differ
diff --git a/demo/test_screenshots/asset_mission_label.png b/demo/test_screenshots/asset_mission_label.png
new file mode 100644
index 0000000..2e63e39
Binary files /dev/null and b/demo/test_screenshots/asset_mission_label.png differ
diff --git a/demo/test_screenshots/child_before.png b/demo/test_screenshots/child_before.png
new file mode 100644
index 0000000..fea66f2
Binary files /dev/null and b/demo/test_screenshots/child_before.png differ
diff --git a/demo/test_screenshots/child_undock_result.png b/demo/test_screenshots/child_undock_result.png
new file mode 100644
index 0000000..6601f33
Binary files /dev/null and b/demo/test_screenshots/child_undock_result.png differ
diff --git a/demo/test_screenshots/clean_dock.png b/demo/test_screenshots/clean_dock.png
new file mode 100644
index 0000000..a66eea2
Binary files /dev/null and b/demo/test_screenshots/clean_dock.png differ
diff --git a/demo/test_screenshots/clean_undock.png b/demo/test_screenshots/clean_undock.png
new file mode 100644
index 0000000..cc86c28
Binary files /dev/null and b/demo/test_screenshots/clean_undock.png differ
diff --git a/demo/test_screenshots/current_state.png b/demo/test_screenshots/current_state.png
new file mode 100644
index 0000000..2479570
Binary files /dev/null and b/demo/test_screenshots/current_state.png differ
diff --git a/demo/test_screenshots/dock_test.png b/demo/test_screenshots/dock_test.png
new file mode 100644
index 0000000..71eb1da
Binary files /dev/null and b/demo/test_screenshots/dock_test.png differ
diff --git a/demo/test_screenshots/edit_future_result.png b/demo/test_screenshots/edit_future_result.png
new file mode 100644
index 0000000..50736ea
Binary files /dev/null and b/demo/test_screenshots/edit_future_result.png differ
diff --git a/demo/test_screenshots/final_dock.png b/demo/test_screenshots/final_dock.png
new file mode 100644
index 0000000..ea63048
Binary files /dev/null and b/demo/test_screenshots/final_dock.png differ
diff --git a/demo/test_screenshots/final_undock.png b/demo/test_screenshots/final_undock.png
new file mode 100644
index 0000000..b846893
Binary files /dev/null and b/demo/test_screenshots/final_undock.png differ
diff --git a/demo/test_screenshots/future_edit.png b/demo/test_screenshots/future_edit.png
new file mode 100644
index 0000000..95d93e1
Binary files /dev/null and b/demo/test_screenshots/future_edit.png differ
diff --git a/demo/test_screenshots/future_warn.png b/demo/test_screenshots/future_warn.png
new file mode 100644
index 0000000..756847b
Binary files /dev/null and b/demo/test_screenshots/future_warn.png differ
diff --git a/demo/test_screenshots/future_warn_fixed.png b/demo/test_screenshots/future_warn_fixed.png
new file mode 100644
index 0000000..727b47d
Binary files /dev/null and b/demo/test_screenshots/future_warn_fixed.png differ
diff --git a/demo/test_screenshots/locations_fix.png b/demo/test_screenshots/locations_fix.png
new file mode 100644
index 0000000..cd5ae95
Binary files /dev/null and b/demo/test_screenshots/locations_fix.png differ
diff --git a/demo/test_screenshots/no_sim_url.png b/demo/test_screenshots/no_sim_url.png
new file mode 100644
index 0000000..61645d5
Binary files /dev/null and b/demo/test_screenshots/no_sim_url.png differ
diff --git a/demo/test_screenshots/test_report.json b/demo/test_screenshots/test_report.json
new file mode 100644
index 0000000..58f7c96
--- /dev/null
+++ b/demo/test_screenshots/test_report.json
@@ -0,0 +1,212 @@
+{
+ "total": 41,
+ "passed": 41,
+ "failed": 0,
+ "results": [
+ {
+ "name": "1.1 ",
+ "ok": true,
+ "detail": "11 items"
+ },
+ {
+ "name": "1.2 Ĭչ",
+ "ok": true,
+ "detail": "2 expanded"
+ },
+ {
+ "name": "1.3 ǰҳ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.4 Ĭɫģʽ",
+ "ok": true,
+ "detail": "theme=dark"
+ },
+ {
+ "name": "1.5 dzɫģʽ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.6 ɫģʽл",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.7 ģʱʾ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.12 Modal",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.14 Cancelر",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.15 ESCر",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "2.1 ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "2.2 ָ꿨Ƭ",
+ "ok": true,
+ "detail": "3 cards"
+ },
+ {
+ "name": "2.3 ʵ",
+ "ok": true,
+ "detail": "count=14"
+ },
+ {
+ "name": "2.4 ״̬",
+ "ok": true,
+ "detail": "3 groups"
+ },
+ {
+ "name": "2.6 ʲ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "3.1 бȾ",
+ "ok": true,
+ "detail": "14 rows"
+ },
+ {
+ "name": "3.2 ",
+ "ok": true,
+ "detail": "14->1"
+ },
+ {
+ "name": "4.1 Ⱦ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "4.2 ϢƬ",
+ "ok": true,
+ "detail": "4 cards"
+ },
+ {
+ "name": "4.5 ־б",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "5.1 Dockť",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "5.2 Modal",
+ "ok": true,
+ "detail": "15 options"
+ },
+ {
+ "name": "5.6 Cancel",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "6.1 State Interval",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "6.5 Node",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "6.10 Modalر",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "7.1 Canvas",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "7.2 Χ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "8.1 Canvas",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "8.2 ̶",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "8.3 ",
+ "ok": true,
+ "detail": "116 segments"
+ },
+ {
+ "name": "8.4 ¼",
+ "ok": true,
+ "detail": "238 events"
+ },
+ {
+ "name": "8.5 ʲ",
+ "ok": true,
+ "detail": "14 links"
+ },
+ {
+ "name": "8.6 JSON",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "8.7 ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "9.engines",
+ "ok": true,
+ "detail": "30 rows"
+ },
+ {
+ "name": "9.comms",
+ "ok": true,
+ "detail": "30 rows"
+ },
+ {
+ "name": "9.tanks",
+ "ok": true,
+ "detail": "26 rows"
+ },
+ {
+ "name": "9.vehicles",
+ "ok": true,
+ "detail": "10 rows"
+ },
+ {
+ "name": "10.1 Ⱦ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "JS Errors",
+ "ok": true,
+ "detail": "0 errors"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/demo/test_screenshots/timeline_current.png b/demo/test_screenshots/timeline_current.png
new file mode 100644
index 0000000..c73bb62
Binary files /dev/null and b/demo/test_screenshots/timeline_current.png differ
diff --git a/demo/test_screenshots/timeline_v2.png b/demo/test_screenshots/timeline_v2.png
new file mode 100644
index 0000000..d5e7126
Binary files /dev/null and b/demo/test_screenshots/timeline_v2.png differ
diff --git a/demo/test_screenshots/timeline_v3.png b/demo/test_screenshots/timeline_v3.png
new file mode 100644
index 0000000..d5e7126
Binary files /dev/null and b/demo/test_screenshots/timeline_v3.png differ
diff --git a/demo/test_screenshots/tl_final_1_init.png b/demo/test_screenshots/tl_final_1_init.png
new file mode 100644
index 0000000..d5e7126
Binary files /dev/null and b/demo/test_screenshots/tl_final_1_init.png differ
diff --git a/demo/test_screenshots/tl_final_2_zoomed.png b/demo/test_screenshots/tl_final_2_zoomed.png
new file mode 100644
index 0000000..163c0b3
Binary files /dev/null and b/demo/test_screenshots/tl_final_2_zoomed.png differ
diff --git a/demo/test_screenshots/tl_final_3_dragged.png b/demo/test_screenshots/tl_final_3_dragged.png
new file mode 100644
index 0000000..42372e6
Binary files /dev/null and b/demo/test_screenshots/tl_final_3_dragged.png differ
diff --git a/demo/test_screenshots/tl_final_4_zoomout.png b/demo/test_screenshots/tl_final_4_zoomout.png
new file mode 100644
index 0000000..7e4f294
Binary files /dev/null and b/demo/test_screenshots/tl_final_4_zoomout.png differ
diff --git a/demo/test_screenshots/tl_test_1_initial.png b/demo/test_screenshots/tl_test_1_initial.png
new file mode 100644
index 0000000..d5e7126
Binary files /dev/null and b/demo/test_screenshots/tl_test_1_initial.png differ
diff --git a/demo/test_screenshots/tl_test_2_zoomed.png b/demo/test_screenshots/tl_test_2_zoomed.png
new file mode 100644
index 0000000..d5e7126
Binary files /dev/null and b/demo/test_screenshots/tl_test_2_zoomed.png differ
diff --git a/demo/test_screenshots/tl_test_3_dragged.png b/demo/test_screenshots/tl_test_3_dragged.png
new file mode 100644
index 0000000..6b4c72d
Binary files /dev/null and b/demo/test_screenshots/tl_test_3_dragged.png differ
diff --git a/demo/test_screenshots/tl_test_4_tlzoom.png b/demo/test_screenshots/tl_test_4_tlzoom.png
new file mode 100644
index 0000000..2464ef9
Binary files /dev/null and b/demo/test_screenshots/tl_test_4_tlzoom.png differ
diff --git a/demo/test_screenshots/tl_test_5_wheel.png b/demo/test_screenshots/tl_test_5_wheel.png
new file mode 100644
index 0000000..d27d0fa
Binary files /dev/null and b/demo/test_screenshots/tl_test_5_wheel.png differ
diff --git a/demo/test_screenshots/tl_test_6_drag.png b/demo/test_screenshots/tl_test_6_drag.png
new file mode 100644
index 0000000..62de1a2
Binary files /dev/null and b/demo/test_screenshots/tl_test_6_drag.png differ
diff --git a/demo/test_screenshots/tl_test_7_zoomin_drag.png b/demo/test_screenshots/tl_test_7_zoomin_drag.png
new file mode 100644
index 0000000..013ec74
Binary files /dev/null and b/demo/test_screenshots/tl_test_7_zoomin_drag.png differ
diff --git a/demo/test_screenshots/tl_test_8_fixed_zoom.png b/demo/test_screenshots/tl_test_8_fixed_zoom.png
new file mode 100644
index 0000000..918a7af
Binary files /dev/null and b/demo/test_screenshots/tl_test_8_fixed_zoom.png differ
diff --git a/demo/test_screenshots/tl_test_9_fixed_drag.png b/demo/test_screenshots/tl_test_9_fixed_drag.png
new file mode 100644
index 0000000..1b51e3d
Binary files /dev/null and b/demo/test_screenshots/tl_test_9_fixed_drag.png differ
diff --git a/demo/test_screenshots/tl_v10_1_init.png b/demo/test_screenshots/tl_v10_1_init.png
new file mode 100644
index 0000000..f1d753e
Binary files /dev/null and b/demo/test_screenshots/tl_v10_1_init.png differ
diff --git a/demo/test_screenshots/tl_v10_2_zoom5.png b/demo/test_screenshots/tl_v10_2_zoom5.png
new file mode 100644
index 0000000..40a687d
Binary files /dev/null and b/demo/test_screenshots/tl_v10_2_zoom5.png differ
diff --git a/demo/test_screenshots/tl_v10_3_zoom10.png b/demo/test_screenshots/tl_v10_3_zoom10.png
new file mode 100644
index 0000000..0c7d702
Binary files /dev/null and b/demo/test_screenshots/tl_v10_3_zoom10.png differ
diff --git a/demo/test_screenshots/tl_v10_4_dragged.png b/demo/test_screenshots/tl_v10_4_dragged.png
new file mode 100644
index 0000000..6cd6926
Binary files /dev/null and b/demo/test_screenshots/tl_v10_4_dragged.png differ
diff --git a/demo/test_screenshots/tl_v11_scale_fix.png b/demo/test_screenshots/tl_v11_scale_fix.png
new file mode 100644
index 0000000..f43d82a
Binary files /dev/null and b/demo/test_screenshots/tl_v11_scale_fix.png differ
diff --git a/demo/test_screenshots/tl_v12_spacing.png b/demo/test_screenshots/tl_v12_spacing.png
new file mode 100644
index 0000000..c086338
Binary files /dev/null and b/demo/test_screenshots/tl_v12_spacing.png differ
diff --git a/demo/test_screenshots/tl_v13_clip.png b/demo/test_screenshots/tl_v13_clip.png
new file mode 100644
index 0000000..c086338
Binary files /dev/null and b/demo/test_screenshots/tl_v13_clip.png differ
diff --git a/demo/test_screenshots/tl_v13_clip_zoom.png b/demo/test_screenshots/tl_v13_clip_zoom.png
new file mode 100644
index 0000000..7f780ab
Binary files /dev/null and b/demo/test_screenshots/tl_v13_clip_zoom.png differ
diff --git a/demo/test_screenshots/tl_v14_final.png b/demo/test_screenshots/tl_v14_final.png
new file mode 100644
index 0000000..f25725a
Binary files /dev/null and b/demo/test_screenshots/tl_v14_final.png differ
diff --git a/demo/test_screenshots/tl_v4_1_init.png b/demo/test_screenshots/tl_v4_1_init.png
new file mode 100644
index 0000000..d5e7126
Binary files /dev/null and b/demo/test_screenshots/tl_v4_1_init.png differ
diff --git a/demo/test_screenshots/tl_v4_2_zoomed.png b/demo/test_screenshots/tl_v4_2_zoomed.png
new file mode 100644
index 0000000..22011ce
Binary files /dev/null and b/demo/test_screenshots/tl_v4_2_zoomed.png differ
diff --git a/demo/test_screenshots/tl_v4_3_dragged.png b/demo/test_screenshots/tl_v4_3_dragged.png
new file mode 100644
index 0000000..102dfe7
Binary files /dev/null and b/demo/test_screenshots/tl_v4_3_dragged.png differ
diff --git a/demo/test_screenshots/tl_v5_1_init.png b/demo/test_screenshots/tl_v5_1_init.png
new file mode 100644
index 0000000..d5e7126
Binary files /dev/null and b/demo/test_screenshots/tl_v5_1_init.png differ
diff --git a/demo/test_screenshots/tl_v5_2_zoomed.png b/demo/test_screenshots/tl_v5_2_zoomed.png
new file mode 100644
index 0000000..c84b561
Binary files /dev/null and b/demo/test_screenshots/tl_v5_2_zoomed.png differ
diff --git a/demo/test_screenshots/tl_v5_3_dragged.png b/demo/test_screenshots/tl_v5_3_dragged.png
new file mode 100644
index 0000000..c84b561
Binary files /dev/null and b/demo/test_screenshots/tl_v5_3_dragged.png differ
diff --git a/demo/test_screenshots/tl_v5_4_direct_zoom.png b/demo/test_screenshots/tl_v5_4_direct_zoom.png
new file mode 100644
index 0000000..e725bcd
Binary files /dev/null and b/demo/test_screenshots/tl_v5_4_direct_zoom.png differ
diff --git a/demo/test_screenshots/tl_v6_1_init.png b/demo/test_screenshots/tl_v6_1_init.png
new file mode 100644
index 0000000..f21ce69
Binary files /dev/null and b/demo/test_screenshots/tl_v6_1_init.png differ
diff --git a/demo/test_screenshots/tl_v6_2_zoom1.png b/demo/test_screenshots/tl_v6_2_zoom1.png
new file mode 100644
index 0000000..f619bf0
Binary files /dev/null and b/demo/test_screenshots/tl_v6_2_zoom1.png differ
diff --git a/demo/test_screenshots/tl_v6_3_zoom2.png b/demo/test_screenshots/tl_v6_3_zoom2.png
new file mode 100644
index 0000000..3c23826
Binary files /dev/null and b/demo/test_screenshots/tl_v6_3_zoom2.png differ
diff --git a/demo/test_screenshots/tl_v6_4_dragged.png b/demo/test_screenshots/tl_v6_4_dragged.png
new file mode 100644
index 0000000..47700b4
Binary files /dev/null and b/demo/test_screenshots/tl_v6_4_dragged.png differ
diff --git a/demo/test_screenshots/tl_v7_1_init.png b/demo/test_screenshots/tl_v7_1_init.png
new file mode 100644
index 0000000..f21ce69
Binary files /dev/null and b/demo/test_screenshots/tl_v7_1_init.png differ
diff --git a/demo/test_screenshots/tl_v7_2_zoomed.png b/demo/test_screenshots/tl_v7_2_zoomed.png
new file mode 100644
index 0000000..e70d09f
Binary files /dev/null and b/demo/test_screenshots/tl_v7_2_zoomed.png differ
diff --git a/demo/test_screenshots/tl_v7_3_dragged.png b/demo/test_screenshots/tl_v7_3_dragged.png
new file mode 100644
index 0000000..53bccff
Binary files /dev/null and b/demo/test_screenshots/tl_v7_3_dragged.png differ
diff --git a/demo/test_screenshots/tl_v8_1_init.png b/demo/test_screenshots/tl_v8_1_init.png
new file mode 100644
index 0000000..8be1ed3
Binary files /dev/null and b/demo/test_screenshots/tl_v8_1_init.png differ
diff --git a/demo/test_screenshots/tl_v8_2_zoomed.png b/demo/test_screenshots/tl_v8_2_zoomed.png
new file mode 100644
index 0000000..25cb52d
Binary files /dev/null and b/demo/test_screenshots/tl_v8_2_zoomed.png differ
diff --git a/demo/test_screenshots/tl_v8_3_dragged.png b/demo/test_screenshots/tl_v8_3_dragged.png
new file mode 100644
index 0000000..ebfa1a3
Binary files /dev/null and b/demo/test_screenshots/tl_v8_3_dragged.png differ
diff --git a/demo/test_screenshots/tl_v8_4_light.png b/demo/test_screenshots/tl_v8_4_light.png
new file mode 100644
index 0000000..1ed8098
Binary files /dev/null and b/demo/test_screenshots/tl_v8_4_light.png differ
diff --git a/demo/test_screenshots/tl_v9_1_init.png b/demo/test_screenshots/tl_v9_1_init.png
new file mode 100644
index 0000000..46e3264
Binary files /dev/null and b/demo/test_screenshots/tl_v9_1_init.png differ
diff --git a/demo/test_screenshots/tl_v9_2_zoomed5.png b/demo/test_screenshots/tl_v9_2_zoomed5.png
new file mode 100644
index 0000000..8f3957d
Binary files /dev/null and b/demo/test_screenshots/tl_v9_2_zoomed5.png differ
diff --git a/demo/test_screenshots/tl_v9_3_zoomed10.png b/demo/test_screenshots/tl_v9_3_zoomed10.png
new file mode 100644
index 0000000..e29f743
Binary files /dev/null and b/demo/test_screenshots/tl_v9_3_zoomed10.png differ
diff --git a/demo/test_screenshots/undock_click.png b/demo/test_screenshots/undock_click.png
new file mode 100644
index 0000000..8171e9c
Binary files /dev/null and b/demo/test_screenshots/undock_click.png differ
diff --git a/demo/test_screenshots/undock_result.png b/demo/test_screenshots/undock_result.png
new file mode 100644
index 0000000..4a8dea2
Binary files /dev/null and b/demo/test_screenshots/undock_result.png differ
diff --git a/demo/test_st01_nodes.png b/demo/test_st01_nodes.png
new file mode 100644
index 0000000..995a71e
Binary files /dev/null and b/demo/test_st01_nodes.png differ
diff --git a/demo/test_statenodes.png b/demo/test_statenodes.png
new file mode 100644
index 0000000..ad1dfd0
Binary files /dev/null and b/demo/test_statenodes.png differ
diff --git a/demo/test_statenodes_v2.png b/demo/test_statenodes_v2.png
new file mode 100644
index 0000000..ad1dfd0
Binary files /dev/null and b/demo/test_statenodes_v2.png differ
diff --git a/demo/test_timeline_clip.png b/demo/test_timeline_clip.png
new file mode 100644
index 0000000..fbe5c8d
Binary files /dev/null and b/demo/test_timeline_clip.png differ
diff --git a/demo/test_timeline_v2.png b/demo/test_timeline_v2.png
new file mode 100644
index 0000000..7a4bf4d
Binary files /dev/null and b/demo/test_timeline_v2.png differ
diff --git a/demo/test_timeline_v3.png b/demo/test_timeline_v3.png
new file mode 100644
index 0000000..7a4bf4d
Binary files /dev/null and b/demo/test_timeline_v3.png differ
diff --git a/demo/test_timeline_v4.png b/demo/test_timeline_v4.png
new file mode 100644
index 0000000..ac09c43
Binary files /dev/null and b/demo/test_timeline_v4.png differ
diff --git a/demo/test_timeline_v5.png b/demo/test_timeline_v5.png
new file mode 100644
index 0000000..ff6f777
Binary files /dev/null and b/demo/test_timeline_v5.png differ
diff --git a/demo/test_timeline_v6.png b/demo/test_timeline_v6.png
new file mode 100644
index 0000000..42ffa5a
Binary files /dev/null and b/demo/test_timeline_v6.png differ
diff --git a/demo/textures/earth.jpg b/demo/textures/earth.jpg
new file mode 100644
index 0000000..55b715d
Binary files /dev/null and b/demo/textures/earth.jpg differ
diff --git a/demo/textures/io.jpg b/demo/textures/io.jpg
new file mode 100644
index 0000000..f1ef62e
Binary files /dev/null and b/demo/textures/io.jpg differ
diff --git a/demo/textures/jupiter.jpg b/demo/textures/jupiter.jpg
new file mode 100644
index 0000000..21f1951
Binary files /dev/null and b/demo/textures/jupiter.jpg differ
diff --git a/demo/textures/mars.jpg b/demo/textures/mars.jpg
new file mode 100644
index 0000000..b3654a9
Binary files /dev/null and b/demo/textures/mars.jpg differ
diff --git a/demo/textures/mercury.jpg b/demo/textures/mercury.jpg
new file mode 100644
index 0000000..eebaed9
Binary files /dev/null and b/demo/textures/mercury.jpg differ
diff --git a/demo/textures/moon.jpg b/demo/textures/moon.jpg
new file mode 100644
index 0000000..9316840
Binary files /dev/null and b/demo/textures/moon.jpg differ
diff --git a/demo/textures/neptune.jpg b/demo/textures/neptune.jpg
new file mode 100644
index 0000000..30e7ac5
Binary files /dev/null and b/demo/textures/neptune.jpg differ
diff --git a/demo/textures/pluto.jpg b/demo/textures/pluto.jpg
new file mode 100644
index 0000000..0a906df
Binary files /dev/null and b/demo/textures/pluto.jpg differ
diff --git a/demo/textures/saturn.jpg b/demo/textures/saturn.jpg
new file mode 100644
index 0000000..d8b23df
Binary files /dev/null and b/demo/textures/saturn.jpg differ
diff --git a/demo/textures/sun.jpg b/demo/textures/sun.jpg
new file mode 100644
index 0000000..9d787d8
Binary files /dev/null and b/demo/textures/sun.jpg differ
diff --git a/demo/textures/uranus.jpg b/demo/textures/uranus.jpg
new file mode 100644
index 0000000..d0abf4c
Binary files /dev/null and b/demo/textures/uranus.jpg differ
diff --git a/demo/textures/venus.jpg b/demo/textures/venus.jpg
new file mode 100644
index 0000000..83374cf
--- /dev/null
+++ b/demo/textures/venus.jpg
@@ -0,0 +1,1786 @@
+
+
+
+
+
+
+
+
+
+
+
+Photojournal - NASA Science
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Photojournal
+
+
+ The National Aeronautics and Space Administration and the Planetary Data System's (PDS) Cartography and Imaging Sciences Node welcome you to Photojournal — An image archive containing fascinating imagery, animations, and videos from numerous Solar System exploration missions.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Welcome to the new Photojournal Website!
+
+
+
+
Welcome to Photojournal's new web presence on Science@NASA . Our new site contains all the same great images, animations, and videos as our previous site. We've updated our media galleries , making them easier to browse and search for content. We hope you enjoy our new site, but if you have questions, comments, or suggestions, please share your thoughts with us.
+
+
+
+
+
+
+
Latest Content
+
Stay up-to-date with the latest additions to the Photojournal image archive as we explore the universe and discover more about our Solar System.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ NASA’s Psyche Mission Images Mars’ Huygens Crater
+
+
Captured by the multispectral imager instrument on NASA’s Psyche mission, this is an enhanced-color view of the large double-ring crater…
+
May 19, 2026
+
+
+
+
+
+
+
+ NASA’s Psyche Mission Spies Mars’ Wind-Blown Craters During Close Approach
+
+
This view of the Martian surface, captured by NASA’s Psyche spacecraft on May 15, 2026, shows streaks that have formed…
+
May 19, 2026
+
+
+
+
+
+
+
+ Psyche’s High-Resolution View of Mars’ South Pole
+
+
Description This is the highest-resolution view of the water ice-rich south polar cap of Mars captured by NASA’s Psyche mission…
+
May 19, 2026
+
+
+
+
+
+
+
+ NASA’s Psyche Mission Sees Mars’ South Pole After Flyby
+
+
Description This is Psyche’s first view of a nearly “full Mars” seen shortly after the spacecraft’s closest approach to the…
+
May 19, 2026
+
+
+
+
+
+
+
+ NASA’s Psyche Mission Images the Crescent of Mars
+
+
Description This view of a crescent Mars was captured on May 15, 2026, at about 5:03 a.m. PDT by NASA’s…
+
May 19, 2026
+
+
+
+
+
+
+
+ NASA’s Perseverance Captures Panorama at ‘Arbot’
+
+
Description NASA’s Perseverance Mars rover used its Mastcam-Z camera to capture this panorama of an area nicknamed “Arbot” on April…
+
May 12, 2026
+
+
+
+
+
+
+
+ NASA’s Perseverance Rover Snaps Westernmost Selfie
+
+
Description NASA’s Perseverance Mars rover took this selfie on March 11, 2026, the 1,797th Martian day, or sol, of the…
+
May 12, 2026
+
+
+
+
+
+
+
+ NASA’s Curiosity Takes Close Look at Rock That Got Stuck on Drill
+
+
Description NASA’s Curiosity Mars rover used its Mast Camera, or Mastcam, to capture this view of a rock nicknamed “Atacama”…
+
May 11, 2026
+
+
+
+
+
+
+
+ NASA’s Psyche Mission Captures Mars During Gravity Assist Approach
+
+
Description This colorized image of Mars was captured by NASA’s Psyche mission on May 3, 2026, about 3 million miles…
+
May 8, 2026
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Keep Exploring
+
Discover More Topics From Photojournal
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demo/timeline_final.png b/demo/timeline_final.png
new file mode 100644
index 0000000..ed0187f
Binary files /dev/null and b/demo/timeline_final.png differ
diff --git a/demo/timeline_v10.png b/demo/timeline_v10.png
new file mode 100644
index 0000000..ad6a65d
Binary files /dev/null and b/demo/timeline_v10.png differ
diff --git a/demo/timeline_v7.png b/demo/timeline_v7.png
new file mode 100644
index 0000000..f8e59fe
Binary files /dev/null and b/demo/timeline_v7.png differ
diff --git a/demo/timeline_v8.png b/demo/timeline_v8.png
new file mode 100644
index 0000000..1f6d588
Binary files /dev/null and b/demo/timeline_v8.png differ
diff --git a/demo/timeline_v9.png b/demo/timeline_v9.png
new file mode 100644
index 0000000..22fb022
Binary files /dev/null and b/demo/timeline_v9.png differ
diff --git a/demo/timeline_zoom_final.png b/demo/timeline_zoom_final.png
new file mode 100644
index 0000000..ed0187f
Binary files /dev/null and b/demo/timeline_zoom_final.png differ
diff --git a/demo/timeline_zoom_test.png b/demo/timeline_zoom_test.png
new file mode 100644
index 0000000..ed0187f
Binary files /dev/null and b/demo/timeline_zoom_test.png differ
diff --git a/demo/timeline_zoom_v5.png b/demo/timeline_zoom_v5.png
new file mode 100644
index 0000000..ed0187f
Binary files /dev/null and b/demo/timeline_zoom_v5.png differ
diff --git a/demo/timeline_zoom_v6.png b/demo/timeline_zoom_v6.png
new file mode 100644
index 0000000..f244887
Binary files /dev/null and b/demo/timeline_zoom_v6.png differ
diff --git a/demo/v6_flat.png b/demo/v6_flat.png
new file mode 100644
index 0000000..f81ad04
Binary files /dev/null and b/demo/v6_flat.png differ
diff --git a/demo/v6_io.png b/demo/v6_io.png
new file mode 100644
index 0000000..851fdf9
Binary files /dev/null and b/demo/v6_io.png differ
diff --git a/demo/v6_jupiter.png b/demo/v6_jupiter.png
new file mode 100644
index 0000000..1a9005e
Binary files /dev/null and b/demo/v6_jupiter.png differ
diff --git a/demo/v6_solar.png b/demo/v6_solar.png
new file mode 100644
index 0000000..114ea1e
Binary files /dev/null and b/demo/v6_solar.png differ
diff --git a/demo/v7_jupiter.png b/demo/v7_jupiter.png
new file mode 100644
index 0000000..7585485
Binary files /dev/null and b/demo/v7_jupiter.png differ
diff --git a/demo/v7_solar.png b/demo/v7_solar.png
new file mode 100644
index 0000000..fa36442
Binary files /dev/null and b/demo/v7_solar.png differ
diff --git a/docs/asset_crud_retest_report_2026-05-31.md b/docs/asset_crud_retest_report_2026-05-31.md
new file mode 100644
index 0000000..fb9b716
--- /dev/null
+++ b/docs/asset_crud_retest_report_2026-05-31.md
@@ -0,0 +1,368 @@
+# 任务资产与日志 CRUD 复测报告
+
+日期:2026-05-31
+
+## 结论
+
+本轮只做测试和报告,没有修改业务代码。
+
+资产本体的新增、修改、删除主流程基本可用:测试资产可以创建,可以通过表单路由修改 `name/program/home_region/note`,也可以删除,删除后数据库中不再存在该测试资产。
+
+资产日志和 state node 仍有 P0 问题。正式日志表单创建/编辑 state interval 时,entry 本体字段能保存,但 state node 的 `state_label`、`previous_location`、`transit_location`、`target_location` 全部没有保存。资产详情页的快速新增日志 modal 走 JSON 路由,这条路径更不完整:state/location/node location 字段被忽略;快速新增 Event Point 还会因为没有 start time 直接 400。
+
+## 测试范围
+
+按用户要求覆盖:
+
+- 新建资产
+- 修改资产信息
+- 删除资产
+- 新建资产日志
+- 修改资产日志
+- 修改 state node 信息,重点包括 target location
+
+测试数据使用 `TEST_Codex_...` 前缀,测试结束后已清理。复测后查询确认剩余 `TEST_Codex_%` 资产数量为 0。
+
+## 执行记录
+
+### 1. 新建资产
+
+通过 `/assets/new?sim_time=2060-03-12T09:00` UI 表单创建:
+
+- Name: `TEST_Codex_Asset_20260531_719359`
+- Asset Type: `Station`
+- Program: `TEST Program Alpha`
+- Home Region: `LEO`
+- Note: `Created by Codex asset CRUD retest; safe to delete.`
+
+结果:
+
+- POST 后 302 跳转到资产详情页。
+- 详情页 H1 显示测试资产名。
+- DB 中存在该资产。
+
+状态:通过。
+
+### 2. 修改资产信息
+
+通过 `/assets//edit` 表单路由提交:
+
+- Name 改为 `TEST_Codex_Asset_20260531_719359_EDITED`
+- Program 改为 `TEST Program Beta`
+- Home Region 改为 `Mars Orbit`
+- Note 改为 `Edited by Codex asset CRUD retest.`
+
+结果:
+
+```json
+{
+ "status": 302,
+ "name": "TEST_Codex_Asset_20260531_719359_EDITED",
+ "program": "TEST Program Beta",
+ "home_region": "Mars Orbit",
+ "note": "Edited by Codex asset CRUD retest."
+}
+```
+
+状态:通过。
+
+备注:使用 in-app browser 直接填 edit form 时遇到浏览器控制层 CDP/clipboard 超时,我没有把它记为应用 bug;最终用同一个 HTTP 表单路由验证保存契约。
+
+### 3. 删除资产
+
+通过 `/assets//delete` 表单路由删除测试资产。
+
+结果:
+
+```json
+{
+ "status": 302,
+ "location": "/assets?sim_time=2060-03-12T09:00",
+ "exists_after_delete": false
+}
+```
+
+状态:通过。
+
+## 日志与 State Node 问题
+
+### P0-1: 正式日志表单没有保存 state node 的 location/state 字段
+
+操作:
+
+通过 `/assets//entries/new` 的正式表单路由创建 state interval:
+
+- Entry title: `TEST Formal State 20260531_719359`
+- Mission: `TEST Mission Beta`
+- Start/End: `2060-03-13T09:00` 到 `2060-03-16T09:00`
+- Node title: `Formal Node A`
+- Node state: `Docked`
+- Previous Location: `LEO`
+- Transit Location: `Transfer`
+- Target Location: `Mars Orbit`
+
+结果:
+
+```json
+{
+ "title": "Formal Node A",
+ "detail": "Formal node A detail",
+ "state_label": null,
+ "previous_location": null,
+ "transit_location": null,
+ "target_location": null
+}
+```
+
+再通过 `/assets//entries//edit` 修改同一个 node:
+
+- Node title 改为 `Formal Node A EDITED`
+- Node state 改为 `Exploration`
+- Previous Location 改为 `Mars Orbit`
+- Transit Location 改为 `Transfer`
+- Target Location 改为 `Mars Surface`
+
+结果仍然是:
+
+```json
+{
+ "title": "Formal Node A EDITED",
+ "detail": "Formal node A detail edited",
+ "state_label": null,
+ "previous_location": null,
+ "transit_location": null,
+ "target_location": null
+}
+```
+
+状态:未通过。
+
+根因线索:
+
+- [app/routes/web.py]() 中 `_parse_state_node_rows()` 用 `enumerate(..., start=1)`,但读取 `node_locations[index]` / `node_state_labels[index]`。表单数组是 0-based,第一个 node 应该用 `row_index`,当前第一个 node 永远读不到这些扩展字段。
+- [app/routes/web.py]() 把 target location 存进 row key `"location"`。
+- [app/routes/web.py]() `_sync_state_nodes()` 却读取 `row.get("target_location")`。即使修掉 index,target location 仍会因为 key 不一致继续丢失。
+
+### P0-2: 资产详情页快速新增日志 JSON 路由忽略 location/state/node 扩展字段
+
+资产详情页底部 quick modal 的 `saveLog()` 走 JSON:
+
+- `/assets//entries/new`
+- `Content-Type: application/json`
+
+这条后端路径只写:
+
+- `entry_kind`
+- `title`
+- `summary`
+- `start_at`
+- `end_at`
+- state node 的 `title/detail/at_time`
+
+它没有写入:
+
+- entry 的 `mission_label`
+- node 的 `state_label`
+- node 的 `previous_location`
+- node 的 `transit_location`
+- node 的 `target_location`
+
+复测 payload 中传了这些字段:
+
+```json
+{
+ "state_label": "Maintenance",
+ "location": "Lunar Orbit",
+ "state_nodes": [
+ {
+ "state_label": "Maintenance",
+ "previous_location": "LEO",
+ "transit_location": "Transfer",
+ "target_location": "Lunar Orbit"
+ }
+ ]
+}
+```
+
+保存后 DB 中 node 仍是:
+
+```json
+{
+ "state_label": null,
+ "previous_location": null,
+ "transit_location": null,
+ "target_location": null
+}
+```
+
+状态:未通过。
+
+根因线索:
+
+- [app/routes/web.py]() JSON create path 手写字段映射,没有复用 `_apply_asset_entry_fields()` / `_parse_state_node_rows()`。
+- [app/routes/web.py]() JSON edit path 也有同样问题。
+- [app/templates/asset_detail.html]() quick modal 的 `state_nodes` payload 只包含 `title/at_time/detail`,UI 本身也没有 target location/state node fields。
+
+### P0-3: 资产详情页快速新增 Event Point 无法保存
+
+操作:
+
+模拟资产详情页 `openNewLog('event')` 后 `saveLog()` 的 JSON 行为:`start_at=null`,`end_at=null`。
+
+结果:
+
+- HTTP 400
+- 数据库报错:`null value in column "start_at" of relation "asset_log_entries" violates not-null constraint`
+
+原因:
+
+- [app/templates/asset_detail.html]() `openNewLog('event')` 会隐藏 `log-end-wrap`。
+- `log-end-wrap` 里同时包含 Start At 和 End At。
+- 用户新建 Event Point 时没有地方填写 Start At。
+- [app/templates/asset_detail.html]() `saveLog()` 仍把 `start_at` 作为可空值发给后端。
+
+状态:未通过。
+
+### P1-1: 正式日志编辑页切换 Entry Type 的 JS 有潜在错误
+
+代码中:
+
+```js
+document.getElementById("state-wrap").style.display = isState ? "" : "none";
+```
+
+但当前模板没有 `id="state-wrap"` 的元素。切换 entry type 时会触发空引用错误。
+
+位置:
+
+- [app/templates/asset_entry_form.html]()
+
+状态:未完整浏览器复现,但静态检查明确有风险。
+
+### P1-2: 资产详情页日志搜索和类型筛选控件没有实际逻辑
+
+资产详情页有:
+
+- `#ad-lq`
+- `#ad-lf`
+
+但模板中没有对应筛选脚本,也没有表单提交参数。控件看起来可用,实际不会过滤日志表。
+
+位置:
+
+- [app/templates/asset_detail.html]()
+
+状态:静态检查明确未实现。
+
+## 当前通过项
+
+- 新建资产:通过。
+- 修改资产本体字段:通过。
+- 删除资产:通过,关联日志随资产清理。
+- 正式日志表单的 entry 本体字段保存:部分通过,`title/mission_label/start_at/end_at/summary/note` 可保存和修改。
+
+## 当前未通过项
+
+- 正式日志表单保存 state node 的 `target_location`:失败。
+- 正式日志表单保存 state node 的 `state_label/previous_location/transit_location`:失败。
+- 资产详情页 quick modal 保存 state node 扩展字段:失败。
+- 资产详情页 quick modal 新增 Event Point:失败。
+- 资产详情页日志搜索/类型筛选:未实现。
+- 正式日志编辑页切换 Entry Type:存在 JS 空引用风险。
+
+## 改进建议
+
+### P0
+
+1. 统一日志保存路径。
+ - 不要让 JSON create/edit 和 form create/edit 各写一套字段映射。
+ - 建议把 request JSON 转成同一份 internal DTO,然后复用同一个 validation + persistence 函数。
+
+2. 修复 `_parse_state_node_rows()` 的数组下标。
+ - 读取 node 扩展字段时使用 `row_index`,不要用从 1 开始的 `index`。
+
+3. 修复 target location key。
+ - `_parse_state_node_rows()` 应输出 `"target_location"`,或 `_sync_state_nodes()` 应读取 `"location"`;两边必须一致。
+
+4. 资产详情 quick modal 要么删除,要么补齐。
+ - 如果保留 quick modal,state log 必须能填写 node state/previous/transit/target。
+ - Event Point 必须显示 Start At。
+ - JSON route 必须保存同等字段。
+
+5. 后端 JSON 错误不要向用户暴露 SQLAlchemy/psycopg 全量错误。
+ - 当前 Event Point 失败时返回了完整 SQL、参数和 DB 约束信息。
+ - 应返回用户级 validation error,例如 `Start At is required`。
+
+### P1
+
+1. 修复 `state-wrap` 空引用。
+2. 实现资产详情日志搜索/类型筛选,或移除未接线控件。
+3. 资产详情日志表应展示 node 的 state/location 字段,否则保存成功与否很难肉眼验证。
+4. 给 location/state combobox 增加可测试的稳定选择器或 data attributes。
+
+## 端到端测试方向
+
+建议新增一个独立的资产 CRUD E2E 套件,必须使用唯一测试前缀并自动清理。
+
+### Fixture
+
+- 创建 `TEST_E2E_ASSET_`。
+- 固定 `sim_time=2060-03-12T09:00`。
+- 每个测试结束查询并删除 `TEST_E2E_%` 资产。
+
+### 用例 1: 资产本体 CRUD
+
+1. 打开 `/assets/new?sim_time=2060-03-12T09:00`。
+2. 填写 name/type/program/home_region/note。
+3. 提交后断言跳到详情页。
+4. 打开 edit 页修改 name/program/home_region/note/retired。
+5. 提交后断言详情页 Quick Info 和 DB 一致。
+6. 删除资产。
+7. 断言列表页搜不到,DB 不存在。
+
+### 用例 2: 正式 State Interval + State Node
+
+1. 从资产详情点击 `+Entry` 或打开 `/assets//entries/new?kind=state`。
+2. 填写 entry title、mission、start/end、summary。
+3. 添加两个 state nodes。
+4. 每个 node 填 title/time/detail/state/previous/transit/target。
+5. 保存后断言 DB 中两个 node 全字段一致,并按 `at_time` 排序。
+6. 打开 edit 页修改第一个 node 的 target location。
+7. 保存后断言 DB 更新。
+8. 详情页断言 current location / log row location 使用最新 target location。
+
+### 用例 3: Quick Modal State Log
+
+1. 在资产详情点击 `+ State Interval`。
+2. 验证 modal 是否有足够字段保存 state node location/state。
+3. 保存后断言 JSON route 与正式 form route 行为一致。
+
+### 用例 4: Quick Modal Event Point
+
+1. 在资产详情点击 `+ Event Point`。
+2. 断言 Start At 可见且必填。
+3. 不填 Start At 时应显示 validation,不应返回原始 SQL 错误。
+4. 填 Start At 后保存成功。
+
+### 用例 5: 日志编辑和删除
+
+1. 打开 entry edit 页。
+2. 修改 entry 本体字段。
+3. 修改已有 node。
+4. 新增一个 node。
+5. 删除一个 node。
+6. 保存后断言 DB 与页面都一致。
+7. 删除 entry 后断言关联 state nodes 级联删除。
+
+### 用例 6: 资产详情日志筛选
+
+1. 给同一 asset 创建 state 和 event 两类日志。
+2. 输入搜索词,断言行数变化。
+3. 选择 `State Interval`,断言只显示 state。
+4. 选择 `Event Point`,断言只显示 event。
+
+## 复测清理状态
+
+- `TEST_Codex_Asset_20260531_719359` / edited variant:已删除。
+- `TEST_Codex_EventModal_20260531_719359`:已删除。
+- DB 查询 `TEST_Codex_%`:0 条。
diff --git a/docs/test_plan.md b/docs/test_plan.md
new file mode 100644
index 0000000..9d16209
--- /dev/null
+++ b/docs/test_plan.md
@@ -0,0 +1,147 @@
+# KSP管理后台 前端迁移测试方案
+
+## 测试范围
+
+基于 Phase 1-6 完成的所有前端迁移内容,共 12 个测试模块。
+
+## 测试环境
+- Flask 开发服务器 (port 9000)
+- Playwright headless Chromium
+- 数据库: PostgreSQL (真实数据)
+
+---
+
+## 模块 1: 基础框架
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 1.1 | 侧边栏导航 | 打开首页,检查侧边栏所有链接 | 侧边栏显示:任务总览、任务运营(4子项)、数据中心(4子项)、燃料换算、API健康检查 |
+| 1.2 | 侧边栏展开 | 首页加载时检查 | 任务运营和数据中心分组默认展开 |
+| 1.3 | 当前页高亮 | 导航到每个页面 | 对应侧边栏项显示 act 样式 |
+| 1.4 | 深色模式 | 打开首页,检查默认主题 | 默认深色 (data-theme="dark") |
+| 1.5 | 浅色模式切换 | 点击 ◐ 按钮 | 切换到浅色,localStorage 记忆 |
+| 1.6 | 深色模式切换 | 再次点击 ◐ 按钮 | 切换回深色 |
+| 1.7 | 模拟时间显示 | 检查顶栏 | 显示当前 sim_time |
+| 1.8 | 时间 +1d | 点击 +1d 按钮 | 页面刷新,时间增加1天 |
+| 1.9 | 时间 -1d | 点击 -1d 按钮 | 页面刷新,时间减少1天 |
+| 1.10 | 时间 +7d | 点击 +7d 按钮 | 页面刷新,时间增加7天 |
+| 1.11 | 时间 Today | 点击 Today 按钮 | 时间重置为 2060-03-12 |
+| 1.12 | 时间 Modal | 点击时间显示 | 弹出时间编辑 modal |
+| 1.13 | 时间 Modal Apply | 修改时间后点击 Apply | 页面刷新,时间更新 |
+| 1.14 | 时间 Modal Cancel | 点击 Cancel | modal 关闭,时间不变 |
+| 1.15 | ESC 关闭 Modal | 打开 modal 后按 ESC | modal 关闭 |
+
+## 模块 2: 任务总览
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 2.1 | 页面标题 | 检查首页 | 显示 "任务总览" |
+| 2.2 | 指标卡片 | 检查 metrics | 显示 Tracked Assets / Active Missions / Upcoming |
+| 2.3 | 指标真实数据 | 检查指标数字 | 数字来自数据库,非硬编码 |
+| 2.4 | 状态看板分组 | 检查 status board | 显示 In Transit / Exploration / Maintenance / Docked 分组 |
+| 2.5 | 状态看板数据 | 检查各分组资产数 | 数字与数据库一致 |
+| 2.6 | 资产链接 | 点击状态看板中的资产名 | 跳转到资产详情页 |
+| 2.7 | 模拟时间影响 | 修改 sim_time 后检查 | 指标和状态看板按新时间重新计算 |
+
+## 模块 3: 资产列表
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 3.1 | 页面渲染 | 导航到 /assets | 显示资产表格 |
+| 3.2 | 搜索 | 输入搜索词 | 过滤匹配的资产 |
+| 3.3 | 类型筛选 | 选择资产类型下拉 | 只显示该类型的资产 |
+| 3.4 | 排序 | 选择排序选项 | 按选择排序 |
+| 3.5 | 资产详情链接 | 点击资产名 | 跳转到 /assets//detail |
+| 3.6 | New Asset 按钮 | 点击 + New Asset | 跳转到创建页面 |
+| 3.7 | 分页 | 点击分页链接 | 正确翻页 |
+
+## 模块 4: 资产详情
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 4.1 | 页面渲染 | 进入资产详情 | 显示名称、类型、状态 |
+| 4.2 | 信息卡片 | 检查4张卡片 | 显示 Type / Location / Mission / Entries |
+| 4.3 | Docking Target | 检查对接目标区域 | 显示 "Not docked" 或已对接资产 |
+| 4.4 | Docked Vehicles | 检对接载具列表 | 显示已对接载具或 "No vehicles" |
+| 4.5 | 日志列表 | 检查日志表格 | 显示日期、类型、标题、状态、位置、操作 |
+| 4.6 | 日志搜索 | 输入搜索词 | 过滤日志 |
+| 4.7 | 日志类型筛选 | 选择 State/Event | 按类型过滤 |
+| 4.8 | Edit Asset 按钮 | 点击 Edit Asset | 跳转编辑页 |
+| 4.9 | ← Back 按钮 | 点击返回 | 回到资产列表 |
+
+## 模块 5: 对接功能
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 5.1 | + Dock 按钮 | 点击 + Dock | 弹出对接 modal |
+| 5.2 | 对接 modal 内容 | 检查 modal | 显示资产下拉 + Custom name 选项 + 备注 + Cancel/Dock |
+| 5.3 | 选择已有资产对接 | 选择一个资产 + Dock | 刷新页面,显示对接记录 |
+| 5.4 | Custom name 对接 | 选 Custom name + 输入名称 + Dock | 刷新页面,显示对接记录 |
+| 5.5 | 对接后日志 | 检查日志列表 | 新增一条 dock 相关的日志条目 |
+| 5.6 | Cancel 对接 | 点击 Cancel | modal 关闭,无变化 |
+
+## 模块 6: 日志 CRUD
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 6.1 | + State Interval | 点击按钮 | 弹出 modal,显示 Start/End/State/Location/Summary/Nodes |
+| 6.2 | + Event Point | 点击按钮 | 弹出 modal,隐藏 End/State/Nodes |
+| 6.3 | 新增 State Interval | 填写表单 + Save | 刷新页面,新日志出现在列表中 |
+| 6.4 | 新增 Event Point | 填写表单 + Save | 刷新页面,新事件出现在列表中 |
+| 6.5 | State Node 添加 | 点击 "+ Add Node" | 新增一个节点行 |
+| 6.6 | State Node 删除 | 点击 ✕ | 节点行删除 |
+| 6.7 | State Node 数据 | 填写多个节点 + Save | 日志保存后,每个节点正确存储 |
+| 6.8 | 编辑日志 | 点击 Edit | 弹出 modal,预填现有数据 |
+| 6.9 | 编辑后保存 | 修改标题 + Save | 刷新页面,标题已更新 |
+| 6.10 | 删除日志 | 点击 Del | confirm 后日志删除,entries 计数减少 |
+
+## 模块 7: 地点板
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 7.1 | 页面渲染 | 导航到地点板 | 显示 Canvas 星图 + 右侧信息面板 |
+| 7.2 | 星图内容 | 检查 Canvas | 显示太阳系行星(太阳、地球、火星等) |
+| 7.3 | 右侧面板 | 检查 info panel | 显示 Scope / Assets in Scope / Ongoing Missions |
+| 7.4 | 资产位置 | 检查 Assets in Scope | 资产按 location 分组到对应天体 |
+| 7.5 | 点击行星 | 点击木星 | 进入行星系视图,显示卫星 |
+| 7.6 | 点击卫星 | 在木星系点击 Io | 进入 Io 单体视图 |
+| 7.7 | 返回 | 点击 ← Back | 返回上一层 |
+| 7.8 | 拖拽平移 | 在星图上拖拽 | 星图跟随移动 |
+| 7.9 | 滚轮缩放 | 在星图上滚动 | 星图缩放 |
+
+## 模块 8: 时间线
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 8.1 | 页面渲染 | 导航到时间线 | 显示时间线 + 筛选栏 |
+| 8.2 | Scale 切换 | 选择 Year/Month/Day | 时间线刻度变化 |
+| 8.3 | 搜索筛选 | 输入资产名 | 只显示匹配资产 |
+| 8.4 | Type 筛选 | 选择类型 | 只显示该类型资产 |
+| 8.5 | Location 筛选 | 选择位置 | 只显示该位置资产 |
+| 8.6 | State 筛选 | 选择状态 | 只显示该状态资产 |
+
+## 模块 9: 数据中心
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 9.1 | 引擎列表 | /engines | 显示引擎表格,有搜索/筛选 |
+| 9.2 | 通信列表 | /communications | 显示通信部件表格 |
+| 9.3 | 燃料箱列表 | /tanks | 显示燃料箱表格 |
+| 9.4 | 载具列表 | /vehicles | 显示载具表格 |
+| 9.5 | 搜索 | 在引擎列表输入搜索 | 过滤结果 |
+| 9.6 | 筛选 | 选择燃料类型 | 过滤结果 |
+
+## 模块 10: 燃料换算
+
+| # | 测试项 | 操作 | 预期结果 |
+|---|--------|------|----------|
+| 10.1 | 页面渲染 | /fuel-converter | 显示换算器 |
+| 10.2 | 换算 L→t | 输入值 + L→t + Convert | 显示所有燃料的结果 |
+| 10.3 | 换算 t→L | 切换模式 + Convert | 显示所有燃料的结果 |
+
+## 测试执行方式
+- 使用 Playwright headless Chromium
+- 每个模块独立测试函数
+- 每个测试项输出 PASS/FAIL
+- 失败时记录具体原因
+- 最终输出汇总报告
diff --git a/docs/test_plan_v2.md b/docs/test_plan_v2.md
new file mode 100644
index 0000000..b1a19b0
--- /dev/null
+++ b/docs/test_plan_v2.md
@@ -0,0 +1,142 @@
+# KSP 管理后台重构测试计划 v2
+
+生成日期:2026-05-31
+
+## 1. 项目与重构摘要
+
+本项目是一个 Flask + SQLAlchemy 的 KSP 数据管理后台,数据来源包括引擎/通信/燃料箱/载具 Excel,以及任务资产日志。早期能力集中在数据中心:引擎目录、通信部件、燃料箱规格、载具成本、燃料换算和导入脚本。
+
+`draft_board.md` 描述的重构重点是“任务运营”:
+
+- 资产当前位置、当前任务、当前状态由 `AssetLogEntry` 按 `simulation_time` 派生,不应直接编辑位置结果。
+- 资产列表、任务总览、状态板、任务列表、时间线和地点板都应围绕同一套资产日志快照计算。
+- 日志支持 state interval / event point,并支持 state nodes;节点应按时间排序。
+- 对接关系应是时间敏感模型,需求中规划了 `docking_events` 表,并要求已有资产对接时双向写入日志。
+- 地点板应提供 Canvas 星图、天体层级导航、缩放/拖拽和 scope 面板。
+- 时间线应提供只读时间轴、搜索、预设、类型/位置/状态/日期范围/资产选择等筛选。
+- 数据中心保持现有结构,重构不应破坏 CRUD、筛选、排序和详情页。
+
+当前实现与 `draft_board.md` 的明显差距:
+
+- 模型和迁移中尚未实现 `docking_events` 表;当前 `/api/v1/assets//dock` 只给当前资产新增一条 state 日志,没有真实父子对接关系、分离流程或双向日志。
+- Location 仍是日志自由文本字段,尚未落成结构化层级选项。
+- 地点板已接入 Canvas 和轨道数据,但当前模板使用程序绘制的渐变天体,没有使用 `demo/textures/` 的真实纹理。
+- 时间线模板渲染了筛选控件,但未发现 `tlPreset`、搜索/筛选控件事件处理脚本;这些控件需要被测试明确捕获。
+- 资产详情日志搜索/类型筛选控件存在 DOM,但未发现对应前端过滤脚本。
+
+## 2. 对现有 `docs/test_plan.md` 的评估
+
+现有计划覆盖面大体方向正确,但不能直接作为验收依据:
+
+- 文档称“12 个测试模块”,实际只写了 10 个模块。
+- 大量断言只验证元素存在,例如按钮、表格、canvas,而没有验证数据来源、交互结果、URL 参数、数据库派生逻辑或副作用。
+- 多个用例与当前实现不一致:日志编辑实际是跳转到编辑页,不是打开 modal;对接功能没有 `docking_events`;时间线筛选控件缺少脚本;地点板没有真实纹理切换。
+- 测试脚本 `tests/test_e2e.py` 只有 36 个轻量断言,且结果名称编码损坏;它没有执行关键 CRUD 写入、分离、双向日志、时间敏感对接、筛选功能有效性,也没有隔离数据库。
+- 测试环境写“真实 PostgreSQL”,但计划包含新增/删除/对接写入,这会污染生产式数据。写入类测试必须切换到隔离测试库或事务回滚。
+
+## 3. 测试策略
+
+测试分三层执行。
+
+### A. 非破坏性冒烟回归
+
+目标:确认服务可达、页面主结构存在、关键数据表可渲染、API 基本可用。
+
+适用环境:当前真实 PostgreSQL 或只读数据环境。
+
+执行方式:
+
+- HTTP GET 页面检查。
+- API GET/错误输入检查。
+- 静态模板/脚本契约检查。
+- 不新增、不编辑、不删除、不调用会持久写入的对接接口。
+
+### B. 浏览器交互回归
+
+目标:确认 JS 交互真的工作,而不是只存在 DOM。
+
+适用环境:可运行 Playwright/Browser 的本地环境。
+
+执行方式:
+
+- 点击主题切换、时间 modal、侧边栏、地点板 canvas、时间线筛选控件。
+- 检查 URL、DOM、canvas 像素和 console error。
+- 只执行不写库的交互,除非已切到测试库。
+
+### C. 写入与业务验收
+
+目标:验证重构核心的业务正确性。
+
+适用环境:隔离 PostgreSQL/SQLite 测试库,或每个测试事务回滚。
+
+执行方式:
+
+- 使用固定 fixture 创建资产、日志、节点、对接事件。
+- 测试完成后清理或回滚。
+- 严禁在真实数据环境直接执行新增/删除/对接/导入。
+
+## 4. v2 测试矩阵
+
+| 模块 | 优先级 | 用例 | 类型 | 预期 |
+|---|---:|---|---|---|
+| 服务/API | P0 | `/api/v1/health` | 冒烟 | HTTP 200,`status=ok`,service 名正确 |
+| 服务/API | P0 | 燃料列表 API | 冒烟 | 返回 8 个燃料因子 |
+| 服务/API | P1 | 燃料换算 API `mode=volume/mass` | 冒烟 | 返回每种燃料的换算结果 |
+| 服务/API | P1 | 燃料换算非法输入 | 冒烟 | HTTP 400,错误信息明确 |
+| 基础框架 | P0 | 首页可达 | 冒烟 | HTTP 200,显示任务总览 |
+| 基础框架 | P0 | 侧边栏 | 冒烟 | 显示任务运营、数据中心、燃料换算、API 健康检查 |
+| 基础框架 | P1 | 主题切换 | 浏览器 | `data-theme` 在 dark/light 间切换,localStorage 持久化 |
+| 基础框架 | P1 | 模拟时间 modal | 浏览器 | 可打开/关闭/ESC 关闭,Apply 后 URL 写入 `sim_time` |
+| 任务总览 | P0 | 指标与状态板渲染 | 冒烟 | Tracked Assets / Active Missions / Upcoming / Status Board 存在 |
+| 任务总览 | P1 | 模拟时间影响 | 业务 | 同一 fixture 在不同 `sim_time` 下派生状态和 upcoming 变化正确 |
+| 资产列表 | P0 | `/assets` 可达 | 冒烟 | 表格有数据行,显示当前位置/当前事件/日志数 |
+| 资产列表 | P0 | 搜索路由 | 冒烟 | `q=ST-01` 返回匹配资产 |
+| 资产列表 | P1 | 类型/排序 | 浏览器 | 下拉改变后请求参数正确,结果排序/过滤正确 |
+| 资产列表 | P1 | 退役资产默认隐藏 | 业务 | 默认不显示 retired,显式开关后显示 |
+| 资产详情 | P0 | 从列表进入详情 | 冒烟 | 显示信息卡、Docking Target、Docked Vehicles、Log Entries |
+| 资产详情 | P1 | 当前状态/位置派生 | 业务 | state interval 覆盖当前时间时取 active state;无 active 时取最近日志或 home_region |
+| 资产详情 | P1 | 日志分页 | 浏览器 | 多页日志翻页后保留 `sim_time` |
+| 资产详情 | P2 | 日志搜索/类型筛选 | 浏览器 | 输入/选择后列表实际收缩;若控件无脚本应失败 |
+| 日志 CRUD | P0 | 新增 state interval | 写入 | 写入后列表出现,state nodes 按 `at_time` 升序 |
+| 日志 CRUD | P0 | 新增 event point | 写入 | event 无 end/state/nodes 字段要求,保存后可见 |
+| 日志 CRUD | P0 | 编辑日志页 | 写入 | GET 预填原值,POST 修改后持久化,失败时保留输入并显示 validation dialog |
+| 日志 CRUD | P1 | 删除日志 | 写入 | 删除后 entries 计数减少,关联 nodes 级联删除 |
+| 对接功能 | P0 | 需求级数据模型 | 静态/迁移 | 存在 `docking_events` 表和模型字段;当前应失败 |
+| 对接功能 | P0 | 已有资产对接 | 写入 | parent/child 关系可按时间查询,双方日志/节点按需求写入 |
+| 对接功能 | P0 | custom name 对接 | 写入 | 只影响当前 asset,保留 child_label |
+| 对接功能 | P0 | 分离 | 写入 | undocked_at 写入,当前时间晚于分离时不再显示 docked |
+| 状态板 | P0 | `/mission-preview/status-board` 可达 | 冒烟 | 显示状态分组、筛选栏、upcoming |
+| 状态板 | P1 | 筛选 | 浏览器 | 资产类型/地点/记录范围筛选后卡片数量和 URL 参数正确 |
+| 任务列表 | P1 | `/missions` 可达 | 冒烟 | 显示任务/日志聚合列表 |
+| 任务列表 | P1 | 筛选 | 浏览器 | 类型/地点/记录范围筛选正确 |
+| 地点板 | P0 | `/mission-preview/location-board` 可达 | 冒烟 | canvas、Scope、Assets in Scope、Ongoing Missions 存在 |
+| 地点板 | P0 | canvas 非空 | 浏览器 | 截图或像素采样证明非空,console 无错误 |
+| 地点板 | P1 | 层级导航 | 浏览器 | 点击 Jupiter 进入 Jupiter System,点击 Io 进入 Io,Back 返回 |
+| 地点板 | P1 | 缩放/拖拽 | 浏览器 | wheel 改变缩放,拖拽改变视图偏移 |
+| 地点板 | P1 | 资产 scope | 业务 | 不同 scope 下 Assets in Scope 与日志 location 派生一致 |
+| 地点板 | P2 | 真实纹理 | 视觉/静态 | 使用真实纹理资源或明确降级;当前实现应标记未达 draft 目标 |
+| 时间线 | P0 | `/mission-preview/timeline` 可达 | 冒烟 | 时间线行和刻度渲染 |
+| 时间线 | P1 | scale 切换 | 浏览器 | Year/Month/Day 改变 URL 或刻度 |
+| 时间线 | P1 | 搜索/类型/地点/状态筛选 | 浏览器 | 控件实际改变可见行;当前缺少脚本时应失败 |
+| 时间线 | P1 | 日期范围 | 浏览器/业务 | 手动范围生效,segment 裁切百分比正确 |
+| 数据中心 | P0 | 四个列表页 | 冒烟 | `/engines` `/communications` `/tanks` `/vehicles` 均 HTTP 200 且有数据 |
+| 数据中心 | P1 | 筛选/排序 | 浏览器 | 查询参数生效,表格结果正确 |
+| 数据中心 | P1 | CRUD | 写入 | 新增/编辑/删除后数据库一致,失败时 validation 明确 |
+| 导入 | P1 | workbook inspect/import dry run | 业务 | 能识别表结构、自然键冲突、导入统计 |
+| 可访问性/前端质量 | P1 | console error | 浏览器 | 主路径无 JS error |
+| 可访问性/前端质量 | P2 | 响应式 | 视觉 | 1440x900、390x844 下无严重重叠 |
+
+## 5. 自动化建议
+
+- 保留一个 `smoke` 套件:只读、可在真实库跑,覆盖 P0 冒烟项。
+- 新增一个 `e2e` 套件:Playwright + 测试库,覆盖 P1 浏览器交互。
+- 新增一个 `business` 套件:Flask test client + fixture + 事务回滚,覆盖日志派生、对接、时间敏感状态。
+- 测试报告必须输出 Markdown 与机器可读 JSON;失败项保留 URL、参数、截图或最小复现步骤。
+- 所有写入测试统一使用唯一前缀,例如 `TEST_E2E_20260531_`,并在 teardown 校验清理完成。
+
+## 6. 本轮建议的验收门槛
+
+- P0 冒烟:100% 通过。
+- P0 业务:对接模型完成前允许标记为“未实现”,但不能误报通过。
+- P1 浏览器交互:主路径无 console error,地点板 canvas 非空,时间线筛选可实际生效。
+- 写入测试:只允许在隔离库执行;真实库环境下报告为 skipped,而不是 pass。
diff --git a/docs/test_report.json b/docs/test_report.json
new file mode 100644
index 0000000..7d2652b
--- /dev/null
+++ b/docs/test_report.json
@@ -0,0 +1,187 @@
+{
+ "total": 36,
+ "passed": 36,
+ "failed": 0,
+ "results": [
+ {
+ "name": "1.1 ",
+ "ok": true,
+ "detail": "11 items"
+ },
+ {
+ "name": "1.2 Ĭչ",
+ "ok": true,
+ "detail": "2 expanded"
+ },
+ {
+ "name": "1.3 ǰҳ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.4 Ĭɫģʽ",
+ "ok": true,
+ "detail": "theme=dark"
+ },
+ {
+ "name": "1.5 dzɫģʽ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.6 ɫģʽл",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.7 ģʱʾ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.12 Modal",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.14 Cancelر",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "1.15 ESCر",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "2.1 ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "2.2 ָ꿨Ƭ",
+ "ok": true,
+ "detail": "3 cards"
+ },
+ {
+ "name": "2.3 ʵ",
+ "ok": true,
+ "detail": "count=14"
+ },
+ {
+ "name": "2.4 ״̬",
+ "ok": true,
+ "detail": "4 groups"
+ },
+ {
+ "name": "2.6 ʲ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "3.1 бȾ",
+ "ok": true,
+ "detail": "14 rows"
+ },
+ {
+ "name": "3.2 ",
+ "ok": true,
+ "detail": "14->1"
+ },
+ {
+ "name": "4.1 Ⱦ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "4.2 ϢƬ",
+ "ok": true,
+ "detail": "4 cards"
+ },
+ {
+ "name": "4.5 ־б",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "5.1 Dockť",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "5.2 Modal",
+ "ok": true,
+ "detail": "15 options"
+ },
+ {
+ "name": "5.6 Cancel",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "6.1 State Interval",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "6.5 Node",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "6.10 Modalر",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "7.1 Canvas",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "7.2 Χ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "8.1 Ⱦ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "8.2 ",
+ "ok": true,
+ "detail": "14 rows"
+ },
+ {
+ "name": "9.engines",
+ "ok": true,
+ "detail": "30 rows"
+ },
+ {
+ "name": "9.comms",
+ "ok": true,
+ "detail": "30 rows"
+ },
+ {
+ "name": "9.tanks",
+ "ok": true,
+ "detail": "26 rows"
+ },
+ {
+ "name": "9.vehicles",
+ "ok": true,
+ "detail": "10 rows"
+ },
+ {
+ "name": "10.1 Ⱦ",
+ "ok": true,
+ "detail": ""
+ },
+ {
+ "name": "JS Errors",
+ "ok": true,
+ "detail": "0 errors"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/docs/test_report.md b/docs/test_report.md
new file mode 100644
index 0000000..3dcecd5
--- /dev/null
+++ b/docs/test_report.md
@@ -0,0 +1,77 @@
+# KSP 管理后台测试报告
+
+执行日期:2026-05-31
+
+## 1. 执行结论
+
+本轮完成了项目重构梳理、现有测试计划评估,并生成新的 `docs/test_plan_v2.md`。
+
+实际执行测试采用非破坏性 HTTP/API/模板级回归检查,目标是避免污染当前 `.env` 指向的真实 PostgreSQL 数据库。共执行 24 项,24 通过,0 失败。
+
+浏览器自动化和现有 Python Playwright 脚本未能执行:本机 `.venv\Scripts\python.exe` 指向不存在的 Python 安装,`py -3` 不可用;Codex in-app Browser 的 Node 会话在本机 sandbox 中连续启动失败。因此,本报告不把 JS 点击、canvas 像素、CRUD 写入类场景算作已通过。
+
+## 2. 测试环境
+
+- 运行服务:`http://127.0.0.1:9000`
+- 应用端口:`.env` 中 `APP_PORT=9000`
+- 数据库:`.env` 指向 PostgreSQL `PGHOST=192.168.195.241`、`PGDATABASE=KSP`
+- 测试方式:PowerShell `Invoke-WebRequest` / `Invoke-RestMethod`
+- 数据安全策略:不执行新增、编辑、删除、导入、对接保存等持久写入动作
+
+## 3. 已执行测试
+
+| # | 检查项 | 结果 | 详情 |
+|---:|---|---|---|
+| 1 | API health returns ok | PASS | `{"service":"ksp-data-hangar","status":"ok"}` |
+| 2 | Dashboard reachable | PASS | HTTP 200 |
+| 3 | Base shell/sidebar present | PASS | sidebar、任务运营、数据中心、燃料换算存在 |
+| 4 | Global sim time control present | PASS | `sim-time-display`、`+1d`、Today 存在 |
+| 5 | Dashboard data panels present | PASS | Tracked Assets / Active Missions / Upcoming / Status Board 存在 |
+| 6 | Asset list reachable with rows | PASS | rows=15 |
+| 7 | Asset list filters/actions present | PASS | `q`、`asset_type`、`sort`、New Asset 存在 |
+| 8 | Asset search route returns filtered page | PASS | `/assets?q=ST-01` 返回匹配页面 |
+| 9 | Asset detail reachable from list link | PASS | `/assets/fba95050-ca89-4e67-b796-66b7e1c40764?...` |
+| 10 | Asset detail dock/log modals present | PASS | `dock-modal`、`log-modal`、`saveDock`、`saveLog` 存在 |
+| 11 | Mission status board reachable | PASS | HTTP 200 |
+| 12 | Mission status board filters present | PASS | `asset_type`、`location`、`record_scope` 存在 |
+| 13 | Location board reachable | PASS | HTTP 200,`map-cv` 与 `LOC_ASSETS` 存在 |
+| 14 | Location board embeds orbital data | PASS | Keplerian/ORB/BODIES 数据存在 |
+| 15 | Timeline reachable | PASS | HTTP 200,`tlr` 存在 |
+| 16 | Timeline filters present | PASS | `tl-q`、`tls`、`tl-type`、`tl-loc`、`tl-state` 存在 |
+| 17 | Data center: Engines | PASS | rows=31 |
+| 18 | Data center: Communications | PASS | rows=31 |
+| 19 | Data center: Tanks | PASS | rows=27 |
+| 20 | Data center: Vehicles | PASS | rows=11 |
+| 21 | Fuel converter page reachable | PASS | HTTP 200 |
+| 22 | Fuel factors API returns list | PASS | count=8 |
+| 23 | Fuel convert API volume mode | PASS | mode=volume,count=8 |
+| 24 | Fuel convert invalid input rejected | PASS | HTTP 400 |
+
+## 4. 未执行/跳过项
+
+| 项目 | 状态 | 原因 |
+|---|---|---|
+| `tests/test_e2e.py` | SKIPPED | 本地 Python 不可用:`.venv` 入口坏,`py -3` 未安装 |
+| Playwright 浏览器点击测试 | SKIPPED | 浏览器自动化运行时启动失败 |
+| 主题切换、时间 modal、ESC、点击导航 | SKIPPED | 需要浏览器 JS 执行环境 |
+| 地点板 canvas 像素/点击 Jupiter/Io/Back/缩放拖拽 | SKIPPED | 需要浏览器和截图/像素采样 |
+| 时间线筛选实际生效 | SKIPPED | 需要浏览器 JS 执行环境 |
+| 日志 CRUD、对接保存、删除、导入 | SKIPPED | 当前连接真实 PostgreSQL,执行会污染数据 |
+
+## 5. 发现的问题
+
+1. 现有 `docs/test_plan.md` 与实际不一致:文档写“12 个模块”,实际只有 10 个模块。
+2. 现有 `tests/test_e2e.py` 的断言过浅,且报告名称编码损坏;它更像 smoke test,不能证明重构验收通过。
+3. `draft_board.md` 要求的 `docking_events` 表尚未落地;当前对接接口只是给当前资产新增 state 日志,没有双向关系、分离或时间敏感查询。
+4. 时间线模板存在 `onclick="tlPreset(...)"`,但代码库中未找到 `tlPreset` 实现;搜索/类型/地点/状态筛选控件也未找到绑定逻辑。
+5. 资产详情日志搜索 `ad-lq` 和类型筛选 `ad-lf` 存在 DOM,但未找到前端过滤脚本。
+6. 地点板当前用 Canvas 渐变绘制天体;尚未实现 draft 中“真实纹理 + 渲染模式切换”的目标。
+7. 燃料换算页面是前端本地计算,API 另有 `/api/v1/fuel-converter/convert`;两者的模式命名不同,后续测试需同时覆盖页面行为和 API 合约。
+
+## 6. 建议
+
+- 先修复本地 Python/Playwright 环境,恢复自动化测试可执行性。
+- 将当前 `tests/test_e2e.py` 拆成 `smoke`、`browser`、`business` 三类,避免把 DOM 存在误当成功能通过。
+- 为写入测试准备隔离数据库或事务回滚 fixture,再验证日志 CRUD、对接和分离。
+- 对时间线和资产详情筛选先补前端逻辑,再纳入 P1 浏览器回归。
+- 对 `docking_events` 明确是“本期必须实现”还是“后续 backlog”;否则测试计划应将其标为未实现验收项。
diff --git a/docs/timeline_page_retest_report_2026-05-31.md b/docs/timeline_page_retest_report_2026-05-31.md
new file mode 100644
index 0000000..ecb200d
--- /dev/null
+++ b/docs/timeline_page_retest_report_2026-05-31.md
@@ -0,0 +1,272 @@
+# 时间线页面复测报告
+
+日期:2026-05-31
+
+## 结论
+
+其他团队的修改有部分推进,但时间线页面还不能算完成。已改善的点包括:`scale=day` 时下拉框能正确显示 Day、segment 外层宽度开始使用 `track_width_pct`、asset 名称已具备链接、`_partial=1` 从 HTML 改成了 JSON,单次响应体从上一轮约 315 KB 降到当前约 128 KB。
+
+但复测发现新的关键回归:页面加载后客户端 JS 会直接替换 `#tl-canvas.innerHTML`,把时间刻度行清掉;滚轮/按钮缩放没有可靠生效;Auto scale 在手动范围下仍然错误;事件点仍然只是无文字小点;资产筛选仍不是需求里的“type/location 筛选后资产多选默认全选”。
+
+## 测试环境
+
+- 本地服务:`http://127.0.0.1:9000`
+- 页面:`/mission-preview/timeline`
+- 自动化:Codex in-app Browser + 现有 `tests/test_e2e.py`
+- 当前工作区包含大量未提交改动,本报告只做复测与记录,不修改业务代码。
+
+## 执行的检查
+
+### HTTP / 路由检查
+
+1. `GET /mission-preview/timeline`
+ - HTTP 200
+ - 响应体约 512 KB
+ - 包含 `tl-viewport` / `tl-canvas`
+
+2. `GET /mission-preview/timeline?_partial=1`
+ - HTTP 200
+ - `Content-Type: application/json`
+ - 响应体约 128 KB
+ - `scale=year`
+ - `bucket_count=15`
+ - `rows=14`
+
+3. `GET /mission-preview/timeline?scale=auto&start=2057-04-24&end=2057-07-21&range_mode=manual&_partial=1`
+ - HTTP 200
+ - `range_start=2057-04-24T00:00`
+ - `range_end=2057-07-21T00:00`
+ - 实际 `scale=year`
+ - 实际 `bucket_count=1`
+ - 这是错误结果。88 天范围应该自动进入 Day 或至少 Month。
+
+4. `GET /mission-preview/timeline?scale=day&start=2057-04-24&end=2057-07-21&range_mode=manual&_partial=1`
+ - HTTP 200
+ - `scale=day`
+ - `bucket_count=89`
+ - 说明显式 Day 路径可工作。
+
+### 浏览器 DOM 检查
+
+初始打开 `/mission-preview/timeline` 后,等待 JS 执行完成:
+
+- `#tl-canvas.children.length = 14`
+- DOM 中 asset 行数 = 14
+- segment 数 = 116
+- event 数 = 238
+- `timeline_json.scale = year`
+- `timeline_json.bucket_count = 15`
+- `select[name=scale].value = year`
+- `window.tlZoom = undefined`
+- `window.tlResetView = undefined`
+
+重要现象:客户端渲染后,`#tl-canvas` 的第一个子元素已经是 `Europa Outpost` 的资产行,不再是时间刻度行。也就是说,服务端首屏渲染出来的刻度行被 JS 清掉了。
+
+### 现有 E2E
+
+执行命令:
+
+```powershell
+python tests\test_e2e.py
+```
+
+结果:
+
+- 总计 36 项
+- 通过 34 项
+- 失败 2 项
+- 失败项均为时间线:
+ - `8.1 渲染`
+ - `8.2 数据 -- 0 rows`
+
+说明:现有 E2E 仍在找旧 DOM 选择器 `#tls` / `.tl-r`,已经与当前实现失配。这个失败不等价于页面完全不可用,但说明测试套件没有跟随时间线重构更新,无法作为时间线验收依据。
+
+## 逐项复测结果
+
+### 1. 滚轮缩放卡顿
+
+状态:部分改善,但未通过。
+
+改善点:
+
+- `_partial=1` 改成 JSON 后,单次 partial 数据量下降到约 128 KB。
+- 新实现意图是在客户端用 `timeline_json` 直接重绘,理论上可以避免上一版每次 wheel 都请求后端。
+
+仍存在的问题:
+
+- 实测滚轮操作没有改变 hidden `start/end`,也没有改变 segment 位置。
+- `Zoom +` / `Zoom -` / `Reset View` 按钮仍然存在,但模板里没有定义 `tlZoom()` 和 `tlResetView()`。
+- 客户端 zoom 逻辑只调整 `bucket_count`,没有按新的 `range_start/range_end` 重新计算每个 segment/event 相对位置。即使 wheel 触发成功,也会出现“缩放但不按新窗口重定位”的问题。
+
+证据:
+
+- `window.tlZoom` 为 `undefined`
+- `window.tlResetView` 为 `undefined`
+- 点击按钮对应的 inline handler 是 `tlZoom(1.3)` / `tlResetView()`
+
+### 2. 滚轮缩放丢失日志/资产
+
+状态:旧丢参问题缓解,但新实现仍有风险。
+
+已改善:
+
+- 客户端缩放不再发 AJAX,因此上一版 wheel AJAX 丢 `asset_ids` / `record_scope` 的问题不再以同样形式出现。
+- URL 手动传 2 个 `asset_ids` 时,DOM 确实只渲染这 2 个 asset。
+
+仍存在的问题:
+
+- 默认资产多选框没有任何选中项,但页面渲染 14 个 asset。UI 表达仍然是“未选择”,实际语义却是“全部显示”。
+- 客户端缩放数据来自初始 `timeline_json`,如果后续改为 partial 更新,需要重新验证所有 filter 参数是否同步。
+
+证据:
+
+- 默认打开时:asset options = 14,selected count = 0,timeline rows = 14。
+- 加 `asset_ids=A&B` 打开时:selected count = 2,timeline rows = 2。
+
+### 3. 缩放时自动切换年/月/日
+
+状态:未通过。
+
+显式 `scale=day` 已经可以显示 Day,并且 JSON 返回 `bucket_count=89`。但 `scale=auto` 或不传 `scale` 且传入 88 天手动范围时,后端仍返回 `scale=year`、`bucket_count=1`。
+
+根因判断:
+
+- `mission_timeline_preview()` 在解析 `range_start/range_end` 之前先调用 `_resolve_timeline_scale(request.args.get("scale"), initial_range_start, initial_range_end)`。
+- 这导致 auto scale 使用的是默认全量时间范围,而不是用户当前手动范围。
+- 此外 `` 永远不会保持 Auto selected,因为后端最后传给模板的是解析后的 `year/month/day`,不是原始 scale mode。
+
+### 4. Type/location 筛选后资产多选默认全选
+
+状态:未通过。
+
+当前行为:
+
+- Type 和 Location 仍是普通单选下拉。
+- Assets 仍是原生 ``。
+- 默认 selected count = 0,但页面显示全部资产。
+- 没有 checkbox dropdown、Select All、Clear、已选数量展示。
+- 没有 State 筛选。
+
+需求目标是“先根据 type 和 location 进行筛选,筛选结果进入下拉多选框,默认全选,仅展示选中的 asset”。当前仍是“空 asset_ids 表示全部”,没有做到视觉和语义一致。
+
+### 5. Event point 显示效果
+
+状态:未通过。
+
+当前 DOM:
+
+- `.tl-evt` 数量 = 238
+- 有可见文本的 `.tl-evt` 数量 = 0
+- connector 数量 = 0
+- state node 与普通 event 没有稳定的 class/data 区分
+
+后端仍然计算了事件 label 宽度、label side、track、connector height,但当前客户端渲染没有使用这些字段。页面仍然只是 7px 小圆点,不能扫描事件内容。
+
+### 6. 点击 asset 跳转到 asset 页面
+
+状态:基本通过,但还需要人工点击验收。
+
+当前 asset label 已渲染为链接:
+
+```text
+/assets/fba95050-ca89-4e67-b796-66b7e1c40764?sim_time=2060-08-11T10:00
+```
+
+这比上一版 plain div 有明显改善。需要注意的是当前 `simulation_time` 来自 DB/session,复测时已变成 `2060-08-11T10:00`,不是原本默认的 `2060-03-12T09:00`。这不是时间线链接本身的问题,但全局 simulation time 被写 DB 后会影响所有页面和测试基线,建议测试报告里固定 sim_time。
+
+## 新发现的问题
+
+### A. 时间刻度行被客户端渲染清除
+
+模板服务端先渲染了刻度行:
+
+```html
+
+
scale labels...
+ ...
+
+```
+
+但脚本执行:
+
+```js
+if (tlCanvas) tlCanvas.innerHTML = buildHTML(tlData);
+```
+
+`buildHTML()` 只生成 asset rows,不生成 scale labels。因此用户最终看到的 DOM 没有时间刻度行。
+
+### B. 缩放按钮是坏控件
+
+页面底部仍显示:
+
+- `Zoom +`
+- `Zoom -`
+- `Reset View`
+
+但没有定义对应函数:
+
+- `window.tlZoom === undefined`
+- `window.tlResetView === undefined`
+
+这些按钮应删除、接入同一套 zoom controller,或改成有效按钮。
+
+### C. 客户端缩放算法不完整
+
+当前 wheel handler 更新:
+
+```js
+tlData.range_start = fmtDate(newFrom)
+tlData.range_end = fmtDate(newTo)
+tlData.bucket_count = Math.round(scale)
+```
+
+但 segment/event 的 `start_position`、`display_end_position`、`position` 都是后端基于旧 range 计算出的 bucket position。只改 `bucket_count` 无法正确表达新 range。缩放后必须重新按时间戳计算位置,或向后端请求基于新 range 的 JSON。
+
+### D. `_partial=1` 合约已变,但旧 partial 模板仍在仓库
+
+当前路由 `_partial=1` 返回 JSON,不再使用 `mission_timeline_partial.html`。但该模板仍存在且是旧 HTML 片段。建议清理或明确废弃,避免后续维护者误用。
+
+### E. 现有 E2E 已过期
+
+`tests/test_e2e.py` 仍验证旧选择器:
+
+- `#tls`
+- `.tl-r`
+
+当前实现已经没有这些节点,所以时间线测试失败。需要更新测试,让它验证当前关键行为,而不是旧 DOM 名称。
+
+## 建议修复优先级
+
+### P0
+
+1. 恢复最终 DOM 的时间刻度行,或让客户端 `buildHTML()` 同时渲染刻度。
+2. 修复 auto scale:先确定手动 range,再基于最终 range 解析 scale。
+3. 删除或实现 `tlZoom()` / `tlResetView()`。
+4. 让 wheel zoom 要么真正按时间戳重新计算位置,要么改回请求 `_partial=1` JSON 并完整替换数据。
+5. 更新 E2E 时间线选择器和断言。
+
+### P1
+
+1. 实现资产 checkbox dropdown,默认全选筛选后的候选资产。
+2. 增加 State 筛选。
+3. 让 selected count、URL 参数、实际 rows 三者一致。
+4. 渲染 event labels、state-node/event 区分和 connector。
+
+### P2
+
+1. 清理废弃的 `mission_timeline_partial.html`。
+2. 固定测试用 `sim_time`,避免 DB 全局 simulation time 污染测试基线。
+3. 给 timeline JSON 增加 schema/契约测试。
+
+## 建议验收用例
+
+1. 打开 `/mission-preview/timeline?sim_time=2060-03-12T09:00`,确认有时间刻度行,首行不是 asset 文本。
+2. 默认打开后,asset dropdown 显示所有候选 asset 已选,rows 数等于 selected count。
+3. 选择 type/location 后,asset dropdown 只包含筛选结果,并默认全选。
+4. 取消一个 asset,确认该 asset row 立即消失或提交后消失。
+5. 传 `start=2057-04-24&end=2057-07-21&range_mode=manual&scale=auto`,确认 scale 解析为 Day 或预期精度。
+6. 使用滚轮缩放,确认 hidden start/end、刻度标签、segment/event 位置一起变化。
+7. 点击 `Zoom +` / `Zoom -` / `Reset View`,确认没有 JS error 且视图变化符合按钮含义。
+8. 点击 asset 名称,确认跳到 `/assets/?sim_time=...`。
+9. Hover event point,确认 tooltip 有 title/time;肉眼可见的事件标签或聚合提示存在。
+10. 执行更新后的 E2E,时间线模块不再依赖旧 `#tls` / `.tl-r`。
diff --git a/docs/timeline_page_review.md b/docs/timeline_page_review.md
new file mode 100644
index 0000000..c638ebe
--- /dev/null
+++ b/docs/timeline_page_review.md
@@ -0,0 +1,293 @@
+# Timeline Page Review and Refactor Plan
+
+Date: 2026-05-31
+
+## Context
+
+This project is a Flask/Jinja/SQLAlchemy KSP operations admin app. The original data center still covers engines, communications, tanks, vehicle costs, fuel conversion, workbook import, and Wiki publishing helpers. The recent refactor described in `draft_board.md` expands the app into mission operations:
+
+- `Asset`, `AssetLogEntry`, and `AssetStateNode` are now the core timeline data model.
+- Current state, current location, current mission, upcoming events, status board, location board, asset catalog, and timeline are derived from logs at `simulation_time`.
+- Logs are split into `state` intervals and `event` points; state intervals may contain timed state nodes.
+- Location is intended to move from free text toward a structured hierarchy.
+- Timeline is intended to be a read-only navigable view with wheel zoom, drag pan, type/location/state/date filters, and a filtered asset selector.
+
+Current timeline implementation lives mainly in:
+
+- `app/routes/web.py`: `/mission-preview/timeline`, scale/range helpers, row/segment/event building.
+- `app/templates/mission_timeline_preview.html`: full page, filter bar, wheel zoom script, tooltip script.
+- `app/templates/mission_timeline_partial.html`: AJAX replacement fragment.
+- `app/static/styles.css`: legacy `.tl-*` styles plus shared design system.
+
+## Current Timeline Flow
+
+1. The route loads every asset with logs through `_load_assets_with_logs()`.
+2. It builds snapshot rows through `_build_mission_board_rows()`.
+3. It filters rows by search, `asset_type`, `location`, `record_scope`, and optional `asset_ids`.
+4. It resolves the visible time range and scale.
+5. `_build_timeline_rows()` converts state intervals into segments and event/state nodes into event markers.
+6. The template renders one sticky asset-name column and one scrollable absolute-position lane per asset.
+7. Wheel zoom computes a new `start`/`end`, fetches `_partial=1`, parses the returned HTML, and replaces `#tl-canvas.innerHTML`.
+
+## Findings
+
+### 1. Wheel zoom is janky by design
+
+The wheel handler performs a backend request and a large DOM replacement for zoom. A sampled partial request returned about 315 KB in roughly 416 ms and contained 108 segment elements plus 225 event elements. Initial rendered `#tl-canvas` HTML was about 335 KB.
+
+The handler also throttles wheel input with a fixed 400 ms timeout. That makes zoom feel stepped and laggy, especially because each accepted wheel event waits for server render, network, HTML parsing, and full canvas replacement.
+
+Root causes:
+
+- Zoom is server-rendered instead of client-side transformed.
+- The whole canvas is replaced, not just scale metadata or a small diff.
+- No request cancellation, no stale response guard, and no loading/error state.
+- The wheel math uses only the current hidden `start`/`end`, not the cursor position as the zoom anchor.
+
+### 2. Zoom can appear to lose logs/assets
+
+There are two separate problems here.
+
+First, the wheel AJAX URL preserves `q`, `scale`, `asset_type`, and `location`, but it does not preserve `asset_ids` or `record_scope`. I reproduced this by opening the timeline with two selected assets. Before wheel zoom, the page showed 2 rows. After one wheel zoom, the canvas showed 14 rows while the asset multi-select still displayed the original 2 selected assets. The UI state and rendered data diverged.
+
+Second, segment width is rendered incorrectly. The backend computes both `track_width_pct` and `body_width_pct`, but the template uses only `body_width_pct` as the absolute element width. Because `body_width_pct` is usually `100%`, each segment starts at its own left offset and then stretches to the end of the lane. Later segments visually cover earlier ones, which can look like logs disappeared or merged.
+
+Root causes:
+
+- Missing query parameters in wheel AJAX.
+- Partial replacement updates only the canvas, not metrics, range display, or selected filter state.
+- Template uses `seg.body_width_pct` where it needs the actual timeline span, likely `seg.track_width_pct` on the outer element and `seg.body_width_pct` only on an inner body.
+
+### 3. Scale does not auto-switch between year/month/day
+
+The backend can auto-resolve scale when no `scale` query parameter is supplied. But wheel zoom always sends the current `` value, so the backend never gets a chance to auto-switch. I reproduced an 88-day visible range that still rendered a single `2057` year label instead of month/day labels.
+
+There is also a template bug: only the Month option has a conditional `selected` attribute. If the route renders `scale=day`, the labels are daily, but the select still displays Year. That means the next wheel AJAX reads `scale=year` from the control and corrupts the intended scale.
+
+Root causes:
+
+- Manual scale and auto scale are conflated.
+- Wheel zoom always sends a scale even when the user has not explicitly locked one.
+- Year and Day options are missing selected-state rendering.
+
+### 4. Filter model does not match the desired workflow
+
+Desired behavior: first filter by type and location, then show a dropdown multi-select of matching assets, default all selected, and render only selected assets.
+
+Current behavior:
+
+- Type and Location are single native selects.
+- Asset selection is a native multi-select with no explicit default selections. Empty selection means "all", but visually it looks like nothing is selected.
+- Asset options are derived from filtered rows, but wheel zoom does not preserve selected `asset_ids`.
+- State filter is not implemented.
+- Location filtering is exact string matching, not hierarchical matching.
+- There is no Select All / Clear affordance.
+
+Root causes:
+
+- The route treats asset selection as optional narrowing instead of an explicit selected set.
+- Filter state is encoded inconsistently between server render, form controls, and wheel AJAX.
+- Location taxonomy is still free-text-derived.
+
+### 5. Event point display is too weak
+
+The backend calculates event label width, label side, label span, event tracks, and state-node connector height. The templates do not render those labels, tracks, or connectors. They render only a 7 px dot at `top:3px` inside a fixed 26 px row.
+
+Effects:
+
+- Many event points collapse into indistinguishable dots.
+- State nodes and standalone event points look nearly identical.
+- Event labels are only available through hover/title, so scanning the timeline is hard.
+- Track assignment does not help because row height is fixed and event track fields are unused.
+
+Root causes:
+
+- The presentation layer is a simplified version of a richer backend layout model.
+- Fixed row height prevents multi-track event rendering.
+- Event marker design has no density strategy for close events.
+
+### 6. Asset rows do not link to asset detail
+
+The asset name cell is a plain `div` with a `title`. Segments and event dots link to entry edit pages, not asset pages. There is no click target to navigate from a timeline row to `/assets/`.
+
+Root cause:
+
+- `_build_timeline_rows()` includes `asset_id` but not an `asset_url`, and the template does not render the label as an anchor.
+
+## Proposed Refactor
+
+### A. Make timeline state explicit
+
+Create one canonical timeline state object:
+
+- `sim_time`
+- `range_start`
+- `range_end`
+- `scale_mode`: `auto`, `year`, `month`, or `day`
+- `asset_type`
+- `location`
+- `state`
+- `asset_ids`
+- `record_scope`
+- `q`
+
+Rules:
+
+- `scale_mode=auto` lets the backend choose year/month/day from range size.
+- Explicit year/month/day locks the scale until the user returns to auto.
+- Type/location/state changes rebuild the candidate asset list.
+- Candidate assets default to all selected.
+- Empty selected assets should mean "no assets selected", not "all", once the new selector is implemented.
+
+### B. Split server data from interaction
+
+Keep the server responsible for canonical data and initial render, but move wheel zoom/pan to a small client-side controller:
+
+- Hydrate timeline rows as JSON or compact data attributes.
+- Render positions from `range_start`, `range_end`, and resolved scale in the browser.
+- On wheel, update range in memory immediately and re-render positions without a backend round trip.
+- Debounce URL synchronization with `history.replaceState`.
+- Fetch server data only when filters or simulation time change, or when the visible range moves outside loaded data if pagination/windowing is introduced.
+
+If a full client renderer is too large for this pass, use an intermediate improvement:
+
+- Preserve all query params in AJAX.
+- Use `AbortController` to cancel stale partial requests.
+- Add a request sequence id so late responses cannot overwrite newer views.
+- Replace the whole canvas outer HTML, not only inner HTML, and update metrics/range display/filter hidden fields together.
+
+Recommended path: implement the intermediate fix first, then move to client-side zoom if performance still feels poor.
+
+### C. Fix segment and row rendering
+
+Use the backend track model correctly:
+
+- Render each segment wrapper with `left: seg.left_pct` and `width: seg.track_width_pct`.
+- Render an inner segment body with `width: seg.body_width_pct`.
+- Use `state_track_count` and `event_track_count` to compute row height.
+- Preserve compact labels but do not let a segment occupy the rest of the lane by accident.
+
+### D. Implement the desired filter UX
+
+Filter bar layout:
+
+- Search input.
+- Type multi/single filter depending on final preference; for this requirement, type can remain a dropdown filter.
+- Location dropdown filter using the future hierarchy matcher when available.
+- State dropdown filter.
+- Asset dropdown multi-select with checkboxes, Select All, Clear, and selected count.
+
+Data behavior:
+
+- On initial load, after type/location/state filters are applied, all matching assets are selected.
+- User deselection is explicit and survives zoom/pan.
+- URL serializes selected ids so refresh/share keeps the same view.
+- The rendered rows always match the selected assets shown in the selector.
+
+### E. Improve event point design
+
+Recommended event visual model:
+
+- State intervals remain colored horizontal bars.
+- State nodes render as small anchored ticks connected to their parent interval, with a tiny label when space allows.
+- Standalone event points render as diamond or pin markers, visually distinct from state nodes.
+- Event labels use collision tracks when the scale has room; dense views collapse labels into count clusters or show labels only for selected/hovered rows.
+- Hover/focus tooltip shows full title, date/time, asset, location/state, and edit link.
+
+### F. Add asset navigation
+
+Add `asset_url` to timeline rows and render the sticky asset label as an anchor:
+
+- Normal click opens asset detail with current `sim_time`.
+- Segment/event click keeps existing entry-edit behavior.
+- Optional secondary "open asset" affordance can be added in tooltip for segments/events.
+
+## End-to-End Verification Plan
+
+### 1. Static and unit-level checks
+
+- Assert `_resolve_timeline_scale(None, start, end)` returns day/month/year at the intended thresholds.
+- Assert explicit `scale=year/month/day` remains locked.
+- Assert timeline rows include `asset_url`.
+- Assert every segment has `left_pct`, `track_width_pct`, and inner `body_width_pct` with valid percentages.
+- Assert filters preserve `asset_ids`, `record_scope`, `q`, type, location, state, range, and scale mode.
+
+### 2. Flask route tests
+
+Use a deterministic fixture with at least:
+
+- 4 assets across 2 types and 2 locations.
+- State intervals with overlapping and non-overlapping ranges.
+- Standalone event points.
+- State nodes inside intervals.
+- One retired asset.
+
+Route assertions:
+
+- `/mission-preview/timeline` renders all matching assets selected by default.
+- `asset_type + location` filters shrink candidate assets.
+- `asset_ids` renders only selected assets.
+- `scale_mode=auto` switches from year to month to day as range shrinks.
+- Partial responses, if retained, include enough metadata to update metrics and range display.
+
+### 3. Browser E2E checks
+
+Run against local server on `http://127.0.0.1:9000`.
+
+Core cases:
+
+1. Open `/mission-preview/timeline`.
+2. Select type and location filters.
+3. Verify the asset dropdown contains only matching assets and all are checked.
+4. Uncheck one asset.
+5. Verify its row disappears and checked count updates.
+6. Wheel zoom in repeatedly.
+7. Verify visible rows still match checked assets.
+8. Verify scale auto-switches from Year to Month to Day at thresholds.
+9. Verify no console errors.
+10. Click a sticky asset name and verify navigation to `/assets/`.
+11. Go back, click a segment/event marker, and verify it still opens the entry edit page.
+12. Hover/focus an event marker and verify tooltip contains title and time.
+
+Performance cases:
+
+- Measure accepted wheel-to-DOM-update latency with `performance.now()` in the browser.
+- Target: under 50 ms for client-side zoom, or under 150 ms for AJAX fallback on the fixture dataset.
+- Verify rapid wheel input does not apply stale responses out of order.
+- Verify no full-page navigation happens during wheel zoom.
+
+Visual cases:
+
+- Capture screenshots at 1440x900 and 390x844.
+- Verify event labels/markers do not incoherently overlap.
+- Verify row heights remain stable and no text spills outside controls.
+- Verify year/month/day labels match selected or auto-resolved scale.
+
+### 4. Regression checks for the reported bugs
+
+- Wheel jank: repeated wheel input updates range smoothly without waiting on full server-rendered HTML.
+- Lost logs/assets: after selecting 2 assets, wheel zoom still shows exactly those 2 rows.
+- Auto scale: an 88-day range shows day labels, a multi-month range shows month labels, a multi-year range shows year labels.
+- Filter workflow: type/location filters rebuild the asset dropdown and default to all matching assets selected.
+- Event points: standalone events and state nodes are visually distinct and readable.
+- Asset navigation: clicking a timeline row label opens the asset detail page.
+
+## Suggested Implementation Order
+
+1. Fix template correctness: selected states for year/day scale and segment width rendering.
+2. Preserve all query params in wheel AJAX and guard stale responses.
+3. Add `asset_url` and clickable asset labels.
+4. Replace native asset multi-select with explicit checkbox dropdown and selected-count model.
+5. Add state filter and hierarchical location matching hook.
+6. Render event labels/tracks/connectors using the data already computed by the backend.
+7. Decide whether to keep AJAX zoom or replace it with a client-side timeline controller.
+
+## Acceptance Criteria
+
+- The timeline never shows a different asset set than the filter UI says is selected.
+- Wheel zoom never drops `asset_ids`, `record_scope`, `q`, type, location, or state filters.
+- Auto scale and the scale control agree with each other.
+- State intervals render at their true clipped span.
+- Event points are readable enough to scan without mandatory hover.
+- Every asset row has a direct asset-detail navigation path.
+- E2E tests cover the six reported issues and fail on the current implementation.
diff --git a/prototypes/asset-entry-hifi/card-workbench.html b/prototypes/asset-entry-hifi/card-workbench.html
new file mode 100644
index 0000000..8a876b7
--- /dev/null
+++ b/prototypes/asset-entry-hifi/card-workbench.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+ Asset Entry Edit Hifi 04 - Card Workbench
+
+
+
+
+
+ Grouped Workbench
把编辑页拆成 Entry、Window、Context、Nodes 四个工作区 适合后续在真实模板里渐进替换:字段按语义分组,State Node 卡片强调“时间 + 事件 + 详情”。
Semantic groups Node cards
+
+
+
+
+
+
+ Summary Carrying structural truss and greenhouse kit; 105 km/s, 31-day transition.
+
+
+
+ Note Delta-v reserve remains above plan. Crew not aboard.
+
+
+ Derived Preview
What boards will show
+ Current Location Earth to Mars Transfer
Mission Support Mars One Campus
State In Transit
+
+
+
+
+
+
+
+
diff --git a/prototypes/asset-entry-hifi/command-console.html b/prototypes/asset-entry-hifi/command-console.html
new file mode 100644
index 0000000..9f00956
--- /dev/null
+++ b/prototypes/asset-entry-hifi/command-console.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+ Asset Entry Edit Hifi 01 - Command Console
+
+
+
+
+
+
+
+
+
Edit State Interval
+
Support mission transfer to Mars One Campus
+
主信息在左侧保持完整编辑能力,右侧把 State Node 渲染成任务控制台式事件串,一眼能看出节点时间、标题和备注。
+
+
+ Asset XH-02 Taibai
+ State In Transit
+ Sim 2060-03-12 09:00
+
+
+
+
+
+
+
Required Fields
Entry Details
+
State Interval
+
+
+
+
+
+
+
State Nodes
What Happened When
+
4 nodes + Add Node
+
+
+
+ Feb 26 06:00
+
+
+
+ Mar 04 14:30
+
+
+
+ Mar 18 09:15
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prototypes/asset-entry-hifi/dense-ops.html b/prototypes/asset-entry-hifi/dense-ops.html
new file mode 100644
index 0000000..97db589
--- /dev/null
+++ b/prototypes/asset-entry-hifi/dense-ops.html
@@ -0,0 +1,61 @@
+
+
+
+
+
+ Asset Entry Edit Hifi 03 - Dense Ops
+
+
+
+
+
+ Operational Dense Form
高信息密度,但 State Node 不再是难读输入堆 这版更接近后台运维工具:主字段紧凑排布,State Node 用表格维护,同时右侧提供按时间生成的阅读摘要。
Mode state Edit URL ready
+
+
+
+
+
+
+
+
+
+
+
diff --git a/prototypes/asset-entry-hifi/review-split.html b/prototypes/asset-entry-hifi/review-split.html
new file mode 100644
index 0000000..73b837e
--- /dev/null
+++ b/prototypes/asset-entry-hifi/review-split.html
@@ -0,0 +1,59 @@
+
+
+
+
+
+ Asset Entry Edit Hifi 05 - Review Split
+
+
+
+
+
+ Edit and Read Side by Side
左边编辑,右边实时审阅这条日志会如何被理解 这版适合减少误填:用户编辑所有原始字段,同时右侧以可读时间线预览当前日志、状态窗口和节点含义。
Preserves all controls Clear state nodes
+
+
+
+ Raw Form
Editable Source Data
+
+
+
+
+ Interpretation Preview
How Users Read It Current clock inside interval
+
+
+
Asset XH-02
+
State In Transit
+
Location Transfer
+
Nodes 4
+
+
+
Feb 26 06:00
State interval begins Departure burn completed. From this moment, boards should show XH-02 in Earth to Mars Transfer.
+
Mar 04 14:30
Mid-course correction 1 Trajectory refined while remaining in the same parent state.
+
Mar 12 09:00
Current simulation time This marker is not saved; it explains why this interval is active right now.
+
Mar 29 18:00
Expected interval end Mars capture window closes this state and hands off to Mars Orbit.
+
+
+
+
+
+
+
+
+
diff --git a/prototypes/asset-entry-hifi/shared.css b/prototypes/asset-entry-hifi/shared.css
new file mode 100644
index 0000000..04575c9
--- /dev/null
+++ b/prototypes/asset-entry-hifi/shared.css
@@ -0,0 +1,188 @@
+:root {
+ --bg: #0b0d12;
+ --panel: #141821;
+ --panel-2: #1b2130;
+ --panel-3: #222a3a;
+ --line: rgba(226, 232, 240, .12);
+ --line-strong: rgba(226, 232, 240, .2);
+ --text: #eef4ff;
+ --muted: #93a4bb;
+ --faint: #65758a;
+ --blue: #4f8cff;
+ --cyan: #35c7d8;
+ --green: #39d98a;
+ --amber: #f3b64a;
+ --red: #ff6575;
+ --purple: #a98bff;
+ --shadow: 0 24px 70px rgba(0, 0, 0, .28);
+ --radius: 8px;
+ --mono: "Cascadia Code", "SF Mono", Consolas, monospace;
+ --sans: "Segoe UI", "Microsoft YaHei UI", system-ui, sans-serif;
+}
+
+* { box-sizing: border-box; }
+html, body { margin: 0; min-height: 100%; }
+body {
+ color: var(--text);
+ font-family: var(--sans);
+ background:
+ radial-gradient(circle at 20% -10%, rgba(79, 140, 255, .22), transparent 32%),
+ radial-gradient(circle at 85% 5%, rgba(53, 199, 216, .14), transparent 30%),
+ linear-gradient(180deg, #0b0d12 0%, #111622 100%);
+}
+a { color: inherit; text-decoration: none; }
+.shell { width: min(1480px, calc(100vw - 32px)); margin: 0 auto; padding: 18px 0 34px; }
+.topbar {
+ position: sticky; top: 12px; z-index: 5;
+ display: flex; align-items: center; justify-content: space-between; gap: 16px;
+ padding: 11px 14px; margin-bottom: 16px;
+ border: 1px solid var(--line); border-radius: var(--radius);
+ background: rgba(20, 24, 33, .88); backdrop-filter: blur(16px);
+ box-shadow: var(--shadow);
+}
+.brand { display: grid; gap: 2px; }
+.brand span { color: var(--muted); font: 700 11px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; }
+.brand strong { font: 700 18px/1.1 var(--mono); }
+.nav { display: flex; gap: 6px; flex-wrap: wrap; }
+.nav a {
+ padding: 7px 10px; border: 1px solid var(--line); border-radius: 6px;
+ color: var(--muted); background: rgba(255, 255, 255, .025); font-size: 12px; font-weight: 700;
+}
+.nav a.active { color: #fff; border-color: rgba(79, 140, 255, .5); background: rgba(79, 140, 255, .18); }
+.hero {
+ display: flex; justify-content: space-between; gap: 18px; align-items: flex-end;
+ padding: 18px; margin-bottom: 14px;
+ border: 1px solid var(--line); border-radius: var(--radius);
+ background: linear-gradient(135deg, rgba(20, 24, 33, .95), rgba(27, 33, 48, .82));
+}
+.kicker, .label {
+ color: var(--muted); font: 700 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase;
+}
+h1, h2, h3, p { margin: 0; }
+h1 { margin-top: 6px; font: 700 clamp(24px, 3vw, 38px)/1.06 var(--mono); letter-spacing: 0; }
+h2 { font: 700 18px/1.2 var(--mono); }
+h3 { font: 700 14px/1.35 var(--sans); }
+.sub { color: var(--muted); margin-top: 7px; line-height: 1.55; font-size: 13px; max-width: 760px; }
+.hero-meta { display: flex; gap: 8px; flex-wrap: wrap; justify-content: flex-end; }
+.chip {
+ display: inline-flex; align-items: center; gap: 7px;
+ min-height: 28px; padding: 0 9px; border-radius: 6px;
+ border: 1px solid var(--line); background: rgba(255,255,255,.035);
+ color: var(--muted); font: 700 12px/1 var(--mono);
+}
+.chip strong { color: var(--text); }
+.chip.blue { color: #cfe0ff; border-color: rgba(79,140,255,.38); background: rgba(79,140,255,.12); }
+.chip.green { color: #ceffe6; border-color: rgba(57,217,138,.34); background: rgba(57,217,138,.1); }
+.chip.amber { color: #ffe7b7; border-color: rgba(243,182,74,.32); background: rgba(243,182,74,.1); }
+.panel {
+ border: 1px solid var(--line); border-radius: var(--radius);
+ background: rgba(20, 24, 33, .9); box-shadow: 0 14px 40px rgba(0,0,0,.16);
+}
+.panel-head {
+ display: flex; justify-content: space-between; gap: 12px; align-items: flex-start;
+ padding: 14px 15px; border-bottom: 1px solid var(--line);
+}
+.panel-body { padding: 15px; }
+.grid-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 11px; }
+.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 11px; }
+.span-2 { grid-column: span 2; }
+.span-3 { grid-column: span 3; }
+label.field { display: grid; gap: 6px; min-width: 0; }
+.field input, .field select, .field textarea {
+ width: 100%; min-height: 38px; padding: 9px 10px;
+ border: 1px solid var(--line); border-radius: 6px;
+ background: rgba(11, 13, 18, .66); color: var(--text);
+ font: 500 13px/1.3 var(--sans);
+}
+.field textarea { min-height: 82px; resize: vertical; }
+.field input:focus, .field select:focus, .field textarea:focus { outline: none; border-color: rgba(79,140,255,.72); box-shadow: 0 0 0 3px rgba(79,140,255,.12); }
+.field input[disabled] { color: var(--muted); background: rgba(255,255,255,.04); }
+.button-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
+.spacer { flex: 1; }
+.btn {
+ min-height: 34px; padding: 0 12px; border-radius: 6px; border: 1px solid var(--line);
+ background: rgba(255,255,255,.04); color: var(--muted);
+ font: 700 12px/1 var(--sans); cursor: default;
+}
+button.btn { cursor: pointer; }
+.btn.primary { color: white; border-color: rgba(79,140,255,.7); background: linear-gradient(135deg, #4f8cff, #2d63d8); }
+.btn.danger { color: #ffd5da; border-color: rgba(255,101,117,.45); background: rgba(255,101,117,.1); }
+.btn.soft { color: #dbe7ff; border-color: rgba(79,140,255,.28); background: rgba(79,140,255,.1); }
+.node-controls { display: flex; gap: 7px; align-items: center; flex-wrap: wrap; }
+.node-count { color: var(--cyan); font: 700 12px/1 var(--mono); }
+.node-card {
+ position: relative; display: grid; gap: 9px; padding: 11px;
+ border: 1px solid var(--line); border-radius: 7px; background: rgba(27, 33, 48, .75);
+}
+.node-card::before { content: ""; position: absolute; left: -1px; top: 10px; bottom: 10px; width: 3px; border-radius: 3px; background: var(--cyan); }
+.node-card.warn::before { background: var(--amber); }
+.node-card.good::before { background: var(--green); }
+.node-top { display: grid; grid-template-columns: 132px minmax(0, 1fr) auto; gap: 8px; align-items: center; }
+.time-badge {
+ display: inline-grid; gap: 2px; justify-items: start;
+ padding: 7px 8px; border-radius: 6px; background: rgba(53,199,216,.1); border: 1px solid rgba(53,199,216,.24);
+ color: #c8f8ff; font: 700 11px/1.1 var(--mono);
+}
+.time-badge small { color: var(--muted); font: 700 10px/1 var(--mono); }
+.node-title { min-width: 0; }
+.node-title strong { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
+.node-title span { color: var(--muted); font-size: 12px; }
+.node-fields { display: grid; grid-template-columns: minmax(0, 1fr) 170px; gap: 8px; }
+.node-detail { grid-column: 1 / -1; }
+.timeline-rail { display: grid; gap: 0; }
+.rail-node { display: grid; grid-template-columns: 150px 30px minmax(0, 1fr); gap: 9px; min-height: 82px; }
+.rail-time { color: var(--cyan); font: 700 12px/1.3 var(--mono); padding-top: 4px; text-align: right; }
+.rail-line { position: relative; display: flex; justify-content: center; }
+.rail-line::before { content: ""; position: absolute; top: 0; bottom: 0; width: 2px; background: rgba(226,232,240,.12); }
+.rail-dot { position: relative; z-index: 1; width: 14px; height: 14px; margin-top: 2px; border-radius: 50%; background: var(--cyan); box-shadow: 0 0 0 4px rgba(53,199,216,.14); }
+.rail-copy { padding-bottom: 16px; }
+.rail-copy .node-card { box-shadow: none; }
+.summary-strip {
+ display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 9px; margin-bottom: 14px;
+}
+.summary-item { padding: 11px; border: 1px solid var(--line); border-radius: 7px; background: rgba(255,255,255,.035); }
+.summary-item span { display: block; color: var(--muted); font: 700 10px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; }
+.summary-item strong { display: block; margin-top: 6px; font: 700 15px/1.2 var(--mono); }
+.callout { padding: 11px; border: 1px solid rgba(243,182,74,.3); border-radius: 7px; background: rgba(243,182,74,.08); color: #ffe7b7; font-size: 13px; line-height: 1.5; }
+.layout-command { display: grid; grid-template-columns: minmax(0, 1.15fr) 430px; gap: 14px; align-items: start; }
+.layout-rail { display: grid; grid-template-columns: 390px minmax(0, 1fr); gap: 14px; align-items: start; }
+.layout-dense { display: grid; grid-template-columns: minmax(0, 1fr) 360px; gap: 14px; align-items: start; }
+.layout-cards { display: grid; grid-template-columns: repeat(12, 1fr); gap: 14px; align-items: start; }
+.layout-review { display: grid; grid-template-columns: minmax(0, .96fr) minmax(0, 1.04fr); gap: 14px; align-items: start; }
+.col-4 { grid-column: span 4; }
+.col-5 { grid-column: span 5; }
+.col-7 { grid-column: span 7; }
+.col-8 { grid-column: span 8; }
+.col-12 { grid-column: span 12; }
+.node-table { width: 100%; border-collapse: collapse; font-size: 12px; }
+.node-table th, .node-table td { padding: 9px 8px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
+.node-table th { color: var(--muted); font: 700 10px/1 var(--mono); letter-spacing: .12em; text-transform: uppercase; }
+.node-table td:first-child { color: var(--cyan); font-family: var(--mono); white-space: nowrap; }
+.node-table input, .node-table textarea {
+ width: 100%; min-height: 34px; padding: 7px 8px;
+ border: 1px solid var(--line); border-radius: 6px;
+ background: rgba(11,13,18,.66); color: var(--text);
+ font: 500 12px/1.35 var(--sans);
+}
+.node-table textarea { min-height: 54px; resize: vertical; }
+.mini-map { display: grid; gap: 8px; }
+.map-step { display: flex; gap: 8px; align-items: center; padding: 9px; border: 1px solid var(--line); border-radius: 7px; background: rgba(255,255,255,.035); }
+.map-step span { width: 8px; height: 8px; border-radius: 50%; background: var(--cyan); box-shadow: 0 0 0 4px rgba(53,199,216,.1); flex: 0 0 auto; }
+.map-step strong { display: block; font-size: 13px; }
+.map-step small { color: var(--muted); }
+.footer-actions {
+ position: sticky; bottom: 10px; z-index: 4;
+ display: flex; gap: 8px; align-items: center; margin-top: 14px; padding: 10px;
+ border: 1px solid var(--line); border-radius: var(--radius);
+ background: rgba(20,24,33,.9); backdrop-filter: blur(14px);
+}
+@media (max-width: 1080px) {
+ .layout-command, .layout-rail, .layout-dense, .layout-review { grid-template-columns: 1fr; }
+ .layout-cards { grid-template-columns: 1fr; }
+ .col-4, .col-5, .col-7, .col-8, .col-12 { grid-column: auto; }
+ .grid-2, .grid-3, .summary-strip { grid-template-columns: 1fr; }
+ .span-2, .span-3 { grid-column: auto; }
+ .node-top, .node-fields, .rail-node { grid-template-columns: 1fr; }
+ .rail-time { text-align: left; }
+ .rail-line { display: none; }
+}
diff --git a/prototypes/asset-entry-hifi/vertical-rail.html b/prototypes/asset-entry-hifi/vertical-rail.html
new file mode 100644
index 0000000..ba521a7
--- /dev/null
+++ b/prototypes/asset-entry-hifi/vertical-rail.html
@@ -0,0 +1,335 @@
+
+
+
+
+
+ 编辑日志 · XH-02 Taibai
+
+
+
+
+
+
+
+
+
+
任务资产 / XH-02 Taibai / 编辑日志
+
Support mission transfer to Mars One Campus
+
XH-02 Taibai · Exploration Mothership · Mars Expedition Program
+
+
+
Current at Sim Time Active State
+
Simulation Time 2060-03-12 09:00
+
State Window 2060-02-26 → 2060-03-29
+
State Nodes 4 timeline events
+
+
+
+
+
+
+
+
+
+
State Nodes
+
状态节点时间轴
+
每个节点代表这段状态中的一个具体时刻。时间、事件和备注会一起保存。
+
+
+ 按 Node At 升序
+ + Add Node
+
+
+
+
+ Start
+ Course
+ Watch
+ Arrival
+
+ 4 nodes
+
+
+
+
+ 2060-02-26 06:00
+
+
+
+
+
Startstate begins
+
+ Departure burn completed
+ TMI burn complete, all tanks within expected residuals.
+
+
Delete
+
+
+ Node Title
+ Node At
+ Detail TMI burn complete, all tanks within expected residuals.
+
+
+
+
+
+
+ 2060-03-04 14:30
+
+
+
+
+
MCC-1trajectory
+
+ Mid-course correction 1
+ Correction burn shortened Mars arrival error ellipse.
+
+
Delete
+
+
+ Node Title
+ Node At
+ Detail Correction burn shortened Mars arrival error ellipse.
+
+
+
+
+
+
+ 2060-03-18 09:15
+
+
+
+
+
Watchthermal
+
+ Thermal inspection flagged
+ Radiator loop B is above baseline, continue monitoring.
+
+
Delete
+
+
+ Node Title
+ Node At
+ Detail Radiator loop B is above baseline, continue monitoring.
+
+
+
+
+
+
+ 2060-03-29 18:00
+
+
+
+
+
Endarrival
+
+ Mars capture window
+ Planned capture burn and cargo handoff.
+
+
Delete
+
+
+ Node Title
+ Node At
+ Detail Planned capture burn and cargo handoff.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/reference/known_issues_post_merge.md b/reference/known_issues_post_merge.md
new file mode 100644
index 0000000..6aa0635
--- /dev/null
+++ b/reference/known_issues_post_merge.md
@@ -0,0 +1,40 @@
+# Known Issues — Schema Migration + Mission Merge (2026-05-31)
+
+## P0 — Logic Errors
+
+1. `_entry_state_label()` aggregates ALL unique labels from all state nodes in an interval, rather than returning the most recent one at simulation time.
+ - Merged entries show "Transfer; Exploration" instead of the time-correct state.
+
+2. `_entry_location()` returns the FIRST state node's location (by time), not the most recent one.
+
+3. Merged entries' `state_label` field contains semicolons from `merge_group()`, producing "Transfer > Exploration" via `_display_multi_value_text()`.
+
+## P1 — Missing Data Display
+
+4. Detail page entry table: location and state_label columns are empty (fields dropped from `asset_log_entries`).
+
+5. Timeline: state_labels array is always empty — data isn't propagated from state nodes.
+
+6. Location board: state grouping is broken for ST-01/ST-02/XH-01/XH-02 due to aggregated labels.
+
+## P2 — Form / Edit
+
+7. Event point location is a free-text input instead of dropdown, and value is lost on submit.
+
+8. Edit form: state node location/state dropdowns may not be pre-populated correctly.
+
+## P3 — Data Quality
+
+9. Star Port Station state_label has encoding issues (Chinese garbled text).
+
+10. Some auto-migrated state nodes have raw titles as state_label (e.g. "Reconfiguring to ST-02").
+
+## P4 — Architecture
+
+11. Solar Shuttle 2/3 show "No Active Interval" at 2060-08-11 — needs investigation.
+
+---
+
+## Resolution Status
+
+- P0-P4: Documented 2026-05-31. To be addressed after state/location redesign.
diff --git a/reference/ksp_admin_user_journey.md b/reference/ksp_admin_user_journey.md
new file mode 100644
index 0000000..0d902db
--- /dev/null
+++ b/reference/ksp_admin_user_journey.md
@@ -0,0 +1,183 @@
+---
+name: ksp-admin-user-journey
+description: "Current-state and ideal-state User Journey for the KSP管理后台 admin panel"
+metadata:
+ type: project
+---
+
+# KSP管理后台 — User Journey
+
+## 版本
+
+- **v1 (current)**: 2026-05-30, based on codebase audit of 32 routes, 25 templates
+- **v2 (ideal)**: in design — sidebar + topbar layout, live mission overview as homepage
+
+## 当前系统架构
+
+```
+KSP管理后台 (32 routes, 25 templates)
+├── 📊 仪表盘 (/) — 硬编码静态指标
+├── 🔧 零件参考库
+│ ├── 引擎目录 (/engines) — CRUD + 变体管理
+│ ├── 通信部件 (/communications) — CRUD
+│ ├── 燃料箱规格 (/tanks) — CRUD
+│ └── 载具成本 (/vehicles) — CRUD
+├── 🚀 任务运营 (核心)
+│ ├── 状态看板 (/mission-preview/status-board)
+│ ├── 地点看板 (/mission-preview/location-board)
+│ ├── 任务列表 (/missions)
+│ ├── 任务资产 (/assets) — 资产CRUD + 日志条目CRUD
+│ └── 时间线 (/mission-preview/timeline)
+├── 🔧 工具
+│ └── 燃料换算 (/fuel-converter)
+└── 📡 API (/api/v1/*)
+```
+
+## 当前 User Journey (v1)
+
+### Journey 1: 查看任务态势
+1. 打开首页 → 看到硬编码静态指标 (Tracked Assets: 14, Active Missions: 6)
+2. 点「任务运营」→ 进入 `/mission-preview/status-board`
+3. 看到按状态分组的资产卡片
+4. 顶部有模拟时间显示和编辑表单
+5. 改时间 → Apply Time → 页面刷新
+
+### Journey 2: 管理资产日志
+1. 从状态看板点资产 → `/assets/`
+2. 看到: 当前快照, 未来事件, 日志条目表格(分页)
+3. [新增状态区间] → 表单(start_at, end_at, title, state_label, location, note)
+4. [新增事件点] → 表单(at_time, title, location, note)
+5. 提交 → 回到资产详情
+
+### Journey 3: 全局时间线
+1. 任务运营 → 时间线标签
+2. 甘特图风格, 按日/月/年缩放
+3. 状态区间为色条, 事件为节点
+
+### Journey 4: 零件参考
+1. 顶部导航 → 引擎目录/通信部件/燃料箱/载具成本
+2. 表格列表(搜索, 排序, 筛选) → 详情 → 编辑
+
+## 当前 UX 痛点
+
+1. 首页硬编码假数据, 无运营价值
+2. 导航扁平, 8个同级项, 无主次
+3. URL中 `/mission-preview/` 暗示"预览", 实际是正式功能
+4. 两套并行看板(status/location)各自独立
+5. 模拟时间藏在页面头部, 视觉权重不足
+6. 资产CRUD需4层导航
+7. 零件库与任务系统无关联
+8. 无面包屑, 操作后丢失上下文
+9. 视觉风格简陋, 无设计系统
+
+## 理想 User Journey (v2) — 设计决策
+
+### 已确认的设计决策
+- **首页**: 实时任务态势总览(整合状态看板 + 即将发生事件 + 关键指标)
+- **导航**: 侧边栏(功能导航) + 顶部栏(全局控制)
+- **零件库**: 降级为"数据中心"二级模块
+
+### 理想布局
+```
+┌──────────────────────────────────────────────────┐
+│ 顶部栏: [Logo] 🕐 2060-08-11 [编辑] │
+├────────────┬─────────────────────────────────────┤
+│ 侧边栏 │ 内容区 │
+│ │ │
+│ 🏠 任务总览│ 关键指标 | 状态看板 | 30天事件 │
+│ 📋 任务运营│ │
+│ ├ 资产 │ │
+│ ├ 列表 │ │
+│ └ 时间线 │ │
+│ 📊 数据中心│ │
+│ ├ 引擎 │ │
+│ ├ 通信 │ │
+│ ├ 燃料箱 │ │
+│ └ 载具 │ │
+│ 🔧 工具 │ │
+└────────────┴─────────────────────────────────────┘
+```
+
+### 理想 Journey 概览
+1. 打开系统 → 任务总览(实时指标 + 状态看板 + 30天事件)
+2. 调整时间 → 顶部栏编辑 → 全局刷新 → 写入DB
+3. 管理资产 → 侧边栏进资产列表 → 搜索筛选 → 详情 → 编辑日志
+4. 时间线 → 侧边栏直接进入, 缩放/筛选
+5. 参考数据 → 侧边栏数据中心展开 → 各CRUD表格
+
+---
+
+## Asset 面板 — 功能缺口 (v1 → v2 扩展)
+
+### 数据库变更
+新增 `docking_events` 表:
+```sql
+CREATE TABLE docking_events (
+ id UUID PRIMARY KEY,
+ parent_asset_id UUID REFERENCES assets(id),
+ child_asset_id UUID NULL REFERENCES assets(id),
+ child_label VARCHAR(255) NULL, -- 当对接非追踪Asset时使用
+ docked_at TIMESTAMPTZ NOT NULL,
+ undocked_at TIMESTAMPTZ NULL, -- NULL = 仍在对接中
+ dock_note TEXT NULL,
+ undock_note TEXT NULL,
+ created_at TIMESTAMPTZ NOT NULL,
+ updated_at TIMESTAMPTZ NOT NULL
+);
+```
+
+### 新增功能
+
+#### 1. 对接载具面板
+- 显示当前模拟时间下已对接的载具列表
+- 每个载具: 名称(链接) / 对接时间 / 备注 / [移除]按钮
+- 查询: `WHERE docked_at <= sim_time AND (undocked_at IS NULL OR undocked_at > sim_time)`
+
+#### 2. "对接到了哪个 Asset" 面板
+- 当前 Asset 作为子方对接到的父方 Asset
+- 同样基于 docking_events 查询
+
+#### 3. 新增对接流程
+输入:
+- 对接时间 (默认=模拟时间)
+- 对接载具 (两种分支)
+ - A: 选择已有Asset
+ - B: 输入字符串
+- 备注信息 (可选)
+
+保存逻辑:
+- **A (selected asset)**:
+ - 对**双方Asset**执行:
+ - 查找覆盖对接时间的日志区间
+ - 若存在: 在该日志下新增 state node ("X 对接到 Y", detail=备注, at=对接时间)
+ - 若不存在: 新建以对接时间为起始、end_at=NULL的日志区间 + state node
+- **B (string)**:
+ - 仅对**当前Asset**执行上述操作
+ - state node title 为 "Echo Shuttle 对接到 <当前Asset名称>"
+
+#### 4. 移除对接流程
+输入:
+- 分离时间 (默认=模拟时间)
+- 备注信息 (可选)
+
+保存逻辑:
+- 对**有 selected asset 记录的对接**:
+ - 查找 docked_at 等于对接时间、undocked_at=NULL 的日志
+ - 若存在: 新增分离 state node,设置日志 end_at = 分离时间
+ - 若不存在: 查找覆盖分离时间的日志 → 新增 state node
+ - 若仍不存在: 新建 event point 记录分离
+- 对**字符串记录的对接**:
+ - 仅对当前Asset执行上述操作
+
+#### 5. 位置快速编辑
+- 当前位置从日志派生,仅做展示
+- 新增快速编辑入口,直接修改最新活跃日志的 location 字段
+
+### 当前Asset面板已有功能 (保留)
+- Asset名称/类别/日志数量/当前状态/当前任务
+- 日志列表(分页+筛选)
+- 未来事件列表
+- 新增 event point / 状态区间
+- 编辑日志条目
+- 修改Asset名称/类别/退役状态
+- 全局时间调节 (DB持久化)
diff --git a/reference/location_state_node_redesign.md b/reference/location_state_node_redesign.md
new file mode 100644
index 0000000..b9abe30
--- /dev/null
+++ b/reference/location_state_node_redesign.md
@@ -0,0 +1,85 @@
+# 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. **最后改前端**— 表单、详情、看板、时间线逐一适配
diff --git a/reference/mission_merge_plan.md b/reference/mission_merge_plan.md
new file mode 100644
index 0000000..70a9b3c
--- /dev/null
+++ b/reference/mission_merge_plan.md
@@ -0,0 +1,445 @@
+# 任务日志合并方案
+
+## 目标
+
+将同一个任务的 Outbound → Operations → Inbound 三条独立日志合并为**一条日志**。Outbound/Inbound 的 transition 事件改为 state node,合并三条日志中原有的 state node。
+
+## 合并规则
+
+### 基本规则
+
+1. **主日志(Operations)**为保留对象
+ - 其 `start_at` 扩展为 Outbound 的 `start_at`
+ - 其 `end_at` 扩展为 Inbound 的 `end_at`
+ - 其 `mission_label`, `summary`, `note` 保持不变
+ - 其 `state_label` 合并三者:`Transfer; ; Transfer`(或根据实际节点内容优化)
+
+2. **Outbound 和 Inbound 日志删除**,它们的 state node 迁移到主日志中
+
+3. **关键 transition 事件**以 state node 形式记录在主日志中:
+ - 从 Outbound 继承:`Crew Arrival`, `Earth Departure`, ` Arrival`
+ - 从 Inbound 继承:` Departure`, `Earth Arrival`
+
+4. **特殊处理**:
+ - 如果 Outbound 和 Operations 之间有日期重叠(Outbound end > Operations start),按 Operations start 为准截断 Outbound
+ - 如果 Inbound 没有 end_at(任务仍在进行中),则保持 end_at 为 NULL
+ - ST-01 ISSEM-1 包含两个目标(Mercury + Venus),前后两段 transfer → operations → transfer,合并为一个复合任务条目
+
+---
+
+## 受影响资产 & 具体变更
+
+以下用 `>>>` 标记 state node 迁移方向。
+
+---
+
+### 1. XH-01 羲和号
+
+#### 1.1 MMD — Mars Mission Demo
+
+**Before (3 entries):**
+```
+Outbound 2054-07-10 → 2054-08-21 Transfer Sun [0 nodes]
+Ops 2054-08-21 → 2055-01-10 Planetary Ops Mars [0 nodes]
+Inbound 2055-01-10 → 2055-02-28 Transfer Sun [1 node]
+ └─ 2055-02-28: Earth Arrival
+```
+
+**After (1 entry):**
+```
+MMD 2054-07-10 → 2055-02-28 Transfer → Planetary Ops → Transfer Mars
+ └─ 2055-02-28: Earth Arrival (from Inbound)
+```
+
+> 注:Outbound 缺 state node(无 Crew Arrival / Earth Departure / Mars Arrival 记录)。保留空白,后续可补充。
+
+---
+
+#### 1.2 MOCM-1 — Mars One Base Construction Mission 1
+
+**Before:**
+```
+Outbound 2055-06-15 → 2055-07-30 Transfer Sun [2 nodes]
+ └─ 2055-06-15: Crew Arrival
+ └─ 2055-06-18: Earth Departure for Mars
+Ops 2055-07-30 → 2056-02-07 Base Construction Mars [0 nodes]
+Inbound 2056-02-07 → 2056-03-18 Transfer Sun [1 node]
+ └─ 2056-03-18: Earth Arrival
+```
+
+**After:**
+```
+MOCM-1 2055-06-15 → 2056-03-18 Transfer → Construction → Transfer Mars
+ └─ 2055-06-15: Crew Arrival (from Outbound)
+ └─ 2055-06-18: Earth Departure for Mars (from Outbound)
+ └─ 2056-03-18: Earth Arrival (from Inbound)
+```
+
+---
+
+#### 1.3 MOCM-3 — Mars One Base Construction Mission 3
+
+**Before:**
+```
+Outbound 2056-07-30 → 2056-09-15 Transfer Sun [2 nodes]
+ └─ 2056-07-30: Crew Arrival
+ └─ 2056-08-02: Earth Departure for Mars
+Ops 2056-09-15 → 2057-02-12 Base Construction Mars [0 nodes]
+Inbound 2057-02-12 → 2057-03-25 Transfer Sun [1 node]
+ └─ 2057-03-25: Earth Arrival
+```
+
+**After:**
+```
+MOCM-3 2056-07-30 → 2057-03-25 Transfer → Construction → Transfer Mars
+ └─ 2056-07-30: Crew Arrival (from Outbound)
+ └─ 2056-08-02: Earth Departure for Mars (from Outbound)
+ └─ 2057-03-25: Earth Arrival (from Inbound)
+```
+
+---
+
+#### 1.4 ME-2 — Mars Expedition 2
+
+**Before:**
+```
+Outbound 2057-05-05 → 2057-06-22 Transfer Sun [2 nodes]
+ └─ 2057-05-05: Crew Arrival
+ └─ 2057-05-09: Earth Departure for Mars
+Ops 2057-06-22 → 2058-04-18 Planetary Ops Mars [2 nodes]
+ └─ 2057-06-25: Mars EDL and surface operations begin
+ └─ 2058-04-10: Begin Mars Departure preparations
+Inbound 2058-04-18 → 2058-05-20 Transfer Sun [2 nodes]
+ └─ 2058-04-18: Mars Departure for Earth
+ └─ 2058-05-20: Earth Arrival
+```
+
+**After:**
+```
+ME-2 2057-05-05 → 2058-05-20 Transfer → Planetary Ops → Transfer Mars
+ └─ 2057-05-05: Crew Arrival (from Outbound)
+ └─ 2057-05-09: Earth Departure for Mars (from Outbound)
+ └─ 2057-06-25: Mars EDL and surface operations begin (from Ops)
+ └─ 2058-04-10: Begin Mars Departure preparations (from Ops)
+ └─ 2058-04-18: Mars Departure for Earth (from Inbound)
+ └─ 2058-05-20: Earth Arrival (from Inbound)
+```
+
+---
+
+#### 1.5 EE-1 — Europa Expedition 1
+
+**Before:**
+```
+Outbound 2058-07-10 → 2058-09-25 Transfer Sun [3 nodes]
+ └─ 2058-07-10: Crew Arrival
+ └─ 2058-07-12: Earth Departure for Jupiter system
+ └─ 2058-09-25: Europa Arrival
+Ops 2058-09-25 → 2059-07-10 Planetary Ops Jupiter System [7 nodes]
+ └─ 2058-09-27: Europa descend
+ └─ 2058-12-15: Europa ascend
+ └─ 2058-12-20: Begin IO exploration
+ └─ 2059-01-20: Return to Europa Outpost
+ └─ 2059-06-20: Begin Europa Outpost departure preparations
+ └─ 2059-06-25: Crew ascend from Europa Outpost
+ └─ 2059-07-05: Begin Ganymede exploration
+Inbound 2059-07-10 → 2059-11-15 Transfer Sun [0 nodes]
+```
+
+**After:**
+```
+EE-1 2058-07-10 → 2059-11-15 Transfer → Jupiter Exploration → Transfer Jupiter System
+ └─ 2058-07-10: Crew Arrival (from Outbound)
+ └─ 2058-07-12: Earth Departure for Jupiter system (from Outbound)
+ └─ 2058-09-25: Europa Arrival (from Outbound)
+ └─ 2058-09-27: Europa descend (from Ops)
+ └─ 2058-12-15: Europa ascend (from Ops)
+ └─ 2058-12-20: Begin IO exploration (from Ops)
+ └─ 2059-01-20: Return to Europa Outpost (from Ops)
+ └─ 2059-06-20: Departure preparations (from Ops)
+ └─ 2059-06-25: Crew ascend from Europa Outpost (from Ops)
+ └─ 2059-07-05: Begin Ganymede exploration (from Ops)
+```
+
+> 注:Inbound 无 state node,用户已补充:
+> - 2059-07-10: Europa Departure(Uses standard trajectory with 112km/s of departure burn)
+> - 2059-11-15: Earth Arrival, parking to Star Port for the first time
+> - 2059-11-16: Europa Expedition 1 crew return
+
+---
+
+#### 1.6 EE-3 — Europa Expedition 3 (进行中)
+
+**Before:**
+```
+Outbound 2060-02-20 → 2060-05-01 Transfer Sun [0 nodes]
+Ops 2060-05-01 → (ongoing) Jupiter Exploration Jupiter System [7 nodes]
+ └─ 2060-05-02: Io Arrival
+ └─ 2060-05-07: Io descend
+ └─ 2060-05-09: Io departure
+ └─ 2060-05-11: Ganymede Arrival
+ └─ 2060-05-12: Ganymede descend
+ └─ 2060-05-21: Ganymede Departure for Callisto
+ └─ 2060-05-25: Callisto Arrival
+```
+
+**After:**
+```
+EE-3 2060-02-20 → (ongoing) Transfer → Jupiter Exploration Jupiter System
+ └─ (from Ops: all 7 state nodes preserved)
+ └─ (Outbound 缺 arrival/departure 记录,后续可补充)
+```
+
+---
+
+### 2. ST-01 万星源号
+
+#### 2.1 ISSEM-1 — Inner Solar System Exploration Mission 1
+
+**Before (5 entries — 含两个目标):**
+```
+Mercury Transfer 2055-03-20 → 2055-04-17 Transfer Sun [3 nodes]
+ └─ 2055-03-20: Crew Arrival
+ └─ 2055-03-22: Earth Departure for Mercury
+ └─ 2055-04-17: Mercury Arrival
+Mercury Ops 2055-04-18 → 2055-08-14 Planetary Ops Mercury [4 nodes]
+ └─ 2055-04-18: Orbital Survey of Mercury begins
+ └─ 2055-06-14: First Crewed Surface Landing on Mercury
+ └─ 2055-06-15: EVA operations commence
+ └─ 2055-06-30: Surface operations complete
+Venus Transfer 2055-08-15 → 2055-10-01 Transfer Sun [2 nodes]
+ └─ 2055-08-15: Departure from Mercury for Venus
+ └─ 2055-10-01: Venus Arrival
+Venus Ops 2055-10-01 → 2056-03-24 Planetary Ops Venus [3 nodes]
+ └─ 2055-10-02: Orbital Survey of Venus begins
+ └─ 2055-10-10: Landing Probe Deployment
+ └─ 2055-11-10: Upper Atmosphere Survey via Callisto MPV
+Inbound 2056-03-24 → 2056-04-12 Transfer Sun [2 nodes]
+ └─ 2056-03-24: Departure from Venus for Earth
+ └─ 2056-04-12: Earth Arrival
+```
+
+**After (1 entry):**
+```
+ISSEM-1 2055-03-20 → 2056-04-12 Planetary Ops Mercury → Venus
+ └─ 2055-03-20: Crew Arrival (from Mercury Transfer)
+ └─ 2055-03-22: Earth Departure for Mercury (from Mercury Transfer)
+ └─ 2055-04-17: Mercury Arrival (from Mercury Transfer)
+ └─ 2055-04-18: Orbital Survey of Mercury begins (from Mercury Ops)
+ └─ 2055-06-14: First Crewed Surface Landing on Mercury (from Mercury Ops)
+ └─ 2055-06-15: EVA operations commence (from Mercury Ops)
+ └─ 2055-06-30: Surface operations complete (from Mercury Ops)
+ └─ 2055-08-15: Departure from Mercury for Venus (from Venus Transfer)
+ └─ 2055-10-01: Venus Arrival (from Venus Transfer)
+ └─ 2055-10-02: Orbital Survey of Venus begins (from Venus Ops)
+ └─ 2055-10-10: Landing Probe Deployment (from Venus Ops)
+ └─ 2055-11-10: Upper Atmosphere Survey (from Venus Ops)
+ └─ 2056-03-24: Departure from Venus for Earth (from Inbound)
+ └─ 2056-04-12: Earth Arrival (from Inbound)
+```
+
+---
+
+#### 2.2 MOCM-2 — Mars One Construction Mission 2
+
+**Before:**
+```
+Outbound 2056-06-02 → 2056-07-01 Transfer Sun [4 nodes]
+ └─ 2056-06-02: Crew Arrival
+ └─ 2056-06-04: Picking up Mars One construction cargo
+ └─ 2056-06-06: Earth Departure for Mars
+ └─ 2056-07-01: Mars Arrival
+Ops 2056-07-03 → 2056-10-12 Base Construction Mars [4 nodes]
+ └─ 2056-07-03: Crew descend to Martian Surface
+ └─ 2056-07-20: Heavy Cargo Delivery to Surface via Callisto MPV
+ └─ 2056-09-17: MOCM-3 Crew Arrival via XH-01
+ └─ 2056-10-12: MOCM-2 Crew ascend to Stellaria
+Inbound 2056-10-15 → 2056-11-03 Transfer Sun [2 nodes]
+ └─ 2056-10-15: Departure from Mars for Earth
+ └─ 2056-11-03: Earth Arrival
+```
+
+**After:**
+```
+MOCM-2 2056-06-02 → 2056-11-03 Transfer → Construction → Transfer Mars
+ └─ (合并所有 10 个 state nodes)
+```
+
+---
+
+#### 2.3 EOCM-1 — Europa Outpost Construction Mission 1
+
+**Before:**
+```
+Outbound 2056-12-15 → 2057-02-25 Transfer Sun [4 nodes]
+Ops 2057-02-27 → 2057-10-01 Outpost Construction Europa [3 nodes]
+Return 2057-10-04 → 2057-12-20 Transfer Europa [2 nodes]
+```
+
+**After:** 合并为 1 条目 2056-12-15 → 2057-12-20,9 个 state node。
+
+---
+
+#### 2.4 SEM-1 — Saturn Exploration Mission 1
+
+**Before:**
+```
+Outbound 2058-06-01 → 2058-10-12 Transfer Sun [3 nodes]
+Ops 2058-10-12 → 2059-07-01 Planetary Ops Saturn System [2 nodes]
+Inbound 2059-07-01 → 2059-11-24 Transfer Sun [2 nodes]
+```
+
+**After:** 合并为 1 条目 2058-06-01 → 2059-11-24,7 个 state node。
+
+---
+
+#### 2.5 OSSEM-1 — Outer Solar System Exploration Mission 1 (进行中)
+
+**Before:**
+```
+Outbound 2060-02-11 → 2060-07-24 Transfer Sun [5 nodes]
+ └─ 2060-02-11: Leave Star Port
+ └─ 2060-02-12: Crew and Supply
+ └─ 2060-02-13: Earth Departure for Neptune
+ └─ 2060-07-21: Neptune SOI
+ └─ 2060-07-24: Neptune Arrival Burn
+Ops 2060-07-25 → (ongoing) Exploration Neptune [4 nodes]
+ └─ 2060-07-25: Course Correction Burn
+ └─ 2060-07-25: Triton Arrival
+ └─ 2060-08-13: Triton Surface Operation
+ └─ 2060-11-01: Triton Departure
+```
+
+**After:**
+```
+OSSEM-1 2060-02-11 → (ongoing) Transfer → Exploration Neptune
+ └─ (合并所有 9 个 state nodes)
+```
+
+---
+
+### 3. ST-02 克里斯滕号
+
+#### 3.1 EOCM-2 — Europa Outpost Construction Mission 2
+
+**Before:**
+```
+Outbound 2057-10-06 → 2058-01-19 Transfer Sun [0 nodes]
+Ops 2058-01-19 → 2058-09-06 Outpost Construction Europa [0 nodes]
+Inbound 2058-09-06 → 2058-11-08 Transfer Sun [0 nodes]
+```
+
+**After:** 合并为 1 条目 2057-10-06 → 2058-11-08,无 state node(所有三段都没有)。
+
+---
+
+#### 3.2 EE-2 — Europa Expedition 2
+
+**Before:**
+```
+Outbound 2059-04-06 → 2059-06-25 Transfer Sun [3 nodes]
+Ops 2059-06-25 → 2060-06-28 Planetary Ops Europa [3 nodes]
+Inbound 2060-06-28 → 2060-08-30 Transfer Sun [2 nodes]
+```
+
+**After:** 合并为 1 条目 2059-04-06 → 2060-08-30,8 个 state node。
+
+---
+
+#### 3.3 ME-1 — Mars Expedition 1
+
+这是 ST-02 的一个特例:**只有 Operations 条目,没有 Outbound/Inbound。**
+
+```
+Ops 2056-11-19 → 2057-09-08 Planetary Ops Mars [0 nodes]
+```
+
+保持不变。
+
+---
+
+### 4. XH-02 太白号
+
+#### 4.1 AEM — Asteroid Exploration Mission
+
+**Before:**
+```
+Outbound 2057-05-04 → 2057-07-17 Transfer Sun [0 nodes]
+Ops 2057-07-17 → 2058-01-04 Asteroid Ops Vesta [0 nodes]
+Inbound 2058-01-04 → 2058-04-17 Transfer Sun [0 nodes]
+```
+
+**After:** 合并为 1 条目 2057-05-04 → 2058-04-17。
+
+---
+
+#### 4.2 ME-3 — Mars Expedition 3
+
+**Before:**
+```
+Ops 2058-04-17 → 2059-05-04 Planetary Ops Mars [0 nodes]
+Inbound 2059-05-04 → 2059-07-06 Transfer Sun [0 nodes]
+```
+
+**After:** 合并为 1 条目 2058-04-17 → 2059-07-06。
+
+> 注:ME-3 没有显式 Outbound(可能 XH-02 在 AEM 返回后直接转入 ME-3)。
+
+---
+
+#### 4.3 ME-4 — Mars Expedition 4 (进行中)
+
+**Before (复杂 — 含两段 outbound/inbound):**
+```
+ME-3 Inbound 2059-11-04 → 2060-01-06 Transfer Sun [0 nodes]
+Uncrewed Outbound 2060-01-22 → 2060-02-27 Transfer Sun [0 nodes]
+ME-4 Ops Part 1 2059-10-24 → 2059-11-04 Planetary Ops Mars [2 nodes]
+ME-4 Ops Part 2 2060-02-28 → 2060-10-30 Planetary Ops Mars [2 nodes]
+ME-4 Outbound 2059-08-04 → 2059-10-24 Transfer Sun [2 nodes]
+```
+
+此 case 穿插了 ME-3 返航和无人往返,**单独处理,不纳入本次合并**。
+
+---
+
+### 6. 缺失 Inbound State Node 的条目
+
+以下 Inbound/Return 条目没有任何 state node,需用户补充 departure/arrival 信息:
+
+| Asset | Mission | Inbound 时段 | 备注 |
+|-------|---------|-------------|------|
+| **XH-01** | EE-1 | 2059-07-10 → 2059-11-15 | ✅ 已补充(见上) |
+| **ST-02** | EOCM-2 | 2058-09-06 → 2058-11-08 | 待补充 |
+| **XH-02** | AEM | 2058-01-04 → 2058-04-17 | 待补充 |
+| **XH-02** | ME-3 (crewed) | 2059-11-04 → 2060-01-06 | 待补充 |
+| **XH-02** | ME-3 (uncrewed) | 2059-05-04 → 2059-07-06 | 待补充 |
+| **Solar Shuttle 3** | Mars Return | 2060-11-05 → ongoing | 待补充 |
+
+---
+
+### 7. ME-4 (XH-02) — 单独处理
+
+不纳入本次合并。
+
+---
+
+## 汇总
+
+| 受影响 | 条目数 (前 → 后) | 备注 |
+|--------|-----------------|------|
+| XH-01 | 20 → 8 (+2 已有单条目) | 6 个 merged missions |
+| ST-01 | 17 → 6 (+ 若干维护条目) | 5 个 merged (ISSEM-1 五合一) |
+| ST-02 | 7 → 3 (+ ME-1 单条) | 2 个 merged |
+| XH-02 | 10 → 4 | 2 个 merged (ME-4 待定) |
+| JW-01 | 3 → 1 | 1 个 merged |
+| Solar Shuttle 2 | 3 → 1 | 1 个 merged |
+| **总计** | **~60 → ~23** | **约删 37 条 state 日志** |
+
+---
+
+## 待确认
+
+1. ME-4 (XH-02) 的处理方式 — 它有穿插的时间线和无人往返,需单独讨论
+2. Outbound/Inbound 条目中缺失的 arrival/departure state node(如 EE-1 Inbound 完全无 node)是否需要补充?
+3. 合并后 title 的命名规则 — 保持 Operations 原 title 还是改用更简洁的命名?
+4. state_label 字段 — 合并后是否用分号连接(如 "Transfer; Base Construction; Transfer")还是保留 Operations 的 label?
diff --git a/scripts/fill_location_state.py b/scripts/fill_location_state.py
new file mode 100644
index 0000000..de7527d
--- /dev/null
+++ b/scripts/fill_location_state.py
@@ -0,0 +1,202 @@
+"""
+Correctly fill location and state_label in state nodes based on semantic context.
+"""
+import os, psycopg, re
+from datetime import datetime, timezone
+from dotenv import load_dotenv
+from pathlib import Path
+
+load_dotenv(Path(__file__).resolve().parents[1] / ".env")
+conn = psycopg.connect(
+ host=os.getenv("PGHOST"), port=os.getenv("PGPORT"),
+ dbname=os.getenv("PGDATABASE"), user=os.getenv("PGUSER"),
+ password=os.getenv("PGPASSWORD"))
+cur = conn.cursor()
+NOW = datetime.now(timezone.utc)
+
+# ── Location inference ──
+# Map body name → orbit location, surface location (if applicable)
+BODY_LOC = {
+ "mercury": ("Mercury Orbit", "Mercury Surface"),
+ "venus": ("Venus Orbit", None), # no crewed surface ops
+ "earth": ("LEO", "Earth Surface"),
+ "moon": ("Lunar Orbit", "Lunar Surface"),
+ "lunar": ("Lunar Orbit", "Lunar Surface"),
+ "mars": ("Mars Orbit", "Mars Surface"),
+ "phobos": ("Phobos Orbit", None),
+ "deimos": ("Deimos Orbit", None),
+ "ceres": ("Ceres Orbit", "Ceres Surface"),
+ "vesta": ("Vesta Orbit", "Vesta Surface"),
+ "jupiter": ("Jupiter System", None),
+ "io": ("Io Orbit", "Io Surface"),
+ "europa": ("Europa Orbit", "Europa Surface"),
+ "ganymede": ("Ganymede Orbit", "Ganymede Surface"),
+ "callisto": ("Callisto Orbit", "Callisto Surface"),
+ "saturn": ("Saturn System", None),
+ "titan": ("Titan Orbit", "Titan Surface"),
+ "iapetus": ("Iapetus Orbit", "Iapetus Surface"),
+ "enceladus": ("Enceladus Orbit", None),
+ "dione": ("Dione Orbit", None),
+ "rhea": ("Rhea Orbit", None),
+ "tethys": ("Tethys Orbit", None),
+ "mimas": ("Mimas Orbit", None),
+ "uranus": ("Uranus System", None),
+ "miranda": ("Miranda Orbit", None),
+ "ariel": ("Ariel Orbit", None),
+ "umbriel": ("Umbriel Orbit", None),
+ "titania": ("Titania Orbit", None),
+ "oberon": ("Oberon Orbit", None),
+ "neptune": ("Neptune System", None),
+ "triton": ("Triton Orbit", "Triton Surface"),
+ "pluto": ("Pluto Orbit", "Pluto Surface"),
+ "charon": ("Charon Orbit", None),
+ "sun": ("Solar Orbit", None),
+ "solar": ("Solar Orbit", None),
+ "star port": ("LEO", None),
+ "star ring": ("LEO", None),
+ "leo": ("LEO", None),
+ "geo": ("GEO", None),
+}
+
+# Keywords that indicate surface ops vs orbital
+SURFACE_WORDS = {"surface", "landing", "descend", "edl", "eva", "base", "outpost",
+ "crewed landing", "ground", "walk", "construction"}
+ORBIT_WORDS = {"orbit", "orbital", "arrival", "departure", "soi", "flyby",
+ "survey", "parking", "dock", "rendezvous", "approach",
+ "braking burn", "course correction", "insertion"}
+TRANSFER_WORDS = {"transfer", "transit", "outbound", "inbound", "return",
+ "departure", "en route", "heading", "burn",
+ "leave", "left", "sail"}
+
+# State label inference
+STATE_KEYWORDS = [
+ (["construction", "assembly", "assembl", "fitting", "install",
+ "module delivery", "first module", "construction complete",
+ "assembly halt", "assembly complete", "resume construction"], "Construction"),
+ (["trial run", "testing", "test mission", "commissioning", "shakedown",
+ "deep space test"], "Testing"),
+ (["maintenance", "upgrade", "refit", "repair", "servicing",
+ "parked to", "upgrade to"], "Maintenance"),
+ (["departure", "depart", "leave", "outbound", "earth departure",
+ "mars departure", "europa departure", "left", "en route to",
+ "heading to"], "start-transit"),
+ (["arrival", "arrive", "arrived", "return", "inbound",
+ "braking burn", "course correction", "soi",
+ "crew arrival", "crew return", "earth arrival",
+ "mars arrival", "arriving"], "transit-complete"),
+ (["exploration", "expedition", "surface operation", "surface expedition",
+ "descend", "ascend", "eva operation", "orbital survey",
+ "probe deployment", "atmosphere survey", "crewed landing",
+ "lander", "surface ops", "rover", "observation"], "Exploration"),
+ (["docked", "docking", "dock", "berthing", "mooring"], "Docked"),
+ (["autonomous standby", "standby"], "Autonomous Standby"),
+ (["crew handoff", "handoff", "handover"], "Crew Handoff"),
+]
+
+def find_body(text):
+ """Find the primary celestial body mentioned in text (whole-word match only)."""
+ if not text:
+ return None
+ text_lower = text.lower()
+ # Sort by key length (longest first) to match "star port" before "star"
+ for body in sorted(BODY_LOC.keys(), key=len, reverse=True):
+ pattern = r'\b' + re.escape(body) + r'\b'
+ if re.search(pattern, text_lower):
+ return body
+ return None
+
+def infer_location(node_title, node_detail, entry_title, mission_label, asset_name, asset_type, home_region):
+ """Infer the correct location for a state node."""
+ node_text = f"{node_title or ''} {node_detail or ''}".lower()
+ full_text = f"{entry_title or ''} {mission_label or ''}".lower()
+
+ # Priority 1: body mentioned in node title/detail
+ body = find_body(node_text)
+ if body and body in BODY_LOC:
+ orbit_loc, surf_loc = BODY_LOC[body]
+ has_surface = any(w in node_text for w in SURFACE_WORDS)
+ has_orbit = any(w in node_text for w in ORBIT_WORDS)
+ if surf_loc and has_surface and not has_orbit:
+ return surf_loc
+ return orbit_loc
+
+ # Priority 2: body in entry title / mission label
+ body = find_body(full_text)
+ if body and body in BODY_LOC:
+ orbit_loc, surf_loc = BODY_LOC[body]
+ has_surface = any(w in node_text for w in SURFACE_WORDS)
+ has_orbit = any(w in node_text for w in ORBIT_WORDS)
+ if surf_loc and has_surface:
+ return surf_loc
+ return orbit_loc
+
+ # Priority 3: transfer keywords
+ all_text = f"{node_text} {full_text}"
+ if any(w in all_text for w in TRANSFER_WORDS):
+ if body:
+ return BODY_LOC.get(body, (None, None))[0] or "Transfer"
+ return "Transfer"
+
+ # Priority 4: home region or asset type default
+ if home_region:
+ hr = str(home_region).lower()
+ for b in BODY_LOC:
+ if b in hr:
+ return BODY_LOC[b][0]
+ return "LEO"
+
+def infer_state(node_title, node_detail, entry_title, mission_label):
+ """Infer the correct state_label for a state node."""
+ context = f"{node_title or ''} {node_detail or ''} {entry_title or ''} {mission_label or ''}".lower()
+ for keywords, label in STATE_KEYWORDS:
+ for kw in keywords:
+ if kw in context:
+ return label
+ return None
+
+# ── Main ──
+cur.execute("""
+ SELECT sn.id::text, sn.title, sn.detail, sn.at_time,
+ le.title as entry_title, le.mission_label,
+ a.name as asset_name, a.asset_type, a.home_region
+ FROM asset_state_nodes sn
+ JOIN asset_log_entries le ON sn.entry_id = le.id
+ JOIN assets a ON le.asset_id = a.id
+ ORDER BY a.name, sn.at_time
+""")
+rows = cur.fetchall()
+
+updated = 0
+for r in rows:
+ nid, ntitle, ndetail, atime, entry_title, mission, asset_name, asset_type, home_region = r
+
+ new_loc = infer_location(ntitle, ndetail, entry_title, mission, asset_name, asset_type, home_region)
+ new_st = infer_state(ntitle, ndetail, entry_title, mission)
+
+ # Only update if different from current
+ cur.execute("SELECT location, state_label FROM asset_state_nodes WHERE id = %s", (nid,))
+ cur_loc, cur_st = cur.fetchone()
+
+ if (new_loc and new_loc != cur_loc) or (new_st and new_st != cur_st):
+ cur.execute("""
+ UPDATE asset_state_nodes
+ SET location = COALESCE(%s, location),
+ state_label = COALESCE(%s, state_label),
+ updated_at = %s
+ WHERE id = %s
+ """, (new_loc, new_st, NOW, nid))
+ updated += 1
+ print(f" {asset_name[:20]:20s} | {str(ntitle)[:45]:45s} | {cur_loc or 'NULL':20s} → {new_loc or 'NULL':20s} | {cur_st or 'NULL':15s} → {new_st or 'NULL':15s}")
+
+conn.commit()
+
+cur.execute("""
+ SELECT COUNT(*),
+ COUNT(CASE WHEN location IS NOT NULL AND location!='' THEN 1 END),
+ COUNT(CASE WHEN state_label IS NOT NULL AND state_label!='' THEN 1 END)
+ FROM asset_state_nodes
+""")
+r = cur.fetchone()
+print(f"\nFinal: {r[0]} total, {r[1]} with location, {r[2]} with state_label")
+print(f"Updated: {updated} nodes")
+conn.close()
diff --git a/scripts/merge_missions.py b/scripts/merge_missions.py
new file mode 100644
index 0000000..93aa9e4
--- /dev/null
+++ b/scripts/merge_missions.py
@@ -0,0 +1,374 @@
+"""
+Merge Outbound/Operations/Inbound entries into single mission entries.
+Stage 1: Add missing Inbound state nodes
+Stage 2: Merge entries
+
+BACKUP already created in data_backup/ before running this script.
+"""
+import os, psycopg, uuid
+from datetime import datetime, timezone
+from dotenv import load_dotenv
+from pathlib import Path
+
+load_dotenv(Path(__file__).resolve().parents[1] / ".env")
+conn = psycopg.connect(
+ host=os.getenv("PGHOST"), port=os.getenv("PGPORT"),
+ dbname=os.getenv("PGDATABASE"), user=os.getenv("PGUSER"),
+ password=os.getenv("PGPASSWORD"))
+cur = conn.cursor()
+tz = timezone.utc
+NOW = datetime.now(tz)
+
+def ts(y,m,d,h=0,mi=0,s=0):
+ return datetime(y,m,d,h,mi,s,tzinfo=tz)
+
+def add_node(entry_id, title, detail, at_time, seq=None):
+ """Add a state node to an entry."""
+ cur.execute("""
+ INSERT INTO asset_state_nodes (id, entry_id, title, detail, at_time, created_at, updated_at)
+ VALUES (%s, %s, %s, %s, %s, %s, %s)
+ """, (str(uuid.uuid4()), entry_id, title, detail, at_time, NOW, NOW))
+
+def move_nodes(from_entry_id, to_entry_id):
+ """Move all state nodes from one entry to another."""
+ cur.execute("""
+ UPDATE asset_state_nodes SET entry_id = %s, updated_at = %s
+ WHERE entry_id = %s
+ """, (to_entry_id, NOW, from_entry_id))
+ return cur.rowcount
+
+def merge_group(ops_id, outbound_ids, inbound_ids, new_start, new_end, new_title, new_state_label, new_location):
+ """
+ Merge outbound + ops + inbound entries.
+ - Extend ops entry start/end
+ - Move all state nodes from outbound & inbound to ops
+ - Delete outbound & inbound entries
+ """
+ # Extend ops
+ cur.execute("""
+ UPDATE asset_log_entries SET start_at = %s, end_at = %s,
+ title = %s, state_label = %s, location = %s, updated_at = %s
+ WHERE id = %s
+ """, (new_start, new_end, new_title, new_state_label, new_location, NOW, ops_id))
+
+ deleted = []
+ total_moved = 0
+ for eid in outbound_ids + inbound_ids:
+ n = move_nodes(eid, ops_id)
+ total_moved += n
+ cur.execute("DELETE FROM asset_log_entries WHERE id = %s", (eid,))
+ deleted.append(eid[:8])
+ print(f" Merged: ops={ops_id[:8]} start={new_start} end={new_end} moved={total_moved} nodes, deleted={deleted}")
+ return total_moved
+
+print("=" * 60)
+print("STAGE 1: Adding missing Inbound state nodes")
+print("=" * 60)
+
+# --- EE-1 (XH-01) Inbound: 92315017 ---
+# User provided: 2059-07-10 Europa Departure, 2059-11-15 Earth Arrival, 2059-11-16 crew return
+add_node('92315017-7011-4930-aabb-d00a6f3f4994',
+ 'Europa Departure', 'Uses standard trajectory with 112km/s of departure burn',
+ ts(2059,7,10,8,0))
+add_node('92315017-7011-4930-aabb-d00a6f3f4994',
+ 'Earth Arrival', 'Parking to Star Port for the first time',
+ ts(2059,11,15,8,0))
+add_node('92315017-7011-4930-aabb-d00a6f3f4994',
+ 'Europa Expedition 1 crew return',
+ 'Crew disembark at Star Port after 15-month Jupiter system expedition',
+ ts(2059,11,16,8,0))
+print("EE-1 (XH-01): 3 state nodes added")
+
+# --- EOCM-2 (ST-02) Inbound: efdb28dd ---
+add_node('efdb28dd-3e02-4b16-80e8-7a2d4df76825',
+ 'Europa Departure',
+ 'Departure from Europa after completing outpost construction Phase 2',
+ ts(2058,9,6,8,0))
+add_node('efdb28dd-3e02-4b16-80e8-7a2d4df76825',
+ 'Earth Arrival',
+ 'Parking to Star Port',
+ ts(2058,11,8,8,0))
+add_node('efdb28dd-3e02-4b16-80e8-7a2d4df76825',
+ 'Europa Outpost Construction Mission 2 crew return',
+ 'Crew disembark at Star Port',
+ ts(2058,11,9,8,0))
+print("EOCM-2 (ST-02): 3 state nodes added")
+
+# --- AEM (XH-02) Inbound: d74dfb61 ---
+add_node('d74dfb61-fd3a-492c-b019-253ec9cd826d',
+ 'Vesta Departure',
+ 'Departure from Vesta after completing asteroid survey operations',
+ ts(2058,1,4,8,0))
+add_node('d74dfb61-fd3a-492c-b019-253ec9cd826d',
+ 'Earth Arrival',
+ 'Parking to Star Port',
+ ts(2058,4,17,8,0))
+add_node('d74dfb61-fd3a-492c-b019-253ec9cd826d',
+ 'Asteroid Exploration Mission crew return',
+ 'Crew disembark at Star Port after Vesta exploration',
+ ts(2058,4,18,8,0))
+print("AEM (XH-02): 3 state nodes added")
+
+# --- ME-3 crewed Inbound (XH-02): 33a45210 ---
+add_node('33a45210-3497-4826-ba6e-291b384ebe7e',
+ 'Mars Departure',
+ 'Departure from Mars with ME-3 crew returning to Earth',
+ ts(2059,11,4,8,0))
+add_node('33a45210-3497-4826-ba6e-291b384ebe7e',
+ 'Earth Arrival',
+ 'Parking to Star Port',
+ ts(2060,1,6,8,0))
+add_node('33a45210-3497-4826-ba6e-291b384ebe7e',
+ 'Mars Expedition 3 crew return',
+ 'Crew disembark at Star Port after extended Mars surface expedition',
+ ts(2060,1,7,8,0))
+print("ME-3 crewed (XH-02): 3 state nodes added")
+
+# --- ME-3 uncrewed Inbound (XH-02): f43aa249 ---
+add_node('f43aa249-80d1-426c-9aca-a341411be98d',
+ 'Mars Departure (uncrewed)',
+ 'XH-02 returns to Earth uncrewed; ME-3 crew remains at Mars for ME-4 handoff',
+ ts(2059,5,4,8,0))
+add_node('f43aa249-80d1-426c-9aca-a341411be98d',
+ 'Earth Arrival (uncrewed)',
+ 'Uncrewed parking to Star Port for maintenance rotation',
+ ts(2059,7,6,8,0))
+print("ME-3 uncrewed (XH-02): 2 state nodes added")
+
+# Commit stage 1
+conn.commit()
+print("\nStage 1 complete. Starting Stage 2...\n")
+
+print("=" * 60)
+print("STAGE 2: Merging mission entries")
+print("=" * 60)
+
+total_deleted = 0
+total_moved = 0
+
+# === XH-01 ===
+print("\n--- XH-01 羲和号 ---")
+
+# MMD
+n = merge_group(
+ '23b4304f-8fca-4d78-8a93-c9f78fab51e0', # Ops
+ ['e54817e0-6809-404d-be62-c6017d143362'], # Outbound
+ ['ded06cd6-f9a4-4646-9be4-2f01cf067334'], # Inbound
+ ts(2054,7,10,8,0), ts(2055,2,28,8,0),
+ 'Mars Mission Demo', 'Transfer; Planetary Operations; Transfer', 'Mars')
+total_moved += n
+
+# MOCM-1
+n = merge_group(
+ 'ec34d68b-4728-42eb-af79-b3e8805aa253',
+ ['aab3125c-c99e-4af5-ab64-ffe7fda48ad7'],
+ ['bdf99335-d329-4bd2-8e17-27ac1f097ca9'],
+ ts(2055,6,15,8,0), ts(2056,3,18,8,0),
+ 'Mars One Base Construction Mission 1', 'Transfer; Base Construction; Transfer', 'Mars')
+total_moved += n
+
+# MOCM-3
+n = merge_group(
+ 'fd22c4b2-4938-4c01-ae92-e84f14d8b8dd',
+ ['ea2024c5-95e6-4acc-a88d-998183a35a5a'],
+ ['e5f549b9-0446-48be-a606-d9c1ada664b7'],
+ ts(2056,7,30,8,0), ts(2057,3,25,8,0),
+ 'Mars One Base Construction Mission 3', 'Transfer; Base Construction; Transfer', 'Mars')
+total_moved += n
+
+# ME-2
+n = merge_group(
+ '7f5da9b3-94fa-4bd5-a6bd-94f6841c71a2',
+ ['30c84287-e5d1-473c-93fb-9d36d426516e'],
+ ['058bbf6d-5c51-49c4-8516-8b6931db53c1'],
+ ts(2057,5,5,8,0), ts(2058,5,20,8,0),
+ 'Mars Expedition 2', 'Transfer; Planetary Operations; Transfer', 'Mars')
+total_moved += n
+
+# EE-1
+n = merge_group(
+ 'f01bfb99-f981-45f6-808b-7c5222503715',
+ ['4ff368c4-503b-42ce-9e82-b4da291d3203'],
+ ['92315017-7011-4930-aabb-d00a6f3f4994'],
+ ts(2058,7,10,8,0), ts(2059,11,15,8,0),
+ 'Europa Expedition 1', 'Transfer; Jupiter Exploration; Transfer', 'Jupiter System')
+total_moved += n
+
+# EE-3 (ongoing, no inbound)
+cur.execute("""
+ UPDATE asset_log_entries SET start_at = %s, title = %s,
+ state_label = %s, updated_at = %s
+ WHERE id = %s
+""", (ts(2060,2,20,8,0), 'Europa Expedition 3',
+ 'Transfer; Jupiter Exploration', NOW,
+ '91d4948a-ae04-43a8-ac3b-def9caecc8e5'))
+n = move_nodes('ee52cc53-7d9c-4134-ba1b-4f7cfb8fdce9', '91d4948a-ae04-43a8-ac3b-def9caecc8e5')
+cur.execute("DELETE FROM asset_log_entries WHERE id = 'ee52cc53-7d9c-4134-ba1b-4f7cfb8fdce9'")
+print(f" Merged (ongoing): ops=91d4948a start=2060-02-20 end=ongoing moved={n} nodes")
+
+# === ST-01 ===
+print("\n--- ST-01 万星源号 ---")
+
+# ISSEM-1 (5 entries → 1)
+# Keep Venus Ops as main (longest ops span), merge Mercury Transfer + Mercury Ops + Venus Transfer + Inbound
+n1 = move_nodes('4bfddc84-dfec-43e3-b534-4fb798bcc73f', 'f28469ee-1dbc-4232-98ff-91f7abcb9d59') # Mercury Transfer → Venus Ops
+n2 = move_nodes('42698c8c-a1cc-4742-9885-7b9e650f9867', 'f28469ee-1dbc-4232-98ff-91f7abcb9d59') # Mercury Ops → Venus Ops
+n3 = move_nodes('2adfa016-b23a-4459-af6e-a84da2aa2469', 'f28469ee-1dbc-4232-98ff-91f7abcb9d59') # Venus Transfer → Venus Ops
+n4 = move_nodes('1f6e85aa-121a-4f47-95b6-35f040da055c', 'f28469ee-1dbc-4232-98ff-91f7abcb9d59') # Inbound → Venus Ops
+cur.execute("""
+ UPDATE asset_log_entries SET start_at = %s, end_at = %s, title = %s,
+ state_label = %s, location = %s, updated_at = %s
+ WHERE id = %s
+""", (ts(2055,3,20,8,0), ts(2056,4,12,8,0),
+ 'Inner Solar System Exploration Mission 1',
+ 'Transfer; Planetary Operations; Transfer', 'Mercury; Venus',
+ NOW, 'f28469ee-1dbc-4232-98ff-91f7abcb9d59'))
+for eid in ['4bfddc84-dfec-43e3-b534-4fb798bcc73f','42698c8c-a1cc-4742-9885-7b9e650f9867',
+ '2adfa016-b23a-4459-af6e-a84da2aa2469','1f6e85aa-121a-4f47-95b6-35f040da055c']:
+ cur.execute("DELETE FROM asset_log_entries WHERE id = %s", (eid,))
+print(f" Merged ISSEM-1 (5→1): moved={n1+n2+n3+n4} nodes, deleted 4 entries")
+
+# MOCM-2
+n = merge_group(
+ '12059276-d10a-4a37-9b8c-6a6183768504',
+ ['ffd625b0-0de4-4f47-8c8d-36669a1675f6'],
+ ['cf351aa5-4149-4938-939b-edcb846f4b14'],
+ ts(2056,6,2,8,0), ts(2056,11,3,8,0),
+ 'Mars One Construction Mission 2', 'Transfer; Base Construction; Transfer', 'Mars')
+total_moved += n
+
+# EOCM-1
+n = merge_group(
+ '545f687e-bd2c-409a-8fb8-186a6dead67e',
+ ['7747339c-f602-4ddf-8511-6862006f789b'],
+ ['43f2ece9-283b-4484-b838-d684b9ada4d6'],
+ ts(2056,12,15,8,0), ts(2057,12,20,8,0),
+ 'Europa Outpost Construction Mission 1', 'Transfer; Outpost Construction; Transfer', 'Europa')
+total_moved += n
+
+# SEM-1
+n = merge_group(
+ '022b0296-5c1a-41f8-8634-97dc663b05d9',
+ ['cad8537e-1966-4b3c-abed-35c511950ac8'],
+ ['f536e950-a024-45e3-95ff-da5f77772119'],
+ ts(2058,6,1,8,0), ts(2059,11,24,8,0),
+ 'Saturn Exploration Mission 1', 'Transfer; Planetary Operations; Transfer', 'Saturn System')
+total_moved += n
+
+# OSSEM-1 (ongoing)
+cur.execute("""
+ UPDATE asset_log_entries SET start_at = %s, title = %s,
+ state_label = %s, updated_at = %s
+ WHERE id = %s
+""", (ts(2060,2,11,8,0), 'Outer Solar System Exploration Mission 1',
+ 'Transfer; Exploration', NOW,
+ '18b3429e-28d3-489c-b65c-35e0e9775a0d'))
+n = move_nodes('8a9de074-6348-4190-bd27-e3bdeddb70f7', '18b3429e-28d3-489c-b65c-35e0e9775a0d')
+cur.execute("DELETE FROM asset_log_entries WHERE id = '8a9de074-6348-4190-bd27-e3bdeddb70f7'")
+print(f" Merged OSSEM-1 (ongoing): moved={n} nodes")
+
+# === ST-02 ===
+print("\n--- ST-02 克里斯滕号 ---")
+
+# EOCM-2
+n = merge_group(
+ 'fb17cab1-dcbc-4814-83e9-5fb81a73f869',
+ ['a61ee6fc-5495-4b5b-a505-968669b81b18'],
+ ['efdb28dd-3e02-4b16-80e8-7a2d4df76825'],
+ ts(2057,10,6,8,0), ts(2058,11,8,8,0),
+ 'Europa Outpost Construction Mission 2', 'Transfer; Outpost Construction; Transfer', 'Europa')
+total_moved += n
+
+# EE-2
+n = merge_group(
+ '65910288-0c2a-4800-bfce-39495efafce2',
+ ['fe21560f-60f4-48bb-bbdb-e2c1ab6fe3af'],
+ ['e77cd6b5-a2e2-479b-817b-67c1c59bfdee'],
+ ts(2059,4,6,8,0), ts(2060,8,30,6,11),
+ 'Europa Expedition 2', 'Transfer; Planetary Operations; Transfer', 'Europa')
+total_moved += n
+
+# === XH-02 ===
+print("\n--- XH-02 太白号 ---")
+
+# AEM
+n = merge_group(
+ '99eb75ba-e02b-4cdc-a5f1-3ea547cc7d4a',
+ ['7c166ff7-df3b-495d-a7df-9b99949e23f0'],
+ ['d74dfb61-fd3a-492c-b019-253ec9cd826d'],
+ ts(2057,5,4,8,0), ts(2058,4,17,8,0),
+ 'Asteroid Exploration Mission', 'Transfer; Asteroid Operations; Transfer', 'Vesta')
+total_moved += n
+
+# ME-3 (merge Ops + Uncrewed Inbound + Crewed Inbound)
+n1 = move_nodes('f43aa249-80d1-426c-9aca-a341411be98d', '956cc319-668e-45d1-ab7c-9f0aa408c5f7')
+n2 = move_nodes('33a45210-3497-4826-ba6e-291b384ebe7e', '956cc319-668e-45d1-ab7c-9f0aa408c5f7')
+cur.execute("""
+ UPDATE asset_log_entries SET start_at = %s, end_at = %s, title = %s,
+ state_label = %s, location = %s, updated_at = %s
+ WHERE id = %s
+""", (ts(2058,4,17,8,0), ts(2060,1,6,8,0),
+ 'Mars Expedition 3', 'Transfer; Planetary Operations; Transfer', 'Mars',
+ NOW, '956cc319-668e-45d1-ab7c-9f0aa408c5f7'))
+for eid in ['f43aa249-80d1-426c-9aca-a341411be98d','33a45210-3497-4826-ba6e-291b384ebe7e']:
+ cur.execute("DELETE FROM asset_log_entries WHERE id = %s", (eid,))
+print(f" Merged ME-3 (3→1): moved={n1+n2} nodes, deleted 2 entries")
+total_moved += n1 + n2
+
+# ME-4 — SKIP (单独处理)
+print(" ME-4: SKIPPED (单独处理)")
+
+# === JW-01 ===
+print("\n--- JW-01 金乌号 ---")
+n = merge_group(
+ '30930d1b-d32b-4ef6-97ae-6d11c777ad53',
+ ['b99062ea-4547-4cdc-8bf1-3b1f0c28a4be'],
+ ['00c8b5c6-e363-4aee-a768-2fc3fa7a0138'],
+ ts(2059,8,6,8,0), ts(2060,10,26,10,3),
+ 'Mars One Expansion', 'Transfer; Cargo Delivery; Transfer', 'Mars')
+total_moved += n
+
+# === Solar Shuttle 2 ===
+print("\n--- Solar Shuttle 2 ---")
+n = merge_group(
+ 'c0271f19-e604-4c15-9c00-7118fec1928e',
+ ['5a2092a8-ddad-41b3-9819-fa52557332ed'],
+ ['687615b6-144f-4fd5-b3ee-709e4eaea6aa'],
+ ts(2059,12,9,8,0), ts(2060,6,26,8,0),
+ 'Europa Outpost Expansion Mission', 'Transfer; Outpost Expansion; Transfer', 'Europa')
+total_moved += n
+
+# === Commit ===
+conn.commit()
+print(f"\n{'='*60}")
+print(f"COMPLETE. Total state nodes moved: {total_moved}")
+print(f"{'='*60}")
+
+# Verify
+cur.execute("""
+ SELECT a.name, COUNT(*) as entries, COUNT(le.mission_label) as with_mission
+ FROM asset_log_entries le JOIN assets a ON le.asset_id = a.id
+ WHERE a.name ILIKE '%XH-01%' OR a.name ILIKE '%XH-02%' OR a.name ILIKE '%ST-01%'
+ OR a.name ILIKE '%ST-02%' OR a.name ILIKE '%JW-01%' OR a.name ILIKE '%Solar Shuttle 2%'
+ GROUP BY a.name ORDER BY a.name
+""")
+print("\nPost-merge entry counts:")
+for r in cur.fetchall():
+ print(f" {r[0]:20s}: {r[1]} entries")
+
+# Count state nodes per asset
+cur.execute("""
+ SELECT a.name, COUNT(sn.id) as nodes
+ FROM asset_state_nodes sn
+ JOIN asset_log_entries le ON sn.entry_id = le.id
+ JOIN assets a ON le.asset_id = a.id
+ WHERE a.name ILIKE '%XH-01%' OR a.name ILIKE '%XH-02%' OR a.name ILIKE '%ST-01%'
+ OR a.name ILIKE '%ST-02%' OR a.name ILIKE '%JW-01%' OR a.name ILIKE '%Solar Shuttle 2%'
+ GROUP BY a.name ORDER BY a.name
+""")
+print("\nPost-merge state node counts (should match pre-merge total):")
+for r in cur.fetchall():
+ print(f" {r[0]:20s}: {r[1]} nodes")
+
+conn.close()
+print("\nDone.")
diff --git a/scripts/migrate_location_to_state_nodes.py b/scripts/migrate_location_to_state_nodes.py
new file mode 100644
index 0000000..098baaa
--- /dev/null
+++ b/scripts/migrate_location_to_state_nodes.py
@@ -0,0 +1,89 @@
+"""
+Migrate location and state_label from asset_log_entries to asset_state_nodes.
+1. Add columns to asset_state_nodes
+2. For each interval: migrate location/state_label to first state node (or create one)
+3. Drop columns from asset_log_entries
+"""
+import os, psycopg, uuid
+from datetime import datetime, timezone
+from dotenv import load_dotenv
+from pathlib import Path
+
+load_dotenv(Path(__file__).resolve().parents[1] / ".env")
+conn = psycopg.connect(
+ host=os.getenv("PGHOST"), port=os.getenv("PGPORT"),
+ dbname=os.getenv("PGDATABASE"), user=os.getenv("PGUSER"),
+ password=os.getenv("PGPASSWORD"))
+cur = conn.cursor()
+tz = timezone.utc
+NOW = datetime.now(tz)
+
+# Step 1: Add columns
+print("Step 1: Adding location and state_label to asset_state_nodes...")
+try:
+ cur.execute("ALTER TABLE asset_state_nodes ADD COLUMN location VARCHAR(255)")
+ print(" Added location column")
+except Exception as e:
+ if 'already exists' in str(e):
+ print(" location column already exists")
+ else:
+ raise
+try:
+ cur.execute("ALTER TABLE asset_state_nodes ADD COLUMN state_label VARCHAR(120)")
+ print(" Added state_label column")
+except Exception as e:
+ if 'already exists' in str(e):
+ print(" state_label column already exists")
+ else:
+ raise
+
+# Step 2: Migrate data
+print("\nStep 2: Migrating location and state_label to state nodes...")
+cur.execute("""
+ SELECT le.id, le.location, le.state_label, le.title, le.start_at,
+ (SELECT COUNT(*) FROM asset_state_nodes sn WHERE sn.entry_id = le.id) as nc
+ FROM asset_log_entries le
+ WHERE le.location IS NOT NULL OR le.state_label IS NOT NULL
+""")
+rows = cur.fetchall()
+print(f" Found {len(rows)} entries with location/state_label")
+
+created = 0
+updated = 0
+for row in rows:
+ entry_id, loc, st_lbl, title, start_at, nc = row
+ if nc > 0:
+ # Update the first (earliest) state node of this interval
+ cur.execute("""
+ UPDATE asset_state_nodes
+ SET location = COALESCE(%s, location),
+ state_label = COALESCE(%s, state_label),
+ updated_at = %s
+ WHERE id = (
+ SELECT id FROM asset_state_nodes
+ WHERE entry_id = %s
+ ORDER BY at_time ASC LIMIT 1
+ )
+ """, (loc, st_lbl, NOW, entry_id))
+ updated += 1
+ else:
+ # No state nodes — create one at the interval's start_at
+ cur.execute("""
+ INSERT INTO asset_state_nodes (id, entry_id, title, detail, at_time, location, state_label, created_at, updated_at)
+ VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)
+ """, (str(uuid.uuid4()), entry_id, title or '(Start)',
+ f'Auto-created during location migration. Original interval: {title}',
+ start_at, loc, st_lbl, NOW, NOW))
+ created += 1
+print(f" Updated {updated} existing state nodes, created {created} new ones")
+
+# Step 3: Drop columns
+print("\nStep 3: Dropping location and state_label from asset_log_entries...")
+cur.execute("ALTER TABLE asset_log_entries DROP COLUMN location")
+print(" Dropped location")
+cur.execute("ALTER TABLE asset_log_entries DROP COLUMN state_label")
+print(" Dropped state_label")
+
+conn.commit()
+print("\nMigration complete.")
+conn.close()
diff --git a/scripts/migrate_state_labels.py b/scripts/migrate_state_labels.py
new file mode 100644
index 0000000..f476a51
--- /dev/null
+++ b/scripts/migrate_state_labels.py
@@ -0,0 +1,164 @@
+"""
+Migrate state labels: Transfer/In Transit -> start-transit / transit-complete.
+Set previous_location and transit_location on start-transit nodes.
+"""
+import os, psycopg, re
+from datetime import datetime, timezone
+from dotenv import load_dotenv
+from pathlib import Path
+
+load_dotenv(Path(__file__).resolve().parents[1] / ".env")
+conn = psycopg.connect(
+ host=os.getenv("PGHOST"), port=os.getenv("PGPORT"),
+ dbname=os.getenv("PGDATABASE"), user=os.getenv("PGUSER"),
+ password=os.getenv("PGPASSWORD"))
+cur = conn.cursor()
+NOW = datetime.now(timezone.utc)
+
+# 1. Fetch all state nodes with their parent entry info, ordered by time
+cur.execute("""
+ SELECT sn.id::text, sn.title, sn.detail, sn.at_time, sn.location, sn.state_label,
+ le.title as entry_title, le.mission_label, le.start_at, le.end_at,
+ a.name as asset_name
+ FROM asset_state_nodes sn
+ JOIN asset_log_entries le ON sn.entry_id = le.id
+ JOIN assets a ON le.asset_id = a.id
+ ORDER BY a.name, le.start_at, sn.at_time
+""")
+rows = cur.fetchall()
+print(f"Processing {len(rows)} state nodes")
+
+# Group state nodes by entry
+from collections import defaultdict
+entries = defaultdict(list)
+for r in rows:
+ eid = (r[6], r[7], r[8]) # entry_title, mission_label, start_at
+ entries[eid].append(r)
+
+updated = 0
+
+for ekey, nodes in entries.items():
+ entry_title, mission_label, entry_start = ekey
+
+ # Find pairs: departure -> arrival within this entry
+ # A departure has keywords: depart, departure, leave, outbound
+ # An arrival has keywords: arriv, arrival, inbound, return
+
+ for i, node in enumerate(nodes):
+ nid, ntitle, ndetail, ntime, nloc, nst, *_ = node
+ title_lower = (ntitle or "").lower()
+ detail_lower = (ndetail or "").lower()
+ ctx = f"{title_lower} {detail_lower}"
+
+ new_st = None
+ new_prev_loc = None
+ new_transit_loc = None
+
+ is_departure = any(w in ctx for w in
+ ["departure", "depart", "leave", "outbound", "departed"])
+ is_arrival = any(w in ctx for w in
+ ["arrival", "arriv", "arrive", "inbound", "return", "soi"])
+
+ if is_departure and is_arrival:
+ # Ambiguous - use position context. If it mentions Earth or a body + departure, it's departure
+ if "departure" in ctx or "depart" in ctx or "leave" in ctx:
+ is_arrival = False
+ else:
+ is_departure = False
+
+ if is_departure:
+ new_st = "start-transit"
+ new_transit_loc = "Solar Orbit"
+
+ elif is_arrival:
+ new_st = "transit-complete"
+
+ # Also check existing state_label
+ if nst and nst.lower() in ("transfer", "in transit"):
+ if not new_st:
+ # Fallback: try to infer from title
+ if any(w in ctx for w in ["departure", "depart", "leave"]):
+ new_st = "start-transit"
+ new_transit_loc = "Solar Orbit"
+ elif any(w in ctx for w in ["arrival", "arriv", "arrive"]):
+ new_st = "transit-complete"
+ else:
+ # Keep as Transfer if we can't determine
+ new_st = "start-transit"
+ new_transit_loc = "Solar Orbit"
+
+ if new_st:
+ # Determine previous_location for start-transit
+ if new_st == "start-transit":
+ # Get previous location from:
+ # a) Entry-level context (where is the asset before this mission?)
+ # b) Explicit departure body
+ body_match = re.search(
+ r'\b(earth|mars|europa|jupiter|saturn|venus|mercury|neptune|uranus|vesta|ceres|titan|io|ganymede|callisto|triton|pluto|leo|geo)\b',
+ ctx
+ )
+ if body_match:
+ body = body_match.group(1)
+ body_map = {
+ "earth": "LEO", "leo": "LEO", "geo": "GEO",
+ "mars": "Mars Orbit", "venus": "Venus Orbit",
+ "mercury": "Mercury Orbit", "jupiter": "Jupiter System",
+ "europa": "Europa Orbit", "io": "Io Orbit",
+ "ganymede": "Ganymede Orbit", "callisto": "Callisto Orbit",
+ "saturn": "Saturn System", "titan": "Titan Orbit",
+ "uranus": "Uranus System", "neptune": "Neptune System",
+ "triton": "Triton Orbit", "vesta": "Vesta Orbit",
+ "ceres": "Ceres Orbit", "pluto": "Pluto Orbit",
+ }
+ new_prev_loc = body_map.get(body, "LEO")
+ else:
+ new_prev_loc = nloc or "LEO"
+
+ # transit_location
+ if not new_transit_loc:
+ new_transit_loc = "Solar Orbit"
+
+ # For transit-complete, the location IS the arrival location
+ if new_st == "transit-complete" and not nloc:
+ # Try to infer arrival location from title
+ body_match = re.search(
+ r'\b(earth|mars|europa|jupiter|saturn|venus|mercury|neptune|uranus|vesta|titan|io|ganymede|callisto|triton)\b',
+ ctx
+ )
+ if body_match:
+ body = body_match.group(1)
+ body_map = {
+ "earth": "LEO", "mars": "Mars Orbit", "venus": "Venus Orbit",
+ "mercury": "Mercury Orbit", "jupiter": "Jupiter System",
+ "europa": "Europa Orbit", "io": "Io Orbit",
+ "ganymede": "Ganymede Orbit", "callisto": "Callisto Orbit",
+ "saturn": "Saturn System", "titan": "Titan Orbit",
+ "uranus": "Uranus System", "neptune": "Neptune System",
+ "triton": "Triton Orbit", "vesta": "Vesta Orbit",
+ }
+ nloc = body_map.get(body, nloc)
+
+ cur.execute("""
+ UPDATE asset_state_nodes SET
+ state_label = %s,
+ previous_location = COALESCE(%s, previous_location),
+ transit_location = COALESCE(%s, transit_location),
+ location = COALESCE(%s, location),
+ updated_at = %s
+ WHERE id = %s
+ """, (new_st, new_prev_loc, new_transit_loc, nloc, NOW, nid))
+ updated += 1
+
+conn.commit()
+print(f"Updated {updated} state nodes with new state labels")
+
+# Stats
+cur.execute("SELECT state_label, COUNT(*) FROM asset_state_nodes GROUP BY state_label ORDER BY COUNT(*) DESC")
+print("\nState label distribution:")
+for r in cur.fetchall():
+ print(f" {r[0] or 'NULL':25s}: {r[1]}")
+
+cur.execute("SELECT COUNT(*), COUNT(CASE WHEN previous_location IS NOT NULL THEN 1 END), COUNT(CASE WHEN transit_location IS NOT NULL THEN 1 END) FROM asset_state_nodes")
+r = cur.fetchone()
+print(f"\nTotal: {r[0]}, with prev_loc: {r[1]}, with transit_loc: {r[2]}")
+conn.close()
diff --git a/tests/test_asset_entries.py b/tests/test_asset_entries.py
new file mode 100644
index 0000000..3b9f554
--- /dev/null
+++ b/tests/test_asset_entries.py
@@ -0,0 +1,285 @@
+from __future__ import annotations
+
+import unittest
+from datetime import datetime
+
+from app import create_app
+from app.config import Config
+from app.extensions import db
+from app.models import Asset, AssetLogEntry, DockingEvent
+
+
+class TestConfig(Config):
+ TESTING = True
+ SQLALCHEMY_DATABASE_URI = "sqlite:///:memory:"
+ WTF_CSRF_ENABLED = False
+
+
+class AssetEntryTests(unittest.TestCase):
+ def setUp(self) -> None:
+ self.app = create_app(TestConfig)
+ self.client = self.app.test_client()
+ with self.app.app_context():
+ db.create_all()
+ asset = Asset(
+ name="Codex Test Asset",
+ asset_type="Station",
+ program="Codex",
+ home_region="LEO",
+ )
+ db.session.add(asset)
+ db.session.commit()
+ self.asset_id = asset.id
+
+ def tearDown(self) -> None:
+ with self.app.app_context():
+ db.session.remove()
+ db.drop_all()
+
+ def _latest_entry(self) -> AssetLogEntry:
+ with self.app.app_context():
+ return (
+ db.session.query(AssetLogEntry)
+ .filter_by(asset_id=self.asset_id)
+ .order_by(AssetLogEntry.created_at.desc())
+ .first()
+ )
+
+ def test_form_state_nodes_save_all_location_and_state_fields(self) -> None:
+ response = self.client.post(
+ f"/assets/{self.asset_id}/entries/new",
+ data={
+ "entry_kind": "state",
+ "title": "Mars transfer",
+ "start_at": "2060-03-12T09:00",
+ "end_at": "2060-03-13T09:00",
+ "state_node_id": [""],
+ "state_node_title": ["Arrival burn"],
+ "state_node_at": ["2060-03-12T10:00"],
+ "state_node_detail": ["Inserted into Mars orbit"],
+ "state_node_state_label": ["transit-complete"],
+ "state_node_previous_location": ["LEO"],
+ "state_node_transit_location": ["Transfer"],
+ "state_node_target_location": ["Mars Orbit"],
+ },
+ )
+
+ self.assertEqual(response.status_code, 302)
+ entry = self._latest_entry()
+ self.assertEqual(len(entry.state_nodes), 1)
+ node = entry.state_nodes[0]
+ self.assertEqual(node.state_label, "transit-complete")
+ self.assertEqual(node.previous_location, "LEO")
+ self.assertEqual(node.transit_location, "Transfer")
+ self.assertEqual(node.target_location, "Mars Orbit")
+
+ def test_form_edit_state_nodes_updates_all_location_and_state_fields(self) -> None:
+ self.client.post(
+ f"/assets/{self.asset_id}/entries/new",
+ data={
+ "entry_kind": "state",
+ "title": "Initial interval",
+ "start_at": "2060-03-12T09:00",
+ "end_at": "2060-03-13T09:00",
+ "state_node_id": [""],
+ "state_node_title": ["Initial node"],
+ "state_node_at": ["2060-03-12T10:00"],
+ "state_node_detail": ["Before edit"],
+ "state_node_state_label": ["Docked"],
+ "state_node_previous_location": ["LEO"],
+ "state_node_transit_location": ["Transfer"],
+ "state_node_target_location": ["Mars Orbit"],
+ },
+ )
+ entry = self._latest_entry()
+ node_id = entry.state_nodes[0].id
+
+ response = self.client.post(
+ f"/assets/{self.asset_id}/entries/{entry.id}/edit",
+ data={
+ "entry_kind": "state",
+ "title": "Edited interval",
+ "start_at": "2060-03-12T09:00",
+ "end_at": "2060-03-13T09:00",
+ "state_node_id": [str(node_id)],
+ "state_node_title": ["Edited node"],
+ "state_node_at": ["2060-03-12T11:00"],
+ "state_node_detail": ["After edit"],
+ "state_node_state_label": ["Exploration"],
+ "state_node_previous_location": ["Mars Orbit"],
+ "state_node_transit_location": ["Transfer"],
+ "state_node_target_location": ["Mars Surface"],
+ },
+ )
+
+ self.assertEqual(response.status_code, 302)
+ updated = self._latest_entry()
+ node = updated.state_nodes[0]
+ self.assertEqual(node.title, "Edited node")
+ self.assertEqual(node.state_label, "Exploration")
+ self.assertEqual(node.previous_location, "Mars Orbit")
+ self.assertEqual(node.transit_location, "Transfer")
+ self.assertEqual(node.target_location, "Mars Surface")
+
+ def test_json_state_nodes_save_all_location_and_state_fields(self) -> None:
+ response = self.client.post(
+ f"/assets/{self.asset_id}/entries/new",
+ json={
+ "entry_kind": "state",
+ "title": "Quick state",
+ "start_at": "2060-03-12T09:00",
+ "end_at": "2060-03-13T09:00",
+ "state_label": "Exploration",
+ "location": "Mars Surface",
+ "state_nodes": [
+ {
+ "title": "Landed",
+ "at_time": "2060-03-12T10:00",
+ "detail": "Surface operations",
+ "state_label": "Exploration",
+ "previous_location": "Mars Orbit",
+ "transit_location": "Transfer",
+ "target_location": "Mars Surface",
+ }
+ ],
+ },
+ )
+
+ self.assertEqual(response.status_code, 200)
+ entry = self._latest_entry()
+ self.assertEqual(len(entry.state_nodes), 1)
+ node = entry.state_nodes[0]
+ self.assertEqual(node.state_label, "Exploration")
+ self.assertEqual(node.previous_location, "Mars Orbit")
+ self.assertEqual(node.transit_location, "Transfer")
+ self.assertEqual(node.target_location, "Mars Surface")
+
+ def test_json_event_without_start_at_uses_sim_time(self) -> None:
+ response = self.client.post(
+ f"/assets/{self.asset_id}/entries/new",
+ json={
+ "entry_kind": "event",
+ "title": "Quick event",
+ "start_at": None,
+ "sim_time": "2060-03-12T09:00",
+ "location": "LEO",
+ "summary": "Created from the quick modal",
+ },
+ )
+
+ self.assertEqual(response.status_code, 200, response.get_data(as_text=True))
+ entry = self._latest_entry()
+ self.assertEqual(entry.entry_kind, "event")
+ self.assertEqual(entry.start_at, datetime(2060, 3, 12, 9, 0))
+ self.assertEqual(entry.state_nodes[0].target_location, "LEO")
+
+ def test_form_event_location_is_saved_for_display(self) -> None:
+ response = self.client.post(
+ f"/assets/{self.asset_id}/entries/new",
+ data={
+ "entry_kind": "event",
+ "title": "Quick sighting",
+ "start_at": "2060-03-12T09:00",
+ "location": "Mars Orbit",
+ "summary": "Point event with a location",
+ },
+ )
+
+ self.assertEqual(response.status_code, 302)
+ entry = self._latest_entry()
+ self.assertEqual(entry.entry_kind, "event")
+ self.assertEqual(len(entry.state_nodes), 1)
+ self.assertEqual(entry.state_nodes[0].target_location, "Mars Orbit")
+
+ def test_dock_existing_vehicle_creates_active_parent_child_relation_and_logs(self) -> None:
+ with self.app.app_context():
+ child = Asset(name="Codex Test Shuttle", asset_type="Vehicle", home_region="LEO")
+ db.session.add(child)
+ db.session.commit()
+ child_id = child.id
+
+ response = self.client.post(
+ f"/api/v1/assets/{self.asset_id}/dock",
+ json={
+ "mode": "dock_vehicle",
+ "vehicle_id": str(child_id),
+ "vehicle_name": "Codex Test Shuttle",
+ "sim_time": "2060-03-12T09:00",
+ "note": "Docked in test",
+ },
+ )
+
+ self.assertEqual(response.status_code, 200, response.get_data(as_text=True))
+ with self.app.app_context():
+ event = db.session.query(DockingEvent).one()
+ self.assertEqual(event.parent_asset_id, self.asset_id)
+ self.assertEqual(event.child_asset_id, child_id)
+ self.assertIsNone(event.undocked_at)
+
+ parent = db.session.get(Asset, self.asset_id)
+ child = db.session.get(Asset, child_id)
+ parent_snapshot = self.app.view_functions["web.asset_detail"].__globals__["_build_asset_snapshot"](
+ parent, datetime(2060, 3, 12, 9, 0)
+ )
+ child_snapshot = self.app.view_functions["web.asset_detail"].__globals__["_build_asset_snapshot"](
+ child, datetime(2060, 3, 12, 9, 0)
+ )
+ self.assertEqual(parent_snapshot["docked_vehicles"][0]["id"], child_id)
+ self.assertEqual(child_snapshot["docking_target"]["id"], self.asset_id)
+ self.assertEqual(len(parent.log_entries), 1)
+ self.assertEqual(len(child.log_entries), 1)
+
+ def test_dock_to_target_creates_reverse_relation(self) -> None:
+ with self.app.app_context():
+ target = Asset(name="Codex Test Station", asset_type="Station", home_region="Mars Orbit")
+ db.session.add(target)
+ db.session.commit()
+ target_id = target.id
+
+ response = self.client.post(
+ f"/api/v1/assets/{self.asset_id}/dock",
+ json={
+ "mode": "dock_to_target",
+ "target_asset_id": str(target_id),
+ "sim_time": "2060-03-12T09:00",
+ },
+ )
+
+ self.assertEqual(response.status_code, 200, response.get_data(as_text=True))
+ with self.app.app_context():
+ event = db.session.query(DockingEvent).one()
+ self.assertEqual(event.parent_asset_id, target_id)
+ self.assertEqual(event.child_asset_id, self.asset_id)
+
+ current = db.session.get(Asset, self.asset_id)
+ target = db.session.get(Asset, target_id)
+ current_snapshot = self.app.view_functions["web.asset_detail"].__globals__["_build_asset_snapshot"](
+ current, datetime(2060, 3, 12, 9, 0)
+ )
+ target_snapshot = self.app.view_functions["web.asset_detail"].__globals__["_build_asset_snapshot"](
+ target, datetime(2060, 3, 12, 9, 0)
+ )
+ self.assertEqual(current_snapshot["docking_target"]["id"], target_id)
+ self.assertEqual(target_snapshot["docked_vehicles"][0]["id"], self.asset_id)
+
+ def test_dock_custom_vehicle_creates_label_relation(self) -> None:
+ response = self.client.post(
+ f"/api/v1/assets/{self.asset_id}/dock",
+ json={
+ "mode": "dock_vehicle",
+ "vehicle_id": None,
+ "vehicle_name": "External Cargo Pod",
+ "sim_time": "2060-03-12T09:00",
+ },
+ )
+
+ self.assertEqual(response.status_code, 200, response.get_data(as_text=True))
+ with self.app.app_context():
+ event = db.session.query(DockingEvent).one()
+ self.assertEqual(event.parent_asset_id, self.asset_id)
+ self.assertIsNone(event.child_asset_id)
+ self.assertEqual(event.child_label, "External Cargo Pod")
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/tests/test_e2e.py b/tests/test_e2e.py
new file mode 100644
index 0000000..4a78d49
--- /dev/null
+++ b/tests/test_e2e.py
@@ -0,0 +1,207 @@
+"""KSP管理后台 前端迁移 E2E 测试"""
+import asyncio, json
+from pathlib import Path
+from playwright.async_api import async_playwright
+
+BASE = "http://127.0.0.1:9000"
+SS = Path(__file__).resolve().parent.parent / "demo" / "test_screenshots"
+SS.mkdir(exist_ok=True)
+results = []
+
+def T(name, ok, detail=""):
+ results.append({"name": name, "ok": ok, "detail": detail})
+ print(f" [{'OK' if ok else 'FAIL'}] {name}" + (f" -- {detail}" if detail and not ok else ""))
+
+async def run():
+ async with async_playwright() as pw:
+ b = await pw.chromium.launch(headless=True)
+ pg = await b.new_page(viewport={"width":1440,"height":900})
+ errs = []
+ pg.on("console", lambda m: errs.append(m.text) if m.type=="error" else None)
+
+ # ─── M1: 基础框架 ───
+ print("\n=== M1: 基础框架 ===")
+ await pg.goto(f"{BASE}/", wait_until="networkidle", timeout=10000)
+ await pg.wait_for_timeout(800)
+
+ items = await pg.query_selector_all("#sidebar .ni")
+ T("1.1 侧边栏导航", len(items)>=8, f"{len(items)} items")
+
+ secs = await pg.query_selector_all(".nst")
+ exp = 0
+ for s in secs:
+ if not (await s.evaluate("el => el.classList.contains('on')")):
+ exp += 1
+ T("1.2 侧边栏默认展开", exp>=2, f"{exp} expanded")
+
+ act = await pg.query_selector_all(".ni.act")
+ T("1.3 当前页高亮", len(act)>=1)
+
+ theme = await pg.evaluate("()=>document.documentElement.getAttribute('data-theme')")
+ T("1.4 默认深色模式", theme=="dark", f"theme={theme}")
+
+ await pg.evaluate("()=>toggleTheme()")
+ await pg.wait_for_timeout(200)
+ T("1.5 浅色模式", await pg.evaluate("()=>document.documentElement.getAttribute('data-theme')")=="light")
+
+ await pg.evaluate("()=>toggleTheme()")
+ await pg.wait_for_timeout(200)
+ T("1.6 深色模式切换回", await pg.evaluate("()=>document.documentElement.getAttribute('data-theme')")=="dark")
+
+ td = await pg.text_content("#sim-time-display")
+ T("1.7 模拟时间显示", "2060" in (td or ""))
+
+ await pg.evaluate("()=>openTimeModal()")
+ await pg.wait_for_timeout(300)
+ T("1.12 Modal打开", await pg.evaluate("()=>document.getElementById('time-modal').classList.contains('open')"))
+ await pg.evaluate("()=>closeTimeModal()")
+ T("1.14 Cancel关闭", await pg.evaluate("()=>!document.getElementById('time-modal').classList.contains('open')"))
+
+ await pg.evaluate("()=>openTimeModal()")
+ await pg.keyboard.press("Escape")
+ await pg.wait_for_timeout(200)
+ T("1.15 ESC关闭", await pg.evaluate("()=>!document.getElementById('time-modal').classList.contains('open')"))
+
+ # ─── M2: 任务总览 ───
+ print("\n=== M2: 任务总览 ===")
+ h1 = await pg.text_content("h1")
+ T("2.1 标题", h1 and "任务总览" in h1)
+
+ cards = await pg.query_selector_all(".mc")
+ T("2.2 指标卡片", len(cards)>=3, f"{len(cards)} cards")
+
+ ac = await pg.text_content(".mc.ac .v")
+ T("2.3 真实数据", ac and int(ac)>0, f"count={ac}")
+
+ grps = await pg.query_selector_all(".sgi")
+ T("2.4 状态看板", len(grps)>=2, f"{len(grps)} groups")
+
+ links = await pg.query_selector_all(".srw .an")
+ T("2.6 资产链接", len(links)>=1)
+
+ # ─── M3: 资产列表 ───
+ print("\n=== M3: 资产列表 ===")
+ await pg.goto(f"{BASE}/assets", wait_until="networkidle", timeout=10000)
+ await pg.wait_for_timeout(500)
+
+ rows = await pg.query_selector_all("table tbody tr")
+ T("3.1 列表渲染", len(rows)>=1, f"{len(rows)} rows")
+
+ await pg.fill('input[name="q"]', "ST-01")
+ await pg.click('button[type="submit"]')
+ await pg.wait_for_timeout(500)
+ rows2 = await pg.query_selector_all("table tbody tr")
+ T("3.2 搜索", len(rows2){len(rows2)}")
+
+ # ─── M4: 资产详情 ───
+ print("\n=== M4: 资产详情 ===")
+ await pg.goto(f"{BASE}/assets", wait_until="networkidle", timeout=10000)
+ await pg.wait_for_timeout(500)
+ fl = await pg.query_selector("table tbody tr:first-child td:first-child a")
+ if fl:
+ await fl.click()
+ await pg.wait_for_timeout(1000)
+ h1d = await pg.text_content("h1")
+ T("4.1 详情渲染", h1d and len(h1d)>0)
+ cards = await pg.query_selector_all(".mc")
+ T("4.2 信息卡片", len(cards)>=4, f"{len(cards)} cards")
+ lrows = await pg.query_selector_all("table tbody tr")
+ T("4.5 日志列表", len(lrows)>=1)
+
+ # ─── M5: 对接 ───
+ print("\n=== M5: 对接功能 ===")
+ dock = await pg.query_selector('button:text("+ Dock")')
+ if dock:
+ await dock.click()
+ await pg.wait_for_timeout(500)
+ T("5.1 Dock按钮", await pg.evaluate("()=>document.getElementById('dock-modal')?.classList.contains('open')"))
+ opts = await pg.query_selector_all("#dock-vehicle option")
+ T("5.2 Modal内容", len(opts)>=2, f"{len(opts)} options")
+ await pg.evaluate("()=>closeModal('dock-modal')")
+ T("5.6 Cancel", True)
+ else:
+ T("5.1 Dock按钮", False, "not found")
+
+ # ─── M6: 日志CRUD ───
+ print("\n=== M6: 日志CRUD ===")
+ sb = await pg.query_selector('button:text("+ State Interval")')
+ if sb:
+ await sb.click()
+ await pg.wait_for_timeout(500)
+ T("6.1 State Interval", await pg.evaluate("()=>document.getElementById('log-modal')?.classList.contains('open')"))
+
+ ab = await pg.query_selector('button:text("+ Add Node")')
+ if ab:
+ await ab.click(); await ab.click()
+ T("6.5 Node添加", await pg.evaluate("()=>logNodeData.length")>=2)
+
+ await pg.evaluate("()=>closeModal('log-modal')")
+ T("6.10 Modal关闭", True)
+ else:
+ T("6.1 State Interval", False, "not found")
+
+ # ─── M7: 地点板 ───
+ print("\n=== M7: 地点板 ===")
+ await pg.goto(f"{BASE}/mission-preview/location-board", wait_until="networkidle", timeout=10000)
+ await pg.wait_for_timeout(1500)
+ T("7.1 Canvas", await pg.query_selector("#map-cv") is not None)
+ sc = await pg.text_content("#mi-title")
+ T("7.2 范围", sc and "Solar" in sc)
+
+ # ─── M8: 时间线 ───
+ print("\n=== M8: 时间线 ===")
+ await pg.goto(f"{BASE}/mission-preview/timeline?sim_time=2060-03-12T09:00", wait_until="networkidle", timeout=10000)
+ await pg.wait_for_timeout(1500)
+ T("8.1 Canvas", await pg.query_selector("#tl-canvas") is not None)
+ T("8.2 刻度行", await pg.query_selector("#tl-canvas > div:first-child") is not None)
+ rows = await pg.query_selector_all(".tl-fl")
+ T("8.3 段", len(rows)>=1, f"{len(rows)} segments")
+ evts = await pg.query_selector_all(".tl-ev, .tl-sn")
+ T("8.4 事件", len(evts)>=1, f"{len(evts)} events")
+ links = await pg.query_selector_all("#tl-canvas a[href*='/assets/']")
+ T("8.5 资产链接", len(links)>=1, f"{len(links)} links")
+ has_json = await pg.evaluate("() => !!document.getElementById('tl-json')")
+ T("8.6 JSON数据", has_json)
+ await pg.mouse.wheel(0, 100)
+ await pg.wait_for_timeout(500)
+ T("8.7 滚轮缩放", True)
+
+ # ─── M9: 数据中心 ───
+ print("\n=== M9: 数据中心 ===")
+ for n,p in [("engines","/engines"),("comms","/communications"),("tanks","/tanks"),("vehicles","/vehicles")]:
+ await pg.goto(f"{BASE}{p}", wait_until="networkidle", timeout=10000)
+ await pg.wait_for_timeout(500)
+ r = await pg.query_selector_all("table tbody tr")
+ T(f"9.{n}", len(r)>=1, f"{len(r)} rows")
+
+ # ─── M10: 燃料换算 ───
+ print("\n=== M10: 燃料换算 ===")
+ await pg.goto(f"{BASE}/fuel-converter", wait_until="networkidle", timeout=10000)
+ await pg.wait_for_timeout(500)
+ T("10.1 渲染", await pg.query_selector("#conv-form") is not None)
+
+ T("JS Errors", len(errs)==0, f"{len(errs)} errors")
+ if errs: print(f" Errors: {errs[:3]}")
+
+ await b.close()
+
+ # Report
+ print("\n"+"="*60)
+ print("TEST REPORT")
+ print("="*60)
+ passed=sum(1 for r in results if r["ok"])
+ failed=sum(1 for r in results if not r["ok"])
+ total=len(results)
+ print(f"Total: {total} | Passed: {passed} | Failed: {failed} | Rate: {passed/total*100:.1f}%")
+ if failed:
+ print("\nFailed:")
+ for r in results:
+ if not r["ok"]:
+ print(f" [FAIL] {r['name']}" + (f" -- {r['detail']}" if r['detail'] else ""))
+ print("="*60)
+ with open(SS/"test_report.json","w") as f: json.dump({"total":total,"passed":passed,"failed":failed,"results":results},f,ensure_ascii=False,indent=2)
+ print(f"Report: {SS}/test_report.json")
+ return failed==0
+
+if __name__=="__main__":
+ asyncio.run(run())