Includes all pending changes needed for nixos-anywhere: - fiberlb: L7 policy, rule, certificate types - deployer: New service for cluster management - nix-nos: Generic network modules - Various service updates and fixes 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
24 KiB
PhotonCloud REST API Guide
Version: 1.0 Last Updated: 2025-12-12 Target: MVP-Alpha Phase
Overview
PhotonCloud provides REST/HTTP APIs for all core services, enabling easy access via curl for:
- 組み込み環境 (Embedded environments)
- Shell scripts and automation
- Debugging and troubleshooting
- Environments without gRPC tooling
All REST APIs follow consistent patterns and run alongside gRPC services on dedicated HTTP ports.
Service Port Map
| Service | HTTP Port | gRPC Port | Purpose |
|---|---|---|---|
| ChainFire | 8081 | 50051 | Distributed KV store with Raft consensus |
| FlareDB | 8082 | 50052 | SQL database (KV backend) |
| IAM | 8083 | 50051 | Identity & Access Management |
| PlasmaVMC | 8084 | 50051 | Virtual Machine Controller |
| k8shost | 8085 | 6443 | Kubernetes Host (kubelet replacement) |
| CreditService | 8086 | 50057 | Credit/Quota Management |
| PrismNET | 8087 | 9090 | Network Management (VPC/Subnet) |
| NightLight | 9090 | — | Prometheus TSDB (HTTP-only) |
| LightningSTOR | 9000 | — | S3-compatible Object Storage |
Common Patterns
Request Format
# Standard POST request with JSON body
curl -X POST http://localhost:8081/api/v1/kv/mykey/put \
-H "Content-Type: application/json" \
-d '{"value": "myvalue"}'
Response Format
Success Response:
{
"data": {
"id": "resource-id",
"name": "resource-name",
...
},
"meta": {
"request_id": "uuid-v4",
"timestamp": "2025-12-12T08:30:00Z"
}
}
Error Response:
{
"error": {
"code": "NOT_FOUND",
"message": "Resource not found",
"details": null
},
"meta": {
"request_id": "uuid-v4",
"timestamp": "2025-12-12T08:30:00Z"
}
}
Authentication
Most services support multi-tenancy via org_id and project_id:
# Query parameters for filtering
curl "http://localhost:8087/api/v1/vpcs?org_id=org-123&project_id=proj-456"
# Request body for creation
curl -X POST http://localhost:8087/api/v1/vpcs \
-H "Content-Type: application/json" \
-d '{
"name": "production-vpc",
"org_id": "org-123",
"project_id": "proj-456",
"cidr_block": "10.0.0.0/16"
}'
For IAM token-based auth:
# Issue token
TOKEN=$(curl -X POST http://localhost:8083/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"principal_id": "user-123",
"scope_id": "project-456",
"ttl_seconds": 3600
}' | jq -r '.data.token')
# Use token in Authorization header
curl -H "Authorization: Bearer $TOKEN" \
http://localhost:8084/api/v1/vms
1. ChainFire (Distributed KV Store)
Port: 8081 Purpose: Raft-based distributed key-value store with strong consistency
Health Check
curl http://localhost:8081/health
Cluster Status
# Get cluster status (node_id, term, role, is_leader)
curl http://localhost:8081/api/v1/cluster/status
Response:
{
"data": {
"node_id": 1,
"cluster_id": "cluster-123",
"term": 42,
"role": "leader",
"is_leader": true
},
"meta": { ... }
}
KV Operations
Put Key-Value:
curl -X POST http://localhost:8081/api/v1/kv/user:123/put \
-H "Content-Type: application/json" \
-d '{"value": "{\"name\":\"alice\",\"email\":\"alice@example.com\"}"}'
Get Value:
curl http://localhost:8081/api/v1/kv/user:123
Response:
{
"data": {
"key": "user:123",
"value": "{\"name\":\"alice\",\"email\":\"alice@example.com\"}"
},
"meta": { ... }
}
Delete Key:
curl -X POST http://localhost:8081/api/v1/kv/user:123/delete
Range Scan (Prefix Query):
# List all keys starting with "user:"
curl "http://localhost:8081/api/v1/kv?prefix=user:"
Response:
{
"data": {
"items": [
{"key": "user:123", "value": "{...}"},
{"key": "user:456", "value": "{...}"}
]
},
"meta": { ... }
}
Cluster Management
Add Cluster Member:
curl -X POST http://localhost:8081/api/v1/cluster/members \
-H "Content-Type: application/json" \
-d '{
"node_id": 2,
"address": "192.168.1.102:50051"
}'
2. FlareDB (SQL Database)
Port: 8082 Purpose: Distributed SQL database with KV backend
Health Check
curl http://localhost:8082/health
KV Operations
Put Key-Value:
curl -X PUT http://localhost:8082/api/v1/kv/config:db_version \
-H "Content-Type: application/json" \
-d '{
"value": "1.0.0",
"namespace": "system"
}'
Get Value:
curl "http://localhost:8082/api/v1/kv/config:db_version?namespace=system"
Response:
{
"data": {
"key": "config:db_version",
"value": "1.0.0",
"namespace": "system"
},
"meta": { ... }
}
Range Scan:
curl "http://localhost:8082/api/v1/scan?start=config:&end=config;&&namespace=system"
SQL Operations (Placeholder)
Execute SQL:
# Note: SQL endpoint is placeholder - use gRPC for full SQL functionality
curl -X POST http://localhost:8082/api/v1/sql \
-H "Content-Type: application/json" \
-d '{
"query": "SELECT * FROM users WHERE id = 123"
}'
List Tables:
# Note: Placeholder endpoint - use gRPC for full functionality
curl http://localhost:8082/api/v1/tables
3. IAM (Identity & Access Management)
Port: 8083 Purpose: Authentication, authorization, user and policy management
Health Check
curl http://localhost:8083/health
Token Operations
Issue Token:
curl -X POST http://localhost:8083/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"principal_id": "user-alice",
"principal_type": "user",
"scope_id": "project-prod",
"ttl_seconds": 3600
}'
Response:
{
"data": {
"token": "eyJhbGciOiJIUzI1NiIs...",
"expires_at": "2025-12-12T10:30:00Z"
},
"meta": { ... }
}
Verify Token:
curl -X POST http://localhost:8083/api/v1/auth/verify \
-H "Content-Type: application/json" \
-d '{
"token": "eyJhbGciOiJIUzI1NiIs..."
}'
Response:
{
"data": {
"valid": true,
"principal_id": "user-alice",
"scope_id": "project-prod",
"expires_at": "2025-12-12T10:30:00Z"
},
"meta": { ... }
}
User Management
Create User:
curl -X POST http://localhost:8083/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"id": "user-bob",
"name": "Bob Smith",
"email": "bob@example.com",
"type": "user"
}'
List Users:
curl "http://localhost:8083/api/v1/users?scope_id=project-prod"
Response:
{
"data": {
"users": [
{
"id": "user-alice",
"name": "Alice Johnson",
"email": "alice@example.com",
"type": "user"
},
{
"id": "user-bob",
"name": "Bob Smith",
"email": "bob@example.com",
"type": "user"
}
]
},
"meta": { ... }
}
Project Management (Placeholder)
# Note: Project management uses Scope/PolicyBinding in gRPC
# These REST endpoints are placeholders
curl http://localhost:8083/api/v1/projects
curl -X POST http://localhost:8083/api/v1/projects \
-H "Content-Type: application/json" \
-d '{"name": "production", "org_id": "org-123"}'
4. PlasmaVMC (Virtual Machine Controller)
Port: 8084 Purpose: VM lifecycle management (create, start, stop, delete)
Health Check
curl http://localhost:8084/health
VM Operations
List VMs:
curl "http://localhost:8084/api/v1/vms?org_id=org-123&project_id=proj-456"
Response:
{
"data": {
"vms": [
{
"id": "vm-001",
"name": "web-server-01",
"state": "Running",
"cpus": 4,
"memory_mb": 8192
},
{
"id": "vm-002",
"name": "db-server-01",
"state": "Stopped",
"cpus": 8,
"memory_mb": 16384
}
]
},
"meta": { ... }
}
Create VM:
curl -X POST http://localhost:8084/api/v1/vms \
-H "Content-Type: application/json" \
-d '{
"name": "app-server-03",
"org_id": "org-123",
"project_id": "proj-456",
"vcpus": 2,
"memory_mib": 4096,
"hypervisor": "kvm",
"image_id": "ubuntu-22.04",
"disk_size_gb": 50
}'
Response:
{
"data": {
"id": "vm-003",
"name": "app-server-03",
"state": "Creating",
"cpus": 2,
"memory_mb": 4096
},
"meta": { ... }
}
Get VM Details:
curl "http://localhost:8084/api/v1/vms/vm-003?org_id=org-123&project_id=proj-456"
Start VM:
curl -X POST "http://localhost:8084/api/v1/vms/vm-003/start?org_id=org-123&project_id=proj-456"
Stop VM:
curl -X POST "http://localhost:8084/api/v1/vms/vm-003/stop?org_id=org-123&project_id=proj-456" \
-H "Content-Type: application/json" \
-d '{"force": false}'
Delete VM:
curl -X DELETE "http://localhost:8084/api/v1/vms/vm-003?org_id=org-123&project_id=proj-456"
5. k8shost (Kubernetes Host)
Port: 8085 Purpose: Kubernetes pod/service/node management (kubelet replacement)
Health Check
curl http://localhost:8085/health
Pod Operations
List Pods:
# All namespaces
curl http://localhost:8085/api/v1/pods
# Specific namespace
curl "http://localhost:8085/api/v1/pods?namespace=production"
Response:
{
"data": {
"pods": [
{
"name": "nginx-deployment-7d8f9c5b6d-xk2p9",
"namespace": "production",
"phase": "Running",
"pod_ip": "10.244.1.5",
"node_name": "worker-01"
}
]
},
"meta": { ... }
}
Create Pod:
curl -X POST http://localhost:8085/api/v1/pods \
-H "Content-Type: application/json" \
-d '{
"name": "nginx-pod",
"namespace": "production",
"image": "nginx:1.21",
"command": ["/bin/sh"],
"args": ["-c", "nginx -g \"daemon off;\""]
}'
Delete Pod:
curl -X DELETE http://localhost:8085/api/v1/pods/production/nginx-pod
Service Operations
List Services:
curl "http://localhost:8085/api/v1/services?namespace=production"
Response:
{
"data": {
"services": [
{
"name": "nginx-service",
"namespace": "production",
"type": "ClusterIP",
"cluster_ip": "10.96.0.100",
"ports": [
{"port": 80, "target_port": 8080, "protocol": "TCP"}
]
}
]
},
"meta": { ... }
}
Create Service:
curl -X POST http://localhost:8085/api/v1/services \
-H "Content-Type: application/json" \
-d '{
"name": "app-service",
"namespace": "production",
"service_type": "ClusterIP",
"port": 80,
"target_port": 8080,
"selector": {"app": "nginx"}
}'
Delete Service:
curl -X DELETE http://localhost:8085/api/v1/services/production/app-service
Node Operations
List Nodes:
curl http://localhost:8085/api/v1/nodes
Response:
{
"data": {
"nodes": [
{
"name": "worker-01",
"status": "Ready",
"capacity_cpu": "8",
"capacity_memory": "16Gi",
"allocatable_cpu": "7.5",
"allocatable_memory": "14Gi"
}
]
},
"meta": { ... }
}
6. CreditService (Credit/Quota Management)
Port: 8086 Purpose: Multi-tenant credit tracking, reservations, and billing
Health Check
curl http://localhost:8086/health
Wallet Operations
Create Wallet:
curl -X POST http://localhost:8086/api/v1/wallets \
-H "Content-Type: application/json" \
-d '{
"project_id": "proj-456",
"org_id": "org-123",
"initial_balance": 10000
}'
Get Wallet Balance:
curl http://localhost:8086/api/v1/wallets/proj-456
Response:
{
"data": {
"project_id": "proj-456",
"org_id": "org-123",
"balance": 10000,
"reserved": 2500,
"available": 7500,
"currency": "JPY",
"status": "active"
},
"meta": { ... }
}
Top Up Credits:
curl -X POST http://localhost:8086/api/v1/wallets/proj-456/topup \
-H "Content-Type: application/json" \
-d '{
"amount": 5000,
"description": "Monthly credit purchase"
}'
Get Transactions:
curl "http://localhost:8086/api/v1/wallets/proj-456/transactions?limit=10"
Response:
{
"data": {
"transactions": [
{
"id": "txn-001",
"project_id": "proj-456",
"amount": 5000,
"type": "deposit",
"description": "Monthly credit purchase",
"timestamp": "2025-12-12T08:00:00Z"
},
{
"id": "txn-002",
"project_id": "proj-456",
"amount": -1500,
"type": "charge",
"description": "VM usage charge",
"resource_id": "vm-003",
"timestamp": "2025-12-12T09:00:00Z"
}
]
},
"meta": { ... }
}
Reservation Operations
Reserve Credits:
curl -X POST http://localhost:8086/api/v1/reservations \
-H "Content-Type: application/json" \
-d '{
"project_id": "proj-456",
"amount": 2000,
"description": "VM creation reservation",
"resource_type": "vm",
"resource_id": "vm-004",
"ttl_seconds": 3600
}'
Response:
{
"data": {
"id": "rsv-001",
"project_id": "proj-456",
"amount": 2000,
"status": "active",
"expires_at": "2025-12-12T10:00:00Z"
},
"meta": { ... }
}
Commit Reservation:
curl -X POST http://localhost:8086/api/v1/reservations/rsv-001/commit \
-H "Content-Type: application/json" \
-d '{
"actual_amount": 1800,
"resource_id": "vm-004"
}'
Release Reservation:
curl -X POST http://localhost:8086/api/v1/reservations/rsv-001/release \
-H "Content-Type: application/json" \
-d '{
"reason": "VM creation failed"
}'
7. PrismNET (Network Management)
Port: 8087 Purpose: Multi-tenant VPC, subnet, and port management
Health Check
curl http://localhost:8087/health
VPC Operations
List VPCs:
curl "http://localhost:8087/api/v1/vpcs?org_id=org-123&project_id=proj-456"
Response:
{
"data": {
"vpcs": [
{
"id": "vpc-001",
"name": "production-vpc",
"org_id": "org-123",
"project_id": "proj-456",
"cidr_block": "10.0.0.0/16",
"description": "Production environment VPC",
"status": "active"
}
]
},
"meta": { ... }
}
Create VPC:
curl -X POST http://localhost:8087/api/v1/vpcs \
-H "Content-Type: application/json" \
-d '{
"name": "staging-vpc",
"org_id": "org-123",
"project_id": "proj-456",
"cidr_block": "172.16.0.0/16",
"description": "Staging environment VPC"
}'
Get VPC:
curl "http://localhost:8087/api/v1/vpcs/vpc-001?org_id=org-123&project_id=proj-456"
Delete VPC:
curl -X DELETE "http://localhost:8087/api/v1/vpcs/vpc-001?org_id=org-123&project_id=proj-456"
Subnet Operations
List Subnets:
curl "http://localhost:8087/api/v1/subnets?vpc_id=vpc-001&org_id=org-123&project_id=proj-456"
Response:
{
"data": {
"subnets": [
{
"id": "subnet-001",
"name": "web-subnet",
"vpc_id": "vpc-001",
"cidr_block": "10.0.1.0/24",
"gateway_ip": "10.0.1.1",
"description": "Web tier subnet",
"status": "active"
},
{
"id": "subnet-002",
"name": "db-subnet",
"vpc_id": "vpc-001",
"cidr_block": "10.0.2.0/24",
"gateway_ip": "10.0.2.1",
"description": "Database tier subnet",
"status": "active"
}
]
},
"meta": { ... }
}
Create Subnet:
curl -X POST http://localhost:8087/api/v1/subnets \
-H "Content-Type: application/json" \
-d '{
"name": "app-subnet",
"vpc_id": "vpc-001",
"cidr_block": "10.0.3.0/24",
"gateway_ip": "10.0.3.1",
"description": "Application tier subnet"
}'
Delete Subnet:
curl -X DELETE "http://localhost:8087/api/v1/subnets/subnet-003?org_id=org-123&project_id=proj-456&vpc_id=vpc-001"
Complete Workflow Examples
Example 1: Deploy VM with Networking
# 1. Create VPC
VPC_ID=$(curl -s -X POST http://localhost:8087/api/v1/vpcs \
-H "Content-Type: application/json" \
-d '{
"name": "app-vpc",
"org_id": "org-123",
"project_id": "proj-456",
"cidr_block": "10.100.0.0/16"
}' | jq -r '.data.id')
# 2. Create Subnet
SUBNET_ID=$(curl -s -X POST http://localhost:8087/api/v1/subnets \
-H "Content-Type: application/json" \
-d "{
\"name\": \"app-subnet\",
\"vpc_id\": \"$VPC_ID\",
\"cidr_block\": \"10.100.1.0/24\",
\"gateway_ip\": \"10.100.1.1\"
}" | jq -r '.data.id')
# 3. Reserve Credits
RSV_ID=$(curl -s -X POST http://localhost:8086/api/v1/reservations \
-H "Content-Type: application/json" \
-d '{
"project_id": "proj-456",
"amount": 5000,
"resource_type": "vm",
"ttl_seconds": 3600
}' | jq -r '.data.id')
# 4. Create VM
VM_ID=$(curl -s -X POST http://localhost:8084/api/v1/vms \
-H "Content-Type: application/json" \
-d '{
"name": "app-server",
"org_id": "org-123",
"project_id": "proj-456",
"vcpus": 4,
"memory_mib": 8192,
"hypervisor": "kvm"
}' | jq -r '.data.id')
# 5. Start VM
curl -X POST "http://localhost:8084/api/v1/vms/$VM_ID/start?org_id=org-123&project_id=proj-456"
# 6. Commit Reservation
curl -X POST "http://localhost:8086/api/v1/reservations/$RSV_ID/commit" \
-H "Content-Type: application/json" \
-d "{
\"actual_amount\": 4500,
\"resource_id\": \"$VM_ID\"
}"
echo "VM deployed: $VM_ID in VPC: $VPC_ID, Subnet: $SUBNET_ID"
Example 2: Deploy Kubernetes Pod with Service
# 1. Create Pod
curl -X POST http://localhost:8085/api/v1/pods \
-H "Content-Type: application/json" \
-d '{
"name": "nginx-app",
"namespace": "production",
"image": "nginx:1.21"
}'
# 2. Create Service
curl -X POST http://localhost:8085/api/v1/services \
-H "Content-Type: application/json" \
-d '{
"name": "nginx-service",
"namespace": "production",
"service_type": "ClusterIP",
"port": 80,
"target_port": 80,
"selector": {"app": "nginx"}
}'
# 3. Verify Pod Status
curl "http://localhost:8085/api/v1/pods?namespace=production" | jq '.data.pods[] | select(.name=="nginx-app")'
Example 3: User Authentication Flow
# 1. Create User
curl -X POST http://localhost:8083/api/v1/users \
-H "Content-Type: application/json" \
-d '{
"id": "user-charlie",
"name": "Charlie Brown",
"email": "charlie@example.com",
"type": "user"
}'
# 2. Issue Token
TOKEN=$(curl -s -X POST http://localhost:8083/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{
"principal_id": "user-charlie",
"scope_id": "project-prod",
"ttl_seconds": 7200
}' | jq -r '.data.token')
# 3. Verify Token
curl -X POST http://localhost:8083/api/v1/auth/verify \
-H "Content-Type: application/json" \
-d "{\"token\": \"$TOKEN\"}"
# 4. Use Token for API Call
curl -H "Authorization: Bearer $TOKEN" \
"http://localhost:8084/api/v1/vms?org_id=org-123&project_id=project-prod"
Debugging Tips
Check All Services Health
#!/bin/bash
services=(
"ChainFire:8081"
"FlareDB:8082"
"IAM:8083"
"PlasmaVMC:8084"
"k8shost:8085"
"CreditService:8086"
"PrismNET:8087"
)
for svc in "${services[@]}"; do
name="${svc%%:*}"
port="${svc##*:}"
echo -n "$name ($port): "
curl -s http://localhost:$port/health | jq -r '.data.status // "ERROR"'
done
Verbose curl for Debugging
# Show request/response headers
curl -v http://localhost:8081/health
# Show timing information
curl -w "@-" -o /dev/null -s http://localhost:8081/health <<'EOF'
time_namelookup: %{time_namelookup}\n
time_connect: %{time_connect}\n
time_total: %{time_total}\n
EOF
Pretty-print JSON Responses
# Install jq if not available
# Ubuntu/Debian: sudo apt-get install jq
# macOS: brew install jq
curl http://localhost:8087/api/v1/vpcs | jq '.'
Migration from gRPC
If you have existing gRPC client code, here's how to migrate:
gRPC (Before)
use chainfire_client::ChainFireClient;
let mut client = ChainFireClient::connect("http://localhost:50051").await?;
let response = client.get(tonic::Request::new(GetRequest {
key: "mykey".to_string(),
})).await?;
println!("Value: {}", response.into_inner().value);
REST (After)
curl http://localhost:8081/api/v1/kv/mykey | jq -r '.data.value'
Or with any HTTP client library:
import requests
response = requests.get('http://localhost:8081/api/v1/kv/mykey')
data = response.json()
print(f"Value: {data['data']['value']}")
Error Handling
All services return consistent error responses:
Common HTTP Status Codes
| Code | Meaning | Example |
|---|---|---|
| 200 | OK | Successful GET/POST |
| 201 | Created | Resource created |
| 400 | Bad Request | Invalid JSON or missing required fields |
| 404 | Not Found | Resource doesn't exist |
| 409 | Conflict | Resource already exists or state conflict |
| 500 | Internal Server Error | Service error |
| 503 | Service Unavailable | Service not ready (e.g., Raft not leader) |
Error Response Example
curl -X POST http://localhost:8087/api/v1/vpcs \
-H "Content-Type: application/json" \
-d '{"name": "invalid"}'
Response (400 Bad Request):
{
"error": {
"code": "VALIDATION_ERROR",
"message": "cidr_block is required",
"details": {
"field": "cidr_block",
"constraint": "required"
}
},
"meta": {
"request_id": "req-12345",
"timestamp": "2025-12-12T08:30:00Z"
}
}
Handling Errors in Scripts
#!/bin/bash
response=$(curl -s -w "\n%{http_code}" http://localhost:8084/api/v1/vms/invalid-id)
body=$(echo "$response" | head -n -1)
status=$(echo "$response" | tail -n 1)
if [ "$status" -ne 200 ]; then
echo "Error: $(echo $body | jq -r '.error.message')"
exit 1
fi
echo "Success: $body"
Performance Considerations
Connection Reuse
For multiple requests, reuse connections:
# Single connection for multiple requests
curl -K - <<EOF
url = http://localhost:8081/api/v1/kv/key1
url = http://localhost:8081/api/v1/kv/key2
url = http://localhost:8081/api/v1/kv/key3
EOF
Batch Operations
Where possible, use range queries instead of individual requests:
# Bad: Multiple individual requests
curl http://localhost:8081/api/v1/kv/user:1
curl http://localhost:8081/api/v1/kv/user:2
curl http://localhost:8081/api/v1/kv/user:3
# Good: Single range query
curl "http://localhost:8081/api/v1/kv?prefix=user:"
Parallel Requests
Use xargs or GNU parallel for concurrent requests:
# Parallel health checks
echo -e "8081\n8082\n8083\n8084\n8085\n8086\n8087" | \
xargs -I {} -P 7 curl -s http://localhost:{}/health
OpenAPI / Swagger Specifications
OpenAPI specifications are available for each service (planned):
docs/api/openapi/chainfire.yamldocs/api/openapi/flaredb.yamldocs/api/openapi/iam.yamldocs/api/openapi/plasmavmc.yamldocs/api/openapi/k8shost.yamldocs/api/openapi/creditservice.yamldocs/api/openapi/prismnet.yaml
You can import these into Postman, Insomnia, or generate client SDKs using openapi-generator.
Postman Collection
A Postman collection with all endpoints and example requests is available:
docs/api/postman/photoncloud-rest-api.json(planned)
Import this into Postman for interactive API exploration and testing.
Related Documentation
- gRPC APIs: See individual service
proto/directories - Architecture:
docs/architecture/ARCHITECTURE.md - REST API Patterns:
docs/specifications/rest-api-patterns.md - Security:
docs/security/AUTH.md(when available) - Deployment:
docs/deployment/(when available)
Support & Feedback
For questions, issues, or feature requests:
- Project Repository:
/home/centra/cloud/ - Task Tracking:
docs/por/(Plan of Record) - Active Task: T050 REST API Implementation
Last Updated: 2025-12-12 Documentation Version: 1.0 (MVP-Alpha Phase)