diff --git a/AGENTS.md b/AGENTS.md index a349b5120..b075289cc 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -205,6 +205,44 @@ npm run dev The server will resolve all paths relative to the current working directory. +## Artifact Specifications + +Each new feature or major change should be documented in an artifact specification file. These files serve as the planning and record of implementation for the feature. + +### Organization + +- **Location**: All artifact specifications are stored in the `artifacts/` directory. +- **Dated Folders**: Specifications should be placed in a subfolder named by the current date (e.g., `artifacts/YYYY-MM-DD/`). +- **Filename**: Use descriptive names for the specification files (e.g., `move-to-library-specification.md`). + +### Managing Folders + +A `Makefile` is provided in the `artifacts/` directory to quickly set up the folder for the current day: + +```bash +cd artifacts +make # Runs the 'today' target to create the dated folder +``` + +### Purpose + +Artifact specifications should serve as a source of truth for the feature's lifecycle. A high-quality specification includes: + +1. **Detailed Overview**: Clear summary of the user-facing functionality. +2. **API & Data Contracts**: Explicit documentation of new endpoints (methods, paths, payloads) and schema changes. +3. **Traceability (Files Modified)**: A table of all files touched in the implementation, categorized (e.g., Backend, Frontend, Docs). +4. **Architectural Decisions**: Explanation of *why* certain patterns were used (e.g., shared utility functions, state management choices). +5. **Localization**: Tracking of new string keys or translation updates. +6. **Verification Plan**: Concrete testing steps (manual or automated) to verify the implementation. +7. **Limitations & Future Work**: Explicitly stating what is *not* supported or known edge cases that weren't addressed. + +### Best Practices + +- **Update as you go**: The artifact should be updated during implementation if the plan changes. +- **Be Specific**: Avoid vague descriptions. If a function is moved to a controller, name the function and the controller. +- **Use Tables**: Tables are great for listing files or comparing before/after states. +- **Include Code Snippets**: For API definitions or complex logic flows, short code/JSON snippets are highly encouraged. + ## Related Documentation - [Main Documentation](https://audiobookshelf.org/docs) diff --git a/artifacts/2026-02-06-move-to-library-feature.md b/artifacts/2026-02-06-move-to-library-feature.md deleted file mode 100644 index 3d256e230..000000000 --- a/artifacts/2026-02-06-move-to-library-feature.md +++ /dev/null @@ -1,132 +0,0 @@ -# Move to Library Feature Documentation - -**Date:** 2026-02-06 - -## Overview - -This feature allows users to move audiobooks (and podcasts) between libraries of the same type via a context menu option. It supports both single-item moves and batch moves for multiple selected items. - -## API Endpoints - -### Single Item Move - -``` -POST /api/items/:id/move -``` - -### Batch Move - -``` -POST /api/items/batch/move -``` - -**Request Body (Single):** - -```json -{ - "targetLibraryId": "uuid-of-target-library", - "targetFolderId": "uuid-of-target-folder" // optional, uses first folder if not provided -} -``` - -**Request Body (Batch):** - -```json -{ - "libraryItemIds": ["uuid1", "uuid2"], - "targetLibraryId": "uuid-of-target-library", - "targetFolderId": "uuid-of-target-folder" // optional -} -``` - -**Permissions:** Requires delete permission (`canDelete`) - -**Validations:** - -- Target library must exist -- Target library must have same `mediaType` as source (book ↔ book, podcast ↔ podcast) -- Cannot move to the same library -- Destination path must not already exist (checked per item) - -**Response (Single):** Returns updated library item JSON on success **Response (Batch):** Returns summary of successes, failures, and error details - ---- - -## Files Modified - -### Backend - -| File | Description | -| --------------------------------------------- | ------------------------------------------------------------------ | -| `server/controllers/LibraryItemController.js` | Implementation of `handleMoveLibraryItem`, `move`, and `batchMove` | -| `server/routers/ApiRouter.js` | Route registration for single and batch move | - -### Frontend - -| File | Description | -| ------------------------------------------------------ | ------------------------------------------------ | -| `client/components/modals/item/MoveToLibraryModal.vue` | Modal component (handles single and batch modes) | -| `client/components/app/Appbar.vue` | Added "Move to library" to batch context menu | -| `client/store/globals.js` | State management for move modal visibility | -| `client/components/cards/LazyBookCard.vue` | Single item context menu integration | -| `client/pages/item/_id/index.vue` | Single item page context menu integration | -| `client/layouts/default.vue` | Modal registration | -| `client/strings/en-us.json` | Localization strings | - -### Localization Strings Added - -- `ToastItemsMoved`, `ToastItemsMoveFailed` -- `LabelMovingItems` -- (Legacy) `ToastItemMoved`, `ToastItemMoveFailed`, `LabelMovingItem`, etc. - ---- - -## Implementation Details - -### Shared Moving Logic (`handleMoveLibraryItem`) - -To ensure consistency, the core logic is encapsulated in a standalone function `handleMoveLibraryItem` in `LibraryItemController.js`. This prevents "this" binding issues when called from `ApiRouter`. - -Steps performed for each item: - -1. Fetch target library with folders -2. Select target folder (first if not specified) -3. Calculate new path: `targetFolder.path + itemFolderName` -4. Check destination doesn't exist -5. Move files using `fs.move(oldPath, newPath)` -6. Update database: `libraryId`, `libraryFolderId`, `path`, `relPath` -7. Update `libraryFiles` paths -8. Update media specific paths (`audioFiles`, `ebookFile`, `podcastEpisodes`) -9. Handle Series and Authors: - - Moves/merges series and authors to target library - - Copies metadata and images if necessary - - Deletes source series/authors if they become empty -10. Emit socket events: `item_removed` (old library), `item_added` (new library) -11. Reset filter data for both libraries - -### Batch Move Strategy - -The `batchMove` endpoint iterates through the provided IDs and calls `handleMoveLibraryItem` for each valid item. It maintains a success/fail count and collects error messages for the final response. - -### Frontend Modal Behavior - -The `MoveToLibraryModal` automatically detects if it's in batch mode by checking if `selectedMediaItems` has content and no single `selectedLibraryItem` is set. It dynamically adjusts its titles and labels (e.g., "Moving items" vs "Moving item"). - ---- - -## Testing - -1. **Single Move**: Verify via context menu on a book card. -2. **Batch Move**: - - Select multiple items using checkboxes - - Use "Move to library" in the top batch bar ⋮ menu - - Verify all items are moved correctly in the UI and filesystem. -3. **Incompatible Move**: Try moving a book to a podcast library (should be blocked). - ---- - -## Known Limitations / Future Work - -- Does not support moving to different folder within same library. -- Rollback is per-item; a failure in a batch move does not roll back successfully moved previous items. -- No overall progress bar for large batch moves (it's sequential and blocking).