letsbe-hub/app/schemas/instance.py

128 lines
3.1 KiB
Python
Raw Normal View History

"""Instance schemas for API serialization."""
from datetime import datetime
from typing import Optional
from uuid import UUID
from pydantic import BaseModel, ConfigDict, Field
class InstanceCreate(BaseModel):
"""Schema for creating a new instance."""
instance_id: str = Field(
...,
min_length=1,
max_length=255,
description="Unique instance identifier (e.g., 'acme-orchestrator')",
)
region: Optional[str] = Field(None, max_length=50, description="Deployment region")
license_expires_at: Optional[datetime] = Field(
None,
description="License expiry date (None = perpetual)",
)
class InstanceResponse(BaseModel):
"""Schema for instance API responses.
Note: license_key and hub_api_key are ONLY returned on creation.
"""
model_config = ConfigDict(from_attributes=True)
id: UUID
instance_id: str
client_id: UUID
# License info
license_key: Optional[str] = Field(
None,
description="ONLY returned on creation - store securely!",
)
license_key_prefix: str
license_status: str
license_issued_at: datetime
license_expires_at: Optional[datetime]
# Hub API key
hub_api_key: Optional[str] = Field(
None,
description="ONLY returned on creation - store securely!",
)
# Activation state
activated_at: Optional[datetime]
last_activation_at: Optional[datetime]
activation_count: int
# Metadata
region: Optional[str]
version: Optional[str]
last_seen_at: Optional[datetime]
status: str
created_at: datetime
updated_at: datetime
class InstanceBriefResponse(BaseModel):
"""Brief instance response for listings (no secrets)."""
model_config = ConfigDict(from_attributes=True)
id: UUID
instance_id: str
client_id: UUID
license_key_prefix: str
license_status: str
license_expires_at: Optional[datetime]
activated_at: Optional[datetime]
activation_count: int
region: Optional[str]
status: str
created_at: datetime
# === ACTIVATION SCHEMAS ===
class ActivationRequest(BaseModel):
"""
Activation request from a client instance.
PRIVACY: This schema ONLY accepts:
- license_key (credential for validation)
- instance_id (identifier)
It NEVER accepts sensitive data fields.
"""
license_key: str = Field(..., description="License key (lb_inst_...)")
instance_id: str = Field(..., description="Instance identifier")
class ActivationResponse(BaseModel):
"""Response to a successful activation."""
status: str = Field("ok", description="Activation status")
instance_id: str
hub_api_key: str = Field(
...,
description="API key for telemetry auth (or 'USE_EXISTING')",
)
config: dict = Field(
default_factory=dict,
description="Optional configuration from Hub",
)
class ActivationError(BaseModel):
"""Error response for failed activation."""
error: str = Field(..., description="Human-readable error message")
code: str = Field(
...,
description="Error code: invalid_license, expired, suspended, instance_not_found",
)