Systemarkitektur
Canopy er en webapplikation bygget på fire hovedkomponenter. Denne side beskriver stakken, forklarer designvalgene og dækker de valgfrie moduler, du kan tilføje for at udvide platformen.
Den firekomponent-stak
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)
Hele brugergrænsefladen er en enkeltsidesapplikation bygget med React 18, MUI 6 og React Router 7. Vite håndterer byggeprocessen; alle sider på ruteniveau bruger lazy()-imports til kodeopdeling, så kun koden til den aktuelle side indlæses. SPA'en kommunikerer udelukkende med FastAPI-backenden via /api/-præfikset — der er ingen direkte databaseadgang fra frontend.
Centrale frontend-biblioteker: AG Grid (inventartabel), Recharts (diagrammer), bpmn-js (BPMN-redigering), TipTap (formateret tekst), @dnd-kit (træk-og-slip), React Flow (arkitekturdiagrammer).
FastAPI-backend
Backenden håndterer al forretningslogik, dataadgang, håndhævelse af tilladelser og realtidshændelser. Den er struktureret som en samling routere (én pr. domæne), der alle monteres under /api/v1/. Enhver routehandler er async og bruger SQLAlchemy's asynkrone session med asyncpg-driveren.
Autentifikation bruger JWT-tokens (HS256, gemt i browserens sessionStorage). Bcrypt håndterer adgangskode-hashing. Følsomme værdier gemt i databasen (SSO-hemmeligheder, SMTP-adgangskoder) krypteres med Fernet symmetrisk kryptering før skrivning og dekrypteres ved læsning.
PostgreSQL
Alle applikationsdata ligger i PostgreSQL. Skemaet administreres af Alembic; applikationen kører alembic upgrade head ved hver opstart, så skemamigreringe anvendes automatisk ved opdatering. Tabeller bruger UUID som primærnøgler overalt.
Der er ingen Redis, ingen meddelelseskø og ingen ekstern cache. Realtidsopdateringer bruger Server-Sent Events (SSE) over en lang-polling HTTP-forbindelse direkte fra backenden.
Edge Nginx
En slank Nginx-container sidder foran React- og FastAPI-containerne. Den leverer den kompilerede React SPA, proxier /api/* til backenden (med SSE-egnede headere), leverer den selvhostede DrawIO på /drawio/* og anvender sikkerhedsheadere (CSP, HSTS, X-Frame-Options osv.). I produktion er dette den eneste container, der er eksponeret for netværket.
Valgfrie moduler
Ollama (AI-forslag)
Tilføj --profile ai til Docker Compose for at starte en medfølgende Ollama-container ved siden af hovedstakken. Backendenes AI-forslagspipeline kalder Ollama HTTP API'et for at generere kortbeskrivelser ved hjælp af en lokalt kørende LLM. Modellen kører udelukkende inden for din infrastruktur.
Du kan også pege Canopy mod en ekstern udbyder, der er kompatibel med Ollama (OpenAI, Anthropic via en proxy osv.), ved at indstille AI_PROVIDER_URL.
MCP-server
Tilføj --profile mcp for at starte Model Context Protocol-serveren. Dette eksponerer Canopys data for AI-assistenter (Claude Desktop, VS Code Copilot osv.) som et sæt værktøjer — som standard kun til læsning, med opt-in skriveværktøjer beskyttet af størrelsesgrænser pr. kald og et bekræftelsesflow.
MCP-serveren autentificerer via OAuth 2.1 delegeret til Canopys SSO-udbyder, så brugere ser de samme tilladelser via MCP-værktøjer som i webgrænsefladen.
Dataflow: gemning af et kort
For at gøre arkitekturen konkret er her, hvad der sker, når en bruger gemmer et kort:
- React kalder
PATCH /api/v1/cards/{id}med den opdaterede nyttelast - Nginx proxier anmodningen til FastAPI-backenden
- Routehandleren validerer JWT, kontrollerer brugerens
inventory.edit-tilladelse og validerer anmodningskroppen med et Pydantic-skema - SQLAlchemy skriver den opdaterede række til PostgreSQL
- Beregningsmotoren kører eventuelle aktive formler for denne korttype
- Datakvalitetsscoren genberegnes ud fra felternes vægte
- En hændelse publiceres til den hukommelsesbaserede SSE-bus
- Alle tilsluttede browsere modtager hændelsen og opdaterer brugergrænsefladen i realtid
Porte og netværk
| Tjeneste | Intern port | Eksponeret for vært |
|---|---|---|
| Nginx (edge) | 80 | HOST_PORT (standard 8920) |
| FastAPI | 8000 | Nej — kun intern |
| React (kun dev) | 5173 | Ja i dev, leveret via Nginx i prod |
| PostgreSQL | 5432 | Nej — kun intern |
| Ollama (valgfri) | 11434 | Nej — kun intern |
| MCP-server (valgfri) | 8001 | Via Nginx /mcp/-præfiks |
Se også
- Forståelse af metamodellen — design af datamodellen
- MCP-integration — konfiguration af MCP-serveren
- AI-funktioner — konfiguration af AI-forslagsfunktionen