feat: backend FastAPI Smart App City — auth JWT, IoT, GIS, notifications, reporting
This commit is contained in:
0
smart-app-city/backend/app/schemas/__init__.py
Normal file
0
smart-app-city/backend/app/schemas/__init__.py
Normal file
Binary file not shown.
Binary file not shown.
147
smart-app-city/backend/app/schemas/schemas.py
Normal file
147
smart-app-city/backend/app/schemas/schemas.py
Normal file
@@ -0,0 +1,147 @@
|
||||
"""Pydantic schemas for request/response validation.
|
||||
|
||||
All models are plain Pydantic BaseModel (not SQLModel) so they can be
|
||||
used purely for API I/O without DB-session side-effects.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import datetime
|
||||
from typing import Any, Generic, List, Optional, TypeVar
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# User
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
class UserCreate(BaseModel):
|
||||
email: str
|
||||
password: str = Field(min_length=8)
|
||||
username: str = Field(min_length=3, max_length=50)
|
||||
first_name: str
|
||||
last_name: str
|
||||
phone: Optional[str] = None
|
||||
|
||||
|
||||
class UserLogin(BaseModel):
|
||||
email: str
|
||||
password: str
|
||||
|
||||
|
||||
class UserResponse(BaseModel):
|
||||
id: UUID
|
||||
email: str
|
||||
username: str
|
||||
first_name: str
|
||||
last_name: str
|
||||
phone: Optional[str] = None
|
||||
role: str
|
||||
avatar_url: Optional[str] = None
|
||||
is_active: bool
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Auth / Token
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
class TokenResponse(BaseModel):
|
||||
access_token: str
|
||||
refresh_token: str
|
||||
token_type: str = "bearer"
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Sensor
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
class SensorResponse(BaseModel):
|
||||
id: UUID
|
||||
name: str
|
||||
type: str
|
||||
status: str
|
||||
latitude: float
|
||||
longitude: float
|
||||
zone_id: Optional[UUID] = None
|
||||
last_value: Optional[float] = None
|
||||
last_reading_at: Optional[datetime] = None
|
||||
battery_level: Optional[int] = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
class SensorReadingResponse(BaseModel):
|
||||
id: UUID
|
||||
sensor_id: UUID
|
||||
value: float
|
||||
unit: str
|
||||
quality: float
|
||||
recorded_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Zone
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
class ZoneResponse(BaseModel):
|
||||
id: UUID
|
||||
name: str
|
||||
description: Optional[str] = None
|
||||
color: str
|
||||
geojson: Optional[str] = None
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Alert
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
class AlertResponse(BaseModel):
|
||||
id: UUID
|
||||
sensor_id: UUID
|
||||
type: str
|
||||
severity: str
|
||||
message: str
|
||||
value: Optional[float] = None
|
||||
threshold: Optional[float] = None
|
||||
status: str
|
||||
created_at: datetime
|
||||
|
||||
model_config = {"from_attributes": True}
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Dashboard
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
class DashboardStats(BaseModel):
|
||||
total_sensors: int
|
||||
active_sensors: int
|
||||
total_readings_24h: int
|
||||
active_alerts: int
|
||||
avg_air_quality: Optional[float] = None
|
||||
avg_temperature: Optional[float] = None
|
||||
avg_humidity: Optional[float] = None
|
||||
|
||||
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
# Pagination (generic)
|
||||
# ──────────────────────────────────────────────────────────────────────
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class PaginatedResponse(BaseModel, Generic[T]):
|
||||
items: List[T]
|
||||
total: int
|
||||
page: int
|
||||
page_size: int
|
||||
pages: int
|
||||
Reference in New Issue
Block a user