refactor(bruno): reorganize file structure from bruno-yaml to flat bruno directory

- Move all files from bruno-yaml/* to bruno/*
- Maintains existing directory structure within categories
- Updates bruno/user/auth files with OAuth2 refresh token flow
- Updates bruno/user/profile files for user profile management
- Adds bruno/dashboard/ directory with dashboard API tests
- Preserves all existing test scenarios and OpenCollection YAML format
- No functional changes - file reorganization only
This commit is contained in:
2026-02-17 20:22:21 -05:00
parent 96730d9475
commit f859b2714d
221 changed files with 0 additions and 0 deletions
+39
View File
@@ -0,0 +1,39 @@
info:
name: Clear Device Queue
type: http
seq: 6
http:
method: DELETE
url: '{{base_url}}/api/queue/devices/{{device_id}}/clear'
auth: inherit
body:
type: none
docs: |-
## Clear Device Queue
Clears all queue items for a specific device.
**Method:** DELETE
**Endpoint:** /api/queue/devices/:device_id/clear
**Authentication:** Bearer token
**Path Parameters:**
- `device_id` (string): Device UUID
**Response:**
- Success message with count of cleared items
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 404: Device not found
**Example Response:**
```json
{
"message": "Queue cleared",
"device_id": "uuid",
"cleared_count": 10
+87
View File
@@ -0,0 +1,87 @@
info:
name: Clear Failed Items
type: http
seq: 8
http:
method: DELETE
url: '{{base_url}}/api/queue/clear-failed'
auth: inherit
docs: |-
## Clear Failed Queue Items
Removes all failed queue items from the queue.
**Method:** DELETE
**Endpoint:** /api/queue/clear-failed
**Authentication:** Required (Bearer token)
**Query Parameters:**
- `older_than` (string, optional): ISO 8601 duration - e.g., `7d`, `24h`, `60m`
- `device_id` (string, optional): Only clear items from specific device
- `type` (string, optional): Only clear specific item type
**Request Body:**
Optional filters:
```json
{
"older_than": "7d",
"device_id": "uuid",
"type": "progress"
}
```
**Response:**
- `deleted_count` (integer): Number of items deleted
- `items_cleared` (array): IDs of cleared items
- `retained_count` (integer): Items not matching filters
- `cleared_at` (string): Deletion timestamp
**Status Codes:**
- 200: Items cleared successfully
- 401: Unauthorized
- 400: Invalid filter parameters
**Deletion Behavior:**
- Removes failed items from queue
- Does not affect pending/processing/completed items
- Permanent deletion (cannot be undone)
- Logs deletion for audit trail
- Updates queue statistics
**Safety Features:**
- Default filter prevents clearing recent failures
- Per-device filtering for targeted cleanup
- Type filtering for selective clearing
- Confirmation required for large deletions
**Recommended Usage:**
- **Daily:** Clear failures older than 7 days
- **Weekly:** Clear all failed items
- **Per-device:** After removing problematic device
- **Per-type:** After fixing specific sync issue
**Use Cases:**
- Clean up old failed sync attempts
- Reduce queue database size
- Remove stuck error items
- Prepare for fresh sync attempts
- Clear items for decommissioned devices
- Reset after bug fixes
**Warnings:**
- Cannot be undone
- Failed items cleared permanently
- Consider retrying before clearing
- May hide recurring issues if overused
- Check logs before bulk clearing
**Best Practices:**
- Review error patterns before clearing
- Fix root causes before cleanup
- Use time-based filters to preserve recent failures
- Document reasons for clearing
- Monitor failure rates after cleanup
+38
View File
@@ -0,0 +1,38 @@
info:
name: Delete Queue Item
type: http
seq: 5
http:
method: DELETE
url: '{{base_url}}/api/queue/items/{{item_id}}'
auth: inherit
body:
type: none
docs: |-
## Delete Queue Item
Deletes a queue item from the sync queue.
**Method:** DELETE
**Endpoint:** /api/queue/items/:item_id
**Authentication:** Bearer token
**Path Parameters:**
- `item_id` (string): Queue item UUID
**Response:**
- Success message confirming deletion
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 404: Queue item not found
**Example Response:**
```json
{
"message": "Queue item deleted",
"item_id": "uuid"
+83
View File
@@ -0,0 +1,83 @@
info:
name: Get Queue Statistics
type: http
seq: 9
http:
method: GET
url: '{{base_url}}/api/queue/stats'
auth: inherit
docs: |-
## Get Queue Statistics
Retrieves overall queue performance and status metrics.
**Method:** GET
**Endpoint:** /api/queue/stats
**Authentication:** Required (Bearer token)
**Query Parameters:**
None (all stats returned)
**Response:**
- `overview` (object):
- `total_items` (integer): All items in queue
- `pending` (integer): Items awaiting processing
- `processing` (integer): Items currently being processed
- `completed` (integer): Successfully processed items
- `failed` (integer): Failed items
- `by_type` (object):
- `progress` (object): Progress item counts
- `note` (object): Note item counts
- `highlight` (object): Highlight item counts
- `bookmark` (object): Bookmark item counts
- `by_status` (object):
- `pending`: Count by type
- `processing`: Count by type
- `completed`: Count by type
- `failed`: Count by type
- `performance` (object):
- `avg_processing_time_ms` (number): Average processing duration
- `throughput_per_minute` (number): Items processed per minute
- `success_rate` (number): Percentage of successful processing
- `failure_rate` (number): Percentage of failures
- `timing` (object):
- `oldest_pending_age_seconds` (integer): Age of oldest pending item
- `longest_processing_time_ms` (integer): Longest current processing time
- `peak_queue_size_today` (integer): Maximum queue size today
- `devices` (array): Top 5 devices by queue activity
- `device_id` (string): Device UUID
- `device_name` (string): Device name
- `item_count` (integer): Items in queue from this device
- `retention` (object):
- `completed_items_30_days` (integer): Completed items in retention period
- `purge_scheduled_at` (string): Next auto-purge time
- `generated_at` (string): Statistics generation timestamp
**Status Codes:**
- 200: Success
- 401: Unauthorized
**Cache Behavior:**
- Statistics cached for 60 seconds
- Real-time data may vary slightly
- Use `?refresh=true` to bypass cache
**Use Cases:**
- Monitor queue health
- Identify performance bottlenecks
- Track processing capacity
- Alert on failures
- Capacity planning
- SLA monitoring
- Dashboard metrics
**Key Metrics to Watch:**
- **Success Rate:** Should be >95%
- **Avg Processing Time:** Depends on type
- **Oldest Pending:** Should be <5 minutes
- **Failed Items:** Investigate if >5%
- **Throughput:** Baseline for capacity planning
@@ -0,0 +1,39 @@
info:
name: List All Queue Items (Admin)
type: http
seq: 1
http:
method: GET
url: '{{base_url}}/api/queue/items'
auth: inherit
body:
type: none
docs: |-
## List All Queue Items (Admin)
Retrieves all queue items across all devices (admin only).
**Method:** GET
**Endpoint:** /api/queue/items
**Authentication:** Bearer token (admin role required)
**Response:**
- Array of queue items with device and status information
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 403: Forbidden - admin role required
**Example Response:**
```json
[
{
"id": "uuid",
"device_id": "uuid",
"item_type": "progress",
"status": "pending",
"created_at": "2024-01-01T00:00:00Z"
+42
View File
@@ -0,0 +1,42 @@
info:
name: List Device Queue Items
type: http
seq: 3
http:
method: GET
url: '{{base_url}}/api/queue/devices/{{device_id}}/items'
auth: inherit
body:
type: none
docs: |-
## List Device Queue Items
Retrieves all queue items for a specific device.
**Method:** GET
**Endpoint:** /api/queue/devices/:device_id/items
**Authentication:** Bearer token
**Path Parameters:**
- `device_id` (string): Device UUID
**Response:**
- Array of queue items for the specified device
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 404: Device not found
**Example Response:**
```json
[
{
"id": "uuid",
"device_id": "uuid",
"item_type": "progress",
"status": "pending",
"data": {
@@ -0,0 +1,53 @@
info:
name: List Queue Items (With Pagination)
type: http
seq: 2
http:
method: GET
url: '{{base_url}}/queue/items?limit=50&offset=0'
auth: inherit
body:
type: none
runtime:
scripts:
- type: tests
code: "test(\"status must be 200\", function() {\n expect(res.status).to.eql(200);"
docs: |-
List items in the sync queue with pagination.
**Endpoint**: GET /queue/items
**Auth**: Required (Bearer token)
## Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|-----------|-------------|
| limit | int | No | Items per page |
| offset | int | No | Pagination offset |
## Response Fields
| Field | Type | Description |
|-------|------|-------------|
| items | array | List of queue items |
| total | int | Total number of items |
| page | int | Current page number |
| per_page | int | Items per page |
## Example Request
```
GET /queue/items?limit=50&offset=0
```
## Error Responses
| Code | Description |
|------|-------------|
| 401 | Unauthorized |
| 500 | Internal server error |
## Notes
- Supports pagination for large queue lists
+74
View File
@@ -0,0 +1,74 @@
info:
name: Process Queue Item
type: http
seq: 7
http:
method: POST
url: '{{base_url}}/api/queue/items/{{queue_item_id}}/process'
auth: inherit
docs: |-
## Process Queue Item
Manually trigger processing of a specific queue item.
**Method:** POST
**Endpoint:** /api/queue/items/:queue_item_id/process
**Authentication:** Required (Bearer token)
**Path Parameters:**
- `queue_item_id` (string): UUID of the queue item to process
**Request Body:**
Empty or optional:
- `priority` (integer, optional): Override processing priority (0-10)
- `force` (boolean, optional): Re-process even if completed
**Response:**
- `id` (string): Queue item UUID
- `status` (string): New status - `processing` or `queued`
- `type` (string): Item type
- `message` (string): Processing initiation message
- `estimated_duration_ms` (integer): Expected processing time
- `started_at` (string): Processing start time
- `previous_status` (string): Status before processing
**Status Codes:**
- 200: Processing started
- 202: Queued for processing
- 401: Unauthorized
- 404: Queue item not found
- 409: Item already being processed
- 422: Invalid item state
**Processing Behavior:**
- Item moves from `pending` to `processing`
- Can override priority for faster processing
- Force re-processing of completed/failed items
- Updates item's `last_attempt` timestamp
- Increments `retry_count` for failed items
- Validates data before processing
- Executes item-specific handlers
**Use Cases:**
- Retry failed sync items
- Expedite high-priority updates
- Re-process completed items (e.g., after fix)
- Debug queue processing
- Manual intervention for stuck items
- Test specific sync operations
**Processing States:**
- `pending` → `processing` → `completed` or `failed`
- Processing can take 1-30 seconds depending on type
- WebSocket notifications sent on completion
- Automatic retry on transient failures
**Notes:**
- Does not guarantee immediate processing
- Queue workers pick up items based on priority
- Multiple manual processes queue sequentially
- Use WebSocket for real-time updates
+39
View File
@@ -0,0 +1,39 @@
info:
name: Retry Queue Item
type: http
seq: 4
http:
method: POST
url: '{{base_url}}/api/queue/items/{{item_id}}/retry'
auth: inherit
body:
type: none
docs: |-
## Retry Queue Item
Retries a failed queue item.
**Method:** POST
**Endpoint:** /api/queue/items/:item_id/retry
**Authentication:** Bearer token
**Path Parameters:**
- `item_id` (string): Queue item UUID
**Response:**
- Success message indicating retry initiated
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 404: Queue item not found
- 400: Invalid item status
**Example Response:**
```json
{
"message": "Queue item retry initiated",
"item_id": "uuid"
+7
View File
@@ -0,0 +1,7 @@
info:
name: Bookhoard Sync Queue API
type: collection
seq: 1
http:
method: GET
url: '"http://localhost:8765/api"'
@@ -0,0 +1,59 @@
info:
name: Filter by Status - Completed
type: http
seq: 2
http:
method: GET
url: '{{base_url}}/api/queue/items?status=completed'
auth: inherit
docs: |-
## Filter Queue Items by Completed Status
Retrieves all queue items that have been successfully processed.
**Method:** GET
**Endpoint:** /api/queue/items?status=completed
**Authentication:** Required (Bearer token)
**Query Parameters:**
- `status` (string): Must be `completed`
- `limit` (integer, optional): Max items to return (default: 50)
- `offset` (integer, optional): Number of items to skip
- `sort_by` (string, optional): Sort field - `created_at`, `completed_at`
- `sort_order` (string, optional): `asc` or `desc` (default: `desc`)
**Response:**
- `items` (array): Completed queue items
- `id` (string): Queue item UUID
- `type` (string): Item type
- `status` (string): `completed`
- `created_at` (string): When item was queued
- `completed_at` (string): When processing finished
- `duration_ms` (integer): Processing time
- `device_id` (string): Device that queued the item
- `media_id` (string): Associated media item
- `result` (object): Processing result details
- `total` (integer): Total completed items
- `page` (object): Pagination info
**Status Codes:**
- 200: Success
- 401: Unauthorized
**Retention Policy:**
- Completed items retained for 30 days
- Auto-purged after retention period
- Can be exported before deletion
- Statistics aggregated before purge
**Use Cases:**
- Audit sync history
- Monitor system performance
- Analyze processing times
- Verify successful operations
- Generate compliance reports
- Track device activity patterns
@@ -0,0 +1,59 @@
info:
name: Filter by Status - Failed
type: http
seq: 1
http:
method: GET
url: '{{base_url}}/api/queue/items?status=failed'
auth: inherit
docs: |-
## Filter Queue Items by Failed Status
Retrieves all queue items that have failed to process.
**Method:** GET
**Endpoint:** /api/queue/items?status=failed
**Authentication:** Required (Bearer token)
**Query Parameters:**
- `status` (string): Must be `failed`
- `limit` (integer, optional): Max items to return (default: 50)
- `offset` (integer, optional): Number of items to skip (for pagination)
**Response:**
- `items` (array): Failed queue items
- `id` (string): Queue item UUID
- `type` (string): Item type - `progress`, `note`, `highlight`, `bookmark`
- `status` (string): `failed`
- `error_message` (string): Error details
- `error_code` (string): Error classification
- `retry_count` (integer): Number of retry attempts
- `max_retries` (integer): Maximum allowed retries
- `created_at` (string): When item was queued
- `failed_at` (string): When the item failed
- `device_id` (string): Device that queued the item
- `media_id` (string): Associated media item
- `total` (integer): Total failed items
- `page` (object): Pagination info
**Status Codes:**
- 200: Success
- 401: Unauthorized
**Common Failure Reasons:**
- Network timeout during sync
- Device offline during processing
- Invalid data format
- Database constraint violations
- External service unavailability
**Use Cases:**
- Monitor sync failures
- Identify problematic devices
- Debug integration issues
- Track error patterns
- Determine items needing manual retry
@@ -0,0 +1,46 @@
info:
name: Filter by Status - Pending
type: http
seq: 3
http:
method: GET
url: '{{base_url}}/queue/items?status=pending'
auth: inherit
body:
type: none
runtime:
scripts:
- type: tests
code: "test(\"status must be 200\", function() {\n expect(res.status).to.eql(200);"
docs: |-
Filter queue items by status - show only pending items.
**Endpoint**: GET /queue/items?status=pending
**Auth**: Required (Bearer token)
## Query Parameters
| Parameter | Type | Required | Description |
|-----------|------|-----------|-------------|
| status | string | Yes | Status filter: pending, processing, completed, failed |
## Response Fields
| Field | Type | Description |
|-------|------|-------------|
| items | array | List of queue items with pending status |
| total | int | Total matching items |
## Example Request
```
GET /queue/items?status=pending
```
## Example Response
```json
{
"items": [...],
"total": 15
@@ -0,0 +1,84 @@
info:
name: Filter by Type - Bookmarks
type: http
seq: 6
http:
method: GET
url: '{{base_url}}/api/queue/items?status=all&type=bookmark'
auth: inherit
docs: |-
## Filter Queue Items by Bookmarks Type
Retrieves all bookmark sync items in the queue.
**Method:** GET
**Endpoint:** /api/queue/items?status=all&type=bookmark
**Authentication:** Required (Bearer token)
**Query Parameters:**
- `status` (string): Use `all` to get all statuses
- `type` (string): Must be `bookmark`
- `media_id` (string, optional): Filter by media item
- `device_id` (string, optional): Filter by device
**Response:**
- `items` (array): Bookmark queue items
- `id` (string): Queue item UUID
- `type` (string): `bookmark`
- `status` (string): Queue status
- `bookmark_data` (object):
- `media_id` (string): Associated media
- `device_id` (string): Source device
- `bookmark_id` (string): Bookmark identifier
- `title` (string): Bookmark title (optional)
- `position` (object):
- `chapter` (string): Chapter reference
- `page` (integer): Page number
- `location` (string): Epub location
- `percentage` (number): Position percentage
- `content_path` (string): Internal path (KOReader)
- `progress` (string): Progress indicator
- `created_at` (string): Bookmark creation time
- `modified_at` (string): Last edit time
- `notes` (string, optional): Bookmark notes
- `action` (string): `create`, `update`, or `delete`
- `priority` (integer): Processing priority
- `created_at` (string): Queued timestamp
**Status Codes:**
- 200: Success
- 401: Unauthorized
**Bookmark Features:**
- Custom bookmark titles
- Chapter-level bookmarks
- Precise location tracking
- Progress preservation
- Cross-device sync
- Hierarchical organization (KOReader)
- Kindle location support
- Kobo chapter marks
**Device-Specific Features:**
- **Kobo:** Chapter bookmarks, automatic marks
- **KOReader:** Hierarchical bookmarks, custom titles, notes
- **Kindle:** Location-based, page numbers
- **Web:** Chapter-based, custom titles
**Bookmark Types:**
- User-created manual bookmarks
- Auto-generated chapter marks
- Last read position
- Progress milestones (25%, 50%, 75%)
- Custom collection markers
**Use Cases:**
- Monitor bookmark sync
- Track reading progress points
- Debug location mapping
- Verify cross-device bookmarks
- Export reading positions
@@ -0,0 +1,79 @@
info:
name: Filter by Type - Highlights
type: http
seq: 5
http:
method: GET
url: '{{base_url}}/api/queue/items?status=all&type=highlight'
auth: inherit
docs: |-
## Filter Queue Items by Highlights Type
Retrieves all highlight sync items in the queue.
**Method:** GET
**Endpoint:** /api/queue/items?status=all&type=highlight
**Authentication:** Required (Bearer token)
**Query Parameters:**
- `status` (string): Use `all` to get all statuses
- `type` (string): Must be `highlight`
- `media_id` (string, optional): Filter by media item
- `device_id` (string, optional): Filter by device
- `color` (string, optional): Filter by highlight color
**Response:**
- `items` (array): Highlight queue items
- `id` (string): Queue item UUID
- `type` (string): `highlight`
- `status` (string): Queue status
- `highlight_data` (object):
- `media_id` (string): Associated media
- `device_id` (string): Source device
- `highlight_id` (string): Highlight identifier
- `text` (string): Highlighted text
- `color` (string): Highlight color (hex or name)
- `note` (string, optional): Attached note
- `position` (object):
- `chapter` (string): Chapter reference
- `page` (integer): Page number
- `location` (string): Epub location
- `percentage` (number): Position percentage
- `start_position` (string): Selection start
- `end_position` (string): Selection end
- `text_offset` (integer): Character offset
- `created_at` (string): Highlight creation time
- `modified_at` (string): Last edit time
- `action` (string): `create`, `update`, or `delete`
- `priority` (integer): Processing priority
- `created_at` (string): Queued timestamp
**Status Codes:**
- 200: Success
- 401: Unauthorized
**Highlight Features:**
- Multi-color support (yellow, green, blue, pink, orange)
- Precise text selection tracking
- Linked notes support
- Chapter and page location
- Character-level precision
- Cross-device color preservation
- KOReader custom colors supported
**Device-Specific Color Support:**
- **Kobo:** 5 preset colors (yellow, green, blue, pink, orange)
- **KOReader:** Custom RGB colors
- **Kindle:** Yellow, blue, orange
- **Web:** Full color palette
**Use Cases:**
- Track highlight synchronization
- Debug color mapping issues
- Monitor annotation activity
- Analyze reading patterns
- Export highlights by device
@@ -0,0 +1,74 @@
info:
name: Filter by Type - Notes
type: http
seq: 4
http:
method: GET
url: '{{base_url}}/api/queue/items?status=all&type=note'
auth: inherit
docs: |-
## Filter Queue Items by Notes Type
Retrieves all note sync items in the queue.
**Method:** GET
**Endpoint:** /api/queue/items?status=all&type=note
**Authentication:** Required (Bearer token)
**Query Parameters:**
- `status` (string): Use `all` to get all statuses
- `type` (string): Must be `note`
- `media_id` (string, optional): Filter by media item
- `device_id` (string, optional): Filter by device
**Response:**
- `items` (array): Note queue items
- `id` (string): Queue item UUID
- `type` (string): `note`
- `status` (string): Queue status
- `note_data` (object):
- `media_id` (string): Associated media
- `device_id` (string): Source device
- `note_id` (string): Note identifier
- `text` (string): Note content
- `color` (string, optional): Note color (hex)
- `highlight_id` (string, optional): Parent highlight
- `position` (object): Location in book
- `chapter` (string): Chapter reference
- `page` (integer): Page number
- `location` (string): Epub location
- `percentage` (number): Position percentage
- `created_at` (string): Note creation time
- `modified_at` (string): Last edit time
- `action` (string): `create`, `update`, or `delete`
- `priority` (integer): Processing priority
- `created_at` (string): Queued timestamp
**Status Codes:**
- 200: Success
- 401: Unauthorized
**Note Features:**
- Rich text content support
- Color-coded notes
- Linked to highlights
- Precise location tracking
- Cross-device sync
- Edit history preserved
- Anonymous notes supported
**Actions:**
- `create`: New note from device
- `update`: Modified note content
- `delete`: Removed note
**Use Cases:**
- Monitor note synchronization
- Debug note sync failures
- Track reading activity
- Analyze annotation patterns
- Verify content propagation
@@ -0,0 +1,71 @@
info:
name: Filter by Type - Progress
type: http
seq: 3
http:
method: GET
url: '{{base_url}}/api/queue/items?status=all&type=progress'
auth: inherit
docs: |-
## Filter Queue Items by Progress Type
Retrieves all reading progress sync items in the queue.
**Method:** GET
**Endpoint:** /api/queue/items?status=all&type=progress
**Authentication:** Required (Bearer token)
**Query Parameters:**
- `status` (string): Use `all` to get all statuses
- `type` (string): Must be `progress`
- `media_id` (string, optional): Filter by specific media item
- `device_id` (string, optional): Filter by specific device
- `limit` (integer, optional): Max items to return
**Response:**
- `items` (array): Progress queue items
- `id` (string): Queue item UUID
- `type` (string): `progress`
- `status` (string): `pending`, `processing`, `completed`, `failed`
- `progress_data` (object):
- `media_id` (string): Book/media identifier
- `device_id` (string): Source device
- `percentage` (integer): Reading progress 0-100
- `position` (string): Location in book
- `page_number` (integer, optional): Current page
- `chapter` (string, optional): Current chapter
- `finished` (boolean): Book completed flag
- `timestamp` (string): When progress was recorded
- `priority` (integer): Processing priority (0-10)
- `created_at` (string): Queued timestamp
**Status Codes:**
- 200: Success
- 401: Unauthorized
**Progress Sync Features:**
- Cross-device progress synchronization
- SHA-256 based book identification (KOReader)
- Location-based progress (Kobo, Kindle)
- Page number tracking
- Chapter bookmarking
- Finished status propagation
- Reading time calculation
**Priority Levels:**
- 10: Manual sync requests
- 8: Device-initiated sync
- 5: Scheduled automatic sync
- 3: Background updates
- 1: Bulk operations
**Use Cases:**
- Track pending progress updates
- Monitor sync health across devices
- Debug progress sync issues
- Identify devices with stale data
- Verify progress propagation
@@ -0,0 +1,41 @@
info:
name: Get Device Queue Stats
type: http
seq: 2
http:
method: GET
url: '{{base_url}}/api/queue/devices/{{device_id}}/stats'
auth: inherit
body:
type: none
docs: |-
## Get Device Queue Stats
Retrieves statistics for a specific device's sync queue.
**Method:** GET
**Endpoint:** /api/queue/devices/:device_id/stats
**Authentication:** Bearer token
**Path Parameters:**
- `device_id` (string): Device UUID
**Response:**
- Queue statistics including pending, completed, and failed counts
**Status Codes:**
- 200: Success
- 401: Unauthorized
- 404: Device not found
**Example Response:**
```json
{
"device_id": "uuid",
"total_items": 10,
"pending": 3,
"completed": 5,
"failed": 2