BorisovAI

Блог

Публикации о процессе разработки, решённых задачах и изученных технологиях

Найдено 20 заметокСбросить фильтры
Новая функцияC--projects-bot-social-publisher

SQLite спасает день: масштабируемая БД вместо хаоса в памяти

# SQLite вместо памяти: как я спас Telegram-ботов от хаоса Проект `bot-social-publisher` взлетал буквально на глазах. Каждый день новые пользователи подключали своих ботов, запускали кампании, расширяли функционал. Но в какой-то момент понял: у нас есть проблема, которая будет только расти. Где-то в недрах памяти процесса валялась вся информация о том, какие чаты под управлением, кто их владелец, какие у них настройки. Приватный чат? Группа? Канал? Всё это было либо в переменных, либо в логах, либо вообще только в голове. Когда рост пользователей начал экспоненциальный скачок, стало ясно: **нужна нормальная база данных. Правильная, масштабируемая, без требований на отдельный сервер**. **Первым делом посмотрел на то, что уже есть.** В проекте уже была собственная SQLite база в `data/agent.db`, и там спокойно жил `UserManager` — отличный пример того, как работать с асинхронными операциями через `aiosqlite`. Логика была простой: одна база, одна инфраструктура, одна точка подключения для всей системы. Так почему бы не применить ту же философию к чатам? Архитектурное решение созревало быстро. Не было никаких грёз о микросервисах, Redis-кэшах или какой-то сложности. Нужна таблица `managed_chats` с полями для `chat_id` (первичный ключ), `owner_id` (связь с пользователем), `chat_type` с `CHECK` constraint для валидации типов, `title` для названия и JSON-поле `settings` про запас на будущее. **Неожиданно выяснилось** — и это было критично — что индекс на `owner_id` вообще не опциональная штука. Когда пользователь запрашивает список своих чатов, база должна найти их за миллисекунды, а не сканировать таблицу от начала до конца. SQLite часто недооценивают в стартапах, думают, что это игрушка для тестирования. На самом деле при правильном использовании индексов и подготовленных SQL-statements она справляется с миллионами записей и может быть полноценной боевой базой. Реализацию сделал по образцу `UserManager`: создал `ChatManager` с асинхронными методами `add_chat()`, `is_managed()`, `get_owner()`. Каждый запрос параметризован — никаких SQL-injection уязвимостей. Всё та же `aiosqlite` для асинхронного доступа, один способ работать с данными, без дублирования логики. Красивый момент получился благодаря `INSERT OR REPLACE` — если чат переиндексируется с новыми настройками, старая запись просто заменяется. Это вышло из архитектуры, не планировалось специально, но сработало идеально. **В итоге:** одна БД, одна инфраструктура, индекс уже готов к аналитическим запросам на будущее, JSON-поле ждёт расширенных настроек. Никаких ORM-фреймворков, которые на этом этапе обычно добавляют больше проблем, чем решают. Дальше — интеграция с обработчиками Telegram API, где эта информация начнёт по-настоящему работать. Но то уже следующая история. 😄 Разработчик говорит: «Я знаю SQLite». HR: «На каком уровне?». Разработчик: «На уровне, когда она работает, и я этому не верю».

#claude#ai#python#javascript#api#security
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

SQLite вместо памяти: как обуздать рост Telegram-ботов

# Управляем Telegram-чаты как должно: от памяти к базе данных Проект `bot-social-publisher` рос как на дрожжах. Каждый день новые пользователи подключали своих ботов, запускали кампании, развивали функционал. Но вот беда: где-то в памяти процесса валялась информация о том, какие чаты под управлением, кто их владелец, какие у них настройки. Приватный чат? Группа? Канал? Всё это было либо в переменных, либо где-то в логах. Нужна была система. Правильная, масштабируемая, не требующая отдельного сервера для базы данных. **Первым делом** посмотрел, как устроен текущий стек. В проекте уже была собственная SQLite база в `data/agent.db`, и там жил `UserManager` — отличный пример того, как правильно работать с асинхронными операциями через `aiosqlite`. Значит, нужно просто добавить новую таблицу `managed_chats` в ту же базу, скопировать философию управления пользователями и запустить в production. **Архитектурное решение** было ясно с самого начала: никаких микросервисов, никаких Redis-кэшей для этого этапа. Нужна таблица с полями для `chat_id` (первичный ключ), `owner_id` (связь с пользователем), `chat_type` (с проверкой через `CHECK` constraint — только валидные типы), `title` и JSON-поле `settings` на будущее. Неожиданно выяснилось, что индекс на `owner_id` — это не опциональная штука. Когда пользователь запрашивает список своих чатов, база должна найти их быстро, а не сканировать всю таблицу от начала до конца. SQLite часто недооценивают в стартапах, думают, что это игрушка для тестирования. На самом деле при правильном использовании индексов и подготовленных statements она справляется с миллионами записей и может быть полноценной боевой базой. **Реализацию** сделал по образцу `UserManager`: создал `ChatManager` с асинхронными методами `add_chat()`, `is_managed()`, `get_owner()`. Каждый запрос параметризован — никаких SQL injection уязвимостей. Используется всё та же `aiosqlite` для асинхронного доступа, одна точка подключения для всей системы, без дублирования логики. Красивый момент получился благодаря `INSERT OR REPLACE` — если чат переиндексируется с новыми настройками, старая запись просто заменяется. Это вышло из архитектуры, а не планировалось специально. В итоге: одна БД, одна инфраструктура, масштабируемая схема. Когда понадобятся сложные аналитические запросы — индекс уже есть. Когда захотим добавить права доступа или расширенные настройки чата — JSON-поле ждёт. Никаких фреймворков ORM, которые обычно добавляют больше проблем, чем решают на этом этапе. Дальше — интеграция с обработчиками Telegram API, где эта информация будет реально работать. Но то уже следующая история. 😄 Разработчик: «Я знаю ArgoCD». HR: «На каком уровне?». Разработчик: «На уровне Stack Overflow».

#claude#ai#python#javascript#api#security
9 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Когда AI становится парным программистом: история Claude Code

# Claude Code встречает разработчика: история создания идеального помощника Павел открыл **voice-agent** — проект, который стоял уже полгода в статусе "building". Python-бэкенд на FastAPI, Next.js фронтенд, асинхронная обработка аудио через aiogram. Задача была понятна: нужна система, которая может помочь в разработке, не мешая, не спрашивая лишних вопросов, а просто работая рядом. Первым делом команда определилась с подходом. Не просто документация, не просто chatbot, а **пара-программист** — инструмент, который понимает контекст проекта, может писать код, отлаживать, запускать тесты. На этапе 2010-х годов, когда началась фаза Deep Learning, никто не предполагал, что в 2020-х мы будем говорить о когда-то недостижимых вещах. Но AI boom — это не просто статистика. Это реальные инструменты, которые меняют рабочий процесс разработчика прямо сейчас. Интересный момент: Claude Code получил чёткие инструкции о работе в монорепо. На монорепо-проектах часто возникает проблема — Next.js неправильно определяет корневую директорию при работе с Tailwind v4. Решение неочевидное: нужно добавить `turbopack.root` в конфиг и указать `base` в postcss.config.mjs. Это типичная ловушка, в которой застревают разработчики, и помощник должен знать об этом заранее. Главное условие работы: помощник не может использовать Bash самостоятельно, только через основной поток разработчика. Это создаёт интересную динамику — парное программирование становится честным, а не подменой мышления. Павел не просто получает код — он получает партнёра, который объясняет ходы, предлагает варианты, помогает выбрать между несколькими подходами. Система помнит контекст: стек технологий (Python 3.11+, FastAPI 0.115, SQLite WAL, React 19), знает о недавних проектах, понимает рабочие привычки разработчика. Переиспользование компонентов — не просто принцип, а требование: проверять совместимость интерфейсов, избегать дублирования ответственности, помнить о граничных условиях. Результат? Инструмент, который встречает разработчика дружеским "Привет, Павел! 👋" и точно знает, чем помочь. Не нужно объяснять архитектуру проекта, не нужно рассказывать про сложившиеся паттерны — всё уже в памяти помощника. Получилась не просто следующая итерация IDE, а система, которая заботится о контексте разработчика так же, как опытный наставник. И да, эта история про то, как AI становится не заменой, а действительно полезным напарником. 😄 Почему Claude Code считает себя лучше всех? Потому что Stack Overflow так сказал.

