50684ce87e
fix(tradein/estimator): remove dead tier-aware-ratio path — truncation artifact + footgun ( #2002 )
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m25s
Deploy Trade-In / deploy (push) Successful in 49s
Deploy Trade-In / build-backend (push) Successful in 53s
2026-06-27 17:34:54 +00:00
91b04a1851
test(tradein): patch _geoportal_house_match in cadastral-before-yandex test
...
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
#1786 merged before the test fix landed → main red on
test_geocode_uses_cadastral_before_yandex. The new geoportal house-match
tier runs first in geocode(); this legacy cadastral test must mock it to
None so it exercises the cadastral forward path (else the MagicMock db row
leaks through the new tier as lat=1.0).
2026-06-19 18:06:28 +03:00
c2a1dc8aeb
fix(tradein): parse street+house for cadastral geocode match (resolve ~60% of failing addresses from local DB)
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
2026-06-19 14:04:12 +03:00
b0fe292a63
fix(tradein): working cian ЖК-url resolver via cat.php SERP ( #972 )
...
CI / changes (push) Successful in 6s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 5s
Deploy Trade-In / test (push) Successful in 31s
Deploy Trade-In / build-backend (push) Successful in 1m20s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 46s
The legacy resolve_cian_zhk_url hit /zhk/<id>/ which now 404s, leaving the
318 geo-matched cian houses (house_sources.ext_id set, cian_zhk_url NULL)
unfetchable -> the newbuilding-enrichment backfill matched 0 houses.
Add resolve_cian_zhk_url_via_search(nb_id): fetch the cat.php newbuilding SERP
and extract the canonical zhk-<slug>.cian.ru url, ANCHORED on the
<h1 data-name="Title"> header anchor (NOT naive first-match — the SERP carries
promo/recommendation zhk-* links before the title that would otherwise resolve
the wrong ЖК and silently corrupt enrichment). Validated against the real
2.81MB prod SERP + an adversarial poisoned-recommendation test.
Wire into newbuilding_enrich_backfill: broaden selection to "has ext_id OR
cian_zhk_url", resolve+persist the url under a SAVEPOINT before enriching,
rate-limited + resumable + idempotent. Keep the old resolver (deprecated).
Bounded prod proof (5 houses, direct): 5/5 urls resolved+persisted, 3/5 fully
enriched (+18 price_dynamics, +3 reliability); the 2 misses were direct-mode
anti-bot on the 2nd fetch. Full 318-run gated on the cian mobile proxy
(mproxy.site) being restored. code-reviewer APPROVE (SQL/idempotency) +
resolver hardened against wrong-ЖК. 19 tests green.
Refs #972 .
2026-06-08 11:13:06 +05:00
571980c56e
feat(tradein): ppm²-tier segmentation of asking→sold ratio ( #928 , flag OFF) ( #934 )
...
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 31s
Deploy Trade-In / build-backend (push) Successful in 44s
Deploy Trade-In / deploy (push) Successful in 36s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-05-31 21:22:39 +00:00
3bd107f923
test(tradein): fix #794 test regressions on main (broken by #919 early squash-merge) ( #921 )
...
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 33s
Deploy Trade-In / build-backend (push) Successful in 45s
Deploy Trade-In / deploy (push) Successful in 45s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-05-31 19:05:10 +00:00
4999c877ae
feat(tradein): СберИндекс time-adjust for frozen Rosreestr ДКП + per-dashboard filter fix ( #794 ) ( #919 )
...
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / deploy (push) Has been skipped
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Failing after 33s
Co-authored-by: lekss361 <lekss361@gendsgn.local>
Co-committed-by: lekss361 <lekss361@gendsgn.local>
2026-05-31 18:48:22 +00:00
870f062587
feat(tradein): expected-sold price in estimate PDF ( #648 S5b — final) ( #665 )
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 43s
Deploy Trade-In / deploy (push) Successful in 35s
2026-05-29 14:09:46 +00:00
492dd0aba6
feat(tradein): бейдж точности адреса (qc_geo) на карточке оценки (accuracy #1 )
...
Честность к пользователю: показываем насколько точно определён адрес —
«до дома» / «до улицы» / «приблизительно» — рядом с confidence.
- schemas/trade_in.py: address_precision: Literal["house","street","approximate"]|None
- estimator.py: _qc_geo_to_precision (qc_geo 0→house, 1→street, ≥2→approximate,
None→None), set в основном return + _empty_estimate
- api/v1/trade_in.py: get_estimate + estimate_pdf теперь rehydrate'ят DaData-поля
(canonical_address, house_cadnum, house_fias_id, address_precision, metro_nearest)
из row — раньше на ?id= reopen / в PDF вся Q1-обогащёнка пропадала (поймал
code-reviewer). Колонки уже persisted, фикс read-path.
- frontend: AddressPrecision type + precision-badge в HeroSummary (.card-meta),
токены --success/--accent-2/--bg-card-alt, без новых токенов.
Канон: tech-analyst (план) → backend-engineer + frontend-engineer → code-reviewer
(✅ APPROVE, поймал reopen-path gap) → fold-in fix. Tests: 7 passed, tsc clean, ruff clean.
match_house_readonly wiring отложен (fast-follow).
2026-05-28 15:37:33 +05:00
386fa8c0e3
feat(tradein): DaData /suggest tier в /suggest endpoint (PR Q2)
...
Yandex Suggest заблокирован (демо 1k/день исчерпан) — DaData /suggest/address
(10k/день free, token-only auth, лучшее покрытие РФ) заменяет его как Tier 2
после Cadastral FDW. Yandex остаётся как Tier 3 fallback.
- app/services/dadata.py: DadataSuggestion dataclass + async suggest_addresses()
(token-only, без X-Secret; graceful [] на все ошибки; 5s timeout;
classifies fias_level→kind: 8=house, 7=street, ≤6=city; count clamp ≤20)
- app/services/geocoder.py: _dadata_suggest() обёртка, дропает entries без
координат; suggest() теперь Cadastral → DaData → Yandex → Nominatim
- tests/services/test_dadata.py: 15 новых unit-тестов (happy + все error paths)
- tests/services/test_cadastral_reverse.py: +тест DaData до Yandex, update
fallback теста под новый tier chain
Tests: 62 passed (35 dadata + 20 cadastral reverse + 7 geocode reverse api).
Ruff clean. Reuse DADATA_API_TOKEN from PR Q1 (#604 ) — secret не нужен для suggest.
2026-05-27 19:08:58 +05:00
a7fa1a4ffa
feat(tradein): DaData on-demand enrichment в estimate flow (PR Q1)
...
Добавляет app/services/dadata.py — async client для DaData /clean/address,
обогащающий target адрес canonical-формой, kadastr_num, ФИАС, координатами
и ближайшим метро. Migration 069 расширяет trade_in_estimates 6 nullable
колонками; estimator.estimate_quality вызывает service после geocode и
сохраняет результат в основной INSERT. AggregatedEstimate отдаёт
canonical_address / house_cadnum / house_fias_id / metro_nearest наружу.
Service graceful: пустые credentials / quota 429 / 5xx / network fail → None,
estimator продолжает работу. Demo tier 100 req/день — хватит для low-traffic
prod и тестов. ENV: DADATA_API_TOKEN, DADATA_API_SECRET.
Tests: 20 unit-тестов через httpx.MockTransport, zero real DaData calls.
Покрыто: happy path, отсутствие creds, короткий адрес, timeout/network,
HTTP 429/401/403/500/502/503, пустой массив, malformed shape, partial
payload, coerce строковых qc-кодов в int, проверка request body+headers.
Закладывает базу для PR Q2 (frontend DaData Suggest, 10k/день free) и
PR Q3 (backfill 339 NULL-coords houses) — обе используют тот же сервис.
2026-05-27 18:50:12 +05:00
42ab74e2e8
feat(tradein): MapPicker snap marker — Phase 5 of #582 ( #594 )
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 48s
Deploy Trade-In / build-frontend (push) Successful in 1m44s
Deploy Trade-In / deploy (push) Successful in 39s
2026-05-27 09:30:17 +00:00
1ce9e10012
feat(tradein): persistent infra для backfill scripts (PR F) ( #592 )
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 46s
Deploy Trade-In / build-backend (push) Successful in 1m38s
Deploy Trade-In / deploy (push) Successful in 42s
2026-05-27 06:59:54 +00:00
94cf199276
feat(tradein): postgres_fdw live read of gendesign.cad_buildings (replaces snapshot) ( #493 )
...
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 26s
Deploy Trade-In / build-backend (push) Successful in 47s
Deploy / build-frontend (push) Successful in 29s
Deploy / build-backend (push) Successful in 1m24s
Deploy Trade-In / deploy (push) Successful in 40s
Deploy / build-worker (push) Successful in 2m57s
Deploy / deploy (push) Failing after 37s
Replaces tradein.cad_buildings snapshot with live postgres_fdw foreign table reading gendesign.v_tradein_cad_buildings. Fixes /trade-in/api/v1/geocode/reverse 500 (Nominatim ban) and address_not_geocoded for cadastre addresses (e.g. Хохрякова 81).
Security (deep-review fixes):
- 100_tradein_fdw_role.sql: passwordless CREATE ROLE; password set by deploy.yml ALTER ROLE bootstrap reading GENDESIGN_FDW_PASSWORD from backend/.env.runtime (via psql :'pw' var → format %L — injection-safe).
- core/fdw.py: regex whitelist [A-Za-z0-9_-]{32,256} on password, ValueError without echoing value, try/rollback on commit.
- 060_postgres_fdw_extension.sql: connect_timeout='3' on FOREIGN SERVER + ALTER ADD/SET fallback.
- geocoder.py: _cadastral_forward_sync / _cadastral_reverse_sync wrapped in asyncio.to_thread.
- 100_*.sql: REVOKE ALL ON ALL TABLES/SEQUENCES/FUNCTIONS IN SCHEMA public; only GRANT SELECT on v_tradein_cad_buildings.
- pg_user_mappings query handles PUBLIC mapping (usename IS NULL).
Tests: 3 SQL-injection guards on ensure_fdw_user_mapping + rewritten cadastral suite.
2026-05-24 08:57:30 +00:00
0efd2dca1d
feat(tradein): cadastral reverse geocode via main backend cad_buildings ( #492 )
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 25s
Deploy Trade-In / build-backend (push) Successful in 47s
Deploy / build-frontend (push) Successful in 29s
Deploy / build-backend (push) Successful in 1m25s
Deploy Trade-In / deploy (push) Successful in 37s
Deploy / build-worker (push) Successful in 2m29s
Deploy / deploy (push) Successful in 1m2s
2026-05-24 07:31:12 +00:00