Меня зовут Артём, я занимаюсь коммерческой разработкой с 2019 года. Последние несколько лет я активно использовал Spring Boot для создания backend-сервисов на Java и Kotlin.
Но в какой-то момент захотелось попробовать что-то новое. Не потому что Spring надоел, а просто чтобы выйти из зоны комфорта и узнать, как чувствует себя проект на другом языке. Я решил: возьму уже начатый pet-проект, перепишу его на Go — и посмотрю, как изменится подход, скорость разработки, ощущения.
Это не туториал «как перепрыгнуть с Kotlin на Go». Это — эксперимент. Расширение границ и проверка своих навыков в новых условиях. Я не пытался доказать, что Go лучше, а просто дал себе возможность попробовать и сравнить.
Фронт у проекта был примитивный, построенный на HTML и JS без фреймворков. Углубляться в TypeScript и вылизывать интерфейсы я не планировал. Я бэкендер, и красить кнопки — точно не цель этого проекта (пока). Главное — чтобы всё работало стабильно, быстро и надёжно.
Так что сделал ставку на знакомые технологии, а всю новизну решил оставить для Go и инфраструктуры.
Заодно добавил интересный вызов: интегрировать GPT-4 через OpenAI API, сделать стриминг в реальном времени через WebSocket и всё это завернуть в CI/CD, который будет деплоить проект без лишних кликов.
Проект я писал около четырёх месяцев, в свободное время — вечерами и по выходным. Местами было сложно, но оно того стоило. В итоге родился полноценный AI-чат с авторизацией, конфигурацией, живыми ответами и гибкой архитектурой.
Важно: дальше в статье будет много текста и деталей. Это не обзор, а скорее история — по шагам и с погружением. Я хотел, чтобы на этом pet-проекте можно было попробовать много технологий, но не в ущерб здравому смыслу. Здесь есть и CI/CD, и WebSocket, и JWT, и взаимодействие с AI. И всё это с упором на:
- безопасность, 
- отказоустойчивость, 
- асинхронность, 
- простоту масштабирования, 
- и, конечно, низкую стоимость эксплуатации. 
Статья ориентирована на разработчиков, которые разбираются по чуть-чуть во всём — в backend-е, frontend-е, инфраструктуре и логике систем.
Эта статья — мой первый опыт публикации технического рассказа. И вышла она после майских праздников — символично: ощущаю это как свою маленькую победу.
Вот какие разделы вас ждут и зачем они нужны:
Почему Go + Gin, а не привычный Spring Boot
Разбираю, что подтолкнуло к смене стека и почему именно Go. Пишу честно: без фанатизма и без попытки продать Go как серебряную пулю. Просто сравнение ощущений и опыта.
CI/CD и деплой без кликов: GitHub Actions, Swagger, Docker и Portainer
Автоматизация — одна из главных целей. Я хотел, чтобы после каждого коммита новая версия приложения автоматически попадала на сервер: без SSH, без ручных рестартов и копипасты. В этом разделе расскажу, как получилось выстроить простой и надёжный пайплайн, который сам собирает образ, загружает его на сервер, обновляет прод и при этом ещё и Swagger держит в актуальном состоянии.
Интеграция с GPT-4 и адаптация под пользователя
Сердце проекта — AI. Рассказываю, как устроен prompt, как работают стриминговые ответы, какие параметры можно настроить и как GPT стал частью бизнес-логики. Будет и про фильтрацию, и про планы на мультимодальность (изображения, код и т.д.).
Реальное время: WebSocket, события, непрочитанные
Почему WebSocket, как устроена отправка сообщений и обновление счётчиков. Распишу архитектуру соединений, примеры событий и логику, которая делает чат «живым». Без диких подробностей — просто, понятно и с практическими выводами.
Архитектура проекта: как не перегрузить pet-проект
Разбор слоёв проекта: что за что отвечает, почему отказался от репозиториев. Пишу про GORM, интерфейсы, зависимости и почему важно не усложнять то, что можно сделать просто.
Безопасность: HTTPS, WSS, JWT и защита на всех уровнях
Описываю подход к авторизации, валидации токенов и работе с WebSocket. Зачем HTTPS, почему не ws://, как обрабатываются ошибки, и где можно упасть (но не стоит). Планы на разграничение ролей — тоже здесь.
Трудности разработки: от горутин до фронта
Раздел про грабли. Всё, что не получилось с первого раза: гонки в map, баги с каналами, «висящие» горутины. Как помог GPT-4 не сойти с ума, и почему писать UI без фреймворков — отдельный квест.
Итоги: что получилось, что не успел, и куда двигаться дальше
Заключение. Рефлексия. Что работает, что предстоит сделать. Какие выводы я сделал за эти четыре месяца, и чем хочу вдохновить других разработчиков.
Всё построено по принципу: от кода — к системе, от «почему так?» — к «как это поддерживать?».
Надеюсь, что этот рассказ окажется полезным не только как набор решений, но и как честная история с реальными трудностями, идеями и подходами. Поехали!
Почему Go + Gin, а не Kotlin + Spring Boot?
Первый вопрос, который, скорее всего, возник у многих:
 зачем вообще менять проверенный стек?
