feat(tradein): search matview + indexes (Phase 3.1) #469

Merged
lekss361 merged 2 commits from feat/tradein-search-matview into main 2026-05-23 14:01:18 +00:00

2 commits

Author SHA1 Message Date
lekss361
09698c5124 fix(tradein): PR #469 BLOCK — h.reviews_count + DSN psycopg strip
deep-code-reviewer caught 2 critical bugs that would cause silent prod regression:

1. 050_search_optimization.sql: h.ratings_count → h.reviews_count
   (alias house_ratings_count preserved for API contract)
   houses.ratings_count does not exist; matview CREATE would abort,
   and deploy-tradein.yml swallows the error (|| echo) — Celery task
   would then fail at runtime with "relation listings_search_mv does not exist".

2. refresh_search_matview.py: strip +psycopg dialect prefix from DSN
   tradein-mvp/docker-compose.prod.yml uses postgresql+psycopg:// (SQLAlchemy
   dialect form) for DATABASE_URL. libpq accepts only postgresql:// — without
   the strip, psycopg.connect() raises OperationalError on every Celery beat tick.

Refs PR #469 review (deep-code-reviewer, 2026-05-23).
2026-05-23 16:58:14 +03:00
lekss361
925d7d15cc feat(tradein): search matview + indexes (Phase 3.1)
Multi-Source Integration Phase 3.1. Foundation for /api/v1/search p95 < 100ms
on 100K+ listings.

SQL 050_search_optimization.sql:
  - CREATE EXTENSION IF NOT EXISTS pg_trgm
  - ALTER listings ADD COLUMN tsv tsvector GENERATED ALWAYS AS (...) STORED
  - 10 indexes (geom GIST, composite, gin_trgm, GIN tsv, partial kadastr, ...)
  - CREATE MATERIALIZED VIEW listings_search_mv (per-listing aggregated across sources)
  - 5 matview indexes

Celery task tradein.refresh_search_matview:
  - REFRESH MATERIALIZED VIEW CONCURRENTLY listings_search_mv
  - Logged duration via logger.info
  - Beat schedule snippet (crontab hour=3, minute=0) in docstring — wiring to
    app/celery_app.py left to follow-up PR per main-session coordination.

Refs Master Plan sec 5.1 + 6.5 + 10.1.
2026-05-23 16:46:37 +03:00