[EPIC] market — контракт данных скрапперов для внешних потребителей #2127

Closed
opened 2026-07-02 13:39:25 +00:00 by lekss361 · 2 comments
Owner

Цель

Дать другим продуктам (gendesign site-finder + будущие) данные скрапперов через стабильный контракт, не связывая их с внутренней схемой. Паттерн write-model / read-model (CQRS-lite).

Контекст / решение

ADR 2026-07-02 (Anton): «движок в скрапперах, другим нужны только данные». Решение по БД (подтверждено): схема market в существующем tradein-postgres, НЕ отдельная БД/инстанс (RAM Beget VPS; данные отдаём через контракт+роль, не через СУБД).

Целевая картина

  • Кухня (listings/houses/snapshots/scrape_runs, схема public) = internal write-model. Снаружи напрямую не читается. listings НЕ двигаем — джойны estimator.py + matching/.
  • market schema = публичный контракт: market.v_* contract-view поверх producer-таблиц (стабильные колонки, изолируют от churn) + enrichment-таблицы (yandex_jk_enrichment уже есть) + matview для тяжёлой аналитики.
  • Роль gendesign_reader (уже есть, миграции 101/102) — но сейчас гранится на сырые таблицы → перенацелить на market.v_*.
  • Канал: co-located → GRANT; remote (gendesign) → FDW IMPORT FOREIGN SCHEMA market (postgres_fdw стоит, server gendesign_remote обратный — нужен встречный) ИЛИ psycopg-ETL (#976 вариант A).

Текущее состояние (не с нуля)

  • market schema существует (миграция 105), в ней yandex_jk_enrichment.
  • gendesign_reader role (101) + GRANT SELECT на 5 сырых таблиц (102): houses, house_sources, houses_price_dynamics, house_reliability_checks, house_reviews.
  • gendesign уже тянет tradein-данные: newbuilding_crossload.py ETL, premises_lookup, competitors.

Под-issues

  • #I Contract-view market.v_* поверх 5 producer-таблиц (стабильный shape) — status/ready (независимо от пакета)
  • #J Перенацелить gendesign_reader на market.v_* (REVOKE сырые → GRANT view) + обновить cross-load ETL #976 — depends #I
  • (follow-up) matview + refresh для тяжёлой cross-product аналитики — p3

Что НЕ делать

  • Физически двигать listings/houses в отдельную схему (джойны estimator; контракт = view-прослойка, не relocation)
  • 3-й postgres-инстанс
  • Revoke сырых таблиц ДО переключения ETL на view (порядок деплоя: view+grant+ETL-switch, ПОТОМ revoke)

Источники

  • ADR: vault decisions/ (scraper-kit + market contract, 2026-07-02)
  • Связано: Epic A (scraper-kit), issue #976 (cross-load ETL), #974 (market.yandex_jk_enrichment)
## Цель Дать другим продуктам (gendesign site-finder + будущие) **данные** скрапперов через стабильный контракт, не связывая их с внутренней схемой. Паттерн write-model / read-model (CQRS-lite). ## Контекст / решение ADR 2026-07-02 (Anton): «движок в скрапперах, другим нужны только данные». Решение по БД (подтверждено): **схема `market` в существующем tradein-postgres**, НЕ отдельная БД/инстанс (RAM Beget VPS; данные отдаём через контракт+роль, не через СУБД). ## Целевая картина - **Кухня** (`listings`/`houses`/`snapshots`/`scrape_runs`, схема public) = internal write-model. Снаружи напрямую не читается. `listings` НЕ двигаем — джойны estimator.py + matching/. - **`market` schema = публичный контракт**: `market.v_*` contract-view поверх producer-таблиц (стабильные колонки, изолируют от churn) + enrichment-таблицы (`yandex_jk_enrichment` уже есть) + matview для тяжёлой аналитики. - **Роль** `gendesign_reader` (уже есть, миграции 101/102) — но сейчас гранится на **сырые** таблицы → перенацелить на `market.v_*`. - **Канал**: co-located → GRANT; remote (gendesign) → FDW `IMPORT FOREIGN SCHEMA market` (postgres_fdw стоит, server `gendesign_remote` обратный — нужен встречный) ИЛИ psycopg-ETL (#976 вариант A). ## Текущее состояние (не с нуля) - `market` schema существует (миграция 105), в ней `yandex_jk_enrichment`. - `gendesign_reader` role (101) + GRANT SELECT на 5 сырых таблиц (102): houses, house_sources, houses_price_dynamics, house_reliability_checks, house_reviews. - gendesign уже тянет tradein-данные: `newbuilding_crossload.py` ETL, `premises_lookup`, `competitors`. ## Под-issues - [ ] #I Contract-view `market.v_*` поверх 5 producer-таблиц (стабильный shape) — **status/ready** (независимо от пакета) - [ ] #J Перенацелить `gendesign_reader` на `market.v_*` (REVOKE сырые → GRANT view) + обновить cross-load ETL #976 — depends #I - [ ] (follow-up) matview + refresh для тяжёлой cross-product аналитики — p3 ## Что НЕ делать - ❌ Физически двигать listings/houses в отдельную схему (джойны estimator; контракт = view-прослойка, не relocation) - ❌ 3-й postgres-инстанс - ❌ Revoke сырых таблиц ДО переключения ETL на view (порядок деплоя: view+grant+ETL-switch, ПОТОМ revoke) ## Источники - ADR: vault `decisions/` (scraper-kit + market contract, 2026-07-02) - Связано: Epic A (scraper-kit), issue #976 (cross-load ETL), #974 (market.yandex_jk_enrichment)
lekss361 added the
data
enhancement
scope/db
tradein
labels 2026-07-02 13:41:48 +00:00
Author
Owner

Волна 1 смержена + QA PASS (2026-07-02):

  • #2130 (шаг I, contract-views) — PR #2141. На проде: market.v_houses 11769, v_house_sources 60165, v_houses_price_dynamics 180, v_house_reliability_checks 111, v_house_reviews 188 — все 5 view живы, миграция 154 применена.

Разблокирован шаг J (#2138, перенацелить reader + ETL). Придерживаю до отдельного фокуса — J требует критичного порядка деплоя (2 деплоя: view+grant+ETL-switch, ПОТОМ revoke сырых), не запускаю в общей волне.

**Волна 1 смержена + QA PASS (2026-07-02):** - ✅ #2130 (шаг I, contract-views) — PR #2141. На проде: `market.v_houses` 11769, `v_house_sources` 60165, `v_houses_price_dynamics` 180, `v_house_reliability_checks` 111, `v_house_reviews` 188 — все 5 view живы, миграция 154 применена. **Разблокирован шаг J (#2138, перенацелить reader + ETL).** Придерживаю до отдельного фокуса — J требует критичного порядка деплоя (2 деплоя: view+grant+ETL-switch, ПОТОМ revoke сырых), не запускаю в общей волне.
Author
Owner

Трек J завершён end-to-end на проде — Epic закрыт (2026-07-02).

3 контролируемых деплоя с QA-гейтами между:

  • 1/3 GRANT (PR #2147, миграция 155) — reader получил SELECT на market.v_*
  • 2/3 ETL-switch (PR #2148) — newbuilding_crossload читает market.v_* (прямой psycopg, не FDW); реальный прогон 8224/8224/0
  • 3/3 REVOKE (PR #2149, миграция 156) — сырые public.* отозваны

Финальная проверка на проде: все 5 сырых таблиц под gendesign_readerpermission denied, контракт market.v_* цел (11769, join 60165), ETL re-run чистый (8224/8224/0), 0 новых ошибок. listings/offer_price_history (грант 102, Site Finder #1191) осознанно не тронуты.

Цель Epic достигнута: потребитель (gendesign) физически видит только контракт market.v_*, не внутреннюю кухню. «Другим проектам — только данные» работает end-to-end. Follow-up (matview для тяжёлой аналитики, p3) — по мере надобности.

**Трек J завершён end-to-end на проде — Epic закрыт (2026-07-02).** 3 контролируемых деплоя с QA-гейтами между: - ✅ 1/3 GRANT (PR #2147, миграция 155) — reader получил SELECT на `market.v_*` - ✅ 2/3 ETL-switch (PR #2148) — `newbuilding_crossload` читает `market.v_*` (прямой psycopg, не FDW); реальный прогон 8224/8224/0 - ✅ 3/3 REVOKE (PR #2149, миграция 156) — сырые `public.*` отозваны Финальная проверка на проде: все 5 сырых таблиц под `gendesign_reader` → **permission denied**, контракт `market.v_*` цел (11769, join 60165), ETL re-run чистый (8224/8224/0), 0 новых ошибок. `listings`/`offer_price_history` (грант 102, Site Finder #1191) осознанно не тронуты. **Цель Epic достигнута:** потребитель (gendesign) физически видит только контракт `market.v_*`, не внутреннюю кухню. «Другим проектам — только данные» работает end-to-end. Follow-up (matview для тяжёлой аналитики, p3) — по мере надобности.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#2127
No description provided.