3753079dee
feat(site-finder): OSM engineering-networks loader + endpoint ( #1746 ) ( #1930 )
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Successful in 1m53s
Deploy / build-worker (push) Successful in 3m6s
Deploy / build-frontend (push) Successful in 3m19s
Deploy / deploy (push) Successful in 1m26s
2026-06-26 20:01:00 +00:00
b82963d12e
feat(financial): ground-floor нежилое (office/commercial) tranche
...
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 1m50s
Deploy / build-worker (push) Successful in 3m0s
Deploy / build-frontend (push) Successful in 3m18s
Deploy / deploy (push) Successful in 1m22s
Carve a documented office share (comfort/business 5%, econom 0) out of GFA before residential — fixes prior overstatement (all non-parking GFA = residential). total_floor_area unchanged → no double-count; office is additive revenue (+15% premium), нежилое → VAT-able (vat base = parking_va + office_va). Σ invariant holds. Additive schema + api-types regen + PDF/concept display. Deep-review ✅ . Refs #1881
2026-06-25 11:40:01 +00:00
55811ff7cc
feat(workers): data-freshness monitor (Celery beat → GlitchTip)
...
Deploy / changes (push) Successful in 15s
Deploy / build-backend (push) Successful in 1m58s
Deploy / build-worker (push) Successful in 3m9s
Deploy / build-frontend (push) Successful in 3m19s
Deploy / deploy (push) Successful in 1m24s
Extract compute_freshness(db) from the /admin/scrape/freshness handler (endpoint unchanged) + daily beat task scrape_freshness_check that alerts via sentry_sdk.capture_message when a source is stale/failed (error on critical-failed, else warning). Registered in celery include + beat (09:00 MSK). Refs #73
2026-06-25 11:29:34 +00:00
39f099bc17
chore(mocks): regenerate parcel-analyze financial_estimate (consistent with current backend)
...
Deploy / build-frontend (push) Successful in 3m29s
Deploy / deploy (push) Successful in 1m11s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / changes (push) Successful in 7s
Regenerate the drifted dev fixture financial_estimate via compute_financial() from its own teap_synth inputs — parking comfort-priced (#1893 ), VAT parking-only (#1898 ), levered_irr refreshed (#1900 ). Dev-only. Refs #1881
2026-06-25 11:02:36 +00:00
d589ddf6c4
feat(financial): levered (equity) IRR — capstone финмодели #1881
...
Deploy / build-worker (push) Successful in 3m8s
Deploy / deploy (push) Successful in 1m30s
Deploy / build-frontend (push) Successful in 3m25s
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 1m53s
Levered (equity) IRR from the LTC debt-schedule equity cashflow, mirroring the unlevered IRR + roi-proxy fallback. Honest negative-leverage (can be below project IRR). Σ equity_cf == net_profit_after_financing invariant holds. Unlevered untouched. Additive schema fields (api-types regenerated). Cockpit drawer + concept display. Deep-review ✅ .
Refs #1881
2026-06-25 09:06:46 +00:00
b6b9aa9929
feat(financial): DCF-график продаж по реальному темпу поглощения (rank 1)
...
CI / changes (pull_request) Successful in 7s
CI / frontend-tests (pull_request) Successful in 1m10s
CI / openapi-codegen-check (pull_request) Successful in 2m3s
CI / backend-tests (pull_request) Successful in 10m10s
Финмодель брала фиксированное окно продаж 30 мес независимо от рынка
(schedule_is_default всегда true). Теперь окно считается из ЛОКАЛЬНОГО темпа
поглощения, который уже вычисляется в том же /analyze, но финмодель его
игнорировала.
Корректность абсорбции (ключевое): velocity.monthly_velocity_sqm — это СУММА
поглощения ВСЕГО конкурентного набора в радиусе (м²/мес), НЕ темп одного
проекта. Поэтому per-project absorption = monthly_velocity / max(n_with_sales,1)
(темп одного типичного локального продавца) — иначе модель считала бы, что новый
проект забирает весь рыночный темп (дико оптимистично). Поле
project_absorption_sqm_per_month добавлено в VelocityResult (objective-путь);
rosreestr-fallback и вырожденные пути → None (поквартальный count без
по-проектной декомпозиции не может задавать график).
financial.py: окно = clamp(ceil(residential/velocity), MIN=6, MAX=120) при
конечной velocity>0; иначе дефолт 30. Эскроу-инвариант сохранён:
sales_end=max(sales_start+base, constr_end). Инвариант Σ cashflow == net_profit
держится (перенос выручки во времени не меняет сумму). schedule_is_default
флипается в false когда график рыночный; новое поле sales_duration_months
(реализованное окно) для UI/PDF.
Wiring: parcels.py → synthesize_parcel_financial(velocity_sqm_per_month) →
compute_financial(market_velocity_sqm_per_month). Generative §1c путь пока
передаёт None (out of scope, follow-up).
Тесты: +13 (None→дефолт+инвариант; рыночная velocity; клампы MIN/MAX; эскроу;
non-finite→fallback; rosreestr→None; инвариант по размерам окна; регресс PR-3 —
ровно одна смена знака на коротком окне). Полный бэкенд: 3414 passed, 0 failed.
ruff+mypy(strict financial.py) чисто. api-types перегенерены.
Code-review: 2× approve, 0 majors (adversarial correctness-lens подтвердил
семантику абсорбции, инвариант, не-proxy IRR, клампы, rosreestr-None).
Refs #1881
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 02:56:48 +05:00
c972eebce6
chore(api-types): regen после нового admin-endpoint backfill ( #1881 )
...
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Successful in 1m6s
CI / openapi-codegen-check (pull_request) Successful in 2m0s
CI / backend-tests (pull_request) Successful in 10m12s
openapi-codegen-check: новый POST /admin/scrape/zone-regulations/backfill +
TriggerZoneRegulationsBackfillRequest добавили path/schema в OpenAPI →
api-types.ts должен байт-в-байт совпадать с генератором.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-24 02:17:04 +05:00
5359556068
chore(mocks): add financial_estimate to parcel-analyze mock for local preview ( #1881 )
...
CI / openapi-codegen-check (pull_request) Successful in 1m50s
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 51s
Финмодель (PR-1..5) видна в кокпите только при NEXT_PUBLIC_USE_MOCKS=true если
мок несёт financial_estimate (моки минуют backend → фронт читает JSON напрямую).
Раньше мок его не имел → Investment Clearance в локальном preview показывал «—».
Добавлен аутентичный financial_estimate (37 полей: каскад затрат + БДР + DCF
NPV/IRR/PBP + финансирование + teap_synth + caveat), сгенерённый РЕАЛЬНОЙ
synthesize_parcel_financial для участка area=8240, КСИТ 3.5, цена 165k/comfort/
high-rise — гарантирует совпадение с прод-выводом, не руками-числа. NPV 3.9М,
IRR 15.4%, чистая прибыль после финанс. 7.2М (проценты 224М съели маржу —
реалистичный тонкий high-rise).
Refs #1881
2026-06-24 01:58:44 +05:00
d350d27325
feat(finmodel): financing overlay (кредит 15%) поверх unlevered DCF (epic #1881 PR-5)
...
CI / frontend-tests (pull_request) Successful in 59s
CI / openapi-codegen-check (pull_request) Successful in 1m53s
CI / backend-tests (pull_request) Successful in 10m1s
CI / changes (pull_request) Successful in 7s
Финансирование как ДОПОЛНИТЕЛЬНЫЙ overlay поверх готового unlevered cashflow:
кредитная линия покрывает накопительный кассовый разрыв, проценты капитализируются
(compound), ставка _CREDIT_RATE_ANNUAL=15% (норматив, ОТДЕЛЬНО от ставки
дисконтирования — разная семантика: стоимость долга vs требуемая доходность).
Backend (financial.py):
- _compute_financing(operating_cf, annual_rate) — чистая (READ-ONLY вход, не
мутирует): процент на остаток на начало месяца ДО движений → капитализация;
draw=-cf при оттоке, repay=min(cf,debt) при притоке (долг не уходит в минус).
Возвращает peak_debt_rub / total_interest_rub / ending_debt_rub.
- compute_financial: вызов после DCF, net_profit_after_financing = net − interest.
- _build_monthly_cashflow и unlevered NPV/IRR/PBP НЕ ТРОНУТЫ → инвариант
Σ unlevered cashflow == net_profit сохранён (регресс-тест).
- FinancialModel +6 полей (financing_enabled/annual_rate_used/peak_debt_rub/
total_interest_rub/net_profit_after_financing_rub/financing_is_simplified).
Frontend: ParcelFinancialEstimate +6 полей; adaptFinanceDrawer + concept-каскад
показывают пиковый долг/проценты/чистую прибыль после финанс. (когда enabled).
MVP: только агрегаты, БЕЗ levered IRR (хрупко на хардкод-100%-долге — отдельный
PR). HEAVY caveat: проценты — реальная стоимость (net после < net до); 100%
покрытие разрыва (нет equity/LTC); compound; эскроу не моделируется; unlevered
headline не затронут. financing_is_simplified=True флаг.
mypy strict clean, +9 backend + 3 frontend тестов (compound точное значение,
no-mutation, инвариант-регресс, монотонность, net_after<net), api-types
регенерён авторитетно, deps не тронуты (hand-roll).
Refs #1881
2026-06-24 01:12:47 +05:00
d4068a255b
feat(finmodel): monthly DCF — real NPV/IRR/PBP, replace IRR-proxy (epic #1881 PR-3)
...
CI / frontend-tests (pull_request) Successful in 57s
CI / backend-tests (pull_request) Successful in 9m54s
CI / changes (pull_request) Successful in 6s
CI / openapi-codegen-check (pull_request) Successful in 1m53s
Hand-rolled детерминированный DCF (без numpy-financial/новых deps): _npv /
_irr_monthly (bisection с bracket-guard) / _payback_months над помесячным
cashflow, построенным из статического каскада (PR-1) + калиброванной цены
(PR-2) по дефолтным нормативам фаз (ПИР 6мес → СМР по development_type
24/36/48 → распродажа, дисконт 15%).
- Налоги прорейтятся на признание выручки → Σ недисконтированного cashflow ==
net_profit (ИНВАРИАНТ, тест — гарантия что DCF не разошёлся со статикой).
- IRR настоящий когда есть смена знака; вырожденный поток → fallback на
roi-proxy (irr_is_proxy=True). Честно помечено.
- График продаж привязан к завершению стройки: sales_end = max(sales_start +
длительность, construction_end) — продажи не заканчиваются раньше ввода
(РФ ДДУ/эскроу). Без этого high_rise распродавался за 12 мес ДО ввода →
двойная смена знака → profitable-проект молча падал в proxy + инверсия NPV.
- FinancialModel +npv_rub/payback_months/discount_rate_used/schedule_is_default
(additive). development_type проброшен через placement.
- UI/PDF: NPV/IRR/PBP + честный caveat «график — типовое допущение, точность
зависит от него». api-types регенерён авторитетно.
mypy strict clean (generative.*), +15 тестов (DCF helpers на учебных значениях,
ИНВАРИАНТ, IRR real-vs-proxy обе ветки, PBP, sales≥construction для всех типов,
profitable high_rise → настоящий IRR). 48 passed.
Refs #1881
2026-06-23 21:52:04 +05:00
b1332d6b55
feat(generative): calibrate finmodel sale price from Objective market data (epic #1881 PR-2)
...
CI / frontend-tests (pull_request) Successful in 1m3s
CI / changes (pull_request) Successful in 7s
CI / openapi-codegen-check (pull_request) Successful in 2m0s
CI / backend-tests (pull_request) Successful in 10m6s
Заменяет хардкод-цену продажи жилья (класс-норма) на реальную рыночную
медиану из Objective по локации участка. compute_financial остаётся ЧИСТЫМ
(без БД) — DB-lookup в API-слое, цена прокидывается параметром.
- compute_financial: +optional market_price_per_sqm/price_source; цена =
рынок если есть, иначе класс-норма. Паркинг/СМР НЕ калибруем (только жильё).
- concepts.py _lookup_market_price(db, lon, lat): центроид → ближайший
ekb_district (ST_DWithin 5км) → медиана objective_lots.price_per_m2_rub
(n>=10, фильтр 30k-600k) → fallback ekb_districts.median_price_per_m2 →
None. try/except → graceful (None, class_norm) при любой ошибке (вне ЕКБ/
нет гео/SQL) без краха генерации. psycopg3 CAST.
- FinancialModel +price_per_sqm_used/price_is_calibrated/price_source (additive).
- Threading market_price через generate→placement→compute_financial (optional
kwargs, backward-compat).
- UI/CSV: честный caption источника (рынок Objective / справочник района /
норматив класса). Старый лживый footnote «не калиброванная модель» → условный.
Prod-verified: калибруется 4 главных ЕКБ-района по name-match (Академический
204k лотов, Ленинский 38k, Кировский, Орджоникидзевский); остальные 5 admin-
районов честно → district_reference. Гео-радиус matching (полное покрытие) —
follow-up.
api-types.ts регенерён авторитетно. mypy strict clean (generative.*), +14
тестов (калибровка/lookup 4 ветки/SQL-ошибки graceful/backward-compat).
Refs #1881
2026-06-23 21:10:25 +05:00
65bab902e1
feat(generative): full static developer financial cascade (epic #1881 PR-1)
...
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Successful in 1m5s
CI / openapi-codegen-check (pull_request) Successful in 1m58s
CI / backend-tests (pull_request) Successful in 10m10s
Объединяет наше (площади из реальной геометрии teap) + полноту девелоперской
Excel-модели (каскад затрат + БДР с налогами). Расширяет financial.py из
статического GDV−COST в полный статический расчёт. БЕЗ DCF (PR-3), БЕЗ новых
вводных от пользователя — только нормативы + существующий TEAP.
Каскад (financial.py):
- Выручка: жильё (residential×price) + ПАРКИНГ (spaces×1.9М)
- Затраты: СМР(резид+паркинг) + ПИР 2.5% + сети/ТУ 6000₽/м² + услуги заказчика
1.5% + резерв 3% + маркетинг/риэлтор 7% выручки + земля
- БДР: валовая маржа → НДС (упрощённо) → прибыль до налога → налог 25% (ФЗ
176-ФЗ) → ЧИСТАЯ прибыль → ROI + чистая маржа%
- Нормативы документированы (источник: Excel-эталон «Авангардная 13» + RU-рынок)
FinancialModel (concept.py): +16 additive-полей (revenue breakdown, cost cascade,
БДР/налоги, roi, margin_pct, irr_is_proxy). Старые 4 поля сохранены (backward-compat).
IRR честно помечен irr_is_proxy=True (annualized net ROI, не DCF) — настоящий
IRR/NPV/PBP в PR-3 (помесячный cashflow). НДС — документированное упрощение, не
точный НК РФ. Офисы пропущены (нет площади в TEAP).
PDF + concept UI: полный БДР-каскад + чистая прибыль/ROI + честные сноски.
api-types.ts регенерён авторитетно (openapi-typescript + prettier, как CI).
mypy strict clean (generative.*), +тесты (каскад/паркинг/налоги/backward-compat/
edge cost=0), 36 passed.
Refs #1881
2026-06-23 16:45:58 +05:00
5408466905
chore(frontend): regen api-types for snapshot exclude_dev param
CI / changes (pull_request) Successful in 5s
CI / frontend-tests (pull_request) Successful in 1m1s
CI / openapi-codegen-check (pull_request) Successful in 1m50s
CI / backend-tests (pull_request) Successful in 8m50s
2026-06-18 15:51:56 +03:00
bcd24923b8
Merge remote-tracking branch 'forgejo-backend/main' into fix/sf-feedback-batch
2026-06-18 10:01:43 +03:00
e7342d9f98
chore(frontend): regenerate api-types.ts for forecast pdf export ( #1739 )
...
CI / changes (pull_request) Successful in 8s
CI / changes (push) Successful in 10s
CI / frontend-tests (pull_request) Failing after 1m47s
CI / frontend-tests (push) Failing after 1m55s
CI / openapi-codegen-check (pull_request) Successful in 3m11s
CI / openapi-codegen-check (push) Successful in 3m1s
CI / backend-tests (pull_request) Successful in 10m29s
CI / backend-tests (push) Successful in 10m41s
#1748 added format=pdf to the forecast export endpoint but didn't regenerate
the frontend OpenAPI types, failing CI openapi-codegen-check. Regenerated via
the CI recipe (app.openapi() dump -> openapi-typescript -> prettier).
2026-06-18 10:00:26 +03:00
d44f78c33e
fix(frontend): regen api-types.ts — add POI-score fields ( #1709 )
...
CI / changes (pull_request) Successful in 6s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Successful in 47s
CI / openapi-codegen-check (pull_request) Successful in 3m7s
openapi-codegen-check падал СИСТЕМНО на каждом backend-PR: committed
frontend/src/lib/api-types.ts отставал от backend OpenAPI на 2 поля,
добавленных в POI-score схемы (PR ~#1486 normalize POI weighted score),
но не перегенерённых:
- PoiScoreItem.score_contribution
- PoiScoreResponse.poi_weighted_score
Контент взят 1:1 из authoritative CI-диффа (openapi-typescript + prettier).
Возвращает gate openapi-codegen-check в зелёное для всех PR.
Refs #1709
2026-06-17 22:22:02 +03:00
7d5962e7b4
Merge pull request 'fix(site-finder): normalize POI weighted score to 0..100 on backend ( #1486 )' ( #1674 ) from fix/poi-score-scale-1486 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:54:52 +00:00
b534579e1b
fix(site-finder): correct POI-score mock shape+values, routing empty assert ( #1486 review)
...
CI / changes (pull_request) Successful in 8s
CI / changes (push) Successful in 9s
CI / backend-tests (push) Has been skipped
CI / frontend-tests (push) Has been skipped
CI / openapi-codegen-check (push) Has been skipped
CI / frontend-tests (pull_request) Successful in 49s
CI / openapi-codegen-check (pull_request) Failing after 1m35s
CI / backend-tests (pull_request) Failing after 8m47s
- Rename top_poi → items in poi-score.json to match PoiScoreResponse TS type
(mock was cast as PoiScoreResponse but had wrong field name → items undefined
at runtime in MOCK_POI_SCORE mode → PoiList2Gis crashed at [...items].sort)
- Recompute all score_contribution values using backend formula
(weight / _MAX_STRAIGHT_SCORE * 100, _MAX_STRAIGHT_SCORE=0.315) and
poi_weighted_score=19.9 (was 72, which was inconsistent with the new normalization)
- Add assert result.poi_weighted_score == 0.0 to test_routing_decay_empty_db
to match the straight-line empty-db assertion
- Remove stale comment in PoiList2Gis.tsx saying normalization needs fixing in
site-finder-api.ts (already done backend-side in this PR)
2026-06-17 20:47:01 +03:00
68eb6ded89
fix(site-finder): normalize POI weighted score to 0..100 on backend ( #1486 )
...
CI / changes (push) Successful in 10s
CI / changes (pull_request) Successful in 12s
CI / frontend-tests (push) Successful in 49s
CI / openapi-codegen-check (push) Failing after 1m45s
CI / backend-tests (push) Failing after 8m57s
CI / frontend-tests (pull_request) Successful in 45s
CI / openapi-codegen-check (pull_request) Failing after 1m37s
CI / backend-tests (pull_request) Failing after 8m53s
Backend now computes poi_weighted_score and per-POI score_contribution in
0..100 range. Normalization denominator = sum of top-7 category weights / 100
(straight-line mode) or sum of top-7 category weights (routing-decay mode).
Frontend stops reconstructing score from raw weight × 100.
2026-06-17 20:26:35 +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
edfdd04923
fix(frontend): regen api-types.ts — rate_ms в BulkGeoEnqueueRequest
...
CI / changes (push) Successful in 7s
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (push) Successful in 59s
CI / frontend-tests (pull_request) Successful in 55s
CI / openapi-codegen-check (push) Successful in 2m5s
CI / openapi-codegen-check (pull_request) Successful in 1m32s
CI / backend-tests (push) Failing after 8m53s
CI / backend-tests (pull_request) Failing after 8m50s
Бэкенд-схема BulkGeoEnqueueRequest получила поле rate_ms (int, default 600),
но api-types.ts не был перегенерён → CI openapi-codegen-check (drift-gate) RED.
Добавлено сгенерированное поле (проверено: openapi-typescript 7.13.0 + prettier
defaults даёт байт-идентичный результат).
2026-06-15 22:32:21 +03:00
479f01ae1a
Merge remote-tracking branch 'forgejo/main' into HEAD
...
CI / changes (push) Successful in 7s
CI / changes (pull_request) Successful in 8s
CI / frontend-tests (push) Successful in 1m7s
CI / openapi-codegen-check (push) Failing after 2m9s
CI / frontend-tests (pull_request) Successful in 1m4s
CI / openapi-codegen-check (pull_request) Failing after 1m37s
CI / backend-tests (pull_request) Failing after 9m7s
CI / backend-tests (push) Failing after 9m11s
# Conflicts:
# backend/app/services/site_finder/gate_verdict.py
2026-06-15 21:07:05 +03:00
8279b0ee1f
fix(week-review): cross-file добивка код-ревью ( #1338 , #1363 , #1419 , #1421 , #1424 , #1480 )
...
- #1338 concepts.py: geometry.generate вынесен в run_in_threadpool (не блокирует event loop)
- #1363 house_imv_backfill.py + scrape_pipeline.py: периодический heartbeat в долгих IMV-фазах (reap_zombies не помечает живой sweep zombie)
- #1419 site-finder-api.ts: placeholderData keepPreviousData для bbox-запроса (KPI не мигает «0/0» при пане/зуме)
- #1421 site-finder-api.ts: area_ha nullable + адаптер не подставляет 0; null-гейт потребителей EntryMap.tsx, ParcelDrawer.tsx
- #1424/#1480 EstimateResult.tsx: блок «Параметры объекта» скрыт при восстановлении по shared-ссылке (нет мусора «0 м²/Студия/Этаж 0 из 0»)
Верификация: tsc --noEmit 0 ошибок; py_compile OK.
2026-06-15 20:29:00 +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
b405ae291d
feat(site-finder): additive objective_lots price fallback for competitors ( #307 OBJ-3) ( #1332 )
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Successful in 1m57s
Deploy / build-worker (push) Successful in 2m51s
Deploy / build-frontend (push) Successful in 3m6s
Deploy / deploy (push) Successful in 1m12s
2026-06-14 16:10:02 +00:00
5507bbc1a4
feat(site-finder): domrf→cad geom-match + parking_ratio конкурентов ( #96 ) ( #1327 )
Deploy / build-frontend (push) Blocked by required conditions
Deploy / deploy (push) Blocked by required conditions
Deploy / build-backend (push) Blocked by required conditions
Deploy / build-worker (push) Blocked by required conditions
Deploy / changes (push) Has been cancelled
2026-06-14 14:49:28 +00:00
eb251ba7e7
ci(infra): coverage-gate ( #68 ) + OpenAPI codegen-assert ( #69 ) + uptime monitoring ( #75 )
...
CI / changes (push) Successful in 13s
CI / changes (pull_request) Successful in 12s
CI / frontend-tests (push) Successful in 53s
CI / openapi-codegen-check (push) Successful in 1m58s
CI / frontend-tests (pull_request) Successful in 47s
CI / openapi-codegen-check (pull_request) Successful in 1m50s
CI / backend-tests (push) Successful in 8m54s
CI / backend-tests (pull_request) Successful in 8m45s
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Successful in 2m50s
Deploy / build-frontend (push) Successful in 3m11s
Deploy / build-worker (push) Successful in 4m38s
Deploy / deploy (push) Successful in 2m1s
#68 : pytest-cov + [tool.coverage] fail_under=65 (baseline 71%), backend-tests --cov + xml.
#69 : openapi-codegen-check job (dump app.openapi() → openapi-typescript → git diff).
Job использует node_modules-pinned openapi-typescript/prettier (НЕ npx --yes latest —
иначе version-mismatch ложный diff). + regenerated api-types.ts из СВЕЖЕГО main openapi
(8288 строк, включая #73 /freshness — синхронен).
#75 : Uptime Kuma isolated stack + status.gendsgn.ru Caddy + external Telegram watchdog.
#77 : no change — build cache достаточен.
Closes #68
Closes #69
Closes #75
Closes #77
2026-06-13 23:28:06 +05:00
0b20d98b45
feat(site-finder): ЗОУИТ visual layer на Leaflet карте ( #255 )
...
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 1m6s
ZouitLayer (GeoJSON-полигоны из geom_geojson, severity blocker/warning/info по keyword,
popup тип+имя) + ZouitLayerControlPanel (collapsible toggle per-severity, счётчик mappable)
+ SiteMap integration (default blocker+warning ON, info OFF, фон под POI). Graceful: нет
geom_geojson → слой/панель скрыты, текстовый NspdZouitOverlapsBlock остаётся. 10 vitest.
Closes #255
2026-06-13 17:41:08 +00: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
16e505326d
perf(site-finder): honour AbortSignal в poll-цикле useParcelAnalyzeQuery ( #1248 )
...
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
queryFn игнорировал TanStack v5 AbortSignal: first POST /analyze, poll GET
/fetch-status и re-POST не передавали signal, цикл спал на non-abortable
setTimeout без проверки signal.aborted. При unmount / смене cad|horizon цикл
жил до 2-мин кэпа, дёргая GET /fetch-status каждые 2с + POST /analyze на каждый
ready — зомби-поллинг. Проброс signal во все 3 fetch, sleep через shared
abortableSleep (extracted из useSiteAnalysis #1242 ), throw AbortError перед
итерацией. +3 vitest (abort + happy-path).
Closes #1248
2026-06-13 13:19:50 +00:00
99c9a130bc
feat(forecast): расширить горизонт прогноза до 24 мес (ТЗ §12.1)
...
CI / changes (push) Successful in 6s
CI / frontend-tests (push) Successful in 46s
CI / changes (pull_request) Successful in 6s
CI / frontend-tests (pull_request) Successful in 46s
CI / backend-tests (push) Successful in 6m35s
CI / backend-tests (pull_request) Successful in 6m30s
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 2m14s
Deploy / build-frontend (push) Successful in 2m55s
Deploy / build-worker (push) Successful in 4m6s
Deploy / deploy (push) Successful in 1m40s
API отвергал ?horizon=24 (422), хотя ТЗ §12.1 называет 6/12/18/24, а движок
УЖЕ считает 24 на каждом ране: _DEFAULT_HORIZONS=(6,12,18,24) во всех 6 точках
стека (orchestrator/forecast-task/demand_supply_forecast/scenarios/
special_indices/report_assembler), PIPELINE_HORIZON_MONTHS=24.
_hidden_release_fraction клампит h/18→1.0 на 24 (без переполнения),
future_supply._horizon_weight расширяет окно чисто — скрытых ≤18 потолков нет.
Чистое расширение валидатора-enum, не новая математика.
Backend: _ALLOWED_FORECAST_HORIZONS → {6,12,18,24}, Query/docstring/error-msg.
Frontend: HorizonSelector HORIZONS=[6,12,18,24] (тип horizon=number, union не нужен;
прочие потребители data-driven через meta.horizons/forecasts_by_horizon).
Тесты: API принимает 24/отвергает 30; движок-тесты доказывают h=24 осмыслен
(поля посчитаны, demand(24)>demand(18), hidden созрел, индексы в диапазонах).
Closes #944 (Q1 горизонт 24)
2026-06-13 17:27:35 +05:00
d8a2ad7854
fix(auth): отобразить роль analyst в UserMenu, расширить Role union в useMe ( #1237 )
2026-06-13 15:03:15 +05:00
03e5d07907
fix(site-finder): adapt backend egrn_block → frontend ParcelEgrn ( #1217 )
...
Deploy / deploy (push) Blocked by required conditions
Deploy / build-worker (push) Has been skipped
Deploy / changes (push) Successful in 7s
Deploy / build-backend (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
Бэкенд /analyze отдаёт egrn_block c snake_case-ключами
permitted_use_text/land_category/ownership_type/parcel_status/
last_egrn_update_date (parcels.py:2151-2171), фронт ждёт ParcelEgrn с
vri/category/owner_type/status/last_updated (site-finder-api.ts:255).
Section1ParcelInfo делал `data.egrn as ParcelEgrn` — каст глушит TS;
6 из 10 строк таблицы ЕГРН в prod пустые. ExportButtons тем же кастом
писал пустые ячейки в CSV. egrn={} (truthy) глушил buildFallbackEgrn.
Mock-фикстура была в старой фронт-форме — маскировала баг в dev.
Patch:
- `adaptEgrn(raw, cad)` в site-finder-api.ts: маппит backend-ключи →
frontend, пустой `{}` → null. Тестируется в изоляции.
- AnalyzeResponse.egrn: ParcelEgrn|null → unknown (wire-shape).
- Section1ParcelInfo: `adaptEgrn(data.egrn, cad) ?? buildFallbackEgrn(cad)`.
- ExportButtons: пропс `egrn` (адаптированный) вместо bad-cast'а.
- mock parcel-analyze.json — на реальную backend-форму.
- 7 vitest-кейсов: backend→frontend mapping, {}→null, null/scalar→null,
partial nullable→em-dash, threading cad, пустые строки=missing.
80/80 frontend тестов зелёные. tsc + lint clean.
Closes #1217
2026-06-13 05:36:52 +00:00
9a2cf32787
fix(api): handle 204 No Content в apiFetch ( #1219 )
...
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Blocked by required conditions
Deploy / changes (push) Successful in 7s
Deploy / build-frontend (push) Has been cancelled
apiFetch безусловно звал response.json() после !response.ok-check, что
падало SyntaxError'ом на пустом теле 204. DELETE /custom-pois/{id} и
DELETE /admin/site-finder/weight-profiles/{id} объявлены status_code=204
→ mutation promise реджектился → onSuccess/invalidateQueries не срабатывали
→ POI/профиль виден в UI до случайного рефетча, хотя реально удалён на
сервере. Silent fail для DELETE кастомных POI на SiteMap (#1219 , P2).
Fix: на 204 или пустом теле resolve'имся с undefined (аналог семантики
apiFetchWithStatus). Сигнатура Promise<T> сохранена — 80 не-204 callers
backward-compatible; два DELETE-хука уже типизированы <unknown>/<void>
и корректно игнорируют возврат.
6 новых vitest кейсов (api.test.ts): 204, empty-body-200, 200+JSON, 404,
500, regression guard. 73/73 frontend тестов зелёные, lint+tsc clean.
Closes #1219
2026-06-13 05:13:44 +00:00
df9d54b532
feat(site-finder): add opportunity-ЗУ + red-line map layers (§12.1-13, #958 )
...
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-frontend (push) Successful in 2m40s
Deploy / build-worker (push) Has been skipped
Deploy / deploy (push) Successful in 1m4s
Render the §12.1-13 geometry already exposed on /analyze but previously
dropped by the MiniMap adapter:
- Перспективные ЗУ (nspd_opportunity_parcels.geom_wkt) — viz-3 polygons
- Красные линии застройки (nspd_red_lines.geom_wkt) — warn dashed lines
Wired as toggles in the existing CpLayerControlPanel (Рынок group),
reusing wkt.ts (extended with LINESTRING/MULTILINESTRING for red lines).
Empty/invalid geometry renders nothing gracefully; popups RU plain-text.
§22 forecast (future_market/special_indices), ППТ-ПМТ planning polygons
and future-ЖК points carry no map-able geometry on the frontend yet — left
as backend follow-ups, not faked.
Refs #958
2026-06-09 07:19:53 +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
cdb6035e39
chore(frontend): add vitest runner + WKT parser unit tests
...
CI / changes (push) Successful in 6s
CI / backend-tests (push) Has been skipped
Deploy / deploy (push) Blocked by required conditions
CI / changes (pull_request) Successful in 5s
CI / backend-tests (pull_request) Has been skipped
Deploy / changes (push) Successful in 6s
Deploy / build-backend (push) Has been skipped
Deploy / build-worker (push) Has been skipped
Deploy / build-frontend (push) Has been cancelled
- Wire vitest (jsdom, globals, @ alias->src, jest-dom matchers); add
test / test:watch scripts and dev deps (vitest 2.1, @vitejs/plugin-react,
jsdom, @testing-library/{react,dom,jest-dom,user-event}); regen lockfile
(both package.json + package-lock.json, alpine-musl binaries verified).
- Revive 4 orphaned tests: jest.fn->vi.fn (Drawer); fix outdated subtitle
DOM assertion (HeadlineBar); drop stale jest setup comments.
- Extract WKT->GeoJSON parser (wktToGeometry/splitTopLevel/parseRing) from
MarketLayers into src/lib/wkt.ts (pure, behavior-preserving refactor) +
add EWKT SRID-prefix tolerance; cover with src/lib/__tests__/wkt.test.ts
(16 cases incl. lon/lat order, holes, multipolygon, EWKT, garbage->null).
57 tests green; type-check green; build green. CI wiring is a devops follow-up.
Refs #999 .
2026-06-07 16:46:27 +05:00
3423a1db74
feat(site-finder): toggleable market layers on analysis map ( #999 )
...
CI / backend-tests (pull_request) Has been skipped
Deploy / deploy (push) Successful in 1m5s
CI / changes (push) Successful in 6s
CI / backend-tests (push) Has been skipped
CI / changes (pull_request) Successful in 6s
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
Add Конкуренты / Будущие проекты / Зоны риска Leaflet layers to the Site Finder
analysis map (MiniMap→SiteMap) with per-layer toggles in CpLayerControlPanel
(Конкуренты on by default; pipeline + risk off). Competitors/pipeline render as
distinct CircleMarkers from analyze lat/lon (#1074 ); risk zones as GeoJSON
polygons parsed from geom_wkt via a small inline WKT parser (no new deps).
Graceful on missing coords / empty arrays / thin responses. Coordinate order
verified (GeoJSON lon-lat for <GeoJSON>, Leaflet lat-lon for CircleMarker).
3 of 4 layers; future-ЖК (newbuilding) pending newbuilding_listings API exposure
(#1108 built the table). Part of #999 .
2026-06-07 14:35:24 +05:00
858b5f4511
feat(site-finder): forecast export control in Section 6 ( #959 )
...
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 2m59s
Deploy / deploy (push) Successful in 1m2s
«Скачать отчёт .md / .json» + «Скопировать для Telegram» on the ready §22
forecast, wired to GET /parcels/{cad}/forecast/export. triggerDownload extracted
to lib/download.ts (reused by ExportButtons). Clipboard fallback for insecure
contexts; 404 → inline «Отчёт ещё не готов». Part of EPIC #959 .
2026-06-07 08:41:05 +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
c08e4d7811
feat(rbac): pilot scope → только /trade-in/** ( #587 )
...
Deploy Trade-In / changes (push) Successful in 6s
Deploy / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 26s
Deploy / build-backend (push) Successful in 28s
Deploy / build-worker (push) Successful in 28s
Deploy / build-frontend (push) Successful in 27s
Deploy Trade-In / deploy (push) Successful in 36s
Deploy / deploy (push) Successful in 55s
Decision 2026-05-26: pilot не видит landing/analytics/site-finder/concept, только Trade-In.
2026-05-26 07:40:44 +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
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
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
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