79c5068e96
Merge pull request 'fix(analytics): drop false market verdict from per-object Sold % KpiCard ( #1407 )' ( #1672 ) from fix/sold-pct-market-verdict-1407 into main
Deploy / changes (push) Waiting to run
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
2026-06-17 17:44:47 +00:00
66afac8bb3
fix(analytics): drop false market verdict from per-object Sold % KpiCard ( #1407 )
CI / changes (push) Successful in 8s
CI / openapi-codegen-check (push) Successful in 1m47s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Successful in 50s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 1m4s
CI / openapi-codegen-check (pull_request) Successful in 2m19s
2026-06-17 20:22:29 +03:00
249182b678
fix(week-review): дожим ревью — #1569 , #1590 , #1642 + feat #801 MSW-preview
...
CI / frontend-tests (pull_request) Successful in 1m2s
CI / openapi-codegen-check (push) Successful in 2m13s
CI / openapi-codegen-check (pull_request) Successful in 1m45s
CI / backend-tests (push) Successful in 9m29s
CI / backend-tests (pull_request) Successful in 9m29s
CI / changes (push) Successful in 8s
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (push) Successful in 1m7s
Финиш-волна по cross-file/partial остаткам аудита + a11y-харнесс.
Полностью (4): #1569 alembic регистрирует все ORM-модели (+убран фантомный Parcel) ·
#1590 «Индекс дефицита» больше не лжёт на fallback-горизонте (report_pdf+report_md) ·
#1642 thumbs mtime-freshness (нет устаревшей миниатюры) ·
#801 /__preview/estimate mock-render для axe/lighthouse (env-gated bypass).
Частично (остаток cross-file/домен, открыты): #1593 #1635 #1640 .
needs-leha (открыт): #1650 (нужна новая миграция вьюхи supply-слоёв).
Verify: tsc --noEmit 0; py_compile OK.
Closes #1569
Closes #1590
Closes #1642
Closes #801
2026-06-17 11:24:34 +05:00
86e9ea2937
fix(week-review): автофиксы код-ревью — 169 issue (label «week ревью 1»)
...
Многоагентный аудит + имплементация: один воркер на файл, точечные правки.
Верификация: py_compile (47/47 .py) + tsc --noEmit (0 ошибок). Unit-тесты
не прогонялись (окружение не поднято: rollup native dep / нет pytest-venv).
Полностью исправлено (169): #1336 , #1337 , #1339 , #1340 , #1341 , #1342 , #1343 , #1345 , #1346 , #1348 , #1349 , #1350 , #1351 , #1354 , #1356 , #1358 , #1359 , #1360 , #1362 , #1364 , #1365 , #1366 , #1367 , #1368 , #1369 , #1370 , #1371 , #1372 , #1373 , #1374 , #1375 , #1376 , #1377 , #1378 , #1379 , #1380 , #1381 , #1382 , #1384 , #1385 , #1386 , #1387 , #1388 , #1389 , #1390 , #1391 , #1392 , #1394 , #1395 , #1396 , #1397 , #1399 , #1400 , #1401 , #1402 , #1403 , #1404 , #1408 , #1409 , #1410 , #1411 , #1412 , #1413 , #1414 , #1415 , #1416 , #1417 , #1418 , #1420 , #1423 , #1425 , #1426 , #1427 , #1428 , #1429 , #1430 , #1431 , #1432 , #1433 , #1434 , #1435 , #1437 , #1438 , #1439 , #1440 , #1441 , #1442 , #1443 , #1444 , #1445 , #1446 , #1447 , #1448 , #1449 , #1450 , #1451 , #1452 , #1453 , #1454 , #1455 , #1456 , #1457 , #1458 , #1459 , #1460 , #1461 , #1462 , #1463 , #1464 , #1465 , #1466 , #1467 , #1468 , #1469 , #1471 , #1472 , #1473 , #1474 , #1476 , #1478 , #1479 , #1481 , #1482 , #1483 , #1484 , #1485 , #1487 , #1488 , #1489 , #1490 , #1491 , #1492 , #1493 , #1494 , #1495 , #1496 , #1497 , #1499 , #1500 , #1501 , #1502 , #1504 , #1505 , #1506 , #1507 , #1510 , #1514 , #1515 , #1516 , #1517 , #1518 , #1519 , #1521 , #1522 , #1523 , #1524 , #1525 , #1526 , #1527 , #1528 , #1529 , #1531 , #1532 , #1533 , #1534 , #1535 , #1536 , #1537 , #1538
Частично (9, in-file часть, остаток cross-file): #1361 , #1419 , #1422 , #1424 , #1470 , #1475 , #1477 , #1480 , #1498
Требуют cross-file (3, не тронуты): #1338 , #1363 , #1421
Пропущено (1): #1539
Не входило в партию: 22 needs-Leha issue (нужны решения владельца).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:21:11 +05:00
8107c23f18
feat(frontend): mobile responsiveness ( #66 ) + data-sources страница ( #80 )
...
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
adc6dde015
feat(site-finder): multi-cad сравнение ( #50 ) + analytics поиск/cross-links ( #65 )
...
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 3m59s
Deploy / deploy (push) Successful in 1m7s
#50 : /site-finder/compare — shortlist (localStorage, SSR-guard, cap 2-5) + CompareTable
(per-row winner-highlight, reuse useParcelAnalyzeQuery per cad, hook-order stable в .map,
cache-shared). Cross-link с site-finder.
#65 : debounced search (300ms, client-side filter top-15) в DeveloperLeaderboard +
cross-link объект→Site Finder analyze. Existing developers compare не дублирован.
Closes #50
Closes #65
2026-06-13 17:14:15 +00:00
750d34d5cb
feat(concept): Concept UI Stage 1d — ввод участка + варианты ( #57 )
...
Заменяет concept/page.tsx TODO-stubs полным generative-флоу: draw-полигон или
кадастр→geom ввод участка, форма параметров ConceptInput, POST /concepts через
useMutation, табы вариантов с placement-картой + ТЭП KPI + финмодель + экспорт
(GeoJSON/CSV client-side, DXF/PDF на /concepts/export graceful 404). Типы зеркалят
concept.py; переиспользует site-finder Leaflet + analytics Section/KpiCard паттерны.
tsc + lint + build clean.
Closes #57
2026-06-13 16:42:19 +00:00
d737307022
feat(site-finder): НСПД verify deep-links + landing GenDesign vs НСПД таблица ( #97 #100 )
...
Deploy / changes (push) Successful in 5s
Deploy / build-frontend (push) Successful in 4m29s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Successful in 1m5s
#97 : nspdLinks helper (nspdMapUrl/pkkSearchUrl, encodeURIComponent) + NspdVerifyLink
компонент (var(--accent), rel=noopener) → одноклик-сверка с НСПД/ПКК в Section1
(кадастр/ЕГРН) + Section2 (инж.сети) карточках analyze.
#100 : landing — сравнительная секция «GenDesign и НСПД» (7-row таблица value-prop:
цены ДДУ/остатки/скорость/инвест-балл/прогноз/квартирография/экспорт сверх бесплатной
гос-карты) + footer deep-links.
Closes #97
Closes #100
2026-06-13 15:53:02 +00:00
84d08940c6
fix(analytics): свежая ипотечная ставка + recommend last_updated + drop dead route ( #236 #237 #251 )
...
Deploy / changes (push) Successful in 6s
Deploy / build-frontend (push) Successful in 3m9s
Deploy / build-backend (push) Successful in 4m12s
Deploy / build-worker (push) Successful in 5m31s
Deploy / deploy (push) Successful in 1m19s
#236 : _current_mortgage_rate сортировал cbr_mortgage_series по TEXT-полю period
лексикографически ('Январь'>'Февраль') → возвращал stale-точку. Сортировка по
parsed (year, month) + regex-guard на malformed period-строки. Остаётся на
subsidized weighted series (НЕ domrf market — иная метрика). Verified prod:
Февраль 2026 (было Январь 2026).
#237 : scope.last_updated = MAX(snapshot_date) domrf_kn_objects в recommend_mix +
подпись «данные на <дата>» в recommend page.
#251 : удалён never-implemented GET /parcels/{parcel_id} (501) + ParcelDetail схема
(frontend bare 1-сегментный route не зовёт).
Closes #236
Closes #237
Closes #251
2026-06-13 15:22:22 +00:00
4adfef2ad0
feat(site-finder): grounded parcel-chat panel UI ( #958 )
...
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)
...
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
...
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
...
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
f7eb98b971
fix(site-finder): handle 202 on-demand geometry in analyze + error boundaries ( #1001 )
...
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 2m52s
Deploy / deploy (push) Successful in 1m1s
Critical demo-blocker: POST /analyze returns 202 {status:fetching} for parcels
whose geometry isn't cached yet (#93 on-demand НСПД fetch). useParcelAnalyzeQuery
treated 202 as success → the stub (no score/competitors) reached render → Section 3/4
threw TypeError → white screen (no error boundary). Repro confirmed on prod.
- useParcelAnalyzeQuery: 202-aware — poll /fetch-status (2s, 2-min cap), re-POST
on ready (status-checked, no stub on 202 race), throw HTTPError on
not_in_nspd/failed/invalid_format; horizon preserved in both POSTs; retry: false
- error boundaries: app/site-finder/analysis/[cad]/error.tsx + app/error.tsx —
no white screen ever; calm RU message in prod, error detail in dev
- Section3/Section4: guard competitors/score against partial payloads
- CadInput: drop hardcoded default cad (empty + placeholder), raw hex → tokens
Map parcel-select already fixed by 3cea915 . Part of EPIC #958 .
2026-06-05 16:12:21 +05:00
740210d9ea
feat(site-finder): horizon selector (6/12/18) on analysis screen ( #996 )
...
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 )
...
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
3cea915e48
feat(site-finder): clickable parcel markers open analysis from the map
...
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 2m47s
Deploy / deploy (push) Successful in 1m7s
Marker click opens an interactive Leaflet popup with a primary "Открыть анализ"
action that navigates to /site-finder/analysis/<cad> (encodeURIComponent —
matches the [cad] route's single-decode contract) and records the visit in
RecentParcels. Hover tooltip enriched with status + actionable hint. Existing
ParcelDrawer preview kept, reachable via the popup's secondary "Подробнее".
ESLint + tsc clean.
2026-06-04 12:50:37 +05:00
56a7a36c9a
feat(auth): UserMenu — личный кабинет top-right (PR D) ( #590 )
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 )
...
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
a2953e97c4
refactor(security): убрать UI ввода admin token (backend не требует с PR #437 ) ( #442 )
Deploy / build-frontend (push) Successful in 2m46s
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Successful in 57s
2026-05-23 12:06:37 +00:00
43a8ec426e
fix(ui): <Link> вместо <a> для internal nav routes (build error fix)
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 3m25s
Deploy / deploy (push) Successful in 57s
2026-05-23 11:31:59 +00:00
65c77b96b6
feat(ui): добавить Trade-In / Концепция / Админ в landing nav ( #438 )
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Failing after 1m32s
Deploy / deploy (push) Has been skipped
2026-05-23 11:11:21 +00:00
f242d9bc44
feat(sf-fe-a12): Landing redesign + PilotCTA с real B3/B4 data (v2 rebased) ( #367 )
...
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 1m27s
Deploy / build-worker (push) Successful in 2m35s
Deploy / build-frontend (push) Successful in 4m41s
Deploy / deploy (push) Successful in 45s
Hero + 5 KPI cards from GET /api/v1/landing/stats (B4, real DB), Pricing card 30k руб/мес, FAQ accordion, PilotRequestModal -> POST /api/v1/pilot/request (B3).
Round 2 fixes:
- B4 fail-loud: LandingStatsOut.stale flag, zeroed fallback, frontend skeleton
- B3 UUID contract: id:string, display tracking GD-{first8hex}
- PilotRequestModal: replaced manual overlay with <Drawer side="bottom"> (A3 #341 ) — focus trap, ESC, scroll-lock, focus restore
- Design tokens: all hex literals replaced with var(--*)
- HeadlineBar component used instead of hand-rolled dark div
Closes #82
Supersedes #366
2026-05-18 05:16:57 +00:00
607be225b0
feat(sf-fe-a11): Section 5 «Атмосфера / воздух» ( #361 )
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
1bbd4e835d
fix(sf-fe): decode cad in Server Component (B5 400 regression after #356 ) ( #359 )
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / deploy (push) Blocked by required conditions
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
2026-05-18 04:07:03 +00:00
lekss361
31474deca8
feat(frontend): expose legacy Site Finder at /legacy/site-finder
...
User asked для доступа к старой версии перед SF redesign (A1-A11 in progress).
Файл backup лежал в frontend/src/app/_legacy/site-finder-page-tabs.tsx —
папка с префиксом _ Next.js игнорирует как route, доступа через URL нет.
Перенос в frontend/src/app/legacy/site-finder/page.tsx делает его accessible
как /legacy/site-finder. Все импорты компонентов (OverviewTab, EnvironmentTab,
LandTab, MarketTab, KpiCard, CadInput, FetchingState, SiteMap, WeightProfilePanel)
существуют — старая страница рабочая без модификаций.
После полной миграции на новый SF (A12 done + acceptance audit) папку
frontend/src/app/legacy/ можно удалить.
2026-05-18 07:04:45 +03:00
91026dcc6f
feat(sf-fe-a10): Section 4 «Оценка участка» ( #358 )
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 )
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
307a75f333
feat(sf-fe-a6): Section 2 «Сети и точки подключения» — real B5 utilities data ( #354 )
Deploy / deploy (push) Successful in 41s
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 2m44s
2026-05-18 00:27:55 +00:00
da8847c0e2
fix(sf-fe): poi-score TypeError + drawer non-overlay + CSS design tokens ( #353 )
Deploy / build-frontend (push) Successful in 4m18s
Deploy / deploy (push) Successful in 49s
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
2026-05-18 00:04:30 +00:00
9ffeee7ed2
feat(22d): admin UI buttons (skip/force) + reduce catalog jitter 800→300ms ( #352 )
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 1m48s
Deploy / build-worker (push) Successful in 3m1s
Deploy / build-frontend (push) Successful in 3m20s
Deploy / deploy (push) Successful in 55s
2026-05-17 23:38:22 +00:00
ac86b75115
fix(sf-fe): decode cad param (B5 400) + hide entry sidebar when drawer open ( #351 )
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
2026-05-17 23:37:46 +00:00
f87a352292
fix(sf-fe): /site-finder — adapt B1 response shape (markers invisible) + restore CadInput ( #349 )
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 2m32s
Deploy / deploy (push) Successful in 40s
2026-05-17 23:20:57 +00:00
fd4eb8c6f4
feat(sf-fe-a5): Section 1 Инфо об участке — HeadlineBar + KPI + EGRN + POI + Export ( #346 )
Deploy / changes (push) Successful in 5s
Deploy / build-frontend (push) Successful in 2m36s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Successful in 48s
2026-05-17 22:55:05 +00:00
956e461b9f
Merge pull request 'feat(sf-fe-a4): analysis sidebar (scrollspy) + breadcrumb + user avatar' ( #344 ) from feat/sf-fe-a4-sidebar into main
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Has been skipped
Deploy / build-frontend (push) Failing after 26s
2026-05-17 22:20:03 +00:00
lekss361
0084773abf
feat(sf-fe-a2): EntryMap + MapFilterBar + ParcelDrawer + RecentParcels + ParcelLegend
...
- EntryMap: Leaflet карта ЕКБ с CircleMarker парцелей, bbox-aware refetch (TanStack Query),
click-to-select, deselect on backdrop, isFetching indicator
- MapFilterBar: chip-фильтры (status/area/vri) + district select + counter, bbox-linked
counter через FilterBarBridge без ремаунта карты
- ParcelDrawer: slide-in panel 360px — 4 KPI (status/area/district/vri) + coords +
CTA «Открыть анализ» -> /site-finder/analysis/[cad], fallback ПКК Росреестр
- RecentParcels: TanStack Query hook с localStorage fallback (gd_recent_parcels),
merges B2 server list + local-only items; empty state + hover effects
- ParcelLegend: status color legend (free/in_progress/favorite) + STATUS_COLORS export
reused in EntryMap markers
- site-finder-api.ts: useParcelsBboxQuery + useRecentParcels hooks, mock fallback via
MOCK_PARCELS_BBOX / MOCK_RECENT_PARCELS; getLocalRecentParcels / addLocalRecentParcel
- parcels-bbox.json: 20 ЕКБ-парцелей фикстура (6 районов, все статусы, разные ВРИ)
- page.tsx: заменены MapPlaceholder + SidebarPlaceholder на реальные компоненты
2026-05-18 01:12:32 +03:00
lekss361
440b53cef0
feat(sf-fe-a4): AnalysisSidebar (scrollspy) + Breadcrumb + UserAvatar
...
Wire analysis/[cad]/page.tsx: replace SidebarPlaceholder with
AnalysisSidebar (sticky, IntersectionObserver scrollspy on sections
1/2/3/3.1/3.2/3.3/4/5), header with AnalysisBreadcrumb (SiteFinder
→ cad → Анализ) and UserAvatar (gd_org_id from localStorage, SSR-safe).
Add lucide-react to package.json (was used in A1 but missing from deps).
2026-05-18 01:12:18 +03:00
3aaaaba5f9
feat(sf-fe-a1): routes shell — entry / analysis + _legacy/ backup + mock toggle ( #340 )
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / deploy (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Failing after 1m18s
2026-05-17 22:01:49 +00:00
90eb5af883
feat(trade-in): TI-3 frontend /trade-in page + 5 components + hooks ( #317 )
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Successful in 39s
Deploy / build-frontend (push) Successful in 2m45s
2026-05-17 16:58:53 +00:00
f8c382f885
feat(22k): object page — full exposure 9 blocks (sales/quartirography/metro/photos/docs/specs/checks) ( #310 )
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 1m35s
Deploy / build-worker (push) Successful in 2m37s
Deploy / build-frontend (push) Successful in 3m2s
Deploy / deploy (push) Successful in 56s
2026-05-17 15:56:39 +00:00
lekss361
6ecd7a9269
feat(#254,#114): custom POI UI + score breakdown stacked-bar viz
...
Task A (#254 ): Leaflet click-to-add custom POIs
- sessionId.ts: getOrCreateSessionId() from localStorage
- types/customPoi.ts: CustomPoi, CustomPoiCreate, CustomPoiUpdate
- hooks/useCustomPois.ts: useCustomPois / useAddCustomPoi / useUpdateCustomPoi / useDeleteCustomPoi (TanStack Query, X-Session-Id header)
- CustomPoiLayer.tsx: LayerGroup with CircleMarker (green/red/gray by weight), popup with edit/delete
- CustomPoiToggleButton.tsx: crosshair mode toggle button
- CustomPoiAddModal.tsx: modal form (name, 26 categories, weight -5..+5, notes)
- CustomPoiEditModal.tsx: same form for editing existing POI
- SiteMap.tsx: MapClickHandler (useMapEvents), integrated all custom POI components
- page.tsx: useCustomPois hook + passes customPois + parcelCad to SiteMap
Task B (#114 ): ScoreBreakdownStackedBar
- ScoreBreakdownStackedBar.tsx: horizontal stacked bar by category with positive/negative split, toggle between category and factor views, custom POIs highlighted orange with dashed outline
- OverviewTab.tsx: renders ScoreBreakdownStackedBar below ScoreBreakdownPanel
Requires backend PR with /api/v1/custom-pois endpoints merged before POI CRUD works.
2026-05-17 09:35:35 +03:00
lekss361
a7671513c9
feat( #115 ): Leaflet layer toggle для connection points (Макс KILLER)
...
- ConnectionPointsLayer.tsx — per-category CircleMarker слой внутри MapContainer
(electricity/gas/water/heat/sewage/telecom/other, классификация по keywords)
- CpLayerControlPanel.tsx — toggle panel под картой: checkbox per-category + count,
toggle-all, summary badges (ближайший, охранная зона)
- SiteMap.tsx — принимает connectionPoints?: ConnectionPointsResponse,
управляет visibleCategories state, рендерит оба новых компонента
- page.tsx — useConnectionPoints(data?.cad_num) -> передаёт в SiteMap
- Empty-state: "0 точек подключения" при dump_available=false или пустом ответе
2026-05-16 22:51:12 +03:00
ce2c48fff5
feat(site-finder): debounce weight re-analyze ( #201 Phase 2) ( #215 )
Deploy / build-frontend (push) Successful in 2m0s
Deploy / deploy (push) Successful in 28s
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
2026-05-16 12:54:51 +00:00
092976f656
feat(site-finder): inline POI weights pass-through в /analyze ( #201 Phase 1) ( #206 )
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 1m35s
Deploy / build-worker (push) Successful in 2m44s
Deploy / build-frontend (push) Successful in 2m9s
Deploy / deploy (push) Successful in 37s
2026-05-16 11:00:41 +00:00
lekss361
ced237804d
feat(admin): cadastre bulk harvest UI at /admin/scrape/cadastre ( #168 PR4/5) ( #172 )
...
Add admin page for triggering and monitoring cadastre_jobs:
- Trigger form: pilot (50) / ekb_full (2408) / manual_list scopes
- Live jobs table 5s auto-refresh (TanStack Query)
- Per-row expand: phase_state JSON, req/s rate, WAF count, error
- Cancel button for queued/running, Resume for failed/cancelled/paused
- Heartbeat staleness: red "STALE" if running and gap > 10min
- WAF count highlighted red+⚠ when > 5
- Progress bar from targets_done/targets_total
- New tab in admin layout
- Token in localStorage same as geo page
Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-15 13:46:07 +03:00
lekss361
8fa1d005fd
feat(velocity): migrate D2 sales source → objective_corpus_room_month ( #158 )
...
* feat(velocity): migrate D2 sales source from stale sale_graph to objective_corpus_room_month
Closes #156
* fix(velocity): cross-stack contract + NULL safety per pre-push review
3 pre-push code-reviewer findings fixed:
1. TS union extended ('objective'|'sale_graph'|'rosreestr_fallback')
+ UI conditions handle both objective и sale_graph как valid sources.
2. COALESCE(deals_total_vol_m2, deals_total_count * 45.0) — NULL safety
for DKP-only rows (vol_m2 nullable, count > 0).
3. room_bucket parking filter — verified false positive (все 5 buckets
apartments: студия/1/2/3/4+).
Refs: PR #157 pre-push code-reviewer
* fix(types): add 'objective' to velocity_source union (cherry-pick miss)
Cherry-pick от закрытого PR #157 потерял этот файл. Frontend type-check fails
с 'no overlap' error. Restoring.
Refs: PR #158 frontend CI failure
---------
Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-15 09:34:00 +03:00
lekss361
b42c9dd8f5
feat(site-finder): weight profile panel + analyze options ( #114 sub-PR 4/4 FINAL) ( #139 )
...
Closing FINAL sub-PR for #114 Custom POI weights — UI complete.
- weightProfiles.ts: TS types + 4 TanStack Query hooks + 11 categories
- WeightProfilePanel.tsx: collapsible panel, sliders, save dialog
- useSiteAnalysis.ts: accepts AnalyzeOptions, query string for backend
- page.tsx: lifts weights state, integrates panel
Approach: 'save first' для ephemeral (no temp profile creation).
tsc 0 errors, ESLint 0 warnings.
Vault: Module_Weight_Profiles_Frontend.md NEW.
Closes #114
Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-15 00:50:02 +03:00
lekss361
2416ed0db1
refactor(frontend): extract SectionLabel + EmptyState + adminStyles shared ( #132 )
...
* fix(docs): block javascript: URLs in renderMarkdown href (XSS guard)
Per audit batch #127 P2 security minor (issue #130 ).
## Risk
`renderMarkdown` substituted `[text](url)` → `<a href="...url...">` verbatim
без URL validation. Edge case: `[click](javascript:alert(1))` →
`<a href="javascript:alert(1)">click</a>` execute'нется при click.
Currently low risk (markdown source = build-time fs.readFileSync из
public/docs/, checked into repo), но защита-в-глубину: если когда-либо
markdown source станет user-supplied, vuln materialize.
## Fix
`frontend/src/app/docs/b2b-channels/renderMarkdown.ts`:
1. New `safeUrl(url)` function — allowlist `https://`, `http://`, `/`, `#`,
`mailto:`. Everything else → `"#"`.
2. Link regex replacement switched from backreference string to callback
so URL passes через `safeUrl` ДО injection в href.
3. URL unescape → safeUrl → re-escape (HTML escape applied per-line).
## Test cases verified
- `[ok](https://example.com )` → href=`https://example.com ` ✅
- `[ok](/local)` → href=`/local` ✅
- `[ok](#anchor)` → href=`#anchor` ✅
- `[ok](mailto:foo@bar.com)` → href=`mailto:foo@bar.com` ✅
- `[bad](javascript:alert(1))` → href=`#` ✅
- `[bad](data:text/html,...)` → href=`#` ✅
- `[bad](vbscript:msgbox(1))` → href=`#` ✅
## Checks
- tsc: 0 errors
- lint: 0 warnings
- No existing `__tests__/renderMarkdown` to break
## Vault
`fixes/Bug_RenderMarkdown_JavascriptUrl_May14.md` — created.
Closes #130
* refactor(frontend): SectionLabel + EmptyState + adminStyles shared (fixup)
Per audit batch #127 P2 hygiene (issue #129 ). Previous commit лошил
файлы из-за pre-commit (видимо). Fixup-коммит с actual diff:
## New shared modules (3)
- frontend/src/components/ui/SectionLabel.tsx
- frontend/src/components/ui/EmptyState.tsx
- frontend/src/lib/adminStyles.ts
## Replacements
- SectionLabel: 12 inline usages → import (Overview/Land/Market/Environment Tab)
- EmptyState: 3 inline usages → import (Land/Market/Environment)
- adminStyles: 5 admin pages import cardStyle/labelStyle/inputStyle/th/td
- BulkGeoPanel: cardStyle only (preserves local labelStyle для span)
- leads/page.tsx: cardStyle с marginTop extend; th/td/inputStyle local (divergent)
## Visual regression: ZERO
All px/colors/CSS properties copied verbatim. Files с divergent values left local.
## Checks
- ruff (no files)
- prettier
- tsc + lint clean (per agent run)
Closes #129
Refs: #127
* docs(adminStyles): JSDoc warning про divergent local overrides
Per bot review #132 non-blocking minor — задокументировать почему
leads/page.tsx и BulkGeoPanel.tsx имеют local overrides, чтобы будущий
читатель не «унифицировал» обратно по ошибке.
Refs: #129 , #132
---------
Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-14 23:55:38 +03:00
lekss361
8647114b22
fix(docs): block javascript: URLs in renderMarkdown href (XSS guard) ( #131 )
...
Per audit batch #127 P2 security minor (issue #130 ).
## Risk
`renderMarkdown` substituted `[text](url)` → `<a href="...url...">` verbatim
без URL validation. Edge case: `[click](javascript:alert(1))` →
`<a href="javascript:alert(1)">click</a>` execute'нется при click.
Currently low risk (markdown source = build-time fs.readFileSync из
public/docs/, checked into repo), но защита-в-глубину: если когда-либо
markdown source станет user-supplied, vuln materialize.
## Fix
`frontend/src/app/docs/b2b-channels/renderMarkdown.ts`:
1. New `safeUrl(url)` function — allowlist `https://`, `http://`, `/`, `#`,
`mailto:`. Everything else → `"#"`.
2. Link regex replacement switched from backreference string to callback
so URL passes через `safeUrl` ДО injection в href.
3. URL unescape → safeUrl → re-escape (HTML escape applied per-line).
## Test cases verified
- `[ok](https://example.com )` → href=`https://example.com ` ✅
- `[ok](/local)` → href=`/local` ✅
- `[ok](#anchor)` → href=`#anchor` ✅
- `[ok](mailto:foo@bar.com)` → href=`mailto:foo@bar.com` ✅
- `[bad](javascript:alert(1))` → href=`#` ✅
- `[bad](data:text/html,...)` → href=`#` ✅
- `[bad](vbscript:msgbox(1))` → href=`#` ✅
## Checks
- tsc: 0 errors
- lint: 0 warnings
- No existing `__tests__/renderMarkdown` to break
## Vault
`fixes/Bug_RenderMarkdown_JavascriptUrl_May14.md` — created.
Closes #130
Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-14 23:39:47 +03:00
lekss361
49fac806fc
feat(site-finder): auto-fetch cadastre geometry on-demand ( #93 ) ( #95 )
...
* feat(site-finder): auto-fetch cadastre geometry on-demand (#93 )
Когда пользователь вводит cad-номер которого нет в БД (cad_quarters_geom /
cad_buildings / cad_parcels_geom), вместо 404 «Загрузи через NSPD geo» (dead-
end для non-admin) — теперь backend автоматически инициирует NSPD fetch,
frontend показывает loading state с polling /fetch-status каждые 2с.
Backend:
- Новый модуль app/services/site_finder/cadastre_fetch.py с helpers:
find_or_enqueue_fetch (atomic check + enqueue с дедупликацией по cad),
fetch_status (smart polling endpoint — отличает not_in_nspd от failed),
detect_thematic_id (3-сегм quarter / 4-сегм parcel / 5-сегм building),
validate_cad_format.
- Reuse: enqueue_geo_job + process_nspd_geo_job (workers/tasks/nspd_geo).
source_kind='auto_on_demand' отличает от bulk; rate_ms=200, priority=9.
- POST /parcels/{cad}/analyze graceful fallback: inline await до 25s
(fast path), затем 202 + job_id + eta_seconds для polling, либо
400/404/503 в зависимости от статуса (с Retry-After 60s на 503).
- GET /parcels/{cad}/fetch-status новый endpoint для polling.
Frontend:
- useSiteAnalysis расширен: fetchingState + cancel(). POST analyze + при 202
polling каждые 2с (max 60 итераций = 2 мин cap). status=ready → re-trigger
analyze; not_in_nspd/failed/invalid_format → typed errors.
- apiFetchWithStatus<T> + HTTPError в lib/api.ts — status-aware variant
для 200 vs 202.
- FetchingState.tsx: animated spinner, progress bar (linear до etaSeconds,
asymptote после), elapsed counter, cancel button. Светло-голубая
scheme отличается от обычного pending skeleton.
- site-finder/page.tsx: FetchingState когда fetchingState активен; обычный
pending skeleton — только при первичном analyze без 202.
Edge cases (per #93 acceptance):
- cad валидный в НСПД, fetch <25s → inline 200 OK
- cad валидный, fetch >25s → 202 + frontend polls → ready → analyze
- cad валидный, не в НСПД → 404 с понятным сообщением + формат hint
- cad invalid format → 400 + формат hint
- NSPD rate-limited / failed → 503 + Retry-After 60s
- Параллельные запросы на тот же cad → один job, оба клиента poll'ят (дедуп
через find_active_on_demand_job).
Closes #93 .
* fix(site-finder): address PR #95 auto-review minor feedback
Backend (cadastre_fetch.py):
1. (race condition) Advisory lock `pg_try_advisory_xact_lock(hashtext(cad_num))`
обёрнут вокруг шагов "check active job → enqueue" в find_or_enqueue_fetch.
Lock transaction-scoped, released at COMMIT. Параллельные запросы на тот
же cad: первый получает lock и enqueue; второй lock=false → re-check
active job (уже виден после первого COMMIT) → возвращает тот же job_id.
Docstring обновлён, упоминание SELECT FOR UPDATE удалено.
Backend (parcels.py):
3. (threadpool exhaustion) _INLINE_FETCH_WAIT_S снижен 25 → 15s с подробным
комментарием: tradeoff про default Starlette anyio threadpool (40 slots)
и concurrent burst saturation. 15s баланс: НСПД avg 5-15s для quarter,
~70% fast path; остальные 30% получают 202 + polling без блока.
Data (87_on_demand_indexes.sql):
2. (missing index) New migration:
- `nspd_geo_targets_cad_num_idx ON nspd_geo_targets(cad_num)` — для
find_active/recent_completed_job (existing UNIQUE composite не покрывает
WHERE cad_num=:c).
- `nspd_geo_jobs_source_status_idx ON nspd_geo_jobs(source_kind, status)`
composite для filter auto_on_demand + queued/running.
Idempotent (CREATE INDEX IF NOT EXISTS), не блокер при текущем размере,
критично при росте on-demand traffic.
Frontend (useSiteAnalysis.ts):
4. (UI flicker) setFetchingState(null) перемещён ПОСЛЕ `await second
apiFetch`. Иначе между clear и resolve есть момент когда mutation
isPending=true + fetchingState=null → пустой экран ~1 RTT.
NOT addressed (rebuttal):
5. (Tailwind convention) — проверил: в проекте нет ни globals.css, ни
@tailwind directives. ВСЕ существующие site-finder components используют
inline styles (ConfidenceBadge, GeotechRiskBlock, ScoreBreakdownPanel etc).
Tailwind в deps но не wired up. Keep inline styles для consistency.
6. (animate-spin) — требует Tailwind globals (см. #5 ). `<style jsx>`
keyframes — built-in Next.js, работает.
Per auto-review on 2252236 .
---------
Co-authored-by: lekss361 <claudestars@proton.me>
2026-05-12 09:02:17 +03:00