Я сам долгое время писал на Kotlin с Spring Boot — с его аннотациями, DI, магией и встроенной экосистемой. Это реально удобно. Особенно когда проект большой, а времени — мало.
Но со временем начали ощущаться минусы:
- громоздкость проекта даже на старте; 
- высокое потребление ресурсов; 
- долгое время запуска; 
- сложность отладки скрытых процессов (особенно, если не ты их писал). 
Хотелось чего-то более простого, явного и быстрого:
- лаконичный синтаксис, где почти нет «магии»; 
- мгновенная компиляция в один бинарник; 
- эффективная работа с памятью; 
- встроенная конкурентность (горутины — любовь с первого взгляда). 
Я давно хотел подтянуть Go, и вместо учебных задач решил пойти ва-банк — взять живой проект, полностью его переписать, и посмотреть, как изменится разработка. Это был и вызов, и способ быстро прокачать скилл в боевых условиях.
Плюс ко всему, Go просто приятно писать. Ты чувствуешь, что контролируешь происходящее: от старта приложения до каждой строчки бизнес-логики. Это оказалось неожиданно приятно после многослойного Spring-приложения.
CI/CD и эксплуатация: GitHub Actions, Docker Swarm и Portainer
Когда я переписывал проект на Go, одной из целей было — автоматизировать всё, что можно. Хотелось просто писать код, пушить — и чтобы всё остальное происходило без моего участия. Так появилась связка: GitHub Actions + Docker + Portainer.
Что делает CI/CD пайплайн
После каждого пуша в main запускается пайплайн в GitHub Actions, который проходит по нескольким этапам:
- Генерация Swagger-документации (OpenAPI) 
 Использую библиотеку, которая пробегается по Go-контроллерам и моделям, генерируя- swagger.yaml.
 Документация всегда остаётся актуальной — теперь её не нужно обновлять вручную.
- Сборка Docker-образа 
 Благодаря Go, итоговый бинарник получается лёгким и не требует JVM.
 Использую- multi-stage Dockerfile:
 сначала- golang, затем финальный слой на- alpine.
- Доставка и обновление 
 Готовый- .tar-архив отправляется через- scpна сервер,
 загружается в локальный Docker Registry (- localhost:5000),
 а затем выполняется- docker service update— и сервис обновляется.
Почему Docker Swarm, а не Kubernetes?
Kubernetes — мощный инструмент, но для одного сервера — перебор.
 Я выбрал Docker Swarm, потому что:
- он встроен в Docker (не требует отдельной установки); 
- не нужно писать десятки YAML-файлов; 
- достаточно одной команды: - docker stack deploy.
Если в будущем понадобится Kubernetes — архитектура проекта к этому готова. Миграция будет безболезненной.
Portainer — визуальный контроль и автоматизация
Чтобы не прыгать по ssh и docker ps, я подключил Portainer — лёгкую и удобную веб-панель.

ai_chat (бэкенд и фронт в одном сервисе), PostgreSQL для хранения данных и NGINX как SSL-прокси через Let's Encrypt. С его помощью можно:
- видеть, какие контейнеры запущены и как работают; 
- быстро перезапускать сервисы; 
- прокидывать переменные окружения без выхода в консоль; 
- смотреть логи, даже если под рукой только браузер. 
Portainer отлично дополняет CI/CD-процесс и даёт контроль «одним глазом».
Мониторинг и планы на будущее
Пока я полагаюсь на логи (docker logs, Portainer UI) и статусы контейнеров
Но в планах:
- 
подключить Prometheus + Grafana для метрик: - количество WebSocket-соединений; 
- время отклика от GPT; 
- загрузка CPU и памяти. 
 
