CRUD-приложение на Vue 3 для управления сущностью Applicant: таблица, серверная пагинация, поиск, фильтрация, сортировка, CRUD-операции и имитация real-time обновлений в DEV.
- Vue 3 — Composition API,
<script setup lang="ts"> - TypeScript — строгая типизация
- Vuetify 3 — UI-компоненты
- Pinia — управление состоянием
- Vue Router — маршрутизация
- MSW (Mock Service Worker) — fake API
- Vite — сборка
- Vue I18n — интернационализация (ru/en)
npm install
npm run devПриложение автоматически откроется на http://localhost:5173.
| Команда | Описание |
|---|---|
npm run dev |
Запуск dev-сервера (vite --open) |
npm run build |
Type-check + production-сборка |
npm run preview |
Локальный просмотр production-сборки |
npm run type-check |
Только проверка типов |
npm run lint:check |
Проверка ESLint без исправлений |
npm run lint |
ESLint с автоисправлением |
npm run format:check |
Проверка форматирования Prettier |
npm run format |
Форматирование Prettier |
Проект использует гибридную архитектуру: общие/глобальные сущности организованы по типам (core/shared), а бизнес-фичи — по модулям (modules):
- модули автоматически обнаруживаются через
import.meta.glob('@/modules/*/index.ts') - каждый модуль реализует контракт
IModule:idlocalesgetRoutes()getNavItems()install?(app)
modulesStoreзагружает модули, вызываетinstall, собирает маршруты и пункты меню- роутер регистрирует маршруты динамически через
registerRoutes(...) - маршрут
/редиректит на первый доступный модульный route, либо наForbidden
src/
├── core/ # Ядро приложения
│ ├── components/
│ │ ├── App.vue # Корневой компонент приложения
│ │ ├── AppLayout.vue # Layout с шапкой и сайдбаром
│ │ └── AppSnackbar.vue # Глобальный snackbar
│ ├── locales/ # Файлы локализации приложения
│ │ ├── ru.json
│ │ └── en.json
│ ├── pages/
│ │ ├── ForbiddenPage.vue # Страница ошибки 403
│ │ └── NotFoundPage.vue # Страница ошибки 404
│ ├── plugins/ # Плагины
│ │ ├── vuetify.ts # Конфигурация Vuetify
│ │ └── i18n.ts # Конфигурация Vue I18n
│ ├── router/ # Маршрутизация
│ │ └── index.ts # Vue Router + Error handlers + registerRoutes(...)
│ ├── stores/
│ │ ├── globalStore.ts # Глобальный store (тема, сайдбар)
│ │ ├── modulesStore.ts # Pinia store для модулей приложения
│ │ └── snackbarStore.ts # Pinia store для уведомлений
│ ├── types/
│ │ └── module.ts # Модель модуля приложения
│ └── utils/
│ ├── validators.ts # Правила валидации
│ └── formatters.ts # Форматирование дат/статусов
│
├── modules/ # Бизнес-фичи
│ └── applicants/ # Модуль «Справочник кандидатов»
│ ├── api/
│ │ └── applicants/
│ │ ├── getApplicants.ts # Получить список с пагинацией
│ │ ├── createApplicant.ts # Создать кандидата
│ │ ├── updateApplicant.ts # Обновить кандидата
│ │ └── deleteApplicant.ts # Удалить кандидата
│ ├── components/
│ │ ├── ApplicantTable.vue # Таблица с пагинацией/поиском
│ │ ├── ApplicantFormDialog.vue # Диалог создания/редактирования
│ │ └── ApplicantStatusChip.vue # Чип статуса
│ ├── composables/
│ │ ├── useApplicants.ts # Параметры запроса + CRUD-обёртки
│ │ ├── useApplicantStatuses.ts # Статусы для кандидата
│ │ └── useRealtimeMock.ts # Real-time имитация (setInterval)
│ ├── locales/
│ │ ├── ru.json # Русская локализация модуля
│ │ └── en.json # Английская локализация модуля
│ ├── pages/
│ │ └── ApplicantsPage.vue # Страница с диалогами
│ ├── routes/
│ │ └── index.ts # Маршруты модуля
│ ├── stores/
│ │ └── applicantsStore.ts # Pinia store (нормализованные данные)
│ ├── types/
│ │ └── applicant.ts # Типы модуля кандидатов
│ ├── utils/
│ │ └── formatters.ts # Форматирование данных модуля
│ └── index.ts # Публичный API модуля
│
├── shared/ # Общие ресурсы
│ ├── api/
│ │ └── client.ts # Единый API-клиент с обработкой ошибок
│ ├── components/
│ │ ├── ConfirmDialog.vue # Универсальный диалог подтверждения
│ │ └── EmptyState.vue # Универсальное пустое состояние
│ ├── composables/
│ │ └── useDebounce.ts # Debounce composable
│ └── types/
│ ├── responses.ts # TypeScript типы (DTO, API responses)
│ └── sorting.ts # Типы сортировки
│
├── mocks/ # MSW mock-сервис (только DEV)
│ ├── db/
│ │ └── applicants.ts # In-memory база данных кандидатов
│ ├── handlers/
│ │ ├── applicants.ts # Обработчики API кандидатов
│ │ └── index.ts # Агрегатор handlers
│ └── browser.ts # Инициализация Service Worker
│
└── main.ts # Точка входа приложения
Правило зависимостей:
modules/→shared/✅modules/→core/✅core/→shared/✅core/→modules/❌ (ядро не знает о фичах)shared/→core/❌ (общее не зависит от ядра)shared/→modules/❌ (общее не зависит от фич)
- В DEV включается MSW (
src/main.ts) и поднимается in-memory база кандидатов - Все HTTP-запросы идут через
apiClient(src/shared/api/client.ts) - Серверная пагинация (
v-data-table-server+ API параметризация) - Real-time имитация обновления данных (
useRealtimeMock) работает только в DEV
- Поддержка русского (ru) и английского (en) языков
- Автоматическое определение языка браузера
- Сохранение выбранного языка в localStorage
- Динамическое добавление локализаций для модулей
husky+lint-stagedнаpre-commit- Для
*.{ts,tsx,vue}запускаются:npm run lintnpm run format
- ESLint
- Prettier
- Синхронизация с URL — параметры
page,search,status,sortByв query string для возможности поделиться ссылкой - Zod — runtime-валидация DTO с автогенерацией TypeScript типов
- Тесты — Vitest для store/actions, Vue Test Utils для компонентов
- Code splitting — разделение чанков Vuetify для уменьшения размера bundle (сейчас >500KB)