feat: Sprint 1 — infrastructure + test creation

Backend:
- FastAPI + SQLAlchemy 2.0 async + Alembic
- Models: Test, Question, Answer
- API: GET /api/tests, GET /api/tests/{id}, POST /api/tests
- Pydantic validation: min 7 questions, min 3 answers, ≥1 correct

Frontend:
- React 18 + TypeScript + Vite + Ant Design + TanStack Query
- Pages: TestList, TestCreate (nested Form.List), TestDetail

Infrastructure:
- Docker Compose: db (postgres:16), backend, frontend, nginx
- Nginx: /api/ → FastAPI, / → Vite dev server with HMR
- Alembic migration 001_init: tests, questions, answers tables
- entrypoint.sh: wait for db, migrate, start uvicorn

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Aleksey Razorvin
2026-03-21 12:05:04 +05:00
parent 054376bca7
commit 8b17c5d3c4
35 changed files with 1370 additions and 0 deletions
+145
View File
@@ -0,0 +1,145 @@
# ШАГ 006 — Спринт 1: Инфраструктура + Создание тестов
**Дата:** 2026-03-21
**Контекст:** Мастер-класс по разработке системы тестирования сотрудников клиники.
---
## Запрос
> готов. поехали (начинаем Спринт 1)
---
## Ответ
Реализован Спринт 1 в полном объёме: инфраструктура + создание тестов без авторизации.
---
## Структура проекта после спринта
```
qa_test_app/
├── docker-compose.yml ← поднимает весь стек одной командой
├── .env.example
├── nginx/
│ └── nginx.conf ← / → frontend, /api/ → backend
├── backend/
│ ├── Dockerfile
│ ├── entrypoint.sh ← ждёт БД, запускает миграции, стартует сервер
│ ├── requirements.txt
│ ├── alembic.ini
│ ├── alembic/
│ │ ├── env.py ← async alembic, берёт URL из settings
│ │ ├── script.py.mako
│ │ └── versions/
│ │ └── 001_init.py ← создаёт таблицы tests, questions, answers
│ └── app/
│ ├── config.py ← настройки через pydantic-settings
│ ├── database.py ← async SQLAlchemy engine + session
│ ├── main.py ← FastAPI app, /api/health
│ ├── models/test.py ← ORM модели: Test, Question, Answer
│ ├── schemas/test.py ← Pydantic схемы с валидацией
│ └── api/tests.py ← REST эндпоинты
└── frontend/
├── Dockerfile
├── package.json
├── vite.config.ts
├── index.html
└── src/
├── App.tsx ← роутер + провайдеры
├── api/
│ ├── client.ts ← axios с baseURL=/api
│ └── tests.ts ← типы + функции запросов
└── pages/
├── TestList/ ← список тестов + кнопка создать
├── TestCreate/ ← форма создания теста
└── TestDetail/ ← просмотр теста с вопросами
```
---
## API эндпоинты
| Метод | URL | Описание |
|-------|-----|----------|
| GET | `/api/health` | Проверка работы сервера |
| GET | `/api/tests` | Список тестов |
| GET | `/api/tests/{id}` | Детали теста с вопросами и ответами |
| POST | `/api/tests` | Создать тест |
---
## Схема БД
```
tests
id, title, description, passing_score, time_limit,
allow_navigation_back, is_active, version, created_at
questions
id, test_id → tests.id, text, order
answers
id, question_id → questions.id, text, is_correct
```
---
## Валидация
**Backend (Pydantic):**
- Тест: минимум 7 вопросов, passing_score 0100
- Вопрос: минимум 3 варианта ответа, хотя бы 1 правильный
**Frontend (Ant Design Form):**
- Те же правила воспроизведены на клиенте
- Nested Form.List для динамических вопросов и ответов
- Таймер показывается только при включённом переключателе (shouldUpdate)
---
## Как запустить
```bash
docker compose up --build
```
Открыть браузер: `http://localhost`
- Список тестов → кнопка «Создать тест»
- Заполнить форму → нажать «Создать тест»
- Перейти к созданному тесту и увидеть все вопросы и ответы
- `http://localhost/api/health``{"status": "ok"}`
- `http://localhost/api/docs` → Swagger UI FastAPI
---
## Ключевые решения для джуниора
**Async SQLAlchemy 2.0:**
- `async_sessionmaker` + `AsyncSession` — не блокируем event loop при запросах к БД
- `selectinload` для жадной загрузки связей (вместо N+1 запросов)
**Alembic async:**
- `async_engine_from_config` + `connection.run_sync(do_run_migrations)`
- URL берётся из `app.config.settings` — одно место для конфига
**Docker Compose healthcheck:**
- `db` объявляет `healthcheck`, `backend` ждёт `condition: service_healthy`
- Дополнительно `entrypoint.sh` вызывает `pg_isready` для надёжности
**TanStack Query:**
- `useQuery` для чтения данных — кэш, loading state, error state из коробки
- `useMutation` для создания — `invalidateQueries` обновляет список после успеха
---
## Следующие шаги
- [x] Спринт 1: Инфраструктура + Создание тестов
- [ ] Спринт 2: Прохождение теста + результаты
- [ ] Спринт 3: Трекер результатов
- [ ] Спринт 4: Авторизация и роли
- [ ] Спринт 5: Уведомления в MAX