5cbf3485a0
fix(tradein/pdf): честный embedded-шрифт (PT Sans/PT Serif) + matplotlib-график вместо div ( #2427 )
Deploy Trade-In / changes (push) Successful in 12s
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 49s
Deploy Trade-In / build-backend (push) Successful in 1m36s
Deploy Trade-In / deploy (push) Successful in 1m1s
2026-07-04 14:39:37 +00:00
e6000cb029
ci(tradein): pre-merge гейт — backend pytest + frontend type-check/lint ( #2208 ) ( #2220 )
Deploy Trade-In / changes (push) Successful in 10s
Deploy Trade-In / build-browser (push) Successful in 34s
Deploy Trade-In / test (push) Successful in 1m38s
Deploy Trade-In / build-backend (push) Successful in 1m29s
Deploy Trade-In / build-frontend (push) Successful in 3m21s
Deploy Trade-In / deploy (push) Successful in 1m18s
2026-07-02 19:56:22 +00:00
8d7feabf9f
chore(scraper-kit): docker-context wiring + restore backend workspace dep ( #2137 )
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-frontend (push) Successful in 31s
Deploy Trade-In / build-browser (push) Successful in 30s
Deploy Trade-In / test (push) Successful in 1m29s
Deploy Trade-In / build-backend (push) Successful in 1m21s
Deploy Trade-In / deploy (push) Successful in 1m2s
2026-07-02 14:21:38 +00:00
ddf6cb7ce3
chore(scraper-kit): scaffold internal package + uv workspace, build-safe ( #2128 )
Deploy Trade-In / build-frontend (push) Has been skipped
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / build-backend (push) Successful in 1m22s
Deploy Trade-In / deploy (push) Successful in 1m24s
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / test (push) Successful in 1m31s
2026-07-02 14:06:07 +00:00
123717994b
feat(tradein): ГАР-loader знаменателя — apartments-per-house → gar_house_flats + match к houses ( #2059 )
Deploy Trade-In / changes (push) Successful in 11s
Deploy Trade-In / build-browser (push) Has been skipped
Deploy Trade-In / test (push) Successful in 1m36s
Deploy Trade-In / build-frontend (push) Successful in 4m43s
Deploy Trade-In / build-backend (push) Successful in 4m44s
Deploy Trade-In / deploy (push) Successful in 2m15s
2026-06-28 14:54:43 +00:00
8361961a44
fix(scrapers/backend): socks5 health-probe (httpx[socks]) + status Literal whitelist + #1820 ext_id=0 dedup-гард
...
CI / changes (pull_request) Successful in 7s
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
- pyproject.toml: httpx[socks]>=0.27.0 — тянет socksio, socks5:// прокси в _probe_current_ip работает прозрачно
- admin.py list_scrape_runs_unified: status Literal["done","running","banned","zombie","failed","cancelled"] вместо str|None — невалидные значения → 422
- avito_houses.py save_house_catalog_enrichment: гард ext_id=0 + нет адреса → skip without DB touch; два id-less novostroyka URL не схлопываются в bogus avito:0 в house_sources
- тесты: test_unified_runs_invalid_status_422 + test_unified_runs_valid_statuses_200; test_save_house_catalog_enrichment_skips_zero_ext_id_no_address + *_with_address_persists
2026-06-20 10:17:37 +03:00
5fb367295a
feat(browser): split camoufox into tradein-browser container, connect-mode ( #905 )
...
Phase 0.5 — revise #884 's in-backend camoufox into a dedicated browser service.
camoufox.server.launch_server exposes a Playwright WS endpoint (fingerprint/geoip/
proxy configured server-side); the backend connects remotely via playwright, so it
no longer ships Firefox.
- NEW tradein-mvp/browser/{server.py,Dockerfile}: camoufox WS server on :3000;
Firefox fetch under app-user + ENV HOME (carries the #899 cache-path fix)
- BrowserFetcher rewritten launch-in-process → playwright.firefox.connect(ws_endpoint);
recycle (close+reconnect every N) + crash-recovery (TargetClosed → reconnect + 1 retry)
- backend Dockerfile slimmed: drop 5 Firefox libs + camoufox fetch layer
- pyproject: remove camoufox[geoip] from backend, promote playwright to main deps
- docker-compose.prod.yml: add browser service (mem_limit 2.5g moves here), remove
mem_limit from backend, backend depends_on browser (service_started)
- config: browser_ws_endpoint default ws://tradein-browser:3000/playwright
- tests/scrapers/test_browser_fetcher.py rewritten for connect-mode (6 pass)
Dormant: scraper_fetch_mode stays curl_cffi → no prod behavior change.
launch_server signature verified (**kwargs→launch_options, port passes through).
Refs #905 , #883 , #884 , #899
2026-05-31 17:24:35 +03:00
e03f4e4534
feat(tradein): BrowserFetcher camoufox wrapper + Docker/config infra (Phase 0, #884 )
...
Epic #883 foundation. Provider-agnostic BrowserFetcher (camoufox headless Firefox):
async ctx mgr + page-recycle + crash-recovery + proxy. camoufox/playwright lazy
imports (won't break app import). scraper_fetch_mode defaults curl_cffi -> DORMANT
(no parser/estimator/avito/cian change). config: 4 browser_* settings. Dockerfile:
+5 Firefox libs + camoufox fetch layer. compose: mem_limit 2.5g. (uv.lock gitignored
-> re-resolved at build.) 9 mocked tests pass, ruff clean.
WARN: Docker build + container fetch UNVERIFIED (no local Docker); ~960MB image;
merge auto-deploys to prod. MERGE-GATE post-demo + CI-build-verify.
Refs #884 , #883
2026-05-31 15:41:56 +03:00
88cdfd6adb
feat(rbac): role-based access control via X-Authenticated-User middleware ( #585 )
...
Deploy Trade-In / changes (push) Successful in 5s
Deploy / changes (push) Successful in 6s
Deploy Trade-In / build-frontend (push) Successful in 27s
Deploy / build-frontend (push) Successful in 30s
Deploy Trade-In / build-backend (push) Successful in 1m8s
Deploy Trade-In / deploy (push) Successful in 45s
Deploy / build-backend (push) Successful in 2m40s
Deploy / build-worker (push) Successful in 3m20s
Deploy / deploy (push) Successful in 1m16s
Backend RBAC + Caddy header_up. Closes part of #fixes-rbac-pra.
2026-05-26 06:18:40 +00:00
02ad9a1f58
feat(tradein): Phase 1 of #582 — address mismatch audit infrastructure
...
Stratified 200-house Yandex reverse-geocode audit comparing our DB's
(address, lat/lon) pair against what Yandex.Карты returns for those
coordinates. Лежит фундамент данных для Phases 2-5 (canonical = Yandex
per user decision).
What ships:
- Migration 066: address_mismatch_audit table + FDW foreign table
gendesign_ekb_districts_geom для stratified sampling.
- Sampling SQL: 8 EKB districts × 25 houses = 200.
- Driver scripts/audit_address_mismatch.py с двумя режимами:
API (если YANDEX_GEOCODER_API_KEY есть) и Playwright (CAPTCHA-aware,
персистентный контекст). Resumable по --batch.
- Report SQL: p50/p75/p95 distance, top-20 outliers, per-district breakdown.
- 19 unit-тестов: normalize, distance bind, API parser, resume idempotency,
captcha → status=blocked.
Devops note: после деплоя миграции — выдать tradein_fdw_reader SELECT на
gendesign.public.ekb_districts_geom перед первым запуском audit.
Refs #582 (Phase 1 of 5). Phase 3 backfill заблокирован до Yandex API
key (#402 ).
2026-05-25 12:50:30 +05:00
0767fb7401
fix(tradein-photos): sanitize uploaded images via Pillow re-encode ( #511 )
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 58s
Deploy Trade-In / deploy (push) Successful in 36s
2026-05-24 11:32:04 +00:00
9643979d2c
feat(tradein): Phase 3.2 — /api/v1/search endpoint + Redis cache ( #479 )
...
Deploy Trade-In / deploy (push) Successful in 26s
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 56s
POST /api/v1/search reading listings_search_mv with ~20 cross-source filters, parameterized SQL (CAST(:x AS type), psycopg v3), whitelisted ORDER BY (Pydantic Literal), Redis 5min hot cache with graceful degradation (singleton pool via lru_cache).
Verified vs data/sql/050_search_optimization.sql: matview column refs (total_area, lng, house_rating, sources[], has_avito/cian/yandex), SQL injection safety, cache failure swallow, router prefix.
Deep-code-reviewer: APPROVE.
2026-05-23 14:44:22 +00:00
eb4764f75a
feat(tradein): scrape_pipeline.py — Avito full orchestrator (search → houses → detail) ( #451 )
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 56s
Deploy Trade-In / deploy (push) Successful in 28s
2026-05-23 12:55:13 +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
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
lekss361
02267d0306
feat: add tradein-mvp subproject (Trade-In Estimator под /trade-in)
...
- FastAPI backend: PostGIS estimator + 3 scrapers (Avito/Cian/Yandex)
- Next.js 15 frontend: tradein.html mockup design, basePath=/trade-in
- WeasyPrint PDF (Брусника-style 4-page report)
- Address autocomplete с typo-tolerance + 6 EKB presets
- Изолированный docker stack gendesign-tradein (отдельная postgres БД)
- Caddy inline routes: gendsgn.ru/trade-in/* и /trade-in/api/v1/*
- Forgejo Actions: .forgejo/workflows/deploy-tradein.yml (shell-based GHCR login)
- Триггер только по paths: tradein-mvp/** (не пересекается с deploy.yml)
- Образы: ghcr.io/lekss361/gendesign-tradein-{backend,frontend}:latest
Первый запуск на сервере (вручную, один раз):
- создать /opt/gendesign/tradein-mvp/.env.runtime (postgres pwd, contact email)
- docker network create gendesign_shared (если нет)
- docker compose -p gendesign-tradein up -d
- docker compose -p gendesign exec caddy caddy reload
2026-05-21 00:25:39 +03:00