laravel-12-tech-specs/task09-book-exchange.md

19 KiB
Raw Blame History

Техническое задание: Платформа для обмена книгами (Book Exchange)

1. Описание проекта

Веб-сервис для обмена книгами между пользователями с системой Wishlist, обменными предложениями и отзывами. Проект закрепляет навыки CRUD, статусных переходов, работы с отношениями многие-ко-многим, разграничения прав и совместной работы через Git.

Команда: 23 человека


2. Функциональные требования

2.1. Аутентификация и регистрация

  • Регистрация, вход, выход (Laravel Breeze)

2.2. Каталог книг

  • Просмотр списка доступных для обмена книг с пагинацией
  • Фильтрация по жанрам/категориям
  • Поиск по названию, автору, ISBN
  • Детальная страница книги (обложка, описание, владелец, состояние, кнопка «Предложить обмен»)

2.3. Управление книгами (владелец)

  • CRUD книг: название, автор, ISBN, описание, жанр, обложка, состояние (новая, хорошая, удовлетворительная)
  • Загрузка обложки книги (валидация: jpg/png, макс. 2MB)
  • Статус книги: доступна для обмена / зарезервирована / обмен состоялась
  • Мои книги (личный кабинет владельца)

2.4. Wishlist (список желаемого)

  • Добавление книг в wishlist: название, автор (свободный ввод)
  • Уведомление владельцу книги из wishlist, если кто-то её добавил
  • Страница «Мой Wishlist»

2.5. Обменные предложения

  • Пользователь создаёт предложение обмена: книга владельца → книга взамен (из книг отправителя) + комментарий
  • Статусы обмена: предложено, принято, отклонено, завершено, отменено
  • Владелец книги принимает или отклоняет предложение
  • При принятии — обе книги получают статус «обмен состоялась»
  • При отмене — возврат статусов «доступна для обмена»
  • Отзывы после завершения обмена

2.6. Отзывы об обмене

  • Оба участника оставляют отзыв друг другу после завершения обмена
  • Поля отзыва: текст, рейтинг (15 звёзд)
  • Средний рейтинг пользователя
  • Отзывы на странице профиля

2.7. Панель пользователя

  • Мои книги (созданные мной)
  • Мои обменные предложения (отправленные и полученные)
  • Мой Wishlist
  • Мои отзывы (полученные и оставленные)
  • Профиль и рейтинг

2.8. Панель администратора

  • Управление пользователями и ролями
  • Модерация книг и отзывов
  • Общая статистика платформы

3. Структура базы данных

Таблица users

Поле Тип Описание
id BIGINT UNSIGNED Первичный ключ
name VARCHAR(255) Имя
email VARCHAR(255) Email (unique)
password VARCHAR(255) Хеш пароля
role ENUM('admin', 'owner', 'requester') Роль
avatar VARCHAR(255) | NULL Аватар
rating DECIMAL(3, 2) | NULL Средний рейтинг (0.005.00)
created_at TIMESTAMP
updated_at TIMESTAMP

Таблица genres

Поле Тип Описание
id BIGINT UNSIGNED Первичный ключ
name VARCHAR(255) Название жанра
slug VARCHAR(255) URL-идентификатор (unique)
created_at TIMESTAMP
updated_at TIMESTAMP

Таблица books

Поле Тип Описание
id BIGINT UNSIGNED Первичный ключ
title VARCHAR(255) Название книги
author VARCHAR(255) Автор
isbn VARCHAR(20) | NULL ISBN
description TEXT | NULL Описание
cover_image VARCHAR(255) | NULL Обложка
genre_id BIGINT UNSIGNED Жанр (FK → genres)
owner_id BIGINT UNSIGNED Владелец (FK → users)
condition ENUM('new', 'good', 'fair') Состояние
status ENUM('available', 'reserved', 'exchanged') Статус
created_at TIMESTAMP
updated_at TIMESTAMP

Таблица wishlists

Поле Тип Описание
id BIGINT UNSIGNED Первичный ключ
user_id BIGINT UNSIGNED FK → users
title VARCHAR(255) Желаемая книга (название)
author VARCHAR(255) | NULL Желаемый автор
created_at TIMESTAMP
updated_at TIMESTAMP

Таблица exchange_offers

Поле Тип Описание
id BIGINT UNSIGNED Первичный ключ
requester_id BIGINT UNSIGNED Инициатор обмена (FK → users)
owner_book_id BIGINT UNSIGNED Книга владельца (FK → books)
offered_book_id BIGINT UNSIGNED Предлагаемая книга взамен (FK → books)
message TEXT | NULL Комментарий инициатора
status ENUM('proposed', 'accepted', 'rejected', 'completed', 'cancelled') Статус
response_message TEXT | NULL Ответ владельца
created_at TIMESTAMP
updated_at TIMESTAMP

Таблица reviews

