[{"data":1,"prerenderedAt":586},["ShallowReactive",2],{"blog-2026-07-07-aklab-ai-development":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"tags":11,"body":19,"_type":580,"_id":581,"_source":582,"_file":583,"_stem":584,"_extension":585},"\u002Fblog\u002F2026-07-07-aklab-ai-development","blog",false,"","AKLAB: как я строю автоматический мониторинг недвижимости для инвесторов","10 парсеров, 15 сервисов, 578 тестов. Как я строю платформу для инвесторов в недвижимость с помощью AI.","2026-07-07",[12,13,14,15,16,17,18],"aklab","ai","разработка","strapi","vue","недвижимость","инвестиции",{"type":20,"children":21,"toc":570},"root",[22,30,35,40,49,56,61,66,72,77,236,241,246,268,274,279,284,295,300,310,315,321,326,336,341,350,355,360,365,371,376,386,396,406,416,422,535,541,566],{"type":23,"tag":24,"props":25,"children":26},"element","p",{},[27],{"type":28,"value":29},"text","Я делаю сервис мониторинга инвестиционной недвижимости — AKLAB. Он автоматически находит объекты, которые стоят значительно ниже рыночных эталонов. Парсит 10 федеральных площадок, анализирует отклонения от эталонных цен, присылает утренний дайджест на email.",{"type":23,"tag":24,"props":31,"children":32},{},[33],{"type":28,"value":34},"Основной фокус — коммерческая недвижимость: офисы, склады, торговые помещения. Но мониторим также земельные участки и квартиры.",{"type":23,"tag":24,"props":36,"children":37},{},[38],{"type":28,"value":39},"За полтора месяца довёл проект от идеи до продакшена. Рассказываю, как устроено.",{"type":23,"tag":24,"props":41,"children":42},{},[43],{"type":23,"tag":44,"props":45,"children":48},"img",{"alt":46,"src":47},"Дашборд AKLAB — тёмная тема","\u002Fuploads\u002Faklab-dashboard-dark.png",[],{"type":23,"tag":50,"props":51,"children":53},"h2",{"id":52},"зачем",[54],{"type":28,"value":55},"Зачем",{"type":23,"tag":24,"props":57,"children":58},{},[59],{"type":28,"value":60},"Рынок инвестиционной недвижимости — это торги. Сбербанк-АСТ, Алфалот, М-ЕТС, ГИС Торги, ЕТПРФ, Инвест Москва и другие. На каждой площадке — сотни лотов. Просматривать их вручную каждый день — нереально.",{"type":23,"tag":24,"props":62,"children":63},{},[64],{"type":28,"value":65},"AKLAB делает это за меня: парсит площадки ночью, анализирует отклонения от эталонов, утром присылает результат на почту.",{"type":23,"tag":50,"props":67,"children":69},{"id":68},"архитектура",[70],{"type":28,"value":71},"Архитектура",{"type":23,"tag":24,"props":73,"children":74},{},[75],{"type":28,"value":76},"Один репозиторий, 15 PM2-процессов:",{"type":23,"tag":78,"props":79,"children":80},"table",{},[81,105],{"type":23,"tag":82,"props":83,"children":84},"thead",{},[85],{"type":23,"tag":86,"props":87,"children":88},"tr",{},[89,95,100],{"type":23,"tag":90,"props":91,"children":92},"th",{},[93],{"type":28,"value":94},"Компонент",{"type":23,"tag":90,"props":96,"children":97},{},[98],{"type":28,"value":99},"Порт",{"type":23,"tag":90,"props":101,"children":102},{},[103],{"type":28,"value":104},"Описание",{"type":23,"tag":106,"props":107,"children":108},"tbody",{},[109,128,146,164,182,200,218],{"type":23,"tag":86,"props":110,"children":111},{},[112,118,123],{"type":23,"tag":113,"props":114,"children":115},"td",{},[116],{"type":28,"value":117},"Frontend (Vue 3 + Vite + Tailwind)",{"type":23,"tag":113,"props":119,"children":120},{},[121],{"type":28,"value":122},":5174",{"type":23,"tag":113,"props":124,"children":125},{},[126],{"type":28,"value":127},"Dashboard, Настройки, Карточки объектов",{"type":23,"tag":86,"props":129,"children":130},{},[131,136,141],{"type":23,"tag":113,"props":132,"children":133},{},[134],{"type":28,"value":135},"Backend (Strapi 5 + SQLite)",{"type":23,"tag":113,"props":137,"children":138},{},[139],{"type":28,"value":140},":1338",{"type":23,"tag":113,"props":142,"children":143},{},[144],{"type":28,"value":145},"REST API, Admin Panel, Cron scheduler",{"type":23,"tag":86,"props":147,"children":148},{},[149,154,159],{"type":23,"tag":113,"props":150,"children":151},{},[152],{"type":28,"value":153},"10 парсеров (Playwright\u002Ffetch)",{"type":23,"tag":113,"props":155,"children":156},{},[157],{"type":28,"value":158},":1345–1355",{"type":23,"tag":113,"props":160,"children":161},{},[162],{"type":28,"value":163},"alfalot, torgi-gov, sberbank-ast, m-ets …",{"type":23,"tag":86,"props":165,"children":166},{},[167,172,177],{"type":23,"tag":113,"props":168,"children":169},{},[170],{"type":28,"value":171},"Analyzer",{"type":23,"tag":113,"props":173,"children":174},{},[175],{"type":28,"value":176},":1341",{"type":23,"tag":113,"props":178,"children":179},{},[180],{"type":28,"value":181},"Сравнение с эталонами",{"type":23,"tag":86,"props":183,"children":184},{},[185,190,195],{"type":23,"tag":113,"props":186,"children":187},{},[188],{"type":28,"value":189},"Digest",{"type":23,"tag":113,"props":191,"children":192},{},[193],{"type":28,"value":194},":1342",{"type":23,"tag":113,"props":196,"children":197},{},[198],{"type":28,"value":199},"Утренний email-дайджест",{"type":23,"tag":86,"props":201,"children":202},{},[203,208,213],{"type":23,"tag":113,"props":204,"children":205},{},[206],{"type":28,"value":207},"Photo",{"type":23,"tag":113,"props":209,"children":210},{},[211],{"type":28,"value":212},":1356",{"type":23,"tag":113,"props":214,"children":215},{},[216],{"type":28,"value":217},"Фото из карточек",{"type":23,"tag":86,"props":219,"children":220},{},[221,226,231],{"type":23,"tag":113,"props":222,"children":223},{},[224],{"type":28,"value":225},"Очередь",{"type":23,"tag":113,"props":227,"children":228},{},[229],{"type":28,"value":230},"—",{"type":23,"tag":113,"props":232,"children":233},{},[234],{"type":28,"value":235},"@aklab\u002Fsqlite-queue",{"type":23,"tag":24,"props":237,"children":238},{},[239],{"type":28,"value":240},"Backend — Strapi 5.44 + SQLite. Выбрал Strapi, потому что из коробки получаю REST API, админку, систему прав и кастомные контроллеры. Не нужно писать boilerplate.",{"type":23,"tag":24,"props":242,"children":243},{},[244],{"type":28,"value":245},"Frontend — Vue 3 + Vite + Tailwind. Дашборд с фильтрами по городу, цене и типу объекта, карточки с галереей фото.",{"type":23,"tag":24,"props":247,"children":248},{},[249,251,258,260,266],{"type":28,"value":250},"Парсеры — каждый микросервис в отдельной папке, shared-модули в ",{"type":23,"tag":252,"props":253,"children":255},"code",{"className":254},[],[256],{"type":28,"value":257},"_shared\u002F",{"type":28,"value":259},". Один манифест ",{"type":23,"tag":252,"props":261,"children":263},{"className":262},[],[264],{"type":28,"value":265},"services.json",{"type":28,"value":267}," управляет портами, health-checks и PM2-конфигом.",{"type":23,"tag":50,"props":269,"children":271},{"id":270},"парсинг",[272],{"type":28,"value":273},"Парсинг",{"type":23,"tag":24,"props":275,"children":276},{},[277],{"type":28,"value":278},"Ночью запускаются 10 парсеров одновременно. Каждый обходит свою площадку, находит новые лоты и проверяет обновления старых.",{"type":23,"tag":24,"props":280,"children":281},{},[282],{"type":28,"value":283},"Парсинг работает в две фазы — и это не просто «скан, потом загрузка». Это принципиальное решение, которое экономит время и ресурсы.",{"type":23,"tag":24,"props":285,"children":286},{},[287,293],{"type":23,"tag":288,"props":289,"children":290},"strong",{},[291],{"type":28,"value":292},"Phase 1 — Scan.",{"type":28,"value":294}," Парсер обходит ленту площадки и собирает только карточные данные: цена, площадь, адрес, тип помещения. Тут же, на лету, применяет фильтры. Не попадает в нужный регион — отбрасывается. Площадь меньше минимума — отбрасывается. Цена выше порога — отбрасывается. Стоп-слова в названии — отбрасывается. Всё это происходит до того, как я потратил хоть одну лишнюю секунду на детальную выгрузку.",{"type":23,"tag":24,"props":296,"children":297},{},[298],{"type":28,"value":299},"Типичный сценарий: площадка выдаёт 200 лотов по всей России. После фильтрации по региону (Москва + МО) остаётся 30. После фильтрации по площади и цене — 12. Именно эти 12 и пойдут во вторую фазу, а не все 200.",{"type":23,"tag":24,"props":301,"children":302},{},[303,308],{"type":23,"tag":288,"props":304,"children":305},{},[306],{"type":28,"value":307},"Phase 2 — Fetch Details.",{"type":28,"value":309}," Для каждого прошедшего фильтр лота парсер заходит в карточку и забирает полное описание, фотографии, документы, условия торгов. Это дорогая операция — каждый запрос это реальный HTTP-запрос к площадке, с ожиданием загрузки, иногда с обходом JavaScript-рендеринга через Playwright.",{"type":23,"tag":24,"props":311,"children":312},{},[313],{"type":28,"value":314},"Две фазы позволяют не грузить детали для объектов, которые заведомо не подходят. На некоторых площадках фильтрация отсекает 80–90% лотов ещё на этапе scan.",{"type":23,"tag":50,"props":316,"children":318},{"id":317},"скоринг",[319],{"type":28,"value":320},"Скоринг",{"type":23,"tag":24,"props":322,"children":323},{},[324],{"type":28,"value":325},"После парсинга analyzer оценивает каждый объект по сравнению с эталонными ценами.",{"type":23,"tag":24,"props":327,"children":328},{},[329,334],{"type":23,"tag":288,"props":330,"children":331},{},[332],{"type":28,"value":333},"Эталоны",{"type":28,"value":335}," — это заранее заданные ориентиры стоимости за квадратный метр для каждого типа помещения в каждом регионе. Не «средняя цена по рынку», а конкретные контрольные точки, которые я веду вручную и корректирую по мере накопления данных.",{"type":23,"tag":24,"props":337,"children":338},{},[339],{"type":28,"value":340},"Для каждого объекта analyzer считает отклонение от эталона:",{"type":23,"tag":342,"props":343,"children":345},"pre",{"code":344},"deviation = (эталонная_цена − фактическая_цена) \u002F эталонная_цена × 100\n",[346],{"type":23,"tag":252,"props":347,"children":348},{"__ignoreMap":7},[349],{"type":28,"value":344},{"type":23,"tag":24,"props":351,"children":352},{},[353],{"type":28,"value":354},"Если отклонение превышает порог (например, 20%) — объект попадает в фокус. Чем больше отклонение, тем выше фокус-скор.",{"type":23,"tag":24,"props":356,"children":357},{},[358],{"type":28,"value":359},"Кроме отклонения, на скор влияют дополнительные факторы: тип торгов (банкротство vs реализация), наличие фото, полнота описания, сроки торгов. Объект с высоким отклонением, но без фотографий и с неполным описанием получит скор ниже, чем объект с аналогичным отклонением, но полной карточкой.",{"type":23,"tag":24,"props":361,"children":362},{},[363],{"type":28,"value":364},"Весь парсинг и анализ происходит ночью. Утром digest формирует email-дайджест по объектам, попавшим в фокус, и отправляет мне на почту.",{"type":23,"tag":50,"props":366,"children":368},{"id":367},"как-ai-помогает",[369],{"type":28,"value":370},"Как AI помогает",{"type":23,"tag":24,"props":372,"children":373},{},[374],{"type":28,"value":375},"Я разрабатываю AKLAB с AI-ассистентом. Вот что это даёт на практике:",{"type":23,"tag":24,"props":377,"children":378},{},[379,384],{"type":23,"tag":288,"props":380,"children":381},{},[382],{"type":28,"value":383},"Параллельная работа.",{"type":28,"value":385}," AI одновременно пишет код для нескольких сервисов — парсера, analyzer, фронтенд-компонента. Я ревьюю результат, а не пишу с нуля.",{"type":23,"tag":24,"props":387,"children":388},{},[389,394],{"type":23,"tag":288,"props":390,"children":391},{},[392],{"type":28,"value":393},"Документация.",{"type":28,"value":395}," После каждого изменения AI обновляет внутреннюю документацию: архитектурные решения, known issues, deployment notes. Всё актуально в каждый момент времени.",{"type":23,"tag":24,"props":397,"children":398},{},[399,404],{"type":23,"tag":288,"props":400,"children":401},{},[402],{"type":28,"value":403},"Тесты.",{"type":28,"value":405}," AI генерирует тесты параллельно с кодом. Не «напиши потом тесты» — а сразу вместе с фичей.",{"type":23,"tag":24,"props":407,"children":408},{},[409,414],{"type":23,"tag":288,"props":410,"children":411},{},[412],{"type":28,"value":413},"Деплой.",{"type":28,"value":415}," Один скрипт: коммит, пуш, npm install, build 10 сервисов, перезапуск PM2, health-check. 3–5 минут от команды до рабочего продакшена.",{"type":23,"tag":50,"props":417,"children":419},{"id":418},"цифры",[420],{"type":28,"value":421},"Цифры",{"type":23,"tag":78,"props":423,"children":424},{},[425,441],{"type":23,"tag":82,"props":426,"children":427},{},[428],{"type":23,"tag":86,"props":429,"children":430},{},[431,436],{"type":23,"tag":90,"props":432,"children":433},{},[434],{"type":28,"value":435},"Метрика",{"type":23,"tag":90,"props":437,"children":438},{},[439],{"type":28,"value":440},"Значение",{"type":23,"tag":106,"props":442,"children":443},{},[444,457,470,483,496,509,522],{"type":23,"tag":86,"props":445,"children":446},{},[447,452],{"type":23,"tag":113,"props":448,"children":449},{},[450],{"type":28,"value":451},"Версия",{"type":23,"tag":113,"props":453,"children":454},{},[455],{"type":28,"value":456},"v1.1.43",{"type":23,"tag":86,"props":458,"children":459},{},[460,465],{"type":23,"tag":113,"props":461,"children":462},{},[463],{"type":28,"value":464},"PM2-процессов",{"type":23,"tag":113,"props":466,"children":467},{},[468],{"type":28,"value":469},"15",{"type":23,"tag":86,"props":471,"children":472},{},[473,478],{"type":23,"tag":113,"props":474,"children":475},{},[476],{"type":28,"value":477},"Активных парсеров",{"type":23,"tag":113,"props":479,"children":480},{},[481],{"type":28,"value":482},"10",{"type":23,"tag":86,"props":484,"children":485},{},[486,491],{"type":23,"tag":113,"props":487,"children":488},{},[489],{"type":28,"value":490},"Площадок",{"type":23,"tag":113,"props":492,"children":493},{},[494],{"type":28,"value":495},"10 федеральных",{"type":23,"tag":86,"props":497,"children":498},{},[499,504],{"type":23,"tag":113,"props":500,"children":501},{},[502],{"type":28,"value":503},"Тестов",{"type":23,"tag":113,"props":505,"children":506},{},[507],{"type":28,"value":508},"578",{"type":23,"tag":86,"props":510,"children":511},{},[512,517],{"type":23,"tag":113,"props":513,"children":514},{},[515],{"type":28,"value":516},"Коммитов",{"type":23,"tag":113,"props":518,"children":519},{},[520],{"type":28,"value":521},"200+",{"type":23,"tag":86,"props":523,"children":524},{},[525,530],{"type":23,"tag":113,"props":526,"children":527},{},[528],{"type":28,"value":529},"Время от идеи до prod",{"type":23,"tag":113,"props":531,"children":532},{},[533],{"type":28,"value":534},"1.5 месяца",{"type":23,"tag":50,"props":536,"children":538},{"id":537},"что-дальше",[539],{"type":28,"value":540},"Что дальше",{"type":23,"tag":542,"props":543,"children":544},"ul",{},[545,551,556,561],{"type":23,"tag":546,"props":547,"children":548},"li",{},[549],{"type":28,"value":550},"Email-дайджест с аналитикой по трендам",{"type":23,"tag":546,"props":552,"children":553},{},[554],{"type":28,"value":555},"Расширение на больше площадок и регионов",{"type":23,"tag":546,"props":557,"children":558},{},[559],{"type":28,"value":560},"API для партнёров",{"type":23,"tag":546,"props":562,"children":563},{},[564],{"type":28,"value":565},"Предсказание доходности на основе исторических данных",{"type":23,"tag":567,"props":568,"children":569},"hr",{},[],{"title":7,"searchDepth":571,"depth":571,"links":572},2,[573,574,575,576,577,578,579],{"id":52,"depth":571,"text":55},{"id":68,"depth":571,"text":71},{"id":270,"depth":571,"text":273},{"id":317,"depth":571,"text":320},{"id":367,"depth":571,"text":370},{"id":418,"depth":571,"text":421},{"id":537,"depth":571,"text":540},"markdown","content:blog:2026-07-07-aklab-ai-development.md","content","blog\u002F2026-07-07-aklab-ai-development.md","blog\u002F2026-07-07-aklab-ai-development","md",1784082563135]