feat(market): contract views market.v_* over producer tables (#2130)
This commit is contained in:
parent
da0b8f0374
commit
2296d33d28
1 changed files with 219 additions and 0 deletions
219
tradein-mvp/backend/data/sql/154_market_contract_views.sql
Normal file
219
tradein-mvp/backend/data/sql/154_market_contract_views.sql
Normal file
|
|
@ -0,0 +1,219 @@
|
||||||
|
-- 154_market_contract_views.sql
|
||||||
|
-- Public data contract for external consumers of the trade-in house dataset (#2130).
|
||||||
|
--
|
||||||
|
-- Context:
|
||||||
|
-- `gendesign_reader` (101_gendesign_reader_role.sql) is currently granted SELECT
|
||||||
|
-- directly on 5 raw producer tables: houses, house_sources, houses_price_dynamics,
|
||||||
|
-- house_reliability_checks, house_reviews (102 grants listings/offer_price_history
|
||||||
|
-- separately). Consumers (gendesign-backend ETL #976,
|
||||||
|
-- backend/app/services/etl/newbuilding_crossload.py) read these raw tables directly,
|
||||||
|
-- which means every scraper-driven ALTER TABLE (new column, renamed column, dropped
|
||||||
|
-- bookkeeping field) is a silent breaking change for an external product.
|
||||||
|
--
|
||||||
|
-- This migration introduces `market.v_*` views as a stable, explicit-column contract
|
||||||
|
-- layer over those 5 raw tables. Consumers should migrate to reading the views
|
||||||
|
-- instead of the raw tables. The column list below IS the promise of stability —
|
||||||
|
-- adding a column later is backward compatible, renaming/removing one is not.
|
||||||
|
--
|
||||||
|
-- Regranting `gendesign_reader` to the views + revoking direct raw-table access is a
|
||||||
|
-- SEPARATE follow-up (#2138) — intentionally NOT done here. This migration only adds
|
||||||
|
-- the views; existing raw-table grants (101_gendesign_reader_role.sql) are untouched.
|
||||||
|
--
|
||||||
|
-- Column selection:
|
||||||
|
-- Every column actually read by the current consumer
|
||||||
|
-- (backend/app/services/etl/newbuilding_crossload.py `_SOURCE_SQL`, gendesign repo) is
|
||||||
|
-- included: houses.{source, ext_house_id, url, slug, address, full_address, lat, lon,
|
||||||
|
-- house_class, developer_name, developer_key, year_built, total_floors, total_units,
|
||||||
|
-- rating, reviews_count, houses_by_turn, cian_internal_house_id, raw_payload,
|
||||||
|
-- last_scraped_at} + house_sources.{house_id, ext_source, ext_id} (LEFT JOIN for
|
||||||
|
-- yandex_jk_id).
|
||||||
|
--
|
||||||
|
-- houses_price_dynamics / house_reliability_checks / house_reviews have no current
|
||||||
|
-- gendesign-side consumer, but are granted to gendesign_reader (101) as future ETL
|
||||||
|
-- sources — views expose their full content-bearing column set so future consumers
|
||||||
|
-- get the same stability guarantee from day one.
|
||||||
|
--
|
||||||
|
-- Deliberately EXCLUDED from all views (producer-internal, high-churn, not part of
|
||||||
|
-- the public contract):
|
||||||
|
-- - raw_payload / raw_characteristics / map_pins / rating_distribution — raw
|
||||||
|
-- scrape-source blobs kept for internal retrofit, not a stable shape.
|
||||||
|
-- (houses.raw_payload IS however read by the ETL today — see v_houses below,
|
||||||
|
-- kept for that reason; house_sources/house_reviews raw_payload are NOT read
|
||||||
|
-- by any current consumer and are excluded.)
|
||||||
|
-- - *_validated_at / *_status / *_qc_* / *_error_reason / last_imv_attempt_at —
|
||||||
|
-- internal scrape-state bookkeeping (dadata QC codes, IMV backfill status),
|
||||||
|
-- churns independently of the actual house data.
|
||||||
|
-- - complex_id — unused FK placeholder (no complexes table yet, per 040 comment).
|
||||||
|
--
|
||||||
|
-- Dependencies:
|
||||||
|
-- - 105_market_schema_yandex_enrichment.sql (CREATE SCHEMA market)
|
||||||
|
-- - 009_houses.sql + all subsequent houses ALTERs (010/020/029/031/040/064/070/071/105)
|
||||||
|
-- - 028_matching_tables.sql + 029_extend_matching_valuation_dynamics.sql (house_sources)
|
||||||
|
-- - 024_houses_price_dynamics.sql + 029 dims (houses_price_dynamics)
|
||||||
|
-- - 025_house_reliability_checks.sql (house_reliability_checks)
|
||||||
|
-- - 014_house_reviews.sql + 043_house_reviews_extend.sql (house_reviews)
|
||||||
|
--
|
||||||
|
-- Idempotent: CREATE SCHEMA IF NOT EXISTS + CREATE OR REPLACE VIEW — safe to re-run.
|
||||||
|
-- AUTO-APPLIED on prod via deploy-tradein.yml/_schema_migrations.
|
||||||
|
-- Does NOT touch grants — gendesign_reader keeps reading raw tables until #2138.
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
|
||||||
|
CREATE SCHEMA IF NOT EXISTS market;
|
||||||
|
|
||||||
|
-- ── market.v_houses ──────────────────────────────────────────────────────────
|
||||||
|
CREATE OR REPLACE VIEW market.v_houses AS
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
source,
|
||||||
|
ext_house_id,
|
||||||
|
url,
|
||||||
|
slug,
|
||||||
|
address,
|
||||||
|
full_address,
|
||||||
|
short_address,
|
||||||
|
lat,
|
||||||
|
lon,
|
||||||
|
geom,
|
||||||
|
year_built,
|
||||||
|
house_type,
|
||||||
|
house_class,
|
||||||
|
material_walls,
|
||||||
|
material_floors,
|
||||||
|
series_name,
|
||||||
|
total_floors,
|
||||||
|
total_units,
|
||||||
|
entrances,
|
||||||
|
flat_count,
|
||||||
|
is_emergency,
|
||||||
|
passenger_elevators,
|
||||||
|
cargo_elevators,
|
||||||
|
has_concierge,
|
||||||
|
closed_yard,
|
||||||
|
has_playground,
|
||||||
|
hot_water,
|
||||||
|
heat_supply_type,
|
||||||
|
gas_supply_type,
|
||||||
|
overlap_type,
|
||||||
|
parking_type,
|
||||||
|
infrastructure_summary,
|
||||||
|
infrastructure_walk_distance,
|
||||||
|
developer_name,
|
||||||
|
developer_key,
|
||||||
|
management_company_id,
|
||||||
|
rating,
|
||||||
|
reviews_count,
|
||||||
|
rating_score,
|
||||||
|
rating_string,
|
||||||
|
transport_accessibility_rate,
|
||||||
|
has_panorama,
|
||||||
|
advantages,
|
||||||
|
banks,
|
||||||
|
builders,
|
||||||
|
houses_by_turn,
|
||||||
|
corpus_count,
|
||||||
|
commission_year,
|
||||||
|
commission_month,
|
||||||
|
total_area_ha,
|
||||||
|
cadastral_number,
|
||||||
|
house_fias_id,
|
||||||
|
yandex_jk_id,
|
||||||
|
yandex_jk_slug,
|
||||||
|
cian_internal_house_id,
|
||||||
|
cian_zhk_url,
|
||||||
|
raw_payload,
|
||||||
|
first_seen_at,
|
||||||
|
last_scraped_at
|
||||||
|
FROM public.houses;
|
||||||
|
|
||||||
|
COMMENT ON VIEW market.v_houses IS
|
||||||
|
'Stable public contract over public.houses (#2130). Explicit column list is the '
|
||||||
|
'stability promise — do not SELECT * against the base table from external '
|
||||||
|
'consumers. raw_payload is included because it is read today by gendesign ETL '
|
||||||
|
'#976 (newbuilding_crossload.py); scraper-internal QC/status/validated_at '
|
||||||
|
'bookkeeping columns are intentionally excluded.';
|
||||||
|
|
||||||
|
-- ── market.v_house_sources ───────────────────────────────────────────────────
|
||||||
|
CREATE OR REPLACE VIEW market.v_house_sources AS
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
house_id,
|
||||||
|
ext_source,
|
||||||
|
ext_id,
|
||||||
|
confidence,
|
||||||
|
matched_method,
|
||||||
|
matched_at,
|
||||||
|
ext_url,
|
||||||
|
last_seen_at
|
||||||
|
FROM public.house_sources;
|
||||||
|
|
||||||
|
COMMENT ON VIEW market.v_house_sources IS
|
||||||
|
'Stable public contract over public.house_sources (#2130). Cross-source house '
|
||||||
|
'match links (house_id -> ext_source/ext_id). raw_payload (internal source '
|
||||||
|
'snapshot for diffing) is intentionally excluded — not read by any current '
|
||||||
|
'consumer.';
|
||||||
|
|
||||||
|
-- ── market.v_houses_price_dynamics ───────────────────────────────────────────
|
||||||
|
CREATE OR REPLACE VIEW market.v_houses_price_dynamics AS
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
house_id,
|
||||||
|
month_date,
|
||||||
|
price_per_sqm,
|
||||||
|
source,
|
||||||
|
room_count,
|
||||||
|
prices_type,
|
||||||
|
period,
|
||||||
|
recorded_at
|
||||||
|
FROM public.houses_price_dynamics;
|
||||||
|
|
||||||
|
COMMENT ON VIEW market.v_houses_price_dynamics IS
|
||||||
|
'Stable public contract over public.houses_price_dynamics (#2130). Monthly '
|
||||||
|
'price-per-sqm time series per house, dimensioned by room_count/prices_type/'
|
||||||
|
'period. No current gendesign consumer — view exists for forward-compat with '
|
||||||
|
'the gendesign_reader grant in 101_gendesign_reader_role.sql.';
|
||||||
|
|
||||||
|
-- ── market.v_house_reliability_checks ────────────────────────────────────────
|
||||||
|
CREATE OR REPLACE VIEW market.v_house_reliability_checks AS
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
house_id,
|
||||||
|
check_status,
|
||||||
|
check_name,
|
||||||
|
details,
|
||||||
|
source,
|
||||||
|
recorded_at
|
||||||
|
FROM public.house_reliability_checks;
|
||||||
|
|
||||||
|
COMMENT ON VIEW market.v_house_reliability_checks IS
|
||||||
|
'Stable public contract over public.house_reliability_checks (#2130). '
|
||||||
|
'наш.дом.рф reliability check results scraped via Cian newbuilding pages. '
|
||||||
|
'No current gendesign consumer — view exists for forward-compat with the '
|
||||||
|
'gendesign_reader grant in 101_gendesign_reader_role.sql.';
|
||||||
|
|
||||||
|
-- ── market.v_house_reviews ────────────────────────────────────────────────────
|
||||||
|
CREATE OR REPLACE VIEW market.v_house_reviews AS
|
||||||
|
SELECT
|
||||||
|
id,
|
||||||
|
house_id,
|
||||||
|
source,
|
||||||
|
ext_review_id,
|
||||||
|
author_name,
|
||||||
|
review_title,
|
||||||
|
score,
|
||||||
|
model_experience,
|
||||||
|
rated_date,
|
||||||
|
text_main,
|
||||||
|
text_pros,
|
||||||
|
text_cons,
|
||||||
|
likes,
|
||||||
|
scraped_at
|
||||||
|
FROM public.house_reviews;
|
||||||
|
|
||||||
|
COMMENT ON VIEW market.v_house_reviews IS
|
||||||
|
'Stable public contract over public.house_reviews (#2130). Resident reviews '
|
||||||
|
'from Avito/Cian/Yandex Houses Catalog. raw_payload excluded (internal retrofit '
|
||||||
|
'blob, no current consumer). No current gendesign consumer — view exists for '
|
||||||
|
'forward-compat with the gendesign_reader grant in 101_gendesign_reader_role.sql.';
|
||||||
|
|
||||||
|
COMMIT;
|
||||||
Loading…
Add table
Reference in a new issue