## 1. Безопасность JWT — критично
**Файл:** `/server/utils/jwt.ts`

- Убрать ВСЕ fallback-значения для секретов (`'access-secret-key'`, `'refresh-secret-key'` и т.д.).
- При старте приложения, если `JWT_ACCESS_SECRET`, `JWT_REFRESH_SECRET` или `JWT_SUPERADMIN_SECRET` не заданы в `process.env` — вызывать `console.error('FATAL: JWT secrets not configured')` и `process.exit(1)`.
- Разделить секреты: access, refresh, superadmin, bot — каждый свой ключ из env.
- Сроки жизни токенов вынести в env с дефолтами: access=15m, refresh=7d, superadmin=1h, bot=1y.

## 2. SSE токен — перенести из query в заголовок
**Файл:** `/server/routes.ts` (SSE endpoint) + фронт (`/client/src/...` где подключается EventSource)

- На бэкенде: endpoint `/api/events` должен читать токен из заголовка `Authorization: Bearer <token>`, а не из `req.query.token`.
- На фронте: стандартный `EventSource` не умеет заголовки. Используй нативный `fetch` с `ReadableStream` для SSE или обёртку, которая передаёт токен в заголовке. **Не используй query-параметр для токена.**
- Если фронт использует TanStack Query — создай кастомный хук `useSSE` на `fetch` + `ReadableStream.getReader()`.

## 3. Разбить routes.ts на модули
**Файлы:** создать `/server/routes/` с файлами:
- `auth.routes.ts` — логин, регистрация, refresh, logout, invite
- `task.routes.ts` — задачи, статусы, поля, kanban, фильтры
- `chat.routes.ts` — сообщения, комментарии, @mentions
- `bot.routes.ts` — Telegram/Discord боты, вебхуки
- `admin.routes.ts` — superadmin, биллинг, настройки
- `automation.routes.ts` — автоматизации, VM sandbox (если есть)
- `index.ts` — сборка всех роутов через `router.use('/api/auth', authRoutes)` и т.д.

**Важно:** 
- Старый `/server/routes.ts` оставь как основной файл, но перенеси логику в модули и импортируй их. 
- Все существующие endpoint'ы (`/api/login`, `/api/tasks` и т.д.) должны продолжать работать. 
- Не меняй логику внутри handler'ов — только структурируй.

## 4. Транзакции для bulk-операций
**Файлы:** `/server/routes/` (где сохраняются формы, статусы, поля)

- Найди места, где в цикле `for` делаются множественные `db.insert()` или `db.update()` (например, сохранение полей формы, статусов kanban).
- Обёртывай их в `await db.transaction(async (trx) => { ... })`.
- Если одна операция в цикле падает — откатывай всю транзакцию.

## 5. Устранить N+1 в legacy endpoint'ах
**Файл:** `/server/routes/task.routes.ts` (или в старом routes.ts если ещё не разбит)

- Найди endpoint `/api/forms/:id/tasks` (legacy) и `/api/forms/:id/tasks/with-fields` (optimized).
- Сделай так, чтобы legacy endpoint использовал тот же JOIN-подход, что и optimized, **или** пометь его deprecated и перенаправь на optimized.
- Для `buildSystemFieldValues()` — замени отдельные запросы на `db.query.tasks.findMany({ with: { ... } })` с Drizzle relations.

## 6. Улучшить in-memory кэш (без Redis)
**Файл:** `/server/utils/cache.ts`

- Добавь TTL: `set(key, value, ttlMs)`. При `get` проверяй `Date.now() > createdAt + ttl`.
- Добавь инвалидацию по префиксу: `invalidatePrefix('forms:')` удалит все ключи, начинающиеся с `forms:`.
- Добавь `maxSize` (например, 1000 записей). При превышении — удаляй самые старые (LRU).
- Добавь метод `clear()` для полной очистки.

## 7. Загрузка файлов — защита и потоки
**Файл:** `/server/routes.ts` (multer конфигурация)

