Загрузить файлы в «/»

main
MadHowl 2026-04-08 04:59:08 +00:00
commit d86abfe469
5 changed files with 1843 additions and 0 deletions

336
task01-task-manager.md Normal file
View File

@ -0,0 +1,336 @@
# Техническое задание: Система управления задачами (Task Manager)
## 1. Описание проекта
Веб-приложение для управления личными и командными задачами с возможностью назначения исполнителей, отслеживания статусаов и приоритетов. Проект закрепляет навыки CRUD, разграничения прав через Roles/Gates/Policies, совместной работы через Git.
**Команда:** 23 человека
---
## 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/

376
task02-online-store.md Normal file
View File

@ -0,0 +1,376 @@
# Техническое задание: Онлайн-магазин с корзиной
## 1. Описание проекта
Веб-приложение интернет-магазина с каталогом товаров, корзиной покупок и оформлением заказов. Проект закрепляет навыки CRUD, работы с отношениями многие-ко-многим, загрузки изображений, разграничения прав и совместной работы через Git.
**Команда:** 23 человека
---
## 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. **Отзывы к товарам:** рейтинг 15 + текст, модерация
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

410
task03-online-courses.md Normal file
View File

@ -0,0 +1,410 @@
# Техническое задание: Платформа для онлайн-курсов
## 1. Описание проекта
Веб-платформа для публикации и прохождения онлайн-курсов с отслеживанием прогресса студентов и системой тестирования. Проект закрепляет навыки CRUD, вложенных сущностей (курс → уроки → тесты), разграничения прав и совместной работы через Git.
**Команда:** 23 человека
---
## 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 | Прогресс в процентах (0100) |
| 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. **Рейтинг курсов:** студенты оценивают курс после завершения (15 звёзд)
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

337
task04-booking-system.md Normal file
View File

@ -0,0 +1,337 @@
# Техническое задание: Система бронирования помещений и оборудования
## 1. Описание проекта
Веб-приложение для бронирования конференц-залов, рабочих мест или оборудования с календарём, подтверждением заявок и управлением расписанием. Проект закрепляет навыки CRUD, валидации дат и времени, разграничения прав и совместной работы через Git.
**Команда:** 23 человека
---
## 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

View File

@ -0,0 +1,384 @@
# Техническое задание: Портфолио-платформа для фрилансеров
## 1. Описание проекта
Веб-сервис для публикации портфолио фрилансеров, поиска заказов и обмена отзывами. Проект закрепляет навыки CRUD, работы с рейтингами и отзывами, разграничения прав и совместной работы через Git.
**Команда:** 23 человека
---
## 2. Функциональные требования
### 2.1. Аутентификация и регистрация
- Регистрация, вход, выход (Laravel Breeze)
- При регистрации выбирается роль: фрилансер или клиент
### 2.2. Профиль фрилансера
- Публичный профиль: имя, фото, описание, навыки, контакты, рейтинг
- Редактирование профиля (только владелец)
- Загрузка аватара (валидация: jpg/png, макс. 2MB)
- Список навыков (свободный ввод или выбор из тегов)
### 2.3. Портфолио-проекты
- CRUD проектов в портфолио: название, описание, изображения (до 5), технологии/навыки, ссылка на проект
- Привязка проекта к навыкам (многие-ко-многим)
- Публичный просмотр на странице профиля
- Сортировка по дате, рейтингу
### 2.4. Каталог фрилансеров
- Просмотр списка фрилансеров с пагинацией
- Фильтрация по навыкам/категориям услуг
- Поиск по имени и описанию
- Карточка фрилансера (аватар, имя, рейтинг, основные навыки)
### 2.5. Заявки на проекты (клиент → фрилансер)
- Клиент создаёт заявку: описание проекта, бюджет, срок, требуемые навыки
- Привязка заявки к фрилансеру
- Фрилансер видит входящие заявки
- Фрилансер отвечает на заявку (принять / отклонить с комментарием)
- Статусы заявки: новая, принята, отклонена, завершена
### 2.6. Отзывы и рейтинги
- Клиент оставляет отзыв фрилансеру после завершения заявки
- Поля отзыва: текст, рейтинг (15 звёзд)
- Средний рейтинг фрилансера (автоматический пересчёт)
- Отзывы отображаются на странице профиля
### 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.005.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 | Рейтинг (15) |
| 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