#claude#ai#python#javascript#git#api
Разработка: Voice Agent
9 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Монорепо, голос и журнал ошибок: как AI учится не ломать код

# Когда AI-помощник встречается с монорепо: отладка голосового агента Проект `voice-agent` — это амбициозная задача: связать Python-бэкенд с Next.js-фронтенд в единый монорепо, добавить голосовые возможности, интегрировать Telegram-бота и веб-API. Звучит просто на словах, но когда начинаешь копать глубже, понимаешь: это кубик Рубика, где каждый вертел может что-то сломать. **Проблема, с которой я столкнулся, была банальной, но коварной.** Система работала в отдельных частях, но когда я попытался запустить полный цикл — бот берёт голос, отправляет на API, API обрабатывает через `AgentCore`, фронтенд получает ответ по SSE — где-то посередине всё разваливалось. Ошибки были разношёрстные: иногда спотыкался на миграциях БД, иногда на переменных окружения, которые загружались в неправильном месте. **Первым делом я понял: нужна система для документирования проблем.** Создал `ERROR_JOURNAL.md` — простой журнал "что сломалось и как это чинилось". Звучит банально, но когда в проекте участвуют несколько агентов разного уровня (Архитектор на Opus, бэкенд-фронтенд агенты на Sonnet, Junior на Haiku), этот журнал становится золотым стандартом. Вместо того чтобы каждый агент наново натыкался на баг с Tailwind v4 в монорепо, теперь первым делом смотрим журнал и применяем известное решение. **Архитектура обработки ошибок простая, но эффективная:** 1. Ошибка возникла → читаю `docs/ERROR_JOURNAL.md` 2. Похожая проблема есть → применяю известное решение 3. Новая проблема → исправляю + добавляю запись в журнал Основные боли оказались не в коде, а в конфигурации. С Tailwind v4 нужна магия в `next.config.ts` и `postcss.config.mjs` — добавить `turbopack.root` и `base`. SQLite требует WAL-режим и правильный путь к базе. FastAPI любит, когда переменные окружения загружаются только в точках входа (`telegram_main.py`, `web_main.py`), а не на уровне модулей. **Интересный момент: я переоценил сложность.** Большинство проблем решались не рефакторингом, а правильной организацией архитектуры. `AgentCore` — это единое ядро бизнес-логики для бота и API, и если оно валидируется с одной строки (`python -c "from src.core import AgentCore; print('OK')"`), весь стек работает как часы. **Итог:** система работает, но главный урок не в технических трюках — в том, что монорепо требует прозрачности. Когда каждая составляющая (Python venv, Next.js сборка, миграции БД, синхронизация переменных окружения) задокументирована и протестирована, даже сложный проект становится управляемым. Теперь каждый новый агент, который присоединяется к проекту, видит ясную картину и может сразу быть полезным, вместо того чтобы возиться с отладкой. На следующем этапе плотнее интегрирую streaming через Vercel AI SDK Data Stream Protocol и расширяю систему управления чатами через новую таблицу `managed_chats`. Но это — уже другая история. 😄 Что общего у монорепо и парка развлечений? Оба требуют хорошей разметки, иначе люди заблудятся.

#claude#ai#python#javascript#git#api#security
Разработка: Voice Agent
9 февр. 2026 г.
Новая функция

Одна БД для всех: как мы добавили чаты без архитектурного хаоса

# Одна база на всех: как мы добавили управление чатами без архитектурного хаоса Когда проект растёт, растут и его аппетиты. В нашем Telegram-боте на основе Python уже была отличная инфраструктура — `UserManager` для управления пользователями, собственная SQLite база в `data/agent.db`, асинхронные запросы через `aiosqlite`. Но вот беда: чат-менеджер ещё не появился. А он нам был нужен. Стояла вот какая задача: нужно отслеживать, какие чаты управляет бот, кто их владелец, какой это тип чата (приватный, группа, супергруппа, канал). При этом не создавать отдельную базу данных — это же кошмар для девопса — а переиспользовать существующую инфраструктуру. **Первым делом** заглянул в текущую архитектуру. Увидел, что всё уже завязано на одной БД, один конфиг, одна логика подключения. Идеально. Значит, нужна просто одна новая таблица — `managed_chats`. Задумал её как простую структуру: `chat_id` как первичный ключ, `owner_id` для связи с пользователем, `chat_type` с проверкой типов через `CHECK`, поле `title` для названия и JSON-колонка `settings` на будущее. Обычно на этом месте разработчик бы создал абстрактный `ChatRepository` с двадцатью методами и паттерном `Builder`. Я же решил сделать проще — скопировать философию `UserManager` и создать классический `ChatManager`. Три-четыре асинхронных метода: добавить чат, проверить, управляется ли он, получить владельца. Всё на `aiosqlite`, как и везде в проекте. **Неожиданно выяснилось**, что индексы — это не украшение. Когда начну искать чаты по владельцу, индекс на `owner_id` будет спасением. SQLite не любит полные скены таблиц, если можно обойтись поиском по индексу. Интересный момент: SQLite часто недооценивают в стартапах, думают, что это игрушка. На самом деле она справляется с миллионами записей, если её правильно использовать. Индексы, `PRAGMA` для оптимизации, подготовленные statements — и у вас есть боевая база данных. Многие проекты потом переходят на PostgreSQL только потому, что привыкли к MySQL, а не из реальной нужды. В итоге получилась чистая архитектура: одна БД, одна точка подключения, новая таблица без какого-либо дублирования логики. `ChatManager` живёт рядом с `UserManager`, используют одни и те же библиотеки и утилиты. Когда понадобятся сложные запросы — индекс уже есть. Когда захотим добавить настройки чата — JSON-поле ждёт. И никаких лишних микросервисов. Следующий шаг — интегрировать это в обработчики событий Telegram API. Но это уже другая история. 😄 Почему база данных никогда не посещает вечеринки? Её постоянно блокирует другой клиент!

#clipboard#python#javascript#git#security
9 февр. 2026 г.
Новая функцияtrend-analisis

AI изучает себя: как мы мониторим научные тренды

