feat: add project export and import functionality

- Implemented `pcli project export` command to export project hierarchy as JSON.
- Added `pcli project import` command to import project data from JSON.
- Created user client to fetch user details for comment attribution.
- Introduced new data structures for export and import processes.
- Ensured name-based references in exports and handled conflicts during imports.
- Added versioning and progress reporting for import operations.
- Updated documentation and specifications for new features.
This commit is contained in:
2026-03-04 19:53:55 +00:00
parent e352fd530f
commit e973b2ce20
49 changed files with 1492 additions and 3303 deletions
+85
View File
@@ -0,0 +1,85 @@
# project-export Spec
## Purpose
Enable users to export a complete Planka project hierarchy (boards, lists, cards, labels, tasks, comments) to a portable JSON format for backup, migration, or documentation purposes.
## Requirements
### Requirement: Export project hierarchy to JSON
The system SHALL export a complete project hierarchy as a JSON object to stdout. The export SHALL include: project metadata, boards, lists, labels, cards (with list and label name references), task lists, tasks, and comments.
#### Scenario: Export entire project
- **WHEN** user runs `pcli project export <project-id-or-name>`
- **THEN** the system outputs a JSON object to stdout containing the project and all its boards with their full hierarchy
#### Scenario: Export with board filter
- **WHEN** user runs `pcli project export <project-id-or-name> --board <board-name-or-id>`
- **THEN** the system outputs a JSON object containing only the specified board (and its full hierarchy) under the project
#### Scenario: Board filter does not match
- **WHEN** user runs `pcli project export <project> --board <nonexistent>`
- **THEN** the system exits with an error indicating the board was not found
### Requirement: Export format uses version envelope
The export JSON SHALL contain a `version` field (integer, currently `1`), an `exportedAt` timestamp (ISO 8601), and a `project` object.
#### Scenario: Export envelope structure
- **WHEN** an export is generated
- **THEN** the root JSON object contains exactly `version`, `exportedAt`, and `project` keys
- **THEN** `version` is `1`
- **THEN** `exportedAt` is a valid ISO 8601 timestamp
### Requirement: Export uses name-based references
The export SHALL use names instead of IDs for all cross-references. Cards SHALL reference their list by `listName` and their labels by `labelNames` (array of label name strings). No Planka IDs SHALL appear in the export.
#### Scenario: Card references list by name
- **WHEN** a card belongs to a list named "In Progress"
- **THEN** the exported card has `"listName": "In Progress"` instead of a list ID
#### Scenario: Card references labels by name
- **WHEN** a card has labels "Bug" and "Urgent"
- **THEN** the exported card has `"labelNames": ["Bug", "Urgent"]`
### Requirement: Export preserves ordering
The export SHALL include `position` fields for boards, lists, labels, and cards to maintain their display ordering on import.
#### Scenario: List ordering preserved
- **WHEN** a board has lists "Todo" (position 1), "Doing" (position 2), "Done" (position 3)
- **THEN** the exported lists include their position values
### Requirement: Export includes comment attribution
Each exported comment SHALL have its text prefixed with `(Original comment by <username>)\n` where `<username>` is resolved from the comment's userId. If the userId cannot be resolved, the prefix SHALL use `unknown user`.
#### Scenario: Comment with known author
- **WHEN** a comment was authored by user "jsmith"
- **THEN** the exported comment text starts with `(Original comment by jsmith)\n`
#### Scenario: Comment with unresolvable author
- **WHEN** a comment's userId does not match any known user
- **THEN** the exported comment text starts with `(Original comment by unknown user)\n`
### Requirement: Export excludes user-specific data
The export SHALL NOT include cardMemberships, creatorUserId, or userId fields. Only textual comment attribution (as a text prefix) SHALL preserve user information.
#### Scenario: Card memberships excluded
- **WHEN** a card has members assigned
- **THEN** the exported card does not contain membership data
### Requirement: Export includes task lists and tasks
The export SHALL include task lists and their tasks for each card. Each task list SHALL contain its tasks inline. Tasks SHALL include `name` and `isCompleted` fields.
#### Scenario: Card with task lists
- **WHEN** a card has a task list "Checklist" with tasks "Item 1" (complete) and "Item 2" (incomplete)
- **THEN** the exported card includes the task list with both tasks and their completion status
### Requirement: Project identified by name or ID
The `<project-id-or-name>` argument SHALL accept either a Planka project ID or a project name. If a name is provided, the system SHALL look up the project by name. If multiple projects match the name, the system SHALL exit with an error.
#### Scenario: Project by name
- **WHEN** user provides a project name that matches exactly one project
- **THEN** the system exports that project
#### Scenario: Ambiguous project name
- **WHEN** user provides a project name that matches multiple projects
- **THEN** the system exits with an error listing the matches