gendesign/backend/app/api/v1
lekss361 608490fbba
fix(parcels): _parse_floors handle int (post-migration #169) (#176)
* fix(parcels): _parse_floors handle int (post-migration #169 schema change)

After PR #169 cad_buildings schema migration, `floors` column is INT
(was TEXT in legacy schema). Existing `_parse_floors(r.get("floors"))`
call in analyze_parcel → _neighbors_summary crashes with:
  AttributeError: 'int' object has no attribute 'strip'

Fix: type union str | int | None. If int → return directly (no strip).
Preserve TEXT range parsing ("5-7" → 7) for backwards-compat with
any legacy data still in cad_buildings_old_apr26.

* test(smoke): production smoke tests for post-deploy regressions (#168)

Add tests/smoke/test_prod_smoke.py covering known regression surfaces.
Marks: prod_smoke + slow. Env: PROD_SMOKE_BASE_URL, PROD_SMOKE_ADMIN_TOKEN.
Run manually: cd backend && uv run pytest tests/smoke/ -m prod_smoke -v

* fix(cadastre): exact-match headers to nspd_lite to bypass NSPD WAF (#168)

Pilot v2 (job_id=2) failed 50/50 with HTTP 403 WAF block. Comparing
nspd_bulk_client.DEFAULT_HEADERS vs legacy nspd_lite.HEADERS (which works
on VPS IP since April 2026):

  PascalCase keys → lowercase keys
  Chrome/148 UA → Chrome/144 UA
  No cache-control / pragma → "no-cache" both
  accept-language ru first → en first
  No origin → "https://nspd.gov.ru"
  referer "/map" → "/map?thematic=PKK"

NSPD WAF (BotShield-class) likely fingerprints на header order + values
combined with TLS fingerprint. Matching legacy exactly minimizes deltas.

Test plan: retry pilot job after deploy, expect 0 WAF blocks for first
5 quarters.

* fix(test): exclude prod_smoke tests by default (#168)

CI ran tests/smoke/test_prod_smoke.py and they hit production
https://gendsgn.ru/api/v1/parcels/.../analyze which currently returns 500
(parse_floors regression — exactly what this PR fixes). Catch-22: PR can't
merge because smoke tests fail against pre-merge prod.

Fix: add `addopts = ["-m", "not prod_smoke"]` so default pytest excludes
them. Run manually post-deploy with: pytest -m prod_smoke -v

---------

Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-15 15:08:16 +03:00
..
__init__.py init 2026-04-25 13:45:19 +03:00
admin_cadastre.py feat(cadastre): bulk_harvest worker + grid-walker + admin API (#168 PR3/5) (#171) 2026-05-15 13:31:32 +03:00
admin_jobs.py refactor(admin): extract _check_token into shared AdminTokenAuth dep (#133) 2026-05-14 23:45:44 +03:00
admin_leads.py refactor(admin): extract _check_token into shared AdminTokenAuth dep (#133) 2026-05-14 23:45:44 +03:00
admin_scrape.py refactor(admin): extract _check_token into shared AdminTokenAuth dep (#133) 2026-05-14 23:45:44 +03:00
admin_weight_profiles.py feat(site-finder): weight profiles endpoints + analyze integration (#114 sub-PR 3/4) (#138) 2026-05-15 00:40:06 +03:00
analytics.py feat(api,analytics): bulk geo backfill + complex_buildings query 2026-05-11 15:56:17 +03:00
concepts.py init 2026-04-25 13:45:19 +03:00
parcels.py fix(parcels): _parse_floors handle int (post-migration #169) (#176) 2026-05-15 15:08:16 +03:00
photos.py fix ui 2026-04-27 20:42:18 +03:00