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>
This commit is contained in:
319
отчеты/отчет-реализация.md
Normal file
319
отчеты/отчет-реализация.md
Normal file
@@ -0,0 +1,319 @@
|
||||
# Отчёт о реализации: Админ-панель, Модерация, Монетизация
|
||||
|
||||
**Дата**: 22 февраля 2026
|
||||
**Проект**: Marketplace
|
||||
**Статус**: Реализовано, собрано, мигрировано, seed обновлён
|
||||
|
||||
---
|
||||
|
||||
## Общий объём работ
|
||||
|
||||
- **29 новых файлов** создано
|
||||
- **13 существующих файлов** модифицировано
|
||||
- **42 файла** затронуто суммарно
|
||||
- **1 новая зависимость** (`recharts`) установлена
|
||||
- **1 миграция БД** применена (`admin_moderation_monetization`)
|
||||
|
||||
---
|
||||
|
||||
## Новые серверные файлы (16)
|
||||
|
||||
| # | Файл | Назначение | Статус |
|
||||
|---|---|---|---|
|
||||
| 1 | `server/src/middleware/requireRole.ts` | RBAC middleware — `requireModerator`, `requireAdmin`, `requireSuperAdmin` | Готово |
|
||||
| 2 | `server/src/middleware/checkBanned.ts` | Проверка бана пользователя (403) | Готово |
|
||||
| 3 | `server/src/utils/moderation.ts` | Кэш PlatformConfig (60с), проверка blockedKeywords | Готово |
|
||||
| 4 | `server/src/routes/admin/index.ts` | Агрегатор всех админ-роутов с authenticate | Готово |
|
||||
| 5 | `server/src/routes/admin/stats.ts` | GET /api/admin/stats — дашборд-аналитика | Готово |
|
||||
| 6 | `server/src/routes/admin/users.ts` | CRUD юзеров, бан/разбан, смена ролей | Готово |
|
||||
| 7 | `server/src/routes/admin/listings.ts` | Approve/reject листингов, featured, force delete | Готово |
|
||||
| 8 | `server/src/routes/admin/reports.ts` | Управление жалобами — список, детали, resolve/dismiss | Готово |
|
||||
| 9 | `server/src/routes/admin/moderation.ts` | Очередь PENDING_REVIEW + лог модерации | Готово |
|
||||
| 10 | `server/src/routes/admin/payments.ts` | Все платежи + revenue breakdown по типам | Готово |
|
||||
| 11 | `server/src/routes/admin/settings.ts` | CRUD PlatformConfig с инвалидацией кэша | Готово |
|
||||
| 12 | `server/src/routes/report.ts` | POST /api/reports — создание жалобы юзером | Готово |
|
||||
| 13 | `server/src/routes/subscription.ts` | Подписки: current, create, cancel | Готово |
|
||||
| 14 | `server/src/routes/promotion.ts` | Продвижение листингов: promote, get status | Готово |
|
||||
| 15 | `server/src/validators/admin.ts` | Zod-схемы: ban, role, reject, resolve, settings | Готово |
|
||||
| 16 | `server/src/validators/report.ts` | Zod-схема создания жалобы | Готово |
|
||||
|
||||
---
|
||||
|
||||
## Новые клиентские файлы (13)
|
||||
|
||||
| # | Файл | Назначение | Статус |
|
||||
|---|---|---|---|
|
||||
| 17 | `client/src/components/layout/RequireRole.tsx` | Route guard по роли пользователя | Готово |
|
||||
| 18 | `client/src/components/layout/AdminLayout.tsx` | Sidebar-layout админки с навигацией | Готово |
|
||||
| 19 | `client/src/components/ui/StatCard.tsx` | Карточка метрики (иконка, число, цвет) | Готово |
|
||||
| 20 | `client/src/components/ui/DataTable.tsx` | Переиспользуемая таблица с поиском и пагинацией | Готово |
|
||||
| 21 | `client/src/components/ReportModal.tsx` | Модалка жалобы с радиокнопками причин | Готово |
|
||||
| 22 | `client/src/pages/admin/AdminDashboardPage.tsx` | Дашборд: 5 метрик + Quick Stats + Health | Готово |
|
||||
| 23 | `client/src/pages/admin/AdminUsersPage.tsx` | Таблица юзеров с поиском и навигацией | Готово |
|
||||
| 24 | `client/src/pages/admin/AdminUserDetailPage.tsx` | Детали юзера: профиль, статы, бан, роль, история | Готово |
|
||||
| 25 | `client/src/pages/admin/AdminListingsPage.tsx` | Таблица листингов с табами по статусу | Готово |
|
||||
| 26 | `client/src/pages/admin/AdminReportsPage.tsx` | Жалобы с табами + модалка resolve/dismiss | Готово |
|
||||
| 27 | `client/src/pages/admin/AdminModerationPage.tsx` | Очередь модерации — карточки с approve/reject | Готово |
|
||||
| 28 | `client/src/pages/admin/AdminPaymentsPage.tsx` | 4 StatCard выручки + таблица транзакций | Готово |
|
||||
| 29 | `client/src/pages/admin/AdminSettingsPage.tsx` | Форма настроек: fees, limits, moderation | Готово |
|
||||
|
||||
---
|
||||
|
||||
## Модифицированные файлы (13)
|
||||
|
||||
| # | Файл | Что изменено | Статус |
|
||||
|---|---|---|---|
|
||||
| 30 | `server/prisma/schema.prisma` | 8 новых enum, 6 новых моделей, 3 модели расширены | Готово |
|
||||
| 31 | `server/prisma/seed.ts` | + PlatformConfig, + роли (alice=SA, bob=A, carol=M), + cleanup новых таблиц | Готово |
|
||||
| 32 | `server/src/index.ts` | + 4 новых route group: reports, subscriptions, promotions, admin | Готово |
|
||||
| 33 | `server/src/middleware/auth.ts` | + `userRole?: string` в Request type | Готово |
|
||||
| 34 | `server/src/routes/auth.ts` | + `role` в select (3 места), + проверка `isBanned` при логине | Готово |
|
||||
| 35 | `server/src/routes/listing.ts` | + autoApprove check, + blockedKeywords check, + isFeatured в select | Готово |
|
||||
| 36 | `server/src/routes/payment.ts` | + динамический listingFee из PlatformConfig, + type: LISTING_FEE | Готово |
|
||||
| 37 | `server/src/routes/offer.ts` | + создание Commission payment при ACCEPTED | Готово |
|
||||
| 38 | `client/src/types/index.ts` | + role в User, + PENDING_REVIEW, + новые NotificationType, + 5 новых интерфейсов | Готово |
|
||||
| 39 | `client/src/context/AuthContext.tsx` | + isAdmin, isModerator, isSuperAdmin | Готово |
|
||||
| 40 | `client/src/router.tsx` | + /admin/* routes (8 маршрутов) | Готово |
|
||||
| 41 | `client/src/components/layout/Header.tsx` | + ссылка "Admin" с иконкой Shield | Готово |
|
||||
| 42 | `client/src/pages/ProductDetailPage.tsx` | + ReportModal вместо alert() | Готово |
|
||||
| + | `client/src/pages/NotificationsPage.tsx` | + иконки и цвета для 6 новых NotificationType | Готово |
|
||||
|
||||
---
|
||||
|
||||
## Схема БД — новые 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Схема БД — новые модели
|
||||
|
||||
### Report
|
||||
```
|
||||
id, reporterId → User, targetType (LISTING|USER), targetId, reason, description?,
|
||||
status (OPEN→REVIEWING→RESOLVED|DISMISSED), resolvedBy?, resolution?
|
||||
```
|
||||
|
||||
### PlatformConfig (singleton)
|
||||
```
|
||||
listingFee ($5), commissionPercent (5%), autoApprove (true),
|
||||
maxImagesPerListing (6), maxListingsFreeTier (5),
|
||||
proPrice ($9.99), businessPrice ($29.99), promotionDayPrice ($2.99),
|
||||
blockedKeywords []
|
||||
```
|
||||
|
||||
### Subscription
|
||||
```
|
||||
userId (unique) → User, tier (BASIC|PRO|BUSINESS), status,
|
||||
stripeSubscriptionId?, currentPeriodEnd?
|
||||
```
|
||||
|
||||
### PromotedListing
|
||||
```
|
||||
listingId (unique) → Listing, userId → User, startDate, endDate,
|
||||
amountPaid, isActive
|
||||
```
|
||||
|
||||
### ModerationLog
|
||||
```
|
||||
moderatorId → User, targetUserId?, targetListingId?,
|
||||
action (ModerationAction), reason?, details (Json?)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## API Endpoints — полный список
|
||||
|
||||
### Admin Stats
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| GET | `/api/admin/stats` | MODERATOR+ |
|
||||
| GET | `/api/admin/stats/revenue` | ADMIN+ |
|
||||
| GET | `/api/admin/stats/users` | ADMIN+ |
|
||||
| GET | `/api/admin/stats/listings` | MODERATOR+ |
|
||||
|
||||
### Admin Users
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| 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+ |
|
||||
| POST | `/api/admin/users/:id/unban` | ADMIN+ |
|
||||
|
||||
### Admin Listings
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| GET | `/api/admin/listings` | MODERATOR+ |
|
||||
| POST | `/api/admin/listings/:id/approve` | MODERATOR+ |
|
||||
| POST | `/api/admin/listings/:id/reject` | MODERATOR+ |
|
||||
| DELETE | `/api/admin/listings/:id` | ADMIN+ |
|
||||
| POST | `/api/admin/listings/:id/feature` | ADMIN+ |
|
||||
|
||||
### Admin Reports
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| GET | `/api/admin/reports` | MODERATOR+ |
|
||||
| GET | `/api/admin/reports/:id` | MODERATOR+ |
|
||||
| PATCH | `/api/admin/reports/:id` | MODERATOR+ |
|
||||
|
||||
### Admin Moderation
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| GET | `/api/admin/moderation/queue` | MODERATOR+ |
|
||||
| GET | `/api/admin/moderation/logs` | ADMIN+ |
|
||||
|
||||
### Admin Payments
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| GET | `/api/admin/payments` | ADMIN+ |
|
||||
| GET | `/api/admin/payments/revenue` | ADMIN+ |
|
||||
|
||||
### Admin Settings
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| GET | `/api/admin/settings` | ADMIN+ |
|
||||
| PATCH | `/api/admin/settings` | SUPER_ADMIN |
|
||||
|
||||
### User Reports
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| POST | `/api/reports` | Авторизованный |
|
||||
|
||||
### Subscriptions
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| GET | `/api/subscriptions/current` | Авторизованный |
|
||||
| POST | `/api/subscriptions/create` | Авторизованный |
|
||||
| POST | `/api/subscriptions/cancel` | Авторизованный |
|
||||
|
||||
### Promotions
|
||||
| Method | Path | Доступ |
|
||||
|---|---|---|
|
||||
| POST | `/api/listings/:id/promote` | Авторизованный |
|
||||
| GET | `/api/listings/:id/promotion` | Авторизованный |
|
||||
|
||||
---
|
||||
|
||||
## Роли и права
|
||||
|
||||
| Действие | USER | MODERATOR | ADMIN | SUPER_ADMIN |
|
||||
|---|---|---|---|---|
|
||||
| Просмотр дашборда | - | + | + | + |
|
||||
| Просмотр юзеров | - | + | + | + |
|
||||
| Бан/разбан | - | - | + | + |
|
||||
| Смена роли | - | - | - | + |
|
||||
| Approve/Reject листинг | - | + | + | + |
|
||||
| Force delete листинг | - | - | + | + |
|
||||
| Feature листинг | - | - | + | + |
|
||||
| Управление жалобами | - | + | + | + |
|
||||
| Просмотр платежей | - | - | + | + |
|
||||
| Настройки платформы (чтение) | - | - | + | + |
|
||||
| Настройки платформы (запись) | - | - | - | + |
|
||||
| Создание жалобы | + | + | + | + |
|
||||
| Подписки | + | + | + | + |
|
||||
| Продвижение | + | + | + | + |
|
||||
|
||||
---
|
||||
|
||||
## Тестовые данные (seed)
|
||||
|
||||
### Пользователи с ролями
|
||||
| Пользователь | Email | Роль | Пароль |
|
||||
|---|---|---|---|
|
||||
| Alice Chen | alice.chen@example.com | SUPER_ADMIN | password123 |
|
||||
| Bob Martinez | bob.martinez@example.com | ADMIN | password123 |
|
||||
| Carol Nguyen | carol.nguyen@example.com | MODERATOR | password123 |
|
||||
| David Kim | david.kim@example.com | USER | password123 |
|
||||
| Eva Johnson | eva.johnson@example.com | USER | password123 |
|
||||
|
||||
### PlatformConfig (дефолты)
|
||||
- Listing Fee: $5.00
|
||||
- Commission: 5%
|
||||
- Auto-Approve: true (включено)
|
||||
- Max Images: 6
|
||||
- Free Tier Limit: 5 листингов
|
||||
- Pro Price: $9.99/мес
|
||||
- Business Price: $29.99/мес
|
||||
- Promotion Day Price: $2.99
|
||||
- Blocked Keywords: `illegal`, `drugs`, `weapons`
|
||||
|
||||
---
|
||||
|
||||
## Миграция данных — обратная совместимость
|
||||
|
||||
| Поле | Default | Влияние на старые данные |
|
||||
|---|---|---|
|
||||
| `User.role` | `USER` | Все существующие юзеры → USER |
|
||||
| `User.isBanned` | `false` | Никто не затронут |
|
||||
| `ListingStatus.PENDING_REVIEW` | — | Аддитивно, старые данные не ломаются |
|
||||
| `Payment.type` | `LISTING_FEE` | Корректно для всех существующих платежей |
|
||||
| `PlatformConfig.autoApprove` | `true` | Текущее поведение не меняется |
|
||||
|
||||
---
|
||||
|
||||
## Проверка сборки
|
||||
|
||||
| Проверка | Результат |
|
||||
|---|---|
|
||||
| `npx tsc --noEmit` (server) | Без ошибок |
|
||||
| `npx tsc --noEmit` (client) | Без ошибок |
|
||||
| `npm run build --workspace=client` | Успешно (432 KB JS, 47 KB CSS) |
|
||||
| `npx prisma migrate dev` | Миграция применена |
|
||||
| `npx tsx prisma/seed.ts` | Seed выполнен |
|
||||
| Health check `/api/health` | `{"status":"ok"}` |
|
||||
|
||||
---
|
||||
|
||||
## Инструкции по деплою
|
||||
|
||||
```bash
|
||||
# На сервере 173.212.212.157:
|
||||
|
||||
# 1. Обновить код
|
||||
cd /var/www/marketplace-app && git pull
|
||||
|
||||
# 2. Установить зависимости
|
||||
npm install
|
||||
|
||||
# 3. Применить миграцию
|
||||
cd server && npx prisma db push
|
||||
|
||||
# 4. Обновить seed (опционально)
|
||||
npx tsx prisma/seed.ts
|
||||
|
||||
# 5. Собрать клиент
|
||||
cd .. && npm run build --workspace=client
|
||||
|
||||
# 6. Скопировать билд
|
||||
cp -r client/dist/* /var/www/marketplace/
|
||||
|
||||
# 7. Перезапустить сервер
|
||||
pm2 restart marketplace-api
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Верификация на проде
|
||||
|
||||
1. Логин как `alice.chen@example.com` (SUPER_ADMIN) → в хедере видна ссылка "Admin"
|
||||
2. `/admin` → дашборд с 5 метриками
|
||||
3. `/admin/users` → таблица юзеров с ролями и статусами
|
||||
4. `/admin/users/:id` → детали юзера, бан david → логин как david → 403
|
||||
5. Разбанить david → логин работает
|
||||
6. `/admin/settings` → отключить autoApprove
|
||||
7. Создать листинг → статус PENDING_REVIEW
|
||||
8. `/admin/moderation` → approve → листинг активен
|
||||
9. На странице товара → Report → модалка → отправить
|
||||
10. `/admin/reports` → resolve жалобу
|
||||
11. `/admin/payments` → транзакции по типам
|
||||
12. `/admin/settings` → изменить listing fee → проверить
|
||||
274
отчеты/план-админ-модерация-монетизация.md
Normal file
274
отчеты/план-админ-модерация-монетизация.md
Normal file
@@ -0,0 +1,274 @@
|
||||
# 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-операции + приоритетная поддержка
|
||||
|
||||
---
|
||||
|
||||
## Деплой
|
||||
|
||||
```bash
|
||||
# 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
|
||||
93
отчеты/список-файлов.md
Normal file
93
отчеты/список-файлов.md
Normal file
@@ -0,0 +1,93 @@
|
||||
# Полный список файлов — Админ-панель, Модерация, Монетизация
|
||||
|
||||
## Новые серверные файлы (16)
|
||||
|
||||
```
|
||||
server/src/middleware/requireRole.ts — RBAC middleware
|
||||
server/src/middleware/checkBanned.ts — Проверка бана
|
||||
server/src/utils/moderation.ts — Кэш конфига + keyword check
|
||||
server/src/routes/admin/index.ts — Агрегатор админ-роутов
|
||||
server/src/routes/admin/stats.ts — Аналитика дашборда
|
||||
server/src/routes/admin/users.ts — Управление юзерами
|
||||
server/src/routes/admin/listings.ts — Управление листингами
|
||||
server/src/routes/admin/reports.ts — Управление жалобами
|
||||
server/src/routes/admin/moderation.ts — Очередь модерации
|
||||
server/src/routes/admin/payments.ts — Платежи и выручка
|
||||
server/src/routes/admin/settings.ts — Настройки платформы
|
||||
server/src/routes/report.ts — Создание жалобы (юзер)
|
||||
server/src/routes/subscription.ts — Подписки
|
||||
server/src/routes/promotion.ts — Продвижение листингов
|
||||
server/src/validators/admin.ts — Zod-схемы для админки
|
||||
server/src/validators/report.ts — Zod-схема жалобы
|
||||
```
|
||||
|
||||
## Новые клиентские файлы (13)
|
||||
|
||||
```
|
||||
client/src/components/layout/RequireRole.tsx — Route guard по роли
|
||||
client/src/components/layout/AdminLayout.tsx — Sidebar-layout админки
|
||||
client/src/components/ui/StatCard.tsx — Карточка метрики
|
||||
client/src/components/ui/DataTable.tsx — Таблица с пагинацией
|
||||
client/src/components/ReportModal.tsx — Модалка жалобы
|
||||
client/src/pages/admin/AdminDashboardPage.tsx — Дашборд
|
||||
client/src/pages/admin/AdminUsersPage.tsx — Юзеры
|
||||
client/src/pages/admin/AdminUserDetailPage.tsx — Детали юзера
|
||||
client/src/pages/admin/AdminListingsPage.tsx — Листинги
|
||||
client/src/pages/admin/AdminReportsPage.tsx — Жалобы
|
||||
client/src/pages/admin/AdminModerationPage.tsx — Очередь модерации
|
||||
client/src/pages/admin/AdminPaymentsPage.tsx — Платежи
|
||||
client/src/pages/admin/AdminSettingsPage.tsx — Настройки
|
||||
```
|
||||
|
||||
## Модифицированные файлы (13)
|
||||
|
||||
```
|
||||
server/prisma/schema.prisma — 8 enum + 6 моделей + расширение 3 моделей
|
||||
server/prisma/seed.ts — PlatformConfig + роли + cleanup
|
||||
server/src/index.ts — 4 новых route group
|
||||
server/src/middleware/auth.ts — userRole в Request
|
||||
server/src/routes/auth.ts — role в select + isBanned check
|
||||
server/src/routes/listing.ts — autoApprove + keywords + isFeatured
|
||||
server/src/routes/payment.ts — динамический listingFee
|
||||
server/src/routes/offer.ts — commission при accept
|
||||
client/src/types/index.ts — role + новые типы
|
||||
client/src/context/AuthContext.tsx — isAdmin/isModerator/isSuperAdmin
|
||||
client/src/router.tsx — /admin/* routes
|
||||
client/src/components/layout/Header.tsx — ссылка Admin
|
||||
client/src/pages/ProductDetailPage.tsx — ReportModal
|
||||
client/src/pages/NotificationsPage.tsx — новые notification types
|
||||
```
|
||||
|
||||
## Итого
|
||||
|
||||
- **29 новых файлов**
|
||||
- **13+1 изменённых файлов**
|
||||
- **43 файла** затронуто
|
||||
|
||||
## Структура папки admin routes
|
||||
|
||||
```
|
||||
server/src/routes/admin/
|
||||
├── index.ts — authenticate + mount sub-routers
|
||||
├── stats.ts — GET /stats, /stats/revenue, /stats/users, /stats/listings
|
||||
├── users.ts — GET/PATCH/POST users, ban, unban, role
|
||||
├── listings.ts — GET listings, approve, reject, delete, feature
|
||||
├── reports.ts — GET/PATCH reports
|
||||
├── moderation.ts — GET queue, GET logs
|
||||
├── payments.ts — GET payments, GET revenue
|
||||
└── settings.ts — GET/PATCH settings
|
||||
```
|
||||
|
||||
## Структура папки admin pages
|
||||
|
||||
```
|
||||
client/src/pages/admin/
|
||||
├── AdminDashboardPage.tsx
|
||||
├── AdminUsersPage.tsx
|
||||
├── AdminUserDetailPage.tsx
|
||||
├── AdminListingsPage.tsx
|
||||
├── AdminReportsPage.tsx
|
||||
├── AdminModerationPage.tsx
|
||||
├── AdminPaymentsPage.tsx
|
||||
└── AdminSettingsPage.tsx
|
||||
```
|
||||
Reference in New Issue
Block a user