379 lines
12 KiB
Markdown
379 lines
12 KiB
Markdown
# Тестовое задание: Система управления сотрудниками
|
||
|
||
## Описание задачи
|
||
|
||
Необходимо разработать с нуля полнофункциональную систему управления сотрудниками компании. Система должна позволять добавлять, редактировать, удалять сотрудников, а также управлять их расписанием и просматривать статистику.
|
||
|
||
## Технический стек
|
||
|
||
- **Frontend**: Next.js 15+ (App Router)
|
||
- **Backend**: GraphQL с Apollo Server
|
||
- **Database**: PostgreSQL с Prisma ORM
|
||
- **Styling**: TailwindCSS с glassmorphism эффектами
|
||
- **UI Components**: Radix UI (через shadcn/ui)
|
||
- **TypeScript**: строгая типизация
|
||
- **Icons**: Lucide React
|
||
- **Notifications**: Sonner
|
||
|
||
## Дизайн-система и стили
|
||
|
||
### Цветовая схема
|
||
- Основные цвета: оттенки фиолетового (oklch(0.75 0.32 315) до oklch(0.68 0.28 280))
|
||
- Фон: тёмный градиент `bg-gradient-smooth`
|
||
- Карточки: стеклянный эффект `glass-card`
|
||
- Текст: белый и оттенки белого/серого
|
||
|
||
### Glassmorphism стили
|
||
```css
|
||
.glass-card {
|
||
background: rgba(255, 255, 255, 0.12);
|
||
backdrop-filter: blur(20px);
|
||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||
box-shadow:
|
||
0 8px 32px rgba(168, 85, 247, 0.18),
|
||
0 4px 16px rgba(147, 51, 234, 0.12),
|
||
inset 0 1px 0 rgba(255, 255, 255, 0.3);
|
||
}
|
||
|
||
.glass-card:hover {
|
||
background: rgba(255, 255, 255, 0.15);
|
||
border: 1px solid rgba(255, 255, 255, 0.3);
|
||
box-shadow:
|
||
0 12px 40px rgba(168, 85, 247, 0.25),
|
||
0 6px 20px rgba(147, 51, 234, 0.18);
|
||
}
|
||
```
|
||
|
||
### Анимации
|
||
- Плавные переходы (0.3s ease)
|
||
- Hover-эффекты с изменением opacity и shadow
|
||
- Анимация появления форм
|
||
- Интерактивные элементы с transform
|
||
|
||
## Структура базы данных
|
||
|
||
```prisma
|
||
model Employee {
|
||
id String @id @default(cuid())
|
||
firstName String
|
||
lastName String
|
||
middleName String?
|
||
birthDate DateTime?
|
||
avatar String?
|
||
passportPhoto String?
|
||
passportSeries String?
|
||
passportNumber String?
|
||
passportIssued String?
|
||
passportDate DateTime?
|
||
address String?
|
||
position String
|
||
department String?
|
||
hireDate DateTime
|
||
salary Float?
|
||
status EmployeeStatus @default(ACTIVE)
|
||
phone String
|
||
email String?
|
||
telegram String?
|
||
whatsapp String?
|
||
emergencyContact String?
|
||
emergencyPhone String?
|
||
organizationId String
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
scheduleRecords EmployeeSchedule[]
|
||
organization Organization @relation(fields: [organizationId], references: [id])
|
||
}
|
||
|
||
model EmployeeSchedule {
|
||
id String @id @default(cuid())
|
||
date DateTime
|
||
status ScheduleStatus
|
||
hoursWorked Float?
|
||
notes String?
|
||
employeeId String
|
||
createdAt DateTime @default(now())
|
||
updatedAt DateTime @updatedAt
|
||
employee Employee @relation(fields: [employeeId], references: [id])
|
||
}
|
||
|
||
enum EmployeeStatus {
|
||
ACTIVE
|
||
VACATION
|
||
SICK
|
||
FIRED
|
||
}
|
||
|
||
enum ScheduleStatus {
|
||
WORK
|
||
WEEKEND
|
||
VACATION
|
||
SICK
|
||
ABSENT
|
||
}
|
||
```
|
||
|
||
## Функциональные требования
|
||
|
||
### 1. Основная страница сотрудников (/employees)
|
||
|
||
**Макет страницы:**
|
||
- Sidebar слева (аналогично dashboard)
|
||
- Основной контент справа
|
||
- Поиск по ФИО, телефону, должности
|
||
- Табы: "Сотрудники", "Расписание", "Статистика"
|
||
|
||
**Таб "Сотрудники":**
|
||
- Карточки сотрудников в grid layout (3-4 в ряд)
|
||
- Каждая карточка содержит:
|
||
- Аватар (или инициалы, если нет фото)
|
||
- ФИО
|
||
- Должность
|
||
- Телефон
|
||
- Email (если есть)
|
||
- Статус (бейдж с цветом)
|
||
- Кнопки: "Редактировать", "Уволить"
|
||
- Кнопка "Добавить сотрудника" вверху
|
||
- Фильтры по статусу
|
||
- Пагинация при большом количестве
|
||
|
||
### 2. Добавление сотрудника
|
||
|
||
**Inline форма (появляется как первая карточка):**
|
||
- Обязательные поля:
|
||
- Имя, Фамилия
|
||
- Должность
|
||
- Дата приёма
|
||
- Телефон
|
||
- Необязательные поля:
|
||
- Отчество
|
||
- Email
|
||
- Дата рождения
|
||
- Адрес
|
||
- Оклад
|
||
- Паспортные данные
|
||
- Контакты для экстренной связи
|
||
- Telegram/WhatsApp
|
||
- Загрузка аватара
|
||
- Валидация всех полей
|
||
- Красивые маски ввода (телефон, паспорт, ЗП)
|
||
|
||
### 3. Редактирование сотрудника
|
||
|
||
**Inline редактирование:**
|
||
- Форма заменяет карточку сотрудника
|
||
- Все те же поля, что при создании
|
||
- Предзаполненные данные
|
||
- Возможность изменить статус
|
||
- Кнопки "Сохранить" / "Отмена"
|
||
|
||
### 4. Управление расписанием
|
||
|
||
**Таб "Расписание":**
|
||
- Календарь на месяц
|
||
- Выбор сотрудника из dropdown
|
||
- Отметки на каждый день:
|
||
- Работа (зелёный)
|
||
- Выходной (серый)
|
||
- Отпуск (синий)
|
||
- Больничный (жёлтый)
|
||
- Прогул (красный)
|
||
- Возможность массово отметить период
|
||
- Подсчёт отработанных часов/дней
|
||
|
||
### 5. Статистика
|
||
|
||
**Таб "Статистика":**
|
||
- Общее количество сотрудников
|
||
- Распределение по статусам
|
||
- Средний возраст
|
||
- Средняя зарплата
|
||
- График найма по месяцам
|
||
- Топ-должности
|
||
- Статистика посещаемости
|
||
|
||
## GraphQL API
|
||
|
||
### Queries
|
||
```graphql
|
||
type Query {
|
||
employees: [Employee!]!
|
||
employee(id: ID!): Employee
|
||
employeeSchedule(employeeId: ID!, year: Int!, month: Int!): [EmployeeSchedule!]!
|
||
employeeStats: EmployeeStats!
|
||
}
|
||
```
|
||
|
||
### Mutations
|
||
```graphql
|
||
type Mutation {
|
||
createEmployee(input: CreateEmployeeInput!): CreateEmployeeResponse!
|
||
updateEmployee(id: ID!, input: UpdateEmployeeInput!): UpdateEmployeeResponse!
|
||
deleteEmployee(id: ID!): Boolean!
|
||
updateEmployeeSchedule(input: UpdateScheduleInput!): Boolean!
|
||
}
|
||
```
|
||
|
||
### Types
|
||
```graphql
|
||
type Employee {
|
||
id: ID!
|
||
firstName: String!
|
||
lastName: String!
|
||
middleName: String
|
||
birthDate: DateTime
|
||
avatar: String
|
||
position: String!
|
||
department: String
|
||
hireDate: DateTime!
|
||
salary: Float
|
||
status: EmployeeStatus!
|
||
phone: String!
|
||
email: String
|
||
telegram: String
|
||
whatsapp: String
|
||
emergencyContact: String
|
||
emergencyPhone: String
|
||
createdAt: DateTime!
|
||
updatedAt: DateTime!
|
||
scheduleRecords: [EmployeeSchedule!]!
|
||
}
|
||
```
|
||
|
||
## Требования к реализации
|
||
|
||
### 1. Файловая структура
|
||
```
|
||
src/
|
||
├── app/
|
||
│ └── employees/
|
||
│ └── page.tsx
|
||
├── components/
|
||
│ └── employees/
|
||
│ ├── employees-dashboard.tsx
|
||
│ ├── employee-card.tsx
|
||
│ ├── employee-form.tsx
|
||
│ ├── employee-schedule.tsx
|
||
│ └── employee-stats.tsx
|
||
├── graphql/
|
||
│ ├── queries.ts
|
||
│ ├── mutations.ts
|
||
│ ├── typedefs.ts
|
||
│ └── resolvers.ts
|
||
└── lib/
|
||
├── validations.ts
|
||
└── input-masks.ts
|
||
```
|
||
|
||
### 2. Компоненты
|
||
|
||
**EmployeesDashboard** - основной контейнер:
|
||
- Управление состоянием
|
||
- GraphQL операции
|
||
- Переключение между табами
|
||
|
||
**EmployeeCard** - карточка сотрудника:
|
||
- Отображение информации
|
||
- Кнопки действий
|
||
- Анимации hover
|
||
|
||
**EmployeeForm** - форма создания/редактирования:
|
||
- Валидация полей
|
||
- Маски ввода
|
||
- Загрузка файлов
|
||
- Обработка ошибок
|
||
|
||
**EmployeeSchedule** - календарь:
|
||
- Интерактивный календарь
|
||
- Управление статусами дней
|
||
- Подсчёт статистики
|
||
|
||
### 3. Требования к UX/UI
|
||
|
||
**Интерактивность:**
|
||
- Плавные анимации при hover
|
||
- Loading состояния для всех операций
|
||
- Оптимистичные обновления
|
||
- Toast уведомления об успехе/ошибке
|
||
|
||
**Адаптивность:**
|
||
- Корректное отображение на мобильных устройствах
|
||
- Responsive grid для карточек
|
||
- Адаптивная форма
|
||
|
||
**Доступность:**
|
||
- Поддержка клавиатурной навигации
|
||
- ARIA атрибуты
|
||
- Семантическая разметка
|
||
|
||
### 4. Валидация
|
||
|
||
**Клиентская валидация:**
|
||
- Обязательные поля
|
||
- Форматы email, телефона
|
||
- Валидные даты
|
||
- Паспортные данные
|
||
|
||
**Серверная валидация:**
|
||
- Дублирование всех проверок
|
||
- Уникальность телефона
|
||
- Проверка существования сотрудника
|
||
|
||
### 5. Обработка ошибок
|
||
|
||
- Graceful обработка всех ошибок API
|
||
- Понятные сообщения пользователю
|
||
- Retry механизм для сетевых ошибок
|
||
- Fallback состояния
|
||
|
||
## Дополнительные фичи (nice to have)
|
||
|
||
1. **Экспорт данных** - выгрузка списка сотрудников в Excel/PDF
|
||
2. **Массовые операции** - выбор нескольких сотрудников для действий
|
||
3. **Фильтры** - по отделу, статусу, дате приёма
|
||
4. **Сортировка** - по ФИО, дате приёма, зарплате
|
||
5. **История изменений** - лог всех изменений сотрудника
|
||
6. **Интеграция с мессенджерами** - отправка уведомлений
|
||
|
||
## Критерии оценки
|
||
|
||
### Обязательно (must have):
|
||
- ✅ Все основные функции работают
|
||
- ✅ Соответствие дизайн-системе
|
||
- ✅ Чистый и понятный код
|
||
- ✅ TypeScript без any
|
||
- ✅ Обработка ошибок
|
||
- ✅ Валидация данных
|
||
- ✅ Адаптивная вёрстка
|
||
|
||
### Дополнительные баллы:
|
||
- ⭐ Оптимизация производительности
|
||
- ⭐ Тесты (unit/integration)
|
||
- ⭐ Документация API
|
||
- ⭐ Инновационные решения UX
|
||
- ⭐ Дополнительные фичи
|
||
|
||
## Ресурсы
|
||
|
||
### Дизайн-референсы:
|
||
- Glassmorphism: https://css.glass/
|
||
- UI Patterns: https://ui-patterns.com/
|
||
|
||
### Технические ресурсы:
|
||
- Next.js App Router: https://nextjs.org/docs
|
||
- Prisma: https://www.prisma.io/docs
|
||
- Apollo GraphQL: https://www.apollographql.com/docs
|
||
- shadcn/ui: https://ui.shadcn.com/
|
||
|
||
## Дедлайн
|
||
|
||
**Время выполнения:** 2 часа
|
||
|
||
**Что предоставить:**
|
||
1. GitHub репозиторий с кодом
|
||
2. README с инструкциями по запуску
|
||
3. Демо на Vercel/Netlify (по возможности)
|
||
4. Краткое описание архитектурных решений
|
||
|
||
---
|
||
|
||
*Удачи в разработке! 🚀* |