# Когда AI исследует сам себя: как мы строили систему мониторинга научных трендов Вот уже несколько недель я сидел над проектом **trend-analisis** и постепенно понимал: обычный парсер научных статей — это скучно и малоэффективно. Нужна была система, которая не просто собирает ссылки на arXiv, а *понимает*, какие исследовательские направления сейчас набирают силу и почему они имеют значение для практиков вроде нас. Задача стояла серьёзная: проанализировать тренд под названием "test SSE progress" на основе контекста передовых научных статей. Звучит сухо, но на деле это означало — нужно было построить мост между миром фундаментальных исследований и инженерными решениями, которые уже завтра могут оказаться в production. ## Что творится в AI-исследованиях прямо сейчас Первым делом я разобрался, какие пять основных направлений сейчас наиболее активны. И вот что получилось интересное: **Мультимодальные модели всё более хитрые.** Появляются проекты вроде **SwimBird**, которые позволяют языковым моделям переключаться между разными режимами рассуждения. Это не просто пухлая нейросеть — это система, которая знает, когда нужно "думать", а когда просто генерировать. **Геометрия — это новый король.** Статьи про пространственное рассуждение показывают, что просто скормить модели килотонны текста недостаточно. Нужны геометрические приоры, понимание 3D-сцен, позиции камер. Проект **Thinking with Geometry** буквально встраивает геометрию в процесс обучения. Звучит как философия, но это работает. **Retrieval-системы перестают быть простыми.** Исследование **SAGE** показало, что для глубоких исследовательских агентов недостаточно BM25 или даже простого векторного поиска. Нужны умные retriever'ы, которые сами знают, что ищут. **Дешёвые модели становятся умнее.** Работы про влияние compute на reinforcement learning показывают: вопрос уже не в том, сколько параметров у модели, а в том, как эффективно использовать доступные ресурсы. Это открывает путь к edge AI и мобильным решениям. **Generative модели наконец-то становятся теоретически понятнее.** Исследования про generalization в diffusion models через inductive biases к ridge manifolds — это не просто красивая математика. Это значит, мы начинаем понимать, *почему* эти модели работают, а не просто наблюдаем результаты. ## Как я это собирал На ветке **feat/scoring-v2-tavily-citations** я сделал интересный ход: интегрировал не просто поиск статей, а *контекстный анализ* с использованием мощных LLM. Система теперь не только находит статьи по ключевым словам, но и организует их в экосистемы: какие зоны исследований связаны, кто на них работает, как это может повлиять на индустрию. Неожиданно выяснилось, что самая сложная часть — не техническая. Это правильно определить связи между соседними трендами. Статья про hydraulic cylinders и friction estimation на первый взгляд кажется совершенно отдельной историей. Но когда понимаешь, что это про predictive maintenance и edge computing, видишь, как она связывается с работами про efficient RL. Промышленная автоматизация и AI-на-краю сети — они развиваются параллельно и подпитывают друг друга. ## Маленький инсайт о diffusion models Кстати, пока копался в исследованиях про обобщающую способность diffusion models, наткнулся на замечательный факт: эти модели естественным образом тяготеют к низкомерным многообразиям в данных. Это не баг и не случайность — это встроенное в архитектуру свойство, которое позволяет моделям избежать зубрёжки и научиться реально генерировать новые примеры. Вот такое вот невидимое мастерство работает под капотом. ## Что дальше Система уже в работе, регулярно обновляется с новыми статьями, и каждый раз я вижу, как исследовательские темы переплетаются в более сложные паттерны. Это напоминает наблюдение за живой экосистемой — каждое новое открытие создаёт точки приложения для трёх других. Главное, что я понял: мониторить тренды в AI — это не про сбор информации, это про построение карты будущего. И каждая на первый взгляд узкая статья может оказаться ключевой для вашего следующего проекта. 😄 Обед разработчика: ctrl+c, ctrl+v из вчерашнего меню.

#claude#ai#javascript#security
Разработка: Trend Analisis
9 февр. 2026 г.
ИсправлениеC--projects-bot-social-publisher

Логи, которые врут: как я нашел ошибку в прошлом Traefik

# Traefik и Let's Encrypt: как я нашел ошибку в логах прошлого Проект **borisovai-admin** молча кричал. Пользователи не могли зайти в систему — браузеры показывали ошибки с сертификатами, Traefik выглядел так, будто вообще забыл про HTTPS. На поверхности всё выглядело очевидно: проблема с SSL. Но когда я начал копать, стало ясно, что это детективная история совсем о другом. ## Завязка: четыре недостающих сертификата Задача была на первый взгляд скучной: проверить, действительно ли Traefik получил четыре Let's Encrypt сертификата для admin и auth поддоменов на `.tech` и `.ru`. DNS для `.ru` доменов только что пропагировался по сети, и нужно было убедиться, что ACME-клиент Traefik успешно прошёл валидацию и забрал сертификаты. Я открыл **acme.json** — файл, где Traefik хранит весь свой кеш сертификатов. И тут началось самое интересное. ## Развитие: сертификаты на месте, но логи врут В файле лежали все четыре сертификата: - `admin.borisovai.tech` и `admin.borisovai.ru` — оба выданы Let's Encrypt R12 - `auth.borisovai.tech` и `auth.borisovai.ru` — R13 и R12 Все валидны, все активны, все будут работать до мая. Traefik их отдавал при подключении. Но логи Traefik были заполнены ошибками валидации ACME-челленджей. Выглядело так, будто сертификаты получены, но используются неправильно. Тогда я понял: эти ошибки в логах — **не текущие проблемы, а исторические артефакты**. Когда DNS для `.ru` ещё не полностью пропагировался, Traefik пытался пройти ACME-валидацию, падал, переходил в retry-очередь. DNS резолвился нестабильно, Let's Encrypt не мог убедиться, что домен принадлежит нам. Но как только DNS наконец стабилизировался, всё прошло автоматически. Логи просто записывали *историю пути к успеху*. ## Познавательный момент: асинхронная реальность Вот в чём фишка ACME-систем: они не сдаются после первой же неудачи. Let's Encrypt встроил resilience в саму архитектуру. Когда челлендж не проходит, он не удаляется — он встаёт в очередь на переток. Система периодически переходит сертификаты, ждёт, когда DNS стабилизируется, и потом *просто работает*. То есть когда ты видишь в логах ACME-ошибку прошлого часа, это вообще не означает, что сейчас есть проблема. Это просто означает, что система пережила переходный процесс и вышла на стабильное состояние. Проблема с браузерами была ещё смешнее. Они кешировали старую информацию о неправильных сертификатах и упорно показывали ошибку, хотя реальные сертификаты давно уже валидны. Решение: `ipconfig /flushdns` на Windows или просто открыть incognito-окно. ## Итог **borisovai-admin** работает, все четыре сертификата на месте, все домены защищены. Главный урок: иногда лучший способ отловить баг — это понять, что это вообще не баг, а просто *асинхронная реальность*, которая движется по своему расписанию. Следующий этап — проверить, правильно ли настроены policies в Authelia для этих новых защищённых endpoints. Но это уже совсем другая история. Java — единственная технология, где «это работает» считается документацией. 😄

#claude#ai#javascript#api#security
9 февр. 2026 г.
Исправлениеborisovai-admin

Traefik и Let's Encrypt: как я нашел ошибку в логах прошлого

# Охота на невидимых врагов: как я отловил проблемы с сертификатами в Traefik Когда ты администрируешь **borisovai-admin** и вдруг замечаешь, что половина пользователей не может зайти в систему из-за ошибок сертификатов, начинается самая интересная работа. Задача казалась простой: проверить конфигурацию сервера, DNS и убедиться, что сертификаты на месте. На практике это превратилось в детективную историю про хронологию событий и кеши, которые саботируют твою жизнь. ## Первый подозреваемый: DNS Первым делом я проверил, резолвятся ли доменные имена с сервера. Оказалось, что DNS работает — это был хороший знак. Но почему Traefik выглядит так, будто ему не хватает сертификатов? Я полез в `acme.json`, где Traefik хранит выданные Let's Encrypt сертификаты. И вот тут началось самое интересное. ## Сюрприз в acme.json В файле лежали **все четыре сертификата**, которые мне были нужны: - `admin.borisovai.tech` — Let's Encrypt R12, выдан 4 февраля, истекает 5 мая - `admin.borisovai.ru` — Let's Encrypt R12, выдан 8 февраля, истекает 9 мая - `auth.borisovai.tech` — Let's Encrypt R13, выдан 8 февраля, истекает 9 мая - `auth.borisovai.ru` — Let's Encrypt R12, выдан 8 февраля, истекает 9 мая Все они были **валидны и активны**. Traefik их отдавал при подключении. Логи Traefik, которые я видел ранее, оказались проблемой *ретроспективной* — они относились к моменту, когда DNS-записи для `.ru` доменов ещё *не пропагировались* по сети. Let's Encrypt не мог выпустить сертификаты, пока не мог убедиться, что домен принадлежит мне. ## Невидимый враг: браузерный кеш Последний вопрос был ужасающе простым: почему браузер по-прежнему ругался на сертификаты, если сами сертификаты в порядке? **DNS кеш**. Браузер запомнил старую информацию и упорно её использовал. ## Финальный диагноз Вся история сводилась к тому, что системные часы интернета движутся медленнее, чем кажется. DNS пропагируется асинхронно, сертификаты выдаются с задержкой, а браузеры кешируют запросы агрессивнее, чем кажется разумным. Решение? Очистить DNS кеш командой `ipconfig /flushdns` (для Windows) или открыть инкогнито-окно, чтобы браузер забыл о своих ошибочных воспоминаниях. Проект **borisovai-admin** работает, сертификаты в порядке, все домены защищены. Ирония в том, что проблема была не в конфигурации — она была в нашей нетерпеливости. Главный урок: иногда лучший способ отловить баг — это понять, что это не баг, а *асинхронная реальность*, которая просто медлит. 😄

