Commit graph

21 commits

Author SHA1 Message Date
9a6b56016b fix(analytics): de-inflate domrf_kn snapshot counts (8.49×) + backfill UPSERT columns (#2464) (#2470)
All checks were successful
Deploy / changes (push) Successful in 9s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 2m1s
Deploy / build-worker (push) Successful in 3m22s
Deploy / deploy (push) Successful in 1m40s
2026-07-08 07:30:12 +00:00
53b160ff0a fix(scrapers): rate-limit/backoff/circuit-breaker для ОКН EGRKN-скрапера (#2445-D3) (#2461)
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 2m13s
Deploy / deploy (push) Successful in 1m41s
Deploy / build-worker (push) Successful in 3m19s
2026-07-05 20:09:18 +00:00
464519c69b fix(workers): izyatie per-doc isolation + newbuilding-crossload breadcrumb (#2445-D5/D6) (#2460)
Some checks failed
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Has been cancelled
2026-07-05 20:09:12 +00:00
7315d04396 fix(scrapers): WAF-guard эндпоинтов + throttled catalog BrowserSession (#2445-D1/D2) (#2459)
Some checks failed
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Has been cancelled
2026-07-05 20:09:06 +00:00
5b3799a23a feat(scrapers): wire per-flat DOM.РФ catalog scraper + propagate catalog_url_hash (#2442) (#2444)
All checks were successful
Deploy / changes (push) Successful in 8s
Deploy / build-backend (push) Successful in 3m26s
Deploy / build-frontend (push) Successful in 3m38s
Deploy / deploy (push) Successful in 2m28s
Deploy / build-worker (push) Successful in 4m20s
2026-07-05 17:00:58 +00:00
eea9c99e73 feat(scrapers): extract + download DOM.РФ flat plan images (#2440) (#2441)
All checks were successful
Deploy / changes (push) Successful in 8s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 2m2s
Deploy / build-worker (push) Successful in 3m20s
Deploy / deploy (push) Successful in 1m35s
2026-07-05 16:23:29 +00:00
3421b21632 fix(scrapers): разблокировать domrf_kn flats — изоляция flats от poison-extras + throttle (#1945) (#2050)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 9m31s
Deploy / build-worker (push) Successful in 11m57s
Deploy / deploy (push) Successful in 3m51s
2026-06-28 13:03:43 +00:00
c3c89646ce fix(scrapers): narrow domrf Level-1 status badge-class regex (#1609 follow-up)
Some checks failed
CI / changes (push) Successful in 8s
CI / changes (pull_request) Has been cancelled
CI / backend-tests (pull_request) Has been cancelled
CI / frontend-tests (pull_request) Has been cancelled
CI / openapi-codegen-check (pull_request) Has been cancelled
CI / backend-tests (push) Has been cancelled
CI / frontend-tests (push) Has been cancelled
CI / openapi-codegen-check (push) Has been cancelled
_STATUS_BADGE_CLS_RE was too broad: `status|badge|tag|chip|label` matched
generic UI elements (e.g. <span class="label">, <span class="chip">) that
are unrelated to the sale-status badge, risking picking the wrong block.

Narrowed to `(?<![a-z])status(?![a-z])` — requires the literal token
"status" as a hyphen-delimited component of the CSS class (matches
`status-badge`, `flat-status-tag`, `object-status` but not bare `label`,
`tag`, `chip`, `badge`).

Adds regression test: page with generic label/tag/chip/badge elements
containing "В продаже" must NOT activate Level-1; only the real
`status-badge` block ("Продана") should be returned → status=sold.
2026-06-17 21:21:56 +03:00
4f0cff92ec fix(scrapers): scope+stem domrf status classification, fix продано/продана mismatch (#1609)
Some checks failed
CI / changes (push) Successful in 8s
CI / changes (pull_request) Successful in 7s
CI / backend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m39s
CI / backend-tests (pull_request) Failing after 8m48s
Replace whole-HTML re.search for status with a 3-level block-scoped strategy:
1. CSS badge classes (status/badge/tag/chip/label) — highest precision.
2. Proximity to block labelled «Статус» via _find_text_near.
3. Full blocks scan where sold/reserved keywords always beat free —
   preventing «в продаже» from nav/similar-flats sections from
   misclassifying sold flats as free.

Add _STATUS_KW_RE and _classify_status_kw at module level with full
morphological coverage: продан/продана/продано, реализован[аоы]?,
забронирован[аоы]?, свободн[аоы]?.

Add 31 tests in test_domrf_catalog_parse.py covering all three
extraction levels plus regression for fem. word-form «Квартира продана».
2026-06-17 20:40:49 +03:00
c3c6e2cef1 fix(okn): expand registry coverage + load detail-card name/address (#1159)
okn_objects_sync собирал 428 ОКН из ~798 ЕГРОКН и сохранял raw_props={id}
без названия/адреса — analyze показывал 'ОКН рядом' без указания КАКОГО.

Coverage: расширил _ADDRESS_PASSES с 2 до 11 подстрок (Екатеринбург,
г. Екатеринбург, 7 районов ЕКБ, 2 формы Свердловской обл.). _PASSES =
декартово (address × category). first-wins дедуп сохраняет высшую категорию.

Detail: fetch_okn_detail(source_id) — GET Show/Show?id=, BeautifulSoup
парсит HTML (dl/dt/dd и tr/td), извлекает name, address, protection_category,
object_kind, dating. _enrich_with_detail сливает в raw_props с graceful
failover (cap=1500, exception per-object не валит прогон).

Lookup: parcel_okn_objects возвращает name/address из raw_props->>'name'.
Existing ird_analyze тесты не сломаны.

49 okn-related тестов passed, ruff clean.

Closes #1159
2026-06-13 15:02:50 +05:00
285e8f974a fix(sf): ekb_ppt_tep post-фильтры + врезка в analyze (#1136)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 2m12s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 4m34s
Deploy / deploy (push) Successful in 1m11s
Post-фильтры парсера (по образцу ppt2018_22823):
- Табл.11: отбрасываем строки без zone_name (преамбульные артефакты
  merged-cells давали 2 фантома при 12 реальных зонах).
- Табл.13: dedup по (phase, composition, zone, area_ha) + фильтры
  короткого-без-зоны и нумерационного шума (~364 строк → ~30-40 реальных).

Analyze-врезка: новый ppt_tep_lookup.parcel_ppt_tep — JOIN
planning_projects ⋈ ekb_ppt_tep по doc_ref↔source_key/doc_full_name
(best-effort, без FK). Wired в build_ird_analyze_block рядом с
planning_projects/krt_requisites — DB-источники, graceful.

Seed-URL остаётся placeholder с # VERIFY (ingest пропускает с WARNING).

Tests: 27 в parser (3 новых), 7 lookup, 22 wiring (2 новых).
All ruff/syntax green.

Closes #1136
2026-06-13 09:32:52 +00:00
5826812816 fix(domrf_kn): детерминированный sha256-fallback для flat_id (#1208)
Some checks failed
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 6s
Deploy / build-worker (push) Has been cancelled
Deploy / build-backend (push) Has been cancelled
Fallback flat_id в _norm_flat использовал abs(hash(elem)) % (2**63 - 1).
В CPython hash(str) РАНДОМИЗИРОВАН per-process (PYTHONHASHSEED нигде в
репо не зафиксирован — uvicorn/celery не выставляют его). Эффект:

- При resume упавшего sweep (resume_kn_run в новом процессе воркера) до
  10 объектов после checkpoint перечитываются. Квартиры без flatId
  получают ДРУГОЙ hash-id → ON CONFLICT (id, snapshot_date) не
  срабатывает → дубли строк одной квартиры в одном snapshot.
- То же при повторном прогоне за ту же дату — каждый раз новый id.
- Дубли инфлируют все агрегации (units_sold/price медианы, supply_layers).

Patch:
- abs(hash(elem)) → int.from_bytes(sha256(elem)[:8], "big") % (2**63 - 1).
- sha256 стабилен между процессами/перезапусками. 8 байт → BIGINT-fit.

6 новых юнит-тестов (test_domrf_kn_normalize.py): formula matches sha256,
stable across calls, distinct elems→distinct ids, flatId wins over
fallback, no-id→None, BIGINT-fit. ruff clean.

Closes #1208
2026-06-13 06:09:54 +00:00
5da4271235 feat(sf): OCR-пайплайн изъятия ЕКБ (Tesseract rus) → land_reservation (#1062)
All checks were successful
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
CI / changes (push) Successful in 6s
CI / frontend-tests (pull_request) Has been skipped
CI / backend-tests (push) Successful in 6m22s
CI / backend-tests (pull_request) Successful in 6m19s
- Dockerfile: добавлены tesseract-ocr tesseract-ocr-rus в runner apt-слой
- pyproject.toml: pymupdf>=1.24 (рендер PDF без poppler) + pytesseract>=0.3.13
- izyatie_client.py: list_izyatie_documents() + fetch_pdf() с екатеринбург.рф
- izyatie_ocr.py: ocr_pdf_text() (PyMuPDF→PIL→Tesseract rus) + extract_izyatie_records()
  с нормализацией OCR-шума (пробелы в кад-номерах, кирилл. О→0, б→6)
- izyatie_ocr_ingest.py: Celery task → land_reservation UPSERT (SAVEPOINT per-row)
- beat_schedule.py: izyatie-ocr-ingest-weekly (пятница 07:00 МСК)
- 33 теста, все зелёные; без реального Tesseract/сети в CI
2026-06-07 18:07:06 +03:00
a6e100b52a fix(sf): корректное urlencode form-data в okn_egrkn_client (#1147)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 1m29s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 2m39s
Deploy / deploy (push) Successful in 1m14s
Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
2026-06-07 14:13:34 +00:00
9ee35bebf0 fix(sf): User-Agent header for okn-mk searchMap (bypass 403) (#1146)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 1m14s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 2m30s
Deploy / deploy (push) Successful in 1m10s
Co-authored-by: bot-backend <bot-backend@gendsgn.local>
Co-committed-by: bot-backend <bot-backend@gendsgn.local>
2026-06-07 13:57:34 +00:00
50fcba1ca0 feat(sf): ingest ОКН-объектов ЕКБ из АИС ЕГРКН (точки+категория) → okn_objects (#1141)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 1m23s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 2m21s
Deploy / deploy (push) Successful in 1m15s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-06-07 12:51:18 +00:00
189ecc81f8 feat(sf): ingest функц.зон генплана ЕКБ-2045 из ГИСОГД-СО WFS → ekb_genplan_functional_zone (#1137)
All checks were successful
Deploy / build-backend (push) Successful in 1m18s
Deploy / build-frontend (push) Has been skipped
Deploy / changes (push) Successful in 5s
Deploy / build-worker (push) Successful in 2m28s
Deploy / deploy (push) Successful in 1m17s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-06-07 12:03:39 +00:00
1e53416277 feat(sf): ППТ/ПМТ ТЭП-парсер (Табл.11/12/13) → ekb_ppt_tep MVP (#1133)
All checks were successful
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Successful in 1m29s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 2m27s
Deploy / deploy (push) Successful in 1m21s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-06-07 11:54:40 +00:00
57c6d119f5 feat(sf): scraper реестра КРТ-площадок ЕКБ → ekb_krt_sites (#1126)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 2m40s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 3m22s
Deploy / deploy (push) Successful in 1m30s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-06-07 11:24:49 +00:00
59f2628e0b feat(sf): ПАГЕ-парсер изъятия/резервирования → land_reservation (#1118)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-frontend (push) Has been skipped
Deploy / build-backend (push) Successful in 2m41s
Deploy / build-worker (push) Successful in 3m25s
Deploy / deploy (push) Successful in 1m25s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-06-07 10:15:03 +00:00
0567ad2130 feat(22d): domrf_catalog_object scraper — fill ~25 NULL kn_objects cols from SSR __NEXT_DATA__ (#335)
Some checks failed
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Successful in 1m43s
Deploy / build-frontend (push) Has been skipped
Deploy / build-worker (push) Successful in 2m49s
Deploy / deploy (push) Failing after 44s
2026-05-17 21:26:22 +00:00