Бэкенд для корпоративного сервиса микроблогов, реализованный на Python с использованием FastAPI, SQLAlchemy и PostgreSQL.
Этот проект представляет собой бэкенд-часть корпоративного сервиса микроблогов. Пользователи могут публиковать короткие сообщения ("твиты"), подписываться на других пользователей, ставить лайки и просматривать ленту новостей от тех, на кого они подписаны.
Архитектура:
- Nginx (
nginxсервис) выступает в роли входной точки (реверс-прокси), слушает порт 8000 (HTTP, с редиректом на HTTPS) и порт 8443 (HTTPS) на хост-машине. Он отвечает за:- Обеспечение HTTPS (SSL/TLS) (автоматически генерируется самоподписанный сертификат для разработки при первом запуске).
- Установку Security Headers для повышения безопасности.
- Применение Rate Limiting для защиты API от брутфорс-атак.
- Раздачу статических файлов пользовательского интерфейса (из
src/static/). - Раздачу загруженных медиафайлов (из
/media/). - Проксирование всех API-запросов (начинающихся с
/api/), документации (/docs,/redoc) и эндпоинта метрик (/metrics) на бэкенд-сервис FastAPI.
- FastAPI (
webсервис) работает под управлением Uvicorn, обрабатывает исключительно API-запросы (/api/...), взаимодействуя с базой данных PostgreSQL через асинхронный SQLAlchemy и Alembic для миграций. Запускается от non-root пользователя (appuser) для повышения безопасности. Интегрирован с Sentry для отслеживания ошибок и производительности (при наличииSENTRY_DSN). - PostgreSQL (
dbсервис) хранит все данные приложения. API-ключи пользователей хранятся в хешированном виде (Argon2 + SHA256 для поиска). - Init-контейнер (
media-initializerсервис) используется для однократного наполнения тома с медиафайлами начальными данными при первом запуске. - Prometheus (
prometheusсервис) собирает метрики с FastAPI-приложения (с эндпоинта/metrics). - Grafana (
grafanaсервис) визуализирует метрики, собранные Prometheus. Автоматически настраивается с Prometheus как источником данных. - Аутентификация пользователей предполагается внешней, бэкенд работает с предоставленным
api-keyв заголовке запроса к API, который проверяется по хешу в базе данных. - Все сервисы оркестрируются с помощью Docker Compose.
- Твиты:
- Создание нового твита (с текстом и опциональными изображениями).
- Удаление своего твита (связанные медиафайлы также удаляются).
- Лайки:
- Постановка отметки "Нравится" твиту.
- Снятие отметки "Нравится".
- Подписки:
- Подписка на другого пользователя.
- Отписка от другого пользователя.
- Лента:
- Получение персонализированной ленты твитов от пользователей, на которых подписан текущий пользователь, и своих собственных твитов.
- Сортировка ленты по популярности (количеству лайков).
- Профили:
- Получение информации о своем профиле (подписчики, подписки).
- Получение информации о профиле другого пользователя по ID.
- Медиа:
- Загрузка изображений (
POST /api/medias) для последующего прикрепления к твитам.
- Загрузка изображений (
- HTTPS: Весь трафик шифруется (используется автоматически сгенерированный самоподписанный сертификат).
- Хеширование API-ключей: Ключи хранятся в БД в виде хешей (Argon2 + SHA256).
- Rate Limiting: Nginx ограничивает частоту запросов к API для защиты от подбора ключей.
- Security Headers: Nginx устанавливает заголовки X-Frame-Options, X-Content-Type-Options, Referrer-Policy, HSTS для защиты от распространенных веб-атак.
- Non-root контейнер: Основное приложение FastAPI работает от пользователя с ограниченными правами.
- Аудит зависимостей: В CI/CD пайплайн включена проверка зависимостей на известные уязвимости (
pip-audit). - Мониторинг Ошибок: Интеграция с Sentry (опционально, через
SENTRY_DSN) для отслеживания ошибок. - Мониторинг Метрик: Сбор метрик приложения с помощью Prometheus и визуализация в Grafana.
- Язык: Python 3.12
- Веб-сервер/Прокси: Nginx (+ OpenSSL для генерации сертификата)
- Фреймворк: FastAPI
- ASGI сервер: Uvicorn
- База данных: PostgreSQL 17
- ORM: SQLAlchemy 2.0 (async)
- Драйвер БД: psycopg3 (binary)
- Миграции: Alembic
- Хеширование: Passlib (Argon2)
- Валидация данных: Pydantic V2
- Логирование: Loguru
- Мониторинг: Sentry SDK, Prometheus, Grafana
- Тестирование: Pytest, pytest-asyncio, pytest-cov, httpx
- Линтинг/Форматирование: Ruff
- Типизация: Mypy
- Аудит зависимостей: pip-audit
- CI/CD: GitHub Actions
- Контейнеризация: Docker, Docker Compose
- Прочее: aiofiles, pre-commit, python-multipart, python-dotenv, su-exec
├── .github/
│ └── workflows/
│ └── ci-cd.yml # GitHub Actions CI/CD
│
├── alembic/ # Alembic миграции БД
│
├── docker/ # Конфигурации и Dockerfiles для сервисов
│ ├── media_init/
│ │ ├── sample_media/ # Медиафайлы для демонстрации
│ │ └── Dockerfile # Dockerfile для init-контейнера медиа
│ ├── monitoring/
│ │ ├── grafana/
│ │ │ ├── dashboards/ # JSON файлы дашбордов
│ │ │ └── provisioning/ # Файлы автонастройки Grafana (datasources, dashboards)
│ │ └── prometheus/
│ │ └── prometheus.yml # Конфигурация Prometheus
│ ├── nginx/
│ │ ├── Dockerfile # Dockerfile для Nginx
│ │ ├── entrypoint.sh # Скрипт генерации сертификата и запуска Nginx
│ │ └── nginx.conf # Конфигурация Nginx
│ └── web/
│ ├── Dockerfile # Dockerfile для FastAPI приложения
│ └── entrypoint.sh # Скрипт точки входа web сервиса (миграции, chown, запуск uvicorn)
│
├── src/ # Исходный код FastAPI приложения
│ ├── api/ # API слой (роуты, зависимости)
│ ├── core/ # Ядро (конфигурация, БД, исключения, логирование, настройки sentry)
│ ├── models/ # Модели SQLAlchemy
│ ├── repositories/ # Репозитории (слой доступа к данным)
│ ├── schemas/ # Схемы Pydantic (валидация)
│ ├── services/ # Сервисы (бизнес-логика)
│ ├── static/ # Статика фронтенда (раздается Nginx)
│ └── main.py # Точка входа FastAPI приложения
│
├── tests/ # Тесты (unit, integration)
│ ├── conftest.py # Общие фикстуры для всех тестов (объекты моделей и др.)
│ ├── integration/
│ │ ├── api/ # Интеграционные тесты API
│ │ ├── core/ # Интеграционные тесты ядра приложения (ошибки)
│ │ └── conftest.py # Фикстуры для интеграционных тестов (БД, HTTP-клиент и др.)
│ └── unit/
│ ├── core/ # Unit-тесты ядра приложения (сессии, настройки конфигурации, sentry)
│ ├── dependencies/ # Unit-тесты зависимостей
│ ├── repositories/ # Unit-тесты репозиториев
│ ├── routes/ # Unit-тесты функций-обработчиков роутов
│ ├── services/ # Unit-тесты сервисов (бизнес-логика)
│ └── conftest.py # Фикстуры для unit-тестов (моки)
│
├── .dockerignore # Игнорируемые файлы Docker при сборке
├── .env.example # Шаблон файла переменных окружения
├── .gitignore # Игнорируемые файлы Git
├── .pre-commit-config.yaml # Конфигурация Pre-commit
├── alembic.ini # Конфигурация Alembic
├── docker-compose.yml # Docker Compose конфигурация (основной оркестратор)
├── pytest.ini # Конфигурация Pytest
├── requirements.txt # Зависимости для Production
├── requirements-dev.txt # Зависимости для разработки и тестов
└── README.md # Этот файл
Для запуска проекта вам понадобятся Docker и Docker Compose.
-
Клонируйте репозиторий:
git clone https://github.com/Nicksok2413/CorporateMicroblog cd CorporateMicroblog -
Создайте файл переменных окружения: Скопируйте файл
.env.exampleв.env:cp .env.example .env
Отредактируйте
.env, указав необходимые значения. РежимыTESTINGиDEBUGдолжны бытьFalseдля production. (Опционально): Чтобы включить отправку ошибок в Sentry, раскомментируйте и установите переменнуюSENTRY_DSN, указав DSN вашего проекта Sentry. ЕслиSENTRY_DSNне задан, интеграция Sentry будет отключена. -
Запустите с помощью Docker Compose: Эта команда соберет образы (если необходимо) и запустит контейнеры. Nginx будет слушать порт 8000 (HTTP, редирект на HTTPS) и 8443 (HTTPS) на вашем хосте. Копирование начальных медиафайлов будет выполнено автоматически при старте сервиса
media-initializer(отработает и завершится). При первом запуске Nginx автоматически сгенерирует самоподписанный SSL-сертификат. Миграции базы данных будет выполнена автоматически при старте сервисаweb.docker compose up -d --build
- Флаг
-dзапускает контейнеры в фоновом режиме. - Флаг
--buildпринудительно пересобирает образы (рекомендуется при первом запуске или после изменений вDockerfileили коде). - При первом запуске может потребоваться время.
- Флаг
-
Проверка:
- Веб-интерфейс будет доступен по адресу
https://localhost:8443. - HTTP (
http://localhost:8000) будет редиректить на HTTPS (https://localhost:8443). - Возможно браузер выдаст предупреждение безопасности из-за самоподписанного сертификата. Примите его ("Продолжить", "Доверять" и т.п.), чтобы продолжить.
- Документация API (Swagger UI) доступна по адресу
https://localhost:8443/docs. - Альтернативная документация (ReDoc) доступна по адресу
https://localhost:8443/redoc.
- Веб-интерфейс будет доступен по адресу
-
Остановка: Для остановки контейнеров выполните:
docker compose down
Чтобы остановить и удалить тома (volumes) с данными PostgreSQL, медиа, логами и др.:
docker compose down -v
- Метрики Prometheus:
http://localhost:9090. Сбор с/metricsсервисаweb. - Grafana UI:
http://localhost:3000(логин/пароль по умолчанию:admin/admin). - Ошибки Sentry: Если
SENTRY_DSNуказан в.env.
Все API-эндпоинты (/api/...) требуют передачи исходного (не хешированного) API-ключа пользователя в HTTP-заголовке api-key. Бэкенд сам выполнит необходимые проверки хешей.
При использовании UI (/):
- В правом верхнем углу форма для ввода API-ключа.
- В поле
'api-key текущего пользователя'по умолчанию стоит API-ключ тестового пользователя:test(пользователь Nick). - Для входа под другим пользователем введите API-ключ одного из тестовых пользователей (см. ниже) и нажмите
'Установить новый api-key'.
При использовании curl:
curl -k -X GET "https://localhost:8443/api/users/me" \
-H "accept: application/json" \
-H "api-key: test_api_key_value"
# Флаг -k нужен для curl, чтобы игнорировать ошибку самоподписанного сертификатаПри первом запуске с применением миграций создаются следующие тестовые пользователи:
| Имя | ID | API Ключ (api-key) |
Примечание |
|---|---|---|---|
| Nick | 1 | test |
Имеет твиты, подписки, лайки |
| Alice | 2 | alice_key |
Имеет твиты, подписки, лайки |
| Bob | 3 | bob_key |
Имеет твиты, подписки, лайки |
| Charlie | 4 | charlie_key |
Имеет твиты, подписки, лайки |
| David (no tweets) | 5 | david_key |
Без твитов |
Используйте соответствующие значения из колонки "API Ключ" для аутентификации от имени нужного пользователя.
Примечание: Сами ключи хранятся в базе данных в виде безопасных хешей.
Тесты используют отдельную базу данных SQLite в памяти и не требуют запущенного Docker Compose. Для запуска тестов необходимо установить зависимости для разработки. Рекомендуется делать это в виртуальном окружении.
-
Создайте и активируйте виртуальное окружение (если еще нет):
python -m venv .venv source .venv/bin/activate # Linux/macOS # .venv\Scripts\activate # Windows
-
Установите dev-зависимости:
pip install -r requirements-dev.txt
-
Отредактируйте
.env, указавTESTING=True. Для более подробного логирования можно включить режим отладки:DEBUG=True. -
Запустите тесты:
pytest
Эта команда запустит все тесты (unit и integration).
-
Запуск тестов с отчетом о покрытии:
pytest --cov=src --cov-report term-missing -vv
-
Аудит зависимостей:
pip-audit
Для поддержания качества кода используется pre-commit для автоматического запуска проверок перед каждым коммитом.
Для проверки и форматирования кода используется Ruff.
Для проверки типов используется mypy.
Запускайте в активном виртуальном окружении.
Настройка pre-commit (единоразово после клонирования):
- Убедитесь, что вы в активном виртуальном окружении.
- Установите dev-зависимости (если ещё не установлены):
pip install -r requirements-dev.txt
- Установите Git хуки:
pre-commit install
Теперь ruff будут автоматически проверяться перед каждым git commit.
Ручной запуск проверок pre-commit:
- Запуск всех pre-commit хуков на измененных файлах:
pre-commit run
- Запуск всех pre-commit хуков на всех файлах:
pre-commit run --all-files
Ruff
-
Проверка:
ruff check . -
Проверка + автоисправление:
ruff check . --fix -
Проверка форматирования:
ruff format . --check -
Автоисправление форматирования:
ruff format .
Проверка типов с mypy:
mypy srcДля управления схемой базы данных используется Alembic.
- Применение миграций: Автоматически при старте контейнера
webс помощьюentrypoint.sh. - Создание новой миграции (при изменении моделей SQLAlchemy):
После генерации внимательно просмотрите созданный файл миграции в
# Убедитесь, что сервис БД запущен (docker-compose up -d db) # Выполняйте в активном venv с установленными зависимостями alembic revision --autogenerate -m "Краткое описание изменений"
alembic/versions/перед его применением. - Применение миграций вручную (если нужно):
# Применить все до последней alembic upgrade head # Откатить последнюю миграцию alembic downgrade -1 # Посмотреть историю alembic history
Спасибо за использование сервиса!