-- 276: витрина лэндинга на РЕАЛЬНЫХ сделках (issue B2C-showcase). -- -- ЗАЧЕМ ТАБЛИЦА, А НЕ ВЫЧИСЛЕНИЕ В РУЧКЕ. Прогноз считается полным спайном -- оценщика: несколько пространственных SELECT'ов на КАЖДУЮ сделку. Двадцать -- сделок — это сотни запросов; на публичной ручке без авторизации это готовый -- рычаг для DoS. Поэтому пересчёт — офлайн-задача (app/tasks/landing_showcase_deals.py), -- ручка читает готовые строки. -- -- ЧЕГО ЗДЕСЬ НАМЕРЕННО НЕТ — АДРЕСА. В `deals` номер дома есть у 2.7% строк -- (620 различных адресов на 24 644 сделки), то есть «улица + дом» на витрине -- была бы додумана. Показываем район + характеристики квартиры; улицы нет -- даже колонкой, чтобы её нельзя было «на минутку» вывести. -- -- deal_quarter — ТЕКСТ КВАРТАЛА, не дата: `deals.deal_date` принимает всего 10 -- различных значений на всю таблицу (первое число квартала), то есть дня -- сделки в данных нет. Хранить date здесь значило бы отдать фронту точность, -- которой не существует. -- -- district и floor — NULLABLE. Район резолвится через FDW-вьюху чужой базы -- (gendesign_ekb_districts_geom), и её гранты уже терялись (см. C3); floor в -- части ДКП-строк пуст. Правило проекта: нет величины — пишем NULL, а не -- правдоподобное значение. Отбор в задаче ранжирует такие строки ниже, но не -- запрещает их: пустая витрина хуже витрины без района. BEGIN; -- Конвенция проекта (#2752): блокирующий DDL идёт под lock_timeout, иначе он -- встанет в очередь за чужой сессией и утащит за собой запросы приложения. SET LOCAL lock_timeout = '5s'; CREATE TABLE IF NOT EXISTS landing_showcase_deals ( id bigserial PRIMARY KEY, computed_at timestamptz NOT NULL DEFAULT now(), district text, rooms integer NOT NULL, area_m2 numeric(8, 2) NOT NULL, floor integer, total_floors integer, deal_quarter text NOT NULL, predicted_rub bigint NOT NULL, fact_rub bigint NOT NULL, err_pct numeric(6, 2) NOT NULL, n_analogs integer NOT NULL, note text NOT NULL ); -- Ручка всегда читает ПОСЛЕДНИЙ пересчёт (max computed_at) — старые батчи -- остаются для сверки «что показывали неделю назад». CREATE INDEX IF NOT EXISTS idx_landing_showcase_deals_computed_at ON landing_showcase_deals (computed_at DESC); COMMIT;