Перейти к основному содержимому

Системная архитектура

Canopy — это веб-приложение, построенное на основе четырёх главных компонентов. На этой странице описывается стек, объясняются проектные решения и рассматриваются дополнительные модули, расширяющие возможности платформы.

Четырёхкомпонентный стек

Browser (React SPA)

│ /api/* (HTTP proxy)

Edge Nginx ──────────────────────────► /drawio/* (self-hosted DrawIO)

│ proxy_pass :8000

FastAPI Backend (Python 3.12, uvicorn)
├── SQLAlchemy 2 (async, asyncpg)
├── Alembic migrations
├── JWT auth (HS256) + bcrypt
├── SSE event stream
└── Rate limiting (slowapi)


PostgreSQL 18

React SPA (фронтенд)

Весь интерфейс представляет собой одностраничное приложение, созданное с использованием React 18, MUI 6 и React Router 7. Сборку выполняет Vite; все страницы на уровне маршрутов используют импорты lazy() для разделения кода, так что загружается только код текущей страницы. SPA взаимодействует исключительно с бэкендом FastAPI через префикс /api/ — прямого доступа к базе данных с фронтенда нет.

Ключевые библиотеки фронтенда: AG Grid (таблица инвентаря), Recharts (графики), bpmn-js (редактирование BPMN), TipTap (форматированный текст), @dnd-kit (перетаскивание), React Flow (диаграммы архитектуры).

Бэкенд FastAPI

Бэкенд обрабатывает всю бизнес-логику, доступ к данным, применение разрешений и события реального времени. Он структурирован как набор маршрутизаторов (по одному на домен), монтируемых под /api/v1/. Все обработчики маршрутов являются асинхронными (async) и используют асинхронную сессию SQLAlchemy с драйвером asyncpg.

Аутентификация использует JWT-токены (HS256, хранящиеся в sessionStorage браузера). Хеширование паролей выполняет Bcrypt. Конфиденциальные значения, хранящиеся в базе данных (секреты SSO, пароли SMTP), шифруются симметричным алгоритмом Fernet перед записью и расшифровываются при чтении.

PostgreSQL

Все данные приложения хранятся в PostgreSQL. Управление схемой осуществляется через Alembic; приложение выполняет alembic upgrade head при каждом запуске, поэтому миграции схемы применяются автоматически при обновлении. В таблицах повсеместно используются UUID в качестве первичных ключей.

Redis, очередей сообщений и внешнего кэша нет. Обновления в реальном времени реализованы через Server-Sent Events (SSE) по long-polling HTTP-соединению напрямую с бэкенда.

Граничный Nginx

Перед контейнерами React и FastAPI расположен тонкий контейнер Nginx. Он обслуживает скомпилированное React SPA, проксирует /api/* к бэкенду (с заголовками, необходимыми для SSE), обслуживает самостоятельно размещаемый DrawIO по адресу /drawio/* и применяет заголовки безопасности (CSP, HSTS, X-Frame-Options и т. д.). В продакшне это единственный контейнер, открытый для сети.

Дополнительные модули

Ollama (AI-рекомендации)

Добавьте --profile ai к Docker Compose, чтобы запустить встроенный контейнер Ollama вместе с основным стеком. Конвейер AI-рекомендаций бэкенда вызывает HTTP API Ollama для генерации описаний карточек с использованием LLM, работающего локально. Модель полностью работает в вашей инфраструктуре.

Вы также можете направить Canopy к любому внешнему провайдеру, совместимому с Ollama (OpenAI, Anthropic через прокси и т. д.), установив AI_PROVIDER_URL.

MCP-сервер

Добавьте --profile mcp, чтобы запустить сервер Model Context Protocol. Это открывает данные Canopy для AI-ассистентов (Claude Desktop, VS Code Copilot и т. д.) в виде набора инструментов — по умолчанию только для чтения, с инструментами записи, требующими явного включения, ограниченных по размеру на один вызов, и с процессом подтверждения.

MCP-сервер выполняет аутентификацию через OAuth 2.1, делегированный провайдеру SSO Canopy, поэтому пользователи видят через инструменты MCP те же разрешения, что и в веб-интерфейсе.

Поток данных: сохранение карточки

Чтобы сделать архитектуру более наглядной, рассмотрим, что происходит при сохранении карточки пользователем:

  1. React вызывает PATCH /api/v1/cards/{id} с обновлённой полезной нагрузкой
  2. Nginx проксирует запрос к бэкенду FastAPI
  3. Обработчик маршрута проверяет JWT, проверяет разрешение пользователя inventory.edit и валидирует тело запроса с помощью схемы Pydantic
  4. SQLAlchemy записывает обновлённую строку в PostgreSQL
  5. Механизм вычислений выполняет все активные формулы для данного типа карточки
  6. Оценка качества данных пересчитывается на основе весов полей
  7. Событие публикуется в шину SSE в памяти
  8. Все подключённые браузеры получают событие и обновляют интерфейс в реальном времени

Порты и сеть

СервисВнутренний портОткрыт для хоста
Nginx (граничный)80HOST_PORT (по умолчанию 8920)
FastAPI8000Нет — только внутри сети
React (только для разработки)5173Да в dev, через Nginx в prod
PostgreSQL5432Нет — только внутри сети
Ollama (опционально)11434Нет — только внутри сети
MCP-сервер (опционально)8001Через Nginx с префиксом /mcp/

Смотрите также