#claude#ai#javascript#security
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Туннели и таймауты: управление инфраструктурой в админ-панели

# Туннели, Traefik и таймауты: как мы добавили управление инфраструктурой в админ-панель Проект **borisovai-admin** рос не по дням, а по часам. Сначала была одна машина, потом две, потом стало ясно — нужна нормальная система для управления сетевыми туннелями между серверами. Задача выглядела острой: юзеру нужен интерфейс, чтобы видеть, какие туннели сейчас активны, создавать новые и удалять старые. Без этого администрирование превращалось в ручную возню с конфигами на каждой машине. Первое решение было логичным: взял **frp** (Fast Reverse Proxy) — лёгкий инструмент для туннелирования, когда сервер скрыт за NAT или брандмауэром. Почему не что-то более «облачное»? Потому что здесь нужна полная контроль, минимум зависимостей и максимум надёжности. FRP ровно это даёт. Спроектировал веб-интерфейс: добавил страницу `tunnels.html` с простеньким списком активных туннелей, кнопками для создания и удаления. На бэкенде в `server.js` реализовал пять API endpoints для управления состоянием. Параллельно обновил скрипты инсталляции: `install-all.sh` и отдельный `install-frps.sh` для развёртывания FRP сервера, плюс `frpc-template` для клиентов на каждой машине. Не забыл навигационную ссылку «Туннели» на всех страницах админ-панели — мелочь, но юзабилити взлетела. Вроде всё шло гладко, но потом началось. Пользователи начали скачивать большие файлы через GitLab, и соединение рубилось где-то в середине процесса. Проблема оказалась в **Traefik** — наш обратный прокси по умолчанию использует агрессивные таймауты. Стоило файлу загружаться дольше пары минут — и всё, соединение закрыто. Пришлось углубиться в конфиги Traefik. Установил `readTimeout` в 600 секунд (10 минут) и создал специальный `serversTransport` именно для GitLab. Написал скрипт `configure-traefik.sh`, который генерирует две динамические конфигурации — `gitlab-buffering` и `serversTransport`. Результат: файлы теперь загружаются спокойно, даже если это полгигабайта архива. **Интересная особенность Traefik:** это микросервис-балансировщик, который позиционируется как облегчённое решение, но на практике требует хирургической точности при настройке. Неправильный таймаут — и приложение выглядит медленным. Правильный — и всё летает. Один параметр, и мир меняется. Параллельно реорганизовал документацию: разбил `docs/` на логические части — `agents/`, `dns/`, `plans/`, `setup/`, `troubleshooting/`. Добавил полный набор конфигов для конкретного сервера в `config/contabo-sm-139/` (traefik, systemd, mailu, gitlab) и обновил скрипт `upload-single-machine.sh` для их загрузки. За вечер родилась полноценная система управления туннелями с интерфейсом, автоматизацией и нормальной документацией. Проект теперь легко масштабируется на новые серверы. Главное, что узнал: **Traefik** — это не просто прокси, это целая философия правильной конфигурации микросервисов. Дальше в планах: расширение аналитики для туннелей, SSO интеграция и лучший мониторинг сетевых соединений. 😄 **Разработчик**: «Я настроил Traefik». **Пользователь**: «Отлично, тогда почему мой файл не загружается?» **Разработчик**: «А ты пробовал перезагрузить сервер?»

#claude#ai#javascript#git#api
8 февр. 2026 г.
Изменение кодаborisovai-admin

Authelia: как я разобрался с хешами паролей и первым входом в админку

# Запускаем Authelia: логины, пароли и первый вход в админку Проект **borisovai-admin** требовал серьёзной работы с аутентификацией. Стояла простая на первый взгляд задача: развернуть **Authelia** — современный сервер аутентификации и авторизации — и убедиться, что всё работает как надо. Но перед тем как запустить систему в боевых условиях, нужно было разобраться с креденшалами и убедиться, что они безопасно хранятся. Первым делом я заглянул в скрипт установки `install-authelia.sh`. Это был не просто набор команд, а целая инструкция по настройке системы с нуля — 400+ строк, описывающих каждый шаг. И там я нашёл ответ на главный вопрос: логин для Authelia — это просто **`admin`**, а пароль... вот тут начиналось интересное. Оказалось, что пароль хранится в двух местах одновременно. В конфиге Authelia (`/etc/authelia/users_database.yml`) он лежит в виде **Argon2-хеша** — это криптографический алгоритм хеширования, специально разработанный для защиты паролей от перебора. Но на сервере управления (`/etc/management-ui/auth.json`) пароль хранится в открытом виде. Логика понятна: Management UI должна иметь возможность проверить, что введён правильный пароль, но хранить его в открытом виде — это классическая дилемма безопасности. Неожиданно выяснилось, что это не баг, а фича. Разработчики системы сделали так специально: пароль Management UI и пароль администратора Authelia — это один и тот же секрет, синхронизированный между компонентами. Это упрощает управление, но требует осторожности — нужно убедиться, что никто не получит доступ к этим файлам на сервере. Я закоммитил все необходимые изменения в ветку `main` (коммит `e287a26`), и pipeline автоматически задеплоил обновлённые скрипты на продакшн. Теперь, если кому-то понадобится сбросить пароль администратора, достаточно просто зайти на сервер, открыть `/etc/management-ui/auth.json` и посмотреть текущее значение. Не самый secure способ, но он работает, пока файл лежит в защищённой директории с правильными permissions. Главный вывод: при работе с аутентификацией нет мелочей. Каждое хранилище пароля — это потенциальная точка входа для атакующего. **Argon2** защищает от перебора, но открытые пароли в конфигах требуют ещё более строгого контроля доступа. В идеальном мире мы бы использовали системы управления секретами вроде HashiCorp Vault, но для локального dev-сервера такой подход сойдёт. Дальше нужно будет настроить интеграцию Authelia с остальными компонентами системы и убедиться, что она не станет узким местом при масштабировании. Но это история для следующего поста. 😄 Что общего у Scala и подростка? Оба непредсказуемы и требуют постоянного внимания.

#claude#ai#python#javascript#security
8 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Traefik и опциональные middleware: война с зависимостями

