Files
marketplace/отчеты/план-админ-модерация-монетизация.md
delta-lynx-89e8 dbbbbd26f4 Add rental system: listings, bookings, payments, payouts, reviews
Full rental marketplace with 6 categories (apartment, house, car, motorcycle, bicycle, ebike).
Booking workflow: create → confirm → pay → active → complete → payout.
Landlord dashboard, admin moderation, availability calendar, Stripe Connect payouts.
14 QA bugs found and fixed including validator schemas, API response types, HTTP methods.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-22 15:33:29 -08:00

15 KiB
Raw Blame History

Marketplace — Админ-панель, Модерация, Монетизация

Контекст

MVP маркетплейса полностью рабочий и задеплоен (buyer/seller flow, чат, офферы, нотификации, избранное, настройки). Но отсутствует вся бизнес-логика уровня продакшена: нет ролей, нет админки, нет модерации, нет системы жалоб, нет монетизации. Сейчас любой листинг публикуется мгновенно без проверки, нет возможности заблокировать пользователя со стороны платформы, и нет инструментов для управления маркетплейсом.

Сервер: 173.212.212.157 | Домен: marketplace.173.212.212.157.sslip.io


Фаза 1: Схема БД + RBAC (Роли и права)

Prisma Schema — server/prisma/schema.prisma

Новые enum'ы:

  • UserRole: USER, MODERATOR, ADMIN, SUPER_ADMIN
  • ReportReason: SPAM, INAPPROPRIATE, SCAM, COUNTERFEIT, PROHIBITED_ITEM, HARASSMENT, OTHER
  • ReportStatus: OPEN, REVIEWING, RESOLVED, DISMISSED
  • ReportTargetType: LISTING, USER
  • SubscriptionTier: BASIC, PRO, BUSINESS
  • SubscriptionStatus: ACTIVE, CANCELLED, EXPIRED, PAST_DUE
  • PaymentType: LISTING_FEE, COMMISSION, PROMOTION, SUBSCRIPTION
  • ModerationAction: APPROVED, REJECTED, WARNING, BAN, UNBAN, LISTING_DELETED, LISTING_FEATURED

Изменения существующих enum'ов:

  • ListingStatus: добавлен PENDING_REVIEW между DRAFT и ACTIVE
  • NotificationType: добавлены LISTING_APPROVED, LISTING_REJECTED, MODERATION_WARNING, ACCOUNT_BANNED, ACCOUNT_UNBANNED, REPORT_RESOLVED

Изменения существующих моделей:

  • User: + role UserRole @default(USER), isBanned Boolean @default(false), banReason String?, bannedAt DateTime?, bannedBy String?
  • Listing: + isFeatured Boolean @default(false), rejectionReason String?, reviewedBy String?, reviewedAt DateTime?
  • Payment: + type PaymentType @default(LISTING_FEE), description String?

Новые модели (6 штук):

Модель Назначение Ключевые поля
Report Жалобы пользователей reporterId, targetType, targetId, reason, status, resolvedBy, resolution
PlatformConfig Настройки платформы (1 строка) listingFee, commissionPercent, autoApprove, maxImagesPerListing, maxListingsFreeTier, proPrice, businessPrice, promotionDayPrice, blockedKeywords[]
Subscription Подписки продавцов userId (unique), tier, status, stripeSubscriptionId, currentPeriodEnd
PromotedListing Продвинутые объявления listingId (unique), userId, startDate, endDate, amountPaid, isActive
ModerationLog Аудит-лог действий модераторов moderatorId, targetUserId?, targetListingId?, action, reason, details(Json)

Middleware — новые файлы

Файл Назначение
server/src/middleware/requireRole.ts Фабрика middleware: requireRole('ADMIN', 'SUPER_ADMIN'). Проверяет роль из БД (не из JWT — изменения роли применяются мгновенно). Экспорт: requireModerator, requireAdmin, requireSuperAdmin
server/src/middleware/checkBanned.ts Проверяет isBanned и возвращает 403 если забанен
server/src/utils/moderation.ts Проверка текста на запрещённые слова из PlatformConfig. Кэш конфига на 60 сек

Изменения существующих файлов

Файл Изменения
server/src/middleware/auth.ts Расширен Request типом userRole?: string
server/src/routes/auth.ts Добавлен role в select; проверка isBanned при логине (403 с причиной)
client/src/types/index.ts Добавлен role: UserRole в User, новые типы Report, PlatformConfig, Subscription и т.д.
client/src/context/AuthContext.tsx Добавлены isAdmin, isModerator, isSuperAdmin (computed из user.role)