- настроить Alertmanager — чтобы оповещения приходили автоматически (Telegram, Email и т.д.). 
Что ещё хочется внедрить
- нагрузочное тестирование; 
- CI-пайплайн для фронта и его сборка отдельно от бэка; 
- отдельные контейнеры для фоновых задач (модерация, чистка логов и др.); 
- ролевая модель доступа на уровне инфраструктуры. 
Вывод
Pet-проекту не нужен Kubernetes — пока. Но если придёт время — я готов.
 Проект уже контейнеризирован, CI работает, инфраструктура гибкая.
А пока связка GitHub Actions + Docker Swarm + Portainer даёт всё, что нужно:
- быстрое развёртывание; 
- простое обновление; 
- уверенность, что всё под контролем. 
Интеграция GPT-4: как устроен AI-чат
Когда базовая инфраструктура была готова, я приступил к самому интересному — внедрению AI.

ai-chat: выполнено 439 запросов к Chat Completions с общим объёмом 82.7K входных токенов.  Модель GPT-4 от OpenAI уже тогда казалась чем-то волшебным. Возможность организовать чат, в котором ответы приходят от мощного языкового движка, — звучало как магия. И стало техническим вызовом: как всё это обернуть в потоковое, гибко настраиваемое решение?
Как всё работает внутри
Когда пользователь пишет сообщение, сервер формирует prompt, в который входит:
- system message: описание правил — например, "Ты ассистент в этом приложении, не обсуждай запрещённые темы, отвечай развёрнуто, но сдержанно."
- user message: последнее сообщение пользователя.
- Дополнительный контекст: email, настройки, история сообщений. 
Этот prompt уходит в OpenAI, а в ответ приходит результат — с учётом всех настроек.
Уже сейчас backend поддерживает передачу
temperature,depthи даже пользовательские подсказки к каждому чату — всё это настраивается из UI.
Потоковый режим и WebSocket
Сначала я пробовал обычные REST-запросы. Но быстро понял, что хочется "эффекта живого общения": чтобы бот печатал ответ в реальном времени, а не присылал всё одним куском.
Для этого я включил режим stream в OpenAI API: модель начинает слать ответ токенами, и можно сразу транслировать их на клиент.
 На стороне Go-сервера для каждого подключения запускается горутина, которая читает поток и пересылает данные в WebSocket.
Фронт ловит эти фрагменты и выводит как "печатающийся" текст — результат выглядит живо и даже эмоционально. Такое общение цепляет.
Почему не REST?
REST — это хорошо для запросов с мгновенным результатом. Но для AI-ответов в реальном времени он не подходит:
- нельзя "частями" возвращать текст; 
- frontend не может показать постепенное появление символов; 
- пользователь не понимает, работает ли бот или "завис". 
С WebSocket всё иначе: соединение живое, и каждый токен от GPT немедленно уходит клиенту. И именно это делает чат "живым".
Настройки для гибкости
Пользователь может сам выбрать:
- temperature — насколько креативным будет AI; 
- depth — сколько сообщений учитывать в истории; 
- 
дополнительный контекст — например, "ты общаешься с клиентом по вопросам доставки".  Скриншот показывает реализацию потоковой генерации ответа от GPT через OpenAI API в Go: формируется POST-запрос с флагом stream: true, авторизация идёт по API-ключу, а результат передаётся по чанкам в обработчик.
Это уже реализовано в настройках чата, и сохраняется в базе для каждого пользователя.
Фильтрация и адаптация
Иногда GPT может вернуть что-то вроде:
{ "chat_id": "123", "user_id": "456" }Это технический ответ, который не имеет смысла для обычного пользователя.
 Поэтому я реализовал адаптер, который:
- фильтрует "пустые" JSON-ответы; 
- добавляет - system-сообщения вроде: "В чате участвует user@example.com", чтобы AI понимал контекст;
- 
проверяет стиль общения — например, избегает неприемлемых тем.  На скриншоте показан адаптер, подготавливающий сообщения для GPT: слева — логика фильтрации, добавления email и генерации prompt, справа — системные инструкции (system prompts), автоматически добавляемые в начало переписки. Такой подход помогает модели лучше ориентироваться в диалоге, персонализировать ответы и соблюдать правила поведения в чате. 