# Когда конфиги кусаются: история про зависимые middleware в Traefik Проект `borisovai-admin` — это не просто админ-панель, это целая инфраструктурная система с аутентификацией через Authelia, обратным прокси на Traefik и кучей moving parts, которые должны работать в идеальной гармонии. И вот в один прекрасный день выясняется: когда ты разворачиваешь систему без Authelia, всё падает с ошибкой 502, потому что Traefik мечтательно ищет middleware `authelia@file`, которого просто нет в конфиге. **Завязка проблемы была в статических конфигах.** Мы жёстко прописали ссылку на `authelia@file` прямо в Traefik-конфигурацию, и это работало, когда Authelia установлена. Но стоило её отключить или не устанавливать вообще — бум, 502 ошибка. Получается, конфиги были сильно связаны с опциональным компонентом. Это классический случай, когда инфраструктурный код требует гибкости. Решение разбилось на несколько фронтов. Во-первых, **убрали жёсткую ссылку на `authelia@file` из статических конфигов Traefik** — теперь это просто не указывается в базовых настройках. Во-вторых, создали правильную цепочку инициализации. Скрипт `install-authelia.sh` теперь сам добавляет `authelia@file` в `config.json` и настраивает OIDC при установке. Скрипт `configure-traefik.sh` проверяет переменную окружения `AUTHELIA_INSTALLED` и условно подключает middleware. А `deploy-traefik.sh` перепроверяет на сервере, установлена ли Authelia, и при необходимости переустанавливает `authelia@file`. По ходу дела обнаружилась ещё одна проблема в `install-management-ui.sh` — там был неправильный путь к `mgmt_client_secret`. Исправили. А `authelia.yml` вообще выкинули из репозитория, потому что его всегда генерирует сам скрипт установки. Зачем держать в git то, что одинаково воспроизводится каждый раз? **Интересный момент про middleware в Docker-сообществе:** люди часто забывают, что middleware — это не просто функция, это *объект конфигурации*, который должен быть определён до использования. Traefik здесь строг: ты не можешь ссылаться на middleware, которого не существует. Это похоже на попытку вызвать функцию, которая не импортирована в Python. Простая ошибка, но очень болезненная в production-системах. **Итоговая архитектура** получилась намного гибче: система работает как с Authelia, так и без неё, конфиги не лежат мёртвым грузом в репо, инсталляторы действительно знают, что они делают. Это хороший пример того, как *опциональные зависимости* требуют условной логики не только в коде приложения, но и в инфраструктурных скриптах. Главный урок: если компонент опциональный, не прописывай его в статические конфиги. Пусть туда добавляются динамически при необходимости. 😄 Разработчик: «Я знаю Traefik». HR: «На каком уровне?». Разработчик: «На уровне количества 502 ошибок, которые я пережил».

#claude#ai#python#javascript#git#security
8 февр. 2026 г.
Исправлениеborisovai-admin

Когда конфиги падают: война Traefik с несуществующим middleware

# Когда конфиги кусаются: история про зависимые middleware в Traefik Проект `borisovai-admin` — это не просто админ-панель, это целая инфраструктурная система с аутентификацией через Authelia, обратным прокси на Traefik и кучей moving parts, которые должны работать в идеальной гармонии. И вот в один прекрасный день выясняется: когда ты разворачиваешь систему без Authelia, всё падает с ошибкой 502, потому что Traefik мечтательно ищет middleware `authelia@file`, которого просто нет в конфиге. **Завязка проблемы была в статических конфигах.** Мы жёстко прописали ссылку на `authelia@file` прямо в Traefik-конфигурацию, и это сработало, когда Authelia установлена. Но стоило её отключить или просто не устанавливать — бум, 502 ошибка. Получается, конфиги были сильно связаны с опциональным компонентом. Это классический случай, когда инфраструктурный код требует гибкости. Решение разбилось на несколько фронтов. Во-первых, пришлось **убрать жёсткую ссылку на `authelia@file` из статических конфигов Traefik** — теперь это просто не указывается в базовых настройках. Во-вторых, создали правильную цепочку инициализации: - `install-authelia.sh` теперь сам добавляет `authelia@file` в `config.json` и настраивает OIDC при установке Authelia; - `configure-traefik.sh` проверяет переменную `AUTHELIA_INSTALLED` и условно подключает middleware; - `deploy-traefik.sh` перепроверяет, установлена ли Authelia на сервере, и если да — переустанавливает `authelia@file`. Неожиданный бонус обнаружился в `install-management-ui.sh` — там был неправильный путь к `mgmt_client_secret`. Исправили по ходу. А `authelia.yml` вообще выкинули из репозитория, потому что его генерирует сам скрипт установки. Зачем держать в git то, что всегда одинаково генерируется? **Интересный момент про middleware в Docker-сообществе:** люди часто забывают, что middleware — это не просто функция, это *объект конфигурации*, который должен быть определён до использования. Traefik здесь строг: ты не можешь ссылаться на middleware, которого не существует. Это похоже на попытку вызвать функцию, которая не импортирована в Python. Простая ошибка, но очень болезненная в production-системах, потому что приводит к отказу в обслуживании. **Итоговая архитектура** получилась намного гибче: система работает как с Authelia, так и без неё, конфиги не лежат мёртвым грузом в репо, а инсталляторы действительно знают, что они делают. Это хороший пример того, как *опциональные зависимости* требуют условной логики не только в коде приложения, но и в инфраструктурных скриптах. Главный урок: если компонент опциональный, не прописывай его в статические конфиги. Пусть они туда добавляются динамически при необходимости. 😄 Что будет, если Fedora обретёт сознание? Первым делом она удалит свою документацию.

#git#commit#javascript#security
8 февр. 2026 г.
Новая функцияborisovai-admin

SSO за выходные: как я запустил Authelia на боевом сервере

# Authelia в боевых условиях: как я собрал Single Sign-On за выходные Задача была амбициозная: в проекте **borisovai-admin** нужно было внедрить полноценную систему единой авторизации. На площадке работают несколько приложений — Management UI, n8n, Mailu, и каждое требует свой вход. Кошмар для пользователя и сущее издевательство над принципом DRY. Решение напрашивалось само: **Authelia** — современный SSO-сервер, который справляется с аутентификацией одной рукой и может интегрироваться практически с чем угодно. ## С чего я начал Первым делом создал `install-authelia.sh` — полный скрипт установки, который берёт на себя всю рутину: скачивает бинарник, генерирует секреты, прописывает конфиги и регистрирует Authelia как systemd-сервис. Это был ключевой момент — автоматизация означала, что процесс установки можно повторить в три команды без магических танцев с палочкой. Потом встала задача интеграции с **Traefik**, который у нас отвечает за маршрутизацию. Здесь нужен был `ForwardAuth` — middleware, который перехватывает запросы и проверяет, авторизован ли пользователь. Создал `authelia.yml` с настройкой ForwardAuth для `auth.borisovai.ru/tech`. Суть простая: любой запрос сначала идёт в Authelia, и если она вас узнала — пропускаем дальше, если нет — отправляем на страницу входа. ## Dual-mode, или как угодить двум господам одновременно Самое интересное началось, когда понадобилось поддержать сразу два способа авторизации. Management UI должна работать и как классическое веб-приложение с сессиями, и как API с **Bearer-токенами** через **OIDC** (OpenID Connect). Пришлось написать `server.js` с логикой, которая проверяет, что именно пришло в запросе: если есть Bearer-токен — валидируем через OIDC, если нет — смотрим на сессию. Включил в проект `express-openid-connect` — стандартную библиотеку для интеграции OIDC в Express. Хитрость в том, что Authelia может быть и провайдером OIDC, и middleware ForwardAuth одновременно. Просто берёшь конфиг для OIDC из Management UI, подтягиваешь его в `config.json` через автоопределение (этим займется `install-management-ui.sh`), и всё начинает работать как часы. ## Неожиданный поворот с logout Оказалось, что обычный logout в веб-приложении — это не просто удалить cookie. Если вы авторизовались через OIDC, нужно ещё уведомить Authelia, что сессия закончена. Пришлось настроить пять HTML-страниц с поддержкой OIDC redirect: пользователь нажимает logout, приложение отправляет его в Authelia, Authelia убивает сессию и редиректит обратно на страницу выхода. Выглядит просто, но заставляет задуматься о том, как много движущихся частей в современном веб. ## Интересный факт: ForwardAuth vs Reverse Proxy Authentication Знаешь ли ты, что многие разработчики путают эти два подхода? ForwardAuth — это когда *сам прокси* отправляет запрос на сервер аутентификации. А Reverse Proxy Authentication — это когда *сервер приложения* полностью отдаёт авторизацию на откуп прокси. Authelia работает с обоими, но ForwardAuth даёт больше контроля — приложение всё равно может принять дополнительные решения на основе данных пользователя. ## Итог: от идеи к prod Всё сложилось в единую систему благодаря интеграции на уровне `install-all.sh` — компонент `INSTALL_AUTHELIA` занимает шаг [7.5/10], что означает: это не первый день, но далеко не последний штрих. Management UI теперь умеет сама себя конфигурировать, находя Authelia в сети, подтягивая OIDC-конфиг и автоматически подключаясь. Главное, чему я научился: SSO — это не просто чёрный ящик, куда ты кидаешь пароли. Это *экосистема*, где каждый компонент должен понимать друг друга: ForwardAuth, OIDC, сессии, logout. И когда всё это работает вместе, пользователь вводит пароль *один раз* и может спокойно прыгать между всеми приложениями. Вот это да. Почему React расстался с разработчиком? Слишком много зависимостей в отношениях 😄

