План разработки: модуль «Статистика» (часть 1)
Документ для поэтапной реализации. По мере выполнения отмечайте пункты:
[ ]→[x].
Последнее обновление: 2026-08-26
1. Цель и scope
Модуль для учёта эффективности каналов трафика: ежедневный ввод фактических показателей сотрудниками (подрядчики, SMM), постановка месячных планов директором, отображение статистики с разрезами по дням, неделям и месяцу (% выполнения = факт / план).
Входит в часть 1
- Роли: подрядчик (
contractor), SMM-специалист (расширение существующей роли), МОП (mop) — роль создаётся, но отдельные поля МОП — этап 2 - Справочник каналов трафика с привязкой к пользователям (роли
contractor,smm_specialist) - Ежедневные отчёты по каналам (обязательная модалка в начале дня)
- Месячные планы (директор)
- Дашборд с разрезами по дням / неделям / месяцу
Не входит в часть 1 (следующие этапы)
- Отдельные поля и отчёты для МОП
- Интеграция с AmoCRM (автоподтягивание заявок)
- Экспорт Excel/PDF, графики, Telegram-напоминания, аудит-лог планов
2. Согласованные решения
| # | Вопрос | Решение |
|---|---|---|
| 1 | Формула «Конверсия в квал. заявку» | кол-во квал. заявок / кол-во заявок |
| 2 | Что заполняет МОП? | Отдельные поля — следующий этап. В части 1 роль создаётся, права на просмотр статистики — да; ежедневная форма МОП — нет |
| 3 | Один пользователь — несколько каналов? | Да, через pivot traffic_channel_users |
| 4 | Пропуск дня (отпуск, болезнь) | Модалка при следующем входе за последний незаполненный рабочий день |
| 5 | Выходные (сб, вс) | Не требуют отчёта и не входят в план |
| 6 | Распределение плана | дневной план = месячный / кол-во рабочих дней в месяце (пн–пт); в сб/вс план = 0 |
| 7 | Праздники РФ | Не учитываем в v1 (только сб/вс) |
3. Роли и права доступа
3.1. Роли
| Slug | Описание | Статус |
|---|---|---|
smm_specialist | SMM-специалист | Уже есть — добавить permissions модуля |
contractor | Подрядчик (рекламные организации) | Создать |
mop | МОП (менеджер отдела продаж) | Создать (заполнение — этап 2) |
Миграция по образцу:backend/modules/Core/database/migrations/2026_07_13_180000_add_smm_specialist_role.php
3.2. Permissions (module: 'statistics')
| Permission | Роли | Назначение |
|---|---|---|
view_statistics | director, administrator, superadmin, mop, contractor, smm_specialist | Доступ к модулю в меню |
view_statistics_all | director, administrator, superadmin, mop | Все каналы и все сотрудники |
view_statistics_own | contractor, smm_specialist | Только свои каналы |
fill_statistics_daily | contractor, smm_specialist | Заполнение ежедневного отчёта по каналам |
manage_statistics_channels | director, administrator, superadmin | CRUD каналов, привязка пользователей |
manage_statistics_plans | director, superadmin | Установка месячных планов |
Slug
moduleв permissions должен совпадать сmoduleвfrontend/utils/menuConfig.js—statistics.
4. Метрики канала
4.1. Заполняемые пользователем (факт)
| Поле | Ключ API | Тип |
|---|---|---|
| Охват | reach | integer ≥ 0 |
| Количество визитов | visits | integer ≥ 0 |
| Количество заявок | applications | integer ≥ 0 |
| Кол-во квал. заявок | qualified_applications | integer ≥ 0 |
| Расходы | expenses | decimal ≥ 0 |
4.2. Вычисляемые (не хранить в БД)
| Метрика | Формула | При делении на 0 |
|---|---|---|
| Конверсия в визит | visits / reach | null |
| Конверсия в заявку | applications / visits | null |
| Конверсия в квал. заявку | qualified_applications / applications | null |
| CPL факт | expenses / applications | null |
| CPQL факт | expenses / qualified_applications | null |
Вычисление — в StatisticsMetricsService (backend) и дублирование для UI при необходимости.
4.3. Плановые значения (директор, на месяц)
Те же метрики, что заполняются вручную: reach, visits, applications, qualified_applications, expenses.
Конверсии и CPL/CPQL для плана считаются из плановых базовых полей теми же формулами.
5. Модель данных
5.1. ER-схема
traffic_channels
├── id
├── name
├── description (nullable)
├── is_active (boolean, default true)
├── created_at, updated_at
traffic_channel_users (pivot)
├── id
├── traffic_channel_id → traffic_channels.id
├── user_id → users.id
├── created_at, updated_at
UNIQUE (traffic_channel_id, user_id)
statistics_daily_reports
├── id
├── traffic_channel_id → traffic_channels.id
├── user_id → users.id (кто заполнил)
├── report_date (date — за какой день данные)
├── reach, visits, applications, qualified_applications
├── expenses (decimal 12,2)
├── submitted_at (timestamp)
├── created_at, updated_at
UNIQUE (traffic_channel_id, report_date)
statistics_monthly_plans
├── id
├── traffic_channel_id → traffic_channels.id
├── year (smallint)
├── month (tinyint 1–12)
├── reach_plan, visits_plan, applications_plan, qualified_applications_plan
├── expenses_plan (decimal 12,2)
├── created_by → users.id
├── created_at, updated_at
UNIQUE (traffic_channel_id, year, month)5.2. Ограничения
- В pivot
traffic_channel_usersдопускаются только пользователи с ролямиcontractorилиsmm_specialist - Один отчёт на канал за календарный день
- Один план на канал за календарный месяц
6. Архитектура модуля
6.1. Backend — backend/modules/Statistics/
Statistics/
├── module.json
├── Providers/
│ └── StatisticsServiceProvider.php
├── routes/
│ └── api.php
├── Http/
│ ├── Controllers/
│ │ ├── TrafficChannelController.php
│ │ ├── DailyReportController.php
│ │ ├── MonthlyPlanController.php
│ │ └── StatisticsSummaryController.php
│ └── Requests/
│ ├── StoreTrafficChannelRequest.php
│ ├── StoreDailyReportRequest.php
│ └── StoreMonthlyPlanRequest.php
├── Services/
│ ├── StatisticsMetricsService.php
│ ├── StatisticsPlanDistributionService.php
│ ├── StatisticsPendingReportService.php
│ └── StatisticsWorkingDaysService.php
├── Models/
│ ├── TrafficChannel.php
│ ├── TrafficChannelUser.php
│ ├── StatisticsDailyReport.php
│ └── StatisticsMonthlyPlan.php
└── database/
└── migrations/
├── ..._create_traffic_channels_table.php
├── ..._create_traffic_channel_users_table.php
├── ..._create_statistics_daily_reports_table.php
├── ..._create_statistics_monthly_plans_table.php
└── ..._add_statistics_permissions.phpРегистрация: module.json → автоподключение в app/Providers/ModuleServiceProvider.php.
Шаблон: модуль BotStats (backend/modules/BotStats/).
6.2. Frontend
frontend/
├── pages/dashboard/statistics/
│ ├── index.vue # дашборд: день / неделя / месяц
│ ├── channels.vue # управление каналами (директор)
│ └── plans.vue # месячные планы (директор)
├── components/statistics/
│ ├── StatisticsDailyReportModal.vue
│ ├── StatisticsChannelForm.vue
│ ├── StatisticsPlanForm.vue
│ ├── StatisticsMetricsTable.vue
│ └── StatisticsWeekBreakdown.vue
└── composables/
└── useStatistics.ts7. API
Префикс: /api/v1/statistics.
Middleware группы: ['api', 'auth:sanctum'] + per-route permission:*.
7.1. Каналы
| Метод | URL | Permission | Описание |
|---|---|---|---|
| GET | /channels | view_statistics_own / view_statistics_all | Список (фильтр по роли) |
| POST | /channels | manage_statistics_channels | Создание |
| PUT | /channels/{id} | manage_statistics_channels | Редактирование |
| DELETE | /channels/{id} | manage_statistics_channels | Деактивация (is_active = false) |
| PUT | /channels/{id}/users | manage_statistics_channels | Привязка пользователей |
7.2. Ежедневные отчёты
| Метод | URL | Permission | Описание |
|---|---|---|---|
| GET | /pending | fill_statistics_daily | Незаполненные дни по каналам пользователя |
| POST | /daily-reports | fill_statistics_daily | Отправка факта |
| GET | /daily-reports | view_statistics_own / view_statistics_all | История с фильтрами |
POST /daily-reports — тело запроса:
json
{
"traffic_channel_id": 1,
"report_date": "2026-08-25",
"reach": 10000,
"visits": 150,
"applications": 12,
"qualified_applications": 5,
"expenses": 25000.00
}7.3. Планы
| Метод | URL | Permission | Описание |
|---|---|---|---|
| GET | /plans?year=&month=&channel_id= | view_statistics_all | Планы за месяц |
| POST | /plans | manage_statistics_plans | Создание / обновление плана |
| GET | /plans/distribution?year=&month=&channel_id= | view_statistics_* | План по дням и неделям |
7.4. Сводная статистика
| Метод | URL | Описание |
|---|---|---|
| GET | /summary?from=&to=&channel_id=&group_by=day|week|month | Факт + план + % выполнения |
Пример фрагмента ответа /summary:
json
{
"period": { "from": "2026-08-01", "to": "2026-08-25" },
"group_by": "week",
"items": [
{
"week": 34,
"from": "2026-08-18",
"to": "2026-08-24",
"metrics": {
"visits": { "fact": 420, "plan": 500, "completion_pct": 84.0 },
"applications": { "fact": 35, "plan": 40, "completion_pct": 87.5 }
}
}
]
}8. Бизнес-логика
8.1. Ежедневная обязательная модалка
Backend — StatisticsPendingReportService:
- Получить каналы, привязанные к текущему пользователю
- Для каждого канала найти последний незаполненный рабочий
report_date(пн–пт, начиная с вчера и ранее) - Суббота и воскресенье пропускать — не попадают в очередь
- Вернуть очередь:
[{ channel_id, channel_name, report_date }, ...]
Frontend — StatisticsDailyReportModal.vue:
- Подключить в
layouts/dashboard.vue - При загрузке layout →
GET /statistics/pending - Если очередь не пуста →
v-dialog persistent(нельзя закрыть без submit) - Поля: канал (если несколько), дата (readonly), метрики факта
- После успешного POST — убрать элемент из очереди; при пустой очереди — закрыть
- Паттерн:
frontend/components/inspection/inspectionCreateModal.vue
Права: только роли contractor, smm_specialist (permission fill_statistics_daily).
8.2. Распределение плана
StatisticsPlanDistributionService + StatisticsWorkingDaysService:
working_days_in_month = COUNT(даты месяца, где день недели пн–пт)
daily_plan[metric][date] =
monthly_plan[metric] / working_days_in_month // если date — рабочий день
0 // если date — сб или вс
weekly_plan[metric][week] = SUM(daily_plan[metric] for dates in ISO week)
completion_pct = (SUM(fact) / SUM(plan)) * 100 // план периода — только рабочие дниНедели: ISO (пн–вс). В выходные дни план = 0, отчёт не требуется.
API /plans/distribution возвращает workingDaysInMonth и isWorkingDay для каждого дня.
8.3. Разграничение доступа к данным
| Роль | Видит |
|---|---|
| contractor, smm_specialist | Только каналы, к которым привязан |
| mop | Только своя статистика МОП (без каналов и «По сотрудникам») |
| director, administrator | Все каналы + сотрудники + планы |
9. Frontend — экраны
9.1. Дашборд /dashboard/statistics
- Фильтры: месяц, канал, группировка (день / неделя / месяц)
- Таблица: План | Факт | % выполнения по каждой метрике
- Accordion / вкладки по неделям
- Для director/mop — все каналы; для contractor/smm — только свои
js
definePageMeta({
layout: 'dashboard',
middleware: ['auth', 'role'],
roles: ['director', 'administrator', 'superadmin', 'mop', 'contractor', 'smm_specialist'],
})9.2. Каналы /dashboard/statistics/channels
- Только
manage_statistics_channels - CRUD + multiselect пользователей (роли contractor, smm_specialist)
9.3. Планы /dashboard/statistics/plans
- Только
manage_statistics_plans - Выбор месяца и канала, форма плановых значений, превью раскладки по неделям
9.4. Меню
Добавить в frontend/utils/menuConfig.js:
js
{
module: 'statistics',
title: 'Статистика',
icon: 'mdi-chart-bar',
to: '/dashboard/statistics',
roles: ['director', 'administrator', 'superadmin', 'mop', 'contractor', 'smm_specialist'],
}10. Этапы разработки
Этап 1 — Фундамент (2–3 дня)
Этап 2 — Ежедневные отчёты (2–3 дня)
Этап 3 — Планы и распределение (2–3 дня)
Этап 4 — Дашборд и разрезы (3–4 дня)
Этап 5 — Полировка (1–2 дня)
Оценка части 1: ~10–15 рабочих дней
11. Риски и митигация
| Риск | Митигация |
|---|---|
| МОП без формы в части 1 | Роль и view_statistics_all создаются сразу; форма МОП — отдельная миграция/таблица на этапе 2 |
Конфликт с существующей ролью smm_specialist | Только добавить statistics-permissions, не менять текущие |
| Модалка блокирует работу при ошибке API | Показать ошибку + «Повторить», не давать закрыть без успешного submit |
| Часовой пояс «начало дня» | Carbon с timezone из config/app.php |
| Несколько незаполненных дней подряд | Очередь в /pending, заполнение по одному дню за submit |
12. Этап 2 — статистика МОП
Подробный план: STATISTICS_MOP_PLAN.md
Кратко:
- Отдельная сущность / таблица отчётов МОП (собственные поля, без привязки к каналу)
- Permission
fill_statistics_mop_daily - Отдельная модалка ежедневного отчёта
- Дашборд и месячные планы по каждому МОП
13. Связанные файлы проекта
| Назначение | Путь |
|---|---|
| Регистрация модулей | backend/app/Providers/ModuleServiceProvider.php |
| Middleware permission | backend/modules/Core/Http/Middleware/CheckPermission.php |
| Меню API | backend/modules/Core/Http/Controllers/MenuController.php |
| Меню frontend | frontend/utils/menuConfig.js |
| Auth / modules | frontend/stores/auth.js |
| API-клиент | frontend/composables/useApiFetch.ts |
| Dashboard layout | frontend/layouts/dashboard.vue |
| Пример analytics-модуля | backend/modules/BotStats/ |
| Пример persistent modal | frontend/components/inspection/inspectionCreateModal.vue |
| Пример migration ролей | backend/modules/Core/database/migrations/2026_07_13_180000_add_smm_specialist_role.php |
14. Порядок первых коммитов
- Модуль + миграции + роли + permissions
- CRUD каналов (API + admin UI)
- Ежедневная модалка (happy path)
- Планы директора
- Дашборд с недельными разрезами