diff --git a/docs/developer/api/authentication/login.md b/docs/developer/api/authentication/login.md index 95145f6b..ef76e385 100644 --- a/docs/developer/api/authentication/login.md +++ b/docs/developer/api/authentication/login.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/auth/login +auth: none +area: authentication +--- + + # Login User Authenticate with email and password. @@ -15,7 +23,7 @@ Authenticate with email and password. ### Example Request -```json +```json example-request { "login": "user@example.com", "password": "SecureP@ss123!" @@ -24,10 +32,9 @@ Authenticate with email and password. ## Response (200 OK) -```json +```json example-response { "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "refresh_token": "d4f5g6h7...", "token_type": "Bearer", "expires_in": 604800, "user": { diff --git a/docs/developer/api/authentication/logout.md b/docs/developer/api/authentication/logout.md index 9ff506e7..ac7ed691 100644 --- a/docs/developer/api/authentication/logout.md +++ b/docs/developer/api/authentication/logout.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/auth/logout +auth: none +area: authentication +--- + + # Logout User Invalidate the current JWT token. @@ -19,9 +27,13 @@ POST /api/auth/logout Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` -## Response (204 No Content) +## Response (200 OK) -No response body. +```json example-response +{ + "message": "logged out successfully" +} +``` ## Error Responses diff --git a/docs/developer/api/authentication/refresh_token.md b/docs/developer/api/authentication/refresh_token.md index 0482cc1d..f0781660 100644 --- a/docs/developer/api/authentication/refresh_token.md +++ b/docs/developer/api/authentication/refresh_token.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/auth/refresh +auth: none +area: authentication +--- + + # Refresh Token Obtain a new JWT access token using a refresh token. @@ -14,7 +22,7 @@ Obtain a new JWT access token using a refresh token. ### Example Request -```json +```json example-request { "refresh_token": "d4f5g6h7..." } @@ -22,7 +30,7 @@ Obtain a new JWT access token using a refresh token. ## Response (200 OK) -```json +```json example-response { "access_token": "new-jwt-token", "token_type": "Bearer", diff --git a/docs/developer/api/authentication/register.md b/docs/developer/api/authentication/register.md index cc40b0b4..39d6f6eb 100644 --- a/docs/developer/api/authentication/register.md +++ b/docs/developer/api/authentication/register.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/auth/register +auth: none +area: authentication +--- + + # Register User Create a new user account. @@ -18,7 +26,7 @@ Create a new user account. ### Example Request -```json +```json example-request { "email": "user@example.com", "username": "john", @@ -30,10 +38,9 @@ Create a new user account. ## Response (201 Created) -```json +```json example-response { - "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", - "refresh_token": "d4f5g6h7...", + "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "token_type": "Bearer", "expires_in": 604800, "user": { @@ -42,9 +49,7 @@ Create a new user account. "username": "john", "first_name": "John", "last_name": "Doe", - "role": "user", - "theme": "tokyo-night", - "created_at": "2026-01-31T10:00:00Z" + "role": "user" } } ``` diff --git a/docs/developer/api/devices/add_to_shelf.md b/docs/developer/api/devices/add_to_shelf.md index 057a6818..e1f348d7 100644 --- a/docs/developer/api/devices/add_to_shelf.md +++ b/docs/developer/api/devices/add_to_shelf.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/devices/:id/shelves +auth: jwt +area: devices +--- + + # Add to Shelf Add a media item to a device's shelf (Kobo reading shelf). @@ -14,25 +22,30 @@ Add a media item to a device's shelf (Kobo reading shelf). ## Request Body -| Field | Type | Required | Description | -| ------------- | ------------- | -------- | ------------------------------- | -| media_item_id | string (UUID) | Yes | Media item UUID to add to shelf | +| Field | Type | Required | Description | +| -------------- | --------------- | -------- | ------------------------------- | +| media_item_ids | array of string | Yes | Media item UUIDs to add to shelf | +| shelf_name | string | No | Shelf name (default "Default") | +| shelf_position | int | No | Starting shelf position | ### Example Request -```json +```json example-request { - "media_item_id": "550e8400-e29b-41d4-a716-446655440001" + "media_item_ids": ["550e8400-e29b-41d4-a716-446655440001"], + "shelf_name": "Default", + "shelf_position": 0 } ``` -## Response (201 Created) +## Response (200 OK) -```json +```json example-response { - "message": "Item added to shelf successfully", - "device_id": "uuid", - "media_item_id": "uuid" + "status": "success", + "added_count": 1, + "shelf_name": "Default", + "total_count": 1 } ``` diff --git a/docs/developer/api/devices/clear_shelf.md b/docs/developer/api/devices/clear_shelf.md index 2199cfd9..575136e1 100644 --- a/docs/developer/api/devices/clear_shelf.md +++ b/docs/developer/api/devices/clear_shelf.md @@ -1,3 +1,11 @@ +--- +method: DELETE +path: /api/devices/:id/shelves/clear +auth: jwt +area: devices +--- + + # Clear Shelf Remove all items from a device's shelf. @@ -24,9 +32,14 @@ DELETE /api/devices/550e8400-e29b-41d4-a716-446655440000/shelves/clear Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ``` -## Response (204 No Content) +## Response (200 OK) -Shelf cleared successfully. +```json example-response +{ + "status": "success", + "message": "all shelves cleared" +} +``` ## Error Responses diff --git a/docs/developer/api/devices/delete_device.md b/docs/developer/api/devices/delete_device.md index 35080ca6..bc223ffb 100644 --- a/docs/developer/api/devices/delete_device.md +++ b/docs/developer/api/devices/delete_device.md @@ -1,3 +1,11 @@ +--- +method: DELETE +path: /api/devices/:id +auth: jwt +area: devices +--- + + # Delete Device Delete a device and revoke its access. diff --git a/docs/developer/api/devices/get_devices.md b/docs/developer/api/devices/get_devices.md index bf75e1c7..50a6aad4 100644 --- a/docs/developer/api/devices/get_devices.md +++ b/docs/developer/api/devices/get_devices.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/devices/register/status +auth: none +area: devices +--- + + # Get Device / Check Registration Status Check device registration status or get device details. @@ -14,7 +22,7 @@ Check device registration status or get device details. ### Example Request (Status Check) -```json +```json example-request { "registration_id": "registration-uuid" } @@ -22,22 +30,18 @@ Check device registration status or get device details. ## Response (200 OK) -```json +```json example-response { - "status": "pending|approved", - "message": "awaiting user approval", - "expires_in": 123, - "auth_token": "device-bearer-token...", - "device_id": "uuid", - "sync_endpoints": { - "progress": "https://bookhoard.com/api/sync/progress", - "metadata": "https://bookhoard.com/api/sync/metadata", - "annotations": "https://bookhoard.com/api/sync/annotations" - } + "status": "pending", + "device_id": "00000000-0000-0000-0000-000000000000" } ``` -`status` is `pending` or `approved`. While pending, the response includes `message` and `expires_in` (seconds remaining). Once approved, the response includes `auth_token`, `device_id`, and `sync_endpoints`; `auth_token` fields are empty when pending. +`device_id` is always present (a uuid.UUID array never serializes as omitted — +it reads as all-zeros while pending). `status` is `pending` or `approved`. +While pending, the response includes `message` and `expires_in` (seconds +remaining). Once approved, the response includes `auth_token`, `device_id`, +and `sync_endpoints`; `auth_token` fields are empty when pending. **The approved response is single-use**: the registration is deleted from the pending map once returned, so store the `auth_token` immediately. A repeat status check for the same `registration_id` returns 404. diff --git a/docs/developer/api/devices/get_shelf.md b/docs/developer/api/devices/get_shelf.md index ed9cc832..c4293663 100644 --- a/docs/developer/api/devices/get_shelf.md +++ b/docs/developer/api/devices/get_shelf.md @@ -1,3 +1,11 @@ +--- +method: GET +path: /api/devices/:id/shelves +auth: jwt +area: devices +--- + + # Get Shelf Get all items on a device's shelf. @@ -26,15 +34,22 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ## Response (200 OK) -```json +```json example-response { - "items": [ + "status": "success", + "device_id": "550e8400-e29b-41d4-a716-446655440000", + "shelf_name": "", + "books": [ { "id": "uuid", "media_item_id": "uuid", "title": "Book Title", - "authors": ["Author Name"], - "cover_url": "/api/media-items/uuid/cover", + "author": "Author Name", + "file_path": "", + "mime_type": "", + "shelf_name": "", + "shelf_position": 0, + "revision_number": 0, "added_at": "2026-02-08T10:00:00Z" } ], diff --git a/docs/developer/api/devices/get_sidecar_config.md b/docs/developer/api/devices/get_sidecar_config.md index 1a8b94af..cf2fb1ab 100644 --- a/docs/developer/api/devices/get_sidecar_config.md +++ b/docs/developer/api/devices/get_sidecar_config.md @@ -1,3 +1,11 @@ +--- +method: GET +path: /api/devices/:id/sidecar +auth: jwt +area: devices +--- + + # Get Device Sidecar Config Returns the KOReader/Kobo sidecar configuration (`.bookhoard.json`) for a device: server endpoints, the user's books (keyed by SHA-256 with UUID fallback), and collections. Used by the Bookhoard KOReader plugin to self-configure after approval. @@ -7,7 +15,7 @@ Returns the KOReader/Kobo sidecar configuration (`.bookhoard.json`) for a device ### Response (200 OK) -```json +```json example-response { "version": "1", "bookhoard": { diff --git a/docs/developer/api/devices/list_devices.md b/docs/developer/api/devices/list_devices.md index 404d0cf0..9e1492d7 100644 --- a/docs/developer/api/devices/list_devices.md +++ b/docs/developer/api/devices/list_devices.md @@ -1,3 +1,11 @@ +--- +method: GET +path: /api/devices +auth: jwt +area: devices +--- + + # List User Devices Retrieve all devices registered to the current user. @@ -20,7 +28,7 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ## Response (200 OK) -```json +```json example-response { "devices": [ { @@ -33,7 +41,8 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... "auto_sync": true, "sync_frequency_minutes": 5 } - ] + ], + "total": 1 } ``` diff --git a/docs/developer/api/devices/register_device.md b/docs/developer/api/devices/register_device.md index c16b4ad1..f6c8b072 100644 --- a/docs/developer/api/devices/register_device.md +++ b/docs/developer/api/devices/register_device.md @@ -1,3 +1,11 @@ +--- +method: POST +path: /api/devices/register +auth: none +area: devices +--- + + # Register Device Register a new device for sync. @@ -16,7 +24,7 @@ Register a new device for sync. ### Example Request -```json +```json example-request { "device_name": "My Kobo Clara", "device_type": "kobo", @@ -26,8 +34,9 @@ Register a new device for sync. ## Response (201 Created) -```json +```json example-response { + "device_id": "550e8400-e29b-41d4-a716-446655440000", "registration_id": "registration-uuid", "auth_url": "https://bookhoard.com/devices/approve/abc123", "qr_code": "data:image/png;base64,iVBORw0KG...", diff --git a/docs/developer/api/devices/remove_from_shelf.md b/docs/developer/api/devices/remove_from_shelf.md index b75ea6ab..b1821cd1 100644 --- a/docs/developer/api/devices/remove_from_shelf.md +++ b/docs/developer/api/devices/remove_from_shelf.md @@ -1,3 +1,11 @@ +--- +method: DELETE +path: /api/devices/:id/shelves +auth: jwt +area: devices +--- + + # Remove from Shelf Remove a media item from a device's shelf. @@ -26,9 +34,14 @@ Remove a media item from a device's shelf. } ``` -## Response (204 No Content) +## Response (200 OK) -Item removed from shelf successfully. +```json example-response +{ + "status": "success", + "message": "book removed from shelf" +} +``` ## Error Responses diff --git a/docs/developer/api/devices/revoke_device.md b/docs/developer/api/devices/revoke_device.md deleted file mode 100644 index ba9765ba..00000000 --- a/docs/developer/api/devices/revoke_device.md +++ /dev/null @@ -1,37 +0,0 @@ -# Revoke Device - -Revoke access to a device. - -**Endpoint**: `DELETE /api/devices/{device_id}` -**Auth**: Required - -## Path Parameters - -| Parameter | Type | Required | Description | -| --------- | ------ | -------- | ----------- | -| device_id | string | Yes | Device UUID | - -## Request Headers - -| Header | Type | Required | Description | -| ------------- | ------ | -------- | ------------ | -| Authorization | string | Yes | Bearer token | - -### Example Request - -```http -DELETE /api/devices/uuid -Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... -``` - -## Response (204 No Content) - -Device revoked successfully. - -## Error Responses - -| Code | Description | -| ---- | ----------------------------- | -| 401 | Invalid or expired token | -| 403 | User does not own this device | -| 404 | Device not found | diff --git a/docs/developer/api/devices/update_device.md b/docs/developer/api/devices/update_device.md index 6f723005..abd066df 100644 --- a/docs/developer/api/devices/update_device.md +++ b/docs/developer/api/devices/update_device.md @@ -1,3 +1,11 @@ +--- +method: PUT +path: /api/devices/:id +auth: jwt +area: devices +--- + + # Update Device Update a device's information. @@ -21,24 +29,32 @@ Update a device's information. ### Example Request -```json +```json example-request { - "name": "My Kobo Clara", - "device_type": "kobo" + "device_name": "My Kobo Clara", + "sync_enabled": true, + "auto_sync": true, + "sync_frequency_minutes": 60 } ``` ## Response (200 OK) -```json +```json example-response { - "id": "uuid", - "name": "My Kobo Clara", - "device_type": "kobo", - "user_id": "user-uuid", - "status": "active", - "created_at": "2026-02-08T10:00:00Z", - "updated_at": "2026-02-08T11:00:00Z" + "device_updated": true, + "device": { + "id": "uuid", + "device_name": "My Kobo Clara", + "device_type": "kobo", + "last_sync": null, + "last_seen": null, + "sync_enabled": true, + "auto_sync": true, + "sync_frequency_minutes": 5, + "created_at": "2026-02-08T10:00:00Z", + "auth_token": "" + } } ``` diff --git a/docs/developer/api/users/get_profile.md b/docs/developer/api/users/get_profile.md index ccd94de7..6a737a17 100644 --- a/docs/developer/api/users/get_profile.md +++ b/docs/developer/api/users/get_profile.md @@ -1,3 +1,11 @@ +--- +method: GET +path: /api/auth/profile +auth: jwt +area: authentication +--- + + # Get Current User Profile Retrieve the current authenticated user's profile. @@ -20,17 +28,14 @@ Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9... ## Response (200 OK) -```json +```json example-response { "id": "uuid", "email": "user@example.com", "username": "john", "first_name": "John", "last_name": "Doe", - "theme": "tokyo-night", - "role": "user", - "max_devices": 10, - "created_at": "2026-01-31T10:00:00Z" + "role": "user" } ``` diff --git a/internal/docs/schema.go b/internal/docs/schema.go index e94cdb9d..ff84dc2f 100644 --- a/internal/docs/schema.go +++ b/internal/docs/schema.go @@ -372,4 +372,71 @@ var Schemas = map[string]Schema{ "DELETE /api/queue/devices/:device_id/clear": { Response: json.RawMessage(`{"message": ""}`), }, + + // --- Beam batch 3: auth core + devices core --- + "POST /api/auth/login": { + Request: handlers.LoginRequest{}, + Response: handlers.AuthResponse{}, + }, + "POST /api/auth/register": { + Request: handlers.RegisterRequest{}, + Response: handlers.AuthResponse{}, + }, + "POST /api/auth/refresh": { + Request: handlers.RefreshTokenRequest{}, + Response: handlers.RefreshTokenResponse{}, + }, + "POST /api/auth/logout": { + Response: json.RawMessage(`{"message": ""}`), + }, + "GET /api/auth/profile": { + Response: handlers.UserProfile{}, + }, + "GET /api/devices": { + Response: handlers.DeviceListResponse{}, + }, + "PUT /api/devices/:id": { + Request: handlers.DeviceUpdateRequest{}, + Response: json.RawMessage(`{ + "device_updated": false, + "device": { + "id": "", "device_name": "", "device_type": "", + "last_sync": null, "last_seen": null, + "sync_enabled": false, "auto_sync": false, + "sync_frequency_minutes": 0, "created_at": "", + "device_metadata": null, "auth_token": "" + } + }`), + }, + "DELETE /api/devices/:id": {}, + "GET /api/devices/:id/shelves": { + Response: json.RawMessage(`{ + "status": "", "device_id": "", "shelf_name": "", + "books": [{}], "total": 0 + }`), + }, + "POST /api/devices/:id/shelves": { + Request: handlers.AddToShelfRequest{}, + Response: json.RawMessage(`{ + "status": "", "added_count": 0, + "shelf_name": "", "total_count": 0 + }`), + }, + "DELETE /api/devices/:id/shelves": { + Response: json.RawMessage(`{"status": "", "message": ""}`), + }, + "DELETE /api/devices/:id/shelves/clear": { + Response: json.RawMessage(`{"status": "", "message": ""}`), + }, + "GET /api/devices/:id/sidecar": { + Response: handlers.SidecarConfig{}, + }, + "POST /api/devices/register": { + Request: handlers.DeviceRegistrationRequest{}, + Response: handlers.DeviceRegistrationResponse{}, + }, + "POST /api/devices/register/status": { + Request: handlers.DeviceAuthStatusRequest{}, + Response: handlers.DeviceAuthStatusResponse{}, + }, }