Назад к проектам
CASE 01 · VISIBLE BACKENDРабочий product MVP · развивается

TATTOTOYOU — AI-ассистент для тату-студии

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

Роль
Backend, архитектура и AI-интеграция
Контур
Telegram · API · Queue · AI · CRM
Модель доставки
Durable Inbox/Outbox · at-least-once
ЗАДАЧА И ОГРАНИЧЕНИЯ

Автоматизировать рутину, не отнимая контроль у мастера.

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

01 / PROBLEM

Что должна делать система

Быстро принять обращение, определить сценарий, дать подтверждённый ответ, сохранить контекст и подготовить мастеру структурированную заявку вместо разрозненной переписки.

02 / CONSTRAINTS

Ключевые ограничения

  • Telegram может повторно доставить один и тот же update.
  • Redis, Telegram и AI API могут быть временно недоступны.
  • Медицинские и конфликтные запросы требуют человека.
  • Телефоны и email нельзя без необходимости отправлять внешнему AI.
  • Ответ не должен выдумывать цены, правила или детали записи.
АРХИТЕКТУРА

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

Webhook не передаёт событие напрямую в бизнес-логику. FastAPI проверяет запрос и атомарно фиксирует update в PostgreSQL Inbox. Очередь получает только идентификатор сохранённого события, а исходящий ответ проходит через отдельный Transactional Outbox.

Архитектура TATTOTOYOU: Telegram, FastAPI, PostgreSQL Inbox, Redis и Celery, worker, RAG и GigaChat, PostgreSQL Outbox и доставка ответа.
  1. 1. Telegram: webhook
  2. 2. FastAPI: validate
  3. 3. PG Inbox: durable
  4. 4. Redis / Celery: schedule
  5. 5. Worker: process
  6. 6. RAG / GigaChat: answer
  7. 7. PG Outbox: persist / retry
  8. 8. Telegram Bot API: send / retry
Celery Beat recoveryCelery Beat recovery

Планировщик повторно ставит готовые или зависшие Inbox- и Outbox-записи в очередь, поэтому ошибка брокера после commit не уничтожает принятую работу.

Inbox: повторная постановкаOutbox: повтор доставки
  • Idempotent inbound processing
  • Single business response in PostgreSQL
  • At-least-once outbound delivery
EVENT FLOW

Событие проходит не по списку функций, а через проверяемые состояния.

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

Сценарий выполнения
  1. TELEGRAM

    Входящее сообщение

    Telegram доставляет update и при сетевой неопределённости может отправить тот же event повторно.

    Вход
    update_id, chat_id, message text
    Действие
    HTTPS webhook delivery
    Результат
    Запрос к публичному endpoint
  2. FASTAPI WEBHOOK

    Проверка границы системы

    API ограничивает размер тела, проверяет Secret Token и применяет rate limit до запуска бизнес-логики.

    Вход
    HTTP headers и Telegram payload
    Действие
    Validate, authenticate, normalise
    Результат
    Проверенный update
  3. POSTGRESQL INBOX

    Долговечная фиксация

    Update сохраняется до обращения к Redis. Уникальный внешний ID превращает повторную доставку в идемпотентное чтение.

    Вход
    Проверенный Telegram update
    Действие
    INSERT или resolve existing event
    Результат
    Inbox UUID со статусом ready
  4. CELERY WORKER

    Захват и классификация

    Worker получает UUID, блокирует запись, загружает диалог и определяет intent, safety-сигналы и текущего владельца разговора.

    Вход
    Inbox UUID и сохранённый контекст
    Действие
    Claim, classify, apply state rules
    Результат
    Решение: AI, fallback или handoff
  5. RAG / GIGACHAT

    Ответ только на подтверждённом знании

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

    Вход
    Intent и очищенный контекст
    Действие
    Retrieve, score, generate or abstain
    Результат
    Grounded reply или сигнал эскалации
  6. POSTGRESQL OUTBOX

    Фиксация результата и доставка

    Бизнес-ответ и delivery-запись создаются транзакционно. Временные ошибки Telegram получают отдельный retry-cycle.

    Вход
    Ответ, fallback или команда handoff
    Действие
    Commit result, enqueue delivery
    Результат
    Отправленное сообщение или retry state
  7. MASTER / CRM

    Контроль человека

    При эскалации AI блокируется, а мастер видит диалог, заявку и контекст, отвечает вручную или возвращает управление системе.

    Вход
    Escalated или human_owned conversation
    Действие
    Review, reply, update lead and booking
    Результат
    Решение мастера и сохранённая история
КЛЮЧЕВЫЕ РЕШЕНИЯ

Надёжность строится вокруг границ между системой и внешним миром.

Основные решения появились не ради архитектурных терминов, а из конкретных сценариев потери данных, дублей и неконтролируемого AI-ответа.

DURABILITY

PostgreSQL Inbox до Celery

