fix(docs): Work Order 2 — correct stale paths (11 docs + 3 Bruno)

Fix all wrong-path artifacts identified by the audit:
- Kobo sync endpoints (init/bookmark/markup/sync-from-server/analytics): add
  missing :token device segment (6 doc files incl. kobo-protocol.md)
- Highlights/notes update+delete: add missing /:id media-item prefix
- media-items/download_media_item.md: removed (static /uploads route, not an
  API endpoint; info about the file route is recoverable from OPDS docs)
- Bruno: /libraries/visible -> /visibility, /collections/books missing id,
  /audio/0 -> track_index
- operations/troubleshooting.md: same /libraries/visible -> /visibility fix
- media-items/get_audio_track.md + get_audio_chapters.md: /audio/0 examples fixed
- Deleted monolithic docs/developer/api-reference.md (duplicate of split docs)
- Fixed 4 stale entries in docs/developer/api/api-reference.md (split index)

Audit re-run: orphan docs 0, orphan Bruno 6 (all scenario files with literal IDs).
This commit is contained in:
John O'Keefe committed 2026-10-24 14:44:19 -04:00
1 parent cc893f758e
commit 50282895f5
19 files changed
+29 -1831

No files matched your search

+2 -2
View File
@@ -5,7 +5,7 @@ info:
http: http:
method: GET method: GET
url: "{{base_url}}/api/collections/books" url: "{{base_url}}/api/collections/{{collection_id}}/books"
body: body:
type: json type: json
data: |- data: |-
@@ -27,7 +27,7 @@ docs: |-
**Method:** GET **Method:** GET
**Endpoint:** /api/collections/books **Endpoint:** /api/collections/{{collection_id}}/books
**Authentication:** Required (Bearer token) **Authentication:** Required (Bearer token)
+2 -2
View File
@@ -5,7 +5,7 @@ info:
http: http:
method: GET method: GET
url: "{{base_url}}/api/libraries/visible" url: "{{base_url}}/api/libraries/visibility"
headers: headers:
- name: "" - name: ""
value: application/json value: application/json
@@ -24,7 +24,7 @@ docs: |-
**Method:** GET **Method:** GET
**Endpoint:** /api/libraries/visible **Endpoint:** /api/libraries/visibility
**Authentication:** Required (Bearer token) **Authentication:** Required (Bearer token)
+1 -1
View File
@@ -5,7 +5,7 @@ info:
http: http:
method: GET method: GET
url: "{{base_url}}/api/media-items/{{media_item_id}}/audio/0" url: "{{base_url}}/api/media-items/{{media_item_id}}/audio/{{track_index}}"
headers: headers:
- name: Range - name: Range
value: bytes=0-1023 value: bytes=0-1023
File diff suppressed because it is too large. Load diff
+5 -5
View File
@@ -256,11 +256,11 @@ See [KOReader Sync](koreader/) and [Sync Protocol](sync/koreader-protocol.md)
See [Kobo Sync](kobo/) and [Sync Protocol](sync/kobo-protocol.md) See [Kobo Sync](kobo/) and [Sync Protocol](sync/kobo-protocol.md)
- POST /api/sync/kobo/markup - Sync markup highlights - POST /api/sync/kobo/:token/markup - Sync markup highlights
- POST /api/sync/kobo/bookmark - Sync bookmarks - POST /api/sync/kobo/:token/bookmark - Sync bookmarks
- POST /api/sync/kobo/v1/analytics/gettests - Analytics endpoint - POST /api/sync/kobo/:token/v1/analytics/gettests - Analytics endpoint
- GET /api/sync/kobo/v1/initialization - Initialize Kobo sync - GET /api/sync/kobo/:token/v1/initialization - Initialize Kobo sync
- POST /api/sync/kobo/sync-from-server - Push content to device - POST /api/sync/kobo/:token/sync-from-server - Push content to device
## WebSocket ## WebSocket
@@ -2,7 +2,7 @@
Delete a highlight. Delete a highlight.
**Endpoint**: `DELETE /api/media-items/highlights/{highlight_id}` **Endpoint**: `DELETE /api/media-items/:id/highlights/:highlightId`
**Auth**: Required **Auth**: Required
## Path Parameters ## Path Parameters
@@ -2,7 +2,7 @@
Update an existing highlight. Update an existing highlight.
**Endpoint**: `PUT /api/media-items/highlights/{highlight_id}` **Endpoint**: `PUT /api/media-items/:id/highlights/:highlightId`
**Auth**: Required **Auth**: Required
**Content-Type**: `application/json` **Content-Type**: `application/json`
@@ -4,7 +4,7 @@
Kobo analytics endpoint (device compatibility). Kobo analytics endpoint (device compatibility).
**Endpoint**: `POST /api/sync/kobo/v1/analytics/gettests` **Endpoint**: `POST /api/sync/kobo/:token/v1/analytics/gettests`
**Auth**: Required (Device authentication) **Auth**: Required (Device authentication)
## Device Authentication ## Device Authentication
+1 -1
View File
@@ -4,7 +4,7 @@
Sync bookmarks from Kobo device. Sync bookmarks from Kobo device.
**Endpoint**: `POST /api/sync/kobo/bookmark` **Endpoint**: `POST /api/sync/kobo/:token/bookmark`
**Auth**: Required (Device authentication) **Auth**: Required (Device authentication)
## Device Authentication ## Device Authentication
+2 -2
View File
@@ -4,7 +4,7 @@
Initialize Kobo device sync. Initialize Kobo device sync.
**Endpoint**: `GET /api/sync/kobo/v1/initialization` **Endpoint**: `GET /api/sync/kobo/:token/v1/initialization`
**Auth**: Required (Device authentication) **Auth**: Required (Device authentication)
## Device Authentication ## Device Authentication
@@ -22,7 +22,7 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen
### Example Request ### Example Request
```http ```http
GET /api/sync/kobo/v1/initialization GET /api/sync/kobo/:token/v1/initialization
X-Device-ID: 550e8400-e29b-41d4-a716-446655440000 X-Device-ID: 550e8400-e29b-41d4-a716-446655440000
X-Device-Key: device-auth-key X-Device-Key: device-auth-key
``` ```
+1 -1
View File
@@ -4,7 +4,7 @@
Sync markup highlights and annotations from Kobo device. Sync markup highlights and annotations from Kobo device.
**Endpoint**: `POST /api/sync/kobo/markup` **Endpoint**: `POST /api/sync/kobo/:token/markup`
**Auth**: Required (Device authentication) **Auth**: Required (Device authentication)
## Device Authentication ## Device Authentication
+1 -1
View File
@@ -4,7 +4,7 @@
Push content and metadata to Kobo device. Push content and metadata to Kobo device.
**Endpoint**: `POST /api/sync/kobo/sync-from-server` **Endpoint**: `POST /api/sync/kobo/:token/sync-from-server`
**Auth**: Required (Device authentication) **Auth**: Required (Device authentication)
## Device Authentication ## Device Authentication
@@ -1,48 +0,0 @@
# Download Media Item
Download a media item file (EPUB, PDF, etc.) from the Bookhoard server.
Book files are served by the authenticated file route, the same one the web reader uses. Build the URL from the media item's `library_id` and relative `file_path` (both returned by the media item list/get endpoints):
**Endpoint**: `GET /uploads/library-{library_id}/{file_path}`
**Auth**: Required (JWT - Bearer header or session cookie)
The `file_path` segments are URL-escaped individually; slashes are preserved. `cover_image_path` uses the same route.
## Path Parameters
| Parameter | Type | Required | Description |
| ----------- | ------ | -------- | ------------------------------------ |
| library_id | string | Yes | Library UUID (the item's library) |
| file_path | string | Yes | The item's relative `file_path` |
## Response
**Success (200 OK)**: Binary file data
**Response Headers**:
- `Content-Type`: MIME type by file extension (`application/epub+zip`, `application/pdf`, …; `application/octet-stream` fallback)
- `Cache-Control`: `public, max-age=86400`
## Error Responses
| Code | Description |
| ---- | --------------------------- |
| 400 | Invalid library ID or path |
| 401 | Missing/invalid token |
| 404 | File not found on disk |
## Example
```bash
curl -O -H "Authorization: Bearer $TOKEN" \
"http://localhost:8765/uploads/library/550e8400-.../books/1984.epub"
```
(URL shape: `/uploads/library-{uuid}/{escaped-relative-path}`.)
## Notes
- **Do not rely on `GET /api/media-items/:id/download`** — it appears in older docs but is **not registered**; `MediaHandler.DownloadBook` exists as dead code. Use the file route above.
- OPDS-capable devices may alternatively use the device-authenticated `GET /opds/devices/{deviceId}/download/{bookId}`, which supports on-the-fly format conversion (epub, kepub, pdf, cbz).
@@ -23,7 +23,7 @@ which file model produced them.
"tracks": [ "tracks": [
{ {
"index": 0, "index": 0,
"url": "/api/media-items/{id}/audio/0", "url": "/api/media-items/{id}/audio/{trackIndex}",
"title": "01 First", "title": "01 First",
"path": "Author/Title/01 First.mp3", "path": "Author/Title/01 First.mp3",
"start": 0.0, "start": 0.0,
@@ -40,5 +40,5 @@ answers **403** on every track (same gate as the download endpoint).
```bash ```bash
curl -H "Authorization: Bearer $TOKEN" \ curl -H "Authorization: Bearer $TOKEN" \
-H "Range: bytes=0-1023" \ -H "Range: bytes=0-1023" \
"http://localhost:8765/api/media-items/550e8400-.../audio/0" "http://localhost:8765/api/media-items/550e8400-.../audio/{track_index}"
``` ```
+1 -1
View File
@@ -2,7 +2,7 @@
Delete a note. Delete a note.
**Endpoint**: `DELETE /api/media-items/notes/{note_id}` **Endpoint**: `DELETE /api/media-items/:id/notes/:noteId`
**Auth**: Required **Auth**: Required
## Path Parameters ## Path Parameters
+1 -1
View File
@@ -2,7 +2,7 @@
Update an existing note. Update an existing note.
**Endpoint**: `PUT /api/media-items/notes/{note_id}` **Endpoint**: `PUT /api/media-items/:id/notes/:noteId`
**Auth**: Required **Auth**: Required
**Content-Type**: `application/json` **Content-Type**: `application/json`
+2 -2
View File
@@ -6,7 +6,7 @@ Kobo uses a proprietary sync protocol with JSON payloads.
## Kobo Markup Sync ## Kobo Markup Sync
**Endpoint**: `POST /api/sync/kobo/markup` **Endpoint**: `POST /api/sync/kobo/:token/markup`
**Auth**: Device token required **Auth**: Device token required
**Content-Type**: `application/json` **Content-Type**: `application/json`
@@ -33,7 +33,7 @@ Kobo uses a proprietary sync protocol with JSON payloads.
### Example Request ### Example Request
```http ```http
POST /api/sync/kobo/markup POST /api/sync/kobo/:token/markup
Authorization: Bearer device-token Authorization: Bearer device-token
x-kobo-device: {"DeviceId":"device-id","Model":"Kobo Clara"} x-kobo-device: {"DeviceId":"device-id","Model":"Kobo Clara"}
Content-Type: application/json Content-Type: application/json
+5 -5
View File
@@ -168,10 +168,10 @@ podman-compose ps # or: docker compose ps
podman-compose exec db psql -U postgres -d bookhoard -c "SELECT 1;" # or: docker compose exec db ... podman-compose exec db psql -U postgres -d bookhoard -c "SELECT 1;" # or: docker compose exec db ...
# Test API endpoint: # Test API endpoint:
curl -s http://localhost:8765/api/libraries/visible curl -s http://localhost:8765/api/libraries/visibility
# For remote servers, use actual IP: # For remote servers, use actual IP:
curl -s http://SERVER_IP:8765/api/libraries/visible curl -s http://SERVER_IP:8765/api/libraries/visibility
``` ```
## 🚀 Quick Verification ## 🚀 Quick Verification
@@ -186,7 +186,7 @@ podman-compose ps # or: docker compose ps
podman-compose exec db psql -U postgres -d bookhoard -c "SELECT 1;" # or: docker compose exec db ... podman-compose exec db psql -U postgres -d bookhoard -c "SELECT 1;" # or: docker compose exec db ...
# Test API endpoint # Test API endpoint
curl -s http://localhost:8765/api/libraries/visible curl -s http://localhost:8765/api/libraries/visibility
# Check application logs # Check application logs
docker compose logs app docker compose logs app
@@ -209,7 +209,7 @@ docker compose up -d
# 4. Verify # 4. Verify
docker compose ps docker compose ps
curl -s http://localhost:8765/api/libraries/visible curl -s http://localhost:8765/api/libraries/visibility
``` ```
## 🌐 Production Deployment ## 🌐 Production Deployment
@@ -319,7 +319,7 @@ The current setup follows best practices:
When properly set up, you should see: When properly set up, you should see:
1. **Healthy containers**: `docker compose ps` shows "Up" status 1. **Healthy containers**: `docker compose ps` shows "Up" status
2. **Working API**: `curl http://localhost:8765/api/libraries/visible` returns JSON 2. **Working API**: `curl http://localhost:8765/api/libraries/visibility` returns JSON
3. **New tables**: `media_highlights` and `media_notes` exist with proper schema 3. **New tables**: `media_highlights` and `media_notes` exist with proper schema
4. **No port conflicts**: Application binds to port 8765 without errors 4. **No port conflicts**: Application binds to port 8765 without errors
5. **Database ready**: PostgreSQL accepts connections and serves requests 5. **Database ready**: PostgreSQL accepts connections and serves requests