🎉 MVP v1.0.0 COMPLETE! 🎉 Final polishing phase with comprehensive documentation and enhanced monitoring: **Enhanced Monitoring:** - Enhanced health check endpoint with component-level status - Database connectivity check (PostgreSQL) - Redis connectivity check - SDK Bridge connectivity check (gRPC) - Overall status (healthy/degraded) - Metrics endpoint with route counts and feature flags - Updated root endpoint with metrics link **Comprehensive Documentation:** - API Reference (docs/api-reference.md) - Complete endpoint documentation - Request/response examples - Authentication guide - Error responses - RBAC table - Deployment Guide (docs/deployment.md) - Prerequisites and system requirements - Installation instructions - Database setup and migrations - Production deployment (Windows Service/IIS/Docker) - Security hardening - Monitoring and alerts - Backup and recovery - Troubleshooting - Usage Guide (docs/usage-guide.md) - Practical examples with curl - Common operations - Use case scenarios - Python and C# client examples - Postman testing guide - Best practices - Release Notes (RELEASE_NOTES.md) - Complete MVP feature list - Architecture overview - Technology stack - Installation quick start - Testing coverage - Security considerations - Known limitations - Future roadmap **MVP Deliverables:** ✅ 21 API endpoints ✅ 84 tasks completed ✅ 213 test cases ✅ 3-tier architecture (API + SDK Bridge + GeViServer) ✅ JWT authentication with RBAC ✅ Cross-switching control (CORE FEATURE) ✅ Camera/monitor discovery ✅ Routing state management ✅ Audit logging ✅ Redis caching ✅ PostgreSQL persistence ✅ Comprehensive documentation **Core Functionality:** - Execute cross-switch (route camera to monitor) - Clear monitor (remove camera) - Query routing state (active routes) - Routing history with pagination - RBAC enforcement (Operator required for execution) **Out of Scope (Intentional):** ❌ Recording management ❌ Video analytics ❌ LPR/NPR ❌ PTZ control ❌ Live streaming 🚀 Ready for deployment and testing! 🚀 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
484 lines
11 KiB
Markdown
484 lines
11 KiB
Markdown
# API Usage Guide
|
|
|
|
Practical examples for using the Geutebruck Cross-Switching API.
|
|
|
|
---
|
|
|
|
## Getting Started
|
|
|
|
### 1. Login
|
|
|
|
First, authenticate to get your access token:
|
|
|
|
**Request:**
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/v1/auth/login \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"username": "admin",
|
|
"password": "admin123"
|
|
}'
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"access_token": "eyJhbGciOiJIUzI1NiIs...",
|
|
"refresh_token": "eyJhbGciOiJIUzI1NiIs...",
|
|
"token_type": "bearer",
|
|
"expires_in": 3600
|
|
}
|
|
```
|
|
|
|
**Save the access token** for subsequent requests.
|
|
|
|
---
|
|
|
|
## Common Operations
|
|
|
|
### Discover Available Cameras
|
|
|
|
```bash
|
|
curl -X GET http://localhost:8000/api/v1/cameras \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"cameras": [
|
|
{
|
|
"id": 1,
|
|
"name": "Entrance Camera",
|
|
"status": "online",
|
|
"has_ptz": true
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "Parking Lot Camera",
|
|
"status": "online",
|
|
"has_ptz": false
|
|
}
|
|
],
|
|
"total": 2
|
|
}
|
|
```
|
|
|
|
### Discover Available Monitors
|
|
|
|
```bash
|
|
curl -X GET http://localhost:8000/api/v1/monitors \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"monitors": [
|
|
{
|
|
"id": 1,
|
|
"name": "Control Room Monitor 1",
|
|
"status": "idle",
|
|
"current_camera_id": null
|
|
},
|
|
{
|
|
"id": 2,
|
|
"name": "Control Room Monitor 2",
|
|
"status": "active",
|
|
"current_camera_id": 5
|
|
}
|
|
],
|
|
"total": 2
|
|
}
|
|
```
|
|
|
|
### Find Available (Idle) Monitors
|
|
|
|
```bash
|
|
curl -X GET http://localhost:8000/api/v1/monitors/filter/available \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
|
```
|
|
|
|
Returns only monitors with no camera currently assigned.
|
|
|
|
---
|
|
|
|
## Cross-Switching Operations
|
|
|
|
### Route Camera to Monitor
|
|
|
|
**⚠️ Requires Operator role or higher**
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/v1/crossswitch \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"camera_id": 1,
|
|
"monitor_id": 1,
|
|
"mode": 0
|
|
}'
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"success": true,
|
|
"message": "Successfully switched camera 1 to monitor 1",
|
|
"route": {
|
|
"id": "uuid",
|
|
"camera_id": 1,
|
|
"monitor_id": 1,
|
|
"executed_at": "2025-12-09T12:00:00Z",
|
|
"executed_by_username": "operator"
|
|
}
|
|
}
|
|
```
|
|
|
|
### Clear Monitor
|
|
|
|
**⚠️ Requires Operator role or higher**
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8000/api/v1/crossswitch/clear \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"monitor_id": 1
|
|
}'
|
|
```
|
|
|
|
### Get Current Routing State
|
|
|
|
```bash
|
|
curl -X GET http://localhost:8000/api/v1/crossswitch/routing \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
|
```
|
|
|
|
**Response:**
|
|
```json
|
|
{
|
|
"routes": [
|
|
{
|
|
"camera_id": 1,
|
|
"monitor_id": 1,
|
|
"executed_at": "2025-12-09T12:00:00Z",
|
|
"is_active": true
|
|
}
|
|
],
|
|
"total": 1
|
|
}
|
|
```
|
|
|
|
### Get Routing History
|
|
|
|
```bash
|
|
curl -X GET "http://localhost:8000/api/v1/crossswitch/history?limit=10&offset=0" \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
|
```
|
|
|
|
**Filter by camera:**
|
|
```bash
|
|
curl -X GET "http://localhost:8000/api/v1/crossswitch/history?camera_id=1" \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
|
```
|
|
|
|
**Filter by monitor:**
|
|
```bash
|
|
curl -X GET "http://localhost:8000/api/v1/crossswitch/history?monitor_id=1" \
|
|
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
|
```
|
|
|
|
---
|
|
|
|
## Use Case Examples
|
|
|
|
### Use Case 1: Quick Camera Check
|
|
|
|
**Scenario**: Operator wants to quickly view entrance camera on their monitor.
|
|
|
|
**Steps:**
|
|
1. Find available monitor
|
|
2. Route entrance camera to that monitor
|
|
|
|
```bash
|
|
# Step 1: Find available monitors
|
|
curl -X GET http://localhost:8000/api/v1/monitors/filter/available \
|
|
-H "Authorization: Bearer $TOKEN"
|
|
|
|
# Step 2: Route camera 1 to monitor 1
|
|
curl -X POST http://localhost:8000/api/v1/crossswitch \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"camera_id": 1, "monitor_id": 1}'
|
|
```
|
|
|
|
### Use Case 2: Monitor Rotation
|
|
|
|
**Scenario**: Automatically rotate through cameras on a monitor.
|
|
|
|
**Script (PowerShell):**
|
|
```powershell
|
|
$token = "YOUR_ACCESS_TOKEN"
|
|
$monitor_id = 1
|
|
$cameras = @(1, 2, 3, 4) # Camera IDs to rotate
|
|
|
|
foreach ($camera_id in $cameras) {
|
|
# Switch camera
|
|
Invoke-RestMethod -Uri "http://localhost:8000/api/v1/crossswitch" `
|
|
-Method POST `
|
|
-Headers @{ "Authorization" = "Bearer $token" } `
|
|
-ContentType "application/json" `
|
|
-Body (@{ camera_id = $camera_id; monitor_id = $monitor_id } | ConvertTo-Json)
|
|
|
|
# Wait 10 seconds
|
|
Start-Sleep -Seconds 10
|
|
}
|
|
```
|
|
|
|
### Use Case 3: Incident Response
|
|
|
|
**Scenario**: Security incident detected, switch multiple cameras to control room monitors.
|
|
|
|
```bash
|
|
# Cameras 1-4 to monitors 1-4
|
|
for i in {1..4}; do
|
|
curl -X POST http://localhost:8000/api/v1/crossswitch \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{\"camera_id\": $i, \"monitor_id\": $i}"
|
|
done
|
|
```
|
|
|
|
### Use Case 4: Audit Trail Review
|
|
|
|
**Scenario**: Review who accessed which cameras today.
|
|
|
|
```bash
|
|
# Get routing history for today
|
|
curl -X GET "http://localhost:8000/api/v1/crossswitch/history?limit=100" \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
| jq '.history[] | select(.executed_at | startswith("2025-12-09"))'
|
|
```
|
|
|
|
---
|
|
|
|
## Python Client Example
|
|
|
|
```python
|
|
import requests
|
|
|
|
class GeutebruckAPI:
|
|
def __init__(self, base_url="http://localhost:8000", username="admin", password="admin123"):
|
|
self.base_url = base_url
|
|
self.token = None
|
|
self.login(username, password)
|
|
|
|
def login(self, username, password):
|
|
"""Authenticate and get token"""
|
|
response = requests.post(
|
|
f"{self.base_url}/api/v1/auth/login",
|
|
json={"username": username, "password": password}
|
|
)
|
|
response.raise_for_status()
|
|
self.token = response.json()["access_token"]
|
|
|
|
def _headers(self):
|
|
return {"Authorization": f"Bearer {self.token}"}
|
|
|
|
def list_cameras(self):
|
|
"""Get all cameras"""
|
|
response = requests.get(
|
|
f"{self.base_url}/api/v1/cameras",
|
|
headers=self._headers()
|
|
)
|
|
return response.json()
|
|
|
|
def list_monitors(self):
|
|
"""Get all monitors"""
|
|
response = requests.get(
|
|
f"{self.base_url}/api/v1/monitors",
|
|
headers=self._headers()
|
|
)
|
|
return response.json()
|
|
|
|
def crossswitch(self, camera_id, monitor_id, mode=0):
|
|
"""Execute cross-switch"""
|
|
response = requests.post(
|
|
f"{self.base_url}/api/v1/crossswitch",
|
|
headers=self._headers(),
|
|
json={
|
|
"camera_id": camera_id,
|
|
"monitor_id": monitor_id,
|
|
"mode": mode
|
|
}
|
|
)
|
|
return response.json()
|
|
|
|
def clear_monitor(self, monitor_id):
|
|
"""Clear monitor"""
|
|
response = requests.post(
|
|
f"{self.base_url}/api/v1/crossswitch/clear",
|
|
headers=self._headers(),
|
|
json={"monitor_id": monitor_id}
|
|
)
|
|
return response.json()
|
|
|
|
def get_routing_state(self):
|
|
"""Get current routing state"""
|
|
response = requests.get(
|
|
f"{self.base_url}/api/v1/crossswitch/routing",
|
|
headers=self._headers()
|
|
)
|
|
return response.json()
|
|
|
|
|
|
# Usage Example
|
|
api = GeutebruckAPI()
|
|
|
|
# List cameras
|
|
cameras = api.list_cameras()
|
|
print(f"Found {cameras['total']} cameras")
|
|
|
|
# Route camera 1 to monitor 1
|
|
result = api.crossswitch(camera_id=1, monitor_id=1)
|
|
print(f"Cross-switch: {result['message']}")
|
|
|
|
# Get routing state
|
|
routing = api.get_routing_state()
|
|
print(f"Active routes: {routing['total']}")
|
|
```
|
|
|
|
---
|
|
|
|
## C# Client Example
|
|
|
|
```csharp
|
|
using System;
|
|
using System.Net.Http;
|
|
using System.Net.Http.Json;
|
|
using System.Threading.Tasks;
|
|
|
|
public class GeutebruckApiClient
|
|
{
|
|
private readonly HttpClient _client;
|
|
private string _accessToken;
|
|
|
|
public GeutebruckApiClient(string baseUrl = "http://localhost:8000")
|
|
{
|
|
_client = new HttpClient { BaseAddress = new Uri(baseUrl) };
|
|
}
|
|
|
|
public async Task LoginAsync(string username, string password)
|
|
{
|
|
var response = await _client.PostAsJsonAsync("/api/v1/auth/login", new
|
|
{
|
|
username,
|
|
password
|
|
});
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
var result = await response.Content.ReadFromJsonAsync<LoginResponse>();
|
|
_accessToken = result.AccessToken;
|
|
_client.DefaultRequestHeaders.Authorization =
|
|
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _accessToken);
|
|
}
|
|
|
|
public async Task<CameraListResponse> ListCamerasAsync()
|
|
{
|
|
var response = await _client.GetAsync("/api/v1/cameras");
|
|
response.EnsureSuccessStatusCode();
|
|
return await response.Content.ReadFromJsonAsync<CameraListResponse>();
|
|
}
|
|
|
|
public async Task<CrossSwitchResponse> ExecuteCrossSwitchAsync(int cameraId, int monitorId, int mode = 0)
|
|
{
|
|
var response = await _client.PostAsJsonAsync("/api/v1/crossswitch", new
|
|
{
|
|
camera_id = cameraId,
|
|
monitor_id = monitorId,
|
|
mode
|
|
});
|
|
|
|
response.EnsureSuccessStatusCode();
|
|
return await response.Content.ReadFromJsonAsync<CrossSwitchResponse>();
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
var api = new GeutebruckApiClient();
|
|
await api.LoginAsync("admin", "admin123");
|
|
|
|
var cameras = await api.ListCamerasAsync();
|
|
Console.WriteLine($"Found {cameras.Total} cameras");
|
|
|
|
var result = await api.ExecuteCrossSwitchAsync(cameraId: 1, monitorId: 1);
|
|
Console.WriteLine($"Cross-switch: {result.Message}");
|
|
```
|
|
|
|
---
|
|
|
|
## Testing with Postman
|
|
|
|
1. **Import Collection**: Import the OpenAPI spec from http://localhost:8000/openapi.json
|
|
2. **Set Environment Variable**: Create `access_token` variable
|
|
3. **Login**: Run POST /api/v1/auth/login, save token to environment
|
|
4. **Test Endpoints**: All subsequent requests will use the token automatically
|
|
|
|
---
|
|
|
|
## Troubleshooting
|
|
|
|
### 401 Unauthorized
|
|
|
|
**Problem**: Token expired or invalid.
|
|
|
|
**Solution**: Re-authenticate:
|
|
```bash
|
|
# Get new token
|
|
curl -X POST http://localhost:8000/api/v1/auth/login \
|
|
-d '{"username":"admin","password":"admin123"}'
|
|
```
|
|
|
|
### 403 Forbidden
|
|
|
|
**Problem**: User role insufficient (e.g., Viewer trying to execute cross-switch).
|
|
|
|
**Solution**: Use account with Operator or Administrator role.
|
|
|
|
### 404 Not Found
|
|
|
|
**Problem**: Camera or monitor ID doesn't exist.
|
|
|
|
**Solution**: List cameras/monitors to find valid IDs.
|
|
|
|
### 500 Internal Server Error
|
|
|
|
**Problem**: SDK Bridge communication failure or database error.
|
|
|
|
**Solution**:
|
|
1. Check health endpoint: `/health`
|
|
2. Verify SDK Bridge is running
|
|
3. Check API logs
|
|
|
|
---
|
|
|
|
## Best Practices
|
|
|
|
1. **Always check health before operations**
|
|
2. **Cache camera/monitor lists** (refreshed every 60s)
|
|
3. **Handle 401 errors** by re-authenticating
|
|
4. **Use refresh tokens** to extend sessions
|
|
5. **Log all cross-switch operations** to external system
|
|
6. **Implement retry logic** for transient failures
|
|
7. **Monitor audit logs** for security events
|
|
|
|
---
|
|
|
|
## Next Steps
|
|
|
|
- Explore interactive documentation: http://localhost:8000/docs
|
|
- Review API reference: `docs/api-reference.md`
|
|
- Check deployment guide: `docs/deployment.md`
|
|
- Review architecture: `docs/architecture.md`
|