diff --git a/docs/developer/api/collections/reorder_items.md b/docs/developer/api/collections/reorder_items.md new file mode 100644 index 00000000..3e5735bb --- /dev/null +++ b/docs/developer/api/collections/reorder_items.md @@ -0,0 +1,47 @@ +--- +method: PUT +path: /api/collections/:id/items/order +auth: jwt +area: collections +--- + + +# Reorder Collection Items + +Applies a static collection's manual playlist order. Owner-only; the payload +is the COMPLETE ordered id list — ids omitted keep their relative order +appended after (the service never deletes membership). + +## Example request + +```json example-request +{ + "item_ids": [ + "550e8400-e29b-41d4-a716-446655440000", + "660e8400-e29b-41d4-a716-446655440001" + ] +} +``` + +## Example response + +```json example-response +{ + "status": "reordered" +} +``` + +## Fields + +| Field | Type | Required | Notes | +| ----- | ---- | -------- | ----- | +| item_ids | array of string (uuid) | Yes | Complete ordered list of media item ids | + +## Errors + +| Status | Body | When | +| ------ | ---- | ---- | +| 400 | `{"error": "item_ids must be a non-empty ordered id list"}` / `{"error": "invalid media item id: ..."}` | malformed or empty list | +| 401 | `{"error": "unauthorized"}` | no/invalid JWT | +| 403 | `{"error": "only the collection owner can reorder it"}` | non-owner | +| 500 | `{"error": "..."}` | unexpected server error | \ No newline at end of file diff --git a/docs/developer/api/collections/update_rule.md b/docs/developer/api/collections/update_rule.md new file mode 100644 index 00000000..a1d4bc17 --- /dev/null +++ b/docs/developer/api/collections/update_rule.md @@ -0,0 +1,51 @@ +--- +method: PUT +path: /api/collections/:id/rules/:ruleId +auth: jwt +area: collections +--- + + +# Update Collection Rule + +Despite the route name, this endpoint **toggles a rule's enabled state only**. +It does not update the rule's field/operator/value — rules are replaced wholesale +via [Create Collection](create_collection.md) (`auto_assign_rules`) or added via +the rules endpoint. + +## Example request + +```json example-request +{ + "enabled": false +} +``` + +## Example response + +```json example-response +{ + "collection_id": "550e8400-e29b-41d4-a716-446655440000", + "is_smart": true, + "enabled": null, + "field": null, + "id": null, + "operator": null, + "priority": null, + "value": null +} +``` + +## Request fields + +| Field | Type | Required | Notes | +| ----- | ---- | -------- | ----- | +| enabled | boolean | yes | toggles the rule on/off | + +## Errors + +| Status | Body | When | +| ------ | ---- | ---- | +| 400 | `{"error": "invalid collection id"}` / `{"error": "rule id required"}` / `{"error": "invalid request"}` | malformed | +| 404 | `{"error": "rule not found"}` | no such rule | +| 500 | `{"error": "..."}` | unexpected server error | diff --git a/docs/developer/api/kobo/analytics_gettests.md b/docs/developer/api/kobo/analytics_gettests.md index ff76e426..7fea802c 100644 --- a/docs/developer/api/kobo/analytics_gettests.md +++ b/docs/developer/api/kobo/analytics_gettests.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/sync/kobo/:token/v1/analytics/gettests +auth: device-token +area: kobo +--- + + # Analytics GetTests > **Status: Coming Soon** — Native Kobo sync is not yet supported on real devices; this endpoint is under active development and may change. @@ -19,7 +27,7 @@ This endpoint requires device authentication (not user JWT). This is a Kobo comp ### Example Request -```json +```json example-request { "data": {} } @@ -27,7 +35,7 @@ This endpoint requires device authentication (not user JWT). This is a Kobo comp ## Response (200 OK) -```json +```json example-response { "result": "ok" } diff --git a/docs/developer/api/kobo/bookmark_sync.md b/docs/developer/api/kobo/bookmark_sync.md index c09ffec7..ae683653 100644 --- a/docs/developer/api/kobo/bookmark_sync.md +++ b/docs/developer/api/kobo/bookmark_sync.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/sync/kobo/:token/bookmark +auth: device-token +area: kobo +--- + + # Bookmark Sync > **Status: Coming Soon** — Native Kobo sync is not yet supported on real devices; this endpoint is under active development and may change. @@ -29,7 +37,7 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen ### Example Request -```json +```json example-request { "bookmarks": [ { @@ -45,10 +53,11 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen ## Response (200 OK) -```json +```json example-response { - "message": "Bookmarks synced successfully", - "synced_count": 1 + "BookmarksSynced": null, + "MarkupsSynced": null, + "Status": null } ``` diff --git a/docs/developer/api/kobo/initialization.md b/docs/developer/api/kobo/initialization.md index 2533bdef..981478dd 100644 --- a/docs/developer/api/kobo/initialization.md +++ b/docs/developer/api/kobo/initialization.md @@ -1,3 +1,11 @@ +--- +method: GET +path: /api/sync/kobo/:token/v1/initialization +auth: device-token +area: kobo +--- + + # Kobo Initialization > **Status: Coming Soon** — Native Kobo sync is not yet supported on real devices; this endpoint is under active development and may change. @@ -29,13 +37,11 @@ X-Device-Key: device-auth-key ## Response (200 OK) -```json +```json example-response { - "result": "ok", - "resources": { - "image_host": "https://cdn.kobo.com/...", - "image_url_quality_template": "{ImageId}/h270/{ImageId}_landscape_cover.jpg" - } + "last_sync": null, + "library_sync": null, + "total_books": null } ``` diff --git a/docs/developer/api/kobo/markup_sync.md b/docs/developer/api/kobo/markup_sync.md index 61787dc2..9ebf8381 100644 --- a/docs/developer/api/kobo/markup_sync.md +++ b/docs/developer/api/kobo/markup_sync.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/sync/kobo/:token/markup +auth: device-token +area: kobo +--- + + # Markup Sync > **Status: Coming Soon** — Native Kobo sync is not yet supported on real devices; this endpoint is under active development and may change. @@ -33,7 +41,7 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen ### Example Request -```json +```json example-request { "bookmarks": [ { @@ -53,10 +61,11 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen ## Response (200 OK) -```json +```json example-response { - "message": "Markup synced successfully", - "synced_count": 1 + "BookmarksSynced": null, + "MarkupsSynced": null, + "Status": null } ``` diff --git a/docs/developer/api/kobo/sync_from_server.md b/docs/developer/api/kobo/sync_from_server.md index ac21ba81..5ba37bec 100644 --- a/docs/developer/api/kobo/sync_from_server.md +++ b/docs/developer/api/kobo/sync_from_server.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/sync/kobo/:token/sync-from-server +auth: device-token +area: kobo +--- + + # Sync From Server > **Status: Coming Soon** — Native Kobo sync is not yet supported on real devices; this endpoint is under active development and may change. @@ -20,7 +28,7 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen ### Example Request -```json +```json example-request { "book_ids": ["content-id-1", "content-id-2"], "full_sync": false @@ -29,24 +37,11 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen ## Response (200 OK) -```json +```json example-response { - "books": [ - { - "ContentID": "content-id-1", - "Title": "Book Title", - "Author": "Author Name", - "ISBN": "978-0123456789", - "PublicationDate": "2026-02-08", - "FileSize": 1234567, - "CoverImageId": "cover-id-1", - "Metadata": { - "language": "en", - "publisher": "Publisher Name" - } - } - ], - "total": 2 + "BookmarksSent": null, + "BooksSynced": null, + "HighlightsSent": null } ``` diff --git a/docs/developer/api/koreader/get_library.md b/docs/developer/api/koreader/get_library.md index 3aa9c81f..dfb047d5 100644 --- a/docs/developer/api/koreader/get_library.md +++ b/docs/developer/api/koreader/get_library.md @@ -1,3 +1,11 @@ +--- +method: GET +path: /api/sync/koreader/library +auth: device-token +area: koreader +--- + + # Get Library Get library metadata for KOReader device. @@ -26,18 +34,11 @@ X-Device-Key: device-auth-key ## Response (200 OK) -```json +```json example-response { - "books": [ - { - "id": "uuid", - "title": "Book Title", - "authors": ["Author Name"], - "file": "book.epub", - "size": 1234567 - } - ], - "total": 42 + "last_sync": null, + "library_sync": null, + "total_books": null } ``` diff --git a/docs/developer/api/koreader/get_metadata.md b/docs/developer/api/koreader/get_metadata.md index 483c0d3d..f797d865 100644 --- a/docs/developer/api/koreader/get_metadata.md +++ b/docs/developer/api/koreader/get_metadata.md @@ -1,3 +1,11 @@ +--- +method: GET +path: /api/sync/koreader/metadata/:uuid +auth: device-token +area: koreader +--- + + # Get Metadata Get a book's stored progress and annotations for a KOReader device — @@ -23,7 +31,7 @@ Authorization: Bearer {device_token} ## Response (200 OK) -```json +```json example-response { "uuid": "774641f9-317b-4087-8e04-53bb4392ae56", "title": "1984", diff --git a/docs/developer/api/koreader/resolve_book.md b/docs/developer/api/koreader/resolve_book.md index c22c29dd..6c2b4ee3 100644 --- a/docs/developer/api/koreader/resolve_book.md +++ b/docs/developer/api/koreader/resolve_book.md @@ -1,4 +1,13 @@ -# Resolve Book +--- +method: GET +path: /api/sync/koreader/resolve +auth: device-token +area: koreader +--- + + +# Resolve Book:<|end|><|start|> assistant to=edit<|channel|>analysis <|constrain|>xml<|message|> +/home/nymusicman/Code/bookhoard/docs/developer/api/koreader/sync_bookmarks.md Map a book's file SHA-256 to its Bookhoard UUID without touching progress state. Used by devices to link a freshly downloaded book before their first @@ -32,12 +41,9 @@ Authorization: Bearer {device_token} ## Response (200 OK) -```json +```json example-response { - "book_uuid": "550e8400-e29b-41d4-a716-446655440000", - "sha256": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", - "title": "Book Title", - "author": "Author Name" + "book_uuid": "550e8400-e29b-41d4-a716-446655440000" } ``` diff --git a/docs/developer/api/koreader/sync_bookmarks.md b/docs/developer/api/koreader/sync_bookmarks.md index c1808d41..65d0f3d5 100644 --- a/docs/developer/api/koreader/sync_bookmarks.md +++ b/docs/developer/api/koreader/sync_bookmarks.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/sync/koreader/bookmarks +auth: device-token +area: koreader +--- + + # Sync Bookmarks Sync bookmarks, notes, and highlights from a KOReader device (bidirectional — the response also returns the server's current state for the book so the device can reconcile). @@ -52,7 +60,7 @@ KOReader paints highlights from a fixed palette of color names; the web reader u ### Example Request -```json +```json example-request { "book_sha256": "64-hex-char-sha256", "bookmarks": [ @@ -83,7 +91,7 @@ KOReader paints highlights from a fixed palette of color names; the web reader u ## Response (200 OK) -```json +```json example-response { "sync_status": "ok", "bookmarks_synced": 1, diff --git a/docs/developer/api/koreader/sync_progress.md b/docs/developer/api/koreader/sync_progress.md index 4279928b..ef717a99 100644 --- a/docs/developer/api/koreader/sync_progress.md +++ b/docs/developer/api/koreader/sync_progress.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/sync/koreader/progress +auth: device-token +area: koreader +--- + + # Sync Progress Push reading progress from a KOReader device. @@ -42,7 +50,7 @@ Authorization: Bearer {device_token} Content-Type: application/json ``` -```json +```json example-request { "books": [ { @@ -67,11 +75,12 @@ Content-Type: application/json ## Response (202 Accepted) -```json +```json example-response { "sync_status": "ok", "books_synced": 1, - "timestamp": "2026-09-26T21:25:09Z" + "timestamp": "2026-09-26T21:25:09Z", + "device_updated": null } ``` diff --git a/internal/docs/schema.go b/internal/docs/schema.go index 5d8c50b9..2fbf74d6 100644 --- a/internal/docs/schema.go +++ b/internal/docs/schema.go @@ -552,4 +552,58 @@ var Schemas = map[string]Schema{ // Delegates to ListMediaItems with library_id injected. Response: json.RawMessage(`{"data": [{}]}`), }, + + // --- Beam batch 6: kobo/koreader (device-token) + collections missing --- + "POST /api/sync/kobo/:token/markup": { + Request: AnyJSONObject{}, // kobo protocol payload (ReadingSync/BookmarkSync) + Response: handlers.KoboSyncStatus{}, // kobo firmware naming: Status/MarkupsSynced + }, + "POST /api/sync/kobo/:token/bookmark": { + Request: AnyJSONObject{}, // kobo bookmark payload + Response: handlers.KoboSyncStatus{}, + }, + "POST /api/sync/kobo/:token/v1/analytics/gettests": { + Request: AnyJSONObject{}, // kobo analytics POST body + // A/B test payload — dynamic keys (tests/features/configuration). + Response: AnyJSONObject{}, + }, + "GET /api/sync/kobo/:token/v1/initialization": { + // NOTE: returns the library sync payload, not the init response. + Response: handlers.KoboLibraryResponse{}, + }, + "POST /api/sync/kobo/:token/sync-from-server": { + Request: AnyJSONObject{}, // kobo sync POST body + Response: handlers.KoboServerSyncResponse{}, + }, + "POST /api/sync/koreader/progress": { + Request: handlers.KOReaderProgressRequest{}, + Response: handlers.KOReaderSyncResponse{}, + }, + "GET /api/sync/koreader/resolve": { + Response: handlers.KOReaderResolveResponse{}, + }, + "GET /api/sync/koreader/metadata/:uuid": { + // Hand-built map in the handler. + Response: AnyJSONObject{}, + }, + "GET /api/sync/koreader/library": { + Response: handlers.KOReaderLibraryResponse{}, + }, + "POST /api/sync/koreader/bookmarks": { + Request: AnyJSONObject{}, // {highlights: [...]} inline struct in handler + Response: AnyJSONObject{}, // hand-built map in the handler + }, + "PUT /api/collections/:id/items/order": { + // Inline request {item_ids} — pinned by sample. + Request: json.RawMessage(`{"item_ids": []}`), + Response: json.RawMessage(`{"status": "reordered"}`), + }, + "PUT /api/collections/:id/rules/:ruleId": { + // Inline anonymous request struct — pinned by sample. + Request: json.RawMessage(`{"rule": {}}`), + Response: json.RawMessage(`{ + "id": "", "collection_id": "", "field": "", "operator": "", + "value": "", "priority": 0, "enabled": false, "is_smart": false + }`), + }, }