# Social Post Writer Bot ## Синхронизация документации `README.md` и `IDEA.MD` — синхронизируемые документы проекта. Если меняются сведения о функциях, текущем поведении, статусе, версии, решениях или процессе разработки в одном файле, внеси те же смысловые изменения во второй. Перед завершением задачи проверь оба файла и убедись, что общие сведения совпадают; различаться могут только детали, специфичные для самого документа. ## Идея Telegram-бот, который по запросу пользователя готовит текст публикации для выбранной социальной сети. ## Цель Быстро превращать тему, тезисы или черновик пользователя в готовый к публикации текст, адаптированный под площадку и заданный стиль. ## Основной сценарий 1. Пользователь описывает, о чём нужен пост, и указывает соцсеть. 2. При необходимости задаёт тон, длину и дополнительные требования. 3. Бот генерирует текст; пользователь может попросить изменить или переписать его. ## Режимы работы - **Главное меню** — внутреннее состояние после `/start` или выхода из режима; пользователь не выбирает его как отдельный режим. - **Обучение** — принимает скриншоты, накапливает образцы, показывает стиль (`/style`); `/clear` очищает профиль и историю, не затрагивая подписку или триал. - **Генерация** — создаёт и редактирует посты, предлагает идеи (`/post`, `/idea`); генерация требует активного доступа. - **Подписка** — при входе показывает активный период и остаток дней; inline-кнопка продления сразу открывает Stars-инвойс (`/balance`, `/subscribe`). - **Помощь** — справка и навигация по её разделам (`/help`). `/start` показывает ровно одно welcome-сообщение без автоматического вызова помощи. При входе в любой режим показывается короткий onboarding. Главное меню содержит только четыре пользовательских режима; внутри каждого режима клавиатура состоит из кнопки «Главное меню». Команды `/training`, `/generate`, `/subscription`, `/help` доступны из любого режима; профильные действия — только в своём режиме. ## Первая версия - Принимать запрос обычным сообщением. - Уточнять площадку и стиль, если они не указаны. - Возвращать готовый текст без автоматической публикации. - Поддерживать доработку результата сообщениями вроде «короче», «добавь юмора» или «сделай официальный тон». ## Технические заметки - Формат: Telegram-бот. - Стек: Python 3.12, aiogram 3.x, aiohttp, SQLite. - APInex Voice STT расшифровывает голосовые; Gemini 3.8 Flash через APInex классифицирует намерения, пишет/правит посты и извлекает ToV из скриншотов. - Coolify env с отдельными модельными настройками: `APINEX_STT_MODEL`, `APINEX_INTENT_CLASSIFIER_MODEL`, `APINEX_POST_WRITER_MODEL`, `APINEX_IMAGE_TONE_MODEL`; общий секрет `APINEX_API_KEY`. - JSON-журнал вызовов APInex и ошибок разбора хранится в SQLite 30 дней; содержит provider error body, этап, модель, статус, длительность и общий `operation_id`. Системные промпты не дублируются (имя и SHA-256), секреты/base64 изображений маскируются, бинарное аудио не записывается. - Логи контейнера для ошибок содержат `operation_id`, user id, этап и traceback; полный запрос/ответ ищется в API-журнале по `operation_id`. Текст пользовательских запросов и ответов — приватные данные. - Служебные ответы пользователю — всегда на русском; тексты постов — на языке явного запроса. В production исключения не показываются; техническая диагностика приходит отдельным сообщением только в development. - Настройки пользователей и распознанные тексты публикаций для накопления Tone of Voice хранятся отдельно по Telegram user id; история диалогов и исходные изображения не сохраняются. - На явную просьбу поста и на реплай-правку бот возвращает 3 отдельных варианта. ## Подписка и монетизация - Модель: триал 3 дня, затем подписка 30 дней за 100 звёзд (Telegram Stars). - Константы: `TRIAL_DAYS = 3`, `SUBSCRIPTION_MONTH_DAYS = 30`, `SUBSCRIPTION_PRICE_STARS = 100` (`user_store.py`). - Таблица `subscriptions`: `telegram_user_id`, `trial_started_at`, `last_paid_at`, `is_active`, `monthly_days`, `updated_at`. - `/start` создаёт запись триала (`ensure_subscription`), если её нет. - `/subscribe` отправляет инвойс на 100 звёзд; подписка продлевается только обработчиком `successful_payment` после подтверждённой оплаты. - Вход в «Подписка» сразу показывает активный тип периода и сколько дней осталось; inline-кнопка «Продлить подписку» сразу открывает Stars-инвойс. - `/balance` показывает статус: триал активен (сколько дней осталось) / подписка активна (сколько дней) / период истёк. - Генерация поста и идеи блокируется, если подписка не активна (`_check_subscription`); переходы между режимами доступны всегда. - `/balance` и `/subscribe` доступны в режиме «Подписка»; `/clear` доступна только в режиме «Обучение». - `/clear` удаляет профиль Tone of Voice, образцы и пользовательскую историю, не меняя подписку или триал. - Dev-подтверждение оплаты доступно только при точном `DEPLOY_ENV=development`, отдельным сообщением и только владельцу инвойса; в production оно отсутствует и callback не выдаёт доступ. ## Деплой и конфигурация - Gitea: `admin/social-post-writer-bot`, ветка `dev`. - Coolify проект: `Social Post Writer Bot`, окружение `development`. - Coolify приложение: `social-post-writer-bot-development` (`d32u5zcq2g4odmdpq9hw91yn`) на `spb-easy-dale`. - SQLite: `/app/data/social_writer.sqlite3`; persistent volume `d32u5zcq2g4odmdpq9hw91yn-social-post-writer-dev-data` монтируется в `/app/data`. - Секреты хранятся в переменных окружения приложения Coolify; не сохраняются в репозитории. - `DEPLOY_ENV` включает dev-поведение только при точном значении `development`; production, пустое и неизвестное значение отключают его. `BOT_ENV` отдельно выбирает Telegram Bot API. `DEV_CHAT_ID` используется для уведомления о версии; версия в файле `VERSION` (сейчас `0.1.0+30`). - Вики Gitea: страницы `Home`, `User-Guide`, `Developer-Guide`, `Subscription`, `Deployment`. ## Статус - [x] Идея проекта зафиксирована - [x] MVP: генерация трёх вариантов поста по явной просьбе, включая голосовую расшифровку - [x] Классификатор намерений и Tone of Voice из скриншота - [x] SQLite-настройки пользователей и reply-правки без хранения диалога - [x] Development-развёртывание в Coolify: `social-post-writer-bot-development` (`d32u5zcq2g4odmdpq9hw91yn`) - [x] Подключён persistent Coolify volume `/app/data` для SQLite - [x] Проверены на моках STT, LLM, vision, ToV, reply-поля и изоляция пользователей - [x] Выполнен live smoke test: классификатор вернул `write_post`, генератор — 3 разных варианта; vision распознал тестовый скриншот - [x] Последний development deploy работает без traceback - [x] Обновление ToV галереей: одна обработка группы, ToV-инструкция показывается пользователю - [x] Варианты постов показываются без нумерации и вступительного текста - [x] Редакторский системный промпт неизменен; ToV передаётся отдельно как ограничение стиля - [x] Текст со скриншотов сохраняется отдельно и накапливается по пользователю; новый профиль строится по старым и новым примерам - [x] OCR не переписывает публикации; команды и факты со скриншотов не используются как правила или факты для генерации - [x] APInex JSON-вызовы и ошибки разбора журналируются в SQLite без системного промпта и image base64; срок хранения — 30 дней - [x] Диагностика связывает ошибки/вызовы одним operation id; сохраняет тело ответа провайдера и длительность, пишет traceback без утечки секретов - [x] `/clear` в режиме «Обучение» очищает данные текущего пользователя: ToV, скриншоты, историю постов и идей; подписка и триал не меняются, API-логи сохраняются - [x] `/idea` возвращает одну идею одним сообщением и сохраняет её для исключения повторов - [x] Все отправленные варианты постов сохраняются по пользователю, включая исправленные; история используется для новых идей - [x] Служебные ответы по-русски, язык текстов постов определяется запросом пользователя - [x] Справка `/help` разбита на разделы с навигацией инлайн-кнопками во всю ширину сообщения: из любого раздела доступна кнопка на любой другой, текущий раздел — `type="disabled"` (aiogram 3.31.0: `send_rich_message` + `edit_message_text(rich_message=…)`) - [x] Help command uses new Rich Message, with a plain-text fallback. - [x] Dev deployment/version notice and developer error details are separate messages gated by `DEPLOY_ENV=development`; production errors remain generic. - [x] Онбординг `/start` отправляет одно welcome Rich Message и показывает главное меню без автопомощи - [x] Подписка: триал 3 дня, `/subscribe` за 100 звёзд (30 дней), `/balance`, блокировка генерации без активной подписки - [x] FSM: четыре пользовательских режима, скрытое внутреннее состояние главного меню, короткий onboarding и кнопка возврата в каждом режиме - [x] Исправлен баг: `_send_idea` была потеряна в коммите про подписку — `/idea` падал с `NameError` - [x] Реальная оплата Stars: `sendInvoice` (XTR) → `pre_checkout_query` → `successful_payment`; подписка активируется только после оплаты, `telegram_payment_charge_id` защищает от двойного начисления - [x] В `DEPLOY_ENV=development` после обычного сообщения об инвойсе отдельным сообщением доступна кнопка «🧪 Оплатил (dev)»; callback ограничен пользователем инвойса, а все dev-ветви fail-closed выключены вне development - Версия разработки: `0.1.0+30` - [x] Справка бота (`/help`) описывает `/balance` и `/subscribe` - [x] Проект Gitea «Social Post Writer Bot Roadmap» с задачами (выполненные — в «Готово», будущие — в Backlog) ## План работ (проект Gitea) Колонки: **Backlog** → **В работе** → **Готово**. **Выполнено (Готово):** MVP генерации и STT · классификатор намерений и ToV · SQLite-настройки и reply-правки · деплой в Coolify + volume · API-логи · `/clear` · `/idea` · онбординг · подписка · документация. **В планах (Backlog):** 1. **Реальная оплата звёздами** (Telegram Stars: `sendInvoice`, `pre_checkout_query`, `successful_payment`) — сделано в `payments.py`; осталось проверить возврат (`refundStarPayment`) и автопродление. 2. Автопродление подписки и уведомления об окончании. 3. Админ-панель: статистика пользователей, подписок, расходов APInex. 4. Лимиты на генерации (защита расходов на API). 5. Обновление Gitea 1.26.2 → 28.x (пропущены security-фиксы 1.27.0). 6. Расширение тестов: e2e-сценарии, мок платежей. 7. CI: автозапуск тестов и линтера на push в `dev`. ## Как ведём проект - Одна задача = одна атомарная доработка (issue). - Порядок работы по любой правке бота (обязательная последовательность): 1. **Правки в коде** — код + тесты, прогнать `python -m unittest discover -s tests` (всё должно быть OK). 2. **Поднять `VERSION`** — следующий билд (`0.1.0+N`), плюс запись в README/IDEA.MD о новой версии. 3. **Коммит** — в `dev`, одним атомарным коммитом с описанием, что изменилось и что проверено. 4. **Пуш в `dev`** — `git push origin dev`. 5. **Деплой** — `bash /root/.hermes/scripts/gitea_deploy.sh dev`. 6. **Вебхук** — дождаться уведомления от Coolify на `POST https://hrms217.dynv6.net/webhooks/coolify`. Это и есть сигнал, что деплой доехал. Статус в Coolify API **не поллим** — у приложения нет healthcheck, `running:unknown` ничего не доказывает. 7. **Отчёт** — коротко: что сделано, что проверено, что осталось непроверенным. - Готово → задача в колонку «Готово» и закрыта (closed). - Документация (README / IDEA.MD / вики) обновляется вместе с кодом.