- **Path Traversal:** замени `key.includes('..') || key.includes('/')` на строгую валидацию: только `a-zA-Z0-9_-`, расширение из белого списка (`jpg`, `jpeg`, `png`, `pdf`, `docx`, `xlsx`, `zip`).
- **Mime-type:** проверяй `file.mimetype` против белого списка. Запрещай `application/octet-stream` без явного расширения.
- **Размер:** лимит 10 МБ для изображений, 50 МБ для документов.
- **Хранение:** для файлов > 5 МБ используй `diskStorage` в `/tmp/uploads`, а не `memoryStorage`. После обработки (S3 upload) — удаляй файл. Для маленьких файлов (< 5 МБ) можно оставить `memoryStorage`.
- **Сканирование:** добавь базовую проверку magic bytes для изображений (чтобы `.exe` переименованный в `.jpg` не прошёл).

## 8. Вебхуки — retry логика (без Redis)
**Файл:** `/server/routes/bot.routes.ts` (или где вызываются `fetch()` для вебхуков)

- Замени голый `fetch().catch()` на функцию `sendWebhook(url, payload, retries = 3)`.
- При неудаче (не 2xx или network error) — жди `2^attempt * 1000` мс (exponential backoff) и повторяй.
- Если все 3 попытки провалились — логируй ошибку в БД (новая таблица `webhook_failures` или в `task_audit_log`).
- **Ограничение:** не более 5 одновременных вебхуков — используй `p-limit` или самописный семафор (массив pending promises, max 5).

## 9. Исправить IDOR в сообщениях
**Файл:** `/server/routes/chat.routes.ts`

- Endpoint `/api/messages/:id` должен проверять, что сообщение принадлежит задаче, которая принадлежит организации текущего пользователя.
- Добавь `AND eq(tasks.organization_id, req.user.organization_id)` в запрос.

## 10. Общий аудит (входы, экспорты, ошибки)
**Файл:** `/server/utils/audit.ts` (создать)

- Создай единую функцию `logAudit({ action, userId, organizationId, taskId, details, ip })`.
- Добавь таблицу `system_audit_log` (id, action, user_id, org_id, task_id, details JSONB, ip, user_agent, created_at).
- Логируй:
  - Успешный/неуспешный вход
  - Выход
  - Экспорт данных (Excel, CSV)
  - Изменение прав пользователя
  - Неудачные попытки аутентификации (rate limit сработал — тоже логируй)
- Используй `db.insert()` без `await` (fire-and-forget), но оборачивай в `.catch()` чтобы не падало основное действие.

## 11. Индексы PostgreSQL
**Файл:** `/shared/schema.ts` (Drizzle) или миграция `/server/migrations/`

- Добавь через Drizzle индексы:
  - `tasks`: `organization_id` + `form_id`, `organization_id` + `current_status_id`, `organization_id` + `assigned_to`
  - `task_field_values`: `task_id` + `field_id`
  - `task_messages`: `task_id` + `created_at DESC`
  - `task_audit_log`: `task_id` + `created_at DESC`
  - `users`: `organization_id` + `role`
- Сгенерируй SQL миграцию через `drizzle-kit generate` (или напиши raw SQL файл).

## 12. Улучшить rate limiting
**Файл:** `/server/routes.ts` или `/server/index.ts`

- API лимит: снизь с 5000/15min до **600/15min** для обычных пользователей.
- SSE: отдельный лимит — **30 соединений/IP**.
- Auth endpoints (`/api/login`, `/api/register`): **5 попыток/15min/IP** (строгий лимит против brute-force).
- Используй `express-rate-limit` с `standardHeaders: true`, `legacyHeaders: false`.

## 13. VM Автоматизации — изоляция (без отдельного микросервиса)
**Файл:** `/server/routes/automation.routes.ts`

- Если в коде есть `vm.createContext` + `vm.Script` — оберни в `try/catch/finally`.
- Добавь `cpuUsage` лимит через `process.cpuUsage()` перед и после. Если скрипт съел > 100ms CPU time — убивай.
- Ограничь память: перед запуском проверяй `process.memoryUsage().heapUsed`. Если > 80% от лимита — отказывай в запуске.
- **Запускай VM в `setImmediate` или `process.nextTick`** чтобы не блокировать текущий HTTP-ответ, если это возможно. Если нет — добавь комментарий `// TODO: вынести в Worker при масштабировании`.