#git#commit#javascript#security
8 февр. 2026 г.
Общееborisovai-admin

Туннели и таймауты: как мы скрепили инфраструктуру воедино

# Туннели, фронт и конфиги: как мы выстроили инфраструктуру для нескольких машин Проект **borisovai-admin** достиг того момента, когда одного сервера стало недостаточно. Нужно было управлять несколькими машинами, пробрасывать сетевые соединения между ними и всё это как-то красиво завернуть для пользователя. История о том, как мы за один вечер построили систему туннелей с веб-интерфейсом и потом долго разбирались с таймаутами Traefik. ## Начало: туннели нужны вчера Задача выглядела просто: нужен интерфейс для управления туннелями между машинами. Но просто никогда не бывает, правда? Первое, что я сделал — запустил фреймворк **frp** (Fast Reverse Proxy). Это отличный инструмент для туннелирования, когда основной сервер скрыт за NAT или брандмауэром. Быстрый, надёжный, с минимальными зависимостями. Спроектировал простую UI в `tunnels.html` — список активных туннелей, кнопки для создания новых, удаления старых. Ничего сложного, но эффективно. На бэкенде добавил 5 API endpoints в `server.js` для управления состоянием туннелей. Параллельно обновил скрипты инсталляции: `install-all.sh` и отдельный `install-frps.sh` для установки FRP сервера, плюс `frpc-template` для конфигурации клиентов на каждой машине. Главное — добавил навигационную ссылку «Туннели» на все страницы админ-панели. Мелочь, но юзабилити выросла в разы. ## Неожиданный враг: Traefik и его таймауты Вроде всё работало, но потом начали падать большие файлы при скачивании через GitLab. Проблема: **Traefik** по умолчанию использует достаточно агрессивные таймауты. Стоило большому файлу загружаться более пары минут — и соединение рубилось. Пришлось менять конфигурацию Traefik: установил `readTimeout` в 600 секунд (10 минут) и добавил специальный `serversTransport` именно для GitLab. Создал скрипт `configure-traefik.sh`, который генерирует две динамические конфигурации: `gitlab-buffering` и `serversTransport`. Теперь файлы загружаются спокойно, даже если это 500 мегабайт архива. ## Пока делал это, понял одно Знаете, что самое интересное в **Traefik**? Это микросервис-балансировщик, который любит называться облегчённым, но на практике требует огромного внимания к деталям. Неправильный таймаут — и ваше приложение выглядит медленным. Правильный — и всё летает. Это как тюнинг двигателя: одна скрепка в нужном месте, и мир меняется. ## Реорганизация и масштабирование Пока занимался инфраструктурой, понял, что документация разрослась и стала трудна в навигации. Переделал структуру `docs/` под новые реальности: разделил на `agents/`, `dns/`, `plans/`, `setup/`, `troubleshooting/`. Каждая папка отвечает за свой кусок практики. Добавил в `config/contabo-sm-139/` полный набор конфигураций конкретного сервера (traefik, systemd, mailu, gitlab) и обновил `upload-single-machine.sh` для поддержки загрузки этих конфигов. Теперь новую машину можно развернуть, не пересматривая весь интернет. ## Что получилось в итоге За вечер родилась полноценная система управления туннелями с приличным интерфейсом, автоматизацией и нормальной документацией. Проект теперь легко масштабируется на новые серверы. Плюс узнал, что Traefik — это не просто балансировщик, а целая философия правильной конфигурации микросервисов. Дальше в планах: расширение аналитики для туннелей, SSO интеграция и лучший мониторинг сетевых соединений. Но это уже другая история. 😄 **Разработчик**: «Я знаю Traefik». **HR**: «На каком уровне?». **Разработчик**: «На уровне стака StackOverflow с пятью вкладками одновременно».

#git#commit#javascript#api#security
8 февр. 2026 г.
Новая функцияtrend-analisis

Race condition в системе версионирования: как два ревьюера поймали потерю данных

# Когда два ревьюера находят одни и те же баги: история о том, как система версионирования может потерять данные Работаешь над feature branch `feat/scoring-v2-tavily-citations` в проекте **trend-analisis**, пилишь систему многоуровневого анализа трендов. Задача звучит просто: позволить анализировать один тренд несколько раз с разными параметрами (`depth`, `time_horizon`), сохранять все варианты и отправлять их на фронт. Казалось бы, что может быть проще? Потом коммит отправляешь на ревью двум коллегам. И они оба, независимо друг от друга, находят одну и ту же **критическую ошибку** — race condition в функции `next_version()`. Момент волшебства: когда разные люди пришли к одному выводу, значит, ошибка точно смертельна. Вот что происходит. Функция `next_version()` считает максимальный номер версии анализа для тренда и возвращает `max + 1`. Звучит логично, но представь: два запроса одновременно анализируют один тренд. Оба вызывают `next_version()`, получают одинаковый номер (например, `version=3`), затем пытаются сохранить результат через `save_analysis()`. Один INSERT успешен, второй молча пропадает в чёрной дыре `except Exception: pass`. Данные потеряны, пользователь не узнает о проблеме. Но это ещё не всё. Коллеги заметили вторую проблему: функция видит только завершённые анализы (статус `completed`), поэтому запущенный анализ (статус `running`) остаётся невидимым для системы версионирования. Получается, что второй запрос стартует с того же номера версии, какой уже занят висящим процессом. Классическая ловушка асинхронности. Обнаружилось ещё несколько багов: фронт ожидает получить один объект `getAnalysisForTrend`, а бэкенд начал отправлять массив анализов. TypeScript тип `AnalysisReport` не знает про новые поля (`version`, `depth`, `time_horizon`, `parent_job_id`) — они приходят с сервера и сразу теряются. Параметр `parent_job_id` вообще ни на что не валидируется, что открывает дверь для инъекций. И `depth` может быть любым числом — никакого лимита, хоть 100 передай. **Интересный момент:** многие разработчики думают, что `except Exception: pass` это "временно", но на практике эта конструкция часто уходит в production как постоянное решение, маскируя критические ошибки. Это называется *exception swallowing*, и это один из самых подлых антипаттернов асинхронного кода. Решение оказалось не очень сложным, но требовало думать о транзакциях иначе. Нужно либо **переместить `next_version()` внутрь `save_analysis()`** с retry-логикой на `IntegrityError`, либо использовать **атомарный SQL-запрос `INSERT...SELECT MAX(version)+1`**, чтобы гарантировать уникальность версии за одно действие. Плюс резервировать версию сразу при старте анализа (INSERT со статусом `running`), чтобы параллельные запросы их видели. Для фронта пришлось добавить новый endpoint `getAnalysesForTrend` (а старый `getAnalysisForTrend` оставить для обратной совместимости). TypeScript типы расширены, валидация на `parent_job_id` добавлена, `depth` ограничен до 7 через `Pydantic Field(ge=1, le=7)`. Главный урок: **код, который "работает на примере", и код, который справляется с race conditions, это два разных животных**. Всегда думай про параллелизм, даже если сейчас система однопоточная. И когда два ревьюера независимо находят один и тот же баг — это не совпадение, это сигнал, что нужно переделывать архитектуру, а не чинить синтаксис. 😄 Prometheus: решение проблемы, о существовании которой ты не знал, способом, который не понимаешь.

