Привет, Хабр. На связи Маша Лещинская, Head of QA в Surf. Мы все любим пет-проекты, и еще больше — пет-проекты на AI. Но есть нюанс: большинство таких штук забываются через неделю, потому что их сложно и дорого поддерживать. Я сделала проект, который живёт уже третий месяц, и причина не в каких-то крутых технологиях, а в том, что цена поддержки стала минимальной.

Рассказываю, как пришла идея и что из этого вышло. Больше инсайтов от меня и других руководителей разработки ищите в Телеграмм-канале «Директорат Surf обсуждает».

Сначала — предыстория

У нас в компании большой парк мобильных устройств – их регулярно берут QA. Когда людей и устройств становится много, все начинают путаться. Периодически нужны одни и те же модели, часть устройств уезжает домой к сотрудникам, часть лежит в офисе, у каких-то заканчивается срок возврата, а перед регрессией нужно понимать, что реально доступно.

Когда-то у нас была нормальная система бронирования: с интерфейсом, слотами и статусами. Потом она умерла. Не потому что была плохая, а потому что её нужно было поддерживать. Поддержка всегда означает чьё-то время, а во внутренних инструментах это время часто проигрывает более срочным задачам. В какой-то момент мы откатились к самому простому и честному способу координации — к чату.

Первая версия за вечер

Первую версию я собрала вечером. Стек выбрала намеренно лёгким: хотелось, чтобы в проекте не появилось ничего, что нужно регулярно обновлять, поддерживать или оплачивать только ради того, чтобы система продолжала жить:

  • Vanilla JavaScript — без фреймворков;

  • Firebase — Firestore, Hosting, Google OAuth;

  • PWA — чтобы система открывалась с телефона без установки.

Получилась реальная система: каталог устройств, бронирование в один клик, история, роли и базовые статусы. Я задеплоила её, скинула ссылку команде и честно думала, что люди немного поиграются и забудут.

Три месяца спустя: всё работает

Не забыли.

Команда продолжила пользоваться системой. Потом начали приходить запросы на фичи, всё чаще и чаще. Раньше, чтобы добавить фичу, разработчику нужно было выкроить вечер, потом ещё один, потом отложить из-за более срочных задач. Теперь это можно сделать в обеденный перерыв. 

Моя система постепенно перестала быть просто внутренним инструментом и стала живым продуктом, на котором можно проверять AI-разработку в реальных условиях.

Продолжаем развивать проект

Покажу теперь, как это все работает и из чего состоит.

Каталог с умными фильтрами

В базовой версии каталог был обычным списком устройств с поиском и фильтрами по типу, ОС и статусу. Поиск работает с задержкой не больше 200 мс, чтобы интерфейс оставался быстрым и не раздражал пользователя.

Но самое интересное началось не с базовых фильтров, а с запросов команды. Например, появился запрос: «Хочу видеть только то, чем я ещё никогда не пользовалась». Так родился фильтр «Не используемые мной».

Система анализирует историю бронирований конкретного пользователя и показывает только устройства, по которым у него ещё нет записей. Это удобно для расширения покрытия.

Ещё полезное — автоопределение устройства. Если открыть систему с телефона, она определяет ОС и подсвечивает релевантные устройства. Это не меняет весь сценарий, но убирает маленькое трение, которое обычно раздражает в повседневной работе.

Бронирование с контекстом

Бронирование работает в двух режимах: в офисе и домой. Если устройство берут в офисе, достаточно указать кабинет. Если берут домой, добавляется дата возврата. 

Есть разделение под проекты. Если у сотрудника несколько активных проектов, он указывает, под какой именно берёт девайс. Потом эта информация попадает в матрицу покрытия устройствами.

Когда пришёл запрос «устал возвращать по одному», я подключила кнопку «Вернуть все» на вкладке «Мои». Одно нажатие — и все активные устройства пользователя возвращаются. Система показывает тост с количеством, чтобы было понятно, что именно произошло.

Матрица покрытия

Самая сложная фича пришла из наших QA-процессов. Мы ведём матрицу покрытия устройствами, о которой писали здесь.

В системе появилась сущность «проект» с минимальными поддерживаемыми версиями ОС. Сотрудники привязаны к проектам, а история бронирований знает, под какой проект брали устройство.

В режиме «Матрица покрытия» выбираешь проект и видишь, какие устройства ещё не тестировались на нём, что давно не использовалось, топ самых частых.

Активность с устройствами

Отдельный раздел показывает аналитику по людям и устройствам с фильтром по периоду и графиками. Сначала это было просто полезно для прозрачности: кто какие устройства берёт, какие девайсы используются часто, а какие почти не трогают.

Потом вокруг этого появилась своеобразная геймификация. Рейтинг пользователей считается по количеству уникальных устройств, которые сотрудник брал за период. Именно уникальных, а не просто по количеству бронирований.

Рейтинг сотрудников и мотивация. Лидеру — поощрение, второму и третьему — догоняющие сообщения в духе «ещё немного, возьми устройство, которое давно не брал». Ребята действительно смотрят на рейтинг и иногда специально берут незнакомый девайс, чтобы подняться в списках.

