diff --git a/backend/app/schemas/nspd_bulk.py b/backend/app/schemas/nspd_bulk.py index 1bef84ae..9a463c34 100644 --- a/backend/app/schemas/nspd_bulk.py +++ b/backend/app/schemas/nspd_bulk.py @@ -69,8 +69,13 @@ class NSPDBulkFeature(BaseModel): @property def category_id(self) -> int | None: - """categoryId из properties (ключ для routing к target table).""" - val = self.properties.get("categoryId") + """category из properties (ключ для routing к target table). + + NSPD response shape: `properties.category` (НЕ `categoryId`). + Field name был неверно interpretirovan в initial PR2 implementation + based on HAR audit, тратили на debug проверял nspd_lite headers. + """ + val = self.properties.get("category") or self.properties.get("categoryId") return int(val) if val is not None else None @property diff --git a/backend/app/scrapers/nspd_bulk_client.py b/backend/app/scrapers/nspd_bulk_client.py index f45c98b9..725f6a5d 100644 --- a/backend/app/scrapers/nspd_bulk_client.py +++ b/backend/app/scrapers/nspd_bulk_client.py @@ -242,7 +242,9 @@ class NSPDBulkClient: return QuarterSnapshot(quarter=quarter, fetched_at=fetched_at) raw_features: list[dict[str, Any]] = data_block.get("features") or [] - raw_meta: list[dict[str, Any]] = data_block.get("meta") or [] + # meta лежит на TOP level: {"data": {features}, "meta": [...]} + # fallback на data.meta для legacy shape (just in case) + raw_meta: list[dict[str, Any]] = payload.get("meta") or data_block.get("meta") or [] features = [NSPDBulkFeature.model_validate(f) for f in raw_features]