feat: all project setup

This commit is contained in:
ivannoskov
2025-11-10 12:07:24 +03:00
parent fbfd7719bb
commit b0a9934220
99 changed files with 19597 additions and 0 deletions

231
project.md Normal file
View File

@@ -0,0 +1,231 @@
# **Общее описание системы**
Система для владельцев каналов позволяющая удобно систематизировать информацию о закупках рекламы и предоставляющая удобный интерфейс для анализа проведенных рекламных компаний
# **Термины и определения**
«Целевой канал» — канал, в который мы приводим подписчиков. Им владеет пользователь (владелец проекта) и именно для него считаем подписки.
«Внешний канал» — сторонний канал, в котором покупаем размещение рекламы выбранного креатива. Пользователю он **не принадлежит**, бот туда **не добавляется**.
«Креатив» — сущность/шаблон текста сообщения, **привязанная к целевому каналу**.
«Закуп» — факт размещения креатива во **внешнем канале**. Для каждого закупа создаётся отдельная invite-ссылка в целевой канал.
CPF — Cost Per Follower — метрика отражающая стоимость привлечения одного подписчика
CPM — Cost Per Mile — метрика отражающая стоимость 1000 просмотров
# **Функционал**
## **1\. Авторизация/регистрация через телеграмм**
Пользователь в веб\-панели нажимает «Войти через Telegram». Его перенаправляет к боту по ссылке вида `https://t.me/example_bot?start=login`. Бот возвращает одноразовую ссылку вида `https://app.example.com/auth/complete?token=<one_time_login_token>`. Сайт обменивает токен на сессию. Если пользователя не существовало — создаётся новый профиль; если существовал — выполняется вход.
### **Сценарии использования**
**Новый пользователь**
1. Пользователь жмёт «Войти через Telegram» на сайте.
2. Редирект в Telegram к боту: `/?start=login`.
3. Создается новый пользователь с данными из события (Telegram ID, username, ФИО)
4. Бот генерирует одноразовый токен для пользователя
5. Бот отправляет кнопку «Войти» со ссылкой вида `/auth/complete?token=....`
6. Пользователь переходит по ссылке и авторизуется.
**Существующий пользователь**
1. Пользователь жмёт «Войти через Telegram».
2. `/?start?login` → бот генерирует ссылку вида `/auth/complete?token=....`
3. Пользователь переходит по ссылке и авторизуется.
## **2\. Подключение целевых каналов**
Пользователь вручную добавляет бота в свой Telegram-канал с правами **администратора** (минимум: право создавать инвайт-ссылки и видеть вступления). Бот получает событие, валидирует, что канал новый/принадлежит пользователю, и регистрирует канал в системе. В веб\-панели доступен список подключённых каналов.
### **Сценарии использования**
**Подключение нового канала**
1. Пользователь в веб\-панели жмёт «Подключить канал» → видит инструкцию «Добавьте бота в нужный канал с правами администратора».
2. Пользователь добавляет бота в канал.
3. Бот получает событие о добавлении в канал
4. Бот создаёт/обновляет запись канала, привязывая её к пользователю.
5. Канал отображается в списке каналов пользователя
**Ошибки (кратко):** нет прав администратора → канал не регистрируется; канал уже подключён → пропускаем, возвращаем «уже в системе».
**Просмотр (и отключение) каналов**
1. Пользователь открывает раздел «Каналы».
2. Система показывает список: название, @username, ссылка
3. Пользователь при необходимости жмёт «Отключить» → система помечает канал как отключённый (и предлагает вручную снять бота из админов в самом канале).
**Результат:** список актуален; отключённые каналы не участвуют в аналитике и создании инвайт-ссылок.
## **3\. Каталог внешних каналов**
### **Описание**
Пользователь ведёт собственный список **внешних каналов** (куда планирует покупать размещения) для целевого канала.
Список можно **редактировать вручную** и **импортировать из Tgstat (Excel)**.
Каждый внешний канал может быть привязан **к одному или нескольким целевым каналам**. При добавлении внешнего канала пользователь указывает, к каким целевым каналам его привязать.
### **Основные действия доступные для каталога каналов**
* Просмотр списка внешних каналов для выбранного целевого канала.
* Добавление/удаление внешнего канала.
* Импорт из Excel (tgstat) с валидацией и дедупликацией.
### **Требования к данным**
Внешний канал и Целевой канал связаны через M2M связь
## **4\. Креативы**
Креатив — это шаблон рекламного сообщения, используемого при закупке рекламы во внешних каналах, содержащий переменную, куда нужно вставить ссылку на целевой канал.
Каждый креатив связан с **одним целевым каналом** и может быть использован в нескольких закупах.
На этапе первой версии поддерживается только **текстовый формат** без медиафайлов.
### **Сценарии использования**
**Создание нового креатива**
1. Пользователь открывает раздел «Креативы» и нажимает «Создать креатив».
2. Указывает:
* Название креатива (для внутреннего использования),
* Текст сообщения,
* Целевой канал, к которому креатив относится.
3. Сохраняет запись.
4. Креатив появляется в списке и доступен для выбора при создании закупа.
**Результат:** создан новый креатив, связанный с выбранным целевым каналом.
**Просмотр и редактирование креативов**
1. Пользователь открывает список креативов.
2. В таблице видны: название, целевой канал, дата создания и количество связанных закупов.
3. При необходимости пользователь может:
* открыть креатив,
* изменить текст,
* переименовать,
* архивировать
* удалить (если не используется в активных закупах).
**Результат:** список актуальных креативов; изменения сохраняются без потери связей с закупами.
## **5\. Закупы**
### **Описание**
**Закуп** — это факт размещения выбранного креатива во внешнем канале.
Для каждого закупа создаётся **уникальная пригласительная ссылка** в целевой канал, по которой отслеживаются подписки.
Закуп связывает между собой три сущности:
* целевой канал (куда ведём трафик),
* внешний канал (где размещаем рекламу),
* креатив (что публикуем).
Пользователь может создавать, редактировать и просматривать закупы, а также видеть их основные показатели эффективности
### **Сценарии использования**
**Создание нового закупа**
1. Пользователь открывает раздел **«Закупы»** и нажимает «Создать закуп».
2. Указывает:
* **Целевой канал**,
* **Внешний канал**,
* **Креатив**,
* Дату размещения (планируемую или фактическую),
* Стоимость закупа (опционально),
* Комментарий,
* Ссылка на рекламное сообщение во внешнем канале (для получение информации о просмотрах).
* Тип ссылки (открытая/с одобрением ботом)
3. После сохранения система создаёт **уникальную публичную или приватную invite-ссылку** (в зависимости от настройки закупа “***тип ссылки***” п.2) в целевой канал через Telegram Bot API.
4. Закуп появляется в списке с возможностью скопировать текст для рекламного сообщений и доступен для просмотра аналитики.
**Результат:** создан новый закуп с уникальной ссылкой для отслеживания переходов и подписок.
**Просмотр и обновление закупов**
1. Пользователь открывает список закупов (таблица).
2. В таблице отображаются: целевой канал, внешний канал, креатив, дата, стоимость, количество подписок.
3. Пользователь может:
* изменить данные закупа (например, обновить стоимость, комментарий или дату),
* удалить закуп (с предупреждением о невозможности восстановления данных),
* архивировать закуп (убрать из статистики и аналитики)
* перейти к просмотру аналитики по конкретному закупу.
## **6\. Обработка события подписки пользователя в целевой канал через Telegram Bot API**
Бот — администратор целевого канала. При вступлении пользователя Telegram шлёт одно из двух событий (`ChatMemberUpdate`, `ChatJoinRequest`) по которым мы **однозначно маппим подписку к закупу**
### **Сценарии использования**
**Подписка по открытой ссылке**
1. Для закупа создана уникальная invite\_link.
2. Пользователь переходит и сразу вступает в канал.
3. Бот получает событие `ChatMemberUpdated`
4. По `invite_link` находим закуп и сохраняем информацию о подписке
5. Инкрементируем метрики закупа (подписки, конверсия).
**Результат:** подписка учтена и привязана к конкретному закупу.
**Запрос на вступление в канла**
1. Для закупа создана уникальная `private_invite_link`.
2. Пользователь переходит по ссылке и отправляет `ChatJoinRequest`.
3. Бот получает событие `ChatJoinRequest`
4. По `invite_link` находим закуп и сохраняем информацию о подписке
5. Инкрементируем метрики закупа (подписки, конверсия).
**Результат:** подписка учтена и привязана к конкретному закупу.
## **7\. Получение информации о кол-ве просмотров через Telegram API**
### **Описание**
Система должна уметь подтягивать **число просмотров** рекламного поста по **ссылке на сообщение** внешнего канала.
Технически корректный способ — через **Telegram API (или MTProto/TDLib)**: для публичных каналов можно читать сообщения и их поле views без добавления бота в канал.
Поддерживаемые форматы ссылок:
* https://t.me/\<username\>/\<message\_id\>
* https://t.me/c/\<internal\_chat\_id\>/\<message\_id\> (для приватных каналов с доступом — см. ограничения ниже)
Метрика хранится как снимки (time series) с периодическим опросом (раз в час), чтобы видеть динамику добора просмотров.
💡Тут надо подумать, как частно нужно получать эти данные и как их надо агрегировать, так как у телеграмма как-то заковыристо считается и показывается кол-во просмотров
### **Сценарии использования**
**Успешное получение просмотров (публичный канал)**
1. В карточке закупа пользователь добавляет ссылку на пост (t.me/\<username\>/\<message\_id\>).
2. Бэкенд через TDLib/MTProto вызывает channels.getMessages и читает поле views.
3. Сохраняет снэпшот: views=12345, fetched\_at=....
4. Планировщик повторяет опрос по расписанию, строится кривая добора просмотров.
**Результат:** в аналитике закупа и сводках отображается актуальный счётчик просмотров и стоимость подписчика с учётом просмотров (пока — только CPS/CPF, просмотры — справочно).
**Недоступно (приватный канал / нет прав / битая ссылка)**
1. Пользователь добавляет ссылку t.me/c/.../123.
2. Запрос через TDLib возвращает «нет доступа» или «не найдено».
3. Система помечает источник как unavailable и предлагает:
* добавить доступ (пригласить учётку чтения), **или**
* указать просмотры вручную, **или**
* загрузить из отчёта Tgstat/экселя.
**Результат:** закуп помечен как недоступный для авто-сбора; допускается ручной ввод/импорт.
## **8\. Просмотр аналитики по целевым каналам, внешним каналам, креативам и закупам**
* Отображать средний CPF в списках закупов, креативов и внешних каналов
* Отображать средний CPM в списках закупов, креативов и внешних каналов
* Отображать столбчатую диаграмму с объемом закупок с группировкой по дате (день, неделя, месяц, квартал, год) и возможностью фильтрации по целевым каналам на отдельном экране “Аналитика” → “Затраты”