Files
TestingWebApp/docs/migration-to-tgflaskform.md
T
Константин Лебединский 4b0d56ff0e feat(flask): E1.0–E1.3, E1.8 — миграция на Python/Flask + AI v2
Этап 1 миграции TestingWebApp на целевой стек (Python/Flask/Jinja),
БД остаётся clinic_tests.

E1.0 — База Flask-приложения: SQLAlchemy/psycopg2 пул, Flask sessions,
фабрика create_app, blueprint main с / и /health, base.html в стиле
кабинета HR (Tailwind CDN + Manrope + Material Symbols), 404/500.

E1.1 — Auth + /api/me: Flask sessions (signed cookie) вместо JWT,
bcrypt + Werkzeug, опц. HR_AUTH=1 с UPSERT в clinic_tests.users по
staff_id. UI /login, JSON /api/auth/{login,logout,me}, декораторы
@login_required / @require_role.

E1.2 — Тесты: список + редактор. 10 эндпоинтов, сервисы test_draft,
test_access, test_chain, ai_editor, llm_client, draft_validator,
editor_content. UI /tests (каталог + создание) и /tests/<id>/edit
(редактор с AI). Полный мобильный UX (аккордеоны/drag-n-drop) — в E1.7.

E1.3 — Импорт документов: pypdf + python-docx, эндпоинт
POST /api/tests/import/document, кнопка «Импорт документа» в
AI-панели редактора, лимит 16 МБ.

E1.8 — AI v2: страница /settings (статус ENV-ключа + ping),
ai/generate-by-title (без сетки), ai/check (рецензия), ai/improve
(массовое было→стало с чекбоксами). Унифицированный ответ AI-ошибок:
{ error, code, settingsUrl }.

Docker:
- docker-compose.dev.yml: добавлены DATABASE_URL, HR_AUTH/HR_DATABASE_URL,
  DEEPSEEK_API_KEY/OPENAI_API_KEY/LLM_BASE_URL/LLM_MODEL и сеть postgres
  для testing-flask.

Документация:
- docs/migration-final.md — двух-этапный план (Этап 1: унификация
  стека внутри TestingWebApp; Этап 2: слияние с tgFlaskForm).
- docs/migration-final-inventory.md — карта 22 эндпоинтов Express.

Made-with: Cursor
2026-04-27 23:29:26 +05:00

