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

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)
- POST /api/sync/kobo/markup - Sync markup highlights
- POST /api/sync/kobo/bookmark - Sync bookmarks
- POST /api/sync/kobo/v1/analytics/gettests - Analytics endpoint
- GET /api/sync/kobo/v1/initialization - Initialize Kobo sync
- POST /api/sync/kobo/sync-from-server - Push content to device
- POST /api/sync/kobo/:token/markup - Sync markup highlights
- POST /api/sync/kobo/:token/bookmark - Sync bookmarks
- POST /api/sync/kobo/:token/v1/analytics/gettests - Analytics endpoint
- GET /api/sync/kobo/:token/v1/initialization - Initialize Kobo sync
- POST /api/sync/kobo/:token/sync-from-server - Push content to device
## WebSocket
@@ -2,7 +2,7 @@
Delete a highlight.
**Endpoint**: `DELETE /api/media-items/highlights/{highlight_id}`
**Endpoint**: `DELETE /api/media-items/:id/highlights/:highlightId`
**Auth**: Required
## Path Parameters
@@ -2,7 +2,7 @@
Update an existing highlight.
**Endpoint**: `PUT /api/media-items/highlights/{highlight_id}`
**Endpoint**: `PUT /api/media-items/:id/highlights/:highlightId`
**Auth**: Required
**Content-Type**: `application/json`
@@ -4,7 +4,7 @@
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)
## Device Authentication
+1 -1
View File
@@ -4,7 +4,7 @@
Sync bookmarks from Kobo device.
**Endpoint**: `POST /api/sync/kobo/bookmark`
**Endpoint**: `POST /api/sync/kobo/:token/bookmark`
**Auth**: Required (Device authentication)
## Device Authentication
+2 -2
View File
@@ -4,7 +4,7 @@
Initialize Kobo device sync.
**Endpoint**: `GET /api/sync/kobo/v1/initialization`
**Endpoint**: `GET /api/sync/kobo/:token/v1/initialization`
**Auth**: Required (Device authentication)
## Device Authentication
@@ -22,7 +22,7 @@ This endpoint requires device authentication (not user JWT). Kobo devices authen
### Example Request
```http
GET /api/sync/kobo/v1/initialization
GET /api/sync/kobo/:token/v1/initialization
X-Device-ID: 550e8400-e29b-41d4-a716-446655440000
X-Device-Key: device-auth-key
```
+1 -1
View File
@@ -4,7 +4,7 @@
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)
## Device Authentication
+1 -1
View File
@@ -4,7 +4,7 @@
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)
## 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": [
{
"index": 0,
"url": "/api/media-items/{id}/audio/0",
"url": "/api/media-items/{id}/audio/{trackIndex}",
"title": "01 First",
"path": "Author/Title/01 First.mp3",
"start": 0.0,
@@ -40,5 +40,5 @@ answers **403** on every track (same gate as the download endpoint).
```bash
curl -H "Authorization: Bearer $TOKEN" \
-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.
**Endpoint**: `DELETE /api/media-items/notes/{note_id}`
**Endpoint**: `DELETE /api/media-items/:id/notes/:noteId`
**Auth**: Required
## Path Parameters
+1 -1
View File
@@ -2,7 +2,7 @@
Update an existing note.
**Endpoint**: `PUT /api/media-items/notes/{note_id}`
**Endpoint**: `PUT /api/media-items/:id/notes/:noteId`
**Auth**: Required
**Content-Type**: `application/json`
+2 -2
View File
@@ -6,7 +6,7 @@ Kobo uses a proprietary sync protocol with JSON payloads.
## Kobo Markup Sync
**Endpoint**: `POST /api/sync/kobo/markup`
**Endpoint**: `POST /api/sync/kobo/:token/markup`
**Auth**: Device token required
**Content-Type**: `application/json`
@@ -33,7 +33,7 @@ Kobo uses a proprietary sync protocol with JSON payloads.
### Example Request
```http
POST /api/sync/kobo/markup
POST /api/sync/kobo/:token/markup
Authorization: Bearer device-token
x-kobo-device: {"DeviceId":"device-id","Model":"Kobo Clara"}
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 ...
# 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:
curl -s http://SERVER_IP:8765/api/libraries/visible
curl -s http://SERVER_IP:8765/api/libraries/visibility
```
## 🚀 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 ...
# Test API endpoint
curl -s http://localhost:8765/api/libraries/visible
curl -s http://localhost:8765/api/libraries/visibility
# Check application logs
docker compose logs app
@@ -209,7 +209,7 @@ docker compose up -d
# 4. Verify
docker compose ps
curl -s http://localhost:8765/api/libraries/visible
curl -s http://localhost:8765/api/libraries/visibility
```
## 🌐 Production Deployment
@@ -319,7 +319,7 @@ The current setup follows best practices:
When properly set up, you should see:
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
4. **No port conflicts**: Application binds to port 8765 without errors
5. **Database ready**: PostgreSQL accepts connections and serves requests