Fullstack-разработка сервиса аналитики: FastAPI, MySQL и Next.js

Практический курс по созданию системы сбора и визуализации данных с нуля. Вы научитесь связывать высокопроизводительный бэкенд на Python с реляционной базой данных и современным фронтендом для отображения метрик.

1. Основы архитектуры: настройка окружения FastAPI и интеграция с базой данных MySQL

Основы архитектуры: настройка окружения FastAPI и интеграция с базой данных MySQL

Добро пожаловать в курс Fullstack-разработка сервиса аналитики. В этом цикле статей мы с нуля создадим полноценный сервис для сбора и визуализации данных, используя современные и производительные инструменты. Наша цель — построить приложение, способное обрабатывать входящие события (аналитику), сохранять их в надежную реляционную базу данных и отображать статистику на клиентской части.

В этой первой статье мы заложим фундамент нашего бэкенда. Мы разберем архитектуру приложения, настроим рабочее окружение Python, установим FastAPI и научимся правильно подключаться к базе данных MySQL, используя ORM SQLAlchemy.

Архитектура проекта

Прежде чем писать код, важно понимать, как компоненты нашей системы будут взаимодействовать друг с другом. Мы используем классическую трехзвенную архитектуру:

  • Frontend (Next.js): Клиентская часть, которая будет отправлять данные аналитики и запрашивать отчеты.
  • Backend (FastAPI): Серверная часть, обрабатывающая HTTP-запросы, валидирующая данные и содержащая бизнес-логику.
  • Database (MySQL): Хранилище данных, где будет лежать вся наша статистика.
  • !Схема взаимодействия компонентов: Клиент, Фронтенд, Бэкенд и База данных

    Почему именно этот стек?

    * FastAPI: Один из самых быстрых Python-фреймворков. Он поддерживает асинхронность из коробки и автоматически генерирует документацию (Swagger UI). * MySQL: Проверенная временем реляционная база данных, отлично подходящая для структурированных данных аналитики. * SQLAlchemy: Мощная ORM (Object-Relational Mapping), позволяющая работать с базой данных, используя объекты Python вместо написания «сырых» SQL-запросов.

    Настройка окружения

    Для начала работы вам потребуется установленный Python версии 3.10 или выше. Мы будем использовать виртуальное окружение, чтобы изолировать зависимости нашего проекта от системных библиотек.

    1. Создание проекта и виртуального окружения

    Создайте папку для проекта и перейдите в нее через терминал:

    Теперь создадим виртуальное окружение. В зависимости от вашей операционной системы команды могут немного отличаться.

    Для Windows:

    Для macOS и Linux:

    После активации вы увидите префикс (venv) в командной строке.

    2. Установка зависимостей

    Нам понадобятся следующие библиотеки:

    * fastapi: Сам веб-фреймворк. * uvicorn: ASGI-сервер для запуска FastAPI. * sqlalchemy: Инструмент для работы с базой данных. * pymysql: Драйвер для подключения к MySQL (SQLAlchemy использует его под капотом). * python-dotenv: Библиотека для управления переменными окружения (чтобы не хранить пароли в коде).

    Выполните команду установки:

    Структура проекта

    Хорошая архитектура начинается с правильной структуры папок. Не стоит сваливать весь код в один файл. Мы будем придерживаться следующей структуры:

    Создайте папку app и пустые файлы внутри нее согласно схеме выше.

    Настройка базы данных MySQL

    Предполагается, что у вас уже установлен MySQL сервер (локально или через Docker). Если вы используете Docker, запустить экземпляр MySQL можно одной командой:

    Эта команда запустит базу данных analytics_db на порту 3306 с паролем secret.

    Конфигурация через .env

    Никогда не пишите пароли от базы данных прямо в Python-коде. Используйте файл .env. Откройте его и добавьте строку подключения:

    Формат строки: протокол+драйвер://пользователь:пароль@хост:порт/имя_базы.

    Подключение через SQLAlchemy

    Теперь настроим файл app/database.py. Этот код будет отвечать за создание соединения (Engine) и сессий.

    > Важно: Функция get_db использует конструкцию yield. Это позволяет FastAPI создавать новую сессию для каждого запроса и автоматически закрывать её после завершения обработки, даже если произошла ошибка.

    Создание первой модели

    Чтобы проверить подключение, опишем простую модель. В файле app/models.py создадим таблицу для хранения событий.

    Здесь мы наследуемся от Base, который создали в database.py. SQLAlchemy автоматически превратит этот класс в SQL-запрос CREATE TABLE.

    Точка входа: main.py

    Теперь соберем всё вместе в файле app/main.py.

    Обратите внимание на Depends(database.get_db). Это механизм внедрения зависимостей (Dependency Injection) в FastAPI. Он гарантирует, что у нас будет активная сессия базы данных внутри функции, и она корректно закроется после.

    Запуск сервера

    Для запуска приложения мы используем Uvicorn. Находясь в корневой папке проекта (где лежит папка app), выполните:

    * app.main:app: путь к объекту приложения FastAPI (файл app/main.py, переменная app). * --reload: флаг, который перезапускает сервер при изменении кода (полезно при разработке).

    Если все прошло успешно, вы увидите в терминале сообщение о том, что сервер запущен на http://127.0.0.1:8000.

    Откройте браузер и перейдите по адресу http://127.0.0.1:8000/docs. Вы увидите автоматически сгенерированную документацию Swagger UI, где можно протестировать наши эндпоинты / и /health.

    В следующей статье мы углубимся в создание схем данных Pydantic и реализуем полноценный API для приема аналитических событий.

    2. Проектирование схемы данных и реализация API для приема и записи аналитических событий

    Проектирование схемы данных и реализация API для приема и записи аналитических событий

    В предыдущей статье мы успешно настроили окружение, установили FastAPI и подключились к базе данных MySQL. Теперь наш «двигатель» запущен, но автомобиль пока никуда не едет. Чтобы сервис начал приносить пользу, нам нужно научить его принимать данные, проверять их на корректность и аккуратно складывать в базу данных.

    В этой статье мы займемся проектированием схем данных (Schemas), расширением моделей базы данных и реализацией API-эндпоинтов для регистрации событий. Мы разберем, чем отличаются Pydantic-модели от SQLAlchemy-моделей, и реализуем паттерн CRUD (Create, Read, Update, Delete).

    Разделение ответственности: Pydantic vs SQLAlchemy

    В мире FastAPI существует четкое разделение между тем, как данные выглядят в базе данных, и тем, как они передаются по сети (в API). Для этого используются две разные библиотеки:

  • SQLAlchemy (Models): Описывает структуру таблиц в базе данных. Эти классы отвечают за то, как данные хранятся.
  • Pydantic (Schemas): Описывает структуру данных в запросах и ответах API. Эти классы отвечают за валидацию и сериализацию (преобразование в JSON).
  • !Схема прохождения данных от клиента до базы данных через слои валидации и ORM

    Такое разделение позволяет нам, например, скрыть внутренний id пользователя или хэш пароля при отправке ответа клиенту, но при этом хранить их в базе.

    Шаг 1: Проектирование Pydantic-схем

    Создадим файл app/schemas.py. Здесь мы опишем, какие данные мы ожидаем получить от фронтенда (Next.js) при наступлении аналитического события.

    Нам понадобятся следующие поля: * event_type: Тип события (например, page_view, button_click). * page_url: Адрес страницы, где произошло событие. * custom_data: Дополнительные данные в формате JSON (например, ID товара или координаты клика).

    Обратите внимание на model_config. Эта настройка сообщает Pydantic, что данные могут приходить не только в виде словаря, но и в виде объектов ORM (SQLAlchemy). Это критически важно для корректной работы ответов API.

    Шаг 2: Расширение модели базы данных

    В прошлой статье мы создали простую модель Event. Давайте доработаем её в файле app/models.py, чтобы она соответствовала нашим новым требованиям. Мы будем использовать тип JSON для хранения произвольных данных события.

    Использование типа JSON в MySQL (доступно с версии 5.7) позволяет нам сохранять гибкую структуру данных без необходимости создавать отдельные таблицы для каждого типа атрибутов.

    Шаг 3: Слой работы с данными (CRUD)

    Чтобы не загромождать код контроллеров (в main.py), хорошей практикой является вынос логики работы с базой данных в отдельный файл. Создайте файл app/crud.py.

    Здесь мы напишем функции для создания события и получения списка событий.

    Этот слой абстракции изолирует логику базы данных. Если завтра мы решим сменить MySQL на PostgreSQL, нам придется менять код в основном здесь, а не во всем приложении.

    Шаг 4: Реализация API эндпоинтов

    Теперь соберем всё воедино в app/main.py. Мы создадим два маршрута:

  • POST /events/ — для записи нового события.
  • GET /events/ — для просмотра списка событий.
  • Обновите содержимое app/main.py:

    Разбор магии FastAPI

    В декораторе @app.post мы указали response_model=schemas.Event. Это говорит FastAPI: > "Какой бы объект ни вернула функция, отфильтруй его и приведи к виду, описанному в схеме schemas.Event".

    Это гарантирует, что мы не вернем клиенту лишние данные, и автоматически сгенерирует документацию.

    Тестирование API

    Запустите сервер, если он еще не запущен:

    Перейдите в браузере по адресу http://127.0.0.1:8000/docs. Вы увидите интерактивную документацию Swagger UI.

    1. Создание события

    Раскройте блок POST /events/, нажмите "Try it out" и вставьте следующий JSON:

    Нажмите Execute. В ответе вы должны получить JSON с добавленными полями id и created_at.

    2. Получение событий

    Раскройте блок GET /events/, нажмите "Try it out" и затем Execute. Вы увидите массив событий, которые вы только что создали.

    Важность валидации данных

    Попробуйте отправить некорректные данные в POST запросе. Например, уберите обязательное поле page_url или отправьте число вместо строки в event_type.

    FastAPI автоматически вернет ошибку 422 Unprocessable Entity с подробным описанием того, какое поле не прошло проверку. Нам не пришлось писать ни одной строчки кода if type != str — Pydantic сделал это за нас.

    Заключение

    Сегодня мы реализовали сердце нашего бэкенда. Мы научились:

  • Описывать схемы данных с помощью Pydantic.
  • Использовать тип JSON в MySQL через SQLAlchemy.
  • Организовывать код с помощью паттерна CRUD.
  • Создавать API-эндпоинты, которые автоматически валидируют входящие данные.
  • Теперь наш бэкенд готов принимать данные. В следующей статье мы переключимся на фронтенд и начнем создавать клиентское приложение на Next.js, которое будет отправлять реальную аналитику на наш сервер.

    3. Бизнес-логика и агрегация: создание оптимизированных эндпоинтов для выдачи статистики

    Бизнес-логика и агрегация: создание оптимизированных эндпоинтов для выдачи статистики

    В предыдущих статьях мы заложили фундамент нашего сервиса аналитики: настроили FastAPI, подключили MySQL и научились сохранять сырые события. Теперь наша база данных наполняется информацией о просмотрах страниц и кликах. Однако, просто хранить данные недостаточно. Ценность аналитики заключается не в самих записях, а в выводах, которые можно из них сделать.

    В этой статье мы займемся бизнес-логикой и агрегацией данных. Мы научимся превращать тысячи строк сырых логов в понятные графики и цифры, не перегружая при этом ни сервер, ни базу данных.

    Проблема «сырых» данных

    Представьте, что ваш сервис собрал 100 000 событий за сутки. Если фронтенд запросит их все сразу (SELECT * FROM events), произойдет следующее:

  • База данных будет долго читать данные с диска.
  • Сеть будет перегружена передачей огромного JSON-файла (мегабайты данных).
  • Браузер пользователя «зависнет», пытаясь обработать этот массив в JavaScript.
  • Вместо этого мы должны переложить тяжелую работу на базу данных. MySQL — это не просто хранилище, это мощный вычислительный движок, оптимизированный для математических операций над множествами строк.

    !Процесс агрегации: превращение большого объема сырых данных в компактную статистику

    Инструменты агрегации в SQLAlchemy

    Для выполнения агрегации (подсчета количества, суммирования, вычисления среднего) в SQL используются функции COUNT, SUM, AVG и оператор GROUP BY. В SQLAlchemy доступ к этим функциям предоставляет модуль func.

    Нам понадобятся следующие инструменты:

    * func.count(Column): Подсчитывает количество записей. * func.date(Column): Извлекает дату из временной метки (отбрасывая время), что полезно для группировки по дням. * group_by(Column): Группирует результаты по значению определенной колонки.

    Проектирование схем ответов (Pydantic)

    Прежде чем писать запросы к БД, давайте определим, в каком виде мы хотим отдавать данные на фронтенд. Поскольку результаты агрегации не соответствуют нашей модели Event (у них нет id, page_url и т.д., зато есть count), нам нужны новые Pydantic-схемы.

    Откройте файл app/schemas.py и добавьте следующие классы:

    Эти простые схемы позволят FastAPI автоматически генерировать документацию и валидировать данные, которые мы вернем из базы.

    Реализация агрегации в CRUD

    Теперь перейдем к самому интересному — написанию SQL-запросов на языке Python. Откройте app/crud.py и добавьте новые функции.

    1. Подсчет событий по типам

    Мы хотим узнать, сколько раз нажали кнопку (click) и сколько раз просмотрели страницу (page_view).

    Обратите внимание на .label("count"). Это позволяет нам дать имя вычисляемой колонке, чтобы Pydantic смог сопоставить её с полем count в нашей схеме StatByType.

    2. Динамика событий по дням

    Для построения графика на фронтенде нам нужно знать, сколько событий происходило в каждый конкретный день.

    Здесь мы используем func.date, чтобы обрезать часы и минуты. Если этого не сделать, группировка будет бесполезной, так как каждое событие имеет уникальное время вплоть до миллисекунд.

    Математика метрик: расчет CTR

    Часто аналитика требует не просто подсчета, а вычисления производных метрик. Одной из ключевых метрик является CTR (Click-Through Rate) — показатель кликабельности.

    Формула расчета CTR выглядит следующим образом:

    Где: * — показатель кликабельности в процентах. * (Clicks) — количество кликов (событий с типом click). * (Views) — количество просмотров (событий с типом page_view).

    Если , то формула не имеет смысла (деление на ноль), что нужно учитывать в коде.

    Давайте реализуем функцию для получения сводной статистики, включая CTR, в app/crud.py:

    Метод .scalar() выполняет запрос и возвращает единственное значение (число), а не список строк.

    Создание эндпоинтов в FastAPI

    Теперь подключим наши новые функции к API. Откройте app/main.py и добавьте новые маршруты.

    Не забудьте обновить импорты и добавить новые схемы в app/schemas.py, если вы хотите типизировать ответ для get_summary_stats (например, создать схему SummaryStats).

    Оптимизация производительности: Индексы

    Когда в таблице events будет миллион записей, запросы с GROUP BY и FILTER могут стать медленными. Чтобы ускорить их, база данных должна иметь индексы.

    В нашей модели Event (файл app/models.py) мы уже позаботились об этом:

    Однако для фильтрации по дате нам также стоит добавить индекс на поле created_at. В SQLAlchemy это делается так:

    Индекс работает как алфавитный указатель в книге: базе данных не нужно перебирать все страницы (строки), чтобы найти нужные записи.

    Проверка работы

  • Запустите сервер: uvicorn app.main:app --reload.
  • Откройте Swagger UI: http://127.0.0.1:8000/docs.
  • Сгенерируйте несколько событий через POST /events/ (с разными типами click и page_view).
  • Проверьте новые эндпоинты GET /stats/....
  • Вы должны увидеть агрегированные данные, готовые для отрисовки графиков.

    Заключение

    Сегодня мы превратили наш сервис из простого «регистратора» в аналитический инструмент. Мы научились:

  • Использовать func и group_by в SQLAlchemy для вычислений на стороне БД.
  • Создавать специализированные Pydantic-схемы для статистики.
  • Считать производные метрики (CTR).
  • Понимать важность индексов для производительности.
  • Теперь наш бэкенд полностью готов. В следующей части курса мы перейдем к разработке фронтенда на Next.js, где визуализируем эти данные с помощью красивых диаграмм.

    4. Разработка клиентской части на Next.js: настройка SSR, интеграция API и визуализация графиков

    Разработка клиентской части на Next.js: настройка SSR, интеграция API и визуализация графиков

    Мы прошли долгий путь: спроектировали базу данных MySQL, написали производительный API на FastAPI и реализовали сложную логику агрегации данных. Теперь у нас есть мощный бэкенд, который умеет считать клики и просмотры. Но для конечного пользователя этот бэкенд невидим. Ему нужен красивый и понятный интерфейс — дашборд.

    В этой финальной статье цикла мы создадим клиентское приложение на Next.js. Мы разберем, как работает Server-Side Rendering (SSR), научимся запрашивать данные у нашего Python-сервиса и визуализируем статистику с помощью графиков.

    Почему Next.js для аналитики?

    Next.js — это фреймворк поверх React, который стал стандартом индустрии. Для сервиса аналитики он подходит идеально по нескольким причинам:

  • Server-Side Rendering (SSR): Страница с отчетами формируется на сервере. Пользователь получает уже готовый HTML с цифрами, а не пустую страницу с крутящимся спиннером загрузки.
  • Оптимизация производительности: Next.js автоматически оптимизирует изображения, шрифты и скрипты.
  • Удобная маршрутизация: Файловая система App Router позволяет легко создавать новые страницы отчетов.
  • !Поток данных при серверном рендеринге: Next.js выступает посредником между клиентом и API

    Настройка проекта

    Для начала создадим новое приложение. Убедитесь, что у вас установлен Node.js (рекомендуется версия 18+). Откройте терминал и выполните команду:

    В процессе установки выберите следующие опции: * TypeScript: Yes * ESLint: Yes * Tailwind CSS: Yes (это ускорит верстку) * App Router: Yes

    После установки перейдите в папку проекта и установим библиотеку для графиков. Мы будем использовать Recharts — это надежная и простая в использовании библиотека для React.

    Архитектура данных: Серверные и Клиентские компоненты

    В современном Next.js (App Router) компоненты по умолчанию являются серверными (Server Components). Это означает, что их код выполняется только на сервере Node.js. Они могут напрямую делать HTTP-запросы к нашему FastAPI бэкенду.

    Однако графики требуют взаимодействия с браузером (DOM, анимации, наведение мыши). Поэтому компоненты графиков должны быть клиентскими (Client Components).

    Наша стратегия будет такой:

  • Главная страница (page.tsx) — серверный компонент. Он загружает данные из API.
  • Компонент графика (Chart.tsx) — клиентский компонент. Он получает данные через пропсы (props) и рисует их.
  • Шаг 1: Получение данных (Server Side)

    Откройте файл app/page.tsx. Мы удалим стандартный шаблон и напишем функцию для получения данных.

    Предположим, наш FastAPI запущен на http://127.0.0.1:8000.

    bash npm run dev python from fastapi.middleware.cors import CORSMiddleware

    app.add_middleware( CORSMiddleware, allow_origins=["http://localhost:3000"], # Разрешаем запросы с фронтенда allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) ```

    Заключение курса

    Поздравляю! Мы завершили цикл статей по созданию Fullstack-сервиса аналитики. Мы прошли полный путь:

  • Развернули FastAPI и спроектировали базу данных.
  • Настроили MySQL и ORM SQLAlchemy.
  • Реализовали API для приема и агрегации событий.
  • Создали современный фронтенд на Next.js.
  • Теперь у вас есть надежный шаблон для создания собственных высоконагруженных приложений. Вы можете расширять этот проект: добавить авторизацию, фильтры по датам, экспорт в CSV или WebSocket для обновления данных в реальном времени.

    5. Финальная сборка, Docker-контейнеризация и развертывание готового сервиса аналитики

    Финальная сборка, Docker-контейнеризация и развертывание готового сервиса аналитики

    Поздравляю! Мы добрались до финального этапа нашего курса. У нас есть работающий бэкенд на FastAPI, база данных MySQL с реальными данными и красивый фронтенд на Next.js. Однако, пока что всё это работает только на вашем локальном компьютере, в разных терминалах, и зависит от конкретных версий библиотек, установленных в вашей системе.

    В этой статье мы превратим наш разрозненный набор скриптов в профессиональный, готовый к развертыванию продукт. Мы упакуем каждый компонент в изолированный контейнер Docker, настроим их взаимодействие через Docker Compose и обсудим, как запустить эту систему на боевом сервере.

    Проблема «У меня всё работает»

    В традиционной разработке часто возникает ситуация, когда код отлично работает на машине разработчика, но ломается при переносе на сервер или компьютер коллеги. Причины могут быть разными:

    * Разные версии Python или Node.js. * Отличия в операционных системах (Windows vs Linux). * Конфликтующие зависимости.

    Docker решает эту проблему кардинально. Он позволяет упаковать приложение вместе со всем его окружением (библиотеками, системными утилитами, настройками) в единый образ. Если приложение работает в Docker-контейнере у вас, оно гарантированно будет работать везде, где установлен Docker.

    !Иллюстрация того, как Docker изолирует сервисы друг от друга, но позволяет им работать на одной хост-машине.

    Подготовка Бэкенда (FastAPI)

    Начнем с нашего API. Чтобы запустить Python-приложение в контейнере, нам нужно создать инструкцию для сборки образа — файл Dockerfile.

    Создайте файл с именем Dockerfile (без расширения) в папке analytics_service (там, где лежит requirements.txt):

    Что здесь происходит?

  • FROM: Мы берем за основу Linux с уже установленным Python. Версия slim весит значительно меньше полной версии.
  • WORKDIR: Все последующие команды будут выполняться в папке /app внутри контейнера.
  • COPY & RUN: Мы устанавливаем библиотеки. Разделение копирования requirements.txt и остального кода — это best practice для ускорения сборки.
  • CMD: Запускаем Uvicorn. Обратите внимание на --host 0.0.0.0. Если оставить 127.0.0.1 (по умолчанию), сервис будет доступен только внутри самого контейнера, и мы не сможем достучаться до него снаружи.
  • Подготовка Фронтенда (Next.js)

    Теперь перейдем к папке analytics-frontend. Next.js требует сборки (build) перед запуском в продакшн.

    Создайте Dockerfile в корне папки фронтенда:

    Этот образ создаст готовую к работе версию нашего сайта, которая использует Server-Side Rendering (SSR).

    Оркестрация с Docker Compose

    У нас есть три компонента:

  • MySQL (база данных).
  • FastAPI (бэкенд).
  • Next.js (фронтенд).
  • Запускать их по отдельности вручную неудобно. Нам нужно описать их взаимодействие, порядок запуска и сетевые настройки. Для этого используется инструмент Docker Compose.

    Создайте файл docker-compose.yml в корневой папке, объединяющей оба проекта (или создайте новую папку для деплоя и перенесите туда проекты). Структура должна быть примерно такой:

    Содержимое docker-compose.yml:

    Ключевые моменты конфигурации

  • Networking (Сети): Все сервисы находятся в одной сети analytics_network. Это позволяет им общаться друг с другом по именам сервисов. Бэкенд видит базу данных по адресу db, а не localhost.
  • Volumes (Тома): Строка - mysql_data:/var/lib/mysql критически важна. Контейнеры эфемерны — при их удалении все данные внутри стираются. Подключая volume, мы говорим Docker хранить файлы базы данных в специальной области на жестком диске вашего компьютера.
  • Depends_on: Эта директива указывает Docker, что бэкенд не стоит запускать раньше базы данных, а фронтенд — раньше бэкенда. Примечание: Docker ждет только запуска контейнера, а не полной готовности сервиса внутри, поэтому в продакшене часто используют скрипты wait-for-it.
  • Нюансы взаимодействия Frontend и Backend

    Здесь есть тонкий момент, связанный с Next.js. У нас есть два типа запросов:

  • Server-Side (SSR): Когда Next.js рендерит страницу на сервере (внутри контейнера frontend), он делает запрос к API. В этом случае он должен использовать адрес внутренней сети Docker: http://backend:8000.
  • Client-Side (Browser): Когда график на странице обновляется или пользователь нажимает кнопку, запрос идет из браузера пользователя. Браузер ничего не знает о внутренней сети Docker. Он должен стучаться на внешний адрес: http://localhost:8000 (или домен сервера).
  • Чтобы это работало корректно, в docker-compose.yml для фронтенда часто передают переменные окружения:

    В коде Next.js вам нужно будет использовать соответствующую переменную в зависимости от того, где выполняется код.

    Запуск и проверка

    Теперь, когда всё настроено, запуск всего стека выполняется одной командой в терминале (из папки с docker-compose.yml):

    Флаг --build заставляет Docker пересобрать образы, если вы меняли код.

    Вы увидите логи всех трех сервисов в одном окне. Если всё прошло успешно:

  • База данных инициализируется.
  • Бэкенд подключится к БД и применит миграции (если вы настроили их автозапуск).
  • Фронтенд соберется и запустится на порту 3000.
  • Откройте http://localhost:3000. Вы должны увидеть ваш дашборд. Данные, которые вы создадите, сохранятся даже если вы остановите контейнеры (Ctrl+C) и запустите их снова.

    Развертывание на сервере (Deployment)

    Как перенести это на реальный сервер (VPS)?

  • Аренда сервера: Вам подойдет любой Linux-сервер (Ubuntu 20.04/22.04) с установленным Docker и Docker Compose.
  • Перенос кода: Вы можете использовать Git. Загрузите код на GitHub/GitLab, зайдите на сервер по SSH и склонируйте репозиторий.
  • Настройка переменных: Создайте файл .env на сервере с реальными паролями и настройками.
  • Запуск: Выполните docker-compose up -d. Флаг -d (detach) запустит контейнеры в фоновом режиме.
  • Reverse Proxy (Nginx)

    В реальном мире не принято открывать порты 3000 и 8000 наружу. Обычно перед приложением ставят веб-сервер Nginx.

    Он выполняет роль швейцара: * Принимает запросы на 80 порт (HTTP) или 443 (HTTPS). * Раздает статику. * Перенаправляет запросы /api/ на контейнер бэкенда. * Остальные запросы перенаправляет на контейнер фронтенда.

    Для этого в docker-compose добавляется четвертый сервис — nginx, который проксирует трафик внутри сети Docker.

    Заключение курса

    Мы прошли огромный путь. Мы начали с пустой папки и закончили полноценной микросервисной архитектурой, упакованной в контейнеры. Вы научились:

    * Проектировать схемы данных в MySQL и работать с ними через SQLAlchemy. * Создавать быстрые и типизированные API на FastAPI. * Реализовывать сложную бизнес-логику и агрегацию данных. * Строить современные интерфейсы на Next.js. * Использовать Docker для создания воспроизводимой среды разработки и деплоя.

    Эти навыки — фундамент для создания любых современных веб-сервисов, от личных блогов до высоконагруженных корпоративных систем. Продолжайте экспериментировать, добавляйте новые метрики, улучшайте графики и оптимизируйте запросы. Удачи в разработке!