Architettura del sistema
Canopy è un'applicazione web costruita da quattro componenti principali. Questa pagina descrive la pila tecnologica, spiega le scelte di design e illustra i moduli opzionali che è possibile aggiungere per estendere la piattaforma.
La pila a quattro componenti
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'intera interfaccia utente è un'applicazione a pagina singola costruita con React 18, MUI 6 e React Router 7. Vite gestisce la compilazione; tutte le pagine a livello di rotta utilizzano importazioni lazy() per la divisione del codice, in modo che venga caricato solo il codice della pagina corrente. La SPA comunica esclusivamente con il backend FastAPI tramite il prefisso /api/ — non vi è accesso diretto al database dal frontend.
Librerie frontend principali: AG Grid (tabella inventario), Recharts (grafici), bpmn-js (editing BPMN), TipTap (testo ricco), @dnd-kit (drag-and-drop), React Flow (diagrammi architetturali).
Backend FastAPI
Il backend gestisce tutta la logica di business, l'accesso ai dati, l'applicazione dei permessi e gli eventi in tempo reale. È strutturato come una raccolta di router (uno per dominio) che si montano tutti sotto /api/v1/. Ogni gestore di rotta è async, utilizzando la sessione asincrona di SQLAlchemy con il driver asyncpg.
L'autenticazione utilizza token JWT (HS256, memorizzati nel sessionStorage del browser). Bcrypt gestisce l'hashing delle password. I valori sensibili memorizzati nel database (segreti SSO, password SMTP) vengono cifrati con cifratura simmetrica Fernet prima della scrittura e decifrati in lettura.
PostgreSQL
Tutti i dati dell'applicazione risiedono in PostgreSQL. Lo schema è gestito da Alembic; l'applicazione esegue alembic upgrade head ad ogni avvio, quindi le migrazioni dello schema vengono applicate automaticamente all'aggiornamento. Le tabelle utilizzano chiavi primarie UUID in tutto il sistema.
Non c'è Redis, nessuna coda messaggi e nessuna cache esterna. Gli aggiornamenti in tempo reale utilizzano Server-Sent Events (SSE) tramite una connessione HTTP a lunga durata direttamente dal backend.
Nginx di bordo
Un contenitore Nginx leggero si trova davanti ai contenitori React e FastAPI. Serve la React SPA compilata, fa da proxy per /api/* verso il backend (con intestazioni appropriate per SSE), serve il DrawIO self-hosted su /drawio/* e applica intestazioni di sicurezza (CSP, HSTS, X-Frame-Options, ecc.). In produzione questo è l'unico contenitore esposto alla rete.
Moduli opzionali
Ollama (suggerimenti AI)
Aggiungere --profile ai a Docker Compose per avviare un contenitore Ollama incluso insieme alla pila principale. La pipeline di suggerimenti AI del backend chiama l'API HTTP di Ollama per generare descrizioni delle schede utilizzando un LLM in esecuzione locale. Il modello viene eseguito interamente all'interno della propria infrastruttura.
È anche possibile puntare Canopy verso qualsiasi provider esterno compatibile con Ollama (OpenAI, Anthropic tramite un proxy, ecc.) impostando AI_PROVIDER_URL.
Server MCP
Aggiungere --profile mcp per avviare il server del Protocollo di Contesto del Modello. Questo espone i dati di Canopy agli assistenti AI (Claude Desktop, VS Code Copilot, ecc.) come un insieme di strumenti — query di sola lettura per impostazione predefinita, con strumenti di scrittura opzionali protetti da limiti di dimensione per chiamata e da un flusso di conferma.
Il server MCP si autentica tramite OAuth 2.1 delegato al provider SSO di Canopy, quindi gli utenti vedono gli stessi permessi tramite gli strumenti MCP come nell'interfaccia web.
Flusso di dati: il salvataggio di una scheda
Per rendere concreta l'architettura, ecco cosa accade quando un utente salva una scheda:
- React chiama
PATCH /api/v1/cards/{id}con il contenuto aggiornato - Nginx fa da proxy della richiesta verso il backend FastAPI
- Il gestore della rotta valida il JWT, verifica il permesso
inventory.editdell'utente e valida il corpo della richiesta con uno schema Pydantic - SQLAlchemy scrive la riga aggiornata in PostgreSQL
- Il motore di calcolo esegue le formule attive per questo tipo di scheda
- Il punteggio di qualità dei dati viene ricalcolato dai pesi dei campi
- Un evento viene pubblicato sul bus SSE in memoria
- Qualsiasi browser connesso riceve l'evento e aggiorna l'interfaccia utente in tempo reale
Porte e rete
| Servizio | Porta interna | Esposto all'host |
|---|---|---|
| Nginx (bordo) | 80 | HOST_PORT (predefinito 8920) |
| FastAPI | 8000 | No — solo interno |
| React (solo sviluppo) | 5173 | Sì in sviluppo, servito via Nginx in produzione |
| PostgreSQL | 5432 | No — solo interno |
| Ollama (opzionale) | 11434 | No — solo interno |
| Server MCP (opzionale) | 8001 | Tramite il prefisso /mcp/ di Nginx |
Vedere anche
- Comprensione del metamodello — il design del modello di dati
- Integrazione MCP — configurare il server MCP
- Funzionalità AI — configurare la funzione di suggerimenti AI