Планы по AI: дальше — больше
Уже сейчас GPT-4 — ядро всей интеллектуальной логики приложения. Но хочется пойти дальше:
- Подключить другие модели для задач: GPT-4o, Vision, Whisper (голос), парсинг изображений. 
- Обработка вложений: например, пользователь присылает фото, а модель анализирует его и формирует ответ. 
- Настроить бизнес-роли: консультант, продавец, помощник поддержки — чтобы ответы были не просто текстом, а соответствовали цели чата. 
- Добавить параметры вроде - max_tokens,- stop_sequence, интеграцию с внешними источниками — например, чтобы бот "смотрел в интернет" при необходимости.
Работая над этим модулем, я понял главное: AI — это не "просто ответ", это диалог, который можно настраивать и развивать. И это, честно, затягивает.
Реальное время на WebSocket: события и непрочитанное
Когда появилась первая интеграция с AI, стало ясно: чтобы чат был по-настоящему живым, нужно уходить от классического подхода с REST-запросами.
 Пользователь не должен ждать, пока кто-то нажмёт F5. Он должен сразу видеть новое сообщение, обновлённый счётчик, или приход уведомления.
Так в проекте появился WebSocket — и с ним, по сути, вторая жизнь приложения.
Почему именно WebSocket?
У REST есть альтернатива — long polling или SSE (Server-Sent Events), но у всех них есть ограничения:
- REST — хорош для запроса и ответа, но не годится для "пуша" от сервера; 
- polling грузит сервер и не даёт мгновенности; 
- SSE работает в одну сторону (только сервер → клиент). 
А WebSocket — это полноценное двустороннее соединение:
- сервер может слать данные в любой момент; 
- клиент может слушать и отправлять одновременно; 
- всё это работает поверх одного TCP-соединения — эффективно и быстро. 
Какие события мы отправляем?
Сервер в любой момент может прислать:
- chat_message— новое сообщение в чате;
- notification— событие вроде "тебя добавили в друзья";
- unread_count— обновление количества непрочитанных.
Каждое событие имеет свой формат, чтобы клиент понимал, как его обработать. Например, chat_message содержит ID чата, отправителя и текст.
Архитектура соединений внутри
Когда клиент подключается к WebSocket:
- Он передаёт JWT (через query или заголовок). 
- Сервер валидирует токен. 
- Создаётся - Session: WebSocket + userId + список чатов.
- Sessionкладётся в- map[userId]Session.
С этой map работают горутины через каналы, чтобы не было гонок и проблем с конкурентностью.
Как работает рассылка
Допустим, пользователь отправляет сообщение в чат:
- оно сохраняется в базу данных; 
- формируется событие - chat_message;
- сервер ищет всех участников чата; 
- у кого открыт WebSocket — тем сразу отправляется сообщение; 
- если пользователь офлайн — сообщение считается непрочитанным. 
Подсчёт непрочитанных
У каждого пользователя:
- в базе хранится количество непрочитанных сообщений; 
- в памяти есть актуальные данные для быстрого доступа; 
- в UI — отображается badge со счётчиком. 
Когда пользователь открывает чат:
- счётчик сбрасывается; 
- отправляется событие - unread_count, чтобы UI обновился.

Пример обработки в реальном времени
У каждого пользователя есть своя горутина и канал сообщений:
type Session struct {
    conn *websocket.Conn
    send chan Event
}
Сервер пишет события в канал, а воркер читает их и шлёт в WebSocket.
 Так можно безопасно и быстро отправлять сообщения, не блокируя основную логику.
Что ещё работает через WebSocket
- Ответы от GPT — прямо по мере генерации; 
- Уведомления — новые друзья, приглашения; 
- Ошибки — если что-то пошло не так, клиент узнаёт мгновенно; 
- Статусы — кто в онлайне, кто набирает текст (в планах). 

