Загрузить файлы в «/»
commit
d86abfe469
|
|
@ -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/
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
Loading…
Reference in New Issue