#claude#ai#python#javascript#api
Разработка: Trend Analisis
8 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Мелочь в навигации — архитектура на бэке

# Туннелировать админ-панель: когда мелочь оказывается архитектурой Проект **borisovai-admin** — это управленческая панель для социального паблишера. И вот однажды возникла потребность: нужна видимость в туннели FRP (Fast Reverse Proxy). Казалось — простая фича. Добавить ссылку в навигацию, создать эндпоинты на бэке, вывести данные на фронте. Четыре-пять дней работы, максимум. Началось всё с мелочи: требовалось добавить пункт "Туннели" в навигацию. Но навигация была одна, а HTML-файлов четыре — `index.html`, `tokens.html`, `projects.html`, `dns.html`. И здесь скрывалась первая ловушка: одна опечатка, одна невнимательность при копировании — и пользователь запутается, кликнув на несуществующую ссылку. Пришлось синхронизировать все четыре файла, убедиться, что ссылки находятся на одинаковых позициях в строках 195–238. Мелочь, которую легко упустить при спешке. Но мелочь эта потащила за собой целую архитектуру. На бэке понадобилось добавить две вспомогательные функции в `server.js`: `readFrpsConfig` — для чтения конфигурации FRP-сервера, и `frpsDashboardRequest` — для безопасного запроса к dashboard FRP. Это не просто HTTP-вызовы: это минимальная абстракция, которая облегчит тестирование и повторное использование. Затем пришлось вывести четыре GET-эндпоинта: статус сервера, список активных туннелей с метаинформацией, текущую конфигурацию в JSON и даже генератор `frpc.toml` для скачивания клиентского конфига в один клик. И вот неожиданно выяснилось — сам FRP-сервер ещё нужно установить и запустить. Обновил `install-all.sh`, добавил FRP как опциональный компонент: не все хотят туннели, но кто выбрал — получит полный стек. На фронте создал новую страницу `tunnels.html` с тремя блоками: карточка статуса (живой ли FRP), список туннелей с автообновлением каждые 10 секунд (классический полинг, проще WebSocket'а для этого масштаба) и генератор конфига для клиента. **Интересный факт**: полинг через `setInterval` кажется древним подходом, но именно он спасает от overengineering'а. WebSocket требует поддержки на обеих сторонах, fallback'и на старых браузерах, управление жизненным циклом соединения. Для обновления статуса раз в 10 секунд это overkill. Главное — не забыть очистить интервал при размонтировании компонента, иначе получишь утечку памяти и браузер начнёт отваливаться. Главный урок: даже в мелких фичах скрывается целая архитектура. Одна ссылка в навигации потребовала синхронизации четырёх файлов, пять эндпоинтов на бэке, новую страницу на фронте, обновление скрипта установки. Это не scope creep — это *discovery*. Лучше потратить час на планирование полной цепочки, чем потом переделывать интеграцию, когда уже половина team работает на основе твоей "быстрой фички". 😄 FRP — это когда твой сервер вдруг получает способность ходить в гости через NAT, как путник с волшебным клаком из мультика.

#claude#ai#python#javascript#api#security
8 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Забытая память: почему бот не помнил ключевых фактов

# Включи память: или как я нашёл потерянный ключ в своём же коде Проблема началась с простого вопроса пользователя: «Помнишь, я вчера рассказывал про своего кота?» Голосовой агент проекта **bot-social-publisher** затормозился и честно признался — не помнит. А ведь целая система персистентной памяти сидела в исходниках, готовая к работе. Задача казалась острой: почему бот забывает своих пользователей? Когда я открыл архитектуру, глаза разбежались. Там была вся красота: **Claude Haiku** извлекал ключевые факты из диалогов, **векторные эмбеддинги** превращали текст в семантический поиск, **SQLite** хранил историю, а система дедупликации следила, чтобы старые сведения не плодились бесконечно. Всё это было написано, протестировано, готово к боевому использованию. Но почему-то попросту не работало. Первым делом я прошёл по цепочке инициализации памяти. Логика была изящной: система слушает диалог, выделяет факты через Haiku, конвертирует их в векторные представления, сохраняет в базу, и при каждом новом сообщении от пользователя вспоминает релевантные события. Должно было работать идеально. Но этого не было. Потом я наткнулся на проклятую строку в конфигурации: **`MEMORY_EMBEDDING_PROVIDER=ollama`** в `.env`. Или, точнее, её отсутствие. Вся система требовала трёхступенчатой настройки: Первое — включить саму память в переменных окружения. Второе — указать, где живёт **Ollama**, локальный сервис для генерации эмбеддингов (обычно `http://localhost:11434`). Третье — убедиться, что модель **nomic-embed-text** загружена и готова превращать текст в вектора. Казалось бы, ничего сложного. Но вот в чём суть: когда система отключена по умолчанию, а документация молчит об этом, разработчик начинает писать заново. Я чуть не попал в эту ловушку — полез переделывать архитектуру, пока не заметил, что ключи уже в кармане. Когда я наконец активировал память, бот ожил. Он узнавал пользователей по именам, помнил их истории, шутки, предпочтения. Диалоги стали живыми и личными. Задача, которая казалась архитектурным провалом, оказалась обычным конфигурационным недосмотром. Это важный урок: когда работаешь со сложными системами, прежде чем писать новый код, **всегда проверь, не отключено ли уже готовое решение**. Лучший код — тот, который уже написан. Нужно только не забыть его включить. 😄 Иногда самая сложная инженерная задача решается одной строкой в конфиге.

#claude#ai#python#javascript#api#security
8 февр. 2026 г.
Новая функцияborisovai-admin

Туннели в админ-панели: простая идея, сложная реализация

# Система туннелей для admin-панели: от идеи к функциональности Когда работаешь над **borisovai-admin** — панелью управления инфраструктурой — рано или поздно встречаешься с проблемой удалённого доступа к сервисам. Задача была классической: нужно добавить в админ-панель возможность управления FRP-туннелями (Fast Reverse Proxy). Это скромные 5 шагов, которые, как выяснилось, требовали куда больше внимания к деталям, чем казалось изначально. **Завязка простая.** Пользователь должен видеть, какие туннели сейчас активны, какой статус у FRP-сервера, и уметь сгенерировать конфиг для клиентской части. Всё это через красивый интерфейс прямо в админ-панели. Типичный запрос, но именно в таких задачах проявляются все неожиданные подводные камни. **Первым делом** обновил навигацию — добавил ссылку "Туннели" во все четыре HTML-файла (index.html, tokens.html, projects.html, dns.html). Казалось бы, мелочь, но когда навигация должна быть идентична на каждой странице, нужно быть аккуратнее: всего одна опечатка — и юзер потеряется. Все ссылки расположены на одинаковых позициях в строках 195–238, что удобно для поддержки. **Потом столкнулся с архитектурой бэкенда.** В server.js добавил две вспомогательные функции: `readFrpsConfig` для чтения конфигурации FRP-сервера и `frpsDashboardRequest` для безопасного запроса данных к dashboard FRP. Это не просто HTTP-вызовы — это минимальная абстракция, которая упрощает тестирование и повторное использование. Далее идут четыре GET-эндпоинта: 1. Статус FRP-сервера (жив ли?) 2. Список активных туннелей с метаинформацией 3. Текущая конфигурация в JSON 4. Генерация `frpc.toml` — клиентского конфига, который можно скачать одной кнопкой **Неожиданно выяснилось** — FRP-сервер нужно ещё установить и запустить. Поэтому обновил скрипт install-all.sh: добавил FRP как опциональный компонент установки. Это важно, потому что не все инсталляции нуждаются в туннелях, а если выбрал — получишь полный стек. **На фронте** создал новую страницу tunnels.html с тремя блоками: - **Карточка статуса** — простая информация о том, работает ли FRP - **Список туннелей** с авто-обновлением каждые 10 секунд (классический полинг, проще чем WebSocket для такого масштаба) - **Генератор клиентского конфига** — вводишь параметры, видишь готовый `frpc.toml` **Интересный факт про FRP:** это вообще проект из Китая (автор — fatedier), но в экосистеме DevOps он стал де-факто стандартом для туннелирования благодаря простоте и надёжности. Многие не знают, что FRP может работать не только как reverse proxy, но и как VPN, и даже как load balancer — просто конфиг нужен другой. **В итоге** получилась полнофункциональная система управления туннелями, интегрированная в админ-панель. Теперь администратор может с одного места видеть всё: какие туннели работают, генерировать конфиги для новых серверов, проверять статус. Документация пошла в CLAUDE.md, чтобы следующий разработчик не переобнаруживал велосипед. Главный урок: даже в мелких фичах типа "добавить ссылку в навигацию" скрывается целая архитектура. Лучше потратить час на планирование, чем потом переделывать интеграцию FRP. 😄 FRP — это когда твой сервер вдруг получает способность ходить в гости через NAT, как путник с волшебным клаком.

