-- 011_listings_alter.sql -- ALTER TABLE listings — добавить ~30 полей для Avito detail page + domoteka (Росреестр) -- -- Dependencies: -- 002_core_tables.sql (listings table) -- 009_houses.sql (houses table — FK house_id_fk) -- -- Apply after: 009_houses.sql -- Apply before: 012_sellers.sql, 013_listings_alter_seller.sql -- -- Sources: -- decisions/Schema_Avito_Houses_Listings_History.md sec 13 (listings ALTER) -- decisions/Schema_Avito_Houses_Listings_History.md sec 29 (owners_count/owners_at_least) -- -- Note: owners_2plus (boolean) из sec 13 заменён на owners_count + owners_at_least (sec 29). -- Идемпотентно: ADD COLUMN IF NOT EXISTS безопасен при повторном запуске. BEGIN; ALTER TABLE listings -- ── House linking ────────────────────────────────────────────────────── ADD COLUMN IF NOT EXISTS house_source text, -- 'avito' / 'cian' ADD COLUMN IF NOT EXISTS house_ext_id text, -- Avito's '3171365' ADD COLUMN IF NOT EXISTS house_url text, -- /catalog/houses// ADD COLUMN IF NOT EXISTS house_id_fk bigint REFERENCES houses(id), ADD COLUMN IF NOT EXISTS listing_segment text, -- 'vtorichka' / 'novostroyki' -- ── Характеристики квартиры (из detail page "О квартире") ───────────── ADD COLUMN IF NOT EXISTS kitchen_area_m2 numeric(6,2), ADD COLUMN IF NOT EXISTS balcony_loggia text, -- balcony/loggia/both/none -- (заменяет has_balcony boolean для detail) ADD COLUMN IF NOT EXISTS room_layout text, -- isolated/adjacent/mixed ADD COLUMN IF NOT EXISTS bathroom_type text, -- combined/separate/both/multi ADD COLUMN IF NOT EXISTS windows_view text, -- yard/street/both/park -- ── Условия продажи ──────────────────────────────────────────────────── ADD COLUMN IF NOT EXISTS sale_type text, -- free/alternative/auction ADD COLUMN IF NOT EXISTS mortgage_available boolean, -- ── Метрики просмотров (Avito tracks viewership) ────────────────────── ADD COLUMN IF NOT EXISTS views_total int, ADD COLUMN IF NOT EXISTS views_today int, ADD COLUMN IF NOT EXISTS publish_date date, -- "18 мая в 13:40" → 2025-05-18 -- ── Текстовое описание ───────────────────────────────────────────────── ADD COLUMN IF NOT EXISTS description text, -- 1000+ chars обычно -- ── Domoteka / Росреестр verification badges ────────────────────────── -- Note: owners_2plus (boolean из sec 13) заменён на owners_count + owners_at_least (sec 29) ADD COLUMN IF NOT EXISTS owners_count int, -- 1 = точно 1; 2 = '2 или больше' ADD COLUMN IF NOT EXISTS owners_at_least boolean, -- true если Avito выдал "X или больше" ADD COLUMN IF NOT EXISTS last_owner_change_date date, -- "Последняя смена собственника YYYY-MM-DD" ADD COLUMN IF NOT EXISTS encumbrances_clean boolean, -- "Не найдены ограничения и обременения" ADD COLUMN IF NOT EXISTS registry_match boolean, -- "Совпадают площадь, адрес и этаж" -- ── Metro + location internal IDs ───────────────────────────────────── ADD COLUMN IF NOT EXISTS metro_stations jsonb DEFAULT '[]'::jsonb, -- [{"name":"Чкаловская","minutes":"11-15","mode":"walk"},...] ADD COLUMN IF NOT EXISTS avito_location_id int, -- 654070 (ЕКБ internal ID) -- ── Detail-page enrichment tracking ─────────────────────────────────── ADD COLUMN IF NOT EXISTS detail_enriched_at timestamptz; -- когда обогатили с detail page -- Индексы для аналитических запросов CREATE INDEX IF NOT EXISTS listings_house_ext_id_idx ON listings (house_source, house_ext_id) WHERE house_ext_id IS NOT NULL; CREATE INDEX IF NOT EXISTS listings_house_id_fk_idx ON listings (house_id_fk) WHERE house_id_fk IS NOT NULL; CREATE INDEX IF NOT EXISTS listings_kitchen_idx ON listings (kitchen_area_m2) WHERE kitchen_area_m2 IS NOT NULL; CREATE INDEX IF NOT EXISTS listings_views_idx ON listings (views_total DESC) WHERE views_total IS NOT NULL; -- Partial index для фильтра "без обременений" — используется estimator CREATE INDEX IF NOT EXISTS listings_encumbrances_idx ON listings (encumbrances_clean) WHERE encumbrances_clean = true; -- Partial index для очереди detail-enrichment (пустой = нужно обогатить) CREATE INDEX IF NOT EXISTS listings_detail_enrich_idx ON listings (detail_enriched_at) WHERE detail_enriched_at IS NULL; -- Partial index для "только с одним собственником" (clean title filter) CREATE INDEX IF NOT EXISTS listings_owners_idx ON listings (owners_count) WHERE owners_count IS NOT NULL; COMMENT ON COLUMN listings.house_ext_id IS 'Avito house ID из /catalog/houses//. NULL для ~18% карточек без ссылки на дом.'; COMMENT ON COLUMN listings.balcony_loggia IS 'Тип балкона: balcony/loggia/both/none. Детальнее чем has_balcony (boolean). Из detail page.'; COMMENT ON COLUMN listings.owners_count IS 'Кол-во собственников из domoteka badge. 1=точно один; 2=''2 или больше'' (Avito скрывает точное для privacy).'; COMMENT ON COLUMN listings.owners_at_least IS 'true если badge содержит "X или больше" — значит owners_count является нижней границей.'; COMMENT ON COLUMN listings.metro_stations IS 'Список станций метро: [{"name":"Чкаловская","minutes":"11-15","mode":"walk"},...]. Из detail page.'; COMMENT ON COLUMN listings.detail_enriched_at IS 'Timestamp обогащения с detail page. NULL = ещё не обогащено (используется как queue flag).'; COMMIT;