103 lines
8.6 KiB
Markdown
Raw 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.
# Этап 2 (на будущее) — слияние TestingWebApp с `HR_TG_Bot/tgFlaskForm`
> **Не текущая фаза.** Текущая работа — **Этап 1**: унификация стека внутри TestingWebApp (Express → Flask + React → Jinja). См. [migration-final.md](migration-final.md). Этот документ — план **последующего** слияния, когда заказчик решит объединять.
**Простое объяснение тех же шагов:** [migration-to-tgflaskform-plain.md](migration-to-tgflaskform-plain.md).
**Связано:** [migration-final.md](migration-final.md) (главный трекер двух этапов), [migration-final-inventory.md](migration-final-inventory.md) (карта Express + gap-analysis с уже существующим модулем `tgFlaskForm`), [PROJECT_STATUS.md](PROJECT_STATUS.md), [README](../README.md), код HR-кабинета: `HR_TG_Bot/tgFlaskForm/webApp/interfaces/testing/`, модели: `HR_TG_Bot/tgFlaskForm/db/models.py`.
---
## 0. Предусловие — Этап 1 закрыт
К моменту, когда этот документ берётся в работу, в TestingWebApp **уже** должно быть:
- Бэкенд переписан с Express на Flask внутри [`flask_app/`](../flask_app/), все 22 эндпоинта работают.
- Фронтенд переписан с React на Jinja-шаблоны в `flask_app/app/templates/`.
- БД — по-прежнему `clinic_tests`, схема не менялась.
- В репозитории остался один сервис приложения.
Если что-то из этого ещё не готово — Этап 2 не начинается.
---
## 1. Что меняется при слиянии
| Аспект | После Этапа 1 (отдельный сервис) | После Этапа 2 (часть HR-кабинета) |
|---|---|---|
| Репозиторий | `TestingWebApp/flask_app/` | `HR_TG_Bot/tgFlaskForm/webApp/interfaces/testing/` |
| Деплой | Свой Docker-сервис, свой URL/порт | Часть основного `tgFlaskForm`, общий URL `/cabinet/testing/...` |
| БД | `clinic_tests`, UUID | `hr_bot_test`, integer ID, схема `testing_*` |
| Авторизация | JWT/bcrypt + опциональный `HR_AUTH` | Сессии общего HR-кабинета, привязка к `staff_members` |
| Модели | Свои (как в Express, но на Python) | Существующие `TestingTest`, `TestingTestVersion`, `TestingQuestion`, `TestingAnswer`, `TestingAssignment`, `TestingAttempt`, `TestingAttemptAnswer`, `TestingSetting`, `TestingHeadPosition` в `db/models.py` |
| UI | Jinja-шаблоны в `flask_app/app/templates/` | Jinja-шаблоны в `tgFlaskForm/webApp/templates/cabinet/testing/` |
---
## 2. План Этапа 2 (по спринтам)
### E2.0 — Сверка кода и моделей
- Сравнить структуру `flask_app/` (после Этапа 1) с уже существующим модулем `tgFlaskForm/webApp/interfaces/testing/`. Где функции называются иначе — выбрать одно имя.
- Сверить модели: `clinic_tests` UUID-схема vs `hr_bot_test` `testing_*` integer-схема. Зафиксировать поле-в-поле соответствия (большая часть уже сделана в [migration-final-inventory.md §10](migration-final-inventory.md#10-gap-analysis-tgflaskformcabinettesting-vs-express)).
- **Критерий выхода:** документ соответствий + решение по спорным точкам (например, кто прав — `is_active` на цепочке или на версии).
### E2.1 — Перенос кода как blueprint
- Скопировать роуты, сервисы, шаблоны из `flask_app/` в `tgFlaskForm`. **Адаптировать**:
- Импорты — на `db/models.py` и `db/queries/testing_queries.py` HR-кабинета.
- Авторизация — сменить с JWT/bcrypt на сессии и `werkzeug.security.check_password_hash`.
- URL-prefix с корневого на `/cabinet/testing/`.
- Шаблоны — наследование от `cabinet/base.html` (хедер, нижний нав-бар).
- **Критерий выхода:** все экраны открываются через HR-кабинет, локальный smoke-тест зелёный.
### E2.2 — Миграция данных (ETL)
Скрипт уже готов: [`HR_TG_Bot/tgFlaskForm/tools/migrate_clinic_tests_to_hr.py`](../../HR_TG_Bot/tgFlaskForm/tools/migrate_clinic_tests_to_hr.py) (437 строк, режимы `--dry-run`/`--apply`, идемпотентность через `public._clinic_tests_migration_map`).
Перед прогоном **на актуальных данных** дописать:
- **Перенос `test_assignments` 1:1** — сейчас скрипт переносит только пары «тест-сотрудник» через попытки; нужны и «висящие» назначения без попыток. (Решение Этапа 2.)
- **Логирование пользователей без `staff_id`:** автор → WARN, попытка → WARN; никаких хардовых ошибок. (Решение Этапа 2.)
**Порядок:**
1. Бэкап `clinic_tests` и `hr_bot_test`.
2. `--dry-run` на копии прод-БД, разбор лога.
3. `--apply` на той же копии, ручная сверка через UI HR-кабинета.
4. После приёмки — `--dry-run` + `--apply` на боевой БД.
### E2.3 — Cutover
Если к этому моменту у TestingWebApp всё ещё «песочница для тестировщиков» (как сейчас) — простое переключение, без окна простоя и баннеров. Если появятся реальные пользователи — добавить пункт E2.3.1: коммуникация и redirect.
- Заморозка записи в `flask_app/` старой инсталляции (read-only).
- Прогон ETL на боевом.
- Маршрутизация: внешние ссылки `clinic-tests.example.com/*``hr-cabinet.example.com/cabinet/testing/*`.
- В корневом репозитории TestingWebApp — ветка `legacy/clinic-tests-flask`, в README — ссылка на этот документ и дату EOL.
**Критерий выхода:** мониторинг ошибок (например Sentry, уже подключён в `webApp/__init__.py`), отсутствие P1 в первую неделю.
---
## 3. Что трогаем в HR-кабинете до Этапа 2
**Ничего.** Существующий модуль `tgFlaskForm/webApp/interfaces/testing/` развивается своим темпом командой HR-кабинета и **не** должен подстраиваться под TestingWebApp до момента слияния. Если в нём появляются полезные правки — переносим в `flask_app/` обратным потоком.
---
## 4. Риски Этапа 2 и как их снимать
| Риск | Мера |
|------|------|
| Несовпадение `users.staff_id``staff_members.id` | Проверка перед `--apply`; пользователей без `staff_id` пропускаем по решению. |
| Расхождение моделей (UUID vs integer, поля «на цепочке» vs «на версии») | Закрыть в E2.0; подкрепить unit-тестами на конвертацию. |
| Назначения «отдел → N сотрудников» | Логировать развёртку с пометкой `created_from_department=...`. |
| Двойное развитие модуля HR-кабинета | До Этапа 2 — не править `tgFlaskForm/cabinet/testing` под нужды TestingWebApp. |
---
## 5. Производительность кабинета (общее)
Если после переноса страницы кабинета или мини-приложения работают медленно — пошаговый план измерений и правок: [performance-flask-mini-app.md](performance-flask-mini-app.md). Это вспомогательный документ, не часть этапов миграции.