← Задача 009 — все материалы · оригинал на GitHub

🏠 Отдельная база знаний по недвижимости — предложение

⚡ Коротко


1️⃣ Варианты отделения

Общий пример для всех вариантов

Квартира Район До пляжа € в месяц с коммуналкой На весну 2027
TAKSIM-2222 la Barceloneta 380 м 2 830 ❌ нет в поиске
ANFA-907 Born (la Ribera) 1,2 км 3 160 ✅
CERET-1256 Gòtic 1,8 км 2 460 ✅
GRAGNANO-1362 Poblenou 2,0 км 3 070 ✅
JABI-2660 Sant Antoni 2,3 км 3 100 ✅
SAHORO-678 Vila de Gràcia 4,3 км 3 115 ✅

Вариант А — изолированный источник в существующей базе gbrain (cheaptrip)

Что это и как работает

Пример — вопрос Ирины

  1. Агент в проекте недвижимости вызывает MCP gbrain (свой токен) — list_pages {type: listing, where: {agency: ukio}}.
    • where открыт только на полной поверхности, через request_tools.
    • where — только равенство. 🔮 По списку purposes ([rent_for_us]) такой фильтр, вероятно, не отберёт — отбор по назначению делает агент.
  2. list_pages не отдаёт frontmatter (ops/pages.ts). Чтобы узнать координаты, агент вызывает get_page по каждой из 6 страниц.
  3. Расстояние до пляжа агент считает сам: в gbrain нет гео.
  4. Ответ — таблица в чате. Карту всё равно строит отдельный скрипт по файлам.

Польза

Что поставить и поддерживать

Риски

Как откатить

Вариант Б — отдельная база gbrain (свой GBRAIN_HOME, MCP по stdio)

Что это и как работает

Пример — вопрос Ирины

Польза

Что поставить и поддерживать

Риски

Как откатить

Вариант В — без gbrain: markdown + JSON в git + HTML-карта

Что это и как работает

Пример — вопрос Ирины

  1. Агент запускает скрипт, 🔮 условное имя SCRIPT-realestate-list-listings-sorted-by-distance-to-beach.py --agency ukio --purposes rent_for_us. Или читает один JSON-реестр объявлений и считает сам.
  2. Ответ — таблица выше плюс ссылка на карту с фильтром «Ukio / аренда для нас».
  3. Ирина открывает карту, видит точки и пляж, сравнивает соседние квартиры.

Польза

Что поставить и поддерживать

Риски

Как откатить

Вариант Г — поэтапный: В сейчас, Б потом, если понадобится (✅ рекомендую)

Что это и как работает

Пример — вопрос Ирины

Польза

Что поставить и поддерживать

Риски

Как откатить

📊 Сравнение

А · источник в cheaptrip Б · отдельная база gbrain В · файлы без gbrain Г · поэтапно (В → Б)
Отдельность от других баз 🟡 логическая: база общая, держится на гранте токена ✅ полная ✅ полная ✅ полная
Гео: карта, район, расстояние, цена «от–до» ❌ в gbrain нет — внешний скрипт ❌ в gbrain нет — внешний скрипт ✅ скрипт и карта ✅ скрипт и карта
Фильтр по назначению и району 🟡 where, только равенство 🟡 where, только равенство ✅ любой, в JSON и на карте ✅ любой
Поиск словами по-русски ❌ язык общий, переключение трогает cheaptrip ✅ свой язык russian 🟡 grep, без форм слов 🟡 → ✅ на этапе 2
Поиск по смыслу ❌ выключен, ключей нет ❌ выключен ❌ ❌
Новые постоянные процессы 0 0 (stdio) 0 0
Работа в двух сессиях сразу ✅ ❌ замок PGLite ✅ ✅ (на этапе 2 — ❌)
Риск для cheaptrip 🔴 общая база, админ-действия через её сервер 🟡 только если ошибиться с mcp expose / setup-gbrain ✅ нет ✅ нет
Что поддерживать источник, токен, sync, бэкап cheaptrip папка базы, sync, миграции, бэкап скрипты и правило скрипты и правило; потом как Б
Откат sources archive, отзыв токена удалить папку и запись MCP удалить репозиторий удалить репозиторий
Цена в часах на старте, 🔮 2–3 ч + риск остановки cheaptrip 2–3 ч + скрипты карты всё равно 4–6 ч на скрипты 4–6 ч, этап 2 ещё 2–3 ч