ProcessStreamingResponse, отвечающей за обработку потоковых AI-ответов от OpenAI в реальном времени. Слева — структура проекта с модулями, а справа — код, который читает входящий поток построчно, парсит JSON-чанки и передаёт их в WebSocket-клиент. Этот механизм лежит в основе стриминга ответов от GPT-4, обеспечивая эффект «печатающегося» текста прямо в чате.  В результате чат стал ощущаться живым. Нет задержек, нет пустых экранов, нет ощущения "ничего не происходит".
 И всё это — на одном компактном соединении. Легко, быстро и эффективно.
А главное — архитектура уже сейчас позволяет масштабировать систему: новые события, новые типы соединений, разделение каналов по тематикам — всё можно добавить без боли.
Архитектура проекта: минимум слоёв, максимум простоты
Переписывая проект на Go, я не стал изобретать архитектуру с нуля. Вместо этого — взял лучшее из привычного мира Spring и адаптировал к философии Go.
 Результат получился простым, но мощным — как раз то, что нужно для быстрого старта и лёгкого развития.
? Структура проекта
Я разбил код по директориям:
- routes— настройка маршрутов и привязка к обработчикам;
- controllers— обработка запросов, валидация, вызов сервисов;
- services— бизнес-логика, работа с БД, GPT и т.д.;
- models— все структуры: модели БД, DTO и вспомогательные типы.
Такой подход делает проект понятным с первого взгляда.
 Заходишь в services — и сразу видишь, где живёт основная логика. Всё читаемо и без лишней "магии".
Почему я отказался от репозиториев
В Java-мире я привык к схеме controller → service → repository. Но в Go она не всегда нужна.
Вот мои причины отказаться от repository:
- GORM уже предоставляет удобные методы: - db.First,- db.Where,- db.Create— и так далее;
- Интерфейсы Go и так дают нужную гибкость для тестов; 
- Чем меньше абстракций — тем проще и быстрее писать код. 
Если в будущем захочу подменить БД или вынести слой доступа — легко добавлю интерфейс и внедрю его. Но пока всё работает и без этого.
В итоге получился проект с минимальным количеством слоёв, но с максимальной ясностью.
 Go помогает писать просто, и эта архитектура отражает именно такой подход: никаких фабрик, DI-контейнеров и обёрток без необходимости.
Код — как открытая книга. И это даёт огромное удовольствие от работы.
Безопасность: HTTPS, WSS, JWT и единый подход для API и WebSocket
Когда строишь даже pet-проект, особенно связанный с личными сообщениями и авторизацией, хочется быть уверенным: данные пользователей защищены. Поэтому я сразу закладывал продакшен-подход — без компромиссов.
HTTPS и WSS: шифруем всё
Чат обменивается чувствительной информацией:
- AI-ответы могут содержать личные вопросы, 
- WebSocket передаёт сообщения в реальном времени, 
- Авторизация построена на токенах. 
Всё это должно передаваться только в зашифрованном виде.
Поэтому:
- Сервер работает через HTTPS, 
- WebSocket подключается только по WSS, 
- Сертификат TLS — от Let's Encrypt, с автопродлением через - certbot.
? Почему это важно?
 Потому что большинство браузеров не разрешают незащищённые WebSocket-соединения, если страница загружена по HTTPS. А ещё — потому что безопасность по умолчанию экономит нервы.
JWT: единый способ авторизации
Для всех защищённых API — и REST, и WebSocket — я использую JWT.
Что внутри токена:
- userId,
- exp(время жизни),
- (в будущем — - role).
Как это работает:
- После логина клиент получает JWT. 
- Для REST-запросов он кладёт токен в заголовок - Authorization.
- Для WebSocket — передаёт в query-параметре или header. 
Сервер на каждом шаге проверяет:
- подпись токена, 
- срок действия, 
- и если всё ок — прокидывает - userIdв контекст.
Если токен просрочен или подделан — пользователь получает 401 Unauthorized и дальше не проходит.
Централизованная обработка ошибок
Для REST API — ошибки всегда возвращаются в виде JSON:
{
  "code": "auth.invalidToken",
  "message": "Token expired"
}
Для WebSocket — соединение закрывается, но перед этим клиент получает финальное сообщение:
{
  "code": "webSocket.closed",
  "message": "WebSocket для уведомлений закрыт, повторное подключение..."
}
Такой подход делает поведение приложения предсказуемым — и удобным для фронтенда.
Recovery и устойчивость
Чтобы не уронить сервер при панике (например, из-за nil-указателя), я подключил middleware Recovery. Также пишутся логи всех запросов и ошибок.

