Amiga
Оглавление курса · урок 8 из 13

Модуль 2 · Строим · урок 8 из 13

Данные, API и интеграции

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

Миграции: только вперёд

Правило из AGENTS.md «применённые миграции не менять» — самое важное в работе с данными. Агент, у которого не сходится схема, охотно правит старую миграцию: локально всё работает, а на стенде, где она уже применена, — нет.

Две команды Prisma, которые нужно различать:

  • npx prisma migrate dev — локально: создаёт и применяет новую миграцию;
  • npx prisma migrate deploy — на стенде и в продакшене: только применяет готовые.

Каждую миграцию читайте построчно, особенно разрушительные операции. Когда офис-менеджер попросил переименовать поле hasScreen в equipment со списком, агент сгенерировал DROP COLUMN и ADD COLUMN — данные об экранах исчезли бы. Безопасный путь — расширить и сжать: добавить новую колонку, перенести данные, переключить код, а старую колонку удалить отдельным релизом.

text
Нужно заменить Room.hasScreen на Room.equipment (массив строк).
Сделай это в три шага, каждый — отдельной миграцией и коммитом:
1) добавить equipment, заполнить из hasScreen (true → ['screen']);
2) перевести API и интерфейс на equipment;
3) удалить hasScreen. Шаг 3 не делай, только опиши.
Покажи SQL каждой миграции до применения.

Время — отдельная тема

Брони — это время, и здесь агент ошибается чаще всего. Правило уже записано в AGENTS.md: в базе timestamptz, в API ISO 8601 со смещением, в интерфейсе — зона офиса. Но правило не помогает, если границы дня считаются по зоне сервера. Сервер в контейнере живёт в UTC, и «брони на сегодня» после полуночи по Москве покажут вчерашний день.

Лекарство — тесты на границах, которые агент сам не придумает:

text
Добавь тесты для расчёта границ дня и недели в apps/api/src/services/time.ts:
- 23:30 и 00:30 по Europe/Moscow попадают в разные дни;
- процесс запущен с TZ=UTC и TZ=Asia/Vladivostok — результат одинаковый;
- неделя начинается в понедельник 00:00 по Москве.
Тесты должны падать на текущей реализации, если она зависит от TZ процесса.

Один контракт на API и интерфейс

Zod-схемы в packages/shared — единственный источник типов запросов и ответов. Агент, которому нужно быстро, объявит тип Booking прямо в компоненте интерфейса — и через месяц у вас три разных Booking. Помогает правило в AGENTS.md и проверка в ревью: «новый тип ответа API, объявленный вне packages/shared, — замечание».

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

Сиды и реалистичные данные

Пустая база скрывает половину ошибок. Попросите агента написать сид с реалистичными данными: четыре комнаты (одна архивная), три десятка броней на текущую неделю, длинные названия встреч, брони впритык друг к другу. Скрипт npm run db:seed должен быть идемпотентным — его будут запускать и тесты, и вы. Персональные данные — только выдуманные.

Актуальная документация библиотек

Агент знает библиотеки по обучающим данным, а API меняются. Если видите вызовы, которых нет в вашей версии пакета, дайте ему документацию. Два способа:

  • MCP-сервер с документацией библиотек, например:
bash
codex mcp add context7 -- npx -y @upstash/context7-mcp
  • справочные файлы в репозитории: docs/references/ с выжимкой нужной версии API. Команда OpenAI в статье о harness engineering описывает именно такой каталог.

Каждый MCP-сервер добавляет контекст в каждую сессию, поэтому подключайте только нужные.

Интеграция 1: подписка на календарь

Сотрудники хотят видеть расписание комнаты в своём календаре. Календарные клиенты не умеют входить по cookie, поэтому подписка работает по секретной ссылке:

text
Добавь GET /api/rooms/:id/calendar.ics — расписание комнаты на 30 дней
в формате iCalendar (RFC 5545). Доступ по персональному токену в query:
токен генерируется на странице профиля, в базе — хэш, токен можно перевыпустить.
Отменённые брони не включать. Тест: ответ разбирается парсером iCalendar,
время событий совпадает с бронями с учётом зоны.
После реализации я проверю подписку в реальном календаре.

Последняя строка — не формальность. Формат iCalendar капризен, и проверка «календарь показал событие в правильное время» стоит больше юнит-теста.

Интеграция 2: уведомления в мессенджер

Когда бронь отменяют, в канал офиса уходит сообщение — комната освободилась. Типичная реализация агента: вызвать вебхук прямо в обработчике отмены. Если мессенджер тормозит, отмена висит; если он недоступен, отмена падает.

text
Уведомление об отмене брони в канал офиса через входящий вебхук.
Требования:
- отмена брони не зависит от доступности мессенджера;
- запись о событии сохраняется в таблицу notifications в той же транзакции,
  что и отмена; отдельный воркер отправляет и ретраит с паузой, до 5 попыток;
- таймаут запроса 5 секунд; URL вебхука — из NOTIFY_WEBHOOK_URL, не логировать;
- в тестах внешний вызов идёт в локальную заглушку, настоящий вебхук не трогать.

Это шаблон «outbox»: побочный эффект сначала записывается в базу, а отправляется потом. Он скучный и надёжный.

Агент и база данных

Агенту полезно смотреть в локальную базу: проверить, что миграция легла, посмотреть реальные данные. Для этого хватит psql с учётными данными из docker-compose.yml. Доступ к базе стенда и тем более продакшена агенту не давайте: одна неудачная команда — и восстанавливать придётся из бэкапа. Подключение баз через MCP разобрано в уроке «MCP на практике».

Попробуйте сами

10–15 мин на рабочем месте
  1. Попросите агента показать SQL следующей миграции до применения и найдите в нём разрушительные операции.
  2. Добавьте тест, который запускает расчёт границ дня под двумя разными TZ, и посмотрите, проходит ли он.
  3. Найдите в своём проекте внешний вызов в обработчике запроса и спросите агента, что произойдёт, если сервис ответит через 30 секунд.

Коротко

  • Миграции только вперёд; разрушительные изменения — через «расширить и сжать».
  • Время: timestamptz в базе, зона офиса для границ дня, тесты на полночь и разные TZ.
  • Один контракт API в общих схемах, а не типы в каждом компоненте.
  • Устаревшие API библиотек лечатся документацией: MCP или docs/references/.
  • Интеграции не должны ронять основной сценарий: таймауты, ретраи, outbox.
  • Агенту — локальная база, не продакшен.
Отметка хранится только в вашем браузере
Хотите связаться с владельцем
компании напрямую?
Дмитрий Тарасов
Дмитрий Тарасов
СЕО

НАПИСАТЬ

Написать в MAX