gendesign/tradein-mvp/backend/tests
Light1YT 4a4a6e8727 feat(rbac): сузить pilot scope только до /trade-in/**
Decision 2026-05-26: pilot аккаунты пилот-программы получают доступ
ТОЛЬКО к разделу Trade-In (оценка вторички). Landing, Analytics,
Site Finder, Concept — admin-only.

Изменения:
- `auth/roles.yaml` — `pilot.paths` сужен с 7 путей до 2:
  `/trade-in/**` + `/trade-in/api/v1/**`. Deny список оставлен
  как есть для defense-in-depth.
- `backend/tests/test_rbac.py` + tradein mirror — переписан
  `test_is_path_allowed_pilot_excludes_admin` → `_pilot_only_tradein`:
  pilot allowed только /trade-in, denied на /, /analytics, /site-finder,
  /concept, /api/v1/parcels. Тест `test_get_user_scope_pilot` ассертит
  что /trade-in/** в allowed, / и /analytics/** нет.
- `frontend/src/lib/__tests__/isPathAllowed.test.ts` — те же parity
  обновления (pilot allowed list сужен, denied list расширен landing
  + non-tradein путями).
- `caddy/users.caddy.snippet` — синхронизирован с VPS-актуальной
  версией: regen'd user1..user10 hashes + admintest/pilottest entries
  (locally added на VPS 2026-05-26 для QA RBAC). Без этого `deploy.yml`
  делал бы `git reset --hard` и стирал бы локальные правки.
- `auth/roles.yaml` users: блок — также добавлены `admintest: admin`
  и `pilottest: pilot` (mirror VPS local edit).

Эффект для UX:
- pilot открывает `/` → frontend RouteGuard → fullscreen «Доступа нет»
  (т.к. `/` не в allowed_paths).
- pilot TopNav на main frontend — только пункт «Trade-In» виден
  (остальные `/analytics`, `/site-finder`, `/concept`, `/admin`
  отфильтрованы `isPathAllowed`).
- pilot открывает `/trade-in` → работает как раньше.
- admin (admintest, kopylov-если бы был admin) — без изменений.

Backend middleware path-enforcement не делает — security guarantee
по-прежнему на admin-only endpoints (`/api/v1/admin/*` блочится для
пилота). Path-filter на UI-уровне через `allowed_paths` /
`deny_paths` в /me response.

Pilot login flow: после basic_auth → main frontend → useMe → /me →
scope (allowed=/trade-in/**). RouteGuard на `/` → NoAccessScreen.
Pilot должен bookmark'ить `https://gendsgn.ru/trade-in/` напрямую.

Follow-up: можно добавить auto-redirect в RouteGuard — если pilot
landing-path → redirect на первый allowed (`/trade-in`). Отдельный PR.

Tests: 20/20 pass на обоих backend стэках, ruff clean.
2026-05-26 12:40:08 +05:00
..
fixtures feat(tradein): Phase 1 of #582 — address mismatch audit infrastructure 2026-05-25 12:50:30 +05:00
matching feat(tradein): conflict_resolution — register Yandex sources in priority dicts (#471) 2026-05-23 14:03:35 +00:00
scrapers fix(tradein/avito): anti-bot hardening — sleep + abort + shared session (#487) 2026-05-23 20:08:40 +00:00
services feat(tradein): postgres_fdw live read of gendesign.cad_buildings (replaces snapshot) (#493) 2026-05-24 08:57:30 +00:00
tasks fix(tradein): geocode backfill + remove Avito exclusion from estimator (#490) 2026-05-23 20:03:48 +00:00
__init__.py feat(tradein): avito_imv.py — Avito IMV evaluation API client (2 requests) (#444) 2026-05-23 12:16:47 +00:00
test_api_avito_stage4a.py feat(tradein): Stage 4a — API endpoints for Avito enrichment + IMV benchmark UI (#460) 2026-05-23 13:34:38 +00:00
test_audit_address_mismatch.py feat(tradein): Phase 1 of #582 — address mismatch audit infrastructure 2026-05-25 12:50:30 +05:00
test_avito_address_clean.py fix(tradein-avito): strip Emotion CSS from listings.address (#502) 2026-05-24 10:52:50 +00:00
test_avito_detail_parse.py feat(tradein): avito_detail.py — detail page parser (30+ fields incl. domoteka) (#443) 2026-05-23 12:17:15 +00:00
test_avito_houses_parse.py feat(tradein): avito_houses.py — Houses Catalog parser (state + reviews + history + recs) (#449) 2026-05-23 12:37:24 +00:00
test_avito_imv_parse.py feat(tradein): avito_imv.py — Avito IMV evaluation API client (2 requests) (#444) 2026-05-23 12:16:47 +00:00
test_avito_relative_date.py feat(tradein-scrapers): parse listing_date from Avito + Yandex (#508) 2026-05-24 11:17:13 +00:00
test_base_save_listings.py feat(tradein): extend base.py save_listings to persist Cian-specific columns (PR #450 follow-up) (#455) 2026-05-23 13:05:20 +00:00
test_cian_detail.py feat(tradein): cian_session cookies management + admin endpoints (Wave 4 Worker A) (#457) 2026-05-23 13:22:00 +00:00
test_cian_newbuilding.py feat(tradein): cian_newbuilding.py — ЖК catalog scraper (chart + reliability + offers, Wave 4 Worker C) (#459) 2026-05-23 13:23:11 +00:00
test_cian_serp_scraper.py feat(tradein): cian.py SERP refactor — state-based extraction (137 fields, no jitter) (#450) 2026-05-23 12:52:04 +00:00
test_cian_session.py fix(tradein): CIAN_REQUIRED_COOKIES — add real auth cookies (DMIR_AUTH + Cian session) (#480) 2026-05-23 14:52:24 +00:00
test_cian_state_parser.py feat(tradein): cian_state_parser shared utility + ScrapedLot Cian fields (#447) 2026-05-23 12:35:01 +00:00
test_cian_valuation.py feat(tradein): cian_valuation.py — auth-required Calculator scraper + 24h cache (#465) 2026-05-23 13:43:34 +00:00
test_city_sweep.py feat(tradein): city sweep — auto ЕКБ pipeline (#477) 2026-05-23 14:38:07 +00:00
test_estimator_cian_integration.py fix(tradein): filter ДКП-only in rosreestr importer + re-enable deals (#549) 2026-05-24 19:42:28 +00:00
test_estimator_cohort.py fix(tradein-estimator): extend cohort filter to Tier S + Tier H, fix late_soviet overlap (#522) 2026-05-24 13:14:59 +00:00
test_estimator_floor_optional.py feat(tradein): этаж/этажность optional + best test presets по deal count (#558) 2026-05-24 21:44:44 +00:00
test_estimator_imv_integration.py feat(tradein): integrate Avito IMV as 5th evaluation source (on-demand cached) (#452) 2026-05-23 13:08:22 +00:00
test_estimator_source_quota.py feat(tradein): source-quota in estimator analogs (fix Cian/Yandex starvation) (#491) 2026-05-23 20:59:58 +00:00
test_estimator_yandex_integration.py feat(yandex-valuation): link history rows to houses via match_or_create_house (#531) 2026-05-24 14:28:30 +00:00
test_extract_short_addr.py feat(tradein-estimator): tiered house-match S→H→W (#507) 2026-05-24 12:41:12 +00:00
test_matching.py fix(tradein-matching): pg_advisory_xact_lock to prevent duplicate house INSERTs (#501) 2026-05-24 10:52:10 +00:00
test_rbac.py feat(rbac): сузить pilot scope только до /trade-in/** 2026-05-26 12:40:08 +05:00
test_scheduler.py feat(tradein): in-app scheduler — UI-managed schedule (replaces SSH crontab) (#482) 2026-05-23 14:54:25 +00:00
test_scrape_pipeline.py feat(tradein): scrape_pipeline.py — Avito full orchestrator (search → houses → detail) (#451) 2026-05-23 12:55:13 +00:00
test_scraper_settings.py feat(tradein): global scraper delay setting (applies across all scrapers) (#485) 2026-05-23 15:43:28 +00:00
test_search_api.py feat(tradein): Phase 3.2 — /api/v1/search endpoint + Redis cache (#479) 2026-05-23 14:44:22 +00:00
test_street_deals_endpoint.py fix(tradein): extract_street_name handles Nominatim reverse format (#557) 2026-05-24 21:03:42 +00:00
test_yandex_detail.py feat(tradein): yandex_detail.py — Product JSON-LD + DOM detail parser (#466) 2026-05-23 13:45:09 +00:00
test_yandex_helpers.py feat(tradein): yandex_helpers.py — JSON-LD + regex + date + NLP + money helpers (#456) 2026-05-23 13:14:11 +00:00
test_yandex_newbuilding.py feat(tradein): yandex_newbuilding.py — ЖК landing parser (149 selectors + NLP) (#467) 2026-05-23 13:46:45 +00:00
test_yandex_realty_serp.py feat(tradein): yandex_realty.py — DOM SERP refactor (vtorichka, 23 cards/page) 2026-05-23 16:21:47 +03:00
test_yandex_scrapers_delay_wiring.py feat(tradein): scraper_settings live-config + Yandex admin trigger endpoints (#484) 2026-05-23 15:28:34 +00:00
test_yandex_valuation.py fix(yandex-valuation): off-by-one cell index in _parse_row_cells (#552) 2026-05-24 19:57:17 +00:00
test_yandex_valuation_save.py feat(yandex-valuation): link history rows to houses via match_or_create_house (#531) 2026-05-24 14:28:30 +00:00