🧭 Моё мнение — вариант Г

Главный довод:

Против А (источник в базе cheaptrip):

Против Б (отдельная база gbrain сразу):

Против В (файлы без правил формата):

Против подварианта «mount»:


2️⃣ Модель данных

Сущности

Сущность Что это Ключ Главные поля Связи
apartment — квартира физический объект apartment_id = нынешний property_id (не меняем); в будущем — 20 символов кадастрового номера этаж, дверь, комнаты, м², purposes, lat/lon, geo_precision → building, → area, ← listing
listing — объявление предложение агентства или сайта listing_id (idealista-<номер>, ukio-<код>) портал, URL, deal_type, цена, коммуналка, депозит, свободна с/по, seen_at, история цены → apartment, → agency, → agent
building — дом дом или участок 14 символов кадастрового номера нормализованный адрес, другие адреса (угловой дом), lat/lon, лифт, год → area, ← apartment
area — район barri Барселоны codi_barri (Open Data BCN) nom_barri, округ, впечатления, расстояние до пляжа ← building, ← apartment
agent — агент человек contact_id (из реестра контактов, не меняем) языки, канал, скорость ответа, комиссия, торгуется ли → agency, ← deal
agency — агентство компания company_id (из реестра компаний) сайт, адрес офиса, lat/lon офиса ← agent, ← listing
visit — просмотр одно посещение visit_id дата и время UTC, кто был, впечатление → apartment или listing
deal — переговоры наши переговоры по одному или нескольким объявлениям deal_id назначение, стадия, предложения (дата, сумма, условия), итог outcome, lost_by, lost_reason → listing (одно или пакет), → agent, → agency
search — требования поиска что ищем search_id назначение, бюджет, районы, срок, обязательное, прописка ← deal, фильтр карты
event — событие хронологии одна датированная строка дата + entity_id + источник суть, msg_id доказательства → любая сущность

Где живёт истина — правило «один факт — одно место»

