433 lines
22 KiB
Markdown
433 lines
22 KiB
Markdown
# Техническое задание: Система помощи питомцам (Pet Shelter Management)
|
||
|
||
## 1. Описание проекта
|
||
|
||
Веб-платформа для приюта животных: каталог питомцев, заявки на усыновление, управление волонтёрами и историями лечения. Проект закрепляет навыки CRUD, загрузки файлов, статусных переходов, разграничения прав и совместной работы через Git.
|
||
|
||
**Команда:** 2–3 человека
|
||
|
||
---
|
||
|
||
## 2. Функциональные требования
|
||
|
||
### 2.1. Аутентификация и регистрация
|
||
- Регистрация, вход, выход (Laravel Breeze)
|
||
|
||
### 2.2. Каталог питомцев
|
||
- Просмотр списка питомцев с пагинацией
|
||
- Фильтрация по видам (кошки, собаки, грызуны, птицы, рептилии)
|
||
- Поиск по кличке, породе
|
||
- Детальная страница питомца (фото, описание, вид, порода, возраст, пол, статус, истории лечения)
|
||
|
||
### 2.3. Управление питомцами (волонтёр/админ)
|
||
- CRUD питомцев: кличка, вид, порода, возраст (примерный), пол, описание, фото (до 3), статус (доступен для усыновления, на лечении, усыновлён)
|
||
- Загрузка фотографий питомца (валидация: jpg/png, макс. 2MB на каждое фото)
|
||
- Особенности характера (свободный текст или теги)
|
||
|
||
### 2.4. Категории питомцев
|
||
- CRUD категорий (видов): кошки, собаки, грызуны, птицы, рептилии
|
||
- Описание вида, особенности содержания
|
||
|
||
### 2.5. Заявки на усыновление
|
||
- Форма заявки: данные заявителя (ФИО, телефон, email, адрес), опыт содержания, цель усыновления, условия содержания
|
||
- Привязка заявки к питомцу
|
||
- Статусы заявки: новая, на рассмотрении, одобрена, отклонена, завершена
|
||
- Волонтёр меняет статус заявки (новая → на рассмотрении → одобрена/отклонена)
|
||
- При одобрении — питомец получает статус «усыновлён»
|
||
- При отклонении — комментарий с причиной
|
||
|
||
### 2.6. Волонтёры
|
||
- Профиль волонтёра: имя, телефон, email, дата начала волонтёрства, статус (активен/неактивен)
|
||
- Расписание волонтёра: дата, время, тип деятельности (выгул, кормление, уборка)
|
||
- CRUD расписания (волонтёр создаёт свои смены)
|
||
|
||
### 2.7. Истории питомцев
|
||
- Записи о здоровье питомца: дата, описание (лечение, вакцинация, осмотр, операция)
|
||
- Привязка к питомцу
|
||
- Хронология на странице питомца
|
||
|
||
### 2.8. Панель волонтёра
|
||
- Мои питомцы (за которыми закреплён)
|
||
- Входящие заявки на усыновление (управление статусами)
|
||
- Моё расписание
|
||
- Добавление историй питомцев
|
||
|
||
### 2.9. Панель потенциального хозяина
|
||
- Каталог питомцев
|
||
- Мои заявки на усыновление (статусы)
|
||
- Создание новой заявки
|
||
|
||
### 2.10. Панель администратора
|
||
- Управление пользователями и ролями
|
||
- Управление категориями питомцев
|
||
- Модерация заявок
|
||
- Общая статистика приюта
|
||
|
||
---
|
||
|
||
## 3. Структура базы данных
|
||
|
||
### Таблица `users`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | BIGINT UNSIGNED | Первичный ключ |
|
||
| name | VARCHAR(255) | Имя |
|
||
| email | VARCHAR(255) | Email (unique) |
|
||
| password | VARCHAR(255) | Хеш пароля |
|
||
| role | ENUM('admin', 'volunteer', 'adopter') | Роль |
|
||
| phone | VARCHAR(20) \| NULL | Телефон |
|
||
| avatar | VARCHAR(255) \| NULL | Аватар |
|
||
| volunteer_start_date | DATE \| NULL | Дата начала волонтёрства (для волонтёров) |
|
||
| is_active | BOOLEAN | Активен ли (для волонтёров) |
|
||
| created_at | TIMESTAMP | |
|
||
| updated_at | TIMESTAMP | |
|
||
|
||
### Таблица `pet_categories`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | BIGINT UNSIGNED | Первичный ключ |
|
||
| name | VARCHAR(255) | Название вида (кошки, собаки, ...) |
|
||
| slug | VARCHAR(255) | URL-идентификатор (unique) |
|
||
| description | TEXT \| NULL | Описание вида |
|
||
| created_at | TIMESTAMP | |
|
||
| updated_at | TIMESTAMP | |
|
||
|
||
### Таблица `pets`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | BIGINT UNSIGNED | Первичный ключ |
|
||
| name | VARCHAR(255) | Кличка питомца |
|
||
| slug | VARCHAR(255) | URL-идентификатор (unique) |
|
||
| species_id | BIGINT UNSIGNED | Вид (FK → pet_categories) |
|
||
| breed | VARCHAR(255) \| NULL | Порода |
|
||
| age_estimate | VARCHAR(50) | Примерный возраст (например, «2 года», «6 месяцев») |
|
||
| gender | ENUM('male', 'female') | Пол |
|
||
| description | TEXT | Описание, особенности характера |
|
||
| status | ENUM('available', 'treatment', 'adopted', 'reserved') | Статус |
|
||
| created_at | TIMESTAMP | |
|
||
| updated_at | TIMESTAMP | |
|
||
|
||
### Таблица `pet_photos`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | BIGINT UNSIGNED | Первичный ключ |
|
||
| pet_id | BIGINT UNSIGNED | FK → pets |
|
||
| photo_path | VARCHAR(255) | Путь к изображению |
|
||
| is_primary | BOOLEAN | Главное фото (true/false) |
|
||
| created_at | TIMESTAMP | |
|
||
| updated_at | TIMESTAMP | |
|
||
|
||
### Таблица `adoption_applications`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | BIGINT UNSIGNED | Первичный ключ |
|
||
| pet_id | BIGINT UNSIGNED | Питомец (FK → pets) |
|
||
| applicant_id | BIGINT UNSIGNED | Заявитель (FK → users) |
|
||
| full_name | VARCHAR(255) | ФИО заявителя |
|
||
| phone | VARCHAR(20) | Телефон |
|
||
| email | VARCHAR(255) | Email |
|
||
| address | TEXT | Адрес проживания |
|
||
| experience | TEXT | Опыт содержания животных |
|
||
| purpose | TEXT | Цель усыновления |
|
||
| living_conditions | TEXT | Условия содержания |
|
||
| status | ENUM('new', 'under_review', 'approved', 'rejected', 'completed') | Статус |
|
||
| rejection_reason | TEXT \| NULL | Причина отклонения |
|
||
| volunteer_notes | TEXT \| NULL | Заметки волонтёра |
|
||
| created_at | TIMESTAMP | |
|
||
| updated_at | TIMESTAMP | |
|
||
|
||
### Таблица `volunteer_schedules`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | BIGINT UNSIGNED | Первичный ключ |
|
||
| volunteer_id | BIGINT UNSIGNED | Волонтёр (FK → users) |
|
||
| pet_id | BIGINT UNSIGNED \| NULL | Питомец (FK → pets), NULL если общая смена |
|
||
| schedule_date | DATE | Дата смены |
|
||
| start_time | TIME | Время начала |
|
||
| end_time | TIME | Время окончания |
|
||
| activity_type | ENUM('walking', 'feeding', 'cleaning', 'grooming', 'other') | Тип деятельности |
|
||
| notes | TEXT \| NULL | Заметки |
|
||
| created_at | TIMESTAMP | |
|
||
| updated_at | TIMESTAMP | |
|
||
|
||
### Таблица `pet_histories`
|
||
| Поле | Тип | Описание |
|
||
|---|---|---|
|
||
| id | BIGINT UNSIGNED | Первичный ключ |
|
||
| pet_id | BIGINT UNSIGNED | FK → pets |
|
||
| history_date | DATE | Дата записи |
|
||
| type | ENUM('vaccination', 'treatment', 'examination', 'surgery', 'other') | Тип записи |
|
||
| description | TEXT | Описание |
|
||
| veterinarian | VARCHAR(255) \| NULL | Ветеринар |
|
||
| created_by | BIGINT UNSIGNED | Создатель записи (FK → users) |
|
||
| created_at | TIMESTAMP | |
|
||
| updated_at | TIMESTAMP | |
|
||
|
||
---
|
||
|
||
## 4. Маршруты и контроллеры
|
||
|
||
```php
|
||
// Публичные маршруты
|
||
Route::get('/', [PetController::class, 'index'])->name('pets.index');
|
||
Route::get('/pets/{pet:slug}', [PetController::class, 'show'])->name('pets.show');
|
||
|
||
// Аутентифицированные маршруты
|
||
Route::middleware('auth')->group(function () {
|
||
// Заявки на усыновление
|
||
Route::prefix('applications')->name('applications.')->group(function () {
|
||
Route::post('/apply/{pet}', [ApplicationController::class, 'store'])->name('apply');
|
||
Route::get('/my-applications', [ApplicationController::class, 'myApplications'])->name('my');
|
||
Route::get('/{application}', [ApplicationController::class, 'show'])->name('show');
|
||
});
|
||
|
||
// Расписание волонтёра
|
||
Route::prefix('volunteer')->name('volunteer.')->middleware('can:be-volunteer')->group(function () {
|
||
Route::resource('schedules', VolunteerScheduleController::class);
|
||
Route::get('dashboard', [VolunteerDashboardController::class, 'index'])->name('dashboard');
|
||
});
|
||
|
||
// Управление питомцами (волонтёр/админ)
|
||
Route::prefix('shelter')->name('shelter.')->middleware('can:manage-pets')->group(function () {
|
||
Route::resource('pets', ShelterPetController::class);
|
||
Route::resource('pets.photos', PetPhotoController::class)->scoped(['pets' => 'pet']);
|
||
Route::resource('pets.histories', PetHistoryController::class)->scoped(['pets' => 'pet']);
|
||
|
||
// Управление заявками
|
||
Route::get('applications', [ShelterApplicationController::class, 'index'])->name('applications.index');
|
||
Route::get('applications/{application}', [ShelterApplicationController::class, 'show'])->name('applications.show');
|
||
Route::post('applications/{application}/review', [ShelterApplicationController::class, 'startReview'])->name('applications.review');
|
||
Route::post('applications/{application}/approve', [ShelterApplicationController::class, 'approve'])->name('applications.approve');
|
||
Route::post('applications/{application}/reject', [ShelterApplicationController::class, 'reject'])->name('applications.reject');
|
||
Route::post('applications/{application}/complete', [ShelterApplicationController::class, 'complete'])->name('applications.complete');
|
||
});
|
||
|
||
// Админка
|
||
Route::prefix('admin')->name('admin.')->middleware('can:access-admin-panel')->group(function () {
|
||
Route::resource('users', AdminUserController::class);
|
||
Route::resource('categories', AdminCategoryController::class);
|
||
Route::get('dashboard', [AdminDashboardController::class, 'index'])->name('dashboard');
|
||
});
|
||
});
|
||
```
|
||
|
||
### Контроллеры
|
||
- `PetController` — публичный каталог и детальный просмотр
|
||
- `ApplicationController` — подача и просмотр своих заявок
|
||
- `VolunteerScheduleController` — CRUD расписания волонтёра
|
||
- `ShelterPetController` — CRUD питомцев (волонтёр/админ)
|
||
- `PetPhotoController` — загрузка/удаление фото питомца
|
||
- `PetHistoryController` — CRUD историй питомца
|
||
- `ShelterApplicationController` — управление заявками (смена статусов)
|
||
- `VolunteerDashboardController`, `AdminUserController`, `AdminCategoryController`, `AdminDashboardController` — панели
|
||
|
||
---
|
||
|
||
## 5. Роли, Gates и Policies
|
||
|
||
### Роли
|
||
| Роль | Описание |
|
||
|---|---|
|
||
| `admin` | Полный доступ, управление пользователями, категориями, модерация |
|
||
| `volunteer` | Управление питомцами, заявками, расписанием, историями питомцев |
|
||
| `adopter` | Просмотр каталога, подача заявок на усыновление, просмотр своих заявок |
|
||
|
||
### Gates
|
||
|
||
```php
|
||
Gate::define('be-volunteer', function (User $user) {
|
||
return in_array($user->role, ['admin', 'volunteer']);
|
||
});
|
||
|
||
Gate::define('manage-pets', function (User $user) {
|
||
return in_array($user->role, ['admin', 'volunteer']);
|
||
});
|
||
|
||
Gate::define('access-admin-panel', function (User $user) {
|
||
return $user->role === 'admin';
|
||
});
|
||
```
|
||
|
||
### Policies
|
||
|
||
**PetPolicy:**
|
||
- `view` — все (публичный каталог)
|
||
- `create`, `update`, `delete` — volunteer или admin
|
||
|
||
**PetPhotoPolicy:**
|
||
- `create`, `delete` — volunteer или admin
|
||
|
||
**PetHistoryPolicy:**
|
||
- `create`, `update`, `delete` — volunteer или admin
|
||
- `view` — все
|
||
|
||
**AdoptionApplicationPolicy:**
|
||
- `create` — adopter (не подавал одобренную заявку на этого питомца)
|
||
- `view` — заявитель, волонтёр/admin
|
||
- `review`, `approve`, `reject`, `complete` — volunteer или admin
|
||
|
||
**VolunteerSchedulePolicy:**
|
||
- `create`, `update`, `delete` — владелец расписания (волонтёр) или admin
|
||
- `view` — volunteer или admin
|
||
|
||
---
|
||
|
||
## 6. Требования к интерфейсу (Bootstrap 5)
|
||
|
||
### Компоненты
|
||
- **Навбар** — логотип, каталог питомцев, «Мои заявки», панель волонтёра, профиль
|
||
- **Карточки питомцев** — главное фото, кличка, вид (бейдж), порода, возраст, статус (бейдж)
|
||
- **Страница питомца** — галерея фото (карусель или грид), описание, характеристики, кнопка «Усыновить», истории питомца (хронология)
|
||
- **Карусель фото** — Bootstrap Carousel для галереи питомца
|
||
- **Форма заявки** — Bootstrap-форма с валидацией, textarea для опыта и условий
|
||
- **Таблица заявок** — питомец, заявитель, статус (цветные бейджи), действия
|
||
- **Календарь/таблица расписания** — дата, время, тип деятельности
|
||
- **Хронология историй** — вертикальный timeline (Bootstrap + кастомные стили)
|
||
- **Дашборд волонтёра** — статистика (карточки), входящие заявки, ближайшее расписание
|
||
- **Адаптивная сетка** — `col-md-4` для карточек, `col-md-8` + `col-md-4` для основного контента
|
||
|
||
### Цветовая схема статусов питомца
|
||
- Доступен — `bg-success`
|
||
- На лечении — `bg-warning`
|
||
- Усыновлён — `bg-primary`
|
||
- Зарезервирован — `bg-info`
|
||
|
||
### Цветовая схема статусов заявки
|
||
- Новая — `bg-info`
|
||
- На рассмотрении — `bg-warning`
|
||
- Одобрена — `bg-success`
|
||
- Отклонена — `bg-danger`
|
||
- Завершена — `bg-secondary`
|
||
|
||
---
|
||
|
||
## 7. Git-workflow для команды
|
||
|
||
### Распределение модулей (для 2 человек)
|
||
|
||
| Участник | Модуль | Ветки |
|
||
|---|---|---|
|
||
| **Участник A** | Питомцы, категории, фото, заявки на усыновление | `feature/pets-crud`, `feature-categories`, `feature-pet-photos` |
|
||
| **Участник B** | Расписание волонтёра, истории, дашборд, UI | `feature/applications`, `feature-application-statuses`, `feature-approval-flow` |
|
||
|
||
### Распределение модулей (для 3 человек)
|
||
|
||
| Участник | Модуль | Ветки |
|
||
|---|---|---|
|
||
| **Участник A** | Питомцы, категории, загрузка фото, каталог | `feature/pets-crud`, `feature-categories`, `feature-pet-photos` |
|
||
| **Участник B** | Заявки на усыновление, статусные переходы | `feature/applications`, `feature-application-statuses`, `feature-approval-flow` |
|
||
| **Участник C** | Расписание волонтёра, истории питомцев, UI, дашборд | `feature-volunteer-schedules`, `feature-pet-histories`, `feature-dashboard-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/pets-crud
|
||
checkout develop
|
||
branch feature/applications
|
||
checkout feature/pets-crud
|
||
commit id: "feat: add pets CRUD"
|
||
commit id: "feat: add pet photos"
|
||
checkout feature/applications
|
||
commit id: "feat: add adoption applications"
|
||
commit id: "feat: add application statuses"
|
||
checkout develop
|
||
merge feature/pets-crud tag: "PR + review"
|
||
merge feature/applications 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/pets-crud
|
||
checkout develop
|
||
branch feature/applications
|
||
checkout develop
|
||
branch feature-volunteer-schedules
|
||
checkout feature/pets-crud
|
||
commit id: "feat: add pets CRUD"
|
||
commit id: "feat: add pet categories"
|
||
checkout feature/applications
|
||
commit id: "feat: add adoption applications"
|
||
commit id: "feat: add application statuses"
|
||
checkout feature-volunteer-schedules
|
||
commit id: "feat: add volunteer schedules"
|
||
commit id: "feat: add pet histories"
|
||
checkout develop
|
||
merge feature/pets-crud tag: "PR + review"
|
||
merge feature/applications tag: "PR + review"
|
||
merge feature-volunteer-schedules tag: "PR + review"
|
||
checkout main
|
||
merge develop tag: "release v1.1"
|
||
```
|
||
|
||
---
|
||
|
||
## 8. Критерии приёмки
|
||
|
||
### Обязательно
|
||
- [ ] CRUD питомцев с загрузкой фото (до 3 фото на питомца)
|
||
- [ ] CRUD категорий питомцев
|
||
- [ ] Каталог питомцев с пагинацией и фильтрацией по видам
|
||
- [ ] Подача заявки на усыновление (форма с валидацией всех полей)
|
||
- [ ] Просмотр своих заявок (заявитель)
|
||
- [ ] Управление статусами заявок волонтёром (новая → на рассмотрении → одобрена/отклонена)
|
||
- [ ] При одобрении заявки — обновление статуса питомца на «adopted»
|
||
- [ ] При отклонении — обязательная причина
|
||
- [ ] CRUD расписания волонтёра
|
||
- [ ] CRUD историй питомцев (лечение, вакцинация, осмотр)
|
||
- [ ] Панель волонтёра (мои питомцы, заявки, расписание)
|
||
- [ ] Policies: adoptter не может управлять питомцами или заявками
|
||
- [ ] Адаптивная Bootstrap-вёрстка
|
||
- [ ] Flash-сообщения
|
||
- [ ] Git-история: минимум 3 ветки на участника, PR с ревью
|
||
|
||
### Дополнительно (бонусные баллы)
|
||
- [ ] Поиск питомцев по кличке и породе
|
||
- [ ] Фильтрация по возрасту и полу
|
||
- [ ] Галерея фото (Bootstrap Carousel)
|
||
- [ ] Экспорт расписания волонтёра в PDF
|
||
- [ ] Уведомления (email при изменении статуса заявки)
|
||
- [ ] Мягкое удаление питомцев и историй
|
||
- [ ] Тесты: PHPUnit Feature-тесты для ApplicationController
|
||
- [ ] API: RESTful API для каталога питомцев
|
||
|
||
---
|
||
|
||
## 9. Дополнительные задания (для продвинутых)
|
||
|
||
1. **Уведомления:** email заявителю при изменении статуса заявки
|
||
2. **Совместимость:** рекомендации питомцев заявителю на основе его опыта и условий
|
||
3. **Статистика приюта:** дашборд с графиками (Chart.js) — усыновления по месяцам, популярные виды
|
||
4. **Тесты:** PHPUnit Feature-тесты для статусных переходов заявок
|
||
5. **API:** RESTful API для каталога питомцев и подачи заявок
|
||
6. **Queue:** асинхронная отправка email-уведомлений
|
||
7. **Events & Listeners:** событие «заявка одобрена» → обновление статуса питомца + email
|
||
|
||
---
|
||
|
||
## 10. Рекомендуемые материалы
|
||
|
||
- Laravel Docs: https://laravel.com/docs/12.x
|
||
- Laravel File Uploads (multiple): https://laravel.com/docs/12.x/filesystem#file-uploads
|
||
- Bootstrap 5 Carousel: https://getbootstrap.com/docs/5.3/components/carousel/
|
||
- Bootstrap 5 Badges: https://getbootstrap.com/docs/5.3/components/badge/
|
||
- Laravel Policies: https://laravel.com/docs/12.x/authorization#creating-policies
|
||
- State Machines (статусные переходы): https://github.com/brentroose/laravel-state-machine
|