Это помогает быстрее находить баги и не бояться нестандартных ситуаций в продакшене.
Хеширование сообщений в базе
Кроме защиты канала передачи данных, я позаботился и о хранении. Все сообщения, которые отправляются через чат — и от пользователя, и от AI — сохраняются в базу в хешированном виде (через SHA-256).
Зачем это нужно:
- Дополнительный уровень защиты — даже если кто-то получит доступ к БД, он не сможет прочитать переписку. 
- Соблюдение приватности — сообщения могут быть чувствительными, и даже на pet-проекте хочется спать спокойно. 
- Прозрачная архитектура — хранение текстов без явного содержания упрощает юридические и этические аспекты при дальнейшем развитии проекта. 
Важно: хеширование применяется только к сохранённой копии в базе, а не к передаваемым сообщениям в реальном времени. Таким образом, можно реализовать аналитику, поиск и другие фичи, если потребуется — без ущерба безопасности.

content не хранит открытый текст — сообщения сохраняются в зашифрованном (или хешированном) виде. Это сделано для защиты личной переписки пользователей от утечек даже в случае доступа к базе данных.  В будущем — роли и права
Сейчас все пользователи равны. Но JWT уже содержит поле role, и я планирую:
- admin— доступ к модерации,
- support— аналитика и техподдержка,
- bot— автоответы и системные события.
Роли будут проверяться на уровне middleware, а значит, основную логику менять не придётся.
 Вывод:
 Безопасность — это не второстепенная задача, а фундамент всей системы. Я заложил продакшен-подход с самого начала: от HTTPS и WSS до JWT и централизованной обработки ошибок. А дополнительное хеширование сообщений в базе — это страховка от любых утечек. Теперь я точно знаю: пользовательские данные под защитой, а архитектура готова к масштабированию, ролям и новым требованиям. 
Трудности разработки: горутины, фронтенд и помощь GPT
Go, WebSocket и OpenAI — это не только про новые технологии, но и про множество граблей, которые на них лежат. И про то, как с этими граблями можно танцевать — особенно если рядом есть GPT.
Горутины и конкурентность
Go отлично справляется с многопоточностью, но он не прощает невнимательности. Я столкнулся с классической ошибкой:
- Хранил все активные WebSocket-соединения в - map[userId]session,
- Писал в неё из нескольких горутин, 
- Не поставил - mutex.
Итог — гонка данных, падения, баги.
Race Detector сразу подсветил проблему, и я добавил sync.Mutex вокруг доступа к карте. Таких мелочей было много: где-то забытый defer close(), где-то лишний канал, который блокировал всю систему.
GPT оказался здесь не просто полезным — он стал настоящим напарником:
- Подсказывал, как правильно синхронизировать доступ, 
- Объяснял поведение горутин, 
- Помогал проектировать очереди и worker'ы. 
Трудности с полнотекстовым поиском
Ещё один открытый вопрос — это реализация полнотекстового поиска по сообщениям. Поскольку содержимое сообщений хранится в базе в хешированном виде, обычный поиск по тексту невозможен.
 Хочется дать пользователю возможность искать по истории, но:
- Простой LIKE не сработает (контент не в открытом виде), 
- PostgreSQL Full Text Search тоже не применим к хешам, 
- Расшифровка сообщений на лету — небезопасна и затратна. 
? Пока у меня нет идеального решения. Возможно, нужно будет хранить отдельный индекс расшифрованных сообщений в защищённой таблице, использовать внешнюю систему (например, Elasticsearch) или проектировать поиск как отдельный сервис с доступом только по JWT и ролям.
Фронтенд — как отдельный квест
Я по натуре бэкендер. И когда пришло время сделать UI, начал с чистого JavaScript — без React, Vue и фреймворков.

