Diagrammes
Modèle Conceptuel de Données (MCD)
Généré depuis packages/db/prisma/schema/.
erDiagram
User {
string id PK
string name
string email
enum accountType
boolean onboardingCompleted
}
Plot {
uuid id PK
string name
enum source
float surface
geometry geom
string cultureType
string userId FK
boolean isActiveRpg
}
ActionPlan {
string id PK
string title
string userId FK
}
Task {
string id PK
string title
enum status
int rank
datetime deadline
string actionPlanId FK
string plotId FK
}
PilotProfile {
string id PK
string userId FK
boolean available
int score
}
Drone {
string id PK
string name
string model
string pilotProfileId FK
}
Sensor {
string id PK
string name
string sensorKindCode FK
string pilotProfileId FK
}
SensorKind {
string code PK
string name
boolean active
}
Mission {
string id PK
string farmerId FK
enum type
enum status
float totalSurface
float price
datetime windowStart
datetime windowEnd
string pilotProfileId FK
}
AnalysisOption {
string id PK
string code
string name
float basePrice
float pricePerHa
}
Deliverable {
string id PK
string missionId FK
string[] files
}
Payment {
string id PK
string missionId FK
float amount
enum status
}
Flight {
string id PK
datetime scheduledAt
enum status
string plotId FK
string pilotId FK
}
User ||--o{ Plot : "possède"
User ||--o{ ActionPlan : "crée"
User ||--o| PilotProfile : "est"
User ||--o{ Mission : "publie"
ActionPlan ||--o{ Task : "contient"
Task }o--o| Plot : "liée à"
PilotProfile ||--o{ Drone : "possède"
PilotProfile ||--o{ Sensor : "équipé de"
Sensor }o--|| SensorKind : "de type"
PilotProfile ||--o{ Mission : "accepte"
Mission }o--o{ Plot : "couvre"
Mission }o--o{ SensorKind : "requiert"
Mission }o--o{ AnalysisOption : "inclut"
Mission ||--o| Deliverable : "livre"
Mission ||--o| Payment : "facturée"
Plot ||--o{ Flight : "survol"
Architecture Logicielle
Monolithe modulaire · Monorepo Turborepo · 3 apps + 6 packages partagés.
graph TB
subgraph Clients
WA["web-agri\nNext.js · :3001\nAgriculteurs"]
WP["web-pilots\nNext.js · :3002\nPilotes"]
MOB["Mobile\nFlutter · iOS & Android"]
end
subgraph Server["Serveur Fastify · :3000"]
ORPC["oRPC /rpc/*"]
AUTH["Better-Auth /api/auth/*"]
subgraph Routers["packages/api"]
direction LR
R1["plots"] --- R2["missions"]
R2 --- R3["actions"]
R3 --- R4["ai"]
R4 --- R5["pilots"]
R5 --- R6["weather"]
end
end
subgraph Infra["Infrastructure"]
PG[("PostgreSQL\n+ PostGIS")]
OLLAMA["Ollama LLM\n:11434"]
S3["S3 Storage"]
STRIPE["Stripe"]
end
WA -->|"HTTPS + cookies"| ORPC
WP -->|"HTTPS + cookies"| ORPC
MOB -->|"HTTPS + Bearer"| ORPC
ORPC --> Routers
AUTH --> PG
Routers --> PG
R4 --> OLLAMA
R2 --> S3
R2 --> STRIPE
Diagramme de SéquenceCycle de vie d’une mission
sequenceDiagram
actor Agri as Agriculteur
participant API as API Fastify/oRPC
participant DB as PostgreSQL
participant S3 as S3 Storage
actor Pilote as Pilote
rect rgb(232, 245, 237)
Note over Agri,DB: Création de mission
Agri->>API: createMission(plotIds, type, window, analysisOptionIds)
API->>DB: vérifier ownership des parcelles
DB-->>API: plots OK
API->>DB: lire pricingConfig (PUBLISHED)
DB-->>API: config OK
API->>API: prix = max(min, base + surface×€/ha + Σ options)
API->>DB: INSERT mission (PUBLISHED)
DB-->>API: OK
API-->>Agri: mission { status: PUBLISHED, price }
end
rect rgb(220, 240, 228)
Note over Pilote,DB: Acceptation
Pilote->>API: acceptMission(missionId)
API->>DB: vérifier capteurs compatibles
DB-->>API: compatible
API->>DB: COUNT missions SCHEDULED < 5
DB-->>API: OK
API->>DB: UPDATE status → SCHEDULED
API-->>Pilote: mission { status: SCHEDULED }
end
rect rgb(208, 235, 218)
Note over Pilote,S3: Livraison
Pilote->>API: uploadDeliverable(missionId, files[])
API->>S3: upload fichiers
S3-->>API: URLs
API->>DB: INSERT deliverable
API->>DB: UPDATE status → DELIVERED
API->>DB: pilotProfile.score + 1
API-->>Pilote: deliverable OK
API-->>Agri: notification DELIVERED
end
Diagramme de Use Cases
graph LR
AGRI(["Agriculteur"])
PILOTE(["Pilote"])
ADMIN(["Admin"])
subgraph Parcelles
UC1["Créer / modifier parcelle"]
UC2["Revendiquer parcelles RPG"]
UC3["Consulter la carte"]
end
subgraph Marketplace
UC4["Créer une mission"]
UC5["Consulter les missions"]
UC6["Accepter une mission"]
UC7["Livrer un livrable"]
end
subgraph Actions["Plans d'Action"]
UC8["Gérer plans d'action"]
UC9["Gérer les tâches"]
end
subgraph IA["Assistant IA"]
UC10["Question agronomique"]
UC11["Analyser une photo"]
end
subgraph Administration
UC12["Import données RPG"]
UC13["Configurer tarification"]
end
AGRI --> UC1
AGRI --> UC2
AGRI --> UC3
AGRI --> UC4
AGRI --> UC8
AGRI --> UC9
AGRI --> UC10
AGRI --> UC11
PILOTE --> UC5
PILOTE --> UC6
PILOTE --> UC7
ADMIN --> UC12
ADMIN --> UC13
Énumérations du modèle de données
| Enum | Valeurs |
|---|---|
AccountType | farmer, buyer, cooperative, pilot, admin |
PlotSource | manual, rpg |
FlightStatus | planned, in_progress, completed, cancelled |
TaskStatus | todo, in_progress, completed |
MissionType | SURVEILLANCE, MAPPING, INSPECTION, SPRAYING |
MissionStatus | PUBLISHED, SCHEDULED, IN_PROGRESS, DELIVERED, CANCELLED |
PaymentStatus | PRE_AUTHORIZED, CAPTURED, REFUNDED |
MissionPricingConfigStatus | DRAFT, PUBLISHED, ARCHIVED |
RpgDatasetStatus | DRAFT, COMPLETE, ACTIVE, ARCHIVED |
RpgImportJobStatus | PENDING, DOWNLOADING, EXTRACTING, PARSING, IMPORTING, COMPLETED, ACTIVATED, CANCELLED, FAILED |
Points clés du modèle
- Plot stocke la géométrie en
MultiPolygon SRID 2154(Lambert 93) via PostGIS. La surface est calculée automatiquement depuis la géométrie. - Mission regroupe des parcelles via la table de jonction
MissionPlotet peut appartenir à unMissionGrouppour les missions groupées. - Score pilote :
PilotProfile.score— +1 par livraison, -2 par annulation, plancher à -20. - Parcelles RPG : importées depuis le Registre Parcellaire Graphique. Une parcelle active (
isActiveRpg=true) est visible par tous les agriculteurs jusqu’à ce qu’elle soit revendiquée. - Tarification mission :
prix = max(minimumMissionPrice, basePrice + surface × pricePerHa + Σ analysisOptions)