Что за факт Где живёт (единственное место) Кто пишет На страницах и карте
Что сказано в переписке WhatsApp: квартиры, ссылки, цены, просмотры, контакты, компании, роли, доказательства cl-cons-whats/realestate-registry/*.json — как сейчас агент задач 003–008 и скрипт черновиков копия, генерируется скриптом, руками не правится
Координаты, точность точки, codi_barri, дом (кадастровый номер), нормализованный адрес новый репо: реестр гео по property_id / listing_id скрипт геокодирования генерируется
Объявления не из WhatsApp: Ukio, ссылки Константина новый репо: реестр объявлений с сайтов агент по ссылке Константина (открытая страница) генерируется
Переговоры: стадия, предложения, итог, причина новый репо: реестр сделок агент со слов Константина и по переписке генерируется
Требования поиска (бюджет, районы, срок) новый репо: реестр требований агент со слов Константина генерируется
События хронологии новый репо: журнал событий .jsonl, только дописывается (как HISTORY-…jsonl сейчас) скрипт (из дат реестров) и агент (слова Константина) генерируется ниже <!-- timeline -->
Впечатления, оценки, стиль агента, открытые вопросы только страница, ручная зона агент со слов Константина пишется руками
Кто такой человек, VIP, к какой теме cl-cons-whats/_cons-project-context/1N-person-…md агент со слов Константина страница агента даёт ссылку, не копию
Факты квартиры для сабаренды соседний репо cl-cons-barceloneta-apartment-sublet-listings как сейчас ссылка, не копия

Довод Константина за отдельность — что с ним при такой схеме


3️⃣ Назначения и фильтр по назначению

Значение в списке purposes Что это Откуда данные На карте
buy Ирина покупает квартиру на Барселонете у пляжа реестры WhatsApp, тема buying_apartment_in_barceloneta (19 квартир) 🔴 точки на домах
rent_for_us снять квартиру весной 2027 Ukio и другие сайты, вручную; позже — агенты аренды 🔵 точки
my_current_rental квартира Давида Гарсии, которую снимает Константин реестры WhatsApp, тема my_current_rental (1 квартира) 🟢 точка уровня «район», без адреса (вопрос 6)
sublet_my_flat Константин сдаёт ту же квартиру сам соседний репо сабаренды — только ссылка та же зелёная точка, отметка «сдаём 27.10.2026 – 03.04.2027»

4️⃣ Гео

Как получаем координаты — по порядку надёжности

  1. Со страницы объявления. У Ukio в коде страницы есть schema.org geo (широта и долгота), но улица без номера. Пишем geo_precision: street (🔮 сайт не говорит, что это точный дом).
  2. Геокодер по адресу с номером дома, бесплатно и без ключа:
    • ICGC Geocoder — официальный для Каталонии, отдаёт нормализованную улицу и номер;
    • Nominatim — запасной, по его правилам: не чаще 1 запроса в секунду, свой User-Agent, результат кэшировать, массово не геокодировать.
    • Для нас это десятки адресов — не «массово».
    • Пишем geo_precision: building.
  3. Кадастр (Catastro) — ключ дома. По адресу или по координатам он отдаёт кадастровый номер (14 символов — дом, 20 — квартира) без ключа API.
    • Решает «угловой дом с двумя адресами»: проверено на тестовом угловом доме Sant Carles 10 / Pescadors 13 (не наш объект).
    • Связывает две квартиры одного дома: Atlàntida 97-99 ×2, Grau i Torras 47-49 и Lucas Fox «Grau i Torras 47».
  4. Только улица без номера (Pescadors) — точка в середине улицы, geo_precision: street.
  5. Адреса нет (квартира Давида) — центр района, geo_precision: area.

Как район привязывается к объекту

Как фильтруем и группируем

Проблема тайлов при открытии двойным кликом (file://)


5️⃣ Кто и как пополняет базу

Поток данных

  1. Константин запускает выгрузку WhatsApp (wacli sync — только он сам).
  2. Агент в cl-cons-whats, как сейчас:
    • SCRIPT-whatsapp-update-registry-all-steps.py → новая переписка и черновики по ссылкам;
    • разбор переписки → правка реестров realestate-registry/ с доказательствами.
  3. Агент в новом репо запускает одну сборку (🔮 условное имя SCRIPT-realestate-rebuild-geo-pages-and-map.py):
    • читает реестры cl-cons-whats — только чтение, по абсолютному пути;
    • геокодирует новые адреса (кэш, пауза 1 с) и считает район;
    • пересобирает генерируемые зоны страниц и хронологию;
    • собирает HTML-карту;
    • проверяет ссылки, lost_reason, ручные правки в генерируемых зонах.
  4. Объявления с сайтов (Ukio и другие) — вручную:
    • Константин присылает ссылку или просит «найди на весну 2027»;
    • агент читает открытую страницу без входа и форм и пишет объявление с датой просмотра seen_at;
    • у объявления stale_after = 30 дней: цены Ukio динамические.
  5. Слова Константина («были на просмотре, шумно», «предложили 280») → агент пишет событие в журнал, обновляет сделку и ручную зону страницы.

Ручная работа в неделю — 🔮 оценка

Кто Что Время, 🔮
Константин выгрузка WhatsApp, ответы на 1–3 вопроса агента, пара фраз о просмотрах 10–20 мин
Агент разбор новой переписки в реестры (как сейчас) 15–30 мин
Агент 2–5 новых объявлений с сайтов, сборка, проверка 10–20 мин
Итого ручного у Константина ~15 мин

6️⃣ Имя и место репозитория

Вариант Плюсы Минусы
✅ cl-cons-realestate-barcelona-apartments-and-agents слово области первым; город; две главные сущности — квартиры и агенты; без жаргона длинновато (по длине как соседний cl-cons-barceloneta-apartment-sublet-listings)
cl-cons-realestate-barcelona-crm-with-map короче, видно «CRM» и «карта» «crm» — жаргон; карта — вид, а не содержимое
cl-cons-realestate-knowledge-base короткое не видно ни города, ни что внутри; «knowledge base» есть у многих проектов

Структура папок — на утверждение

cl-cons-realestate-barcelona-apartments-and-agents/
├── README.md, CLAUDE.md, AGENTS.md, CHANGELOG.md, log.md
├── RULES-realestate-one-fact-one-place-registries-generate-pages.md
├── realestate-registry-local/
├── realestate-pages/
│   ├── apartments/   buildings/   areas/
│   ├── people/   companies/   deals/   searches/
├── realestate-geo-data/
├── realestate-scripts/
├── _cons-output-realestate-map/
├── _cons-project-context/
└── _cons-changes/
Папка или файл Польза — что даёт в работе
README.md Константин открывает и видит: что ищем, сколько объектов по назначениям, ссылка на карту
CLAUDE.md + AGENTS.md любой агент (Claude, Codex, Cursor) с первой минуты знает, где истина и что руками не правят
RULES-realestate-one-fact-one-place-…md правило «один факт — одно место» записано один раз; на него ссылаются скрипт проверки и агенты
realestate-registry-local/ свои JSON: гео, объявления с сайтов, сделки, требования, журнал событий. Всё, чего нет в переписке, в одном месте
realestate-pages/<тип>/ страницы, которые читает человек и находит grep; папка = тип страницы, потому при этапе 2 gbrain берёт их как есть
realestate-geo-data/ границы barris и кэш геокодера: карта и расчёт района работают без повторных запросов в сеть
realestate-scripts/ одна команда пересобирает всё; руками ничего не копируется
_cons-output-realestate-map/ готовая карта — одним файлом, открыть двойным кликом
_cons-project-context/ цель «купить у пляжа», критерии аренды, люди — без повторения из cl-cons-whats, указателями
_cons-changes/ задачи по базе, как во всех проектах

7️⃣ Что делать дальше — после ответов Константина

  1. Записать ответы в справочник решений проекта и в README задачи 009.
  2. Если выбран вариант Г или В — создать репозиторий под утверждённым именем и с утверждённой структурой. Шапки OKF, AGENTS.md рядом с CLAUDE.md, указатели .LINK.md на общие правила.
  3. Написать правило «один факт — одно место» и скрипты:
    • сначала геокодирование с кэшем и расчёт района;
    • затем сборка карты из реестров — прототип координатора станет шаблоном;
    • затем сборка страниц с ручной зоной;
    • затем проверка.
  4. Перенести в рабочую базу объекты прототипа: 6 кандидатов на покупку с Барселонеты, 5 квартир Ukio, TAKSIM как ориентир. Квартиру Давида — по ответу на вопрос 6.
  5. Завести требования поиска (searches/) по ответам на вопросы 4–5. Заново проверить Ukio с весенними датами — нет ли новых квартир на Барселонете.
  6. Внести итог торга On Urbe и статус Sant Miquel 116 по ответам на вопросы 8–9.
  7. Независимая проверка: карта открывается двойным кликом, 2–3 точки сверены с источником, в генерируемых зонах нет ручных правок.
  8. Вариант Б (этап 2) — не делать, пока не появится один из сигналов из раздела «Вариант Г».