API Reference ============= This section provides detailed documentation for all Flask routes and REST API endpoints. Base URL -------- * **Development**: ``http://localhost:5000`` * **Production**: ``https://your-domain.com`` Authentication -------------- **Session-based Authentication**: All protected routes use Flask sessions. Login via ``/auth/login`` (web) or ``/api/v1/auth/login`` (API). **User Management**: Users are created by administrators through the admin interface or API. Passwords are securely hashed using bcrypt. Users can be assigned admin privileges, which grants access to user management features. **Default Admin User**: On first run, a default admin user is created with username ``admin`` and password ``admin`` (or the value of ``KIOSK_ADMIN_PASSWORD`` environment variable). Change this password immediately in production. Standard Response Format ------------------------ **Success Response:** .. code-block:: json { "success": true, "data": {}, "message": "Optional success message" } **Error Response:** .. code-block:: json { "success": false, "error": "Error message", "code": 400 } **Status Codes:** * ``200 OK``: Request successful * ``201 Created``: Resource created successfully * ``400 Bad Request``: Invalid request data * ``401 Unauthorized``: Authentication required * ``403 Forbidden``: Access denied (admin required) * ``404 Not Found``: Resource not found * ``500 Internal Server Error``: Server error Content Types ------------- All API endpoints accept and return JSON data with ``Content-Type: application/json``. Data Models ----------- **User Model:** .. code-block:: json { "id": 1, "username": "string", "email": "string", "is_active": true, "is_admin": true, "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z", "last_login_at": "2024-01-01T00:00:00Z" } **Slideshow Model:** .. code-block:: json { "id": 1, "name": "string", "description": "string", "is_active": true, "is_default": false, "default_item_duration": 30, "transition_type": "fade", "total_duration": 120, "active_items_count": 4, "owner_id": 1, "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" } **Slideshow Item Model:** .. code-block:: json { "id": 1, "slideshow_id": 1, "title": "string", "content_type": "image|video|url|text", "content_url": "string", "content_text": "string", "content_file_path": "string", "content_source": "string", "display_url": "string", "display_duration": 30, "effective_duration": 30, "order_index": 0, "is_active": true, "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" } **Display Model:** .. code-block:: json { "id": 1, "name": "string", "description": "string", "resolution_width": 1920, "resolution_height": 1080, "resolution_string": "1920x1080", "resolution": "1920x1080", "rotation": 0, "location": "string", "is_active": true, "is_online": false, "online": false, "last_seen_at": "2024-01-01T00:00:00Z", "heartbeat_interval": 60, "owner_id": 1, "current_slideshow_id": 1, "created_at": "2024-01-01T00:00:00Z", "updated_at": "2024-01-01T00:00:00Z" } **Assignment History Model:** .. code-block:: json { "id": 1, "display_id": 1, "display_name": "string", "previous_slideshow_id": 1, "previous_slideshow_name": "string", "new_slideshow_id": 2, "new_slideshow_name": "string", "action": "assign|unassign|change", "reason": "string", "created_at": "2024-01-01T00:00:00Z", "created_by_id": 1, "created_by_username": "string" } Application Routes ================== Main Application Routes ----------------------- ``GET /`` ~~~~~~~~~ **Purpose**: Application home page **Authentication**: Optional **Returns**: Redirect to ``/admin`` if authenticated, otherwise ``/auth/login`` ``GET /health`` ~~~~~~~~~~~~~~~ **Purpose**: Health check endpoint **Authentication**: None **Returns**: ``{"status": "healthy", "version": "0.1.0"}`` ``GET /about`` ~~~~~~~~~~~~~~ **Purpose**: About page with application information **Authentication**: None **Returns**: HTML page with app info ``GET /uploads/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Serve uploaded files **Authentication**: None **Parameters**: - ``filename`` (path): File path to serve **Returns**: File content or 404 Authentication Routes --------------------- ``GET /auth/login`` ~~~~~~~~~~~~~~~~~~~ **Purpose**: Login page **Authentication**: None **Returns**: HTML login form ``POST /auth/login`` ~~~~~~~~~~~~~~~~~~~~ **Purpose**: Process login **Authentication**: None **Parameters**: - ``username`` (form): Username (any value accepted) - ``password`` (form): Password (any value accepted) **Returns**: Redirect to dashboard or login page with error ``GET /auth/logout`` ~~~~~~~~~~~~~~~~~~~~ **Purpose**: Logout current user **Authentication**: Required **Returns**: Redirect to login page ``GET /auth/status`` ~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get authentication status **Authentication**: Optional **Returns**: ``{"authenticated": true/false, "user": {...}}`` Dashboard Routes ---------------- ``GET /`` ~~~~~~~~~ **Purpose**: Main dashboard (same as root) **Authentication**: Required **Returns**: HTML dashboard with slideshow/display stats ``GET /profile`` ~~~~~~~~~~~~~~~~ **Purpose**: User profile page **Authentication**: Required **Returns**: HTML page with user information ``GET /settings`` ~~~~~~~~~~~~~~~~~ **Purpose**: Admin settings page **Authentication**: Required (Admin) **Returns**: HTML page with admin settings ``GET /health`` ~~~~~~~~~~~~~~~ **Purpose**: Dashboard health check **Authentication**: None **Returns**: ``{"status": "healthy", "timestamp": "..."}`` Slideshow Management Routes (Web) ---------------------------------- ``GET /slideshow/`` ~~~~~~~~~~~~~~~~~~~ **Purpose**: List all slideshows **Authentication**: Required **Returns**: HTML page with slideshow list ``GET /slideshow/create`` ~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Show create slideshow form **Authentication**: Required **Returns**: HTML form for creating slideshow ``POST /slideshow/create`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Create new slideshow **Authentication**: Required **Parameters**: - ``name`` (form): Slideshow name (required) - ``description`` (form): Description (optional) **Returns**: Redirect to edit page or form with errors ``GET /slideshow//edit`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Edit slideshow and its slides **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Returns**: HTML edit form with slides ``POST /slideshow//delete`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Delete slideshow (soft delete) **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Returns**: Redirect to slideshow list Display Interface Routes ------------------------ ``GET /display/`` ~~~~~~~~~~~~~~~~~ **Purpose**: Display interface landing page **Authentication**: None **Returns**: HTML display configuration page ``GET /display/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Main display interface for kiosk **Authentication**: None **Parameters**: - ``display_name`` (path): Display identifier **Returns**: HTML slideshow interface or configuration page **Side Effects**: Auto-creates display if not exists, updates heartbeat ``GET /display//info`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Display information and status **Authentication**: None **Parameters**: - ``display_name`` (path): Display identifier **Returns**: HTML page with display info and slideshow data ``POST /display//heartbeat`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Update display heartbeat and resolution **Authentication**: None **Parameters**: - ``display_name`` (path): Display identifier **Request Body**: .. code-block:: json { "resolution": {"width": 1920, "height": 1080}, "user_agent": "Browser info", "timestamp": "ISO timestamp" } **Returns**: ``{"status": "success", "timestamp": "..."}`` ``GET /display//status`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get display status and configuration **Authentication**: None **Parameters**: - ``display_name`` (path): Display identifier **Returns**: JSON with display status and current slideshow ``GET /display//slideshow/current`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get current slideshow data for AJAX updates **Authentication**: None **Parameters**: - ``display_name`` (path): Display identifier **Returns**: JSON with current slideshow and slides ``POST /display//assign/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Assign slideshow to display **Authentication**: Required **Parameters**: - ``display_name`` (path): Display identifier - ``slideshow_id`` (path): Slideshow ID **Returns**: Redirect with success/error message ``GET /display/slideshow/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Display slideshow by ID **Authentication**: None **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Returns**: HTML slideshow interface ``GET /display//slideshow/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Display specific slideshow on named display **Authentication**: None **Parameters**: - ``display_name`` (path): Display identifier - ``slideshow_id`` (path): Slideshow ID **Returns**: HTML slideshow interface Admin Interface Routes ---------------------- ``GET /admin`` ~~~~~~~~~~~~~~ **Purpose**: React admin interface entry point **Authentication**: Required **Returns**: React SPA (production) or redirect to dev server ``GET /admin/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: React admin interface routes **Authentication**: Required **Parameters**: - ``path`` (path): React route path **Returns**: React SPA content REST API Endpoints ================== API Root -------- ``GET /api/`` ~~~~~~~~~~~~~ **Purpose**: API version information **Authentication**: None **Returns**: .. code-block:: json { "message": "Kiosk.show Replacement API", "versions": {"v1": "/api/v1/"}, "documentation": "/api/v1/docs" } ``GET /api/health`` ~~~~~~~~~~~~~~~~~~~ **Purpose**: API health check **Authentication**: None **Returns**: .. code-block:: json { "status": "healthy", "api_version": "v1", "endpoints": [...] } API v1 Authentication --------------------- ``POST /api/v1/auth/login`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: API login endpoint **Authentication**: None **Request Body**: .. code-block:: json { "username": "string", "password": "string" } **Returns**: User object on success, or 401 error if credentials are invalid **Side Effects**: Establishes session cookie on successful authentication ``GET /api/v1/auth/user`` ~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get current user information **Authentication**: Required **Returns**: Current user object ``POST /api/v1/auth/logout`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Logout current user **Authentication**: Required **Returns**: ``{"success": true, "message": "Successfully logged out"}`` API v1 Status ------------- ``GET /api/v1/status`` ~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: API status check **Authentication**: None **Returns**: .. code-block:: json { "status": "healthy", "api_version": "v1", "timestamp": "2024-01-01T00:00:00Z" } API v1 Slideshows ----------------- ``GET /api/v1/slideshows`` ~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: List all slideshows **Authentication**: Required **Returns**: Array of slideshow objects ``POST /api/v1/slideshows`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Create new slideshow **Authentication**: Required **Request Body**: .. code-block:: json { "name": "string", "description": "string", "default_item_duration": 30 } **Returns**: Created slideshow object (201) ``GET /api/v1/slideshows/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get specific slideshow with items **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Returns**: Slideshow object with items array ``PUT /api/v1/slideshows/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Update slideshow **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Request Body**: .. code-block:: json { "name": "string", "description": "string", "default_item_duration": 30, "is_active": true } **Returns**: Updated slideshow object ``DELETE /api/v1/slideshows/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Delete slideshow (soft delete) **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Returns**: Success message ``POST /api/v1/slideshows//set-default`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Set slideshow as default **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Returns**: Success message **Side Effects**: Unsets previous default slideshow API v1 Slideshow Items ---------------------- ``GET /api/v1/slideshows//items`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get slideshow items **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Returns**: Array of slideshow item objects ``POST /api/v1/slideshows//items`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Create slideshow item **Authentication**: Required **Parameters**: - ``slideshow_id`` (path): Slideshow ID **Request Body**: .. code-block:: json { "title": "string", "content_type": "image|video|url|text", "content_url": "string", "content_text": "string", "display_duration": 30, "order_index": 0 } **Returns**: Created item object (201) ``PUT /api/v1/slideshow-items/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Update slideshow item **Authentication**: Required **Parameters**: - ``item_id`` (path): Item ID **Request Body**: Same as create **Returns**: Updated item object ``DELETE /api/v1/slideshow-items/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Delete slideshow item (soft delete) **Authentication**: Required **Parameters**: - ``item_id`` (path): Item ID **Returns**: Success message ``POST /api/v1/slideshow-items//reorder`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Reorder slideshow item **Authentication**: Required **Parameters**: - ``item_id`` (path): Item ID **Request Body**: .. code-block:: json { "new_order": 2 } **Returns**: Success message **Side Effects**: Reorders other items as needed API v1 Displays --------------- ``GET /api/v1/displays`` ~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: List all displays **Authentication**: Required **Returns**: Array of display objects ``GET /api/v1/displays/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get specific display **Authentication**: Required **Parameters**: - ``display_id`` (path): Display ID **Returns**: Display object ``PUT /api/v1/displays/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Update display **Authentication**: Required **Parameters**: - ``display_id`` (path): Display ID **Request Body**: .. code-block:: json { "name": "string", "description": "string", "location": "string", "rotation": 0, "is_active": true } **Returns**: Updated display object ``DELETE /api/v1/displays/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Delete display (soft delete) **Authentication**: Required **Parameters**: - ``display_id`` (path): Display ID **Returns**: Success message ``POST /api/v1/displays//assign-slideshow`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Assign slideshow to display by name **Authentication**: Required **Parameters**: - ``display_name`` (path): Display name **Request Body**: .. code-block:: json { "slideshow_id": 1, "reason": "string" } **Returns**: Success message **Side Effects**: Creates assignment history record ``POST /api/v1/displays//reload`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Send reload command to display via SSE **Authentication**: Required **Parameters**: - ``display_id`` (path): Display ID **Returns**: .. code-block:: json { "success": true, "data": { "display_id": 1, "connections_notified": 1 }, "message": "Reload command sent to display 'display-name'" } **Side Effects**: Sends ``display.reload_requested`` SSE event to display API v1 Assignment History ------------------------- ``GET /api/v1/displays//assignment-history`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get assignment history for display **Authentication**: Required **Parameters**: - ``display_id`` (path): Display ID **Returns**: Array of assignment history objects ``GET /api/v1/assignment-history`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get global assignment history **Authentication**: Required **Query Parameters**: - ``limit`` (optional): Number of records to return - ``offset`` (optional): Offset for pagination **Returns**: Array of assignment history objects ``POST /api/v1/assignment-history`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Create assignment history record **Authentication**: Required **Request Body**: .. code-block:: json { "display_id": 1, "previous_slideshow_id": 1, "new_slideshow_id": 2, "reason": "string" } **Returns**: Created assignment history object (201) API v1 Video URL Validation --------------------------- ``POST /api/v1/validate/video-url`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Validate a video URL for browser compatibility and extract duration **Authentication**: Required **Request Body**: .. code-block:: json { "url": "https://example.com/video.mp4" } **Returns** (Success): .. code-block:: json { "success": true, "data": { "valid": true, "duration_seconds": 120, "duration": 120.5, "codec_info": { "video_codec": "h264", "audio_codec": "aac", "container_format": "mp4" } } } **Returns** (Invalid Codec): .. code-block:: json { "success": false, "error": "Video codec 'mpeg2video' is not supported by web browsers. Supported: h264, vp8, vp9, theora, av1" } **Returns** (Inaccessible URL): .. code-block:: json { "success": false, "error": "Could not retrieve video information from the URL. The URL may be inaccessible." } **Notes**: - Uses ``ffprobe`` to validate the video URL - Timeout is 60 seconds for remote URLs - Browser-compatible video codecs: H.264, VP8, VP9, Theora, AV1 API v1 File Uploads ------------------- ``POST /api/v1/uploads/image`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Upload image file **Authentication**: Required **Content-Type**: ``multipart/form-data`` **Form Data**: - ``file``: Image file - ``slideshow_id``: Slideshow ID (required) **Returns**: File information object (201) **Limits**: Max 50MB per image ``POST /api/v1/uploads/video`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Upload video file **Authentication**: Required **Content-Type**: ``multipart/form-data`` **Form Data**: - ``file``: Video file - ``slideshow_id``: Slideshow ID (required) **Returns**: File information object (201) **Limits**: Max 500MB per video ``GET /api/v1/uploads/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get file information **Authentication**: Required **Parameters**: - ``file_id`` (path): File ID **Returns**: Not implemented (501) ``DELETE /api/v1/uploads/`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Delete uploaded file **Authentication**: Required **Parameters**: - ``file_id`` (path): File ID **Returns**: Not implemented (501) ``GET /api/v1/uploads/stats`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **Purpose**: Get storage statistics **Authentication**: Required **Returns**: .. code-block:: json { "total_size": 1024000, "total_size_formatted": "1.0 MB", "image_size": 512000, "image_size_formatted": "512.0 KB", "video_size": 512000, "video_size_formatted": "512.0 KB", "total_files": 10, "image_files": 5, "video_files": 5, "users_with_files": 2, "slideshows_with_files": 3 }