notification.js, который подключается к WebSocket для получения уведомлений и отслеживает непрочитанные сообщения. Очень много логов для отладки.Хотелось:
- отображать сообщения в реальном времени, 
- видеть, как AI «печатает» ответ, 
- корректно подсчитывать непрочитанное, 
- и просто... чтобы всё выглядело прилично. 
Проблем хватало:
- браузер не успевал отрисовывать символы, если GPT присылал их слишком быстро, 
- scroll вниз не срабатывал на всех браузерах одинаково, 
- токен терялся при перезагрузке страницы. 
С нуля — значит по-новому
Нечто похожее на UI в проекте появилось только на этом этапе. Это дало свободу:
- переписать HTML под API-first подход, 
- сделать WebSocket-логику централизованной, 
- перенести авторизацию и state-менеджмент на JS. 
В какой-то момент приложение из скрипта превратилось в живой чат, с динамикой, всплывающими уведомлениями и ощущением настоящего мессенджера.
GPT — как тиммейт
Было чувство, что работаю в паре:
- я описывал задачу, 
- GPT давал реализацию или подсказывал подход. 
Он помогал не тратить часы на Stack Overflow, а сразу идти к сути.
Вывод:
 Трудности были — но именно они помогли прокачаться.
 Я стал лучше понимать не только Go и JS, но и архитектуру, DevOps, и сам процесс разработки. А GPT помогал пройти этот путь быстрее и увереннее.
Итоги и планы: что получилось и куда двигаться дальше
Этот проект оказался для меня не просто попыткой попробовать Go — это было настоящее приключение. Смена стека, интеграция с GPT-4, борьба с горутинами и JavaScript, настройка DevOps и CI/CD — всё это превратилось в цепочку вызовов, преодоление которых дало невероятное ощущение роста.
Что получилось:
- Я собрал полноценный AI-чат с WebSocket и GPT-4; 
- Настроил CI/CD на GitHub Actions с автообновлением через Portainer; 
- Развернул прод через Docker Swarm без боли; 
- Реализовал стриминг сообщений и работу в реальном времени; 
- Погрузился в Go и его конкурентную модель; 
- Написал свою первую большую статью 
Что дальше?
Проект только начинается. Вот что планирую делать:
- Развивать авторизацию и роли — добавить разграничение доступа, например, для поддержки, аналитики или автоматизации; 
- Прокачать AI — дать пользователю больше настроек, выбор ассистента, возможность использовать другие модели; 
- Обновить фронт — сделать его адаптивным и дружелюбным для мобильных; 
- Запустить нагрузочное тестирование — чтобы понять пределы; 
- Добавить централизованное логирование и мониторинг; 
- 
Подключить внешние API — например: - API погоды, чтобы бот мог отвечать на бытовые вопросы; 
- YouTube или Spotify API — для рекомендаций и поиска контента; 
- OCR/анализ изображений (например, через Vision API) — чтобы распознавать текст или предметы на картинках; 
- сервисы по верификации пользователей (email, телефон); 
- или даже интеграция с CRM-системой — чтобы AI мог подсказывать по клиентским данным. 
 
Немного личного
Эту статью я заканчиваю в майские праздники — когда вся страна празднует День Победы. И пусть это совсем другая история, но для меня эти дни стали символом победы над собой: над усталостью, над страхом перед незнакомым, над отсутствием времени и над собственными сомнениями.
Спасибо, что дочитали до конца 
 Если вы задумываетесь о переходе с Kotlin/Java на Go — возможно, мой опыт вдохновит вас на первый шаг.
 Или хотя бы напомнит: любой pet-проект — это уже шаг вперёд.
 GPT может быть настоящим помощником, если его правильно использовать.
 Новые технологии — это не страшно. Это интересно. Буду рад вашим вопросам, комментариям и идеям.
