v1.10.8
python-jose jwt.decode() requires audience as string or None, not list. Now extract and validate audience from unverified claims first, then use token's actual audience for JWT decode. Fixes "audience must be a string or None" error. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Core Code API
Central API service providing infrastructure management, home automation, and utility endpoints for the homelab ecosystem.
Features
Infrastructure Management
- Portainer Integration: Stack and container management
- NPM Integration: Nginx Proxy Manager domain and certificate management
- Service Control: Start/stop services with container orchestration
Home Automation (Housekeeping API)
- Device Control: Turn on/off, toggle, and set brightness for smart devices
- Scene Activation: Trigger Home Assistant scenes
- Script Execution: Run Home Assistant scripts
- Automation Management: Enable/disable automations
- State History: Query device state changes over time
- Area Discovery: List rooms and areas
Utilities
- DNS Lookup: Query DNS records (A, AAAA, MX, TXT, CNAME, NS, SOA, PTR)
- Health Checks: Service health monitoring with database connectivity status
Architecture
src/
├── config.py # Global application settings
├── logging_config.py # Logging configuration
├── base_controller.py # Base controller pattern
├── main.py # FastAPI application entry point
├── auth/
│ └── oidc.py # OIDC authentication
├── clients/
│ ├── homeassistant_client.py # Home Assistant REST client
│ ├── npm_client.py # Nginx Proxy Manager client
│ └── portainer_client.py # Portainer API client
├── controllers/
│ ├── health_controller.py # Health endpoints
│ ├── housekeeping_controller.py # Home automation endpoints
│ ├── infrastructure_controller.py # Infrastructure management
│ ├── static_controller.py # Static file serving
│ └── tools_controller.py # DNS and utility tools
└── dns/
├── service.py # DNS lookup service
└── exceptions.py # DNS-specific exceptions
API Endpoints
Health
GET /- Service info and documentation linksGET /health- Basic health statusGET /health/full- Detailed component healthGET /health/diagnostics- Full diagnostic information
Infrastructure (/infrastructure)
GET /infrastructure/health- Portainer/NPM connection statusGET /infrastructure/services- List all services (stacks)GET /infrastructure/services/{name}- Get service detailsGET /infrastructure/services/{name}/status- Service statusPOST /infrastructure/services/{name}/start- Start servicePOST /infrastructure/services/{name}/stop- Stop serviceGET /infrastructure/containers- List containersGET /infrastructure/containers/{name}- Container detailsGET /infrastructure/containers/{name}/logs- Container logsGET /infrastructure/ports- List exposed portsGET /infrastructure/domains- List proxy domainsGET /infrastructure/widget-data- Dashboard widget data
Housekeeping (/housekeeping)
GET /housekeeping/health- Home Assistant connection statusGET /housekeeping/devices- List controllable devicesGET /housekeeping/devices/{entity_id}- Device detailsPOST /housekeeping/devices/{entity_id}/control- Control deviceGET /housekeeping/scenes- List scenesPOST /housekeeping/scenes/{scene_id}/activate- Activate sceneGET /housekeeping/scripts- List scriptsPOST /housekeeping/scripts/{script_id}/run- Run scriptGET /housekeeping/automations- List automationsPOST /housekeeping/automations/{automation_id}/toggle- Toggle automationGET /housekeeping/history- State historyGET /housekeeping/areas- List areas/rooms
Tools (/tools)
POST /tools/dns/lookup- DNS record lookup
Development
Requirements
- Python 3.12+
- Docker (for containerized deployment)
Local Development
# Install dependencies
pip install -r requirements.txt
# Run locally
uvicorn src.main:app --reload --host 0.0.0.0 --port 8083
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=src --cov-report=term-missing
# Run specific test file
pytest tests/test_housekeeping.py -v
Adding New Dependencies
Dependencies use major version pinning (~=) for automatic patch updates while preventing breaking changes.
-
Add package to
requirements.txtwith major version constraint:package-name~=1.2.0 # Allows 1.2.x, blocks 1.3.0 -
Restart the container to install:
docker restart core-api
Docker Build
# Build image
docker build -t core-code:latest .
# Run container
docker run -p 8083:8083 core-code:latest
Deployment
Portainer Stack
- Navigate to Portainer UI
- Go to Stacks → Add Stack
- Name:
core-code - Upload
stacks/core-code.ymlor paste contents - Deploy
Environment Variables
| Variable | Description | Default |
|---|---|---|
PORTAINER_URL |
Portainer API URL | http://localhost:9000 |
PORTAINER_API_KEY |
Portainer API key | - |
NPM_URL |
Nginx Proxy Manager URL | http://localhost:81 |
NPM_EMAIL |
NPM admin email | - |
NPM_PASSWORD |
NPM admin password | - |
HOMEASSISTANT_URL |
Home Assistant URL | http://localhost:8123 |
HOMEASSISTANT_TOKEN |
HA long-lived access token | - |
OIDC_ENABLED |
Enable OIDC auth | false |
OIDC_ISSUERS |
OIDC issuer URLs (comma-separated) | See config.py |
OIDC_AUDIENCES |
OIDC audiences (comma-separated) | See config.py |
API Documentation
Once deployed, access documentation at:
- Swagger UI: http://localhost:8083/docs
- ReDoc: http://localhost:8083/redoc
- OpenAPI Spec: http://localhost:8083/openapi.json
Health Checks
- Basic:
GET /health- Fast liveness check for container orchestration - Full:
GET /health/full- Returns database status (503 if unhealthy) - Diagnostics:
GET /health/diagnostics- Service info and configuration
Security
- Runs as non-root user (uid 1000)
- OIDC authentication support via Authentik
- CORS configured for same-network access
- Admin endpoints require authentication when OIDC enabled
License
Internal use only.
Releases
5
Release v1.11.0
Latest
Languages
Python
95.9%
HTML
3.2%
Shell
0.4%
Makefile
0.4%