Сначала фиксируется факт принятия update, затем выполняется best-effort постановка UUID в очередь. Recovery закрывает окно недоступности Redis.

DELIVERY

Transactional Outbox

Ответ и задание на отправку коммитятся вместе. Telegram-доставка отделена от формирования бизнес-результата и получает собственные retry-состояния.

CONTROL

Handoff как state machine

После эскалации AI перестаёт отвечать, но сообщения клиента продолжают сохраняться. Владение диалогом становится явным состоянием.

AI SAFETY

RAG без обязательного ответа

Если подтверждённого знания недостаточно, система не просит LLM заполнить пробел. Она создаёт понятный fallback и передаёт диалог мастеру.

PRIVACY

Минимизация PII

Телефоны и email маскируются перед внешним AI, TLS-проверка не отключается, а оригинальный текст остаётся в собственной PostgreSQL.

CONCURRENCY

Блокировки и уникальные инварианты

FOR UPDATE SKIP LOCKED и частичные уникальные индексы защищают обработку событий, единственный бизнес-ответ и один открытый диалог клиента.

FAILURE SCENARIOS

Что происходит, когда зависимость отвечает не по happy path.

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

СбойРеакция системыРезультат
Redis недоступен после сохранения webhook

Inbox остаётся ready; Celery Beat повторно ставит событие в очередь.

Принятое обращение не теряется.

GigaChat timeout, 429, 5xx или отказ OAuth token

Typed error, bounded backoff с jitter и управляемый refresh token под Redis-lock.

После лимита попыток — fallback и эскалация мастеру.

Временная ошибка Telegram Bot API

Outbox delivery возвращается в retrying с exponential backoff.

Бизнес-ответ сохранён независимо от доставки.

Медицинский, конфликтный или явно нестандартный запрос

Диалог переводится в escalated, AI-ответ блокируется, мастер получает уведомление.

Решение остаётся у человека.

OPERATOR EXPERIENCE

Backend заканчивается не ответом бота, а рабочим процессом студии.

Встроенная панель позволяет мастеру видеть открытые диалоги, отвечать клиенту, вести CRM-карточку, оформлять отдельные тату-проекты и управлять расписанием без отдельного frontend-приложения.

01

Диалоги и handoff

Очередь обращений, непрочитанные сообщения, takeover, возврат к AI, ручной ответ через Outbox и закрытие диалога.

02

CRM и заявки

Идея, место, размер, стиль, бюджет, желаемая дата, референсы и неизменяемая история переходов по воронке.

03

Запись и предоплата

Сеансы, согласованная цена, статусы предоплаты и PostgreSQL-ограничения, не допускающие пересечение активных записей.

Валидируемая воронка заявки
  1. new
  2. qualification
  3. consultation
  4. awaiting_deposit
  5. booked
  6. completed
TESTING & DELIVERY

Проверяются не только функции, но и конкурентные инварианты.

CI разделён на независимые уровни: быстрые unit-проверки, интеграционный PostgreSQL-контур и сборку production Docker-образа из lock-файла.

UNITPython 3.11 / 3.12

Ruff, Alembic graph, unit suite и текущий coverage gate 74%. В regression dataset — 169 размеченных клиентских фраз.

INTEGRATIONPostgreSQL 15 + pgvector

Миграции с пустой БД и тесты конкурентной обработки Inbox/Outbox, уникальных инвариантов и health endpoints.

CONTAINERDocker Compose

Проверка production/development Compose, сборка строго из uv.lock и import/config smoke-test.

TRADE-OFFS & NEXT

Границы гарантий обозначены явно.

Кейс не изображает систему завершённой enterprise-платформой. В репозитории зафиксированы реальные ограничения и следующий уровень production-проверок.

Осознанный компромисс

At-least-once доставка в Telegram

Bot API не принимает idempotency key для sendMessage. В редком окне после успешной отправки и до commit статуса sent возможен повтор на стороне платформы.

В работе

Строгая типизация

Mypy пока остаётся отдельным диагностическим этапом, потому что накопленный type debt ещё не погашен полностью.

Roadmap

Production observability

Структурированные логи и health endpoints уже есть; метрики, dashboard, нагрузочные, e2e и chaos-тесты остаются следующим этапом.

РЕЗУЛЬТАТ И ВЫВОДЫ

Из Telegram-бота получился событийный продуктовый backend.

Проект связывает транспорт, фоновые задачи, AI, данные клиента и реальную работу оператора. Главная ценность кейса — не количество технологий, а явные гарантии на границах между ними.

  • Надёжный webhook начинается с долговечного принятия события, а не с task.delay().
  • AI fallback должен быть частью бизнес-сценария, а не общей фразой в except.
  • Handoff работает только тогда, когда владение диалогом хранится как состояние.
  • Инварианты записи и оплаты надёжнее защищать и в PostgreSQL, а не только в формах UI.
SOURCE & EVOLUTION

Код, миграции, тесты и история решений доступны в репозитории.

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