from typing import Any from pydantic import BaseModel, Field # ── Connection points schemas (issue #115) ──────────────────────────────────── class EngineeringStructure(BaseModel): name: str | None type: str | None cad_num: str | None distance_to_boundary_m: float geometry_geojson: dict[str, Any] readable_address: str | None raw_props: dict[str, Any] source: str class ZouitOverlap(BaseModel): reg_numb_border: str | None type_zone: str | None subcategory: int | None intersects_parcel: bool geometry_geojson: dict[str, Any] raw_props: dict[str, Any] source: str class ConnectionPointsSummary(BaseModel): nearest_structure_distance_m: float | None in_protection_zone: bool protection_zones_intersecting: int total_structures_in_radius: int class ConnectionPointsResponse(BaseModel): engineering_structures: list[EngineeringStructure] zouit_engineering_overlaps: list[ZouitOverlap] summary: ConnectionPointsSummary dump_available: bool dump_fetched_at: str | None # ── Parcel search/detail schemas ────────────────────────────────────────────── class ParcelFilter(BaseModel): vri: list[str] | None = None area_min_sqm: float | None = None area_max_sqm: float | None = None region: str | None = None polygon_geojson: dict[str, Any] | None = None text_search: str | None = None class ScoringWeights(BaseModel): distance_to_center: float = 0.4 poi_density: float = 0.3 neighborhood_price: float = 0.3 class ParcelSearchRequest(BaseModel): filters: ParcelFilter = Field(default_factory=ParcelFilter) weights: ScoringWeights = Field(default_factory=ScoringWeights) limit: int = 50 class ScoreBreakdown(BaseModel): total: float distance_to_center: float poi_density: float neighborhood_price: float class ParcelSummary(BaseModel): id: str cadastral_number: str area_sqm: float vri: str address: str | None score: ScoreBreakdown class ParcelSearchResponse(BaseModel): items: list[ParcelSummary] total: int class ParcelDetail(ParcelSummary): geometry_geojson: dict[str, Any] enrichment: dict[str, Any]