Commit graph

521 commits

Author SHA1 Message Date
5e3ba351a0 fix(tradein): security hotfix — C-3 config default + C-4 empty estimate persist + C-6 PDF URL allowlist (#435)
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 38s
Deploy Trade-In / deploy (push) Successful in 25s
2026-05-23 09:38:23 +00:00
3295808b41 fix(security): caddy/** в deploy paths + username из 401 попытки (#434)
All checks were successful
Deploy / build-frontend (push) Successful in 24s
Deploy / build-worker (push) Successful in 25s
Deploy / build-backend (push) Successful in 26s
Deploy / changes (push) Successful in 5s
Deploy / deploy (push) Successful in 54s
2026-05-23 09:25:41 +00:00
de1652a6d8 feat(security): добавить юзера kopylov в basic_auth gate (#433) 2026-05-23 09:07:50 +00:00
f4d43d1cfc fix(security): forwarder PermissionError — убрать USER nobody + deploy automation (#432)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / deploy (push) Successful in 59s
Deploy / build-backend (push) Successful in 27s
Deploy / build-worker (push) Successful in 27s
Deploy / build-frontend (push) Successful in 25s
Hotfix для GlitchTip Issue #71 (PermissionError при чтении /var/log/caddy/gendsgn.ru.log).

Changes:
- ops/glitchtip-auth-forwarder/Dockerfile — убран USER nobody, форвардер под root
- ops/glitchtip-auth-forwarder/forwarder.py — throttle capture_exception (300s)
- .forgejo/workflows/deploy.yml — paths-filter + build + force-recreate sidecar
- docs/runbooks/basic_auth_management.md — Deploy section

Security: caddy_logs mount read-only, нет network listener, нет shell,
auth_forwarder_state dedicated volume. Attack surface минимален.

После merge deploy.yml автоматически rebuild+recreate sidecar на VPS.
2026-05-23 09:04:00 +00:00
03dc8e6735 feat(security): GlitchTip forwarder для basic_auth 401 events (Phase 2 PR #426) (#430)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-backend (push) Successful in 27s
Deploy / build-worker (push) Successful in 27s
Deploy / build-frontend (push) Successful in 26s
Deploy / deploy (push) Successful in 54s
2026-05-23 08:42:36 +00:00
cc2d148967 feat(security): закрыть gendsgn.ru basic_auth gate (multi-user, 11 users) (#426)
All checks were successful
Deploy / changes (push) Successful in 5s
Deploy / build-worker (push) Successful in 30s
Deploy / build-frontend (push) Successful in 28s
Deploy / build-backend (push) Successful in 31s
Deploy / deploy (push) Successful in 53s
Pilot demo 28.05.2026: closed gendsgn.ru/* (включая trade-in/) basic_auth gate. /health и /preview/* остаются public через route { } wrapper (Caddy 2.x directive ordering fix).

11 users (admin + user1..user10), bcrypt cost=14, snippet в git (audit trail). Scripts: scripts/auth/{add,remove,list}_user.sh.

Fixup PR #426 (route{} wrap + log rotation + base64 busybox-compat + runbook audit log fix).
2026-05-23 08:16:10 +00:00
99c19f9fbb Merge pull request 'fix(tradein): PDF — рабочая ссылка на отчёт + «Есть/Нет» для балкона' (#425) from fix/tradein-pdf-link-balcony into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / deploy (push) Successful in 16s
Deploy Trade-In / build-backend (push) Successful in 44s
2026-05-22 11:01:50 +00:00
420057aa02 fix(tradein): PDF — рабочая ссылка на отчёт + «Есть/Нет» для балкона
«Этот отчёт онлайн» и QR-код в PDF вели на
gendsgn.ru/trade-in/trade-in?id=… — двойной /trade-in/: PUBLIC_URL
на проде уже = https://gendsgn.ru/trade-in, а код добавлял /trade-in
ещё раз → ссылка/QR давали 404.

Плюс «Балкон / лоджия» печатался как «1»/«0» (сырое булево) вместо
«Есть»/«Нет».
2026-05-22 16:01:12 +05:00
7a9b183296 Merge pull request 'fix(tradein): восстановленная оценка показывает этаж/площадь, не 0/0' (#424) from fix/tradein-restore-estimate-params into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Successful in 42s
Deploy Trade-In / build-frontend (push) Successful in 1m27s
Deploy Trade-In / deploy (push) Successful in 18s
2026-05-22 10:51:04 +00:00
9b2a54788b fix(tradein): восстановленная оценка показывает этаж/площадь, не 0/0
AggregatedEstimate не нёс параметры целевой квартиры (площадь, этаж,
комнаты, год, тип дома). HeroSummary брал их из формы-инпута — у
свежей оценки работало, но при открытии оценки по ссылке (?id=, из
Истории) формы нет → «Сводка» показывала «ЭТАЖ 0/0, Площадь 0 м²».

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

Заодно в TS-тип добавлен пропущенный est_days_on_market.
2026-05-22 15:50:19 +05:00
7daa2dec55 Merge pull request 'fix(tradein): фото аналога в Сводке больше не скрыто плейсхолдером' (#423) from fix/tradein-hero-photo-visible into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m23s
Deploy Trade-In / deploy (push) Successful in 17s
2026-05-22 10:35:44 +00:00
6041ac8464 fix(tradein): фото аналога в Сводке больше не скрыто плейсхолдером
В .hero-photo псевдоэлементы ::before/::after рисуют декоративный
скелет-плейсхолдер «фасада дома». Они position:absolute, а <img> с
фото аналога — position:static, поэтому абсолютные псевдоэлементы
рисовались ПОВЕРХ картинки: реальное фото загружалось (naturalWidth
есть), но визуально всегда был серый плейсхолдер.

Фото (z-index 1) и подпись .photo-meta (z-index 2) теперь над
скелетом. Скелет остаётся виден, когда фото нет или оно не
загрузилось (onError → display:none).
2026-05-22 15:35:01 +05:00
07903b1c36 Merge pull request 'fix(tradein): бюджет по времени в geocode-missing — cron не таймаутит' (#422) from fix/tradein-geocode-time-budget into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 41s
Deploy Trade-In / deploy (push) Successful in 26s
2026-05-22 09:37:42 +00:00
0b14538f7d fix(tradein): бюджет по времени в geocode-missing — cron не таймаутит
cron geocode-missing-шаг дёргает эндпоинт через `curl -m 320`, а
геокодинг 100 адресов упирается в Nominatim (1 req/sec + typo-тиры на
провалах) и выходит за 320с. При таймауте curl cron-loop обрывался —
объявления Cian/N1 оставались без координат и были невидимы для оценки
(ST_DWithin по geom). Сейчас ~200 таких объявлений в БД.

geocode_missing теперь выходит из цикла по бюджету 240с (заведомо
меньше cron-таймаута) и возвращает remaining > 0 — cron штатно
продолжает следующим чанком. Заодно убран мёртвый import asyncio.
2026-05-22 14:37:15 +05:00
389fcb2146 Merge pull request 'fix(tradein): оценка исключает Avito из радиусного поиска аналогов' (#421) from fix/tradein-estimate-exclude-avito into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 42s
Deploy Trade-In / deploy (push) Successful in 26s
2026-05-22 09:26:59 +00:00
8bef0fd872 fix(tradein): оценка исключает Avito из радиусного поиска аналогов
У Avito-объявлений «координаты» = якорь cron-скрейпа ± jitter (DOM
Avito реальных coords не отдаёт). Фейковые точки кучкуются плотными
кластерами на 5 якорях ЕКБ — tier-1 радиус (1 км) набирался почти
целиком из них: оценка для центра давала sources_used=['avito'],
18 аналогов все Avito, при 1400 живых cian/yandex/n1 в БД.

_fetch_analogs теперь исключает source='avito'. Трёхтирный fallback
по радиусу доходит до реальных cian/yandex/n1 с настоящей геопривязкой
— оценка считается по корректным аналогам.
2026-05-22 14:26:29 +05:00
c3df202d8a Merge pull request 'fix(tradein): N1.ru — честный статус источника вместо хардкод-timeout' (#420) from fix/tradein-n1-source-status into main
All checks were successful
Deploy Trade-In / build-frontend (push) Successful in 1m25s
Deploy Trade-In / deploy (push) Successful in 17s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
2026-05-22 09:16:54 +00:00
14c81dd5ac fix(tradein): N1.ru — честный статус источника вместо хардкод-timeout
SourcesProgress хардкодил N1.ru как error («timeout — нет ответа»)
при готовой оценке — строка никогда не сверялась с sources_used.
Но N1 — реальный рабочий источник (224 объявления на проде), и при
вкладе в оценку он показывался красным крестом-ошибкой.

Теперь строка N1 ведёт себя как cian/avito/yandex: done + счётчик
лотов, если источник в sources_used, иначе loading/idle.
2026-05-22 14:16:30 +05:00
9713f734d7 Merge pull request 'fix(tradein): Avito-парсер тащит фото и реальный адрес из DOM' (#419) from fix/tradein-avito-photos-address into main
All checks were successful
Deploy Trade-In / build-backend (push) Successful in 44s
Deploy Trade-In / deploy (push) Successful in 16s
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Has been skipped
2026-05-22 08:49:37 +00:00
1d788b27d0 fix(tradein): Avito-парсер тащит фото и реальный адрес из DOM-карточек
DOM-путь (_dom_card_to_lot) — основной для Avito: mobile API отдаёт
бан, формат __initialState__ устарел, так что почти все объявления
идут через него. Но он не извлекал фото вообще, а адрес брал мёртвым
селектором [class*="geo-address"] — поэтому объявления Avito оставались
без фото (серый блок в Сводке) и с заглушкой «Екатеринбург (Avito)».

Теперь:
- фото — из <img itemprop="image"> карточки-слайдера (до 5 шт);
- адрес — первый <p> внутри data-marker="item-location" (улица + дом).

Селекторы проверены на живой выдаче Avito.
2026-05-22 13:49:09 +05:00
65e84913b0 Merge pull request 'fix(tradein): map-picker подставляет уличный адрес, а не название POI' (#418) from fix/tradein-reverse-geocode-street into main
All checks were successful
Deploy Trade-In / build-backend (push) Successful in 41s
Deploy Trade-In / deploy (push) Successful in 16s
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
2026-05-22 08:36:28 +00:00
a7a3831ce7 fix(tradein): map-picker подставляет уличный адрес, а не название POI
Обратный геокодинг (Nominatim /reverse) возвращал display_name,
который ведёт с названия ближайшей организации/POI — клик по
ЖК Малевич давал «NataliOlympic, 2к1, Трамвайный переулок…»
вместо адреса дома. Такой адрес не геокодировался обратно,
и оценка находила 0 аналогов.

Теперь reverse_geocode собирает адрес из Nominatim address-объекта
(улица + дом + город), display_name остаётся фолбэком. Follow-up к #415.
2026-05-22 13:32:39 +05:00
e713c1d50e Merge pull request 'fix(tradein): GET /estimate/{id} возвращает полный набор полей' (#417) from fix/tradein-restore-full-estimate into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 43s
Deploy Trade-In / deploy (push) Successful in 17s
2026-05-22 08:21:11 +00:00
TradeIn Deploy
18c2e64182 fix(tradein): GET /estimate/{id} возвращает полный набор полей
При открытии оценки по ссылке (?id=) или перезагрузке страницы
get_estimate отдавал огрызок: без sources_used, confidence_explanation,
target_address, координат, data_freshness_minutes. Из-за этого карточка
«Сбор данных по квартире» пустела до «0 / 7 источников · ожидает
запрос» — хотя данные в БД есть.

Теперь SELECT и ответ включают полный набор полей AggregatedEstimate.
period_months 24 → 12 (совпадает с estimator / DEALS_PERIOD_MONTHS).
2026-05-22 13:20:53 +05:00
a1cd5e293e Merge pull request 'feat(tradein): выбор адреса на карте ЕКБ (#415)' (#416) from feat/tradein-map-picker into main
All checks were successful
Deploy Trade-In / build-frontend (push) Successful in 1m28s
Deploy Trade-In / deploy (push) Successful in 19s
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Successful in 44s
2026-05-22 07:09:51 +00:00
TradeIn Deploy
d456e4fecb feat(tradein): выбор адреса на карте ЕКБ (#415)
Кнопка справа от поля адреса → модалка с картой Екатеринбурга.
Клик по дому → reverse-геокодинг → адрес подставляется в форму.

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

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

Closes #415
2026-05-22 12:09:35 +05:00
c25ccee58c Merge pull request 'fix(tradein): фото аналога в Сводке + честный статус источников' (#414) from fix/tradein-ui-photo-sources into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m22s
Deploy Trade-In / deploy (push) Successful in 17s
2026-05-22 07:03:12 +00:00
TradeIn Deploy
1941c3d7df fix(tradein): фото аналога в Сводке + честный статус источников
UI-баги, замеченные при обзоре результата оценки:

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

- SourcesProgress: источники без данных после завершения оценки
  оставались в статусе idle с подписью «ожидает запрос» — выглядело
  как зависший запрос. Теперь после готовности → «нет данных»
  (терминальный статус).
2026-05-22 12:02:56 +05:00
b7b50c1daf Merge pull request 'feat(tradein): рабочие страницы История и Кэш (#399)' (#413) from feat/tradein-history-cache-pages into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Successful in 43s
Deploy Trade-In / build-frontend (push) Successful in 1m26s
Deploy Trade-In / deploy (push) Successful in 17s
2026-05-22 06:28:44 +00:00
TradeIn Deploy
abafb60120 feat(tradein): рабочие страницы История и Кэш (#399)
Заглушки навбара (href=#) → рабочие страницы.

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

Closes #399
2026-05-22 11:28:27 +05:00
4e36fcb0cc Merge pull request 'feat(tradein): бэкап tradein-postgres по cron (#397)' (#412) from feat/tradein-db-backup into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Successful in 23s
Deploy Trade-In / build-backend (push) Successful in 23s
Deploy Trade-In / deploy (push) Successful in 16s
2026-05-22 06:23:35 +00:00
TradeIn Deploy
34bef40ec5 feat(tradein): бэкап tradein-postgres по cron (#397)
deploy/backup-tradein-db.sh — pg_dump через docker exec → gzip,
retention последних 7 копий. Дамп с --clean --if-exists --no-owner
(самодостаточен для restore). До этого бэкапа БД не было.

Активация: добавить в crontab прод-хоста (пример — в шапке скрипта).

Closes #397
2026-05-22 11:22:30 +05:00
5e907aa7af Merge pull request 'feat(tradein): мониторинг ошибок через GlitchTip (#396)' (#410) from feat/tradein-glitchtip into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Successful in 23s
Deploy Trade-In / deploy (push) Successful in 21s
Deploy Trade-In / build-backend (push) Successful in 58s
2026-05-22 06:21:24 +00:00
TradeIn Deploy
59ad41c183 feat(tradein): мониторинг ошибок через GlitchTip (#396)
Подключаем tradein-backend к GlitchTip (Sentry-совместимый, уже на
сервере). Необработанные исключения FastAPI улетают в дашборд —
баг estimate-500 (#388/#389) был бы виден сразу с трейсбеком.

- sentry-sdk в зависимостях.
- main.py — sentry_sdk.init(), env-gated: пусто GLITCHTIP_DSN → off.
- config.glitchtip_dsn + GLITCHTIP_DSN в docker-compose.prod.yml.
- traces_sample_rate=0 (только ошибки), send_default_pii=False.

Активация: создать проект в GlitchTip → DSN в .env.runtime.
2026-05-22 11:18:26 +05:00
4c51406fda Merge pull request 'feat(tradein): CRM-поля в форме оценки (#395)' (#409) from feat/tradein-crm-fields into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Successful in 43s
Deploy Trade-In / build-frontend (push) Successful in 1m24s
Deploy Trade-In / deploy (push) Successful in 18s
2026-05-22 06:15:32 +00:00
TradeIn Deploy
48ccbdafc8 feat(tradein): CRM-поля в форме оценки (#395)
Доп. поля для трейд-ин менеджера: тип собственности, ипотека/
обременение, имя и телефон клиента. На расчёт оценки не влияют —
сохраняются в trade_in_estimates вместе с записью.

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

Closes #395
2026-05-22 11:15:15 +05:00
88d2840edf Merge pull request 'feat(tradein): фронтенд загрузки фото квартиры (#394)' (#408) from feat/tradein-photo-upload-ui into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-backend (push) Has been skipped
Deploy Trade-In / build-frontend (push) Successful in 1m24s
Deploy Trade-In / deploy (push) Successful in 17s
2026-05-22 06:11:05 +00:00
TradeIn Deploy
0a1df4d13a feat(tradein): фронтенд загрузки фото квартиры (#394)
Компонент PhotoUpload на result-view: выбор image/* (multiple),
загрузка в POST /estimate/{id}/photos, превью загруженных фото.
Multipart напрямую через fetch — apiFetch форсит JSON content-type.

Closes #394
2026-05-22 11:10:50 +05:00
a904037f95 Merge pull request 'feat(tradein): backend загрузки фото квартиры (#394)' (#407) from feat/tradein-photo-upload into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 1m10s
Deploy Trade-In / deploy (push) Successful in 20s
2026-05-22 06:06:10 +00:00
TradeIn Deploy
5413cce953 feat(tradein): backend загрузки фото квартиры (#394)
Фото квартиры прикрепляются к оценке, хранятся в Postgres (bytea) —
без отдельного файлового тома, уезжают вместе с бэкапом БД.

- data/sql/007_estimate_photos.sql — таблица estimate_photos
  (FK на trade_in_estimates, ON DELETE CASCADE).
- POST /estimate/{id}/photos — multipart-загрузка (image/*, ≤10 МБ,
  ≤12 фото на оценку).
- GET  /estimate/{id}/photos — список метаданных.
- GET  /estimate/{id}/photos/{photo_id} — отдать содержимое.
- python-multipart добавлен в зависимости (FastAPI UploadFile).

Фронтенд (file-drop в форме) — отдельным PR.
2026-05-22 11:05:35 +05:00
c86f2e5a72 Merge pull request 'feat(tradein): кадастр зданий как источник house_metadata (#393)' (#406) from feat/tradein-cadastre-enrichment into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 4s
Deploy Trade-In / build-frontend (push) Successful in 23s
Deploy Trade-In / build-backend (push) Successful in 40s
Deploy Trade-In / deploy (push) Successful in 15s
2026-05-22 05:55:05 +00:00
TradeIn Deploy
9cc8ab96f7 feat(tradein): кадастр зданий как источник house_metadata (#393)
В gendesign-БД есть cad_buildings — ~36к зданий ЕКБ с годом постройки
и этажностью (Росреестр). Подключаем как ПРИОРИТЕТНЫЙ источник
обогащения house_metadata, OSM Overpass остаётся fallback-ом.

- data/sql/006_cad_buildings.sql — таблица cad_buildings в tradein-БД.
- deploy/import-cadastre.sh — ETL: ЕКБ-срез cad_buildings из
  gendesign-postgres → tradein (по образцу import-rosreestr.sh).
- house_metadata._cad_buildings_get — lookup по гео-близости (60 м),
  проверяется ПЕРВЫМ в get_house_metadata, до OSM.

cad_buildings — кадастр ЗДАНИЙ, не квартир: поле ручного ввода кадастра
(исходная идея #393) не делаем — гео-обогащение полезнее и работает
автоматически для каждой оценки.

Closes #393
2026-05-22 10:54:42 +05:00
64c6759002 Merge pull request 'feat(tradein): обогащение house_metadata через OSM Overpass (#392)' (#405) from feat/tradein-house-metadata-osm into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 45s
Deploy Trade-In / deploy (push) Successful in 15s
2026-05-22 05:40:13 +00:00
TradeIn Deploy
bf2886509d feat(tradein): обогащение house_metadata через OSM Overpass (#392)
Когда пользователь не указал год постройки / тип дома, estimator
подтягивает их из OpenStreetMap (Overpass API) — building:levels,
start_date, building:material. Улучшает house-match аналогов (#6).

- app/services/house_metadata.py — Overpass-провайдер + кэш в таблице
  house_metadata (TTL 30 дней, lookup по близости координат, 40 м).
- estimator.estimate_quality — обогащает target_year / target_house_type
  перед _fetch_analogs. Best-effort: ошибка OSM → оценка без обогащения.

OSM по ЕКБ: building:levels населён хорошо, год постройки — частично.

Closes #392
2026-05-22 10:39:56 +05:00
4dc173c15b Merge pull request 'chore(security): убрать sshkey.txt из репозитория (#391)' (#404) from chore/untrack-sshkey-secrets into main 2026-05-22 05:29:10 +00:00
TradeIn Deploy
6f372402be chore(security): убрать sshkey.txt из репозитория (#391)
sshkey.txt содержит открытым текстом GHCR-PAT, пароли БД, ADMIN_TOKEN,
пароль Obsidian. git rm --cached снимает файл с отслеживания (локальная
копия остаётся) + добавлен в .gitignore.

Частично закрывает #391. Остаётся (требует ручных действий):
- ротация всех засвеченных секретов;
- чистка истории git (filter-repo) — секреты остаются в старых коммитах.
2026-05-22 10:28:23 +05:00
3b2850b91b Merge pull request 'fix(tradein): cron-scrape подхватывает .env.runtime (#390)' (#403) from fix/tradein-cron-scrape-env into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-backend (push) Successful in 23s
Deploy Trade-In / build-frontend (push) Successful in 24s
Deploy Trade-In / deploy (push) Successful in 16s
2026-05-22 05:23:33 +00:00
TradeIn Deploy
78df203919 fix(tradein): cron-scrape подхватывает .env.runtime (#390)
cron запускается с пустым окружением — ADMIN_TOKEN отсутствует, и все
вызовы admin/scrape и geocode-missing получают 401 (#2 admin-auth).
Парсинг новых объявлений и сделок не работал с ~21.05.

cron-scrape.sh теперь сам читает tradein-mvp/.env.runtime
(resolve по BASH_SOURCE → ../.env.runtime, source с set -a).

Closes #390
2026-05-22 10:23:03 +05:00
e170dddd24 Merge pull request 'fix(tradein): estimate 500 — AmbiguousParameter на NULL-параметрах' (#389) from fix/tradein-estimate-ambiguous-param into main
All checks were successful
Deploy Trade-In / changes (push) Successful in 5s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 40s
Deploy Trade-In / deploy (push) Successful in 16s
2026-05-22 05:03:53 +00:00
TradeIn Deploy
923513f906 fix(tradein): estimate 500 — AmbiguousParameter на NULL-параметрах
Второй баг из #385 (#388 закрыл только алиас distance_m). В
_fetch_analogs ORDER BY использует :target_year и :target_house_type.
Когда год постройки / тип дома не заданы, они приходят NULL — psycopg
шлёт их без типа, PostgreSQL не может определить тип параметра →
psycopg.errors.AmbiguousParameter ($8) → 500 на каждый estimate.

Фикс: явный CAST(:target_year AS integer) и CAST(:target_house_type
AS text). Проверено на прод-БД через psycopg3: без CAST падает с
AmbiguousParameter, с CAST — успешно (7 строк).
2026-05-22 10:03:17 +05:00