docs: add zotero collection import design

This commit is contained in:
Saberlve 2026-04-15 11:48:43 +08:00
commit 0c0c773e61

View File

@ -0,0 +1,336 @@
# Zotero Collection Import Design
## Overview
This design upgrades the current left-panel import area from two temporary flows:
- import current selection from a bridge snapshot
- text-search fallback import
into one unified Zotero collection importer.
The new importer must visualize the user's current Zotero collection hierarchy, let the user browse collections, display the literature under the selected collection, remember cross-collection checkbox state, and batch-import selected items into the current project.
This work is intentionally scoped to the import surface only. The project card panel and writing panel remain in place.
## Goals
- Replace the current left-panel import widgets with one unified `Import From Zotero` section
- Visualize Zotero collections as a tree in the left panel
- When a collection is selected, show the literature under that collection and all descendant collections
- Support checkbox-based multi-selection across collection switches
- Remember previous selection state while the page remains open
- Support bulk actions:
- select all items from the current collection plus descendants
- clear all selected items
- import selected items into the current project
- Preserve the existing project panel, card panel, and writing panel structure
## Non-Goals
- Full drag-and-drop tree editing
- Editing Zotero collections
- Multi-pane import wizard
- Persisting import selections across browser restarts or across different users
- Replacing the bridge-based current-selection import flow at the API level
The bridge-based import endpoint may remain available, but it is no longer the main UI path.
## Product Scope
The importer is a left-panel replacement only.
### Unchanged Areas
- project creation
- project list
- project card list
- card detail viewer
- writing recommendation form
- writing plan form
### Replaced Area
The current pair of sections:
- `导入当前选中`
- `后备导入`
will be removed and replaced with:
- `从 Zotero 导入`
## User Flow
1. The user selects a project
2. The user browses the Zotero collection tree
3. The user clicks one collection
4. The UI loads all literature from that collection and all descendants
5. The user checks items to import
6. The user may switch to a different collection and continue selecting
7. Previously selected items remain selected
8. The user clicks `导入所选到当前项目`
9. The backend imports all selected items into the current project
10. The card panel refreshes with the newly imported cards
## Layout
The page stays three-column.
### Left Panel
The left panel contains:
1. `创建项目`
2. `项目列表`
3. `从 Zotero 导入`
### Import Section Structure
The import section has three internal regions:
1. collection tree
2. collection item list
3. sticky action bar
#### Collection Tree
- tree view with expand/collapse state
- current collection highlighted
- each node shows:
- collection name
- descendant-aware item count
#### Collection Item List
- shows items from the current collection and all descendant collections
- each row contains:
- checkbox
- title
- year
- item type
- compact metadata
- rows already selected in other collections remain checked when shown again
#### Sticky Action Bar
- selected count
- `全选当前目录及子目录`
- `清空选择`
- `导入所选到当前项目`
The action bar remains visible while scrolling within the import section.
## Interaction Semantics
### Collection Selection
Clicking a collection:
- sets it as the active collection
- loads all items under that collection plus descendants
- does not clear already selected items
### Checkbox State
Selection is tracked by `item_key`, not by visible row index.
This means:
- switching collections does not lose selection
- re-entering a collection restores prior checkbox state
- the selected count reflects the union of all selected items across the session
### Select-All Behavior
`全选当前目录及子目录` means:
- take the currently displayed item set
- merge all of those item keys into the global selected set
- keep existing selections from other collections intact
### Clear Behavior
`清空选择` means:
- clear the full selected item set
- uncheck all visible rows
- reset the selected count to zero
### Import Behavior
`导入所选到当前项目` means:
- require a currently selected project
- submit the full selected item key set to the backend
- keep the active collection and tree expansion state
- clear the selected item set on success
- refresh the project card list
## Frontend State Model
The page should maintain these state keys:
- `selectedCollectionKey`
- `expandedCollectionKeys`
- `selectedItemKeys`
- `visibleCollectionItems`
### State Rules
- `selectedCollectionKey` changes when the user clicks a tree node
- `expandedCollectionKeys` changes when nodes are opened or closed
- `selectedItemKeys` persists across collection switches during the current browser session
- `visibleCollectionItems` updates whenever the active collection changes
`selectedItemKeys` is the source of truth for checkbox rendering and batch import.
## Backend API Additions
Three API capabilities are required.
### 1. Collection Tree
`GET /api/zotero/collections/tree`
Returns the current Zotero collection hierarchy.
Each node must include:
- `collection_key`
- `name`
- `parent_key`
- `children`
- `direct_item_count`
- `descendant_item_count`
### 2. Collection Items
`GET /api/zotero/collections/{collection_key}/items?include_descendants=true`
Returns all regular Zotero items under the selected collection. In V1 of this feature, the UI will always request `include_descendants=true`.
Each returned item must include:
- `item_key`
- `title`
- `year`
- `item_type`
- `abstract`
- `collection_paths`
### 3. Batch Import
`POST /api/projects/{project_id}/imports/item-keys`
This endpoint already exists and should remain the import execution path for the new UI.
Input:
```json
{
"item_keys": ["ABCD1234", "EFGH5678"]
}
```
Output:
- `project_id`
- `imported_item_keys`
- `project_view`
## Reader Responsibilities
The Zotero reader must support collection-tree import without depending on bridge snapshots.
Required reader capabilities:
- build normalized collection tree data
- compute direct item counts per collection
- compute descendant-aware item counts per collection
- list all regular items under a collection with optional descendant inclusion
The reader should continue to ignore attachment, note, and annotation rows as import roots.
## Error Handling
### No Project Selected
- disable import submission or return a clear UI error
- do not clear selected checkboxes
### Collection Tree Load Failure
- show error state in the import section
- do not affect cards or writing sections
### Empty Collection
- show an empty-state list
- keep tree navigation usable
### Partial Import Failure
- report imported item keys and failed item keys separately if the backend can distinguish them
- do not silently report full success if part of the request failed
### Missing Local Zotero Data
- show import section unavailable
- preserve the rest of the application
## Testing Strategy
### Reader Tests
- build collection tree from fixture Zotero data
- compute descendant-aware item counts
- list collection items with descendant inclusion
### API Tests
- `GET /api/zotero/collections/tree`
- `GET /api/zotero/collections/{collection_key}/items?include_descendants=true`
- `POST /api/projects/{project_id}/imports/item-keys`
### UI Tests
The index template must include:
- collection tree container
- collection item list container
- selected count area
- select-all button
- clear-selection button
- import-selected button
## Constraints And Tradeoffs
### Why Tree + Side List Instead Of Tree-Mixed Items
The user explicitly chose:
- collection tree on one side
- item list shown after selecting a collection
This keeps scanning manageable for large libraries and avoids turning the tree itself into an overloaded mixed node structure.
### Why Session-Scoped Selection Memory
The user explicitly asked to remember previous selection state, but not to store durable drafts of import batches. Session-scoped state is enough for the workflow and avoids backend persistence complexity.
### Why Keep Cards And Writing Panels Unchanged
The import feature is a left-panel responsibility. Expanding it into a page-level mode would create unnecessary layout churn and broaden the implementation risk.
## Acceptance Criteria
This feature is complete when:
- the old `导入当前选中` and `后备导入` UI sections are gone
- the left panel shows a collection tree and descendant-aware collection item list
- selecting items survives collection switches during the session
- the user can select all items from a collection plus descendants
- the user can clear all current selections
- the user can batch-import the selected items into the active project
- the project card area refreshes after a successful import