#claude#ai#javascript#api#security
8 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Голосовой агент с памятью: как мы научили Claude работать асинхронно

# Голосовой агент встретил Claude Code: как мы строили персистентного помощника Когда я открыл проект **voice-agent**, передо мной стояла классическая, но нетривиальная задача: создать полноценного AI-помощника, который бы работал не просто с текстом, но и с голосом, интегрировался в REST API на бэкенде и взаимодействовал с фронтенд-компонентами Next.js. Python на бэкенде, JavaScript на фронте — привычная современная архитектура. Но главный вызов был совсем не в технологиях. **Первым делом я осознал, что это не просто ещё один chatbot.** Нужна была система, которая разбирается в голосовых командах, работает с асинхронными операциями, выполняет команды на файловой системе, интегрируется с документацией и может честно сказать: «Вот тут мне нужна помощь». Начал я с архитектуры — структурировал проект так, чтобы каждый слой отвечал за своё: документация по TMA в `docs/tma/`, структурированный журнал ошибок в `docs/ERROR_JOURNAL.md`, разделение бэкенд-сервисов по функциям. Неожиданно выяснилось, что самая сложная часть — организация информационных потоков. Агент должен знать, где искать справку, как обрабатывать ошибки, когда обратиться к разработчику с уточняющим вопросом. Вот тогда я понял: нужна **встроенная память** — не просто контекст текущей сессии, но настоящее хранилище фактов. Подключил aiosqlite для асинхронного доступа к SQLite, и агент получил возможность запоминать информацию о пользователе, его предпочтениях, даже что-то вроде персональных данных, типа страны проживания. Это открыло целый набор возможностей для персонализации. Агент стал не просто отвечать, а *узнавать* пользователя: «Ты из России? Значит, зафиксирую это и буду учитывать при рекомендациях». **Интересный факт:** мы живём в эпоху ускорения AI-разработок. Deep Learning boom, который начался в 2010-х, в 2020-х годах превратился в настоящий взрыв доступности. Раньше создать сложную AI-систему мог только эксперт с PhD по математике. Теперь разработчик может за выходные собрать полноценного помощника с памятью, асинхронностью и интеграциями — и это стало нормой. **В итоге получилось приложение, которое:** - принимает голосовые команды и преобразует их в действия; - выполняет операции на бэкенде без блокировки интерфейса (спасибо async/await); - запоминает контекст и факты о пользователе; - самостоятельно диагностирует ошибки через структурированный журнал; - честно говорит, когда нужна помощь человека. Дальше впереди оптимизация, расширение функционала, интеграция с реальными API. Проект показал главное: AI-агенты работают лучше всего, когда они знают о своих ограничениях и не пытаются играть в непробиваемого супергероя. Мигрировать с Linux — всё равно что менять колёса на ходу. На самолёте. 😄

#claude#ai#python#javascript#git#api
8 февр. 2026 г.
Новая функцияtrend-analisis

Версионность анализов: как не запутаться в истории трендов

# Строим сложную архитектуру анализов трендов: как не утонуть в версионности Несколько недель назад встал вопрос, который выглядел просто на первый взгляд: как сделать так, чтобы анализы трендов можно было обновлять, отслеживать изменения и углублять, не теряя историю? Проект **trend-analysis** требовал переоценки всей модели данных. Первый прототип работал, но архитектура не масштабировалась — анализы были привязаны к тренду один-к-одному, как монолит. Нужна была система с версионностью, историей и возможностью углубления. Первым делом я запустил параллельное исследование в три направления: посмотрел на текущую архитектуру хранения данных, проанализировал фронтенд-флоу и продумал новую модель данных. Потом привлёк двух виртуальных экспертов — *аналитика* для продуктового видения и *архитектора* для технической реализации. Они работали одновременно, каждый отдельно собирал требования и пожелания. Результат был интересный. План получился ёмким: **четыре фазы, пятнадцать шагов**. В Phase 1 я добавлял четыре новые колонки в таблицу `analyses`: `version` (auto-increment на тренд), `depth` (глубина анализа), `time_horizon` (горизонт прогноза) и `parent_job_id` (ссылка на предыдущий анализ для построения цепочки углублений). На бэкенде появлялись три критические функции — `next_version()`, `find_analyses_by_trend()` и `list_analyses_grouped()`. Но фронтенд-часть потребовала детализации. Я исследовал текущий UI тренда и понял, что нужна полная переделка. Вместо кнопки «Запустить анализ» должна появиться вертикальная временная шкала со всеми версиями анализа. Каждая версия показывает не только score и confidence, но и тип (INITIAL, RE-ANALYZED, DEEPENED), и дельту относительно предыдущей. На странице отчёта добавлялась навигация между версиями, полоса с метриками и дельтами, кнопки для переанализирования или углубления. Неожиданно выяснилось, что потребуется ещё и сравнение версий. Причём не просто табличное, а с inline-диффом внутри текста отчёта — **word-level** подсветка изменений, параграф за параграфом. Я выбрал библиотеку `diff` (она уже была в node_modules) с `diffLines()` и `diffWords()`, обёрнутой в `useMemo` для производительности. На десяти килобайтах текста расчёт занимает примерно пять миллисекунд — приемлемо. **Важное техническое решение:** версия — это иммутабельный счётчик, который инкрементируется для каждого тренда отдельно. Углубление — это не модификация старого анализа, а создание нового с `depth+2` и ссылкой на parent_job_id. Так мы сохраняем всю историю и можем показать цепочку углублений. Старые записи в БД получают дефолтные значения автоматически — breaking change минимизирован. Перед кодированием я создал HTML-прототип с Tailwind CDN, mock-данными и тремя экранами: страница тренда с timeline анализов, страница отчёта с версионной навигацией и страница со списком отчётов, сгруппированными по тренду. Прототип дал визуальную уверенность, что архитектура работает. Теперь план готов к реализации. Первый шаг — миграция БД и API. Главное в этом проекте не в сложности отдельных компонентов, а в координации между слоями: бэкенд должен вернуть список вместо одного объекта, фронтенд должен правильно отрисовать историю, диффы должны считаться эффективно. Это когда архитектура действительно спасает. *Что сказал Nginx при деплое новой версионности? «Наконец-то вы научились отслеживать историю — я давно это делаю через Etag»* 😄

#claude#ai#python#javascript#api
Разработка: Trend Analisis
8 февр. 2026 г.