Seed — server/prisma/seed.ts

  • Создана строка PlatformConfig с дефолтами
  • alice → SUPER_ADMIN, bob → ADMIN, carol → MODERATOR

Фаза 2: Админ-панель — Layout + Dashboard

Новые компоненты

Файл Назначение
client/src/components/layout/RequireRole.tsx Route guard: проверяет user.role, редирект на / если нет доступа
client/src/components/layout/AdminLayout.tsx Sidebar с навигацией (Dashboard, Users, Listings, Reports, Moderation, Payments, Settings) + <Outlet />
client/src/components/ui/StatCard.tsx Карточка метрики: иконка, число, подпись, тренд
client/src/components/ui/DataTable.tsx Переиспользуемая таблица: колонки, пагинация, поиск, сортировка

Backend — server/src/routes/admin/stats.ts

Endpoint Доступ Что делает
GET /api/admin/stats MODERATOR+ Общая статистика: юзеры, листинги, офферы, выручка, активные сегодня
GET /api/admin/stats/revenue ADMIN+ Выручка по дням/неделям/месяцам
GET /api/admin/stats/users ADMIN+ Рост пользователей по времени
GET /api/admin/stats/listings MODERATOR+ Активность листингов по времени

Frontend — client/src/pages/admin/AdminDashboardPage.tsx

  • 5 StatCard'ов: юзеры, листинги, офферы, выручка, активные
  • Quick Stats и Platform Health панели

Router — client/src/router.tsx

/admin → RequireRole(['MODERATOR','ADMIN','SUPER_ADMIN']) → AdminLayout
  /admin (index)       → AdminDashboardPage
  /admin/users         → AdminUsersPage
  /admin/users/:id     → AdminUserDetailPage
  /admin/listings      → AdminListingsPage
  /admin/reports       → AdminReportsPage
  /admin/moderation    → AdminModerationPage
  /admin/payments      → AdminPaymentsPage
  /admin/settings      → AdminSettingsPage

Header — client/src/components/layout/Header.tsx

  • Добавлена ссылка "Admin" в навигацию (если isModerator || isAdmin)

Фаза 3: Управление пользователями

Backend — server/src/routes/admin/users.ts

Endpoint Доступ Что делает
GET /api/admin/users MODERATOR+ Список юзеров с поиском, фильтром по роли/статусу, пагинацией
GET /api/admin/users/:id MODERATOR+ Полный профиль + кол-во листингов/офферов/жалоб + лог модерации
PATCH /api/admin/users/:id/role SUPER_ADMIN Сменить роль (нельзя себя понизить)
POST /api/admin/users/:id/ban ADMIN+ Забанить (body: { reason }). Создаёт ModerationLog, отправляет нотификацию ACCOUNT_BANNED
POST /api/admin/users/:id/unban ADMIN+ Разбанить. ModerationLog + нотификация ACCOUNT_UNBANNED

Frontend

  • AdminUsersPage.tsx — DataTable: аватар+имя, email, роль (Badge), статус, дата регистрации, действия
  • AdminUserDetailPage.tsx — профиль + статистика + история модерации + кнопки бан/разбан/роль

Фаза 4: Модерация объявлений

Backend

server/src/routes/admin/listings.ts:

Endpoint Доступ Что делает
GET /api/admin/listings MODERATOR+ Все листинги, фильтр по статусу/категории, поиск
POST /api/admin/listings/:id/approve MODERATOR+ Статус → ACTIVE, ModerationLog, нотификация LISTING_APPROVED
POST /api/admin/listings/:id/reject MODERATOR+ Статус → DELETED, сохранить rejectionReason, нотификация LISTING_REJECTED
DELETE /api/admin/listings/:id ADMIN+ Принудительное удаление, ModerationLog
POST /api/admin/listings/:id/feature ADMIN+ Переключить isFeatured

server/src/routes/admin/moderation.ts:

Endpoint Доступ Что делает
GET /api/admin/moderation/queue MODERATOR+ Листинги со статусом PENDING_REVIEW, пагинация
GET /api/admin/moderation/logs ADMIN+ Полная история действий модерации

Изменения server/src/routes/listing.ts:

  • POST /:id/activate: если PlatformConfig.autoApprove === false → статус PENDING_REVIEW вместо ACTIVE
  • POST / (создание): проверка текста на blockedKeywords → если найдено, автоматически PENDING_REVIEW
  • Добавлен isFeatured в listingSelect

