All remaining endpoint docs frontmatter'd: media-item bulk ops + audio surface, collections book-listing/preview, koreader rating/review/stats plugin protocol, hash-conflicts JSON list. Scope call (Claude): resolve_hash_conflict.md DELETED — the resolve POST renders an htmx fragment (renderResolved), a web-admin flow under rule 3; only the GET list is a JSON API. update_media_review skipped by Beam (correct): ratings/upsert_media_review.md already covers the PUT. Registry: 16 entries. koreader rating/review/stats all bind koreaderBookRef (query or body) — odd=half-star rating scale; audio track endpoint serves raw bytes (ServeContent, Range) — response nil. Fixed drift: deleted_annotations doc's secondary restore/purge fences unlabeled (gate validates labeled blocks against the ONE frontmatter route); chapters example labeled. UNVERIFIED: 1 (koreader book-ref fields, push_stats). make test 9/9.
93 lines
2.8 KiB
Markdown
93 lines
2.8 KiB
Markdown
---
|
|
method: GET
|
|
path: /api/media-items/:id/annotations/deleted
|
|
auth: jwt
|
|
area: media-items
|
|
---
|
|
<!-- source: internal/handlers/annotation_history.go:61 MediaHandler.GetDeletedAnnotations -->
|
|
|
|
# Deleted Annotations History
|
|
|
|
List, restore, or permanently delete tombstoned annotations (highlights,
|
|
notes, bookmarks) for a book. Deletions — from the web or propagated from a
|
|
synced device — are soft-deleted and retained for the sync retention window
|
|
(default 30 days), powering the book page's "Recently deleted" list. A
|
|
restore returns the row to the active set on every synced device; a purge
|
|
removes it immediately and irreversibly.
|
|
|
|
All endpoints require user JWT authentication and operate only on the
|
|
caller's own annotations.
|
|
|
|
## List Deleted Annotations
|
|
|
|
**Endpoint**: `GET /api/media-items/:id/annotations/deleted`
|
|
|
|
Returns tombstoned annotations for the book, newest deletion first.
|
|
|
|
### Response (200 OK)
|
|
|
|
```json example-response
|
|
{
|
|
"deleted_annotations": [
|
|
{
|
|
"id": "550e8400-e29b-41d4-a716-446655440000",
|
|
"annotation_type": "highlight",
|
|
"display_text": "the chosen text",
|
|
"secondary_text": "user note",
|
|
"color": "#ffd54f",
|
|
"deleted_at": "2026-08-22T15:04:05Z",
|
|
"created_at": "2026-08-01T10:00:00Z"
|
|
}
|
|
],
|
|
"total": 1
|
|
}
|
|
```
|
|
|
|
| Field | Description |
|
|
| --------------- | ------------------------------------------------------ |
|
|
| annotation_type | `highlight`, `note`, or `bookmark` |
|
|
| display_text | Highlighted text / note content / bookmark title |
|
|
| secondary_text | Note text (highlights) or notes field (bookmarks) |
|
|
|
|
## Restore Deleted Annotation
|
|
|
|
**Endpoint**: `POST /api/media-items/:id/annotations/:annotationId/restore`
|
|
|
|
Body (or query param) `annotation_type` must be `highlight`, `note`, or
|
|
`bookmark`. Clears the tombstone; the annotation reappears in the active
|
|
set and re-syncs to devices on their next pull.
|
|
|
|
```json
|
|
{ "annotation_type": "highlight" }
|
|
```
|
|
|
|
### Response (200 OK)
|
|
|
|
```json
|
|
{ "restored": true }
|
|
```
|
|
|
|
404 when no matching *deleted* annotation exists for this user and book.
|
|
|
|
## Permanently Delete Annotation
|
|
|
|
**Endpoint**: `DELETE /api/media-items/:id/annotations/:annotationId?annotation_type=highlight|note|bookmark`
|
|
|
|
Removes the tombstoned row from the history immediately. Irreversible —
|
|
unlike the tombstone itself, which is restorable until the retention window
|
|
lapses and the daily maintenance sweep purges it.
|
|
|
|
### Response (200 OK)
|
|
|
|
```json
|
|
{ "purged": true }
|
|
```
|
|
|
|
## Error Responses
|
|
|
|
| Code | Description |
|
|
| ---- | -------------------------------------------------- |
|
|
| 400 | Invalid IDs or missing/unknown `annotation_type` |
|
|
| 401 | Not authenticated |
|
|
| 404 | No matching deleted annotation |
|