LMS и CRM на 205 000 строк кода силами ИИ-агентов: цена эксплуатации, три отметки лида и один символ \r
Две связанные боевые системы — образовательная платформа LMS (121 853 строки TS/TSX, 47 роутеров, 288 процедур) и CRM с единым реестром из 334 инструментов (83 251 строка) — были написаны без команды разработчиков с помощью ИИ-агентов поверх единого PostgreSQL. Написание кода заняло вечера, а главную цену выставила доводка до продакшна: 14 критических дефектов на этапе адверсарного ревью, ещё 5 при проверке собственных фиксов и невидимый символ возврата каретки \r, тихо отключивший интерактивную практику на 138 уроках из 146. Надёжная интеграция ИИ-агентов с живым бизнесом потребовала разделить работу с лидом на три независимых состояния под блокировкой FOR UPDATE, реконструировать историю диалога на сервере и сохранять свою запись встречи до вызова внешних API Zoom и Google Calendar.

- Объём кодовой базы без команды разработчиков: 205 104 строки TypeScript/TSX (121 853 в LMS на 532 файлах и 83 251 в CRM на 367 файлах)
- Поверхность API и агентного фасада: 47 роутеров и 288 процедур tRPC в LMS (93 инструмента) + 334 инструмента в реестре CRM (257 открыты в фасаде)
- Масштаб одного невидимого бага CRLF: 138 из 146 практических уроков с нулём успешных отправок из-за хвостового символа `\r` при разборе на сервере
- Урожай адверсарного ревью перед запуском: 14 опасных уязвимостей в первой волне + 5 дефектов, внесённых самими фиксами
Написать крупную систему силами ИИ-агентов без штата программистов сегодня стало дешёвой задачей. Дорого стоит всё, что начинается на следующее утро после демо: защита от подделки истории клиентом, блокировки в базе при двойном клике менеджеров и невидимые спецсимволы в секретах.
Обе мои системы — обучающая платформа LMS (121 853 строки TS/TSX, Next 16.2.6, React 19, Drizzle ORM, 58 миграций, 16 треков, 211 уроков и 55 симуляторов) и стоящая рядом CRM (83 251 строка, Prisma 7.6, 48 моделей БД, BullMQ и четыре подключённых ИИ-агента) — живут на одном инстансе PostgreSQL. Свой стек мы строили по двум причинам: в коробочных LMS нет примитива, где нейросеть сначала отыгрывает слабый промпт студента и лишь затем коучит по скрытой преамбуле, а CRM должна была без дублирования баз лечь поверх работающего в Telegram бота воронки. Кстати, перекраска 289 цветовых переменных при форке CRM заняла вечер, а вычищение унаследованных демо-данных (205 тестовых заявок, фолбэк «маржа 38%» и фальшивые бейджи «Задачи 7») растянулось на два месяца.
Как один невидимый символ возврата каретки \r сломал 138 уроков,
дедупликацию и OAuth?
Самый коварный баг в LMS не оставлял ошибок в логах. Студенты видели нормально отрисованный блок `:::practice`, нажимали «Отправить» и получали «Практический блок не найден». Статистика по базе показала, что на 138 уроках из 146 было ровно ноль успешных прохождений. Контент создавался на Windows с переносами `CRLF` (`\r\n`): фронтенд перед рендером нормализовал текст, а серверный парсер резал по `\n`, оставляя невидимый `\r` на конце строки:
```typescript // Без нормализации хвостовой \r ломает якорь $ в JS, // так как точка (.) не захватывает \r, и поле task парсится пустым: md = md.replace(/\r\n?/g, "\n"); const match = line.match(/^(task|starter|goal|model|system)\s:\s?(.)$/i); ```
Тот же `\r` менял контрольный хеш текста при нарезке чанков, заставляя систему заново оплачивать генерацию эмбеддингов, а в третий раз приехал в конец секрета в `.env`, из-за чего Google OAuth возвращал `invalid_client` (поймано проверкой длины строки `awk -F= '/^GOOGLE_/ {print $1, length($2)}' .env` — 36 байт вместо 35).
Почему нельзя верить данным из браузера и как устроен реестр из 334
инструментов CRM?
Адверсарное ревью перед запуском вскрыло 14 тяжёлых дефектов, а проверка написанных по ним патчей — ещё 5. В первой версии практики браузер сам присылал на сервер текст задания и массив `history`, позволяя подменить реплику через DevTools, а 8 из 55 симуляторов проходились на 71–90 баллов простым копированием условия в ответ. Мы перевели сборку преамбулы и реконструкцию 6 последних реплик строго на сервер, а таймаут грейдера подняли с 30 до 60 секунд.
В CRM вся архитектура построена вокруг единого реестра из 334 инструментов (257 открыты в агентный фасад, а 77 системных закрыты флагом `facadeExposed: false`). Любой вызов проходит единый конвейер `invoke()`: идентичность `acting_user` извлекается только из сессии (разделяя ошибки `missing` и `invalid`, когда прислали ID сессии `api-...` или отрицательный ID группового чата), а аргументы перед записью в `audit_log` чистятся регуляркой `SECRET_KEY_RE`.
Зачем делить одну кнопку лида на три состояния и как ловить встречи-сироты в
Zoom?
В живых продажах продавец пишет клиенту в личном Telegram, а параллельно того же человека догревает бот. Поэтому одну кнопку «Взять лида» пришлось разделить на три независимых состояния: «Беру в работу» (ответственный), «Связались» (факт первого касания) и «Перехвачен» (бот замолкает и уступает диалог человеку). Чтобы два менеджера не перетёрли карточку при двойном клике, CRM находит самую старую запись по `telegram_id` и берёт её под блокировку `SELECT ... FOR UPDATE`. А при создании встреч в Zoom и Google Calendar первой строкой всегда идёт `INSERT` в свою БД со статусом `creating` и полями `zoom_state` / `gcal_state`, чтобы при сбое внешнего API в облаке не оставались неучтённые встречи-сироты.
Эта механика интерактивных тренажёров и агентных реестров работает внутри [Hamidun Academy](https://academy.hamidun.com) (открыт 72-часовой триал) и в контуре [Nomad AI](https://nomadnet.ai) / [agent.nomadnet.ai](https://agent.nomadnet.ai), а архитектуру наших CRM и LMS мы разбираем в [Vibe Club](https://hamidun.com/club).
- 29 окт. 2026 г.Anthropic в S-1 показала: 11 900 клиентов платят от $100 тысяч в год
- 29 окт. 2026 г.Google DeepMind нашла дефект softmax: градиент обнуляется при отрыве 16,6
- 28 окт. 2026 г.CNN 2015 года обошла GPT-6 Astra и Claude Fable 5.1 в диагностике рака кожи
- 28 окт. 2026 г.Google научила LLM «спать»: SLEEP закрепляет знания в весах, до 10 млн токенов
Вопросы и ответы по материалу
Как один невидимый символ возврата каретки \r сломал 138 уроков, дедупликацию и OAuth?
Самый коварный баг в LMS не оставлял ошибок в логах. Студенты видели нормально отрисованный блок `:::practice`, нажимали «Отправить» и получали «Практический блок не найден». Статистика по базе показала, что на 138 уроках из 146 было ровно ноль успешных прохождений. Контент создавался на Windows с переносами `CRLF` (`\r\n`): фронтенд перед рендером нормализовал текст, а серверный парсер резал по `\n`, оставляя невидимый `\r` на конце строки: ```typescript // Без нормализации хвостовой \r ломает якорь $ в JS, // так как точка (.) не захватывает \r, и поле task парсится пусты
Почему нельзя верить данным из браузера и как устроен реестр из 334 инструментов CRM?
Адверсарное ревью перед запуском вскрыло 14 тяжёлых дефектов, а проверка написанных по ним патчей — ещё 5. В первой версии практики браузер сам присылал на сервер текст задания и массив `history`, позволяя подменить реплику через DevTools, а 8 из 55 симуляторов проходились на 71–90 баллов простым копированием условия в ответ. Мы перевели сборку преамбулы и реконструкцию 6 последних реплик строго на сервер, а таймаут грейдера подняли с 30 до 60 секунд. В CRM вся архитектура построена вокруг единого реестра из 334 инструментов (257 открыты в агентный фасад, а 77 системных зак
Зачем делить одну кнопку лида на три состояния и как ловить встречи-сироты в Zoom?
В живых продажах продавец пишет клиенту в личном Telegram, а параллельно того же человека догревает бот. Поэтому одну кнопку «Взять лида» пришлось разделить на три независимых состояния: «Беру в работу» (ответственный), «Связались» (факт первого касания) и «Перехвачен» (бот замолкает и уступает диалог человеку). Чтобы два менеджера не перетёрли карточку при двойном клике, CRM находит самую старую запись по `telegram_id` и берёт её под блокировку `SELECT ... FOR UPDATE`. А при создании встреч в Zoom и Google Calendar первой строкой всегда идёт `INSERT` в свою БД со статусом
Соберите рабочего ИИ-агента или сервис своими руками без ручного кода
В Академии Жемала Хамидуна (academy.hamidun.com) открыт бесплатный 72-часовой тест-драйв: интерактивные скетч-уроки по Claude Code и Cursor, живой Tech Radar и готовые шаблоны агентов.
Главное из мира ИИ — раз в неделю
7 ключевых событий недели, отобранных вручную. Без шума, репостов и пресс-релизов.
Готово! Проверьте почту — мы отправили подтверждение.