Commit graph

40 commits

Author SHA1 Message Date
bd3e5c8216 feat(tradein): аккаунт praktika + лимит 15 оценок/мес, чистка PRINZIP в UI (#635)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy Trade-In / changes (push) Successful in 7s
Deploy / build-backend (push) Successful in 29s
Deploy / build-frontend (push) Successful in 28s
Deploy / build-worker (push) Successful in 29s
Deploy Trade-In / build-backend (push) Successful in 46s
Deploy / deploy (push) Successful in 58s
Deploy Trade-In / build-frontend (push) Successful in 1m40s
Deploy Trade-In / deploy (push) Successful in 39s
2026-05-28 22:04:58 +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
b0c03942be feat(tradein): tier badge на DealsCard rows (#603)
All checks were successful
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m38s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / deploy (push) Successful in 38s
2026-05-27 13:15:49 +00:00
63756c3c29 feat(tradein): StreetDealsCard с paired listings (PR L, #564 Phase 2) (#599)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Successful in 1m38s
Deploy Trade-In / deploy (push) Successful in 35s
Deploy Trade-In / build-backend (push) Has been skipped
2026-05-27 12:29:06 +00:00
42ab74e2e8 feat(tradein): MapPicker snap marker — Phase 5 of #582 (#594)
All checks were successful
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
56a7a36c9a feat(auth): UserMenu — личный кабинет top-right (PR D) (#590)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m45s
Deploy Trade-In / deploy (push) Successful in 38s
Deploy / build-frontend (push) Successful in 3m0s
Deploy / deploy (push) Successful in 58s
2026-05-26 10:48:57 +00:00
7a2b055b35 feat(rbac): frontend route-guard + nav filter (#586)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m42s
Deploy Trade-In / deploy (push) Successful in 39s
Deploy / build-frontend (push) Successful in 2m55s
Deploy / deploy (push) Successful in 1m1s
PR B (frontend) to backend RBAC #585. RouteGuard wraps app, NoAccessScreen on 403 from /me, TopNav filtered by role.
2026-05-26 06:51:45 +00:00
dcf5e32aa1 fix(tradein): убрать «PRINZIP» wordmark из шапки
Оставляем TI-логотип и «Trade-In» рядом. PRINZIP-брендинг скрыт — для
текущего демо/пилота он не нужен. Когда понадобится white-label под
конкретного заказчика, вернём через `brand-name` slot.

Найдено пользователем в шапке gendsgn.ru/trade-in.
2026-05-25 13:28:48 +05:00
33c4c84467 feat(tradein): этаж/этажность optional + best test presets по deal count (#558)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 44s
Deploy Trade-In / build-frontend (push) Successful in 1m53s
Deploy Trade-In / deploy (push) Successful in 44s
2026-05-24 21:44:44 +00:00
4d1c409e18 feat(tradein): «По вашей улице» — StreetDealsCard на real ДКП-сделки Росреестра (#556)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m35s
Deploy Trade-In / deploy (push) Successful in 40s
2026-05-24 20:37:29 +00:00
lekss361
0ac54d1de0 feat(tradein): sell-time sensitivity block (4 цены × медиана срока продажи)
Backend: GET /api/v1/trade-in/estimate/{id}/sell-time-sensitivity
- 4 фиксированных бакета по premium к медиане года: −5% / медиана (±3%) / +5% / +10%
- Median exposure_days + p25/p75 per bucket
- Filter outliers: last_price > start_price * 0.7 (отбрасываем подозрительно дешёвые)
- Benchmark: median ₽/м² за последние 2 года

Frontend: новый SellTimeSensitivity component (4-card grid)
- color-coded buckets (green→blue→yellow→red)
- median highlighted синей рамкой
- показывает "~31 дн" + "обычно 31-61 дн" + count лотов
- встроен в HouseAnalyticsSection между KpiRow и PriceHistoryChart

Использует существующий house_placement_history (15k+ rows).
2026-05-24 22:43:32 +03:00
5bfacd51b0 feat(tradein): «Росреестр» button — copy address + open EGRN request form (#550)
Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 6s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
2026-05-24 19:42:09 +00:00
967e7185ca feat(tradein): cian price-change badges + split chart Avito/Yandex (#547)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 42s
Deploy Trade-In / build-frontend (push) Successful in 1m36s
Deploy Trade-In / deploy (push) Successful in 45s
2026-05-24 18:24:00 +00:00
80850a591e feat(tradein): house analytics section (chart + KPI + sold list) (#546)
All checks were successful
Deploy Trade-In / build-backend (push) Successful in 43s
Deploy Trade-In / changes (push) Successful in 6s
Deploy Trade-In / build-frontend (push) Successful in 2m34s
Deploy Trade-In / deploy (push) Successful in 39s
2026-05-24 18:09:45 +00:00
08cf615ad7 feat(tradein/cian): surface valuation chart + rent + change-pct on /trade-in (#530)
Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 48s
Deploy Trade-In / build-frontend (push) Has been cancelled
2026-05-24 14:32:54 +00:00
f2f9e5b79b feat(tradein-ui): placement history card (#529)
Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / build-frontend (push) Has been cancelled
Deploy Trade-In / changes (push) Successful in 6s
Deploy Trade-In / build-backend (push) Has been skipped
2026-05-24 14:22:16 +00:00
591039493c feat(tradein/cian): admin endpoints + UI for detail+newbuilding history scrape (#525)
All checks were successful
Deploy Trade-In / build-backend (push) Successful in 58s
Deploy Trade-In / build-frontend (push) Successful in 1m37s
Deploy Trade-In / deploy (push) Successful in 1m45s
Deploy Trade-In / changes (push) Successful in 6s
2026-05-24 14:05:55 +00:00
92d00ec874 feat(tradein-ui): mock-disclaimer + progressive enrichment + UX polish (#517)
All checks were successful
Deploy Trade-In / build-frontend (push) Successful in 1m42s
Deploy Trade-In / deploy (push) Successful in 35s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
2026-05-24 12:58:39 +00:00
3190bbec54 fix(tradein-frontend): MapPicker focus trap + Leaflet SRI, PhotoUpload size check (#514)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m26s
Deploy Trade-In / deploy (push) Successful in 32s
2026-05-24 12:01:17 +00:00
3665a61e48 fix(tradein-frontend): safeUrl validator, apiFetch dedup, ListingsCard a11y, error boundary (#512)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m24s
Deploy Trade-In / deploy (push) Successful in 32s
2026-05-24 11:47:38 +00:00
726e774a7f feat(tradein-ui): Yandex admin scraper page — mirror Avito + global delay control (#488)
Some checks failed
Deploy Trade-In / deploy (push) Blocked by required conditions
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Has been cancelled
Replaces 5-line stub at /scrapers/yandex with full admin page mirroring Avito. 5 sections: global delay (umbrella yandex key), search around, detail snapshot, JK newbuilding, valuation. TanStack Query hooks + apiFetch, TS strict, reuses trade-in.css.

Fixup: useScraperSettings unwraps {settings:[...]} response wrapper; PUT body includes required source field (matches backend Pydantic ScraperSettingPayload). useEffect race guarded with initializedRef so 30s refetch doesn't clobber user input mid-edit.

Verdict: APPROVE — deep-code-reviewer (response shape unwrap + source field both applied).
2026-05-23 20:07:48 +00:00
ffb0c67c84 fix(tradein-ui): double /trade-in/ prefix in Cian page Link (PR #486 follow-up) (#489)
All checks were successful
Deploy Trade-In / build-frontend (push) Successful in 1m23s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 23s
2026-05-23 15:56:01 +00:00
ebfd29a0a6 feat(tradein-ui): Cian scraper admin page + global request delay control (#486)
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m21s
Deploy Trade-In / deploy (push) Successful in 24s
2026-05-23 15:36:07 +00:00
65029cd1a7 feat(tradein-ui): Cian cookies upload admin page (#481)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m22s
Deploy Trade-In / deploy (push) Successful in 23s
2026-05-23 15:19:42 +00:00
fd3cb4e6ed feat(tradein): /scrapers/avito — 6-я секция Расписание (in-app scheduler UI) (#483)
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Successful in 1m22s
Deploy Trade-In / deploy (push) Successful in 23s
Deploy Trade-In / build-backend (push) Has been skipped
2026-05-23 14:55:31 +00:00
dd24bd8136 feat(tradein): /scrapers/avito — 5-я секция City sweep (auto + cancel + runs list) (#478)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m22s
Deploy Trade-In / deploy (push) Successful in 23s
2026-05-23 14:40:11 +00:00
649034479f feat(tradein): Stage 4c — scrapers admin pages (Avito real + Cian/Yandex stubs) (#472)
All checks were successful
Deploy Trade-In / build-frontend (push) Successful in 1m23s
Deploy Trade-In / deploy (push) Successful in 22s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
2026-05-23 14:05:56 +00:00
72d2b97ee0 feat(tradein): Stage 4b — IMV benchmark badge + house info card on estimate result (#461)
All checks were successful
Deploy Trade-In / deploy (push) Successful in 21s
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m21s
2026-05-23 13:28:23 +00:00
9b2a54788b fix(tradein): восстановленная оценка показывает этаж/площадь, не 0/0
AggregatedEstimate не нёс параметры целевой квартиры (площадь, этаж,
комнаты, год, тип дома). HeroSummary брал их из формы-инпута — у
свежей оценки работало, но при открытии оценки по ссылке (?id=, из
Истории) формы нет → «Сводка» показывала «ЭТАЖ 0/0, Площадь 0 м²».

Параметры теперь проходят сквозь весь стек:
- AggregatedEstimate + TS-тип получили area_m2/rooms/floor/
  total_floors/year_built/house_type/repair_state/has_balcony;
- estimate_quality заполняет их из payload, get_estimate — из строки
  trade_in_estimates (колонки там уже есть);
- HeroSummary читает из estimate с откатом на input.

Заодно в TS-тип добавлен пропущенный est_days_on_market.
2026-05-22 15:50:19 +05:00
6041ac8464 fix(tradein): фото аналога в Сводке больше не скрыто плейсхолдером
В .hero-photo псевдоэлементы ::before/::after рисуют декоративный
скелет-плейсхолдер «фасада дома». Они position:absolute, а <img> с
фото аналога — position:static, поэтому абсолютные псевдоэлементы
рисовались ПОВЕРХ картинки: реальное фото загружалось (naturalWidth
есть), но визуально всегда был серый плейсхолдер.

Фото (z-index 1) и подпись .photo-meta (z-index 2) теперь над
скелетом. Скелет остаётся виден, когда фото нет или оно не
загрузилось (onError → display:none).
2026-05-22 15:35:01 +05:00
14c81dd5ac fix(tradein): N1.ru — честный статус источника вместо хардкод-timeout
SourcesProgress хардкодил N1.ru как error («timeout — нет ответа»)
при готовой оценке — строка никогда не сверялась с sources_used.
Но N1 — реальный рабочий источник (224 объявления на проде), и при
вкладе в оценку он показывался красным крестом-ошибкой.

Теперь строка N1 ведёт себя как cian/avito/yandex: done + счётчик
лотов, если источник в sources_used, иначе loading/idle.
2026-05-22 14:16:30 +05:00
TradeIn Deploy
d456e4fecb feat(tradein): выбор адреса на карте ЕКБ (#415)
Кнопка справа от поля адреса → модалка с картой Екатеринбурга.
Клик по дому → reverse-геокодинг → адрес подставляется в форму.

- geocoder.reverse_geocode + GET /api/v1/geocode/reverse — Nominatim
  /reverse (координаты → адрес).
- MapPicker.tsx — модалка с Leaflet + OSM-тайлами (Leaflet с CDN,
  без npm-зависимости), circleMarker по клику.
- EstimateForm — кнопка-карта справа от AddressInput.

Карта на OSM (без API-ключа). При появлении ключа Yandex (#402)
можно перейти на Я.Карты.

Closes #415
2026-05-22 12:09:35 +05:00
TradeIn Deploy
1941c3d7df fix(tradein): фото аналога в Сводке + честный статус источников
UI-баги, замеченные при обзоре результата оценки:

- HeroSummary: блок hero-photo был пустым серым плейсхолдером (в
  макете там фото, в коде слот не подключён). Теперь показывает фото
  первого аналога с картинкой; onError → fallback на плейсхолдер.

- SourcesProgress: источники без данных после завершения оценки
  оставались в статусе idle с подписью «ожидает запрос» — выглядело
  как зависший запрос. Теперь после готовности → «нет данных»
  (терминальный статус).
2026-05-22 12:02:56 +05:00
TradeIn Deploy
abafb60120 feat(tradein): рабочие страницы История и Кэш (#399)
Заглушки навбара (href=#) → рабочие страницы.

- GET /api/v1/trade-in/history — последние оценки из trade_in_estimates.
- GET /api/v1/trade-in/cache-stats — счётчики данных/кэшей.
- app/history/page.tsx — таблица прошлых оценок, ссылки на отчёты.
- app/cache/page.tsx — состояние данных (объявления, сделки, кадастр,
  кэш геокодера, последний парсинг).
- navbar — ссылки История / Кэш ведут на страницы.

Closes #399
2026-05-22 11:28:27 +05:00
TradeIn Deploy
48ccbdafc8 feat(tradein): CRM-поля в форме оценки (#395)
Доп. поля для трейд-ин менеджера: тип собственности, ипотека/
обременение, имя и телефон клиента. На расчёт оценки не влияют —
сохраняются в trade_in_estimates вместе с записью.

- data/sql/008_crm_fields.sql — 4 колонки в trade_in_estimates.
- TradeInEstimateInput + estimator INSERT — приём и сохранение.
- EstimateForm — секция «CRM — для менеджера» (4 поля).

Closes #395
2026-05-22 11:15:15 +05:00
TradeIn Deploy
0a1df4d13a feat(tradein): фронтенд загрузки фото квартиры (#394)
Компонент PhotoUpload на result-view: выбор image/* (multiple),
загрузка в POST /estimate/{id}/photos, превью загруженных фото.
Multipart напрямую через fetch — apiFetch форсит JSON content-type.

Closes #394
2026-05-22 11:10:50 +05:00
lekss361
aeb895a9dc fix(tradein): PDF-ссылка через API_BASE_URL (basePath)
href Скачать PDF был /api/v1/... без префикса /trade-in → попадал в
main gendesign backend (404). Та же причина что #373 для apiFetch.
2026-05-21 10:15:44 +03:00
lekss361
a17a73af71 fix(tradein): префиксить API_BASE_URL через basePath
Без префикса /trade-in клиентский fetch шёл на gendsgn.ru/api/v1/...
который Caddy маршрутизировал в main gendesign backend (не tradein).
Теперь NEXT_PUBLIC_API_BASE_URL fallback на NEXT_PUBLIC_BASE_PATH —
build с BASE_PATH=/trade-in корректно префиксит запросы.
2026-05-21 01:13:46 +03:00
lekss361
5082f50d53 fix(tradein): убрать basePath redirect-loop
Под basePath=/trade-in next.config redirects() + app/page.tsx с
redirect(/trade-in) делали /trade-in/ → /trade-in/trade-in (двойной
префикс basePath) → пустая страница / 404.

- Перенёс контент app/trade-in/page.tsx → app/page.tsx (теперь корень
  Next = /trade-in/ snaружи)
- Удалил app/trade-in/ как избыточный
- Удалил redirects() блок из next.config.ts
- router.replace("/?id=...") вместо "/trade-in?id=..." — basePath
  префиксит автоматически
2026-05-21 01:05:49 +03:00
lekss361
02267d0306 feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in)
- FastAPI backend: PostGIS estimator + 3 scrapers (Avito/Cian/Yandex)
- Next.js 15 frontend: tradein.html mockup design, basePath=/trade-in
- WeasyPrint PDF (Брусника-style 4-page report)
- Address autocomplete с typo-tolerance + 6 EKB presets
- Изолированный docker stack gendesign-tradein (отдельная postgres БД)
- Caddy inline routes: gendsgn.ru/trade-in/* и /trade-in/api/v1/*
- Forgejo Actions: .forgejo/workflows/deploy-tradein.yml (shell-based GHCR login)
- Триггер только по paths: tradein-mvp/** (не пересекается с deploy.yml)
- Образы: ghcr.io/lekss361/gendesign-tradein-{backend,frontend}:latest

Первый запуск на сервере (вручную, один раз):
  - создать /opt/gendesign/tradein-mvp/.env.runtime (postgres pwd, contact email)
  - docker network create gendesign_shared (если нет)
  - docker compose -p gendesign-tradein up -d
  - docker compose -p gendesign exec caddy caddy reload
2026-05-21 00:25:39 +03:00