From 9cb07e2f8eb6c6e72eb0ccea8e2bfee22aa016a4 Mon Sep 17 00:00:00 2001 From: Oscar Date: Fri, 5 Jun 2026 11:26:12 +0300 Subject: [PATCH] upd --- README.md | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..9b0cbe2 --- /dev/null +++ b/README.md @@ -0,0 +1,131 @@ +# 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 предсгенерированных элементов (случайные строки 6–12 символов). Выбранные элементы хранятся в `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 +```