feat(tradein): SQL migration 029 — extend matching/valuation/dynamics tables (PR #445 follow-up) #448
No reviewers
Labels
No labels
admin
analytics
auth
automation
bug
business
chore
ci
compliance
data
data-moat
docs
duplicate
dx
enhancement
Fable 5 ревью
feedback/max
generative
GG-форсайт
needs-discussion
needs-human
observability
pause-bots
performance
priority/p0
priority/p1
priority/p2
priority/p3
scope/backend
scope/db
scope/devops
scope/frontend
scope/qa
scrapers
security
site-finder
stage/1
stage/2
status/blocked
status/done
status/needs-analysis
status/needs-fix
status/qa
status/ready
status/review
status/wip
tech-debt
tradein
ux
week ревью 1
wontfix
вторичка
ИРД
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: lekss361/gendesign#448
Loading…
Add table
Reference in a new issue
No description provided.
Delete branch "feat/tradein-sql-029-extend-matching-valuation"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Follow-up к PR #445 (Stage 1 SQL migrations). Addresses 3 MEDIUM follow-ups from deep-code-reviewer + 1 missing column для Tier-0 matching.
Blocks Wave 4-6 stages (cian_detail/newbuilding/valuation scrapers + matching service).
Sections
house_sourcesALTERlisting_sourcesALTERexternal_valuationsALTERhouses_price_dynamicsALTERhousesALTERIdempotency
Section D — единственное non-trivial место. Wrapped в
DO $$ ... $$block:houses_price_dynamics_house_id_month_date_source_keyif existshouses_price_dynamics_dim_keyUNIQUE on(house_id, source, room_count, prices_type, period, month_date)if not existsroom_count='all',prices_type='priceSqm',period='allTime'Re-running migration safe.
Deviations from spec
room_counttypedtextnotint— vault sec 16.3 specifies text enum values ('studio'/'oneRoom'/'twoRoom') matching Cian's API. Avoids mapping layer bug.listing_sources.last_seen_atдублирует существующийlast_scraped_at— kept both для backward compat (existing code reads last_scraped_at; new code uses semantic alias).external_house_idtypedbigintnottext— Cian'shouseIdis always integer per vault sec 26.3.Refs
decisions/Cross_Source_Matching_Strategy.mdsec 2.1, 2.2decisions/Schema_Cian_SERP_Inventory.mdsec 16.3, 26Test plan
houses_price_dynamicsrows survive UNIQUE replacement (backfill UPDATE in migration)Merged via deep-code-reviewer — verdict APPROVE.
Section D verification (UNIQUE constraint replacement):
houses_price_dynamics_house_id_month_date_source_key— confirmed correct (PG auto-generated from anonymousUNIQUE (house_id, month_date, source)in024_houses_price_dynamics.sql:19)(room_count='all', prices_type='priceSqm', period='allTime')so 6-col UNIQUE projection still unique by(house_id, month_date, source)— no dup violationpg_constraintcheck usesconrelid::regclass— schema-safePaths trigger:
.forgejo/workflows/deploy-tradein.ymlfiltertradein-mvp/**catchestradein-mvp/backend/data/sql/029_*.sql— deploy will trigger.Dependencies verified: tables
houses_price_dynamics(024),house_sources+listing_sources(028),external_valuations(026),houses(009) all exist with expected column names.cadastral_numberabsent from 009/020 — new column legitimate.Vault cross-check:
decisions/Schema_Cian_SERP_Inventory.md sec 16.3confirms exact UNIQUE shape(house_id, source, room_count, prices_type, period, month_date)and text enumroom_countvalues — PR matches spec identically.MINOR (non-blocking):
room_counttext enum — typo risk delegated to app-layer Pydantic enum (spec also defers)last_seen_atvslast_scraped_atredundancy — explicit in PR body, dual-write should be enforced in scraper codePost-deploy SQL verification (recommended):
SELECT count(*) FROM houses_price_dynamics WHERE room_count IS NULL;→ 0\d houses_price_dynamics→houses_price_dynamics_dim_keyUNIQUE present, old..._keygoneSELECT cadastral_number FROM houses LIMIT 5;→ column exists