167 lines
8.0 KiB
Markdown
167 lines
8.0 KiB
Markdown
# Test Task CRM
|
||
|
||
Многопользовательская mini-CRM на FastAPI + PostgreSQL c сервисно-репозиторной архитектурой, JWT-аутентификацией, Alembic-миграциями и готовым React/Vite фронтендом.
|
||
|
||
## Стек и особенности
|
||
|
||
- Python 3.14, FastAPI, SQLAlchemy Async ORM, Alembic.
|
||
- Pydantic Settings для конфигурации, JWT access/refresh токены, кеш аналитики в Redis.
|
||
- Frontend: Vite + React + TypeScript (см. `frontend/`).
|
||
- Докер-окружение для разработки (`docker-compose-dev.yml`) и деплоя (`docker-compose-ci.yml`).
|
||
|
||
## Структура проекта
|
||
|
||
```text
|
||
app/
|
||
api/ # FastAPI-роуты и зависимости
|
||
core/ # Настройки, база, безопасность
|
||
models/ # SQLAlchemy-модели
|
||
repositories/ # Работа с БД
|
||
services/ # Бизнес-правила и сценарии
|
||
frontend/ # Vite + React SPA
|
||
migrations/ # Alembic-миграции
|
||
tests/ # Pytest (unit + интеграции)
|
||
```
|
||
|
||
## Переменные окружения
|
||
|
||
1. Скопируйте шаблон: `cp .env.example .env`.
|
||
2. Обновите секреты (`DB_PASSWORD`, `JWT_SECRET_KEY`, и т.д.) перед запуском.
|
||
3. Все переменные описаны в `app/core/config.py`; Vite читает только ключи с префиксом `VITE_`.
|
||
|
||
### Backend
|
||
|
||
| Переменная | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- |
|
||
| `PROJECT_NAME` | `"Test Task CRM"` | Заголовки/метаданные API |
|
||
| `VERSION` | `"0.1.0"` | Версия приложения |
|
||
| `API_V1_PREFIX` | `/api/v1` | Базовый префикс REST |
|
||
| `DB_HOST` | `localhost` | Хост PostgreSQL |
|
||
| `DB_PORT` | `5432` | Порт PostgreSQL |
|
||
| `DB_NAME` | `test_task_crm` | Имя БД |
|
||
| `DB_USER` | `postgres` | Пользователь БД |
|
||
| `DB_PASSWORD` | `postgres` | Пароль пользователя |
|
||
| `DATABASE_URL` | — | Полный DSN (перекрывает `DB_*`), формат `postgresql+asyncpg://user:pass@host:port/db` |
|
||
| `SQLALCHEMY_ECHO` | `false` | Логирование SQL |
|
||
| `JWT_SECRET_KEY` | `change-me` | Секрет для подписи JWT |
|
||
| `JWT_ALGORITHM` | `HS256` | Алгоритм JWT |
|
||
| `ACCESS_TOKEN_EXPIRE_MINUTES` | `30` | TTL access-токена |
|
||
| `REFRESH_TOKEN_EXPIRE_DAYS` | `7` | TTL refresh-токена |
|
||
| `REDIS_ENABLED` | `false` | Включить кеш аналитики |
|
||
| `REDIS_URL` | `redis://localhost:6379/0` | Строка подключения к Redis |
|
||
| `ANALYTICS_CACHE_TTL_SECONDS` | `120` | TTL кэша аналитики |
|
||
| `ANALYTICS_CACHE_BACKOFF_MS` | `200` | max задержка при ретраях записи в кеш |
|
||
|
||
### Frontend (Vite)
|
||
|
||
| Переменная | Значение по умолчанию | Назначение |
|
||
| --- | --- | --- |
|
||
| `VITE_API_URL` | `http://localhost:8000` (в `.env.example`), в `src/config/env.ts` дефолт `https://kitchen-crm.k1nq.tech` | Базовый URL бекенда (без завершающего `/`) |
|
||
| `VITE_APP_URL` | `http://localhost:5173` | URL SPA, используется для deeplink'ов и редиректов |
|
||
|
||
⚠️ В `frontend/src/config/env.ts` зашит production URL (`https://kitchen-crm.k1nq.tech`). При деплое в другое место обязательно обновите `VITE_API_URL`/`VITE_APP_URL` в `.env` или настройте переменные окружения на уровне хостинга.
|
||
|
||
## Локальный запуск без Docker
|
||
|
||
### Предварительные требования
|
||
|
||
- Python 3.10+ и [uv](https://github.com/astral-sh/uv).
|
||
- PostgreSQL 16+ (локально или через Docker).
|
||
- (Опционально) Redis 7+ для кеша аналитики.
|
||
|
||
### Backend (API)
|
||
|
||
```bash
|
||
# 1. Готовим окружение
|
||
cp .env.example .env
|
||
# отредактируйте .env: базы, секреты, VITE_* (если нужен фронтенд)
|
||
|
||
# 2. Устанавливаем зависимости
|
||
uv sync
|
||
|
||
# 3. Применяем миграции
|
||
uvx alembic upgrade head
|
||
|
||
# 4. Запускаем API
|
||
uvx uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
|
||
```
|
||
|
||
PostgreSQL/Redis можно поднять вручную или командой `docker compose -f docker-compose-dev.yml up postgres redis -d`.
|
||
|
||
### Frontend
|
||
|
||
```bash
|
||
cd frontend
|
||
npm install
|
||
npm run dev -- --host
|
||
```
|
||
|
||
Фронтенд ожидает, что `VITE_API_URL` указывает на работающий бекенд (например, `http://localhost:8000`).
|
||
|
||
## Запуск через Docker Compose
|
||
|
||
### Локальная разработка (`docker-compose-dev.yml`)
|
||
|
||
- Собирает бекенд из `app/Dockerfile`, поднимает `postgres:16-alpine` и `redis:7-alpine`.
|
||
- Порты по умолчанию: API `8000`, Postgres `5432`, Redis `6379`.
|
||
- Все переменные берутся из `.env`.
|
||
|
||
```bash
|
||
docker compose -f docker-compose-dev.yml up --build
|
||
# или в фоне
|
||
docker compose -f docker-compose-dev.yml up --build -d
|
||
```
|
||
|
||
### Прод/CI стек (`docker-compose-ci.yml`)
|
||
|
||
1. Соберите образы и статику:
|
||
|
||
```bash
|
||
docker build -f app/Dockerfile -t <registry>/test-task-crm:app .
|
||
docker build -f migrations/Dockerfile -t <registry>/test-task-crm:migrations .
|
||
cd frontend && npm install && npm run build && cd ..
|
||
```
|
||
|
||
2. Залейте `frontend/dist` (используется как read-only volume) и задайте `GIT_HOST`, `GIT_USER`, `GIT_REPO` в `.env`.
|
||
3. Запустите стек:
|
||
|
||
```bash
|
||
docker compose -f docker-compose-ci.yml up -d
|
||
```
|
||
|
||
В этом режиме `migrations` прогоняется один раз, `app` слушает порт `80`, Postgres хранит данные на `/mnt/data/postgres` (смонтируйте хостовую директорию заранее).
|
||
|
||
## Redis для аналитики
|
||
|
||
Кеш аналитики выключен по умолчанию. Чтобы включить:
|
||
|
||
1. Поднимите Redis (`docker compose ... redis` или любым другим способом).
|
||
2. В `.env` выставьте:
|
||
- `REDIS_ENABLED=true`
|
||
- `REDIS_URL=redis://<host>:6379/0`
|
||
- (опционально) `ANALYTICS_CACHE_TTL_SECONDS` и `ANALYTICS_CACHE_BACKOFF_MS`.
|
||
3. При недоступности Redis сервис автоматически возвращается к прямым запросам в PostgreSQL и пишет предупреждения в лог.
|
||
|
||
## Тестирование
|
||
|
||
Все тесты находятся в каталоге `tests/` (unit на бизнес-правила и интеграционные сценарии API). Запуск:
|
||
|
||
```bash
|
||
uvx pytest
|
||
```
|
||
|
||
Полезные варианты:
|
||
|
||
- Запустить только юнит-тесты сервисов: `uvx pytest tests/services -k service`.
|
||
- Запустить конкретный сценарий API: `uvx pytest tests/api/v1/test_deals.py -k won`.
|
||
|
||
Перед деплоем рекомендуется прогонять миграции на чистой БД и выполнять `uvx pytest` для проверки правил ролей/стадий.
|
||
|
||
## Линтинг и статический анализ
|
||
|
||
- `uv run ruff check app tests` — основной линтер (PEP8, сортировка импортов, дополнительные правила).
|
||
- `uv run ruff format app tests` — автоформатирование (аналог black) для единообразного стиля.
|
||
- `uv run mypy app services tests` — статическая проверка типов (строгий режим + плагин pydantic).
|
||
|
||
В CI/PR рекомендуется запускать команды именно в этом порядке, чтобы быстрее находить проблемы.
|