Frontend

  • AdminListingsPage.tsx — DataTable с табами по статусу (ALL, PENDING_REVIEW, ACTIVE, SOLD, DELETED)
  • AdminModerationPage.tsx — Карточки листингов на ревью: фото, заголовок, описание, продавец, кнопки Approve/Reject

Фаза 5: Система жалоб (Reports)

Backend

server/src/routes/report.ts (пользовательский):

Endpoint Доступ Что делает
POST /api/reports Авторизованный Создать жалобу: { targetType, targetId, reason, description }

server/src/routes/admin/reports.ts:

Endpoint Доступ Что делает
GET /api/admin/reports MODERATOR+ Список жалоб, фильтр по статусу/типу, пагинация
GET /api/admin/reports/:id MODERATOR+ Детали жалобы с информацией о цели
PATCH /api/admin/reports/:id MODERATOR+ Разрешить/отклонить: { status, resolution }

Frontend

  • ReportModal.tsx — Модалка с радиокнопками причин + описание
  • ProductDetailPage.tsx — кнопка "Report" теперь открывает ReportModal (вместо alert())
  • AdminReportsPage.tsx — DataTable с табами по статусу

Фаза 6: Настройки платформы + Админ платежей

Backend

server/src/routes/admin/settings.ts:

Endpoint Доступ Что делает
GET /api/admin/settings ADMIN+ Текущий PlatformConfig
PATCH /api/admin/settings SUPER_ADMIN Обновить любые поля PlatformConfig

server/src/routes/admin/payments.ts:

Endpoint Доступ Что делает
GET /api/admin/payments ADMIN+ Все платежи, фильтр по типу/статусу, пагинация
GET /api/admin/payments/revenue ADMIN+ Разбивка: listing fees, commissions, promotions, subscriptions

Изменения server/src/routes/payment.ts:

  • POST /create-intent: читает listingFee из PlatformConfig вместо хардкода 500
  • Записывает type: 'LISTING_FEE' в Payment

Frontend

  • AdminSettingsPage.tsx — Форма: listing fee, commission %, auto-approve toggle, max images, free tier limit, pro/business цены, promotion day price, blocked keywords
  • AdminPaymentsPage.tsx — 4 карточки выручки по типам + таблица транзакций

Фаза 7: Монетизация — Подписки + Продвижение

Backend

server/src/routes/subscription.ts:

Endpoint Доступ Что делает
GET /api/subscriptions/current Авторизованный Текущая подписка (или BASIC по умолчанию)
POST /api/subscriptions/create Авторизованный Создать подписку PRO/BUSINESS
POST /api/subscriptions/cancel Авторизованный Отменить подписку

server/src/routes/promotion.ts:

Endpoint Доступ Что делает
POST /api/listings/:id/promote Авторизованный Оплатить продвижение (body: { days })
GET /api/listings/:id/promotion Авторизованный Статус продвижения

Изменения server/src/routes/offer.ts:

  • При ACCEPTED: создаётся Payment с type: 'COMMISSION' и суммой = commissionPercent от amount

Тарифные планы:

  • Basic (бесплатно): до 5 листингов/мес
  • Pro ($9.99/мес): безлимит + аналитика продавца
  • Business ($29.99/мес): bulk-операции + приоритетная поддержка

Деплой

# 1. Миграция
cd server && npx prisma migrate dev --name admin_moderation_monetization

# 2. Обновить seed
npx tsx prisma/seed.ts

# 3. Билд и деплой
npm run build --workspace=client
scp -r client/dist/* root@173.212.212.157:/var/www/marketplace/
ssh root@173.212.212.157 'cd /var/www/marketplace-app && git pull && cd server && npm install && npx prisma db push && pm2 restart marketplace-api'

# 4. Seed на проде
ssh root@173.212.212.157 'cd /var/www/marketplace-app/server && npx tsx prisma/seed.ts'

Верификация

  1. Логин как alice (SUPER_ADMIN) → в хедере видна ссылка "Admin"
  2. /admin → дашборд с метриками
  3. /admin/users → таблица юзеров, можно забанить david
  4. Логин как david → получить 403 "Account suspended"
  5. /admin/users → разбанить david
  6. /admin/settings → отключить autoApprove
  7. Логин как david → создать листинг → статус PENDING_REVIEW
  8. /admin/moderation → увидеть листинг в очереди → Approve
  9. На странице товара нажать Report → модалка → отправить жалобу
  10. /admin/reports → увидеть жалобу → Resolve
  11. /admin/payments → все транзакции с типами
  12. /admin/settings → изменить listing fee