Сторінка контролю/аналітики — це не просто “ще один список”. Це інструмент, яким користуються щодня: редактор дивиться, що сталося за день, хто що опублікував, де завис статус, що треба перевірити, що не пішло в соцмережі, які матеріали без обкладинки, які в чернетках, які на модерації. Якщо ви зробите її правильно, вона економить години ручної роботи. Якщо зробите “як вийшло” — вона перетвориться на повільний, незручний екран, де все губиться.
Починайте з чіткої мети сторінки. У контролі за публікаціями мета зазвичай одна: швидко знайти матеріали за період і побачити їхній стан. Тому мінімальний набір фільтрів: дата (від/до), юзер (хто створив/відредагував/опублікував), статус (чернетка/на модерації/опубліковано/відхилено/архів), плюс пошук по заголовку. Далі, якщо у вас мультисайт або ресурси, додається фільтр по ресурсу/розділу. Але ядро — дата, юзер, статус.
Далі — найважливіша архітектурна дисципліна: запит будується в правильному порядку. Порядок такий: спочатку обмеження доступу (хто що може бачити), потім накладання фільтрів з query string, потім сортування, і тільки в кінці пагінація. Якщо ви порушите порядок, ви отримаєте або витік даних (фільтр “розширив доступ”), або неправильні сторінки (paginate до фільтрів), або повільні запити (фільтрація вже після вибірки в PHP).
Обмеження доступу — це фундамент. Наприклад, автор бачить лише свої матеріали, редактор — матеріали свого ресурсу, адміністратор — все. Це повинно бути на рівні SQL, не на рівні Blade. Тобто базовий query одразу містить where created_by = $user->id або where resource_id in (...) залежно від прав. Тільки після цього ви додаєте status, from/to, user_id як фільтри. Таким чином жоден параметр URL не розширить видимість.
Фільтр по даті — найбільш “слизький”. Перше, що треба вирішити: яка дата є “контрольною” — published_at чи created_at чи updated_at. Для контролю публікацій майже завжди потрібен published_at, але для контролю роботи редакції інколи потрібен updated_at (хто що правив). Правильний UX — мати перемикач “фільтрувати по: дата публікації / дата створення / дата оновлення”. Якщо ви цього не зробите, користувачі будуть плутатись, і сторінка стане джерелом конфліктів “вона ж була сьогодні, чого її тут нема”.
Після вибору поля дати треба коректно працювати з межами. Якщо ви даєте фільтр у форматі “дата без часу”, то from має перетворюватись у початок дня, а to — у кінець дня. Інакше ви будете “втрачати” записи. Це не теорія — це типова помилка, яка потім виглядає як “система інколи не показує матеріали”. У адмінці це неприйнятно, бо контроль має бути точним.
Фільтр по юзеру — теж має бути чітким: кого саме фільтруємо. Часто потрібні два варіанти: “створив” і “останній редагував”. У простій версії достатньо “created_by”. Але якщо у вас є activity log або updated_by, тоді аналітика стає сильнішою. Важливо: список юзерів не треба тягнути “всіх завжди” у великих системах. На старті можна, але потім краще або робити пошук, або обмежувати ролями.
Фільтр по статусу має бути жорстко контрольований. Ніяких “довільних строк”. Статуси мають бути з переліку, і це має відображатися у UI як select. Так ви тримаєте систему чистою: в запити не потрапляють “ліві” значення, і ви не ускладнюєте собі підтримку. Плюс статуси майже завжди мають бути індексованими в БД, бо це один із найбільш частих WHERE.
Тепер пагінація. На сторінках контролю/аналітики пагінація не “для краси”, а для продуктивності і стабільності. Правильний розмір сторінки — 25–50 елементів, інколи 100, якщо таблиця легка. Але не “все”. Пагінація повинна зберігати query string, інакше ви натискаєте “сторінка 2” і втрачаєте фільтр — і знову хаос. Тому стандарт: paginate + збереження параметрів у посиланнях.
Ще один важливий момент: при зміні фільтрів потрібно скидати page на 1. Інакше користувач був на сторінці 7, поставив статус “draft”, і отримає пусто — бо під draft є лише 2 сторінки. Це виглядає як “нічого не знайдено”, і люди починають сумніватися в системі. Тому або форма не передає page, або ви в UI робите “очистити пагінацію” при сабміті.
Стан сторінки має жити в URL. Це означає: форма фільтрів — GET, усі поля — у query string, поточні значення підставляються назад у поля, і будь-який список можна відкрити по прямому посиланню. Це критично для роботи редакції: “скинь мені список матеріалів на модерації за вчора” — і це має бути один URL. Якщо у вас фільтри в POST або в сесії, ви втрачаєте керованість.
Далі — сортування. На сторінці контролю стандартно сортують за датою (desc), інколи за статусом, інколи за пріоритетом. Але сортування теж має бути контрольованим: дозволяєте 2–3 поля і напрямок asc/desc. Ніяких “довільних orderBy з URL”, бо це прямий шлях до SQL-ін’єкцій на рівні колонок або до хаотичних запитів.
Тепер про “аналітику” поверх списку. Часто на такій сторінці потрібні підсумки: скільки матеріалів у кожному статусі за період, скільки зробив кожен юзер, скільки було відхилено. Важливе правило: ці агрегати не треба рахувати в PHP по всій таблиці, якщо даних багато. Це або окремі легкі SQL-агрегації з тими самими фільтрами, або кешовані підсумки, або взагалі окрема сторінка. Але навіть просте “показати лічильники по статусах” дуже підсилює контроль і дає “картину дня”.
З точки зору продуктивності, ця сторінка завжди росте в проблемне місце. Тому зразу думайте про індекси: дата-поле (published_at/created_at), статус, created_by, resource_id. І дуже уважно до JOIN: якщо ви робите join на users для відображення імені — це нормально. Але якщо ви тягнете купу зв’язків без потреби, ви отримаєте важкі запити. Найкращий підхід: вибирати тільки потрібні колонки, eager load лише те, що точно відображаєте, і не робити N+1.
У фіналі вам потрібна “стабільна поведінка”. Вона досягається простими правилами: однакові параметри URL завжди дають однаковий результат, сторінка 2 — це продовження того самого фільтра, зміна фільтра — повертає на сторінку 1, і недоступні записи ніколи не потрапляють у вибірку. Якщо ці речі виконані, сторінці починають довіряти, а довіра в адмінці — це головне.
Висновок: сторінка контролю/аналітики — це “серце” операційної роботи. Робіть її як інструмент: чіткі фільтри по даті/юзеру/статусу, стан у URL, правильний порядок побудови запиту (доступи → фільтри → сортування → paginate), збереження query string у пагінації, індекси під фільтри, і мінімум зайвих підвантажень. Якщо закласти це стандартом зараз, далі ви легко додасте нові фільтри, підсумки та швидкі дії, не ламаючи ні продуктивність, ні безпеку.