docs: add comprehensive project documentation and clean up snapshot-related files and components

This commit is contained in:
taDuc
2026-05-14 23:50:49 +07:00
parent b220798978
commit 57e3d6b3e5
13 changed files with 1527 additions and 288 deletions
+280
View File
@@ -0,0 +1,280 @@
# UHM Editor - state và vòng đời dữ liệu
Tài liệu này mô tả state thật đang được dùng bởi editor hiện tại.
Entry point chính là `useEditorSessionState()``useEditorState()`.
## 1. Hai lớp state chính
Editor đang tách làm hai khối:
- `useEditorSessionState()`
- state UI, session, form, project, timeline, background, wiki
- `useEditorState(initialData, snapshotUndo)`
- state draft hình học, diff và undo
Nói ngắn gọn:
- `session state` quyết định editor đang nhìn cái gì và panel đang thao tác gì
- `editor state` quyết định geometry nào đang tồn tại trong draft và khác baseline ra sao
## 2. State geometry trung tâm
### `initialData`
- Nằm ở `useEditorSessionState()`
-`FeatureCollection` đang được nạp vào editor khi mở project hoặc restore commit
- Khi thay đổi, `useEditorState()` sẽ reset toàn bộ draft và baseline tương ứng
### `draft`
- Nằm trong `useEditorState()`
- Là nguồn dữ liệu render trực tiếp cho `Map`
- Mọi thao tác create/update/delete geometry đều đi qua đây
### `draftRef`
- Bản ref của `draft`
- Được dùng trong event handlers của map engine để luôn đọc được state mới nhất mà không phải rebind callback liên tục
### `initialMapRef`
- `Map<featureId, Feature>` tạo từ `initialData`
- Là baseline để tính diff giữa draft hiện tại và dữ liệu gốc của session
### `changes`
- Kết quả `diffDraftToInitial(draft, initialMapRef.current)`
- Map theo `feature.properties.id`
- Mỗi phần tử có thể là:
- `create`
- `update`
- `delete`
Lưu ý: diff hiện chỉ là cơ chế nhận biết geometry nào đã thay đổi so với baseline. Snapshot commit thực tế vẫn được build từ toàn bộ `draft` cộng với các snapshot bảng phụ.
### `changeCount`
- Số lượng geometry thay đổi hiện tại
- Được cộng thêm dirty state của wiki/entity/entity-wiki để tạo `pendingSaveCount`
## 3. Undo state
Undo được quản lý bởi `useUndoStack()`.
Kiểu action hiện có:
- `create`
- `delete`
- `update`
- `properties`
- `snapshot_entities`
- `snapshot_wikis`
- `snapshot_entity_wiki`
- `group`
Ý nghĩa:
- geometry create/delete/update/properties undo được trực tiếp trên `draft`
- snapshot entity/wiki/link undo được apply qua `snapshotUndo` API truyền vào `useEditorState`
- `group` dùng để gom nhiều thay đổi thành một thao tác undo logic
Editor hiện có `undo`, nhưng chưa có redo.
## 4. Session state theo nhóm
### 4.1. Mode và selection
- `mode: EditorMode`
- `selectedFeatureIds`
- `selectedGeometryEntityIds`
`selectedFeatureIds` là state gốc cho:
- panel metadata geometry
- bind entity
- bind geometry
- focus geometry từ search/binding panel
### 4.2. Form state
- `entityForm`
- dùng cho form tạo entity local
- `geometryMetaForm`
- `type_key`
- `time_start`
- `time_end`
- `binding`
`geometryMetaForm.binding` hiện chủ yếu là giá trị hiển thị/đồng bộ UI, còn chỉnh sửa binding thật đi qua `GeometryBindingPanel`.
### 4.3. Project/session task state
`useProjectSessionState()` gom các cờ async vào một state machine nhỏ:
- `sectionTask: "idle" | "saving" | "submitting" | "opening-project"`
Từ đó sinh ra:
- `isSaving`
- `isSubmitting`
- `isOpeningSection`
Ngoài ra còn có:
- `activeSection`
- `projectState`
- `sectionCommits`
- `baselineSnapshot`
- `commitTitle`
### 4.4. Timeline state
`useTimelineState()` giữ:
- `timelineYear`
- `timelineDraftYear`
- `isTimelineLoading`
- `timelineStatus`
Trong page hiện tại, timeline filter đang dùng `timelineDraftYear`.
Không có fetch dữ liệu project theo `timelineYear`; timeline đang là client-side visibility filter.
### 4.5. Background/session UI
`useBackgroundSessionState()` giữ:
- `backgroundVisibility`
- `isBackgroundVisibilityReady`
Giá trị thật được load từ `localStorage` key `uhm.backgroundLayerVisibility.v1`.
### 4.6. Wiki/session state
`useWikiSessionState()` giữ:
- `snapshotWikis`
- `snapshotEntityWikiLinks`
Đây là single source of truth cho phần wiki trong snapshot commit.
## 5. Snapshot state
Editor đang làm việc với 3 snapshot collection chính ngoài geometry:
- `snapshotEntities`
- `snapshotWikis`
- `snapshotEntityWikiLinks`
Chúng đại diện cho "current session snapshot", không phải danh sách delta thô.
Ví dụ:
- entity ref được giữ bằng `operation: "reference"`
- entity/wiki local mới tạo có thể mang `operation: "create"`
- link entity-wiki mới tạo dùng `operation: "binding"`
Khi commit, `buildEditorSnapshot()` sẽ so với `baselineSnapshot` để chuyển các collection này thành snapshot đúng semantic cho backend.
## 6. Baseline snapshot là gì
`baselineSnapshot` là snapshot đang được xem như gốc của session hiện tại.
Nó được cập nhật khi:
- mở project
- commit thành công
- restore từ một commit
`baselineSnapshot` được dùng để:
- biết link nào là `reference`, link nào là `binding`, link nào là `delete`
- biết wiki/entity nào là thay đổi thực sự so với snapshot trước
- giữ lại inline entity/wiki từ snapshot trước nếu user chưa xóa chúng
## 7. Derived state quan trọng trong page
### `timelineVisibleDraft`
-`draft` đã qua filter timeline nếu `timelineFilterEnabled = true`
- geometry mới tạo trong session không bị timeline filter ẩn
### `snapshotEntitiesVisible`
- loại bỏ các row `delete`
- dedupe theo `id`
### `selectedFeatures`
- map từ `selectedFeatureIds` sang feature thật trong `editor.draft.features`
### `isMultiEditValid`
- chỉ `true` khi tất cả geometry đang chọn cùng `geometry.type`
- một số thao tác bind sẽ chặn nếu giá trị này là `false`
### `pendingSaveCount`
Được tính như sau:
- `editor.changeCount`
- `+1` nếu wiki dirty
- `+1` nếu entities dirty
- `+1` nếu entity-wiki dirty
Đây là con số dùng trong UI commit, không phải số record backend chắc chắn sẽ thay đổi.
## 8. Dirty detection
Dirty check của:
- `snapshotWikis`
- `snapshotEntities`
- `snapshotEntityWikiLinks`
đều đang làm bằng cách normalize trước rồi so `JSON.stringify`.
Điều này đủ thực dụng cho snapshot cỡ vừa, nhưng cần lưu ý:
- không tối ưu cho dữ liệu rất lớn
- phụ thuộc vào tính ổn định của thứ tự mảng sau normalize
## 9. State được persist vào localStorage
Hiện editor chỉ persist hai nhóm nhỏ:
- background layer visibility
- key: `uhm.backgroundLayerVisibility.v1`
- map projection
- key: `uhm:mapProjection`
Editor hiện không persist toàn bộ draft/project snapshot vào localStorage.
Nếu cần autosave local draft, đó là tính năng phải làm thêm, không phải behavior hiện tại.
## 10. Khi nào state bị reset
### Reset toàn phần
Xảy ra khi:
- mở project khác
- mở lại project
- restore commit
Hiệu ứng:
- `initialData` đổi
- `useEditorState()` reset `draft`
- `undoStack` bị clear
- baseline map được build lại
### Reset cục bộ
- đổi selection có thể reset `geometryMetaForm`
- đóng/mở wiki modal không reset snapshot wiki, chỉ reset form local của modal
## 11. Một số giới hạn hiện tại cần nhớ khi đọc code
-`undo`, chưa có `redo`
- timeline state có `timelineYear`, nhưng page hiện dùng `timelineDraftYear` cho filtering
- dirty count của commit không tương ứng một-một với số mutation backend
- map selection, binding filter và timeline filter đều là state client-side