Appearance
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 # Просмотр + модерацияNavigation
- В
default.vueheader для 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
| Action | Method | Endpoint |
|---|---|---|
| Список | 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)
- Просмотр аудит-лога