← К списку версий
v0.35.0
19.08.2026
PATCH
Система тарифов и задач по уровням
Что сделано
- Добавлено поле `level` (unsigned tiny integer, default 0) в таблицу `tariffs`
- Добавлено поле `tariff_level` (unsigned tiny integer, default 0) в таблицу `client_task_templates`
- Базовый запуск: level 0, 3000 BYN, 3 мес (1000/мес)
- Цифровая архитектура: level 1, 6000 BYN, 6 мес (1000/мес)
- Экосистема роста: level 2, 12000 BYN, 12 мес (1000/мес)
- Стратегическое партнёрство: level 3, 15000 BYN, VIP (гейтинг)
- Итеративная инкрементная поставка: level 1, 6000 BYN, 5 этапов
- `ClientTariffController::subscribe()` — создаёт подписку, деактивирует предыдущую, обновляет finance
- POST-роут `tariff/{tariff}/subscribe`
- Валидация: проверка публичности, доступности, дубликатов
- ActivityLogger логирует подключение
- Шаблоны задач (`ClientTaskTemplate`) имеют поле `tariff_level` (0–3)
- Level 0: базовые задачи (ТЗ, договор, оплата, материалы, проверка) — доступны всем
- Level 1: аналитика, контент-план, SEO-отчёт
- Level 2: стратегия продвижения, стратегическая сессия
- Level 3: персональная дорожная карта
- Клиент видит только задачи с `tariff_level <= его уровень`
- `DashboardController::index()` — фильтрует clientTasks по tariff_level клиента
- `ProjectController::show()` — фильтрует clientTasks по tariff_level
- `ProjectTokenController::show()` — фильтрует clientTasks по tariff_level (гостевой доступ)
- Задачи без шаблона (`template_id = null`) доступны всегда
- Добавлен `level` в fillable/casts
- Добавлен `Tariff::levelLabel(int $level)` — возвращает название уровня
- Добавлен `Tariff::getClientLevel(Client $client)` — определяет уровень клиента по активной подписке
- Добавлен `tariff_level` в fillable/casts
- Показывает все публичные тарифы (не только апгрейды)
- Текущий тариф выделен зелёным с бейджем «Ваш тариф»
- Кнопка «Подключить» — POST-форма с CSRF
- Текущий тариф — кнопка «Текущий тариф» (disabled)
- Недоступные — замок с причиной
Техническое
- `app.css`: добавлен блок «Kebab menu (универсальный)» (~80 строк)
- `app.blade.php`: глобальный `toggleKebab` + click-outside + Escape handler
- `APP_VERSION` изменён: `0.34.2` → `0.34.3`
- 142 тестов, 580 ассертов — все пройдены.
Что исправлено
- Добавлены унифицированные CSS-классы: `.kebab-wrap`, `.kebab-btn`, `.kebab-menu`, `.kebab-item`, `.kebab-sep`
- Ранее стили были размазаны по инлайн-блокам `<style>` в каждом blade-файле
- Теперь kebab-меню работает везде: карточки проектов, админка, страница проекта
- `toggleKebab(btn)` — глобальная, определена в layout (ранее дублировалась в каждом файле)
- Закрытие по клику вне меню — глобальный обработчик
- Закрытие по Escape — глобальный обработчик
- `dashboard/index.blade.php` — удалены инлайн kebab-стили и JS
- `admin/index.blade.php` — удалены инлайн kebab-стили и JS
- `admin/projects/index.blade.php` — удалены инлайн kebab-стили и JS
- `admin/projects/show.blade.php` — удалены инлайн kebab-стили и JS, `.kebab` → `.kebab-wrap`
Результат
- Тарифы привязаны к уровням — задачи фильтруются по тарифу
- Кнопка «Подключить» работает — создаёт подписку и обновляет финансы
- Клиент видит только задачи, доступные его тарифу