# Техническое задание: Система помощи питомцам (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