Aller au contenu principal

Architecture du système

Canopy est une application web construite à partir de quatre composants principaux. Cette page décrit la pile, explique les choix de conception et couvre les modules optionnels que vous pouvez ajouter pour étendre la plateforme.

La pile à quatre composants

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 (frontend)

L'intégralité de l'interface est une application monopage construite avec React 18, MUI 6 et React Router 7. Vite gère le build ; toutes les pages au niveau des routes utilisent des imports lazy() pour le découpage du code, de sorte que seul le code de la page courante est chargé. La SPA communique exclusivement avec le backend FastAPI via le préfixe /api/ – il n'y a pas d'accès direct à la base de données depuis le frontend.

Bibliothèques frontend clés : AG Grid (tableau d'inventaire), Recharts (graphiques), bpmn-js (édition BPMN), TipTap (texte enrichi), @dnd-kit (glisser-déposer), React Flow (diagrammes d'architecture).

Backend FastAPI

Le backend gère l'ensemble de la logique métier, l'accès aux données, l'application des permissions et les événements en temps réel. Il est structuré comme une collection de routeurs (un par domaine) qui s'attachent tous sous /api/v1/. Chaque gestionnaire de route est async, utilisant la session asynchrone de SQLAlchemy avec le pilote asyncpg.

L'authentification utilise des tokens JWT (HS256, stockés dans le sessionStorage du navigateur). Bcrypt gère le hachage des mots de passe. Les valeurs sensibles stockées dans la base de données (secrets SSO, mots de passe SMTP) sont chiffrées avec un chiffrement symétrique Fernet avant l'écriture et déchiffrées à la lecture.

PostgreSQL

Toutes les données de l'application résident dans PostgreSQL. Le schéma est géré par Alembic ; l'application exécute alembic upgrade head à chaque démarrage, de sorte que les migrations de schéma sont appliquées automatiquement lors des mises à jour. Les tables utilisent des clés primaires UUID partout.

Il n'y a pas de Redis, pas de file de messages et pas de cache externe. Les mises à jour en temps réel utilisent les Server-Sent Events (SSE) via une connexion HTTP à long sondage directement depuis le backend.

Nginx en périphérie

Un conteneur Nginx léger se place devant les conteneurs React et FastAPI. Il sert la SPA React compilée, proxifie /api/* vers le backend (avec les en-têtes appropriés pour SSE), sert le DrawIO auto-hébergé sous /drawio/* et applique les en-têtes de sécurité (CSP, HSTS, X-Frame-Options, etc.). En production, c'est le seul conteneur exposé au réseau.

Modules optionnels

Ollama (suggestions IA)

Ajoutez --profile ai à Docker Compose pour démarrer un conteneur Ollama intégré aux côtés de la pile principale. Le pipeline de suggestions IA du backend appelle l'API HTTP Ollama pour générer des descriptions de fiches à l'aide d'un LLM fonctionnant localement. Le modèle s'exécute entièrement au sein de votre infrastructure.

Vous pouvez également pointer Canopy vers n'importe quel fournisseur externe compatible Ollama (OpenAI, Anthropic via un proxy, etc.) en définissant AI_PROVIDER_URL.

Serveur MCP

Ajoutez --profile mcp pour démarrer le serveur Model Context Protocol. Cela expose les données de Canopy aux assistants IA (Claude Desktop, VS Code Copilot, etc.) sous forme d'un ensemble d'outils – des requêtes en lecture seule par défaut, avec des outils d'écriture optionnels protégés par des limites de taille par appel et un flux de confirmation.

Le serveur MCP s'authentifie via OAuth 2.1 délégué au fournisseur SSO de Canopy, de sorte que les utilisateurs voient les mêmes permissions via les outils MCP que dans l'interface web.

Flux de données : enregistrement d'une fiche

Pour rendre l'architecture concrète, voici ce qui se passe lorsqu'un utilisateur enregistre une fiche :

  1. React appelle PATCH /api/v1/cards/{id} avec le payload mis à jour
  2. Nginx proxifie la requête vers le backend FastAPI
  3. Le gestionnaire de route valide le JWT, vérifie la permission inventory.edit de l'utilisateur et valide le corps de la requête avec un schéma Pydantic
  4. SQLAlchemy écrit la ligne mise à jour dans PostgreSQL
  5. Le moteur de calcul exécute toutes les formules actives pour ce type de fiche
  6. Le score de qualité des données est recalculé à partir des poids des champs
  7. Un événement est publié dans le bus SSE en mémoire
  8. Tout navigateur connecté reçoit l'événement et met à jour l'interface en temps réel

Ports et réseau

ServicePort interneExposé sur l'hôte
Nginx (périphérie)80HOST_PORT (défaut 8920)
FastAPI8000Non – interne uniquement
React (dev uniquement)5173Oui en dev, via Nginx en prod
PostgreSQL5432Non – interne uniquement
Ollama (optionnel)11434Non – interne uniquement
Serveur MCP (optionnel)8001Via le préfixe Nginx /mcp/

Voir aussi