Комментарии (12)
 - saag16.05.2025 18:26- Наблюдал как из каждой радиоточки было педалирование Котлина, теперь такой свитчинг в другие языки...  - nekoluchiy Автор16.05.2025 18:26- Спасибо, что читаете. - Kotlin остаётся моим основным рабочим инструментом в финтехе, где важна совместимость с существующим Java-стеком и зрелая экосистема. - Go в этом проекте — способ расширить экспертизу и сравнить, как в реальных условиях ведут себя корутины и горутины: по стабильности, масштабируемости, отладке и поведению под нагрузкой. Особенно интересно было протестировать асинхронную работу с OpenAI через стриминг токенов — в Go с горутинами и каналами это реализуется довольно естественно, без дополнительных библиотек. - В дальнейшем хочу продолжить развивать тему — уже с акцентом на производительность, профилирование и реальные сценарии. 
 
 - Sunknown16.05.2025 18:26- Странно читать про защищенность данных пользователей, когда все данные из чата улетают за бугор в прямом эфире.  - nekoluchiy Автор16.05.2025 18:26- Справедливое замечание. Сейчас проект использует OpenAI API как наиболее доступное и мощное решение для генерации ответов — в том числе ради эксперимента и быстрого старта. - Но архитектура чата построена таким образом, что модель можно заменить — например, на свою LLM, развернутую локально или в изолированном контуре. Для этого достаточно адаптировать один сервис, отвечающий за генерацию ответов. Возможность полного контроля над обработкой данных — как раз один из аргументов в пользу собственной модели. - Кстати, на Хабре действительно есть отличные статьи про развертывание LLM в закрытом контуре — рекомендую. 
 
 - Mhapach16.05.2025 18:26- Красавчик. Чувствуется системный подход и работа в Энтерпрайзе. Была та же идея год назад написать проксирующий сервис для различных моделей, но 100500 причин не дали. Рекомендация - предусмотреть возможность расширения решения на мобайл 
 - nekoluchiy Автор16.05.2025 18:26- Спасибо! Да, мобайл звучит разумно — особенно если появится реальный кейс. Пока приоритет — добить роли, метрики, стабильность. А там посмотрим, будет время — расширим. 
 - dpvpro16.05.2025 18:26- Основательная статья. Мне понравилось. Почерпнул некоторые вещи, например про Portainer. 
 - yrub16.05.2025 18:26- так на spring boot такие же приложения точно так же компилируются сек за 5 и запускаются за 2. + вроде если докер контейнер собираешь, то он умеет еще и aot-cdc прогнать чтоб на проде ускорить запуск с этим профилем еще на 40%, при этом вам руками ничего делать не надо. учитывая, что ваш сервер это прокси между gpt и юзером то можно одной строчкой включить виртуальные потоки и обрабатывать тысячи тысяч параллельных запросов. + вы получаете все плюшки спринг бута в виде удобного тестирования всех уровней. из плюсов go только то что он сильно меньше памяти кушает в сравнении с приложениями такого же (малого) функционала. горутины прикольно, но насколько понимаю можно с каналами накосячить и получить разные проблемы - следовательно под это желательно иметь тесты. в общем если у вас дохлая vps и вы хотите запустить на ней все ваши pet проекты в количестве 10 штук - норм, в остальном сомнительная замена. В принципе если сильно хочется то можно и graalvm заюзать и точно так же собрать exe с сильно меньшим потреблением памяти, но мне было бы лень без острой необходимости ждать пока это скомпилируется и резолвить проблемы, хотя опять-таки, для вашего случая наверно все заработает сразу и дополнительно для нативного имиджа ничего делать не придется. В общем я фишку го не выкупаю, я хочу язык с большим количеством крутых фич на котором я минимальным кодом буду делать много. Ну а так сэкономлю я 250 мб памяти (в лучшем случаи), но сейчас разве это проблема? Вроде как за компьют деньги просят.  - nekoluchiy Автор16.05.2025 18:26- Спасибо за развёрнутый и точный комментарий — особенно ценно, что подметил сильные стороны JVM: AOT, CDC, виртуальные потоки, тестируемость. Всё так и есть — сейчас с этим действительно удобно жить. Полностью согласен, что Spring Boot отлично подходит для прокси-сервисов, особенно когда важна скорость разработки и зрелость экосистемы. - Но тут история была не про замену, а про попробовать другой стек на реальном проекте. Хотелось посмотреть, как Go поведёт себя с WebSocket, стримингом, CI/CD и в целом в продакшене. Планирую сделать сквозное нагрузочное тестирование и сравнить, как чувствуют себя корутины и горутины под нагрузкой. - Ну и в целом — если бы я шёл только от здравого смысла и плюшек JVM, этой статьи бы не появилось. Иногда надо просто сделать шаг в сторону, чтобы прочувствовать всё на практике. 
 
 
           
 
Krokochik
В итоге про Go только 1% статьи, остальное про CI/CD, Docker, GPT (?) - в общем, про вещи с заявленной темой не связанные...
nekoluchiy Автор
Спасибо, что прочитал и за замечание. Вижу, что пользователи хотят больше технических подробностей(название ввело в заблуждение). Не хочется, чтобы «много-букав» превращались в гайд и код-ревью. В общем буду работать над материалом лучше.