Популярность устройств. На карточках каталога появились промо-плашки. Система подсвечивает самые востребованные устройства и те, что давно никто не брал.

Здесь получается двойной эффект. С одной стороны, это мотивирует брать разные устройства, а не ходить по одному и тому же привычному набору. С другой — это сигнал для закупок. Если устройство постоянно востребовано, возможно, таких моделей не хватает. Если девайс лежит мёртвым грузом, возможно, его не нужно докупать или стоит пересмотреть его роль в тестировании. Экономим и тут.

Подбор устройств

Отдельный режим для тех, кто ищет устройство по техническим характеристикам, а не по названию. 

Можно фильтровать по разрешению экрана, соотношению сторон, например 20:9, и плотности пикселей — PPI. Есть переключатель «Только точное разрешение», если нужны устройства без допустимых отклонений. 

Экспорт и отчёты

Данные можно выгрузить в нескольких разрезах из одного пространства в админке.  Есть CSV-выгрузки: история бронирований, каталог устройств с выбором нужных колонок, статистика активности, ежемесячный отчёт, сломанные устройства, просроченные возвраты и проблемные ситуации. Есть PDF-отчёт — ежемесячная сводка по парку устройств: какие девайсы брались, кто и сколько пользовался, какая оборачиваемость. Такой отчёт удобно передать руководителю или использовать на ретроспективе по парку.

Аналитика и прогнозирование закупок

Это появилось само как побочный эффект нормального учёта.

Раздел «Анализ устройств» разбит на четыре вкладки: неиспользуемые устройства, которые не брали больше N дней; просроченные возвраты; оборачиваемость — сколько раз брали и среднее время использования; сломанные устройства.

Теперь можно смотреть, каких устройств не хватает и по каким платформам появляется очередь, что лежит мёртвым грузом и не нужно докупать, какие версии ОС недопредставлены в тестировании.

Это не полноценная BI-система, но для внутреннего инструмента такого уровня уже достаточно, чтобы принимать более осознанные решения.

Feature flags и версионирование

Экспериментальные фичи живут за feature flags в Firestore. Их можно включать и выключать из админки без редеплоя. Это удобно, когда нужно раскатить фичу постепенно, проверить её на небольшой группе или быстро отключить, если что-то пошло не так.

Есть механизм Force Update. Администратор задаёт минимальную версию приложения, а пользователи с устаревшей версией видят просьбу обновить страницу. Клик на версию открывает диалог с историей изменений.

Эта мелочь сильно упрощает взаимодействие с PWA-версиями: пользователи не остаются на старой версии, так как система вовремя обновляется.

Как работает конвейер

Спецификации как рельсы для AI

Это главное, что я поняла за три месяца: качество результата определяет не детальность промпта, а качество контекста, который AI получает автоматически.

Промпт вроде «добавь фильтр “Не используемые мной”» сам по себе слишком общий. Без контекста он может привести к чему угодно: лишней логике, странному UI, тестам не того поведения или изменениям не в тех местах. 

Поэтому полный цикл выглядит так: 

1. Сначала фиксируется, зачем нужна фича и что меняется,
2. Затем строится дельта-спека с требованиями и сценариями,
3. Потом пишутся RED-тесты до кода,
4. После этого идёт реализация,
5. Затем code review
6. И только потом MR.

Где AI справился, а где облажался

С feature flags AI справился хорошо. Аккуратно реализовал хранение флагов в Firestore, переключение из админки без редеплоя и применение изменений без перезагрузки страницы.

Тестовая архитектура тоже получилась сильной. AI предложил связку Screenplay pattern + Page Object с небольшими подсказками, и дальше смог выдерживать её в последующих тестах. В проекте появилось 38 Screenplay-задач (TakeDevice, BookDeviceHome, ToggleFeature, ...) плюс 15 Page Objects. AI предложил именно эту архитектуру и выдержал её во всех последующих тестах.

Граничные случаи в тестах стали отдельным плюсом. Мок Firebase с поддержкой мутаций позволяет воспроизводить состояния, которые сложно поймать вручную. Orphan device (устройство без владельца), одновременное бронирование двумя пользователями, ошибка записи в базу — это просто мутация конфига:

const overdueMyDeviceConfig = configWithMutations((config) => {

  const device = config.data.devices.find(d => d.id === 'dev-booked-home');

  device.bookedUntil = {

    __ts: true,

    value: new Date(Date.now() - 24  60  60 * 1000).toISOString()

  };

});

Где плохо

God Object вместо рефакторинга. Каждую новую фичу AI добавлял в devices.js. Через несколько недель файл вырос до 305 KB и содержал семь независимых доменов: каталог, бронирование, историю, матрицу покрытия, матчер, CRUD, аналитику. AI оптимизировал локально — видел файл, дописывал туда. Никто не смотрел на размер целиком. Пришлось в отдельной задаче просить явный рефакторинг.

