Commit graph

16 commits

Author SHA1 Message Date
5d6895127b fix(site-finder): invest-score advisory flag + velocity data-honesty + h1 a11y (#1926)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (pull_request) Successful in 1m14s
CI / openapi-codegen-check (pull_request) Successful in 2m12s
CI / backend-tests (pull_request) Successful in 14m24s
Остаток аудита #1871 (#1926), тема data-honesty #1953.

- invest_score: machine-readable score_is_advisory + score_advisory
  {kind=poi_density_heuristic, scale_min/scale_max=SCORE_MAX_REFERENCE} в
  analyze-payload + AnalyzeResponse (optional, backward-compat) + регенерён
  api-types.ts. Явно помечает score как POI-эвристику, не абсолютный рейтинг.
- velocity (Section3 VelocityBlock): явный провенанс объёма — бейдж
  «Источник: Objective» + видимый --warn-soft caveat когда объём по прокси/
  кад.кварталу, а не прямые продажи Objective. Поля провенанса уже доходили.
- a11y: <h1> во всех состояниях страницы анализа (был только в success).
- cleanup: удалён неиспользуемый export confidenceLevelToValue (latent risk).

units_sold-пункт #1926 закрыт ранее (#2054 inline _SOLD_COUNT_SQL).
2026-06-29 11:27:02 +05:00
e809063ca3 feat(site-finder): add «7. Концепция» section to light analysis report
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 58s
CI / openapi-codegen-check (pull_request) Successful in 1m58s
Fold the generative concept generator (3 strategy variants: placement map +
ТЭП + finance) into the light analysis report (/site-finder/analysis/{cad}) as
a new section after «6. Прогноз», so Концепция lives in one place alongside the
report instead of a separate flow (epic #1953, #1965 Stage 1).

Frontend-only: reuses ConceptParamsForm / ConceptVariantsResult and the
/concepts mutation (useCreateConcept) as-is — no duplication, no backend change.
Inputs are seeded from the analysis the report already has (no re-entry of the
cadastre/polygon): polygon ← extractPolygon(geom_geojson); housing_class /
development_type ← financial_estimate inferred values; land_cost ←
egrn.cadastral_value_rub; falls back to comfort/mid_rise.

Runs on demand (heavy generative call — never auto on mount); result block
(Leaflet map) is lazy-mounted via dynamic({ ssr: false }) and the section is
collapsed by default. When financial_estimate is null (ЗОУИТ/СЗЗ/нет зоны) it
shows an honest banner but still allows a manual run, since /concepts is
independent of the financial_estimate gate. Graceful empty state when geometry
is missing/unsupported. Stage 2 (interactive 3D + /concepts/recompute) left as
a seam, not built.
2026-06-28 00:13:57 +05:00
f7773c71d4 fix(site-finder): P3 a11y/UI batch from audit #1871
All checks were successful
CI / openapi-codegen-check (pull_request) Successful in 1m46s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 48s
- add <h1> page title to analysis page (иерархия стартовала с h2 — a11y)
- emoji → Lucide во всех вердикт/баннер/статус UI (ui-conventions: emoji
  запрещены): GateVerdictBanner (VerdictColor.icon string→ComponentType,
  sourceHint→ReactNode, SectionLabels), + найдены ещё 3 файла:
  OverviewTab (⚠ ЛЭП/трамвай), GeotechRiskBlock (🟡 вечная мерзлота → Snowflake,
  ⚠ загрязнение), HydrologyBlock (⚠ паводок, 🏞💦🪷🚣💧 subtype-map → Waves/Droplet).
  Все иконки декоративные → aria-hidden, семантика дублируется текстом.
  Семантические цвета через var(--success/--warn/--danger) + hex-fallback.
- расшифровка аббревиатур при первом упоминании (ui-microcopy):
  Section2 «строительство в охранной зоне (ОЗ)... зоне с особыми условиями
  использования территорий (ЗОУИТ), тип 5»; Section4 title-tooltip для ЗОУИТ.
- ForecastChart: axis-chrome hex (:65/67/68) задокументирован как canvas-renderer
  исключение (echarts canvas не резолвит CSS var() — var() сломал бы chrome,
  как и VIZ-series). Цвета не тронуты, только комментарий.

НЕ в scope: ForecastChart CI-band (±p25/p75 — backend не отдаёт, отдельная
задача); ★ в WeightProfilePanel <option> (SVG в option невозможен);
токенизация legacy-hex в Geotech/Hydrology (отдельный pass).

138 frontend vitest passed, tsc/lint clean. lucide-react уже в deps.

Refs #1871
2026-06-23 12:52:32 +05:00
470c6b1f32 revert: remove Site Finder v2 cockpit (PR #1866/#1868/#1870)
All checks were successful
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Successful in 1m49s
CI / frontend-tests (pull_request) Successful in 56s
Полный откат «Site Finder v2» с прода — пилот-беты редизайна
кокпита ПТИЦА. Удалён роут /site-finder/analysis/{cad}/v2, все
компоненты ptica-v2/* (18 файлов), беta-ссылка из AnalysisPageContent.

Сохраняется как было: старый Section1-6 на /site-finder/analysis/{cad},
PticaMapInner и старый /ptica-роут (через 301 на parent), ptica-adapt,
mocks — всё нетронуто. Прод-URL и UX не меняются для пилотов.

Старый ptica-кокпит, на основе которого делался v2, был забракован
визуально, новая попытка тоже не дошла до 1:1 с эталоном. Откат
к стабильному состоянию.
2026-06-22 15:33:25 +05:00
eb7290dcf0 feat(site-finder): add Site Finder v2 cockpit route (ПТИЦА v2)
All checks were successful
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 53s
CI / changes (pull_request) Successful in 5s
CI / openapi-codegen-check (pull_request) Successful in 1m51s
Port the approved ptica-v2 prototype to a new non-destructive route
/site-finder/analysis/{cad}/v2 — dark/light cockpit shell, real Leaflet
map (reuses PticaMapInner), 6 scan cards, lower/bottom grids, 11 drawers
and grounded chat. All values flow through the existing ptica-adapt layer
(real /analyze data or honest «—»). One beta link added on the analysis page.
2026-06-21 22:29:18 +05:00
8cd0620543 feat(site-finder): продуктовые решения по фидбеку analyze (#1741 #1742 #1743 #1744 #1745)
All checks were successful
CI / changes (pull_request) Successful in 8s
CI / changes (push) Successful in 9s
CI / frontend-tests (push) Successful in 1m43s
CI / frontend-tests (pull_request) Successful in 1m59s
CI / openapi-codegen-check (push) Successful in 2m43s
CI / openapi-codegen-check (pull_request) Successful in 1m55s
CI / backend-tests (push) Successful in 9m28s
CI / backend-tests (pull_request) Successful in 9m28s
После ролевой дискуссии (аналитик×комдир×собственник):
- #1741 секции в 2 группы «Участок»→«Стройка и рынок» (Section1→4→2→3→5→6), gate-баннер вынесен НАД группой (убран дубль из Section4Estimate), nav-группы
- #1742 объяснение выбора класса: фраза-причина + мини-таблица 3 классов по deficit_index («+1 острый дефицит, −1 затоварка»). POI «обеспеченность»/market-overstock relabel — N/A (в UI не выводятся)
- #1743 «Остатки и скорость»→«Как продаётся рынок рядом» + headline-вердикт + «Темп продаж»/«Будущее предложение конкурентов (24 мес)» (убран англицизм Velocity-score/Pipeline) + интерпретированные единицы
- #1744 горизонт: caption+tooltip «пересчёт ~10-30с» + статус «Пересчитываем…»; колонки прогноза «…, квартир» + caveat advisory
- #1745 фаза1: таблица «Прогноз по всем форматам» (студия/1-5к × индекс дефицита/прогноз спроса/сигнал); backend пробросил per-format projected_demand_units + signal. Слайдеры/рубли — фаза2 после бэктеста #951

Verify: tsc 0 ошибок; py_compile; what_to_build/recommendation/report/exporter тесты pass.

Closes #1741
Closes #1742
Closes #1743
Closes #1744
Closes #1745
2026-06-18 12:18:04 +05:00
8107c23f18 feat(frontend): mobile responsiveness (#66) + data-sources страница (#80)
Some checks failed
CI / changes (push) Successful in 8s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Successful in 1m3s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 50s
Deploy / changes (push) Has been cancelled
Deploy / build-frontend (push) Has been cancelled
Deploy / deploy (push) Has been cancelled
Deploy / build-backend (push) Has been cancelled
Deploy / build-worker (push) Has been cancelled
#66: responsive CSS-layer в globals.css (3-контекста <768/768-1280/>1280, не Tailwind
sm/md/lg) + ResizeObserver в ChartShell (единственный echarts импортёр → все charts
рефлоу) + class-применение (grid-collapse, nav horizontal-scroll, map-stack) на
site-finder/analytics. overflow-x guard.
#80: /data-sources attribution-страница (OSM ODbL/ДОМ.РФ/Объектив/Open-Meteo/Росреестр/
НСПД, server component, tokens) + footer-link.

Closes #66
Closes #80
2026-06-13 23:12:31 +05:00
4adfef2ad0 feat(site-finder): grounded parcel-chat panel UI (#958)
All checks were successful
CI / changes (push) Successful in 6s
CI / backend-tests (push) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (push) Successful in 45s
CI / frontend-tests (pull_request) Successful in 42s
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 2m43s
Deploy / deploy (push) Successful in 1m4s
CI / changes (pull_request) Successful in 6s
Chat panel on the analysis screen consuming POST /api/v1/chat/ask:
preset-intent quick-buttons (summary/what_to_build/why_forecast/risks/
scenarios), history-aware turns (cap 10), advisory badge + grounded_in
provenance + llm_used marker. Plain-text answer rendering (no HTML
injection); loading/pending/error states with retry. TanStack useMutation
(no useEffect-for-HTTP), tokens-only, Lucide icons, TS strict. Types inline
(codegen backend unreachable in env); no new dependency.

Refs #958
2026-06-08 18:08:01 +05:00
f5aa7ed191 feat(sf): 6.6 in-app future-supply pressure + pipeline competitors (§13.3)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m21s
Deploy / deploy (push) Successful in 1m32s
Surface the §16-traceability evidence behind the supply forecast that
previously lived only in exports: future_market.future_supply (§9.3
supply-pressure breakdown — open/hidden stock, absorption, months of
pressure, future units, pressure index) and future_market.future_competitors
(§9.7 relevance-weighted pipeline, sorted by relevance desc). New
ForecastFutureSupplyBlock as subsection 6.6 (+ section-6-6 nav),
complementing 6.1's per-horizon aggregates.

- Fix FutureSupply/FutureSupplyBreakdown/FutureCompetitor optionality in
  forecast.ts to match the backend (FutureSupplyPressure/Competitor): null
  metrics typed + rendered «нет данных», never a fabricated 0.
- Supply panel gates on computed metrics (index/pressure), NOT open/hidden
  unit stocks — so the empty-supply_layers state (pre Monday-worker, every
  parcel today) hides the panel instead of falsely showing "0 ед."; the
  competitor table still renders. hasSupplySignal shared in forecast-helpers.
- RU labels reuse report_pdf/excel export wording. Graceful on partial/202.

Part of #958; surfaces #950 future-supply data.
2026-06-07 10:55:59 +00:00
a66c35ae49 feat(forecast): render scoring transparency (§13.6) as in-app subsection 6.5
All checks were successful
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 3m2s
Deploy / changes (push) Successful in 6s
Deploy / deploy (push) Successful in 1m2s
Surface the product-score + special-index breakdown behind the overall KPI
as two token-bar groups in Section 6 (6.5), sidebar anchor section-6-5.
Product scores use a 0..1 quality gradient anchored on the documented 0.5
balance point (>=0.55 strong / 0.45-0.55 mid / <0.45 weak; risk scores are
pre-inverted so higher=better); special indices use a neutral accent
(value = signal strength, direction non-uniform). Null values render as
«нет данных», never a 0-bar that implies a real zero. Graceful on
absent/partial/202-pending.

- types/forecast.ts: ReportScoring + nested (dict-keyed scores/indices)
- ForecastScoringBlock.tsx: two bar groups, a11y, null-distinct rendering
- forecast-helpers.ts: scoreVariant/scoreBarWidthPct + RU label maps
- Section6Forecast + sidebar nav: wire 6.5

Part of #958.
2026-06-07 10:08:28 +00:00
54a501b90a feat(forecast): render product_tz (ТЗ на ЖК) as in-app subsection 6.4
All checks were successful
Deploy / changes (push) Successful in 8s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 2m56s
Deploy / deploy (push) Successful in 1m14s
Adds «6.4 Рекомендация по продукту» to Section6Forecast — the §13.4
product recommendation (class, unit-mix, commercial, USP, §16 reasons)
that previously existed only in the export renderers. Unit-mix is shown
as token-colored horizontal bars; since the assembler emits no per-format
share (pct), bars are honestly labeled as a deficit-by-format signal, not
a build-share. Graceful on thin/202-pending/partial reports.

- types/forecast.ts: ReportProductTz + nested interfaces, optional on ForecastReport
- ForecastProductTzBlock.tsx: per-field guards, role=img bars, reasons disclosure
- forecast-helpers.ts: deficitBarWidthPct
- Section6Forecast + sidebar nav: wire 6.4

Part of #958.
2026-06-07 09:55:54 +00:00
740210d9ea feat(site-finder): horizon selector (6/12/18) on analysis screen (#996)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 2m49s
Deploy / deploy (push) Successful in 1m0s
Segmented control «Горизонт прогноза» driving the analyze query (?horizon=)
and Section 6's target highlight. Default 12.

- HorizonSelector: radiogroup + a11y radios, tokens-only, tabular-nums,
  disabled while a re-analyze is in flight
- useParcelAnalyzeQuery(cad, horizon=12): horizon in queryKey + ?horizon=;
  keepPreviousData so switching horizon doesn't blank the page to loading
- AnalysisPageContent: horizon state + forecast-poll invalidation on change
- Section6Forecast/ForecastHorizonsBlock: selectedHorizon → target row («Целевой»)

Part of EPIC #958.
2026-06-05 15:42:58 +05:00
4ec762a202 feat(site-finder): forecast Section 6 (прогноз/сценарии/confidence) on analysis screen (#998)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 2m56s
Deploy / deploy (push) Successful in 1m4s
Renders the §22 SiteFinderReport (future_market/scenarios/confidence) as a new
Section 6 on the modern analysis page (/site-finder/analysis/[cad]), mirroring the
Section1-5 pattern. Polls GET /parcels/{cad}/forecast (202 pending → 200 ready) via
TanStack Query. Render-only (horizon selector = separate #996).

- 6.1 прогноз по горизонтам (deficit_index, MOI, demand/supply, ставка)
- 6.2 сценарии base/aggressive/conservative + rate_path
- 6.3 уверенность: level pill + явный список drivers (confidence.factors)
- types/forecast.ts typed against real prod report; fixture parcel-forecast.json (run #68)
- reuses design tokens + Badge/KpiCard; advisory disclaimer always shown

Part of EPIC #958. Deps 955-A2/A4 (backend §13, merged).
2026-06-05 14:09:55 +05:00
607be225b0 feat(sf-fe-a11): Section 5 «Атмосфера / воздух» (#361)
All checks were successful
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 2m50s
Deploy / deploy (push) Successful in 40s
2026-05-18 04:07:48 +00:00
91026dcc6f feat(sf-fe-a10): Section 4 «Оценка участка» (#358)
All checks were successful
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Successful in 45s
Deploy / changes (push) Successful in 4s
Deploy / build-frontend (push) Successful in 3m3s
2026-05-18 03:57:25 +00:00
68b1968826 feat(sf-fe-a7): Section 3.1 «Настройки выборки» + Server/Client split (rebased) (#356)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / deploy (push) Successful in 40s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Successful in 2m45s
2026-05-18 00:55:05 +00:00