From d86abfe4693c2cd75fa9b8a4e53a278b4f0f4bb2 Mon Sep 17 00:00:00 2001 From: MadHowl Date: Wed, 8 Apr 2026 04:59:08 +0000 Subject: [PATCH] =?UTF-8?q?=D0=97=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20=D1=84=D0=B0=D0=B9=D0=BB=D1=8B=20=D0=B2=20=C2=AB?= =?UTF-8?q?/=C2=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- task01-task-manager.md | 336 ++++++++++++++++++++++++++++ task02-online-store.md | 376 +++++++++++++++++++++++++++++++ task03-online-courses.md | 410 ++++++++++++++++++++++++++++++++++ task04-booking-system.md | 337 ++++++++++++++++++++++++++++ task05-freelance-portfolio.md | 384 +++++++++++++++++++++++++++++++ 5 files changed, 1843 insertions(+) create mode 100644 task01-task-manager.md create mode 100644 task02-online-store.md create mode 100644 task03-online-courses.md create mode 100644 task04-booking-system.md create mode 100644 task05-freelance-portfolio.md diff --git a/task01-task-manager.md b/task01-task-manager.md new file mode 100644 index 0000000..6df9ac8 --- /dev/null +++ b/task01-task-manager.md @@ -0,0 +1,336 @@ +# Техническое задание: Система управления задачами (Task Manager) + +## 1. Описание проекта + +Веб-приложение для управления личными и командными задачами с возможностью назначения исполнителей, отслеживания статусаов и приоритетов. Проект закрепляет навыки CRUD, разграничения прав через Roles/Gates/Policies, совместной работы через Git. + +**Команда:** 2–3 человека + +--- + +## 2. Функциональные требования + +### 2.1. Аутентификация и регистрация +- Регистрация, вход, выход (Laravel Breeze) +- Восстановление пароля (опционально) + +### 2.2. Управление задачами +- Создание, просмотр, редактирование, удаление задач +- Поля задачи: название, описание, статус (новая, в работе, завершена), приоритет (низкий, средний, высокий, критический), дедлайн, исполнитель, автор +- Назначение исполнителя из списка пользователей +- Добавление комментариев к задаче +- Фильтрация по статусу, приоритету, исполнителю +- Сортировка по дате создания, приоритету, дедлайну +- Пагинация списка задач + +### 2.3. Управление проектами +- Создание проектов (группировка задач) +- Привязка задач к проекту +- CRUD проектов + +### 2.4. Панель администратора +- Управление пользователями (просмотр, блокировка, назначение ролей) +- Просмотр статистики (количество задач, проектов, пользователей) + +### 2.5. Дашборд пользователя +- Мои задачи (назначенные мне) +- Созданные мной задачи +- Просроченные задачи +- Быстрая смена статуса + +--- + +## 3. Структура базы данных + +### Таблица `users` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Имя | +| email | VARCHAR(255) | Email (unique) | +| password | VARCHAR(255) | Хеш пароля | +| role | ENUM('admin', 'manager', 'executor') | Роль | +| is_blocked | BOOLEAN | Заблокирован ли | +| created_at | TIMESTAMP | Дата создания | +| updated_at | TIMESTAMP | Дата обновления | + +### Таблица `projects` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Название проекта | +| description | TEXT | Описание | +| user_id | BIGINT UNSIGNED | Автор проекта (FK → users) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `tasks` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| title | VARCHAR(255) | Название задачи | +| description | TEXT | Описание | +| status | ENUM('new', 'in_progress', 'completed', 'cancelled') | Статус | +| priority | ENUM('low', 'medium', 'high', 'critical') | Приоритет | +| due_date | DATE | Дедлайн | +| author_id | BIGINT UNSIGNED | Автор (FK → users) | +| assignee_id | BIGINT UNSIGNED \| NULL | Исполнитель (FK → users) | +| project_id | BIGINT UNSIGNED \| NULL | Проект (FK → projects) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `comments` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| body | TEXT | Текст комментария | +| user_id | BIGINT UNSIGNED | Автор комментария (FK → users) | +| task_id | BIGINT UNSIGNED | Задача (FK → tasks) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +--- + +## 4. Маршруты и контроллеры + +### Route группы + +```php +// Публичные маршруты +Route::get('/', [DashboardController::class, 'index'])->name('dashboard'); + +// Аутентифицированные маршруты +Route::middleware('auth')->group(function () { + // Задачи + Route::resource('tasks', TaskController::class); + Route::patch('tasks/{task}/status', [TaskController::class, 'updateStatus'])->name('tasks.status'); + + // Комментарии + Route::resource('tasks.comments', CommentController::class)->scoped(['tasks' => 'task']); + + // Проекты + Route::resource('projects', ProjectController::class); + + // Админка + Route::prefix('admin')->name('admin.')->group(function () { + Route::resource('users', AdminUserController::class); + Route::patch('users/{user}/block', [AdminUserController::class, 'toggleBlock'])->name('users.block'); + Route::patch('users/{user}/role', [AdminUserController::class, 'changeRole'])->name('users.role'); + }); +}); +``` + +### Контроллеры +- `TaskController` — CRUD задач + обновление статуса +- `CommentController` — CRUD комментариев (только создание и удаление) +- `ProjectController` — CRUD проектов +- `AdminUserController` — управление пользователями (только admin) +- `DashboardController` — дашборд с фильтрами + +--- + +## 5. Роли, Gates и Policies + +### Роли +| Роль | Описание | +|---|---| +| `admin` | Полный доступ ко всему | +| `manager` | Создание/редактирование проектов и задач, назначение исполнителей | +| `executor` | Просмотр назначенных задач, изменение статуса, комментарии | + +### Gates (в `AuthServiceProvider`) + +```php +Gate::define('access-admin-panel', function (User $user) { + return $user->role === 'admin'; +}); + +Gate::define('assign-tasks', function (User $user) { + return in_array($user->role, ['admin', 'manager']); +}); + +Gate::define('manage-projects', function (User $user) { + return in_array($user->role, ['admin', 'manager']); +}); +``` + +### Policies + +**TaskPolicy:** +- `view` — может видеть задачу, если автор или исполнитель, или имеет роль admin/manager +- `update` — автор, назначенный исполнитель (только статус), admin, manager +- `delete` — только автор задачи или admin +- `assign` — только admin или manager + +**ProjectPolicy:** +- `view` — все аутентифицированные +- `update`, `delete` — автор проекта или admin + +**CommentPolicy:** +- `create` — все аутентифицированные +- `delete` — автор комментария или admin + +--- + +## 6. Требования к интерфейсу (Bootstrap 5) + +### Компоненты +- **Навбар** — логотип, навигация, профиль пользователя +- **Карточки задач** — заголовок, бейджи статуса/приоритета, дедлайн, исполнитель +- **Таблица списка задач** — с сортировкой, фильтрами, пагинацией +- **Модальное окно** — быстрое создание/редактирование задачи +- **Формы** — валидация на клиенте и сервере, Bootstrap-классы `is-invalid` +- **Алерты** — flash-сообщения об успехе/ошибке (`alert-success`, `alert-danger`) +- **Дашборд** — сетка Bootstrap (`row`, `col-md-*`) с карточками статистики +- **Бейджи** — цветные индикаторы статуса и приоритета + +### Цветовая схема статусов +- Новая — `bg-info` +- В работе — `bg-warning` +- Завершена — `bg-success` +- Отменена — `bg-secondary` + +### Цветовая схема приоритетов +- Низкий — `bg-light text-dark` +- Средний — `bg-primary` +- Высокий — `bg-warning` +- Критический — `bg-danger` + +--- + +## 7. Git-workflow для команды + +### Распределение модулей (для 2 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Аутентификация, пользователи, админка, задачи | `feature/auth-users`, `feature/tasks-crud` | +| **Участник B** | Проекты, комментарии, дашборд, UI | `feature/projects-crud`, `feature-task-comments` | + +### Распределение модулей (для 3 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Аутентификация, пользователи, админка | `feature/auth-users`, `feature/admin-panel` | +| **Участник B** | Задачи, комментарии, фильтры | `feature/tasks-crud`, `feature/task-comments` | +| **Участник C** | Проекты, дашборд, UI | `feature/projects-crud`, `feature/dashboard-ui` | + +### Правила +1. Каждый участник работает в своей фич-ветке от `develop` +2. Перед мёржем в `develop` — Pull Request с код-ревью от другого участника +3. Минимум 3 PR на каждого участника за проект +4. Коммиты по Conventional Commits: `feat:`, `fix:`, `refactor:`, `docs:` +5. `main` — защищённая ветка, мёрж только из `develop` + +### Визуализация workflow (2 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/auth-users + checkout develop + branch feature/projects-crud + checkout feature/auth-users + commit id: "feat: add registration and login" + commit id: "feat: add admin panel" + checkout feature/projects-crud + commit id: "feat: add projects CRUD" + commit id: "feat: add comments to tasks" + checkout develop + merge feature/auth-users tag: "PR + review" + merge feature/projects-crud tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +### Визуализация workflow (3 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/auth-users + checkout develop + branch feature/tasks-crud + checkout develop + branch feature/projects-crud + checkout feature/auth-users + commit id: "feat: add auth + admin panel" + commit id: "feat: add user management" + checkout feature/tasks-crud + commit id: "feat: add task CRUD" + commit id: "feat: add task filters" + checkout feature/projects-crud + commit id: "feat: add projects CRUD" + commit id: "feat: add dashboard UI" + checkout develop + merge feature/auth-users tag: "PR + review" + merge feature/tasks-crud tag: "PR + review" + merge feature/projects-crud tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +### Пример командной работы +```bash +# Создание фич-ветки +git checkout develop +git checkout -b feature/tasks-crud + +# После разработки +git add . +git commit -m "feat: add task CRUD with validation" +git push origin feature/tasks-crud + +# Создание Pull Request через GitHub/GitLab +# Код-ревью от другого участника → Approve → Merge +``` + +--- + +## 8. Критерии приёмки + +### Обязательно +- [ ] Регистрация и вход работают +- [ ] CRUD задач с валидацией (название обязательно, дедлайн — дата) +- [ ] CRUD проектов +- [ ] Комментарии к задачам (создание + удаление) +- [ ] Фильтрация задач по статусу и приоритету +- [ ] Роли работают: executor не может удалять чужие задачи +- [ ] Policies корректно ограничивают доступ +- [ ] Admin-панель доступна только admin +- [ ] Bootstrap-вёрстка адаптивная (проверка на мобильном) +- [ ] Flash-сообщения при создании/редактировании/удалении +- [ ] Пагинация списка задач +- [ ] Git-история: минимум 3 ветки от каждого участника, слитые через PR + +### Дополнительно (бонусные баллы) +- [ ] Drag-and-drop для смены статуса задач (kanban-доска) +- [ ] Уведомления (email при назначении задачи) +- [ ] Экспорт задач в CSV +- [ ] Поиск задач по названию/описанию +- [ ] Прикрепление файлов к задачам + +--- + +## 9. Дополнительные задания (для продвинутых) + +1. **Kanban-доска:** визуальное отображение задач по колонкам (новая, в работе, завершена) с drag-and-drop +2. **Уведомления:** отправка email при назначении задачи или изменении статуса +3. **API:** RESTful API для задач (resource-маршруты с JSON-ответами) +4. **Тесты:** PHPUnit Feature-тесты для TaskController (минимум 5 тестов) +5. **Queues:** асинхронная отправка уведомлений через очереди Laravel +6. **Soft Deletes:** мягкое удаление задач и проектов + +--- + +## 10. Рекомендуемые материалы + +- Laravel Docs: https://laravel.com/docs/12.x +- Laravel Authorization (Gates & Policies): https://laravel.com/docs/12.x/authorization +- Bootstrap 5 Documentation: https://getbootstrap.com/docs/5.3 +- Git Flow: https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow +- Conventional Commits: https://www.conventionalcommits.org/ diff --git a/task02-online-store.md b/task02-online-store.md new file mode 100644 index 0000000..3d29367 --- /dev/null +++ b/task02-online-store.md @@ -0,0 +1,376 @@ +# Техническое задание: Онлайн-магазин с корзиной + +## 1. Описание проекта + +Веб-приложение интернет-магазина с каталогом товаров, корзиной покупок и оформлением заказов. Проект закрепляет навыки CRUD, работы с отношениями многие-ко-многим, загрузки изображений, разграничения прав и совместной работы через Git. + +**Команда:** 2–3 человека + +--- + +## 2. Функциональные требования + +### 2.1. Аутентификация и регистрация +- Регистрация, вход, выход (Laravel Breeze) +- Восстановление пароля (опционально) + +### 2.2. Каталог товаров +- Просмотр списка товаров с пагинацией +- Детальная страница товара +- Фильтрация по категориям +- Поиск по названию и описанию +- Сортировка по цене, дате добавления, названию + +### 2.3. Управление товарами (админка) +- CRUD товаров: название, описание, цена, изображение, количество на складе, наличие +- CRUD категорий товаров +- Загрузка изображений товаров (валидация: jpg/png, макс. 2MB) +- Привязка товара к нескольким категориям + +### 2.4. Корзина +- Добавление товара в корзину (количество) +- Изменение количества в корзине +- Удаление позиции из корзины +- Отображение итоговой суммы +- Корзина сохраняется в сессии (для гостей) или в БД (для авторизованных) + +### 2.5. Оформление заказа +- Форма оформления заказа: имя, телефон, email, адрес доставки, комментарий +- Перенос позиций корзины в заказ +- Очистка корзины после оформления +- Просмотр своих заказов (покупатель) + +### 2.6. Управление заказами (админка) +- Просмотр списка всех заказов +- Изменение статуса заказа (новый, в обработке, отправлен, доставлен, отменён) +- Детали заказа (список товаров, сумма, данные покупателя) + +### 2.7. Дашборд администратора +- Статистика: количество товаров, заказов, пользователей +- Последние заказы +- Товары, заканчивающиеся на складе + +--- + +## 3. Структура базы данных + +### Таблица `users` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Имя | +| email | VARCHAR(255) | Email (unique) | +| password | VARCHAR(255) | Хеш пароля | +| role | ENUM('admin', 'order_manager', 'customer') | Роль | +| phone | VARCHAR(20) \| NULL | Телефон | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `categories` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Название категории | +| slug | VARCHAR(255) | URL-идентификатор (unique) | +| description | TEXT \| NULL | Описание | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `products` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Название товара | +| slug | VARCHAR(255) | URL-идентификатор (unique) | +| description | TEXT | Описание | +| price | DECIMAL(10, 2) | Цена | +| image | VARCHAR(255) \| NULL | Путь к изображению | +| stock_quantity | INT | Количество на складе | +| is_available | BOOLEAN | Доступен для покупки | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `category_product` (многие-ко-многим) +| Поле | Тип | Описание | +|---|---|---| +| category_id | BIGINT UNSIGNED | FK → categories | +| product_id | BIGINT UNSIGNED | FK → products | + +### Таблица `carts` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| user_id | BIGINT UNSIGNED \| NULL | Пользователь (FK → users), NULL для гостей | +| session_id | VARCHAR(255) \| NULL | ID сессии для гостей | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `cart_items` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| cart_id | BIGINT UNSIGNED | FK → carts | +| product_id | BIGINT UNSIGNED | FK → products | +| quantity | INT | Количество | + +### Таблица `orders` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| user_id | BIGINT UNSIGNED \| NULL | Покупатель (FK → users) | +| total_amount | DECIMAL(10, 2) | Итоговая сумма | +| status | ENUM('new', 'processing', 'shipped', 'delivered', 'cancelled') | Статус | +| customer_name | VARCHAR(255) | Имя получателя | +| customer_phone | VARCHAR(20) | Телефон | +| customer_email | VARCHAR(255) | Email | +| shipping_address | TEXT | Адрес доставки | +| comment | TEXT \| NULL | Комментарий | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `order_items` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| order_id | BIGINT UNSIGNED | FK → orders | +| product_id | BIGINT UNSIGNED | FK → products | +| quantity | INT | Количество | +| price | DECIMAL(10, 2) | Цена на момент заказа | + +--- + +## 4. Маршруты и контроллеры + +```php +// Публичные маршруты +Route::get('/', [ProductController::class, 'index'])->name('home'); +Route::get('/products/{product:slug}', [ProductController::class, 'show'])->name('products.show'); + +// Корзина +Route::prefix('cart')->name('cart.')->group(function () { + Route::get('/', [CartController::class, 'index'])->name('index'); + Route::post('/add/{product}', [CartController::class, 'add'])->name('add'); + Route::patch('/update/{cartItem}', [CartController::class, 'update'])->name('update'); + Route::delete('/remove/{cartItem}', [CartController::class, 'remove'])->name('remove'); +}); + +// Аутентифицированные маршруты +Route::middleware('auth')->group(function () { + // Оформление заказа + Route::get('/checkout', [OrderController::class, 'create'])->name('checkout'); + Route::post('/checkout', [OrderController::class, 'store'])->name('checkout.store'); + Route::get('/my-orders', [OrderController::class, 'myOrders'])->name('orders.my'); + Route::get('/my-orders/{order}', [OrderController::class, 'show'])->name('orders.show'); + + // Админка + Route::prefix('admin')->name('admin.')->middleware('can:access-admin-panel')->group(function () { + Route::resource('products', AdminProductController::class); + Route::resource('categories', AdminCategoryController::class); + Route::resource('orders', AdminOrderController::class)->only(['index', 'show', 'update']); + Route::patch('orders/{order}/status', [AdminOrderController::class, 'updateStatus'])->name('orders.status'); + Route::get('dashboard', [AdminDashboardController::class, 'index'])->name('dashboard'); + }); +}); +``` + +### Контроллеры +- `ProductController` — публичный каталог и детальный просмотр +- `CartController` — управление корзиной +- `OrderController` — оформление и просмотр своих заказов +- `AdminProductController` — CRUD товаров (с загрузкой изображений) +- `AdminCategoryController` — CRUD категорий +- `AdminOrderController` — управление заказами и статусами +- `AdminDashboardController` — панель администратора + +--- + +## 5. Роли, Gates и Policies + +### Роли +| Роль | Описание | +|---|---| +| `admin` | Полный доступ, управление пользователями, товарами, заказами | +| `order_manager` | Просмотр и обновление статусов заказов | +| `customer` | Просмотр каталога, корзина, оформление заказов, просмотр своих заказов | + +### Gates + +```php +Gate::define('access-admin-panel', function (User $user) { + return in_array($user->role, ['admin', 'order_manager']); +}); + +Gate::define('manage-products', function (User $user) { + return $user->role === 'admin'; +}); + +Gate::define('manage-categories', function (User $user) { + return $user->role === 'admin'; +}); + +Gate::define('manage-orders', function (User $user) { + return in_array($user->role, ['admin', 'order_manager']); +}); +``` + +### Policies + +**ProductPolicy:** +- `view` — все (публичный каталог) +- `create`, `update`, `delete` — только admin + +**CategoryPolicy:** +- `create`, `update`, `delete` — только admin + +**OrderPolicy:** +- `view` — владелец заказа или admin/order_manager +- `updateStatus` — admin или order_manager +- `create` — все аутентифицированные + +--- + +## 6. Требования к интерфейсу (Bootstrap 5) + +### Компоненты +- **Навбар** — логотип, ссылки, корзина (с бейджем количества), профиль +- **Карточки товаров** — изображение, название, цена, бейдж наличия, кнопка «В корзину» +- **Каталог** — боковая панель с категориями + сетка товаров (`col-md-4`) +- **Корзина** — таблица позиций с кнопками +/- количества, итоговая сумма +- **Форма заказа** — Bootstrap-форма с валидацией +- **Модальное окно** — быстрый просмотр товара +- **Таблица заказов** — статусы с цветными бейджами, кнопка просмотра деталей +- **Дашборд** — карточки статистики (`card` + `row`/`col`) + +### Цветовая схема статусов заказа +- Новый — `bg-info` +- В обработке — `bg-warning` +- Отправлен — `bg-primary` +- Доставлен — `bg-success` +- Отменён — `bg-danger` + +--- + +## 7. Git-workflow для команды + +### Распределение модулей (для 2 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Товары, категории, загрузка изображений, админка | `feature/products-crud`, `feature/categories`, `feature-image-upload` | +| **Участник B** | Корзина, оформление заказа, заказы, UI | `feature/cart`, `feature/checkout`, `feature-orders` | + +### Распределение модулей (для 3 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Товары, категории, загрузка изображений | `feature/products-crud`, `feature/categories`, `feature-image-upload` | +| **Участник B** | Корзина, оформление заказа, заказы | `feature/cart`, `feature/checkout`, `feature-orders` | +| **Участник C** | Аутентификация, админка, дашборд | `feature/admin-dashboard`, `feature/admin-orders`, `feature-statistics` | + +### Правила +1. Ветка `develop` — основная ветка разработки +2. Каждый участник создаёт фич-ветки от `develop` +3. Минимум 3 PR на участника +4. Обязательный код-ревью перед мёржем +5. Conventional Commits для всех коммитов + +### Визуализация workflow (2 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/products-crud + checkout develop + branch feature/cart + checkout feature/products-crud + commit id: "feat: add products CRUD with images" + commit id: "feat: add categories CRUD" + checkout feature/cart + commit id: "feat: add cart session logic" + commit id: "feat: add checkout form" + checkout develop + merge feature/products-crud tag: "PR + review" + merge feature/cart tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +### Визуализация workflow (3 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/products-crud + checkout develop + branch feature/cart + checkout develop + branch feature/admin-dashboard + checkout feature/products-crud + commit id: "feat: add products CRUD" + commit id: "feat: add image upload" + checkout feature/cart + commit id: "feat: add cart management" + commit id: "feat: add checkout flow" + checkout feature/admin-dashboard + commit id: "feat: add admin panel" + commit id: "feat: add order management" + checkout develop + merge feature/products-crud tag: "PR + review" + merge feature/cart tag: "PR + review" + merge feature/admin-dashboard tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +--- + +## 8. Критерии приёмки + +### Обязательно +- [ ] CRUD товаров с загрузкой изображений (валидация формата и размера) +- [ ] CRUD категорий +- [ ] Связь многие-ко-многим (товар ↔ категории) +- [ ] Корзина работает (добавление, изменение количества, удаление) +- [ ] Оформление заказа с валидацией всех полей +- [ ] Уменьшение `stock_quantity` при оформлении заказа +- [ ] Просмотр своих заказов (покупатель) +- [ ] Управление статусами заказов (админ/менеджер) +- [ ] Policies: покупатель не может управлять товарами/чужими заказами +- [ ] Адаптивная Bootstrap-вёрстка +- [ ] Flash-сообщения при действиях +- [ ] Пагинация каталога +- [ ] Git-история: минимум 3 ветки на участника, PR с ревью + +### Дополнительно (бонусные баллы) +- [ ] Поиск товаров по названию/описанию +- [ ] Сортировка товаров (цена, дата, название) +- [ ] Фильтрация по нескольким категориям +- [ ] Избранное (wishlist) +- [ ] Промокоды со скидкой +- [ ] Генерация PDF-чека заказа + +--- + +## 9. Дополнительные задания (для продвинутых) + +1. **Промокоды:** система скидок с уникальными кодами и процентом/фиксированной суммой +2. **Избранное:** добавление товаров в wishlist (многие-ко-многим user ↔ product) +3. **Отзывы к товарам:** рейтинг 1–5 + текст, модерация +4. **Тесты:** PHPUnit Feature-тесты для CartController и OrderController +5. **API:** RESTful API для каталога товаров (resource-маршруты с JSON) +6. **Кэширование:** кэширование каталога через Laravel Cache +7. **Soft Deletes:** мягкое удаление товаров и категорий + +--- + +## 10. Рекомендуемые материалы + +- Laravel Docs: https://laravel.com/docs/12.x +- Laravel Filesystem (загрузка файлов): https://laravel.com/docs/12.x/filesystem +- Laravel Many-to-Many Relationships: https://laravel.com/docs/12.x/eloquent-relationships#many-to-many +- Bootstrap 5 Cards: https://getbootstrap.com/docs/5.3/components/card/ +- Laravel Session & Cart: https://laravel.com/docs/12.x/session diff --git a/task03-online-courses.md b/task03-online-courses.md new file mode 100644 index 0000000..bd73f1d --- /dev/null +++ b/task03-online-courses.md @@ -0,0 +1,410 @@ +# Техническое задание: Платформа для онлайн-курсов + +## 1. Описание проекта + +Веб-платформа для публикации и прохождения онлайн-курсов с отслеживанием прогресса студентов и системой тестирования. Проект закрепляет навыки CRUD, вложенных сущностей (курс → уроки → тесты), разграничения прав и совместной работы через Git. + +**Команда:** 2–3 человека + +--- + +## 2. Функциональные требования + +### 2.1. Аутентификация и регистрация +- Регистрация, вход, выход (Laravel Breeze) +- Восстановление пароля (опционально) + +### 2.2. Каталог курсов +- Просмотр списка доступных курсов с пагинацией +- Фильтрация по категориям +- Детальная страница курса (описание, автор, список уроков, рейтинг) +- Запись на курс (кнопка «Записаться») + +### 2.3. Управление курсами (преподаватель/админ) +- CRUD курсов: название, описание, обложка, категория, уровень сложности +- Вложенный CRUD уроков внутри курса: + - Название урока, порядковый номер, тип (текст/видео) + - Текстовое содержание (WYSIWYG или markdown) + - URL видео (опционально, YouTube/Vimeo embed) +- CRUD тестов/викторин к урокам: + - Вопросы с вариантами ответов + - Один или несколько правильных ответов + - Проходной балл (в процентах) + +### 2.4. Прохождение курса (студент) +- Список записанных курсов (личный кабинет) +- Последовательное прохождение уроков +- Отметка урока как пройденного +- Сдача теста после урока (или в конце курса) +- Просмотр результатов теста (правильные/неправильные ответы) +- Прогресс-бар прохождения курса (в процентах) + +### 2.5. Панель преподавателя +- Мои курсы (созданные мной) +- Список студентов по каждому курсу +- Прогресс каждого студента +- Статистика: количество курсов, студентов, средний балл + +### 2.6. Панель администратора +- Управление пользователями и ролями +- Модерация курсов (скрыть/показать) +- Общая статистика платформы + +--- + +## 3. Структура базы данных + +### Таблица `users` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Имя | +| email | VARCHAR(255) | Email (unique) | +| password | VARCHAR(255) | Хеш пароля | +| role | ENUM('admin', 'instructor', 'student') | Роль | +| avatar | VARCHAR(255) \| NULL | Аватар | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `categories` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Название категории | +| slug | VARCHAR(255) | URL-идентификатор (unique) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `courses` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| title | VARCHAR(255) | Название курса | +| slug | VARCHAR(255) | URL-идентификатор (unique) | +| description | TEXT | Описание | +| cover_image | VARCHAR(255) \| NULL | Обложка курса | +| difficulty_level | ENUM('beginner', 'intermediate', 'advanced') | Уровень | +| instructor_id | BIGINT UNSIGNED | Преподаватель (FK → users) | +| category_id | BIGINT UNSIGNED | Категория (FK → categories) | +| is_published | BOOLEAN | Опубликован ли | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `lessons` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| course_id | BIGINT UNSIGNED | Курс (FK → courses) | +| title | VARCHAR(255) | Название урока | +| position | INT | Порядковый номер | +| content_type | ENUM('text', 'video') | Тип контента | +| content | TEXT | Содержимое (текст или URL видео) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `quizzes` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| lesson_id | BIGINT UNSIGNED | Урок (FK → lessons) | +| title | VARCHAR(255) | Название теста | +| passing_score | INT | Проходной балл (%) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `quiz_questions` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| quiz_id | BIGINT UNSIGNED | Тест (FK → quizzes) | +| question | TEXT | Вопрос | +| position | INT | Порядковый номер | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `quiz_answers` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| question_id | BIGINT UNSIGNED | Вопрос (FK → quiz_questions) | +| answer_text | VARCHAR(255) | Текст ответа | +| is_correct | BOOLEAN | Правильный ли | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `course_user` (запись на курс) +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| course_id | BIGINT UNSIGNED | FK → courses | +| user_id | BIGINT UNSIGNED | FK → users | +| progress | INT | Прогресс в процентах (0–100) | +| enrolled_at | TIMESTAMP | Дата записи | +| completed_at | TIMESTAMP \| NULL | Дата завершения | + +### Таблица `lesson_progress` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| user_id | BIGINT UNSIGNED | FK → users | +| lesson_id | BIGINT UNSIGNED | FK → lessons | +| is_completed | BOOLEAN | Пройден ли | +| completed_at | TIMESTAMP \| NULL | | + +### Таблица `quiz_results` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| user_id | BIGINT UNSIGNED | FK → users | +| quiz_id | BIGINT UNSIGNED | FK → quizzes | +| score | INT | Набранный балл (%) | +| passed | BOOLEAN | Сдал ли | +| taken_at | TIMESTAMP | Дата прохождения | + +--- + +## 4. Маршруты и контроллеры + +```php +// Публичные маршруты +Route::get('/', [CourseController::class, 'index'])->name('courses.index'); +Route::get('/courses/{course:slug}', [CourseController::class, 'show'])->name('courses.show'); + +// Аутентифицированные маршруты +Route::middleware('auth')->group(function () { + // Запись на курс + Route::post('/courses/{course}/enroll', [CourseController::class, 'enroll'])->name('courses.enroll'); + + // Прохождение курса + Route::prefix('my-courses')->name('my-courses.')->group(function () { + Route::get('/', [StudentCourseController::class, 'index'])->name('index'); + Route::get('/{course}', [StudentCourseController::class, 'show'])->name('show'); + Route::get('/{course}/lessons/{lesson}', [LessonController::class, 'show'])->name('lessons.show'); + Route::post('/{course}/lessons/{lesson}/complete', [LessonController::class, 'complete'])->name('lessons.complete'); + + // Тесты + Route::get('/{course}/quizzes/{quiz}', [QuizController::class, 'take'])->name('quizzes.take'); + Route::post('/{course}/quizzes/{quiz}/submit', [QuizController::class, 'submit'])->name('quizzes.submit'); + }); + + // Преподаватель + Route::prefix('instructor')->name('instructor.')->middleware('can:be-instructor')->group(function () { + Route::resource('courses', InstructorCourseController::class); + Route::resource('courses.lessons', InstructorLessonController::class)->scoped(['courses' => 'course']); + Route::resource('lessons.quizzes', InstructorQuizController::class)->scoped(['lessons' => 'lesson']); + Route::resource('quizzes.questions', InstructorQuestionController::class)->scoped(['quizzes' => 'quiz']); + Route::get('courses/{course}/students', [InstructorCourseController::class, 'students'])->name('courses.students'); + Route::get('dashboard', [InstructorDashboardController::class, 'index'])->name('dashboard'); + }); + + // Админка + Route::prefix('admin')->name('admin.')->middleware('can:access-admin-panel')->group(function () { + Route::resource('users', AdminUserController::class); + Route::patch('courses/{course}/toggle-publish', [AdminCourseController::class, 'togglePublish'])->name('courses.publish'); + Route::get('dashboard', [AdminDashboardController::class, 'index'])->name('dashboard'); + }); +}); +``` + +### Контроллеры +- `CourseController` — публичный каталог и запись +- `StudentCourseController` — прохождение курсов студентом +- `LessonController` — просмотр уроков и отметка пройденными +- `QuizController` — прохождение тестов +- `InstructorCourseController` — CRUD курсов преподавателем +- `InstructorLessonController` — CRUD уроков +- `InstructorQuizController` — CRUD тестов +- `InstructorQuestionController` — CRUD вопросов +- `InstructorDashboardController` — панель преподавателя +- `AdminUserController`, `AdminCourseController`, `AdminDashboardController` — админка + +--- + +## 5. Роли, Gates и Policies + +### Роли +| Роль | Описание | +|---|---| +| `admin` | Полный доступ, модерация курсов, управление пользователями | +| `instructor` | Создание/редактирование своих курсов, просмотр студентов | +| `student` | Запись на курсы, прохождение уроков и тестов | + +### Gates + +```php +Gate::define('be-instructor', function (User $user) { + return in_array($user->role, ['admin', 'instructor']); +}); + +Gate::define('access-admin-panel', function (User $user) { + return $user->role === 'admin'; +}); +``` + +### Policies + +**CoursePolicy:** +- `view` — все (если опубликован), автор или admin (если не опубликован) +- `create` — instructor или admin +- `update`, `delete` — автор курса или admin +- `enroll` — student (не записан на этот курс) + +**LessonPolicy:** +- `view` — студент, записанный на курс, или преподаватель/admin +- `create`, `update`, `delete` — преподаватель курса или admin + +**QuizPolicy:** +- `view` — студент, записанный на курс, или преподаватель/admin +- `take` — студент, записанный на курс +- `create`, `update`, `delete` — преподаватель курса или admin + +**QuizResultPolicy:** +- `view` — владелец результата или преподаватель/admin +- `create` — все студенты + +--- + +## 6. Требования к интерфейсу (Bootstrap 5) + +### Компоненты +- **Навбар** — логотип, каталог, «Мои курсы», профиль +- **Карточки курсов** — обложка, название, автор, уровень (бейдж), прогресс-бар +- **Страница курса** — описание, список уроков (accordion), кнопка записи +- **Страница урока** — контент (текст или embed видео), кнопка «Отметить пройденным» +- **Прогресс-бар** — Bootstrap `progress` для отображения прохождения курса +- **Accordion** — список уроков курса +- **Тест** — форма с radio/checkbox, кнопка отправки, результат +- **Дашборд преподавателя** — статистика (карточки), таблица студентов +- **Адаптивная сетка** — `col-md-4` для карточек, `col-md-8` + `col-md-4` для основного контента и сайдбара + +### Цветовая схема уровней сложности +- Начальный — `bg-success` +- Средний — `bg-warning` +- Продвинутый — `bg-danger` + +--- + +## 7. Git-workflow для команды + +### Распределение модулей (для 2 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Курсы, категории, обложки, дашборд преподавателя | `feature/courses-crud`, `feature/categories`, `feature-course-covers` | +| **Участник B** | Уроки, тесты, вопросы, прохождение тестов | `feature/lessons-crud`, `feature/quizzes`, `feature-quiz-questions` | + +### Распределение модулей (для 3 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Курсы, категории, загрузка обложек | `feature/courses-crud`, `feature/categories`, `feature-course-covers` | +| **Участник B** | Уроки, тесты, вопросы | `feature/lessons-crud`, `feature/quizzes`, `feature-quiz-questions` | +| **Участник C** | Запись на курс, прогресс, прохождение тестов, UI | `feature/enrollment`, `feature-progress-tracking`, `feature-student-ui` | + +### Правила +1. Ветка `develop` — основная ветка разработки +2. Каждый участник создаёт фич-ветки от `develop` +3. Минимум 3 PR на участника +4. Обязательный код-ревью перед мёржем +5. Conventional Commits + +### Визуализация workflow (2 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/courses-crud + checkout develop + branch feature/lessons-crud + checkout feature/courses-crud + commit id: "feat: add courses CRUD with covers" + commit id: "feat: add categories CRUD" + checkout feature/lessons-crud + commit id: "feat: add lessons CRUD" + commit id: "feat: add quizzes system" + checkout develop + merge feature/courses-crud tag: "PR + review" + merge feature/lessons-crud tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +### Визуализация workflow (3 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/courses-crud + checkout develop + branch feature/lessons-crud + checkout develop + branch feature/enrollment + checkout feature/courses-crud + commit id: "feat: add courses CRUD with covers" + commit id: "feat: add instructor dashboard" + checkout feature/lessons-crud + commit id: "feat: add lessons CRUD" + commit id: "feat: add quizzes system" + checkout feature/enrollment + commit id: "feat: add enrollment flow" + commit id: "feat: add progress tracking" + checkout develop + merge feature/courses-crud tag: "PR + review" + merge feature/lessons-crud tag: "PR + review" + merge feature/enrollment tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +--- + +## 8. Критерии приёмки + +### Обязательно +- [ ] CRUD курсов с загрузкой обложки +- [ ] CRUD уроков внутри курса (вложенный ресурс) +- [ ] CRUD тестов и вопросов (минимум 3 ответа на вопрос, 1+ правильный) +- [ ] Запись на курс (студент) +- [ ] Отметка уроков пройденными +- [ ] Прохождение теста с подсчётом результата +- [ ] Прогресс-бар прохождения курса +- [ ] Панель преподавателя (мои курсы, студенты) +- [ ] Policies: студент не может редактировать курсы, преподаватель не может редактировать чужие курсы +- [ ] Адаптивная Bootstrap-вёрстка +- [ ] Flash-сообщения +- [ ] Пагинация каталога курсов +- [ ] Git-история: минимум 3 ветки на участника, PR с ревью + +### Дополнительно (бонусные баллы) +- [ ] Рейтинг курса (средняя оценка студентов) +- [ ] Сертификат при завершении курса (генерация PDF) +- [ ] Поиск курсов по названию/описанию +- [ ] Фильтрация по уровню сложности +- [ ] Тесты: перемешивание вопросов и ответов +- [ ] Soft Deletes для курсов и уроков + +--- + +## 9. Дополнительные задания (для продвинутых) + +1. **Рейтинг курсов:** студенты оценивают курс после завершения (1–5 звёзд) +2. **Сертификаты:** генерация PDF-сертификата при 100% прохождении +3. **Обсуждения:** комментарии к урокам (вложенные, как на YouTube) +4. **Тесты:** таймер на прохождение теста, автоматическая отправка по истечении +5. **API:** RESTful API для каталога курсов и прохождения +6. **Тесты:** PHPUnit Feature-тесты для QuizController +7. **Events & Listeners:** событие «урок пройден» → обновление прогресса + +--- + +## 10. Рекомендуемые материалы + +- Laravel Docs: https://laravel.com/docs/12.x +- Nested Resources: https://laravel.com/docs/12.x/controllers#restful-nested-resources +- Bootstrap 5 Progress: https://getbootstrap.com/docs/5.3/components/progress/ +- Bootstrap 5 Accordion: https://getbootstrap.com/docs/5.3/components/accordion/ +- Laravel Policies: https://laravel.com/docs/12.x/authorization#creating-policies diff --git a/task04-booking-system.md b/task04-booking-system.md new file mode 100644 index 0000000..11fd93a --- /dev/null +++ b/task04-booking-system.md @@ -0,0 +1,337 @@ +# Техническое задание: Система бронирования помещений и оборудования + +## 1. Описание проекта + +Веб-приложение для бронирования конференц-залов, рабочих мест или оборудования с календарём, подтверждением заявок и управлением расписанием. Проект закрепляет навыки CRUD, валидации дат и времени, разграничения прав и совместной работы через Git. + +**Команда:** 2–3 человека + +--- + +## 2. Функциональные требования + +### 2.1. Аутентификация и регистрация +- Регистрация, вход, выход (Laravel Breeze) + +### 2.2. Каталог ресурсов +- Просмотр списка доступных ресурсов (помещения, оборудование) +- Фильтрация по категориям (конференц-залы, переговорки, проекторы, ноутбуки) +- Детальная страница ресурса (описание, вместимость, фото, календарь бронирований) +- Поиск по названию ресурса + +### 2.3. Управление ресурсами (админ) +- CRUD ресурсов: название, описание, категория, вместимость/количество, изображение, доступен ли +- CRUD категорий ресурсов +- Загрузка изображений ресурсов + +### 2.4. Бронирование +- Создание заявки на бронирование: ресурс, дата начала, дата окончания (или время), цель +- **Валидация:** проверка на пересечение с существующими бронированиями того же ресурса +- Просмотр своих бронирований (статусы: ожидание, подтверждено, отклонено, завершено, отменено) +- Отмена бронирования (пользователь — если статус «ожидание») +- Календарь бронирований ресурса (визуальное отображение занятых дат) + +### 2.5. Управление бронированиями (модератор/админ) +- Просмотр всех бронирований +- Подтверждение/отклонение заявки +- Изменение дат бронирования +- Отмена бронирования с комментарием + +### 2.6. Дашборд модератора +- Статистика: количество ресурсов, бронирований (по статусам) +- Последние заявки, ожидающие подтверждения +- Популярные ресурсы + +### 2.7. Дашборд пользователя +- Мои активные бронирования +- История бронирований +- Быстрая ссылка на создание заявки + +--- + +## 3. Структура базы данных + +### Таблица `users` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Имя | +| email | VARCHAR(255) | Email (unique) | +| password | VARCHAR(255) | Хеш пароля | +| role | ENUM('admin', 'moderator', 'user') | Роль | +| phone | VARCHAR(20) \| NULL | Телефон | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `resource_categories` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Название категории | +| slug | VARCHAR(255) | URL-идентификатор (unique) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `resources` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Название ресурса | +| slug | VARCHAR(255) | URL-идентификатор (unique) | +| description | TEXT | Описание | +| category_id | BIGINT UNSIGNED | Категория (FK → resource_categories) | +| capacity | INT \| NULL | Вместимость (для помещений) | +| quantity | INT \| NULL | Количество (для оборудования) | +| image | VARCHAR(255) \| NULL | Изображение | +| is_available | BOOLEAN | Доступен для бронирования | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `bookings` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| resource_id | BIGINT UNSIGNED | Ресурс (FK → resources) | +| user_id | BIGINT UNSIGNED | Инициатор (FK → users) | +| start_datetime | DATETIME | Дата и время начала | +| end_datetime | DATETIME | Дата и время окончания | +| purpose | TEXT | Цель бронирования | +| status | ENUM('pending', 'confirmed', 'rejected', 'completed', 'cancelled') | Статус | +| rejection_reason | TEXT \| NULL | Причина отклонения | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +--- + +## 4. Маршруты и контроллеры + +```php +// Публичные маршруты +Route::get('/', [ResourceController::class, 'index'])->name('resources.index'); +Route::get('/resources/{resource:slug}', [ResourceController::class, 'show'])->name('resources.show'); +Route::get('/resources/{resource:slug}/calendar', [ResourceController::class, 'calendar'])->name('resources.calendar'); + +// Аутентифицированные маршруты +Route::middleware('auth')->group(function () { + // Бронирования пользователя + Route::get('/my-bookings', [BookingController::class, 'myBookings'])->name('bookings.my'); + Route::resource('bookings', BookingController::class)->except(['index', 'show']); + Route::post('/bookings/{booking}/cancel', [BookingController::class, 'cancel'])->name('bookings.cancel'); + + // Панель модератора + Route::prefix('moderator')->name('moderator.')->middleware('can:be-moderator')->group(function () { + Route::get('dashboard', [ModeratorDashboardController::class, 'index'])->name('dashboard'); + Route::get('bookings', [ModeratorBookingController::class, 'index'])->name('bookings.index'); + Route::get('bookings/{booking}', [ModeratorBookingController::class, 'show'])->name('bookings.show'); + Route::post('bookings/{booking}/confirm', [ModeratorBookingController::class, 'confirm'])->name('bookings.confirm'); + Route::post('bookings/{booking}/reject', [ModeratorBookingController::class, 'reject'])->name('bookings.reject'); + }); + + // Админка + Route::prefix('admin')->name('admin.')->middleware('can:access-admin-panel')->group(function () { + Route::resource('resources', AdminResourceController::class); + Route::resource('categories', AdminCategoryController::class); + Route::resource('users', AdminUserController::class); + Route::get('dashboard', [AdminDashboardController::class, 'index'])->name('dashboard'); + }); +}); +``` + +### Контроллеры +- `ResourceController` — публичный каталог и календарь бронирований +- `BookingController` — создание/отмена бронирований, мои бронирования +- `ModeratorBookingController` — просмотр, подтверждение, отклонение +- `ModeratorDashboardController` — панель модератора +- `AdminResourceController` — CRUD ресурсов +- `AdminCategoryController` — CRUD категорий +- `AdminUserController`, `AdminDashboardController` — админка + +--- + +## 5. Роли, Gates и Policies + +### Роли +| Роль | Описание | +|---|---| +| `admin` | Полный доступ, управление ресурсами, категориями, пользователями | +| `moderator` | Подтверждение/отклонение бронирований, управление расписанием | +| `user` | Создание бронирований, просмотр своих бронирований и доступных ресурсов | + +### Gates + +```php +Gate::define('be-moderator', function (User $user) { + return in_array($user->role, ['admin', 'moderator']); +}); + +Gate::define('access-admin-panel', function (User $user) { + return $user->role === 'admin'; +}); +``` + +### Policies + +**ResourcePolicy:** +- `view` — все аутентифицированные +- `create`, `update`, `delete` — только admin + +**BookingPolicy:** +- `create` — все аутентифицированные (если ресурс доступен) +- `view` — владелец бронирования или moderator/admin +- `update` — moderator/admin (даты) или владелец (только если status = pending) +- `cancel` — владелец (если status = pending или confirmed) или moderator/admin +- `confirm`, `reject` — только moderator или admin + +--- + +## 6. Требования к интерфейсу (Bootstrap 5) + +### Компоненты +- **Навбар** — логотип, каталог ресурсов, «Мои бронирования», профиль +- **Карточки ресурсов** — изображение, название, категория (бейдж), вместимость +- **Форма бронирования** — выбор ресурса, дата/время начала и окончания (input type="datetime-local"), цель +- **Календарь ресурса** — таблица или упрощённый календарь с подсветкой занятых дней +- **Таблица бронирований** — ресурс, даты, статус (цветные бейджи), действия +- **Модальное окно** — подтверждение/отклонение бронирования (с полем причины) +- **Дашборд** — карточки статистики (`card` + `row`/`col`) +- **Алерты** — flash-сообщения об успехе/ошибке + +### Цветовая схема статусов бронирования +- Ожидание — `bg-warning` +- Подтверждено — `bg-success` +- Отклонено — `bg-danger` +- Завершено — `bg-secondary` +- Отменено — `bg-light text-muted` + +### Валидация формы бронирования +- Дата начала — не в прошлом +- Дата окончания — позже даты начала +- Сообщение об ошибке при пересечении с существующим бронированием + +--- + +## 7. Git-workflow для команды + +### Распределение модулей (для 2 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Ресурсы, категории, изображения, календарь | `feature/resources-crud`, `feature/categories`, `feature-resource-images` | +| **Участник B** | Бронирования, валидация, модерация, дашборды | `feature/bookings-crud`, `feature-booking-validation`, `feature-booking-calendar` | + +### Распределение модулей (для 3 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Ресурсы, категории, загрузка изображений | `feature/resources-crud`, `feature/categories`, `feature-resource-images` | +| **Участник B** | Бронирования, валидация пересечений, календарь | `feature/bookings-crud`, `feature-booking-validation`, `feature-booking-calendar` | +| **Участник C** | Управление бронированиями (модератор), дашборды | `feature/moderator-panel`, `feature/dashboards`, `feature-booking-statuses` | + +### Правила +1. Ветка `develop` — основная ветка разработки +2. Каждый участник создаёт фич-ветки от `develop` +3. Минимум 3 PR на участника +4. Обязательный код-ревью перед мёржем +5. Conventional Commits + +### Визуализация workflow (2 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/resources-crud + checkout develop + branch feature/bookings-crud + checkout feature/resources-crud + commit id: "feat: add resources CRUD" + commit id: "feat: add resource categories" + checkout feature/bookings-crud + commit id: "feat: add bookings CRUD" + commit id: "feat: add booking validation" + checkout develop + merge feature/resources-crud tag: "PR + review" + merge feature/bookings-crud tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +### Визуализация workflow (3 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/resources-crud + checkout develop + branch feature/bookings-crud + checkout develop + branch feature/moderator-panel + checkout feature/resources-crud + commit id: "feat: add resources CRUD" + commit id: "feat: add booking calendar" + checkout feature/bookings-crud + commit id: "feat: add bookings CRUD" + commit id: "feat: add booking validation" + checkout feature/moderator-panel + commit id: "feat: add moderator panel" + commit id: "feat: add booking statuses" + checkout develop + merge feature/resources-crud tag: "PR + review" + merge feature/bookings-crud tag: "PR + review" + merge feature/moderator-panel tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +--- + +## 8. Критерии приёмки + +### Обязательно +- [ ] CRUD ресурсов с загрузкой изображений +- [ ] CRUD категорий ресурсов +- [ ] Создание бронирования с валидацией дат (не в прошлом, окончание > начала) +- [ ] **Валидация пересечения:** нельзя забронировать ресурс на время, которое уже занято +- [ ] Отмена бронирования пользователем (если статус «ожидание») +- [ ] Подтверждение/отклонение бронирования модератором +- [ ] Просмотр своих бронирований (фильтрация по статусу) +- [ ] Календарь бронирований ресурса (визуальное отображение) +- [ ] Policies: пользователь не может управлять чужими бронированиями +- [ ] Адаптивная Bootstrap-вёрстка +- [ ] Flash-сообщения +- [ ] Пагинация каталога ресурсов и списка бронирований +- [ ] Git-история: минимум 3 ветки на участника, PR с ревью + +### Дополнительно (бонусные баллы) +- [ ] Повторяющиеся бронирования (еженедельно, ежемесячно) +- [ ] Уведомления (email при подтверждении/отклонении) +- [ ] Экспорт бронирований в CSV/ICS (календарь) +- [ ] Поиск ресурсов по названию +- [ ] Фильтрация по вместимости +- [ ] Рейтинг ресурсов (пользователи оценивают) +- [ ] Soft Deletes для ресурсов + +--- + +## 9. Дополнительные задания (для продвинутых) + +1. **Повторяющиеся бронирования:** возможность забронировать ресурс на каждую неделю/месяц +2. **Уведомления:** email при подтверждении/отклонении/напоминании за день +3. **ICS-экспорт:** генерация .ics-файла для добавления в Google/Apple Calendar +4. **Конфликты:** визуальное отображение конфликтов при создании бронирования +5. **Тесты:** PHPUnit Feature-тесты для BookingController (валидация пересечений) +6. **API:** RESTful API для каталога ресурсов и создания бронирований +7. **Queue:** асинхронная отправка email-уведомлений + +--- + +## 10. Рекомендуемые материалы + +- Laravel Docs: https://laravel.com/docs/12.x +- Laravel Validation (custom rules): https://laravel.com/docs/12.x/validation#custom-validation-rules +- Bootstrap 5 Forms: https://getbootstrap.com/docs/5.3/forms/overview/ +- Carbon (работа с датами): https://carbon.nesbot.com/docs/ +- Laravel Policies: https://laravel.com/docs/12.x/authorization#creating-policies diff --git a/task05-freelance-portfolio.md b/task05-freelance-portfolio.md new file mode 100644 index 0000000..7d0d03c --- /dev/null +++ b/task05-freelance-portfolio.md @@ -0,0 +1,384 @@ +# Техническое задание: Портфолио-платформа для фрилансеров + +## 1. Описание проекта + +Веб-сервис для публикации портфолио фрилансеров, поиска заказов и обмена отзывами. Проект закрепляет навыки CRUD, работы с рейтингами и отзывами, разграничения прав и совместной работы через Git. + +**Команда:** 2–3 человека + +--- + +## 2. Функциональные требования + +### 2.1. Аутентификация и регистрация +- Регистрация, вход, выход (Laravel Breeze) +- При регистрации выбирается роль: фрилансер или клиент + +### 2.2. Профиль фрилансера +- Публичный профиль: имя, фото, описание, навыки, контакты, рейтинг +- Редактирование профиля (только владелец) +- Загрузка аватара (валидация: jpg/png, макс. 2MB) +- Список навыков (свободный ввод или выбор из тегов) + +### 2.3. Портфолио-проекты +- CRUD проектов в портфолио: название, описание, изображения (до 5), технологии/навыки, ссылка на проект +- Привязка проекта к навыкам (многие-ко-многим) +- Публичный просмотр на странице профиля +- Сортировка по дате, рейтингу + +### 2.4. Каталог фрилансеров +- Просмотр списка фрилансеров с пагинацией +- Фильтрация по навыкам/категориям услуг +- Поиск по имени и описанию +- Карточка фрилансера (аватар, имя, рейтинг, основные навыки) + +### 2.5. Заявки на проекты (клиент → фрилансер) +- Клиент создаёт заявку: описание проекта, бюджет, срок, требуемые навыки +- Привязка заявки к фрилансеру +- Фрилансер видит входящие заявки +- Фрилансер отвечает на заявку (принять / отклонить с комментарием) +- Статусы заявки: новая, принята, отклонена, завершена + +### 2.6. Отзывы и рейтинги +- Клиент оставляет отзыв фрилансеру после завершения заявки +- Поля отзыва: текст, рейтинг (1–5 звёзд) +- Средний рейтинг фрилансера (автоматический пересчёт) +- Отзывы отображаются на странице профиля + +### 2.7. Панель фрилансера +- Мой профиль (редактирование) +- Мои проекты портфолио +- Входящие заявки (статусы, ответы) +- Мой рейтинг и отзывы + +### 2.8. Панель клиента +- Мои заявки (статусы) +- Создание новой заявки (выбор фрилансера) +- Оставить отзыв (после завершения) + +### 2.9. Панель администратора +- Управление пользователями +- Модерация отзывов (скрыть/удалить) +- Общая статистика + +--- + +## 3. Структура базы данных + +### Таблица `users` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Имя | +| email | VARCHAR(255) | Email (unique) | +| password | VARCHAR(255) | Хеш пароля | +| role | ENUM('admin', 'freelancer', 'client') | Роль | +| bio | TEXT \| NULL | О себе | +| avatar | VARCHAR(255) \| NULL | Аватар | +| rating | DECIMAL(3, 2) \| NULL | Средний рейтинг (0.00–5.00) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `skills` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| name | VARCHAR(255) | Название навыка (unique) | +| slug | VARCHAR(255) | URL-идентификатор (unique) | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `freelancer_skill` (многие-ко-многим) +| Поле | Тип | Описание | +|---|---|---| +| freelancer_id | BIGINT UNSIGNED | FK → users | +| skill_id | BIGINT UNSIGNED | FK → skills | + +### Таблица `portfolio_projects` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| freelancer_id | BIGINT UNSIGNED | FK → users | +| title | VARCHAR(255) | Название проекта | +| description | TEXT | Описание | +| project_url | VARCHAR(255) \| NULL | Ссылка на проект | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `portfolio_skill` (многие-ко-многим) +| Поле | Тип | Описание | +|---|---|---| +| portfolio_project_id | BIGINT UNSIGNED | FK → portfolio_projects | +| skill_id | BIGINT UNSIGNED | FK → skills | + +### Таблица `project_proposals` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| client_id | BIGINT UNSIGNED | Клиент (FK → users) | +| freelancer_id | BIGINT UNSIGNED | Фрилансер (FK → users) | +| title | VARCHAR(255) | Название заявки | +| description | TEXT | Описание проекта | +| budget | DECIMAL(10, 2) \| NULL | Бюджет | +| deadline | DATE \| NULL | Срок выполнения | +| status | ENUM('new', 'accepted', 'rejected', 'completed') | Статус | +| response_message | TEXT \| NULL | Ответ фрилансера | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +### Таблица `reviews` +| Поле | Тип | Описание | +|---|---|---| +| id | BIGINT UNSIGNED | Первичный ключ | +| client_id | BIGINT UNSIGNED | Автор отзыва (FK → users) | +| freelancer_id | BIGINT UNSIGNED | Получатель отзыва (FK → users) | +| proposal_id | BIGINT UNSIGNED \| NULL | Связанная заявка (FK → project_proposals) | +| rating | TINYINT | Рейтинг (1–5) | +| comment | TEXT | Текст отзыва | +| is_published | BOOLEAN | Опубликован ли | +| created_at | TIMESTAMP | | +| updated_at | TIMESTAMP | | + +--- + +## 4. Маршруты и контроллеры + +```php +// Публичные маршруты +Route::get('/', [FreelancerController::class, 'index'])->name('freelancers.index'); +Route::get('/freelancers/{user}', [FreelancerController::class, 'show'])->name('freelancers.show'); + +// Аутентифицированные маршруты +Route::middleware('auth')->group(function () { + // Профиль + Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); + Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); + + // Портфолио (фрилансер) + Route::prefix('my-portfolio')->name('portfolio.')->middleware('can:be-freelancer')->group(function () { + Route::resource('projects', PortfolioProjectController::class); + Route::get('dashboard', [FreelancerDashboardController::class, 'index'])->name('dashboard'); + }); + + // Заявки + Route::prefix('proposals')->name('proposals.')->group(function () { + Route::post('/send/{freelancer}', [ProposalController::class, 'store'])->name('send'); + Route::get('/my-sent', [ProposalController::class, 'mySent'])->name('my-sent'); // клиент + Route::get('/incoming', [ProposalController::class, 'incoming'])->name('incoming'); // фрилансер + Route::post('/{proposal}/accept', [ProposalController::class, 'accept'])->name('accept'); + Route::post('/{proposal}/reject', [ProposalController::class, 'reject'])->name('reject'); + }); + + // Отзывы + Route::resource('reviews', ReviewController::class)->only(['store', 'update', 'destroy']); + + // Админка + Route::prefix('admin')->name('admin.')->middleware('can:access-admin-panel')->group(function () { + Route::resource('users', AdminUserController::class); + Route::resource('skills', AdminSkillController::class); + Route::patch('reviews/{review}/toggle-publish', [AdminReviewController::class, 'togglePublish'])->name('reviews.publish'); + Route::get('dashboard', [AdminDashboardController::class, 'index'])->name('dashboard'); + }); +}); +``` + +### Контроллеры +- `FreelancerController` — публичный каталог и профиль +- `ProfileController` — редактирование профиля +- `PortfolioProjectController` — CRUD проектов портфолио +- `ProposalController` — создание и управление заявками +- `ReviewController` — создание/удаление отзывов +- `FreelancerDashboardController` — панель фрилансера +- `AdminUserController`, `AdminSkillController`, `AdminReviewController`, `AdminDashboardController` — админка + +--- + +## 5. Роли, Gates и Policies + +### Роли +| Роль | Описание | +|---|---| +| `admin` | Полный доступ, модерация отзывов, управление пользователями | +| `freelancer` | Управление профилем, портфолио, просмотр входящих заявок, ответы | +| `client` | Создание заявок, просмотр каталога, написание отзывов | + +### Gates + +```php +Gate::define('be-freelancer', function (User $user) { + return in_array($user->role, ['admin', 'freelancer']); +}); + +Gate::define('be-client', function (User $user) { + return in_array($user->role, ['admin', 'client']); +}); + +Gate::define('access-admin-panel', function (User $user) { + return $user->role === 'admin'; +}); +``` + +### Policies + +**PortfolioProjectPolicy:** +- `view` — все (публичное портфолио) +- `create`, `update`, `delete` — только владелец портфолио или admin + +**ProposalPolicy:** +- `create` — client +- `view` — клиент (отправитель), фрилансер (получатель), admin +- `accept`, `reject` — только фрилансер (получатель) + +**ReviewPolicy:** +- `create` — client (после завершения заявки) +- `view` — все (если опубликован), автор или admin (если не опубликован) +- `delete` — автор отзыва или admin + +--- + +## 6. Требования к интерфейсу (Bootstrap 5) + +### Компоненты +- **Навбар** — логотип, каталог фрилансеров, панель (мои заявки / портфолио), профиль +- **Карточки фрилансеров** — аватар (круглый), имя, рейтинг (звёзды), навыки (бейджи) +- **Профиль фрилансера** — большое фото, описание, навыки (бейджи), проекты портфолио (карточки), отзывы +- **Звёздный рейтинг** — интерактивные звёзды (radio buttons + стилизация или простой JS) +- **Карточки проектов портфолио** — изображение, название, описание, технологии (бейджи) +- **Форма заявки** — описание, бюджет (число), срок (дата), требуемые навыки +- **Таблица заявок** — статусы (цветные бейджи), действия (принять/отклонить) +- **Дашборд фрилансера** — статистика (карточки), входящие заявки, рейтинг +- **Адаптивная сетка** — `col-md-4` для карточек, `col-md-3` + `col-md-9` для профиля + +### Цветовая схема статусов заявок +- Новая — `bg-info` +- Принята — `bg-success` +- Отклонена — `bg-danger` +- Завершена — `bg-secondary` + +--- + +## 7. Git-workflow для команды + +### Распределение модулей (для 2 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Профили, навыки, портфолио, каталог | `feature/profiles`, `feature-skills`, `feature-portfolio-crud` | +| **Участник B** | Заявки, отзывы, рейтинги, UI | `feature/proposals`, `feature-proposal-responses`, `feature-proposal-statuses` | + +### Распределение модулей (для 3 человек) + +| Участник | Модуль | Ветки | +|---|---|---| +| **Участник A** | Профили, навыки, портфолио | `feature/profiles`, `feature-skills`, `feature-portfolio-crud` | +| **Участник B** | Заявки, статусы, ответы фрилансера | `feature/proposals`, `feature-proposal-responses`, `feature-proposal-statuses` | +| **Участник C** | Отзывы, рейтинги, каталог фрилансеров, UI | `feature-reviews`, `feature-ratings`, `feature-freelancer-catalog` | + +### Правила +1. Ветка `develop` — основная ветка разработки +2. Каждый участник создаёт фич-ветки от `develop` +3. Минимум 3 PR на участника +4. Обязательный код-ревью перед мёржем +5. Conventional Commits + +### Визуализация workflow (2 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/profiles + checkout develop + branch feature/proposals + checkout feature/profiles + commit id: "feat: add profiles and skills" + commit id: "feat: add portfolio CRUD" + checkout feature/proposals + commit id: "feat: add proposals system" + commit id: "feat: add proposal responses" + checkout develop + merge feature/profiles tag: "PR + review" + merge feature/proposals tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +### Визуализация workflow (3 участника) + +```mermaid +gitGraph + commit id: "init" tag: "v1.0" + branch develop + checkout develop + branch feature/profiles + checkout develop + branch feature/proposals + checkout develop + branch feature-reviews + checkout feature/profiles + commit id: "feat: add profiles and skills" + commit id: "feat: add portfolio images" + checkout feature/proposals + commit id: "feat: add proposals system" + commit id: "feat: add proposal responses" + checkout feature-reviews + commit id: "feat: add reviews and ratings" + commit id: "feat: add freelancer catalog" + checkout develop + merge feature/profiles tag: "PR + review" + merge feature/proposals tag: "PR + review" + merge feature-reviews tag: "PR + review" + checkout main + merge develop tag: "release v1.1" +``` + +--- + +## 8. Критерии приёмки + +### Обязательно +- [ ] Регистрация с выбором роли (фрилансер / клиент) +- [ ] Редактирование профиля с загрузкой аватара +- [ ] CRUD проектов портфолио с изображениями +- [ ] Навыки (многие-ко-многим фрилансер ↔ навыки) +- [ ] Каталог фрилансеров с пагинацией и фильтрацией по навыкам +- [ ] Создание заявки клиентом +- [ ] Фрилансер может принять/отклонить заявку +- [ ] Оставление отзыва клиентом (после завершения заявки) +- [ ] Расчёт среднего рейтинга фрилансера +- [ ] Policies: фрилансер не видит чужие входящие заявки, клиент не может управлять чужими заявками +- [ ] Адаптивная Bootstrap-вёрстка +- [ ] Flash-сообщения +- [ ] Git-история: минимум 3 ветки на участника, PR с ревью + +### Дополнительно (бонусные баллы) +- [ ] Поиск фрилансеров по имени и описанию +- [ ] Несколько изображений в проекте портфолио (галерея) +- [ ] Сортировка фрилансеров по рейтингу, дате регистрации +- [ ] Уведомления (email при новой заявке / ответе) +- [ ] Мягкое удаление отзывов +- [ ] Тесты: PHPUnit Feature-тесты для ProposalController +- [ ] API: RESTful API для каталога фрилансеров + +--- + +## 9. Дополнительные задания (для продвинутых) + +1. **Мессенджер:** встроенный чат между клиентом и фрилансером по заявке +2. **Контракт:** генерация PDF-документа с условиями при принятии заявки +3. **Уведомления:** email и on-site уведомления при новых заявках/ответах/отзывах +4. **Фильтры:** расширенная фильтрация (рейтинг, стоимость, навыки) +5. **Тесты:** PHPUnit Feature-тесты для ReviewController и ProposalController +6. **API:** RESTful API для каталога фрилансеров и создания заявок +7. **Queue:** асинхронная отправка email-уведомлений + +--- + +## 10. Рекомендуемые материалы + +- Laravel Docs: https://laravel.com/docs/12.x +- Laravel Many-to-Many: https://laravel.com/docs/12.x/eloquent-relationships#many-to-many +- Laravel File Uploads: https://laravel.com/docs/12.x/filesystem#file-uploads +- Bootstrap 5 Cards: https://getbootstrap.com/docs/5.3/components/card/ +- Laravel Policies: https://laravel.com/docs/12.x/authorization#creating-policies