setTimeout вместо Promise. В нескольких местах вместо нормального async/await появился setTimeout(fn, 100) — ждать, пока данные загрузятся. Это работает на хорошем соединении и ломается на плохом. AI видел timing issue и брал самый простой инструмент.

N+1 запросы в админке. Загрузить список пользователей → для каждого отдельным запросом загрузить назначения. 50 пользователей = 50 запросов к Firestore. Поймали только когда квота free-плана начала уходить быстрее ожидаемого.

Тест несуществующего поведения. При генерации тестов для матрицы покрытия AI написал тест, который проверял тултип с процентом покрытия при клике на устройство. Тултип в спеке упоминался как идея — не как реализованная фича. AI воспринял его как часть требований. Тест прошёл бы только если бы тултип существовал. Причина — не в промпте, а в неточной спеке: граница между «что есть» и «что хотелось бы» была размыта. Именно поэтому дельта-спека пишется до кода, а не после.

innerHTML без санитизации. Прямая вставка HTML-строк в DOM — паттерн, который AI воспроизводил стабильно. Для внутреннего корпоративного инструмента с авторизацией через Google это некритично, но это потенциальная XSS-уязвимость, которую нужно было явно запросить исправить.

Каждый промах — это апдейт фреймворка

Важный момент: мы не просто фиксировали найденные проблемы и шли дальше. Каждый повторяющийся паттерн превращался в изменение в sdlc-dev-framework: новый этап, правило code review или отдельный скилл. Например:

  • После истории с setTimeout вместо Promise в фреймворк добавился этап статического анализа async-кода. 

  • После God Object появился явный шаг архитектурной декомпозиции перед реализацией. 

  • После теста несуществующего поведения в шаблон дельта-спеки добавилось разделение «реализовано сейчас» и «идеи для будущего». 

  • После N+1 запросов в code review чеклист вошёл пункт про пакетные запросы к Firestore.

Этим проект и ценен как полигон. AI все равно ошибается везде. Здесь же мы используем живой продукт и четко видим, где именно AI ошибается. И тогда можно улучшать и совершенствовать проект.

Чек-лист: страховка от AI-ошибок

Когда фича готова, прошу ИИ пройтись по единому чек-листу, который сделала для того, чтобы не терять важные изменения и поддерживать проект в актуальном состоянии. Каждый пункт в нём появился на основе наших отработок. 

  1. Спецификация — открыт proposal, созданы дельта-спеки, пройдена валидация спек.

  2. Discovery-документация — обновлены бизнес-требования, use cases, E2E-флоу.

  3. Данные и доступы — обновлены правила Firestore при новых коллекциях или ролях.

  4. UI и логика — разметка, стили, JS-модули.

  5. Feature flags — если постепенный rollout, добавлен флаг.

  6. Ручные тесты — обновлены компонентные и сценарные тесты в JSON.

  7. Автотесты — новый *.spec.ts, обновлены Page Objects, Screenplay-задачи, мок-данные.

  8. Документация — обновлены README.md и DOCUMENTATION.md.

  9. Версия — поднята в js/version.js, синхронизирована скриптом.

  10. Финальные проверки — playwright test, smoke-check ключевых сценариев.

10 разделов, около 30 пунктов внутри. Большинство занимают минуты. Я терпеть не могу создавать процесс ради процесса, поэтому для меня такой чек-лист — страховка, которая позволяет AI генерировать код, а не мусор.

Что в итоге

  • Живой сервис, которым реально пользуется команда

  • 23 фичи за три месяца

  • Время от идеи до MR — за обеденный перерыв

Больше о таких инсайтах, наших внутренних проектах, ускорении и автоматизации с помощью AI читайте из первых рук — от хедов в нашем ТГ-канале «Директорат Surf обсуждает».

Комментарии (4)


  1. rezsoseres
    25.05.2026 10:24

    Про God Object на 305 KB. Вы пишете, что после этого инцидента в процесс добавили этап архитектурной декомпозиции. А как это технически выглядит? отдельный промпт перед реализацией, где модель сама предлагает разбиение? или это ручной шаг человека?


  1. Petro_Wujcik
    25.05.2026 10:24

    Самое любопытное - тезис "качество контекста, а не промпта". На каком объеме кодовой базы у вас стабильно работает дельта-спека? На пет проекте все понятно — объем контролируемый, один разработчик в голове держит всю модель. А вот на чем-то типа 150-200к строк нейронка у меня начинает терять нить уже после 3-4 связанных файлов, и никакая структурированная спека не вытягивает. Тестировали подход вне песочницы?


  1. dzzd_cnffsd
    25.05.2026 10:24

    Крутой проект для сотрудников! А вы как-то следите за здоровьем девайсов? Например, за той же батарейкой? Учитывая, сколько они гоняются, могут быстро подыхать аккумы. Не планируете отслеживать это в приложении? Ну и в целом сделать поле, где указывать какие-нибудь технические дефекты смартфона.


    1. shteyner
      25.05.2026 10:24

      А зачем? Это же не для аренды, это для тестов работы какого-то софта на реальном устройстве. Скорее всего телефоны выдаются без расписки, просто кто что взял.