# Анализ проекта КЛГ АСУ ТК и рекомендации **Дата анализа:** 2025 **Путь к проекту:** `/Users/yrippertgmail.com/Desktop/klg_asutk_app` **Статус:** Рекомендации из данного документа применены (коммит/дата по желанию). --- ## 1. Обзор архитектуры | Слой | Технологии | |------|------------| | **Frontend** | Next.js 14, React 18, Tailwind, SWR, next-auth (beta), PWA | | **Backend** | FastAPI, SQLAlchemy 2, Pydantic 2, Alembic, Redis, Prometheus | | **Инфраструктура** | PostgreSQL, Redis, Keycloak OIDC, Docker, Helm | - **Фронт:** ~40 страниц, единый API-клиент (`lib/api/api-client.ts`), проксирование `/api/v1/*` на бэкенд через `next.config.js` rewrites. - **Бэкенд:** 29+ роут-файлов, 147+ эндпоинтов, мультитенантность (RLS), роли (RBAC), DEV/OIDC авторизация. --- ## 2. Сильные стороны - **Чёткая доменная модель:** ВС, ЛГ, наряды, дефекты, персонал ПЛГ, ФГИС РЭВС, нормативная база — с привязкой к правовым основаниям (ВК РФ, ФАП, EASA, ICAO). - **Единый API-клиент:** `api-client.ts` с токеном, редиректом при 401, типами; часть страниц уже переведена на него. - **Безопасность:** `.env` в `.gitignore`, `.env.example`, `docs/SECURITY.md`, заголовки X-Frame-Options / X-Content-Type-Options, CORS из настроек. - **Логгер:** `lib/logger.ts` вместо `console.log` на фронте; на бэкенде — `logging`. - **Рефакторинг модулей:** legal → пакет (base + handlers), personnel — пакет, FGIS — вынесены типы в `fgis/base_service.py`. - **Тесты:** pytest в backend (conftest, переопределение БД), Playwright для E2E. --- ## 3. Критичные проблемы и рекомендации ### 3.1 SQL-инъекция в `set_tenant` (backend) **Файл:** `backend/app/db/session.py` ```python db.execute(text(f"SET LOCAL app.current_org_id = '{org_id}'")) ``` Если `org_id` приходит из JWT/пользователя, возможна инъекция. **Рекомендация:** использовать параметризованный запрос (например, через `text("... :org_id").bindparams(org_id=org_id)` или аналог для вашего драйвера), либо жёстко валидировать `org_id` (UUID/белый список). --- ### 3.2 SQLAlchemy 2: `db.execute("SELECT 1")` без `text()` **Файл:** `backend/app/api/routes/health.py`, эндпоинт `detailed_health`: ```python db.execute("SELECT 1") ``` В SQLAlchemy 2.x строка должна быть обёрнута в `text()`. **Рекомендация:** ```python from sqlalchemy import text db.execute(text("SELECT 1")) ``` --- ### 3.3 Тесты: переопределение `get_db` не покрывает все роуты **Файл:** `backend/tests/conftest.py` Переопределяется `app.db.session.get_db`, тогда как часть роутов импортирует `get_db` из `app.api.deps`. В таких роутах подмена не срабатывает, тесты могут ходить в реальную БД. **Рекомендация:** везде использовать один источник зависимости — например, только `app.api.deps.get_db` — и в conftest переопределять именно его: ```python from app.api.deps import get_db # ... app.dependency_overrides[get_db] = _override_get_db ``` Либо оставить реализацию в `session.py`, а в `deps.py` реэкспортировать `from app.db.session import get_db` и везде импортировать из `deps`. --- ### 3.4 Обработчики исключений не подключены **Файл:** `backend/app/main.py` В `app/api/exceptions.py` определены обработчики для `RequestValidationError`, `IntegrityError`, `SQLAlchemyError` и др., но в `main.py` они не регистрируются. Используется только общий `@app.exception_handler(Exception)`. **Рекомендация:** в `main.py` подключить обработчики из `exceptions.py` (например, через `app.add_exception_handler`), чтобы возвращать 422/409 с единообразным форматом и не «проглатывать» валидацию и ошибки БД общим 500. --- ### 3.5 Сборка и качество кода отключены **Файл:** `next.config.js` ```javascript eslint: { ignoreDuringBuilds: true }, typescript: { ignoreBuildErrors: true }, ``` Линт и проверка типов при сборке отключены — ошибки ESLint/TypeScript не блокируют деплой. **Рекомендация:** для продакшена включить проверки: убрать или выставить `false` и починить накопившиеся ошибки; при необходимости временно ограничить scope (например, только `app/`, `lib/`). --- ## 4. Важные улучшения (средний приоритет) ### 4.1 Единый источник зависимости `get_db` Сейчас часть роутов импортирует `get_db` из `app.db.session`, часть — из `app.api.deps`. Это усложняет тесты и конфигурацию. **Рекомендация:** оставить реализацию в `app.db.session`, в `app.api.deps` делать реэкспорт и везде в роутах использовать `from app.api.deps import get_db`. В тестах переопределять только этот `get_db`. --- ### 4.2 Единообразные запросы к API на фронте Много страниц по-прежнему используют «голый» `fetch('/api/v1/...')` без единого клиента: разный подход к токену, ошибкам и редиректу при 401. **Рекомендация:** постепенно переводить все вызовы на `lib/api/api-client.ts` (или обёртки над ним), чтобы авторизация, обработка ошибок и редирект были централизованы. --- ### 4.3 DEV-авторизация по умолчанию **Файл:** `backend/app/api/deps.py` ```python ENABLE_DEV_AUTH = os.getenv("ENABLE_DEV_AUTH", "true").lower() == "true" ``` При отсутствии переменной окружения включён dev-режим (обход авторизации). **Рекомендация:** по умолчанию считать продакшен: `"false"` и явно включать dev только в локальной среде (например, в `.env.local` с `ENABLE_DEV_AUTH=true`). В `config` уже есть `ENABLE_DEV_AUTH: bool = False` — использовать `settings.ENABLE_DEV_AUTH` вместо чтения `os.getenv` в deps. --- ### 4.4 Health check: Redis и зависимости **Файл:** `backend/app/api/routes/health.py` В `detailed_health` Redis подключается к `host="localhost", port=6379`, тогда как в конфиге используется `REDIS_URL`. При смене окружения проверка может быть некорректной. **Рекомендация:** брать URL из `settings.REDIS_URL` (или из переменной окружения) и использовать `redis.from_url()` как в основном `health_check`. --- ### 4.5 Дублирование логгеров на фронте В `package.json` присутствуют и `winston`, и `pino`. При этом в коде используется собственный `lib/logger.ts`. **Рекомендация:** если winston/pino не используются — удалить из зависимостей; если планируется использование — зафиксировать один стек и постепенно перейти на него в `lib/logger.ts`, чтобы не дублировать логику. --- ## 5. Дополнительные рекомендации (низкий приоритет) ### 5.1 Backend `.env.example` В корне есть `.env.example` для фронта и общих переменных; для бэкенда отдельного шаблона нет. **Рекомендация:** добавить `backend/.env.example` с переменными из `app/core/config.py` (DATABASE_URL, REDIS_URL, OIDC_*, ENABLE_DEV_AUTH, CORS_ORIGINS и т.д.) и кратким комментарием. --- ### 5.2 Миграции при старте В `main.py` при старте выполняется обход папки `migrations` и выполнение всех `.sql` файлов. При сбое делается только `rollback`, без явного учёта уже применённых миграций. **Рекомендация:** в продакшене полагаться на Alembic и не применять сырые SQL при старте приложения; оставить автозапуск миграций только для dev или вынести в отдельный job/entrypoint. --- ### 5.3 Документация API и версии В коде указаны версии (например, `2.1.0` в main, `2.2.0` в health). Имеет смысл вынести версию в одно место (например, `app/__init__.py` или `pyproject.toml`) и использовать её в OpenAPI и в health. --- ### 5.4 Роли на эндпоинтах Часть роутов не использует `require_roles` и полагается только на `get_current_user`. Для чувствительных операций (удаление, экспорт, панель регулятора) стоит явно ограничивать доступ по ролям. --- ## 6. Краткий чек-лист по приоритетам | Приоритет | Действие | |-----------|----------| | Критично | Исправить `set_tenant` (параметризованный запрос или валидация `org_id`) | | Критично | В `health.py` использовать `text("SELECT 1")` | | Критично | Унифицировать `get_db` и переопределение в тестах | | Критично | Подключить обработчики из `exceptions.py` в `main.py` | | Высоко | Убрать `ignoreDuringBuilds` / `ignoreBuildErrors` в next.config и починить ошибки | | Средне | Перевести все вызовы API на фронте на api-client | | Средне | Использовать в deps `settings.ENABLE_DEV_AUTH`, по умолчанию False | | Средне | В detailed_health использовать `REDIS_URL` из конфига | | Низко | Добавить backend/.env.example, упорядочить версии и миграции | --- © Анализ подготовлен для проекта КЛГ АСУ ТК (АО «REFLY»).