Поле Тип Описание
id BIGINT UNSIGNED Первичный ключ
exchange_offer_id BIGINT UNSIGNED Связанный обмен (FK → exchange_offers)
author_id BIGINT UNSIGNED Автор отзыва (FK → users)
target_user_id BIGINT UNSIGNED Получатель отзыва (FK → users)
rating TINYINT Рейтинг (15)
comment TEXT Текст отзыва
created_at TIMESTAMP
updated_at TIMESTAMP

4. Маршруты и контроллеры

// Публичные маршруты
Route::get('/', [BookController::class, 'index'])->name('books.index');
Route::get('/books/{book}', [BookController::class, 'show'])->name('books.show');

// Аутентифицированные маршруты
Route::middleware('auth')->group(function () {
    // Wishlist
    Route::resource('wishlist', WishlistController::class);

    // Обменные предложения
    Route::prefix('exchanges')->name('exchanges.')->group(function () {
        Route::post('/offer/{book}', [ExchangeController::class, 'store'])->name('offer');
        Route::get('/sent', [ExchangeController::class, 'sent'])->name('sent');
        Route::get('/received', [ExchangeController::class, 'received'])->name('received');
        Route::get('/{exchange}', [ExchangeController::class, 'show'])->name('show');
        Route::post('/{exchange}/accept', [ExchangeController::class, 'accept'])->name('accept');
        Route::post('/{exchange}/reject', [ExchangeController::class, 'reject'])->name('reject');
        Route::post('/{exchange}/complete', [ExchangeController::class, 'complete'])->name('complete');
        Route::post('/{exchange}/cancel', [ExchangeController::class, 'cancel'])->name('cancel');
    });

    // Отзывы
    Route::resource('reviews', ReviewController::class)->only(['store', 'destroy']);

    // Мои книги (владелец)
    Route::prefix('my-books')->name('my-books.')->group(function () {
        Route::resource('books', BookController::class);
        Route::get('dashboard', [DashboardController::class, 'index'])->name('dashboard');
    });

    // Админка
    Route::prefix('admin')->name('admin.')->middleware('can:access-admin-panel')->group(function () {
        Route::resource('users', AdminUserController::class);
        Route::resource('genres', AdminGenreController::class);
        Route::patch('books/{book}/toggle-status', [AdminBookController::class, 'toggleStatus'])->name('books.status');
        Route::patch('reviews/{review}/toggle-publish', [AdminReviewController::class, 'togglePublish'])->name('reviews.publish');
        Route::get('dashboard', [AdminDashboardController::class, 'index'])->name('dashboard');
    });
});

Контроллеры

  • BookController — публичный каталог + CRUD книг для владельца
  • WishlistController — CRUD желаемых книг
  • ExchangeController — создание и управление обменными предложениями
  • ReviewController — создание/удаление отзывов
  • DashboardController — панель пользователя
  • AdminUserController, AdminGenreController, AdminBookController, AdminReviewController, AdminDashboardController — админка

5. Роли, Gates и Policies

Роли

Роль Описание
admin Полный доступ, модерация книг и отзывов, управление пользователями
owner Добавление книг, управление обменными предложениями, подтверждение обмена
requester Просмотр каталога, создание запросов на обмен, Wishlist

Примечание: при регистрации пользователь получает обе роли owner и requester (фактически — роль user). Разделение логическое, а не через middleware.

Gates

Gate::define('access-admin-panel', function (User $user) {
    return $user->role === 'admin';
});

Policies

BookPolicy:

  • view — все (публичный каталог)
  • create — все аутентифицированные
  • update, delete — владелец книги или admin
  • offer — не владелец этой книги (и не предлагает свою же)

ExchangeOfferPolicy:

  • create — все аутентифицированные (не владелец целевой книги)
  • view — инициатор, владелец книги или admin
  • accept, reject — владелец целевой книги
  • complete, cancel — инициатор или владелец (до завершения)

WishlistPolicy:

  • create, update, delete — владелец wishlist или admin
  • view — только владелец wishlist

ReviewPolicy:

  • create — участник завершённого обмена (ещё не оставил отзыв)
  • view — все (если опубликован), автор или admin (если не опубликован)
  • delete — автор отзыва или admin

6. Требования к интерфейсу (Bootstrap 5)

Компоненты

  • Навбар — логотип, каталог, «Мои книги», «Обмены», «Wishlist», профиль
  • Карточки книг — обложка, название, автор, жанр (бейдж), состояние (бейдж), владелец
  • Страница книги — большая обложка, описание, автор, ISBN, состояние, кнопка «Предложить обмен»
  • Форма обменного предложения — выбор своей книги взамен (dropdown), комментарий
  • Таблица обменных предложений — книги, статус (цветные бейджи), действия
  • Звёздный рейтинг — для отзывов
  • Wishlist — список желаемых книг (таблица/карточки)
  • Дашборд — статистика (карточки), активные обмены, wishlist-совпадения
  • Адаптивная сеткаcol-md-4 для карточек, col-md-8 + col-md-4 для основного контента

