# Subspace TV Configuration Server A Docker-hosted FastAPI service that serves JSON configuration to tvOS clients. Authorized devices receive privileged configuration while unauthorized devices receive blank configuration. ## Features - Device-based authorization via custom header (`X-Device-ID`) - Hot-reload of authorization list without service restart - Docker containerization with non-root user - CORS support for web-based clients - Health check endpoint for monitoring ## Architecture ``` subspace-tv/ ├── src/ │ ├── __init__.py │ ├── config.py # Pydantic settings management │ ├── auth.py # Authorization logic with hot-reload │ └── main.py # FastAPI application ├── bruno/ │ ├── environments/ # Bruno environment configurations │ └── *.bru # Bruno API test requests ├── config/ │ └── authorized_devices.json # Device authorization list ├── .env.example # Environment variable template ├── Dockerfile # Container image definition ├── docker-compose.yml # Service orchestration └── requirements.txt # Python dependencies ``` ## Local Development ### Prerequisites - Python 3.11+ - pip ### Setup 1. Clone the repository and navigate to the project directory 2. Install dependencies: ```bash pip install -r requirements.txt ``` 3. Create environment file: ```bash cp .env.example .env ``` 4. Edit `.env` with your configuration values 5. Run the development server: ```bash uvicorn src.main:app --reload ``` 6. Access the API at `http://localhost:8000` ## Docker Deployment ### Prerequisites - Docker - Docker Compose ### Setup 1. Create environment file: ```bash cp .env.example .env ``` 2. Configure `.env` with production values: ```env CONFIG_URL=https://your-production-server.com CONFIG_PORT=8000 CONFIG_TIMEZONE=America/New_York CONFIG_UPDATE_INTERVAL=3600 ``` 3. Configure authorized devices in `config/authorized_devices.json`: ```json { "authorized_devices": [ "tvos-device-001", "tvos-device-002" ] } ``` 4. Build and launch the container: ```bash docker-compose up -d ``` 5. Verify the service is running: ```bash curl http://localhost:8000/health ``` ## API Endpoints ### Health Check **GET** `/health` Returns service health status. **Response:** ```json { "status": "healthy" } ``` ### Get Configuration **GET** `/api/v1/config` **Headers:** - `X-Device-ID` (required): Device identifier **Response (Authorized):** ```json { "authorized": true, "config": { "url": "https://your-server.example.com", "port": 8000, "timezone": "America/New_York", "update_interval": 3600 } } ``` **Response (Unauthorized):** ```json { "authorized": false, "config": {} } ``` **Error Response (Missing Header):** ```json { "detail": "X-Device-ID header is required" } ``` Status: `400 Bad Request` ## Usage Examples ### Test with curl (Authorized Device) ```bash curl -H "X-Device-ID: device-example-001" http://localhost:8000/api/v1/config ``` ### Test with curl (Unauthorized Device) ```bash curl -H "X-Device-ID: unknown-device" http://localhost:8000/api/v1/config ``` ### Test with Bruno A Bruno API collection is available in the `bruno/` directory for comprehensive API testing. **Prerequisites:** - Install [Bruno](https://www.usebruno.com/) **Usage:** 1. Open Bruno 2. Open Collection → Select the `bruno/` directory in this project 3. Select environment (Local or Production) 4. Run individual requests or entire collection **Available Requests:** - `Health Check` - Verify service status - `Config - Authorized Device` - Test authorized device response - `Config - Unauthorized Device` - Test unauthorized device response - `Config - Missing Header` - Test error handling for missing header All requests include assertions to validate expected responses. ## Authorization Management ### Adding Authorized Devices Edit `config/authorized_devices.json` and add device IDs: ```json { "authorized_devices": [ "tvos-device-001", "tvos-device-002", "new-device-id" ] } ``` The authorization list is automatically reloaded when the file is modified. No service restart required. ### Removing Authorized Devices Remove device IDs from `config/authorized_devices.json`. Changes take effect immediately. ## Configuration Reference ### Environment Variables | Variable | Description | Default | |----------|-------------|---------| | `HOST` | Server bind address | `0.0.0.0` | | `PORT` | Server port | `8000` | | `DEBUG` | Debug mode | `false` | | `AUTHORIZATION_FILE` | Path to authorization JSON | `/app/config/authorized_devices.json` | | `CONFIG_URL` | URL returned to authorized devices | `https://your-server.example.com` | | `CONFIG_PORT` | Port returned to authorized devices | `8000` | | `CONFIG_TIMEZONE` | Timezone for authorized devices | `America/New_York` | | `CONFIG_UPDATE_INTERVAL` | Update interval in seconds | `3600` | | `CORS_ORIGINS` | Allowed CORS origins | `["*"]` | ## Security Considerations - The service runs as a non-root user (`appuser`) in the Docker container - Authorization file is mounted from the host filesystem - Privileged configuration data is stored in environment variables - No sensitive data is returned to unauthorized devices - Health check endpoint is publicly accessible for orchestration ## Troubleshooting ### Service won't start Check Docker logs: ```bash docker-compose logs -f ``` ### Authorization not working 1. Verify `config/authorized_devices.json` format is valid JSON 2. Check that device ID matches exactly (case-sensitive) 3. Confirm file permissions allow reading by container user ### Hot-reload not working The authorization file is checked for modifications on each request. Ensure the file modification timestamp changes when editing.