Files
tmc-test-task/README.md
Oscar 9cb07e2f8e upd
2026-06-05 11:26:12 +03:00

132 lines
6.0 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# TMC Test Task
Fullstack-приложение для управления коллекцией элементов с двухпанельным интерфейсом, виртуальным скроллом и drag & drop.
**Задеплоенное приложение:** [https://test-1.koptilnya.xyz/](https://test-1.koptilnya.xyz/)
---
## Что это
Интерфейс с двумя панелями: слева — 1 000 000 предсгенерированных элементов, справа — выбранные. Элементы можно перемещать между панелями, искать, добавлять новые и менять порядок через drag & drop.
---
## Стек
| Слой | Технологии |
|---|---|
| Backend | Node.js 22, Express 4, TypeScript 5 |
| Frontend | Nuxt 4 (SPA), Vue 3, TypeScript 6 |
| UI | @nuxt/ui, vue-draggable-next, SCSS |
| Инфраструктура | Docker, Traefik, Let's Encrypt |
| CI/CD | Gitea Actions |
---
## Архитектура бэкенда
Сервер запускается на порту **1337**. API задокументировано через Swagger: `/api/docs`.
### Эндпоинты (`/api/items`)
| Метод | Путь | Описание |
|---|---|---|
| `GET` | `/` | Невыбранные элементы (пагинация, поиск) |
| `GET` | `/selected` | Выбранные элементы в заданном порядке |
| `POST` | `/add` | Добавить элемент в очередь на создание |
| `POST` | `/add-value` | Создать элемент с произвольным значением |
| `POST` | `/select` | Переместить элемент в правую панель |
| `POST` | `/deselect` | Вернуть элемент в левую панель |
| `PUT` | `/reorder` | Изменить порядок выбранного элемента |
### Хранилище
In-memory хранилище с 1 000 000 предсгенерированных элементов (случайные строки 612 символов). Выбранные элементы хранятся в `Set` для O(1)-поиска и в упорядоченном массиве для drag & drop. Новые элементы получают ID начиная с 1 000 001.
### Очередь с батчингом
Ключевая часть бэкенда — класс `RequestQueue` (`src/services/queue.ts`):
- **Добавление элементов** — батч сбрасывается каждые **10 секунд** или при достижении **100 операций**
- **Select / Deselect** — применяются **немедленно** для мгновенного отклика UI
- **Reorder** — батч сбрасывается каждую **1 секунду**
- **Дедупликация** — повторные операции над одним элементом отбрасываются
Такое разделение позволяет держать UI отзывчивым для частых пользовательских действий и одновременно снижать нагрузку на запись.
---
## Архитектура фронтенда
SPA на Nuxt 4, SSR отключён. Сервер отдаётся через Nginx.
### Панели
**Левая панель (`LeftPanel.vue`)** — невыбранные элементы:
- Виртуальный скролл (высота строки 47px, overscan 5 элементов)
- Infinite scroll для подгрузки страниц
- Поиск с дебаунсом 300 мс
- Модальное окно добавления нового элемента
**Правая панель (`RightPanel.vue`)** — выбранные элементы:
- Те же параметры виртуализации
- Drag & drop через `vue-draggable-next`
- Автоскролл во время перетаскивания (зона 80px, скорость до 12px/тик)
- После отпускания — синхронизация нового порядка с бэкендом
### Состояние
Composable `useItems.ts` управляет всем состоянием: загрузка, пагинация, поиск, операции select/deselect/reorder. API-клиент генерируется автоматически из OpenAPI-спеки бэкенда (`npm run gen:api`).
---
## CI/CD и деплой
Пайплайны описаны в `.gitea/workflows/` и запускаются при пуше в `main`.
### deploy-backend.yml
Триггер: изменения в `/backend/**`
1. Checkout через SSH
2. `docker build -t tmc-backend ./backend`
3. Остановка старого контейнера
4. Запуск нового в сети `traefik` с env `PATH_PREFIX=/test-1`
5. Traefik автоматически получает Let's Encrypt сертификат и проксирует на `api.koptilnya.xyz`
### deploy-frontend.yml
Триггер: изменения в `/frontend/**`
1. Checkout через SSH
2. `docker build` с build-arg `API_BASE_URL` (URL бэкенда)
3. Остановка старого контейнера
4. Запуск нового; Traefik проксирует на `test-1.koptilnya.xyz`
Оба сервиса живут в одной Docker-сети `traefik`. Traefik роутит запросы по хосту и управляет TLS.
---
## Локальный запуск
```bash
# Backend
cd backend
pnpm install
pnpm dev # :1337
# Frontend
cd frontend
pnpm install
pnpm dev # :3000
```
По умолчанию фронт обращается к `http://localhost:1337`. Переопределить через `NUXT_PUBLIC_API_BASE`.
```bash
# Обновить API-клиент после изменений в бэкенде
cd frontend
pnpm gen:api # требует запущенного бэкенда на :1337
```