Skip to content

Admin Moderation — Design Document

Date: 2026-02-08 Scope: Модерация объявлений в админ-панели (MVP)

Overview

Встраиваем админ-панель в текущее Nuxt-приложение. В рамках MVP реализуем только модерацию объявлений (approve/reject). Архитектура закладывается с расчётом на расширение (пользователи, справочники, дашборд — позже).

Routing & Layout

Layout: admin.vue

  • Header: логотип + "Админ-панель" + кнопка выхода
  • Боковая панель (десктоп — sidebar, мобайл — drawer)
  • Пока один пункт навигации: "Объявления"
  • Расширяемо для будущих разделов

Middleware: admin.ts

  • Проверяет authStore.isAuthenticated && authStore.isAdmin
  • Если не admin — редирект на /

Pages

app/pages/admin/
├── index.vue                    # Редирект → /admin/products
└── products/
    ├── index.vue                # Список объявлений
    └── [id].vue                 # Просмотр + модерация
  • В default.vue header для admin-пользователей — ссылка "Админ-панель"

Список объявлений (/admin/products)

UI

  • Табы по статусам: Pending (по умолчанию), All, Active, Draft, Rejected, Archived, Sold
  • Таблица (UTable): заголовок, продавец, категория, цена, дата, статус (UBadge)
  • Клик по строке → /admin/products/[id]
  • Курсорная пагинация (reuse useCursorPagination)

Polling (автообновление)

  • useIntervalFn из VueUse — polling каждые 30 секунд
  • Активен только на табе "Pending"
  • Дедупликация: обновляем список только если данные изменились (isEqual)
  • Останавливается при onUnmounted
  • Визуальный индикатор "Последнее обновление: X сек назад"

Страница модерации (/admin/products/[id])

Отображение (read-only)

  • Фотогалерея
  • Заголовок, описание, цена
  • Спецификации: OEM, производитель, руль
  • Совместимость (марки/модели/поколения)
  • Категории
  • Локация (город, район, метро, адрес)
  • Информация о продавце (имя, email, дата регистрации, кол-во объявлений)

Действия (для pending-объявлений)

  • "Одобрить"PUT /admin/products/:id/approve → статус active
  • "Отклонить" → модал с textarea для причины → PUT /admin/products/:id/reject → статус rejected
  • После действия — редирект на список

Для других статусов

  • Просмотр без кнопок модерации

FSD-структура

app/
├── pages/admin/
│   ├── index.vue
│   └── products/
│       ├── index.vue
│       └── [id].vue
├── layouts/admin.vue
├── middleware/admin.ts
└── features/
    └── admin-moderation/
        ├── composables/
        │   └── useAdminProducts.ts    # API обёртка + polling логика
        └── ui/
            └── ModerationActions.vue   # Кнопки одобрить/отклонить + модал отклонения

Переиспользуем: productDetailSchema, userSchema, useApi(), useCursorPagination(), ProductStatusBadge.

API Endpoints

ActionMethodEndpoint
СписокGET/admin/products?status=pending&limit=20&cursor=...
ДеталиGET/admin/products/:id
ОдобритьPUT/admin/products/:id/approve
ОтклонитьPUT/admin/products/:id/reject{ reason: string }

Response format

ts
// GET /admin/products
{ data: ProductDetail[], meta: { has_more: boolean, next_cursor: string | null } }

// GET /admin/products/:id
ProductDetail (+ seller info)

// PUT approve/reject
{ success: boolean }

Не входит в scope (осознанно)

  • Дашборд со статистикой
  • Управление пользователями
  • CRUD справочников (марки, модели, категории, гео)
  • Счётчик pending в header
  • Массовые действия (bulk approve/reject)
  • Просмотр аудит-лога