Audio Scribe: архитектура backend, очереди и production-контур

Снаружи Audio Scribe может выглядеть как Telegram-бот и workspace для расшифровки. Но за этим простым входом быстро появляется менее видимая часть: что происходит с файлом после загрузки, где живёт результат, как не потерять долгую обработку и как не превратить один AI-вызов в хрупкий сценарий.

Внутри это уже backend-платформа: API, очереди, база, object storage, AI routing, биллинг, admin-инструменты и production-контур с отдельным frontend. Эта заметка не про красивую схему «пользователь загрузил файл, AI всё сделал». Мне важнее показать практические части, из которых складывается надёжный сценарий: где лежат данные, какие процессы вынесены в очереди, что остаётся optional, как проверяется health и как проект выкатывается.

Backend: NestJS как центр системы

Backend написан на NestJS и TypeScript. Он держит большую часть доменной логики:

  • Telegram bot updates;
  • backend API для workspace и admin dashboard;
  • пользователей и авторизацию;
  • транскрибацию и AI-анализ;
  • Files/artifacts;
  • notes;
  • tasks и calendar-связи;
  • reminders;
  • billing;
  • feature flags;
  • agent/workflow/admin endpoints.

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

PostgreSQL и Prisma

Основная база — PostgreSQL через Prisma. В ней лежат пользователи, результаты анализа, рабочие сущности, настройки и связи между ними.

Это важно для продукта: результат обработки не исчезает после ответа в Telegram. Если пользователь возвращается к разговору, открывает workspace или превращает расшифровку в рабочий артефакт, системе нужен устойчивый источник правды. Результат может стать сохранённым файлом, заметкой, задачей, календарным элементом или контекстом для будущего вопроса.

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

Redis и BullMQ

Тяжёлые и фоновые операции вынесены в BullMQ-очереди на Redis. Сейчас ключевые очереди такие:

  • audio-processing — обработка аудио и голосовых;
  • question-processing — вопросы, conversational pipeline и часть URL-сценариев;
  • video-processing — YouTube/Vimeo и video-specific задачи;
  • reminder-scanner — поиск напоминаний, которые пора доставить;
  • recurring-job-scanner — регулярные задачи и recurring-сценарии.

Очереди нужны не для красоты. Telegram update или HTTP-запрос не должен зависеть от того, сколько займёт тяжёлая транскрибация, скачивание видео или длинный AI-анализ. Backend принимает входящее событие, создаёт работу, сохраняет состояние и дальше возвращает результат, когда обработка завершилась. Для пользователя это выглядит как нормальный продуктовый сценарий, а не как ожидание у открытой двери, пока вся тяжёлая работа выполняется прямо в запросе.

MinIO и Files/artifacts

Для файлов используется MinIO/S3-compatible storage. Пользовательски это называется Files или Файлы, но backend/API/domain всё ещё часто говорит artifacts.

В storage попадают материалы, которые нужно обработать, скачать, показать в preview или использовать повторно. Это особенно важно для workspace: файл должен быть не одноразовым вложением, которое исчезло после обработки, а рабочим объектом, к которому можно вернуться и от которого можно построить следующий шаг.

Типовые операции Files/API:

  • список;
  • детальная карточка;
  • upload;
  • download;
  • preview;
  • delete.

AI routing

Audio Scribe не завязан на одного AI-провайдера. В routing-слое могут использоваться разные направления:

  • AudioScribe;
  • Google/Gemini;
  • OpenAI;
  • Anthropic;
  • OpenRouter;
  • SiliconFlow;
  • Polza AI;
  • Perplexity;
  • local provider;
  • OpenAI-compatible endpoint;
  • AssemblyAI transcription.

Это не значит, что каждый provider всегда включён в production. Часть зависит от credentials, feature flags, настроек окружения и конкретного типа задачи. Важна сама развилка: разные задачи не обязаны проходить через один универсальный AI-молоток, если архитектурно проект может направлять их к подходящим инструментам.

Optional и conditional modules

В кодовой базе есть несколько инженерных слоёв, которые не нужно подавать как обязательный пользовательский функционал:

  • Temporal workflows;
  • sandbox;
  • skills registry;
  • MCP registry;
  • memory.

Они полезны для agent-control-plane и внутренних workflows, но могут быть optional/conditional. Это помогает не выдавать инженерные эксперименты за обязательную часть пользовательского продукта: в production часть таких возможностей может быть выключена, скрыта feature flags или доступна только оператору.

Health и readiness

Для production важны два endpoint:

  • GET /api/health — базовая проверка, что backend жив;
  • GET /api/ready — readiness-проверка, что сервис готов принимать трафик.

Это простая, но нужная граница. Health не должен обещать, что «всё идеально», а readiness помогает отличать запущенный процесс от реально готового сервиса. Для production это один из тех скучных механизмов, которые становятся заметны только тогда, когда их нет.

Production runtime

Текущий production-контур разделён на backend, frontend и инфраструктуру:

  • backend работает через PM2 на 127.0.0.1:3000;
  • frontend собирается в Docker/nginx и слушает 127.0.0.1:3001;
  • PostgreSQL, Redis, Temporal и MinIO поднимаются через Docker;
  • frontend и backend не смешиваются в один процесс.

Такой контур удобен для постепенного rollout. Backend можно перезапускать через PM2, frontend — обновлять как контейнерный nginx image, инфраструктуру — держать отдельным docker-слоем. Получается не монолитный «запустить всё сразу», а набор понятных точек, где можно обновлять и проверять части системы по отдельности.

Deploy workflow

Deploy построен через GitHub Actions:

  • backend tests;
  • frontend typecheck/tests;
  • сборка GHCR frontend image;
  • SSH deploy;
  • rollout backend через PM2.

Отдельная важная деталь: docs-only изменения не триггерят автодеплой. Для портфолио-репозитория это удобно: можно обновлять описания проекта, не заставляя production лишний раз пересобираться.

Где проходит граница ответственности

Backend отвечает за состояние и маршрутизацию. Очереди отвечают за долгие операции. PostgreSQL хранит доменную модель. MinIO хранит файлы. Frontend показывает workspace и admin dashboard. Telegram-бот даёт быстрый канал входа и уведомлений.

Именно здесь техническая схема становится продуктовой. Если границы размываются, проект быстро превращается в набор случайных обработчиков: сегодня один сценарий пишет напрямую в storage, завтра другой сам решает, когда отправлять напоминание, послезавтра AI-workflow живёт отдельно от пользовательского состояния. В Audio Scribe важная инженерная задача как раз в обратном: не дать транскрибации, задачам, reminder-сканерам, agent workflows и admin-инструментам перемешаться в один неподдерживаемый комок.

Что дальше

В активных планах есть targeted refactoring roadmap. Это правильное направление для такого проекта: когда продукт растёт от одной сильной функции к платформе, главная сложность — не добавить ещё один экран, а удержать доменные границы, очереди, feature flags и production-процессы в понятном состоянии. Тогда backend остаётся не набором технических деталей, а каркасом, на котором держится понятный и надёжный пользовательский сценарий.


Это техническая заметка по Audio Scribe: без заявлений о нагрузке и SLA, только фактический backend/runtime-контур и ограничения, которые важно помнить при описании проекта.