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 :
- React appelle
PATCH /api/v1/cards/{id}avec le payload mis à jour - Nginx proxifie la requête vers le backend FastAPI
- Le gestionnaire de route valide le JWT, vérifie la permission
inventory.editde l'utilisateur et valide le corps de la requête avec un schéma Pydantic - SQLAlchemy écrit la ligne mise à jour dans PostgreSQL
- Le moteur de calcul exécute toutes les formules actives pour ce type de fiche
- Le score de qualité des données est recalculé à partir des poids des champs
- Un événement est publié dans le bus SSE en mémoire
- Tout navigateur connecté reçoit l'événement et met à jour l'interface en temps réel
Ports et réseau
| Service | Port interne | Exposé sur l'hôte |
|---|---|---|
| Nginx (périphérie) | 80 | HOST_PORT (défaut 8920) |
| FastAPI | 8000 | Non – interne uniquement |
| React (dev uniquement) | 5173 | Oui en dev, via Nginx en prod |
| PostgreSQL | 5432 | Non – interne uniquement |
| Ollama (optionnel) | 11434 | Non – interne uniquement |
| Serveur MCP (optionnel) | 8001 | Via le préfixe Nginx /mcp/ |
Voir aussi
- Comprendre le métamodèle – la conception du modèle de données
- Intégration MCP – configuration du serveur MCP
- Fonctionnalités IA – configuration de la fonctionnalité de suggestions IA