Files
subspace-tv/README.md
Michael Simard 57ad4b0f33 Add subspace-tv FastAPI service with Unraid deployment
Includes FastAPI application with device authentication, Docker configuration,
Bruno API tests, and git-based deployment scripts for Unraid.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 09:22:32 -06:00

5.9 KiB

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:

    pip install -r requirements.txt
    
  3. Create environment file:

    cp .env.example .env
    
  4. Edit .env with your configuration values

  5. Run the development server:

    uvicorn src.main:app --reload
    
  6. Access the API at http://localhost:8000

Docker Deployment

Prerequisites

  • Docker
  • Docker Compose

Setup

  1. Create environment file:

    cp .env.example .env
    
  2. Configure .env with production values:

    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:

    {
      "authorized_devices": [
        "tvos-device-001",
        "tvos-device-002"
      ]
    }
    
  4. Build and launch the container:

    docker-compose up -d
    
  5. Verify the service is running:

    curl http://localhost:8000/health
    

API Endpoints

Health Check

GET /health

Returns service health status.

Response:

{
  "status": "healthy"
}

Get Configuration

GET /api/v1/config

Headers:

  • X-Device-ID (required): Device identifier

Response (Authorized):

{
  "authorized": true,
  "config": {
    "url": "https://your-server.example.com",
    "port": 8000,
    "timezone": "America/New_York",
    "update_interval": 3600
  }
}

Response (Unauthorized):

{
  "authorized": false,
  "config": {}
}

Error Response (Missing Header):

{
  "detail": "X-Device-ID header is required"
}

Status: 400 Bad Request

Usage Examples

Test with curl (Authorized Device)

curl -H "X-Device-ID: device-example-001" http://localhost:8000/api/v1/config

Test with curl (Unauthorized Device)

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:

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:

{
  "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:

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.