Цветовая схема статусов обмена

  • Предложено — bg-info
  • Принято — bg-success
  • Отклонено — bg-danger
  • Завершено — bg-primary
  • Отменено — bg-secondary

Цветовая схема состояния книги

  • Новая — bg-success
  • Хорошая — bg-primary
  • Удовлетворительная — bg-warning

7. Git-workflow для команды

Распределение модулей (для 2 человек)

Участник Модуль Ветки
Участник A Книги, жанры, обложки, обменные предложения feature/books-crud, feature-genres, feature-book-covers
Участник B Wishlist, отзывы, рейтинги, дашборд, UI feature-exchange-offers, feature-offer-statuses, feature-offer-validation

Распределение модулей (для 3 человек)

Участник Модуль Ветки
Участник A Книги, жанры, загрузка обложек, каталог feature/books-crud, feature-genres, feature-book-covers
Участник B Обменные предложения, статусы, валидация feature-exchange-offers, feature-offer-statuses, feature-offer-validation
Участник C Wishlist, отзывы, рейтинги, UI, дашборд feature-wishlist, feature-reviews, feature-dashboard-ui

Правила

  1. Ветка develop — основная ветка разработки
  2. Каждый участник создаёт фич-ветки от develop
  3. Минимум 3 PR на участника
  4. Обязательный код-ревью перед мёржем
  5. Conventional Commits

Визуализация workflow (2 участника)

gitGraph
   commit id: "init" tag: "v1.0"
   branch develop
   checkout develop
   branch feature/books-crud
   checkout develop
   branch feature-exchange-offers
   checkout feature/books-crud
   commit id: "feat: add books CRUD"
   commit id: "feat: add book covers"
   checkout feature-exchange-offers
   commit id: "feat: add exchange offers"
   commit id: "feat: add offer statuses"
   checkout develop
   merge feature/books-crud tag: "PR + review"
   merge feature-exchange-offers tag: "PR + review"
   checkout main
   merge develop tag: "release v1.1"

Визуализация workflow (3 участника)

gitGraph
   commit id: "init" tag: "v1.0"
   branch develop
   checkout develop
   branch feature/books-crud
   checkout develop
   branch feature-exchange-offers
   checkout develop
   branch feature-wishlist
   checkout feature/books-crud
   commit id: "feat: add books CRUD"
   commit id: "feat: add genres CRUD"
   checkout feature-exchange-offers
   commit id: "feat: add exchange offers"
   commit id: "feat: add offer statuses"
   checkout feature-wishlist
   commit id: "feat: add wishlist CRUD"
   commit id: "feat: add reviews system"
   checkout develop
   merge feature/books-crud tag: "PR + review"
   merge feature-exchange-offers tag: "PR + review"
   merge feature-wishlist tag: "PR + review"
   checkout main
   merge develop tag: "release v1.1"

8. Критерии приёмки

Обязательно

  • CRUD книг с загрузкой обложек
  • CRUD жанров
  • Каталог книг с пагинацией и фильтрацией по жанрам
  • Wishlist (добавление, просмотр, удаление)
  • Создание обменного предложения (книга владельца → книга взамен)
  • Принятие/отклонение предложения владельцем
  • При принятии — обновление статусов обеих книг на «exchanged»
  • При отмене — возврат статусов «available»
  • Отзывы после завершения обмена (оба участника)
  • Расчёт среднего рейтинга пользователя
  • Policies: пользователь не может управлять чужими книгами и предложениями
  • Адаптивная Bootstrap-вёрстка
  • Flash-сообщения
  • Git-история: минимум 3 ветки на участника, PR с ревью

Дополнительно (бонусные баллы)

  • Поиск книг по названию, автору, ISBN
  • Уведомления владельцу книги из wishlist
  • Уведомления (email при новом предложении / ответе)
  • Рекомендации книг (по жанру, wishlist)
  • Мягкое удаление книг и отзывов
  • Тесты: PHPUnit Feature-тесты для ExchangeController
  • API: RESTful API для каталога книг

9. Дополнительные задания (для продвинутых)

  1. Уведомления: email и on-site уведомления при новых предложениях, ответах, wishlist-совпадениях
  2. Совпадения Wishlist: автоматическое определение, когда книга одного пользователя есть в wishlist другого
  3. Множественный обмен: предложение нескольких книг взамен
  4. Тесты: PHPUnit Feature-тесты для ExchangeController (статусные переходы)
  5. API: RESTful API для каталога и создания предложений
  6. Queue: асинхронная отправка email-уведомлений
  7. Events & Listeners: событие «обмен завершён» → напоминание оставить отзыв

10. Рекомендуемые материалы