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:
@@ -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 0–100
|
||||
- Вопрос: минимум 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
|
||||
Reference in New Issue
Block a user